ステンシルバッファ
ステンシル( stencil )は直訳すると 型紙 や 原紙 といった意味になる言葉で、3D プログラミングにおいては 型抜き という意味としてステンシルバッファは利用されています。
ステンシルバッファ上のデータは全て整数値によって管理されます。
要は、この部分は型を抜く、別の部分は型を抜かない、といったように特定のフラグメントをレンダリングするべきか否かを決定する権限を持っているのです。
ステンシルバッファに対して設定された基準値は、ステンシルテストに使われます。
ステンシルテストは テスト の名が示すように
対象のピクセルにレンダリングを行なうか否かを決定するための評価を行ないます。
このステンシルテストの評価方法を決めるのがstencilFuncメソッドです。
このメソッドは三つの引数を取り、記述例を示すと以下のようになります。
stencilFunc メソッドの記述例
gl.stencilFunc(gl.ALWAYS, ref, mask);
第一引数
table:stencilFuncの引数
定数名 意味
gl.ALWAYS 常にステンシルテストを通過する
gl.NEVER 常にステンシルテストを通過しない
gl.LESS ref & mask < pixel & mask のとき通過する
gl.LEQUAL ref & mask <= pixel & mask のとき通過する
gl.EQUAL ref & mask == pixel & mask のとき通過する
gl.NOTEQUAL ref & mask != pixel & mask のとき通過する
gl.GREATER ref & mask > pixel & mask のとき通過する
gl.GEQUAL ref & mask >= pixel & mask のとき通過する
ref はstencilFuncメソッドの第二引数に指定した値です。
整数値
pixel というのはステンシルテストを行なったその瞬間に、ステンシルバッファに書き込まれている基準値です。
基準値の書き込み
ステンシルバッファに基準値を書き込む
ステンシルバッファに対して何かしらの値を書き込むには、
どのように値を書き込むのかルールを決めてやり、その上で実際にレンダリングを行ないます。
たとえば
A の場合には 1 を書き込みなさい
とルールをあらかじめ決めた上でなにかのモデルをレンダリングするとします。
そのモデルがレンダリングされる対象ピクセルが A の条件を満たしていると、ステンシルバッファ上の対象ピクセルに 1 という基準値が書き込まれます。
この基準値をどう扱うのかというルールはstencilOpメソッドによって自由に指定することができます。
このメソッドは引数を三つ取ります。記述例は以下のような感じです。
gl.stencilOp(fail, zfail, zpass);
第一引数の fail は、ステンシルテストが不合格だった場合に基準値をどう扱うのかを指定します。
第二引数はステンシルテストには合格したけれども、深度テストが不合格だった場合に基準値をどう扱うのか指定します。
第三引数はステンシルテストも深度テストも双方共に合格だった場合の指定です。
table:引数
定数名 意味
gl.ZERO 基準値を 0 にする
gl.KEEP 現状の基準値を維持する
gl.REPLACE 直前の stencilFunc メソッドで指定された ref の値を基準値として設定する
gl.INCR 現在の基準値をインクリメント( +1 )する
gl.DECR 現在の基準値をデクリメント( -1 )する
gl.INVERT 現在の基準値をビット反転する
gl.INCR_WRAP 現在の基準値をインクリメント( +1 )するが最大値を超えた場合には 0 に戻す
gl.DECR_WRAP 現在の基準値をデクリメント( -1 )するが 0 を下回る場合には最大値に設定する
有効化
他のデプステストとかと違い、初期化時に有効化が必要
コンテキストの初期化処理をステンシルバッファ有効で行なう
var gl = canvas.getContext('webgl', {stencil: true}) ;
そのうえでgl.enable(gl.STENCIL_TEST);
depthと同様に、clear時にbit指定する必要がある
gl.STENCIL_BUFFER_BIT
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
ステンシルバッファを初期化する際には、必ずしも 0 に初期化されるわけではありません。
初期化される際にどのような基準値が設定されるようにするのかはclearStencilメソッドを使って自由に設定することが可能です。
gl.clearStencil(0)
特に理由がなければ0
https://gyazo.com/5c3c64a45bb90d5d7f989ab94c5dfb42
3枚めは存在するが、ステンシルバッファで区切ってしまう
一枚目のポリゴン:Z 軸を奥側にずらしてレンダリング
gl.stencilFunc(gl.ALWAYS, 1, ~0);
gl.stencilOp(gl.KEEP, gl.REPLACE, gl.REPLACE);
二枚目のポリゴン:Z 値は 0.0
gl.stencilFunc(gl.ALWAYS, 0, ~0);
gl.stencilOp(gl.KEEP, gl.INCR, gl.INCR);
三枚目のポリゴン:Z 軸は手前にずらしてレンダリング
gl.stencilFunc(gl.EQUAL, 2, ~0);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
glslじゃないがわかりやすい
内容を考えると、深度テストをプログラマブルにしたという感じ