1

PowerVRGPUのGLSLコンパイルの最適化に関連していると思われる問題が発生しました。AdrenoおよびTegraGPUでは、フラグメントシェーダーは問題なく機能しますが、PowerVR(Motorola Droid)では、条件付きステートメントで誤った結果が生成されます。フラグメントシェーダーコードの条件ステートメントを変更することで問題を修正しました。ステートメントreturnのブロックを呼び出す代わりに、ブロックを追加しました。これで、PowerVRで問題なく動作します。ifelse

両方のシェーダーのロジックは完全に同一でgl_FragColorあり、どちらの場合も設定されます。今後問題を回避できるように、PowerVROpenGLドライバーのこの動作について説明してください。なぜこのように条件文を処理するのですか?

これは、PowerVRGPUで正しく機能しない古いフラグメントシェーダーです。

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とPowerVRGPUの両方で正常に機能する新しいフラグメントシェーダーコード:

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;またはreturn;ステートメントの後にコードを追加することはお勧めできません。それでも実行され、予測できない結果を引き起こす可能性があります。

ステートメントに適用できるこの動作を説明する記事がいくつかありますがdiscard;、私が見ているように、同様の動作が発生する可能性もありreturn;ます。ここで1つ読んでください:http://people.freedesktop.org/~idr/OpenGL_tutorials/03-fragment-intro.html#infinite-loop ここで述べられているように、場合によっては、discard;

フラグメントシェーダーは、一度に1つのテクセルではなく、通常は2x2ピクセルのバッチでGPUによって実行されます。そして、フラグメントシェーダーのこの並列実行は、後にコードを引き起こす可能性がありますreturn;

したがって、フラグメントシェーダーがifステートメントを正しく処理するには、またはで関数を終了するだけでなく、常に演算子で使用elseする必要があります。これはまさに私がやったことです。ifreturn;discard;

于 2012-09-25T13:37:17.400 に答える