GL_DEPTH_TEST と透明テクスチャによるレンダリングの不具合
質問
ある角度から見ると、私の低木は次のように見えます。
もう一方から見ると、次のようになります。
私の理論では、最初の角度から低木を見ると、低木の背後にあるすべてのブロックがすでに描画されているため、低木を描画するときは、それらを上に重ねて描画するだけです。
しかし、別の角度から見ると、基本的には最初に低木を描画しようとし、次に低木の背後にあるブロックを描画しようとするときに、深度バッファをチェックして、すでにブロックの視界を遮るものがあることを確認します。レンダリングしないと、紺色の四角形 (私のクリアカラー) が表示されます。
しかし、この問題を解決する方法がまったくわかりません。深度テストを無効にすると、他のあらゆる種類のエラーが発生します。頂点またはポリゴンに透明度があるというフラグを付けて、背後にあるものをレンダリングする必要があることを認識させる方法はありますか?
これを見つけました. 。これが唯一の解決策でしょうか?プレイヤーが動き回れるため、透明なブロックと不透明なブロックを分離し、ほぼすべてのフレームごとに CPU 上で手動で並べ替えるにはどうすればよいでしょうか?これをGPUに委任する方法が必要です...
解決
そのリンク (および CPU でのソート) はアルファ ブレンディング用です。(ブレンディングではなく) アルファ テストのみが必要な場合は、何も並べ替える必要はありません。アルファ テストを有効にし、深度テストを有効にしたままにすると、すべてが正常にレンダリングされます。
ここを参照してください: http://www.opengl.org/wiki/Transparency_Sortingソートが必要な「標準半透明」ではなく、アルファテストが必要な「アルファテスト」が必要です。
他のヒント
解決策 #1:
- 深度バッファーを有効にして、すべての不透明なオブジェクトを任意の順序で最初にレンダリングします。これには、アルファ テストを使用するすべてのオブジェクトが含まれます それなし アルファブレンディング。
- のために
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
オブジェクト (煙/ガラス/草):最も遠いところから透明なシーンをレンダリングする ポリゴン 深度バッファー書き込みが無効になっている最も近いポリゴンへ (glDepthMask(GL_FALSE)
)。すべての透明なオブジェクトが凸状で交差しない場合は、ポリゴンの代わりにオブジェクトを並べ替えることができます。 - のために
glBlendFunc(GL_SRC_ALPHA, GL_ONE)
そしてglBlend(GL_ONE, GL_ONE)
(火、「マジック」パーティクル システム、グロー):深度バッファ書き込みを使用して、透明なシーンを任意の順序でレンダリングします (glDepthMask(GL_FALSE)
) 無効。 - ステップ 3 の後で、深度バッファーが有効になっているオブジェクトをレンダリングしないでください。
解決策 #2:
デプスピーリングを使用します(グーグルで調べてください)。特に透明なオブジェクトが互いに交差する場合。ソリューション #1 を必要とするパーティクル システムや草には適していません。
そして、ほぼすべてのフレームごとに CPU 上で手動で並べ替えます。
挿入ソートは、すでにソート済みまたは部分的にソートされたデータに最適です。
これをGPUに委任する方法が必要です...
草の有無をマークするチャネル(アルファ)を持つテクスチャを使用して、ジオメトリ シェーダで草のポリゴンを(正しい順序で)生成できると思います。OpenGL 4 が必要で、おそらく草パッチを生成するためにシェーダーにフィードするポリゴンに対して、ある種の高レベルのソートを実行する必要があります。
個々の低木が全方向に完全に対称であれば、頂点シェーダーで (+- 90/180/270 度) 回転して、正しいポリゴンの順序を維持できます。
また、適切に並列化され、GDGPU アプローチまたは OpenCL/CUDA のいずれかを使用して GPU 上で実行できるマージ ソート アルゴリズムもあります。
ただし、そのようなものを使用して 5 つの草の低木をレンダリングすることは、グレネードランチャーでゴキブリを殺そうとするのとほぼ同じであり、楽しいことですが、まったく効率的ではありません。
実際にパフォーマンスの問題が発生するまでは、「GPU へのオフロード」については忘れることをお勧めします。プロファイラーを使用し、最適化する前に必ず測定してください。そうしないと、不必要な最適化によって開発時間が大幅に無駄になってしまいます。
WebGL または OpenGL ES 2.0 (iPhone/Android) を使用している場合、アルファ テストはありません。代わりに、透明なピクセルを描画する必要はありません。そうすれば、ピクセルが書き込まれないため、深度バッファーには影響しません。これを行うには、フラグメント シェーダーで透明なピクセルを破棄する必要があります。ハードコードすることもできます
...
void main() {
vec4 color = texture2D(u_someSampler, v_someUVs);
if (color.a == 0.0) {
discard;
}
gl_FragColor = color;
}
または、アルファ値を設定できる古いスタイルのアルファ テストをシミュレートすることもできます。
...
uniform float u_alphaTest;
void main() {
vec4 color = texture2D(u_someSampler, v_someUVs);
if (color.a < u_alphaTest) {
discard;
}
gl_FragColor = color;
}