カリングと深度テスト
今回のサンプルの実行結果
ポリゴンの表と裏とカリングと
前回はインデックスバッファ、いわゆる IBO を用いたレンダリングについて解説しました。インデックスバッファを用いることで、頂点を使いまわしながら効率よく描画できるのでしたね。今後のテキストでは、特別な理由が無い限りは基本的にインデックスバッファを用いて drawElements
による描画を行ないますので、そのつもりで。
さて、今回はカリングと深度テストについて解説します。派手さはありませんが、地味に重要な概念である両者。内容的にはそれほど難しくはないと思いますので、落ち着いて考えていきましょう。
さてまずはカリングについてです。当サイトのテキストを最初から読み進めてきている人なら既にこの[ カリング ]という言葉は聞いたことがあるはずです。以前のテキスト(頂点とポリゴン)でもカリングについて説明しているからですね。
簡単に概要を示すとするなら、カリングとはポリゴンの裏表を判断基準にそのポリゴンをレンダリングするかどうか判断する機構のことです。ポリゴンの裏と表を判断する方法など、詳細は以前のテキストで解説していますので、そちらを見ていただくと理解が深まると思います。
WebGL の場合は既定ではカリングが無効になっているため、どのような順序で頂点を定義しても全てのポリゴンが描画されます。ただし、カリングを有効にした場合には、特定の条件を満たしたポリゴンしか画面上には描画されなくなります。見えない部分のポリゴンを描画しないようにすることで、座標演算などの負荷を軽減できるわけですね。
WebGL でカリングを有効にするには enable
メソッドに適切な引数を与えて呼び出します。この enable
メソッドは、カリングだけでなく様々なパラメータを有効にする際に利用するメソッドで、与えられた引数に応じて指定された機能を有効化します。
カリングを有効にする場合には、 enable
メソッドに組み込み定数 gl.CULL_FACE
を与えます。コードの例を示すと以下のようになりますね。
カリングを有効にするコードの例
gl.enable(gl.CULL_FACE);
逆に、特定の機能を無効化したい場合には disable
メソッドを使います。与える引数は enable
メソッドと同じ組み込み定数を使い、機能を無効化します。
カリングの裏表を切り替える方法
頂点を結ぶ順序でポリゴンの裏表を判断するカリングですが、ときには、その判断基準を逆転したいケースが出てくることもあります。既定値では、ポリゴンを形成する頂点を結ぶ順序が、時計回りの場合に裏、反時計回りの場合に表というふうに判断されます。これを逆に、時計回りを表として判断するようにしたいということですね。
時計回りのことを通称して CW と呼んだりします。これは[ 時計回り ]の英語訳が ClockWise であり、その頭文字をとってのことです。また反時計回りのことは CCW と呼びます。これも、英語表記した場合の CounterClockWise の頭文字をとっているわけですね。WebGL にはカリングの裏表の判断基準を変更するためのメソッドもキチンと用意されています。それが frontFace
メソッドです。引数に与える組み込み定数は、先ほど説明した CW と CCW に由来するものです。
時計回りを[ 表 ]にする:gl.frontFace(gl.CW);
時計回りを[ 裏 ]にする(既定値):gl.frontFace(gl.CCW);
深度テストとは
さて続いては深度テストです。
先ほどのカリングを設定するところで登場した enable
メソッドは、実は深度テストを有効化するのにも使います。組み込みの定数である gl.DEPTH_TEST
を引数に与えて enable
メソッドを呼び出すことで深度テストを有効にできます。また、同じように disable
メソッドで無効化させることも可能です。
深度テストは、既定では無効になっています。そして、深度テストを有効にすると、いったいどういうことが起こるのでしょうか。そもそも、どうして深度テストが必要なのでしょう。
深度テストは[ 深度 ]という言葉からも連想できるように、三次元空間の奥行きを表現するために欠かせない要素の一つです。DirectX では Z テストなどと呼ばれたりもしますが、要は手前にあるものが奥にあるものを覆い隠すという現実世界では当たり前のように起こっていることをシミュレートするためなどに、深度テストが必要になります。
WebGL のなかで描画命令が発行されると、仮想的な三次元空間上に次々とモデルが描画されていきます。ただしこのとき、描画されたものが順番に配置されていくため、最初のほうに描画されたものは後から描画されたものによってどんどん上書きされていきます。これはモデルが手前にあろうが奥にあろうが変わりません。実際には遠くのほうにあるはずのモデルが、手前にあるはずのモデルの上に上書きされていってしまうのですね。
深度テストが有効にされると、奥行きを基準とした評価(テスト)が行なわれるようになります。テストに合格したものだけが画面上に描画され、テストに合格できなかったものは描画されないようになるわけです。
先ほども書いたように、カリングの場合と同様、深度テストを有効にする場合にも enable
メソッドを利用します。引数として与える組み込み定数は gl.DEPTH_TEST
を指定します。やはり、無効にする場合には disable
メソッドを利用します。この辺はカリングのときと同じですね。
深度テストを有効にするコードの例
gl.enable(gl.DEPTH_TEST);
深度テストの評価方法を指定するのが depthFunc
メソッドです。このメソッドの引数に、組み込みの定数で評価方法を指定するのですが、一般的には次の組み込み定数を使います。
一般的な深度テストの評価方法指定
gl.depthFunc(gl.LEQUAL);
ここで指定されている gl.LEQUAL
という組み込み定数を使うと、奥にあるものが隠れるという一般的な三次元シミュレートが実現できます。逆に言うと、あまりこれ以外の指定をすることはないでしょう。
まとめ
今回はカリングと深度テストについて解説しましたが、いずれも同じ enable
メソッドによって有効化でき、 disable
メソッドによって無効化できます。この enable
と disable
の両メソッドは他のパラメータでも使うことがある汎用的なメソッドで、引数として与えた組み込み定数の内容によって、様々なパラメータが有効化・無効化されます。
カリングを有効にすることで、裏を向いているポリゴンは描画されなくなります。これにより負荷を軽減することができるわけですね。深度テストは奥行きのある三次元空間をシミュレートするために非常に重要な役割があり、正しく評価方法を指定することで、奥にあるものが手前にあるものによって遮られるという現実世界では当たり前のように起こっていることをシミュレートすることが可能です。
今回作成したサンプルでは、カリングの有効化と無効化、またポリゴンの表と裏の指定を自由に切り替えることができるようにしました。サンプルページにあるチェックボックスをオンオフすることで、リアルタイムにパラメータを変更できます。
さらに、深度テストについても有効化と無効化を自由に切り替えられるようにしています。サンプルを実際に動作させながら観察すると、カリングや深度テストについて理解が深まるでしょう。
サンプルの内容を補足
サンプルでは四角形のポリゴンを描画するようにプログラムしてあります。また、描画される四角形は二つあり、一つは X 軸による回転を行い、もう一つは Y 軸による回転を行なっています。この二つの四角形は、原点を中心に円運動しながら移動します。深度テストを有効にすれば、奥にある四角形は手前にある四角形によってキチンと隠れるようになるはずです。
また、サンプルのコードをよく見ればわかりますが、この四角形を形成するポリゴンは表向きと裏向きの二つのポリゴンによって形成されています。つまり、カリングを有効にすることによって、上下のどちらかのポリゴンは描画されなくなります。
頂点を結ぶ順序は、インデックスバッファのための配列を定義している部分を見るとよくわかると思います。抜粋したコードが以下です。
インデックスの配列を定義している部分の一部を抜粋
// 頂点属性を格納する配列
var position = [
0.0, 1.0, 0.0,
1.0, 0.0, 0.0,
-1.0, 0.0, 0.0,
0.0, -1.0, 0.0
];
// 頂点のインデックスを格納する配列
var index = [
0, 1, 2,
1, 2, 3
];
画像とコードをよく見比べると、表と裏の二つのポリゴンによって四角形が作られていることがわかるでしょう。今回のサンプルでは、カリングの効果をわかりやすくするために、あえてこのような表と裏の両方の属性を持つポリゴンを使って四角形を描画するようにしています。普通、3D モデルを作成する際にはこのような表と裏を混ぜたような頂点定義はしません。カリングによってモデルが穴だらけになってしまっては台無しですものね。
今回のサンプルは以下のリンクから実際に動作させることができます。