なんとかするから、なんとかなる

エンジニア関係のことを書きます

Unityのステンシルバッファを使ってみた

Unityのステンシルバッファ(stencil buffer)を使ってみました

ステンシルバッファ

ステンシルバッファとは

レンダリングを実行する際に、各ピクセルに対してレンダリング実行時の条件をバッファしておくもの。

あるピクセルに対して、レンダリングを許可するかを判断する基準となる値を設定する

ステンシルテスト

基準値を元にピクセルレンダリングを実行するかを決定する。 下記の関数で評価方法を決定する

gl.stencilFunc(gl.ALWAYS, ref, mask);
  • 第一引数: ステンシルテストの通過条件(第二引数と基準値の比較など)
  • 第二引数: 第一引数の通過条件を計算するため比較値
  • 第三引数: ステンシルテストの最初の段階でmask値とrefやpixelの間でAND演算(ビット演算)を実施する

基準値の書き込み

あらかじめ決められたルールに従って、基準値を書き込む。 下記の関数でルールを設定する。

gl.stencilOp(fail,zfail,zpass);
  • 第一引数: ステンシルテストが不合格だった場合の基準値の扱い方
  • 第二引数: ステンシルテストは合格だが、深度テストが不合格だった場合の基準値の扱い方
  • 第三引数: ステンシルテストおよび深度テスト双方共合格だった場合の基準値の扱い方

ステンシルバッファを有効にする

ステンシルバッファは明示的にWebGLコンテキストの初期化時に生成を宣言しなければならない

1.ステンシルバッファを内部的にで生成

var gl = canvas.getContext('webgl',{stencil: true}) || canvas.getContext('experimental-webgl', {stencil: true});

2.WebGLに対して、有効化

gl.enable(gl.STENCIL_TEST);

3.レンダリングされるたびに毎回クリアするように設定する

gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);

4.初期化する際の値を設定するには

gl.clearStencil(0)

個人の考察

ステンシルバッファの営み

  1. はじめに基準値を設定する。大体の場合0
  2. その後、各テクスチャに応じてステンシルテストを実施する。ここで、カメラからみたあるピクセルの位置にテクスチャが重なっている場合基準値は伝搬する。
  3. ステンシルテストの結果に応じてstencilOpにより基準値を更新する

上記の基準値が伝搬することで、各テクスチャに対して透過するかなどを制御することができる。

個人的なQA

  • Q1.どうやってはじめの基準値を設定するのか → はじめは0
  • Q2.いつステンシルテストは終了となるのか → すべてのテクスチャに対してテストが完了したとき。
  • Q2-1.ステンシルテスト後に基準値を塗り替えるが、ステンシルテストは1度だけではないのか?複数のレンダリングが実施されるため? → 複数のテクスチャに対して基準値が伝搬するため。

ステンシルテストが実施される順序

  • カメラから見て奥から手前に向かって順序よく。

参考URL

大変勉強になりました。