Unity
Shader
HLSL

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

More than 3 years have passed since last update.

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

ステンシルバッファ | 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 にする