hololensの学習枠の続きです。
bluebirdofoz.hatenablog.com
以下の技術ブログを参考にしています。
tips.hecomi.com
今回は「方法1」プロジェクト内のコードを確認して、技術への理解を深めます。
改めてプロジェクトの全体像を確認します。

Sceneタブの視点を遠ざけていくと、巨大な円形のSkyboxオブジェクトがあることが分かります。

アプリが開始すると、SpatialMapping のメッシュが視界を覆います。
SpatialMapping のメッシュに穴を開けて、その奥にある Skybox オブジェクトのメッシュを覗き見るという仕組みです。

視界を遮る SpatialMapping のシェーダと、そこに窓を開ける Window オブジェクトのシェーダを読み解きます。
まずは、視界を遮る SpatialMapping のシェーダです。
・Wall.shader
Shader "HoloLens/Wall"
{
Properties
{
_Mask("Mask", Int) = 1
}
SubShader
{
// タグ付け
Tags
{
// "RenderType(レンダータイプ)"を"Opaque(不透明)"に指定
"RenderType" = "Opaque"
// "Queue(描画順)"を"Geometry(デフォルト)-1"に指定
// Background→Geometry→AlphaTest→Transparent→Overlayの順で描画される。
// つまり通常オブジェクトより背景に近いシェーダとして設定している
"Queue" = "Geometry-1"
}
CGINCLUDE
// "UnityCG.cginc"をインクルード
#include "UnityCG.cginc"
// v2f構造体の定義
// v2fという名前は慣例で Vertex To Fragmentの略
// 頂点シェーダからフラグメントシェーダに複数の値を渡す時に利用する
struct v2f
{
// float4 SV_POSITION MVP 変換後の座標
float4 vertex : SV_POSITION;
// VRのシングルパスステレオレンダリングのマクロ
UNITY_VERTEX_OUTPUT_STEREO
};
// 頂点シェーダ
v2f vert(appdata_base v)
{
// 返り値として利用するv2f構造体の変数を作成
v2f o;
// インスタンス ID がシェーダー関数にアクセス可能になる
UNITY_SETUP_INSTANCE_ID(v);
// VR向けの頂点シェーダーへの変換を行う
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
// 同次座標において、オブジェクト空間からカメラのクリップ空間へ点を変換する
o.vertex = UnityObjectToClipPos(v.vertex);
// 構造体を返す
return o;
}
// フラグメントシェーダ
fixed4 frag(v2f i) : COLOR
{
// 描画するカラーを返却する
// 必ず 0 を返却する
// ただし ColorMask 0 が設定されているため、カラーチャネルは書き込まれない
return 0;
}
ENDCG
Pass
{
// カラーチャネルの書き込みを設定
// ColorMask 0 ですべてのカラーチャネルのレンダリングを無効化
ColorMask 0
// ZWrite:デプスバッファに書き込みするか制御
// 不透明なオブジェクトを描画する場合、On
ZWrite On
// ZTest:デプステストの実行方法
// LEqual:既に描画されているオブジェクトと距離が等しいか、より近い場合に描画する
// それより遠い場合はオブジェクトで隠す
ZTest LEqual
// Stencil:ステンシルバッファはピクセルマスクごとにピクセルを保存や廃棄することを目的とする
// ステンシルバッファは、通常、1 ピクセルあたり 8 ビットの整数である
Stencil
{
// バッファに_Maskの 1 の整数が書き込まれる
Ref [_Mask]
// Comp:関数はバッファの現在の内容と基準値の比較に使用される
// NotEqual:ピクセルのレファレンス値がバッファの値と等しくない場合のみレンダリングする
Comp NotEqual
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 5.0
#pragma only_renderers d3d11
ENDCG
}
}
}次に、壁に穴を開ける Window のシェーダです。
・Window.shader
Shader "HoloLens/Window"
{
Properties
{
_Mask ("Mask", Int) = 1
}
SubShader
{
// タグ付け
Tags
{
// "RenderType(レンダータイプ)"を"Opaque(不透明)"に指定
"RenderType" = "Opaque"
// "Queue(描画順)"を"Geometry(デフォルト)-2"に指定
// つまり先ほどの Wall オブジェクトより先駆けて描画する
"Queue" = "Geometry-2"
}
CGINCLUDE
// "UnityCG.cginc"をインクルード
#include "UnityCG.cginc"
// v2f構造体の定義
// v2fという名前は慣例で Vertex To Fragmentの略
// 頂点シェーダからフラグメントシェーダに複数の値を渡す時に利用する
struct v2f
{
// float4 SV_POSITION MVP 変換後の座標
float4 vertex : SV_POSITION;
// VRのシングルパスステレオレンダリングのマクロ
UNITY_VERTEX_OUTPUT_STEREO
};
// 頂点シェーダ
v2f vert(appdata_base v)
{
// インスタンス ID がシェーダー関数にアクセス可能になる
UNITY_SETUP_INSTANCE_ID(v);
// 返り値として利用するv2f構造体の変数を作成
v2f o;
// 同次座標において、オブジェクト空間からカメラのクリップ空間へ点を変換する
o.vertex = UnityObjectToClipPos(v.vertex);
// VR向けの頂点シェーダーへの変換を行う
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
// 構造体を返す
return o;
}
// フラグメントシェーダ
fixed4 frag (v2f i) : SV_Target
{
// 描画するカラーを返却する
// 必ず 0 を返却する
// ただし ColorMask 0 が設定されているため、カラーチャネルは書き込まれない
return 0;
}
ENDCG
Pass
{
// カラーチャネルの書き込みを設定
// ColorMask 0 ですべてのカラーチャネルのレンダリングを無効化
ColorMask 0
// ZWrite:デプスバッファに書き込みするか制御
// 透明なオブジェクトを描画する場合、Off
ZWrite Off
// Stencil:ステンシルバッファはピクセルマスクごとにピクセルを保存や廃棄することを目的とする
// ステンシルバッファは、通常、1 ピクセルあたり 8 ビットの整数である
Stencil
{
// バッファに_Maskの 1 の整数が書き込まれる
Ref [_Mask]
// Comp:関数はバッファの現在の内容と基準値の比較に使用される
// Always:常にステンシルテストをパスさせる
Comp Always
// Pass:ステンシルテスト(及びデプステスト)をパスした場合、バッファの内容をどうするか決める
// Replace:リファレンス値をバッファに書き込む
Pass Replace
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
}要は Window.shader が先駆けてステンシルバッファに 1 を書き込み。
その後、Wall.shader がステンシルバッファに 1 が書き込まれていない箇所のみ、デプスバッファを設定して背景の Skybox の描画を遮蔽しています。
以下の記事も参考になります。
tips.hecomi.com
次回は、方法2の動作と仕組みについて理解します。
bluebirdofoz.hatenablog.com