2

球をテクスチャにレンダリングし(フレームバッファオブジェクト(FBO)を使用して実行)、そのテクスチャをバックバッファとアルファブレンドする必要があります。これまでのところ、すべてのフレームの先頭でテクスチャをクリアする以外は、テクスチャを使用して処理を行っていません。

私のシーンは、空の空間にある惑星だけで構成されていると言えます。球は、惑星の隣または周囲に表示されます(今のところ月のようなものです)。球をバックバッファに直接レンダリングすると、正しく表示されます。しかし、テクスチャにレンダリングしてからそのテクスチャをバックバッファとブレンドする中間ステップを実行すると、球は惑星の前にある場合にのみ表示され、前にない部分は単に「切り取られます」 ":

惑星の端で切り取られた球

glutSolidSphereFBOにバインドされたRGBA8フルスクリーンテクスチャを使用して球をレンダリングし、すべての球ピクセルが1.0のアルファ値を受け取るようにします。次に、テクスチャをフラグメントシェーダープログラムに渡し、このコードを使用して、アルファブレンディング中にフルスクリーンクワッド(テクスチャがマップされている)をバックバッファーにレンダリングします。

glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);

glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glBegin(GL_QUADS);
glTexCoord2i(0, 1);
glVertex3i(-1,  1, -1);   // TOP LEFT
glTexCoord2i(0, 0);
glVertex3i(-1, -1, -1);   // BOTTOM LEFT
glTexCoord2i(1, 0);   
glVertex3i( 1, -1, -1);   // BOTTOM RIGHT
glTexCoord2i(1, 1);   
glVertex3i( 1,  1, -1);   // TOP RIGHT
glEnd();
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glEnable(GL_DEPTH_TEST);

glDisable(GL_BLEND);

これはシェーダーコードです(Cgで記述されたFXファイルから取得):

sampler2D BlitSamp = sampler_state
{
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = LINEAR;
    AddressU = Clamp;
    AddressV = Clamp;
};

float4 blendPS(float2 texcoords : TEXCOORD0) : COLOR
{
    float4 outColor = tex2D(BlitSamp, texcoords);
    return outColor;
}

これがデプスバッファの問題なのかアルファブレンディングの問題なのかさえわかりません。デプステストの有効化と無効化(FBOにデプスバッファを接続)とアルファブレンディングの組み合わせをたくさん試しました。

編集:私は空白のフルスクリーンクワッドをバックバッファーにまっすぐにレンダリングしようとしましたが、それでも惑星の端の周りでトリミングされました。何らかの理由で、クワッドをレンダリングするための深度テストを有効にする(つまり、線glDisable(GL_DEPTH_TEST)とを削除するglEnable(GL_DEPTH_TEST) in the code above)ことで問題が解消されましたが、惑星と球以外はすべて白く表示されます。

白い間違った白い背景を持つ球

テクスチャのアルファチャネルが球以外のすべてのピクセルで0であることを確認した(そして確認できた)ので、どこに白さが導入されるのかわかりません。(深度テストを有効にするとこの効果がある理由の説明にも興味があります。)

4

2 に答える 2

1

ここに2つの考えられるエラーの原因があります。

1.FBOへのレンダリング

レンダリング後に欠落しているピクセルがFBOに存在しない場合は、対応するフラグメントを破棄するメカニズムが必要です。OpenGLパイプラインには、フラグメントが破棄される可能性のある4種類のフラグメントテストが含まれています。

  1. はさみテスト:はさみテストは画面の長方形の部分にのみ影響するため、原因とは考えられません。
  2. アルファテスト:フラグメントはすべて同じアルファ値を持つ必要があるため、同様に可能性は低くなります。
  3. ステンシルテスト:背景の惑星を描画するときにステンシル操作を使用し、バックバッファーからFBOにステンシルバッファーをコピーしない限り、可能性は低いです。
  4. 深度テスト:ステンシルテストと同じです。

したがって、ここではFBOへのレンダリングが問題にならない可能性があります。ただし、念のため、カラーアタッチメントのテクスチャを読み戻して、検査のためにファイルにダンプする必要があります。そのために次の関数を使用できます。

void TextureToFile(GLuint texture, const char* filename) {
  glBindTexture(GL_TEXTURE_2D, texture);
  GLint width, height;
  glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
  glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);

  std::vector<GLubyte> pixels(3 * width * height);
  glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, &pixels[0]);

  std::ofstream out(filename, std::ios::out | std::ios::binary);
  out << "P6\n"
      << width << '\n'
      << height << '\n'
      << 255 << '\n';
  out.write(reinterpret_cast<const char*>(&pixels[0]), pixels.size());  
}

結果のファイルは、ポータブルピックスマップ(.ppm)です。テクスチャを読み戻す前に、必ずFBOのバインドを解除してください。

2.テクスチャマッピング

FBOへのレンダリングが期待どおりに機能すると仮定すると、他の唯一のエラーの原因は、以前にレンダリングされたシーンにテクスチャをブレンドすることです。2つのシナリオがあります。

a)フラグメントは破棄されます

フラグメントが破棄される理由として考えられるものは、1と同じです。

  1. シザーテスト:いいえ、長方形の領域にのみ影響します。
  2. アルファテスト:おそらくそうではありません。テクセルで覆われた球はすべて同じアルファ値を持つ必要があります。
  3. ステンシルテスト:背景の惑星を描画するときにステンシル操作/ステンシルテストを使用し、古いステンシル状態がまだアクティブである場合は、原因である可能性があります。
  4. デプステスト:原因の可能性がありますが、すでに無効にしているため、実際には何の効果もありません。

したがって、これらのテスト、特にステンシルテストがすべて無効になっていることを確認する必要があります。

b)ブレンドの結果が間違っている

すべてのフラグメントがバックバッファーに到達すると仮定すると、それでも間違った結果を引き起こす可能性があるのはブレンディングだけです。ブレンディング関数(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)では、バックバッファの値はブレンディングとは無関係であり、テクスチャのアルファ値が正しいと想定しています。したがって、ここでブレンドが根本的な原因である理由はわかりません。

結論

結論として、観察された結果の唯一の賢明な原因はステンシルテストであるように思われます。そうでない場合、私はオプションがありません:)

于 2012-09-29T16:14:58.807 に答える
0

私はそれを解決したか、少なくとも回避策を思いついた。

glClearColorまず第一に、白さはに設定されていたという事実から生じているglClearColor(1.0f, 1.0f, 1.0f, 1000.0f)ので、惑星以外のすべては最終的には書かれていませんでした。球をレンダリングする前に、バックバッファの内容(惑星、大気、およびその周囲の空間)をテクスチャにコピーし、そのコピー/ブリット操作の前に大気と空間をレンダリングするので、それらが含まれます。初期化。以前は、惑星自体以外のすべてが私のクワッドの後にレンダリングされていました。これは、深度テストを使用すると、明らかにクワッドの後ろにすべてを配置し、クワッドを非表示にしました。

私が達成しようとしているエフェクトのリファレンス実装では、常にこの種のブリット操作をコードで使用していますが、エフェクトに必要だとは思いませんでした。今、私は他の方法がないかもしれないように感じます...

于 2012-10-01T14:31:24.580 に答える