GLSL ES Phong着色器结果中的设备/操作系统不一致

ric*_*ter 5 opengl-es glsl fragment-shader ios opengl-es-2.0

Apple的OpenGL ES最佳实践建议不要对片段着色器中计算的结果进行分支.但是,当光源位于表面的"错误"侧时,Phong阴影通常涉及跳过镜面术语,其中直接的方法是N点亮单位法线方向和光线方向L并检查阳性结果.

我试图在我的着色器中没有分支的情况下执行此操作:我不是使用if语句,而是对镜面反射项进行所有计算,然后给它一个系数,即1.0if dot(N, L)大于零,0.0否则.(我使用内置step()函数实现了这一点.结合max()sign()产生相同的结果,但据说速度有点慢.)

但是,这似乎导致奇怪的,设备和/或iOS版本特定的结果:

与分支没有分支

  • 在运行iOS 6.0的iPhone 4上,带分支的版本具有宽镜面高光(左图); 没有分支我看到一个狭窄的镜面高光(右图),尽管"光泽"指数保持不变.
  • 在iOS 6.0模拟器上,我看到了两个版本的着色器的第二个图像.
  • 在我的iPad(原始的2010型号,卡在iOS 5.1上),我看到第一个图像与两个版本的着色器.

显然,这不是问题的分支或缺乏.(顺便说一句,右手图像是"正确的"渲染.)

这是我的片段着色器:

precision mediump float;

uniform lowp vec3 ambientLight;
uniform lowp vec3 light0Color;
uniform lowp vec3 materialAmbient;
uniform lowp vec3 materialDiffuse;
uniform lowp vec3 materialSpecular;
uniform lowp float materialShininess;

// input variables from vertex shader (in view coordinates)
varying vec3 NormDir;
varying vec3 ViewDir;
varying vec3 LightDir;

void main (void)
{
    vec3 L = normalize(LightDir);
    vec3 N = normalize(NormDir);
    vec3 E = normalize(ViewDir);

    lowp vec3 ambient = ambientLight * materialAmbient;

    float cos_theta = dot(L, N);

    lowp vec3 diffuse = materialDiffuse * light0Color * max(0.0, cos_theta);

    lowp vec3 specular = vec3(0.0, 0.0, 0.0);
//  if (cos_theta > 0.0) {
        lowp vec3 R = reflect(-L, N);
        lowp vec3 V = normalize(-E);
        float cos_alpha = dot(R, V);
        specular =  step(0.0, cos_theta) *  materialSpecular * light0Color * pow(max(0.0, cos_alpha), materialShininess);
        //          ~~~~~~~~~~~~~~~~~~~~~~
        //          should produce the same results as the commented branch, right?
//  }
    gl_FragColor = vec4(ambient + diffuse + specular, 1.0);
}
Run Code Online (Sandbox Code Playgroud)

我也欢迎进一步提出改进这款着色器在iOS硬件上的性能的建议!

ric*_*ter 1

正如@BradLarson 的评论中指出的,结果证明lowp限定符materialShininess是问题所在;相反,将其设置为mediump,它可以在我手头的所有设备和操作系统版本上正确渲染(右侧图像),无论是否step使用着色器的分支或无分支(带有 )版本。

(使用lowpvsmediump作为输入RV从中cos_alpha计算不会产生任何明显的差异,这是有道理的:这些是​​归一化向量,因此它们的分量的幅度在 0.0 到 1.0 范围内。这与颜色分量的范围相同,其中lowp看来是故意的。)