WebGL は前後のオブジェクト間の関係を正しく処理します - 隠れ表面の除去 (深度テスト) / 深度の競合

目次

序文

オブジェクトのコンテキストを処理するための WebGL のルールを確認します - 後で描画されたグラフィックスが以前に描画されたグラフィックスを上書きします 

隠れ面の除去 (深度テスト)

陰面消去機能をオンにするには、次の 2 つの手順に従う必要があります。

1. 陰面消去機能をオンにします。

gl.enable() 関数の仕様

2. 描画する前に、深度バッファをクリアします。 

gl.clear(gl.DEPTH_BUFFER_BIT)

消去面のサンプルコードを非表示にする (DepthBuffer) 

効果例

深い対立

深い対立効果

深い対立の理由 

ポリゴン オフセット機能をオンにするには、次の 2 つの手順に従う必要もあります。

1. ポリゴンオフセットを有効にします。

2. 描画前にオフセットの計算に使用するパラメータを指定します。 

gl.polygonOffset() 関数の仕様編集

Deep Conflict サンプルコード (Zfighting)

効果例


序文

実際の世界では、下の図に示すように、テーブル上に 2 つのボックスを前後に配置すると、前のボックスが後ろのボックスを部分的にブロックします。

オブジェクトのコンテキストを処理するための WebGL のルールを確認します - 後で描画されたグラフィックスが以前に描画されたグラフィックスを上書きします 

以下の図に示すように、WebGL モデル ビュー投影行列_Hawthorn ツリーの blog-CSDN ブログサンプル プログラムPerspectiveView_mvpの効果を見てください。緑の三角形は、黄色と青の三角形によって部分的にブロックされています。WebGL は 3 次元グラフィックスに特化して設計されているようで、3 次元オブジェクトの距離を自動的に解析し、オクルージョン関係を正確に処理できます。 

 残念ながら、現実は想像ほど良くありません。デフォルトでは、WebGL は描画操作を高速化するために、バッファ内の順序で頂点を処理します。以前のプログラムでは、最初に遠くのオブジェクトを定義し、次に近くのオブジェクトを定義することで、正しい効果が得られました。

例えば​​PerspectiveView_mvpでは、以下の順序で三角形の頂点と色のデータを定義していますが、太字で示した Z 座標に注目してください。

WebGL は、バッファー内の順序で頂点を描画します (1 番目は最も遠い緑の三角形、2 番目は中央の黄色の三角形、3 番目は最も近い青い三角形です)。上図に示すように、後から描画されるグラフィックスがそれまでに描画されたグラフィックスを覆い、近くの三角形が遠くの三角形をブロックする効果が生じます。 

これを確認するために、バッファ内の三角形の頂点データの順序を調整し、以下に示すように、手前にある青い三角形、次に中央の黄色の三角形、最後に遠くにある緑の三角形を定義します。

プログラムを実行すると、下の図に示すように、 最も遠い側に表示されるはずの緑の三角形が、近くの黄色と青の三角形を不自然に遮っていることがわかります。

WebGL はデフォルトで、バッファ内の順序でグラフィックスを描画し、効率的であるため、後で描画されたグラフィックスが先に描画されたグラフィックスを上書きします。シーン内のオブジェクトが動かず、観察者の状態が一意である場合、このアプローチには問題はありません。しかし、たとえば、視点を移動し続けてさまざまな角度からオブジェクトを見たい場合、オブジェクトが表示される順序を事前に決定することはできません。 

隠れ面の除去 (深度テスト)

この問題を解決するために、WebGL では陰面削除機能を提供しています。この機能は、遮蔽されたサーフェス (隠れたサーフェス) を除去するのに役立ちます。遠くにあるオブジェクトは近くのオブジェクトによって自動的にブロックされるため、バッファ内のオブジェクトの順序を気にせずにシーンを描画できます。この機能はすでに WebGL に組み込まれているため、これをオンにするだけで済みます。

陰面消去機能をオンにするには、次の 2 つの手順に従う必要があります。

1. 陰面消去機能をオンにします。

gl.enable(gl.DEPTH_TEST)

いわゆる奥行き検出(DEPTH_TEST)というと奇妙に聞こえるかもしれませんが、実際にはオブジェクトの奥行きを(ピクセルごとに)検出して描画するかどうかを決定する仕組みであるため、この名前が付けられています。 

手順 1 で使用した gl.enable() 関数は、実際に WebGL のさまざまな機能を有効にすることができ、その仕様は次のとおりです。 

gl.enable() 関数の仕様

 

2. 描画する前に、深度バッファをクリアします。 

gl.clear(gl.DEPTH_BUFFER_BIT)

 ステップ 2: gl.clear() メソッドを使用して深度バッファをクリアします。深度バッファーは中間オブジェクトであり、その役割は WebGL による隠れた表面の除去を支援することです。WebGLはカラーバッファに幾何学図形を描画し、描画が完了したカラーバッファを<canvas>上に表示します。隠れた表面を除去したい場合は、各幾何学的図形の深度情報を知る必要があり、深度情報を保存するために深度バッファーが使用されます。深さ方向は通常 Z 軸方向であるため、Z バッファとも呼ばれます。

深度バッファと隠面の除去

