Обработка неопределенных значений NaN или Inf в glsl. Думая о matherrors - PullRequest
1 голос
/ 07 декабря 2011

Я до сих пор не избавился от некоторых досадных ошибок в моем шейдере glsl (GL 2.0) ... Я искал решение этой проблемы уже более 3 недель, но я не получил никаких. В Google много примеров и объяснений, но ни один из них не работает.

Прежде всего, вот мой фрагментарный код. После этого я объясню, в чем именно проблема:

//fragmentshader
const int MAX_POINT_LIGHTS = LL.MAX_POINT_LIGHTS;
const int MAX_DIR_LIGHTS = LL.MAX_DIR_LIGHTS;
const int MAX_TEXTURES = LL.MAX_TEXTURES;
//float-precision
precision mediump float;
//varyings
varying vec2 texcoord;
varying vec3 normal;
varying vec3 position;
varying float depth;
//pointlights
uniform float pl_range[MAX_POINT_LIGHTS];
uniform vec3 pl_position[MAX_POINT_LIGHTS];
uniform vec3 pl_color[MAX_POINT_LIGHTS];
uniform vec3 pl_specular[MAX_POINT_LIGHTS];
//dirlights
uniform vec3 dl_direction[MAX_DIR_LIGHTS];
uniform vec3 dl_position[MAX_DIR_LIGHTS];
uniform vec3 dl_color[MAX_DIR_LIGHTS];
uniform vec3 dl_specular[MAX_POINT_LIGHTS];
//cameras
uniform vec3 camera;
//fog
uniform vec4 uVecFog;
uniform float uFogNear;
uniform float uFogFar;
//material
uniform vec3 mat_diff;
uniform vec3 mat_spec;
uniform float mat_shine;
uniform float mat_elum;
//texture
uniform sampler2D uTexture;
//ambientlight
vec4 ambient = vec4(0.0,0.0,0.0,0.0);

void main() {

    vec3 N = normalize(normal);
    vec3 V = normalize(camera - position);
    vec4 diff  = vec4(0.0,0.0,0.0,0.0);
    vec4 spec = vec4(0.0,0.0,0.0,0.0);
    //dirlights
    for(int i=0;i<MAX_DIR_LIGHTS;i++) {
        vec3 L = -normalize(dl_direction[i]);
        vec3 R = -normalize(reflect(L,N));
        float RV = max(dot(R,V),0.0);
        float S = pow(max(dot(R,V),0.0),mat_shine);
        float F = clamp(dot(L,N),0.0,1.0);
        diff += vec4(F * mat_diff * dl_color[i],1.0);
        spec = vec4(S * mat_spec * dl_specular[i],1.0);
    }

    //pointlights
    for(int i=0;i<MAX_POINT_LIGHTS;i++) {
        vec3 L = normalize(pl_position[i] - position);
        vec3 R = -normalize(reflect(L,N));
        float D = distance(pl_position[i],position);
        float DF = clamp(1.0 - D/pl_range[i],0.0,1.0);
        float S = pow(max(dot(R,V),0.0),mat_shine);
        float F = clamp(DF * max(dot(L,N),0.0),0.0,1.0);
        diff += vec4(F * mat_diff * pl_color[i],1.0);
        spec += vec4(DF * S * mat_spec * pl_specular[i],1.0);
    }
    //fog
    float fogDensity = 0.0;
    if (depth > uFogFar) {
        fogDensity = 1.0;
    } else if(depth > uFogNear) {
        float newDepth = depth-uFogNear;
        fogDensity = newDepth/(uFogFar-uFogNear);
    } else if (depth < uFogNear) {
        fogDensity = 0.0;
    }
    vec4 vecFog = uVecFog * fogDensity;
    //texturecolor
    vec4 colortex = texture2D(uTexture,vec2(texcoord.x,-texcoord.y));
    //final fragmentcolor
    gl_FragColor = mix((ambient + colortex * (diff + vec4(mat_diff * mat_elum,1.0)) + spec),vecFog,fogDensity);
}

Есть следующие значения переменных, где:

  • pl_ являются точечными значениями,
  • dl_ являются значениями направления света,
  • mat_diff - диффузное значение для материала,
  • также mat_spec, mat_elum, mat_shine для материала зеркального, элюминированного и блестящего,
  • N = Нормальный,
  • V = вектор от вершины до вершины,
  • L = Световой вектор до вершины,
  • R = Вектор отражения,
  • D = световое расстояние,
  • DF = Коэффициент расстояния для смешивания света,
  • S = Расчетный коэффициент зеркальности,
  • F = Дотпродукт из L, N
  • и diff, spec vectorsum из вычисленных diffuse / spec-векторов.

Теперь возникает следующая проблема: Точечные светильники сами по себе работают идеально. Направленные фонари тоже работают отлично. Но вместе они не будут работать очень хорошо. Я уточню проблему: У меня есть 4 прожектора и 4 указателя поворота для максимума. Для тестирования я использовал 4 точечные и 1 направленный свет.

  • Если я закомментировал вычисление цикла for alightlight, я получил следующий результат: Directionallights are disable, pointlights enabled
  • Если я закомментировал цикл for для точечных светильников, я получил следующий результат: Pointlights are disabled, directionallights enabled instead
  • Если я включил оба цикла for, происходит следующее: Both lightsource types are anabled

Направление света, похоже, полностью игнорируется. Вместо этого автомобиль освещается только точечным освещением.

Итак, что я узнал: Если я изменю порядок циклов for, pointlights -> directionallights, а не dirlights -> pointlights, эффект поменяется местами: pointlights игнорируются, directionallight вычисляется.

Что я тоже обнаружил, эта проблема должна быть до: функция pow () или деление на ноль, но: Если я закомментирую следующие строки кода:

spec = vec4(S * mat_spec * dl_specular[i],1.0);
spec += vec4(DF * S * mat_spec * pl_specular[i],1.0);

я могу получить следующий результат:

spec += lines commented out

-> Рассеянный цвет обычно вычисляется для точечных И направленных светов!

Поэтому я подумал о том, как устранить эту проблему, потому что я думал, что 0 при питании от 0 приводит к математической ошибке. Делим на ноль тоже .... Как я могу избежать значений, которые не определены?

Функции isnan () или isinf (), по-видимому, не существуют в android-glsl.

Энди решения или советы, что я мог бы сделать лучше, что это будет работать? Я был бы рад любому ответу, если бы он мог немного помочь. Это сводит меня с ума с 3 недель. Большое спасибо за помощников! :)

Больше информации о коде: https://github.com/Chrise55/Llama3D

Chrise

...