2Dレンダリングにフル解像度の深度バッファーを使用する


9

私は正投影を使用して2Dエンジンの前面から背面へのレンダラーに取り組んでいます。オーバードローを避けるために深度バッファーを使用したい。16ビットの深度バッファーがあり、Z = 100でZ = 0を見ているカメラ、zNearが1、zFarが1000です。レンダリングされた各スプライトは、Z座標を次第に離れた値に設定し、深度テストでレンダリングをスキップできるようにします下にあるものは何でも。

ただし、Z位置がZバッファ値で終わる方法が非線形であることは知っています。私は、16ビットの深度バッファのフル解像度を利用したいと考えています。つまり、65536の一意の値を許可しています。したがって、レンダリングされるすべてのスプライトについて、Z位置を次の位置にインクリメントして、次の一意の深度バッファー値に関連付けます。

言い換えると、描画されるスプライトのインクリメントインデックス(0、1、2、3 ...)を各スプライトの適切なZ位置に変更して、一意の深度バッファー値を設定します。この背後にある数学についてはわかりません。これを行うための計算は何ですか?

注:私はWebGL(基本的にはOpenGL ES 2)で作業しており、幅広いハードウェアをサポートする必要があるため、gl_FragDepthなどの拡張機能でこれが簡単になる場合もありますが、互換性の理由で使用できません。


Zバッファーを使用すると、すべてのZバッファーの書き込み、計算、比較と、テクスチャの前面へのコピーとを追加した後、パフォーマンスの向上(もしあれば)が得られるとは想像できません。アルファ透明度/ブレンドは言うまでもありません。苦痛。
Matt Esch、2015年

@MattEsch:これらの計算はすべてGPUで非常に高速に行われるため、そうすることは理にかなっています。
Panda Pajama

@MattEsch:FWIWこれは、専用のGPUメモリではなくシステムメモリを使用するIntel統合GPUを対象としています。これにより、多くのスプライトをオーバードローすると、速度が遅くなり、フィルレートの上限に達しやすくなります。インテルは、この方法を回避する方法としてこのアプローチを推奨しました。おそらく、深度テストの実装は十分に最適化されており、多くのフィルレートを節約できます。それはまだ見られないままです、私はまだそれをプロファイルしていません!
AshleysBrain、2015年

@PandaPajamaブロックのメモリのコピーは実際には非常に高速であるため、テクスチャをサーフェスにブリットするだけの場合は、非常に高速になります。最初の主要なオーバーヘッドは、最初にGPUにデータを取得することです。これは、Ashleyが指摘しているように、統合されたGPUではコストが高くなる可能性があります。そもそも、マトリックスの計算に必要なデータをアップロードするのは非常にコストがかかるため、多くの3Dゲームでも、CPUで(ボーンアニメーションのように)かなりの量の処理を実行します。
Matt Esch

@MattEsch:ブリッティングだけでできることはたくさんあります。回転、スケーリング、変形が頭に浮かびますが、ピクセル/頂点シェーダーを使用しているため、ハードウェアで実行できることの制限は、ブリットで実行できることよりもはるかに高くなります。
Panda Pajama、2015年

回答:


5

実際、zバッファーに格納されている値は、オブジェクトの実際のz座標に線形ではなく、逆数になっています。これは、バックプレーンに近いものよりも目の近くにあるものに高い解像度を与えるためです。

あなたがやっていることは、あなたのマッピングということですzNear0、あなたがzFarします1。以下の場合zNear=1zFar=2、それは次のようになります。

Zバッファ

これを計算する方法は、次のように定義されます。

z_buffer_value = k * (a + (b / z))

どこ

 k = (1 << N), maximum value the Z buffer can store
 N = number of bits of Z precision
 a = zFar / ( zFar - zNear )
 b = zFar * zNear / ( zNear - zFar )
 z = distance from the eye to the object

...そしてz_buffer_valueは整数です。

上記の方程式は、この素晴らしいページのおかげであなたにもたらされます。これは、Zバッファーを本当に良い方法で説明しています。

そのzため、指定されたの必要性を見つけるためにz_buffer_value、以下をクリアしzます。

z = (k * b) / (z_buffer_value - (k * a))

答えてくれてありがとう!私はあなたがあなたの最終的な方式をどうやって手に入れたのか少し混乱しています。私が取りz_buffer_value = k * (a + (b / z))、解決するために単純に並べ替えるとz、次のようになりz = b / ((z_buffer_value / k) - a)ます。
AshleysBrain、2015年

@AshleysBrain:あなたは分母を取る(v / k) - a => (v - k * a) / k、とに崩壊(k * b) / (v - (k * a))。同じ結果です。
Panda Pajama

ああ、分かった。答えをありがとう、それはうまくいきます!
AshleysBrain、2015年

0

多分あなたはあなたのアプローチをもっと簡単なものに変えるべきです。私が何をするか。Z深度は維持しますが、レンダリングしたもののリストは維持します。z深度の値に基づいてそのリストを並べ替え、リストの順序でオブジェクトをレンダリングします。

これが役立つことを願っています。人々はいつも私に物事をシンプルに保つように言う。


1
申し訳ありませんが、それはあまり役に立ちません。私はすでにそうしています。問題は、どのZポジションを選択するかです。
AshleysBrain、2015年

0

レンダリングするもののリスト(前面から背面)が既に並べ替えられているので、本当にZインデックスをインクリメントする必要がありますか?「チェック機能」に「以下」は使えませんか?このようにして、特定のピクセルが既に描画されているかどうかを実際にチェックします。


すべてが常に等しいZインデックスを持ち、したがって深度テストに合格するため、「以下」は絶対にすべてを上書きします。
AshleysBrain、2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.