フレームを描画する前に、深度バッファをクリアして、前のフレームの描画時に深度バッファに残されたトレースを削除する必要があります。これを行わないと、誤った結果が得られます。gl.clear() 関数を呼び出し、パラメータ gl.DEPTH_BUFFER_BIT を渡して深度バッファをクリアします。 

gl.clear(gl.DEPTH_BUFFER_BIT)

もちろん、カラーバッファもクリアする必要があります。ビットごとの OR 記号 (|) を使用して gl.DEPTH_BUFFER_BIT と gl.COLOR_BUFFER_BIT を接続し、パラメータとして gl.clear() に渡します。

同様に、任意の 2 つのバッファを同時にクリアする場合は、ビット単位の OR を使用できます。

gl.enable() 関数に対応するのは gl.disable() 関数で、その仕様は以下の通りで、前者は特定の機能を有効にし、後者は特定の機能を無効にします。

gl.disable() 関数の仕様 

消去面のサンプルコードを非表示にする (DepthBuffer) 

サンプルプログラムはDepthBuffer .js という名前で、WebGL モデルビュー射影行列_ サンザシの木のブログ - CSDN ブログPerspectiveView_mvp.jsをベースに陰面消去に関するコードを追加しています。バッファ内の頂点の順序は変わっていないことに注意してください。プログラムは依然として近く (青)、中央 (黄)、遠方 (緑) の順序で三角形を描画します (ただし、描画順序は逆になります - 青 -> 黄) -> 緑色)実行したプログラムの効果はPerspectiveView_mvpと全く同じで、プログラムコードは以下の通りです。

効果例

DepthBufferを実行すると、プログラムが隠れたサーフェスを正常に削除し、近くにある三角形が遠くの三角形をブロックしていることがわかります。この手順は、視点の位置に関係なく、隠れたサーフェスを削除できることを示しています。3D シーンでは、適切な時点 (通常は各フレームを描画する前) に、隠面の削除を有効にし、深度バッファをクリアする必要があります。

 隠れ面を削除するための前提条件は、可視空間を正しく設定することです。そうでないと、誤った結果が生成される可能性があることに注意してください。ボックス型の正投影空間でも、ピラミッド型の透視投影空間でも、必ず使用する必要があります。

深い対立

隠面の除去は WebGL の複雑かつ強力な機能であり、ほとんどの場合、うまく機能します。ただし、幾何学的な図形やオブジェクトの 2 つの表面が非常に近い場合、次のように表面がまだらに見えるという新たな問題が発生します。この現象をZファイティングといいます。ここで、まったく同じ Z 値を持つ 2 つの三角形を描画してみましょう。

深い対立効果

深い対立の理由 

 深度の競合が発生する理由は、2 つのサーフェスが近すぎるため、深度バッファーの精度が限られているため、どちらが前でどちらが後ろであるかを区別できなくなるためです。厳密に言えば、3D モデルの作成時に頂点の深度値に注意すれば、深度の競合を回避できます。ただし、シーン内に複数の移動オブジェクトがある場合、これを実現することはほとんど不可能です。

WebGL では、この問題を解決するために、ポリゴン オフセットと呼ばれるメカニズムが提供されています。このメカニズムにより、Z 値にオフセットが自動的に追加されます。オフセット値は、観察者の視線に対するオブジェクト表面の角度によって決まります。このメカニズムを有効にするには、次の 2 行のコードのみが必要です。

ポリゴン オフセット機能をオンにするには、次の 2 つの手順に従う必要もあります。

1. ポリゴンオフセットを有効にします。

gl.enable(gl.POLYGON_OFFSET_FILL)

2. 描画前にオフセットの計算に使用するパラメータを指定します。 

gl.polygonOffset(1.0, 1.0)

2 つの競合するオブジェクトを描画している最中に呼び出されます

 ステップ 1 では、ポリゴン オフセットを有効にするために gl.enable() が呼び出されます。この関数は隠れ面の削除を有効にするためにも使用されますが、異なるパラメーターが渡されることに注意してください。手順 2 の関数 gl.polygonOffset() の仕様は次のとおりです。

gl.polygonOffset() 関数の仕様

サンプル プログラムZfightingを考えてみましょう。これは、深さの競合を避けるためにポリゴン オフセットを使用します。 

Deep Conflict サンプルコード (Zfighting)

すべての頂点の Z 座標値は同じ -0.5 (行 80) ですが、深さの競合がないことがわかります。 

コードの残りの部分では、ポリゴン オフセット メカニズムをオンにして (70 行目)、緑色の三角形 (72 行目) と黄色の三角形 (74 行目) を描画します。2 つの三角形のデータは同じバッファーに格納されるため、gl.drawArrays() の 2 番目と 3 番目のパラメーターに特に注意する必要があります。2 番目のパラメーターは描画を開始する頂点の数を表し、3 番目のパラメーターはこの操作で描画される頂点の数を表します。したがって、最初に緑色の三角形を描画し、次に gl.polygonOffset() を通じてポリゴン オフセット パラメータを設定して、後続の描画がポリゴン オフセット メカニズムの影響を受けるようにしてから、黄色の三角形を描画しました。プログラムを実行すると、下の図に示すように、2 つの三角形の間に深さの競合がないことがわかります。73 行目をコメントアウトしてプログラムを再度実行すると、上に示したように、深さの競合が再び表示されます: 深さの競合効果。

効果例

おすすめ

転載: blog.csdn.net/dabaooooq/article/details/132892256