1

我遇到了一个我认为与 PowerVR GPU 的 GLSL 编译优化有关的问题。在 Adreno 和 Tegra GPU 上,片段着色器工作得很好,但在 PowerVR(摩托罗拉 Droid)上,它会在条件语句中产生不正确的结果。我通过更改片段着色器代码中的条件语句解决了这个问题。我没有在语句中调用return块,而是添加了块,它现在在 PowerVR 上工作正常。ifelse

两个着色器的逻辑是完全一样的,gl_FragColor在两种情况下都设置了。请解释 PowerVR OpenGL 驱动程序的这种行为,以便将来避免出现问题。为什么它以这种方式处理条件语句?

这是旧的片段着色器,它在 PowerVR GPU 上无法正常工作:

precision mediump float;

varying vec3 vNormal;
varying vec3 vViewVec;
varying vec2 vTextureCoord;

uniform sampler2D sTexturePumpkin;

void main(void)
{
const float sheen = 0.68;
const float noiseScale = 0.05;
const float furriness = 10.0;
const vec4 lightDir = vec4(0.267260, 0.267260, -0.925820, 0.0);

  vec4 color = texture2D(sTexturePumpkin, vTextureCoord/*vec2(0.0,0.0)*/);
  if(vTextureCoord.y > 0.7) { // in this case PowerVR displays incorrect color
     gl_FragColor = color;
     return;
  }

  float diffuse = 0.5 * (1.0 + dot(vNormal, vec3(lightDir.x, lightDir.y, -lightDir.z)));
  float cosView = clamp(dot(normalize(vViewVec), vNormal), 0.0, 1.0);
  float shine = pow(1.0 - cosView * cosView, furriness);

  gl_FragColor = (color + sheen * shine) * diffuse; // in this case PowerVR works correctly
}

新的片段着色器代码,在 Adreno 和 PowerVR GPU 上都能正常工作:

precision mediump float;

varying vec3 vNormal;
varying vec3 vViewVec;
varying vec2 vTextureCoord;

uniform sampler2D sTexturePumpkin;

void main(void)
{
const float sheen = 0.68;
const float noiseScale = 0.05;
const float furriness = 10.0;
const vec4 lightDir = vec4(0.267260, 0.267260, -0.925820, 0.0);

  vec4 color = texture2D(sTexturePumpkin, vTextureCoord/*vec2(0.0,0.0)*/);
  if(vTextureCoord.y > 0.7) {
     gl_FragColor = color;
  }
  else {
    float diffuse = 0.5 * (1.0 + dot(vNormal, vec3(lightDir.x, lightDir.y, -lightDir.z)));
    float cosView = clamp(dot(normalize(vViewVec), vNormal), 0.0, 1.0);
    float shine = pow(1.0 - cosView * cosView, furriness);
    gl_FragColor = (color + sheen * shine) * diffuse;
  }
}
4

1 回答 1

3

好的,经过更深入的调查,我发现这不是着色器编译器的错误,而是处理片段着色器执行的特定方式。discard;放一个简单的orreturn;语句,后面跟着一些代码通常是个坏主意。它仍然可以执行并导致不可预知的结果。

有一些文章解释了这种适用于discard;语句的行为,并且我看到类似的行为也可能发生return;。请在此处阅读:http: //people.freedesktop.org/~idr/OpenGL_tutorials/03-fragment-intro.html#infinite-loop 正如这里所说,在某些情况下,您甚至可以通过不正确使用来实现无限循环discard;.

片段着色器由 GPU 执行,而不是一次针对单个纹素,通常是 2x2 像素的批次。而这种片段着色器的并行运行会导致代码在return;.

因此,要让片段着色器if正确处理语句,您必须始终使用elsein运算符,而不是简单地通过orif退出函数。这正是我所做的。return;discard;

于 2012-09-25T13:37:17.400 回答