1

我仍然没有摆脱我的 glsl 着色器(GL 2.0)中的一些烦人的错误......我已经搜索了超过 3 周的这个问题的解决方案,但我没有得到任何解决方案。谷歌上有很多例子和解释,但没有一个真正有效。

首先,这是我的片段着色器代码。之后,我将解释究竟是什么问题:

//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,计算出的漫反射/规格矢量的规格矢量和。

现在出现以下问题: Pointlights 本身运行完美。定向灯本身也运行完美。但是它们在一起不会很好地工作。我将解决这个问题:我最多有 4 个点光源和 4 个定向光源。为了测试,我使用了 4 个点光源和 1 个定向光源。

  • 如果我注释掉定向灯的for循环计算,我得到以下结果: 禁用定向灯,启用点灯
  • 如果我注释掉点光源的 for 循环,我会得到以下结果: 点光源被禁用,方向灯被启用
  • 如果我启用了两个 for 循环,则会发生以下情况: 两种光源类型均已启用

定向光似乎完全被忽略了。汽车仅由点灯照明。

所以,我发现:如果我改变 for 循环的顺序,点灯 -> 定向灯,而不是 dirlights -> 点灯,效果会交换:点灯被忽略,定向灯被计算。

我也发现,这个问题一定是:pow() 函数或除以零,但是:如果我注释掉以下代码行:

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

我可以得到以下结果:

spec += 注释掉的行

-> 漫反射颜色通常为点光源和定向光源计算!

所以我想到了如何消除这个问题,因为我认为 0 power by 0 会导致数学错误。也除以零....如何避免未定义的值?

isnan() 或 isinf() 函数似乎在 android-glsl 中不存在。

安迪解决方案或提示我可以做得更好,这会奏效吗?如果它可以帮助一点点,我会很高兴任何答案。这让我很生气,因为 3 周。非常感谢帮手!:)

有关代码的更多信息: https ://github.com/Chrise55/Llama3D

克里斯

4

0 回答 0