[Unity] UnityのShaderでステンシルバッファを試す

  • 30
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

ステンシルバッファについてはこちらの記事が詳しいです。
ステンシルバッファ | wgld.org

上記サイトから説明を引用させてもらうと、

ステンシル( stencil )は直訳すると[ 型紙 ]や[ 原紙 ]といった意味になる言葉で、3D プログラミングにおいては[ 型抜き ]という意味としてステンシルバッファは利用されています。

ということ。
要は、3Dのオブジェクトにマスクを掛けることができる、というものです。
そして当然、Unityでも同じように処理することが可能です。(Unityのドキュメントはこちら

サンプルコード

Unityのドキュメントに書かれているコードを引用すると、以下のように記述します。

stencile-sample
Shader "Red" {
    SubShader {
        Tags { "RenderType"="Opaque" "Queue"="Geometry"}
        Pass {
            Stencil {
                Ref 2
                Comp always
                Pass replace
                ZFail decrWrap
            }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            struct appdata {
                float4 vertex : POSITION;
            };
            struct v2f {
                float4 pos : SV_POSITION;
            };
            v2f vert(appdata v) {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                return o;
            }
            half4 frag(v2f i) : COLOR {
                return half4(1,0,0,1);
            }
            ENDCG
        }
    } 
}

具体的には

stencile-snipet
Stencil {
    Ref 2
    Comp always
    Pass replace
    ZFail decrWrap
}

の部分がステンシルを実行している箇所です。

解説の詳細は最初に紹介した記事を見ていただいたほうがいいので割愛します。
概要としてはシェーダの役割である「ピクセルに対するレンダリング」を行う際、該当のシェーダのピクセルをレンダリングすべきかどうか、の判断を行うために使われるのがこの ステンシルバッファ です。

つまり、このステンシルバッファを使った「ステンシルテスト」に合格しなかった場合はそのシェーダの該当ピクセルへのレンダリングはたんに無視されます。
そして、現在計算中のピクセルに対してのステンシルテストの結果によって該当ピクセルのステンシル値の値が変更されます。

変更されうるステータスとしては以下の3つがあります。

  • 合格
  • 不合格
  • 合格したが深度テスト不合格

合格/不合格は読んで字のごとくなので問題ないでしょう。
最後の項目は、「ステンシルテストには合格したが、深度テストが不合格でピクセルがレンダリングされなかった場合」にどうするかを決めるものとなります。
(ピクセルがレンダリングされるかどうかは、ステンシル以外にも深度値によるテストがあるためです)

ステンシルの設定については以下の構文になっています。

構文

syntax-stencil
Ref [整数値]
Comp [比較関数]
Pass [合格]
Fail [不合格]
ZFail [合格だが深度テスト不合格]
種類 意味
Ref ステンシル値。比較対象とされる値。
Comp 比較関数。Equalなどいくつかの種類がある。
Pass 合格時にステンシル値をどうするか。
Fail 不合格時にステンシル値をどうするか。
ZFail 合格だが深度テストが不合格だった場合にどうするか。

比較関数

比較関数は以下のものがあります。(ドキュメントから引用)

関数名 意味
Greater 参照値がバッファ値より大きい参照値のピクセルのみレンダリング
GEqual 参照値がバッファ値と等しいまたは大きい参照値のピクセルのみレンダリング
Less 参照値がバッファ値より小さい参照値のピクセルのみレンダリング
LEqual 参照値がバッファ値と等しいまたは小さい参照値のピクセルのみレンダリング
Equal 参照値がバッファ値と等しい参照値のピクセルのみレンダリング
NotEqual 参照値がバッファ値と等しくない参照値のピクセルのみレンダリング
Always 常にステンシル テストは成功
Never 常にステンシル テストは失敗

処理

また、合格時などの処理については以下の項目があります。(ドキュメントから引用)

項目 意味
Keep バッファの現在コンテンツを保持します
Zero バッファにゼロを書き込みます
Replace 参照値をバッファに書き込みます
IncrSat バッファの現在値を増分させる。値がすでに 255 の場合は維持する
DecrSat バッファの現在値を減分させる。値がすでに 0 の場合は維持する
Invert すべてのビットを無効にする
IncrWrap バッファの現在値を増分する。値がすでに 255 の場合は 0 にする
DecrWrap バッファの現在値を減分する。値がすでに 0 の場合は 255 にする