OpenGLで透明度をレンダリングするいくつかの方法は何ですか


14

次のように、アルファブレンディングをオンにして、表面を透明にすることができます。

glDisable(GL_DEPTH_TEST); //or glDepthMask(GL_FALSE)? depth tests break blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

しかし、これはオブジェクトが最前面から最前面にレンダリングされる場合にのみ機能します。それ以外の場合、背景の物体は、下の画像の床のように、より近いオブジェクトの前に表示されます。パーティクルとGUI要素のソートは問題ありませんが、三角形メッシュの場合、https//www.opengl.org/wiki/Transparency_Sortingで説明しているように、手間がかかり、時間がかかるようです。

これに対処する一般的な方法は何ですか?これは非常に広範であり、実装の詳細な詳細ではなく、いくつかのアプローチの簡単な説明と、関与する可能性があることを知っています。

ここに画像の説明を入力してください


これが答えになるかどうかはわかりませんが、画像のエラーは、すべてのプリミティブで深度テストを行わずにレンダリングすることで発生します。シーンは2つのパスでレンダリングする必要があります。まず、通常はすべてのソリッドジオメトリをレンダリングします。その後、深度書き込み(GL_DEPTH_TESTでない)を無効にし、半透明のジオメトリをほぼ前後の順序でレンダリングします。これにより、前にあるソリッドジオメトリの前に透明なジオメトリが描画されなくなります。
yuriks

@yuriksこの場合、それはおそらく私の側の貧弱な例ですが、すべてが透明であることが意図されています。ひどく行われた場合、間違った透明度がどのように見えるかを示すものが欲しかった。また、ジオメトリの並べ替えが驚くほど難しい例(たとえば、ここでは床は1つの巨大なポリゴンであり、深さ範囲全体をカバーしています)。
jozxyqk

回答:


10

明示的な順序付けを回避するための一連の手法は、Order Independent Transparency(略してOIT)という名前で行われます。

多くのOITテクニックがあります。

歴史的には、深度ピーリングです。このアプローチでは、最初に最前面のフラグメント/ピクセルをレンダリングし、次に前のステップなどで見つかったものに最も近いものを見つけて、必要な数の「レイヤー」を続けます。各パスで1層の深度を「剥離」するため、深度剥離と呼ばれます。すべてのレイヤーは、通常、後ろから前に再結合できます。このアルゴリズムを実装するには、深度バッファのコピーが必要です。

テクニックの別のセットは、ブレンドエンドOITテクニックです。最近の興味深いものの1つは、McGuireとBavoilによって提案されたWeighted Blended OIT です。基本的に、特定のフラグメントを占めるすべてのサーフェスに加重合計を適用します。彼らが提案する重み付けスキームは、カメラ空間Z(オクルージョンの近似値)と不透明度に基づいています。
考えは、問題を加重和に減らすことができれば、実際には順序を気にしないということです。

オリジナルの論文以外に、Weighted Blended OITの実装の詳細と問題に関する優れたリソースがMatt Pettineoのブログにあります。彼の投稿からわかるように、この手法は特効薬ではありません。主な問題は、重み付けスキームが中心であり、シーン/コンテンツに応じて調整する必要があることです。彼の実験から、この手法は比較的低いおよび中程度の不透明度ではうまく機能するように見えますが、不透明度が1に近づくと失敗します。

繰り返しになりますが、深さの重みをどのように調整するかによってすべてが決まり、ユースケースに完全に適合するものを見つけることは必ずしも簡単ではありません。

Weighted Blended OITに必要なものは、2つの追加レンダーターゲットのみです。事前に乗算されたアルファカラー(色*アルファ)とアルファで塗りつぶしたもの。両方ともそれに応じて重み付けされます。もう1つはウェイト専用です。


6

1つのオプションは、深度ピーリングを使用することです。

基本的に、シーンの設定された回数(たとえば、n時間)を処理して、シーンの最も近い、2番目に近い、n最後から最後までのフラグメントを決定します。

この処理は、最初に通常の深度テストをシーン全体に適用することで実行されます(当然、最も近いサーフェスが返されます)。次に、深度テストの結果を使用して、深度テストで返された深度よりも小さい深度のすべてを無視することにより、最初のレイヤーを除外します。

深度テストを再度適用すると、2番目のレイヤーが返されます。必要に応じて繰り返します。

レイヤーができたら、すべてのレイヤーを逆の順序(各レイヤーのRGBAカラーを追跡していると仮定)で描画できます。レイヤーは前後の順序であるため、通常のブレンドを行います。


1
ありがとう!このために2つの深度バッファーが必要になるようです。つまり、最後の深度を保存および除外し、現在のレンダリングの深度テストを実行します。間違っている場合は修正しますが、各剥離パス間でスワップするFBOの2つの深度テクスチャが必要になると思います。
jozxyqk

1
@jozxyqk正しい、この手順には2つの深度バッファーが必要です。
es1024

1

シングルパスのクリームは、OpenGLの透明性を損なわない(またはほとんどない)Aバッファーです。最新のOpenGLでは、以下を実装できます。

http://blog.icare3d.org/2010/06/fast-and-accurate-single-pass-buffer.html

深層剥離の複数のパスを回避し、面倒なソートを必要としません。


3
理想的には、回答は自己完結型であり、外部リンクに大きく依存する必要があります。補足資料にはリンクがあると便利ですが、答えはキーワードだけではいけません。Aバッファとは何か、そしてそれがどのように機能するかについていくつかの詳細を含めることができれば、答えは大きく改善されます。
マーティンエンダー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.