【UnityShader】デプスバッファを可視化する #26
前回の成果
今回やること
デプスバッファを可視化しようと思います。
デプスバッファ(深度バッファ・Zバッファ)とは、カメラからオブジェクトまでの距離を格納したバッファとなります。
下記の記事で解説したのですが、可視化までは行っていなかったので今回やっていきます。
事前準備
Scene上にオブジェクトを複数個配置し、Z座標をズラしてください。
また今回はmaterialをオブジェクトにアタッチしないでください。
そして、PostEffect.csをCameraにアタッチして、_shaderには今回製作したものをアタッチしてください。
ソースコード
Shaderのコード
Shader "Unlit/depthEffect" { SubShader { Tags { "RenderType" = "Opaque"} LOD 200 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" sampler2D _CameraDepthTexture; float4 _CameraDepthTexture_ST; struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; }; v2f vert(appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _CameraDepthTexture); return o; } fixed4 frag(v2f i) : COLOR{ return UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture, i.uv)); } ENDCG } } }
fragで何を返しているのかがいまいちわかりません。
Scriptのコード
using UnityEngine; [ExecuteInEditMode, RequireComponent(typeof(Renderer))] public class PostEffect : MonoBehaviour { [SerializeField] private Shader _shader; private Material _material; void Start() { GetComponent<Camera>().depthTextureMode |= DepthTextureMode.Depth; _material = new Material(_shader); } void OnRenderImage(RenderTexture source, RenderTexture dest) { Graphics.Blit(source, dest, _material); } }
こちらもいまいちよくわかりません。
ひとつずつ紐解いていきます。
_CameraDepthTexture
これはデプステクスチャを取得できる変数です。
デプステクスチャ
これは各ピクセルが高い精度の0~1のデプス値をもっているテクスチャです。
TRANSFORM_TEX
この記事でも説明した通り、テクスチャのスケールとオフセットを適応するものです。
また、float4やhalf4のテスクチャ名_STが必要になります。
今回の場合は
float4 _CameraDepthTexture_ST;
これです。
UNITY_SAMPLE_DEPTH
非線形深度データを線形スケールに変換するものです。
Unityの公式にもリファレンスがないのでおまじないだと思って大丈夫です。
詳しくはこちらのサイト様に乗っています。
DepthTextureMode
これがないとデプステクスチャが生成されず、_CameraDepthTextureに値が代入されないので気をつけてください。
変数名 | 用途 |
---|---|
None | デプステクスチャを生成しない(デフォルト) |
Depth | デプステクスチャを生成する |
DepthNormals | 深度と法線を組み合わせたテクスチャを生成する |
MotionVectors | モーションベクターをレンダリングするかを指定する |
モーションベクターとは、オブジェクトが前フレームからどれだけ移動したかをベクトルで表したものです。
今回のデプスバッファとは関係ないので詳しくはこちらのサイト様を参考にしてください。
ORしている理由
ORとはビット演算のことです。
DepthTextureModeは複数の状態を持てるので、ORをしています。
// |= がOR
GetComponent<Camera>().depthTextureMode |= DepthTextureMode.Depth;
ビット演算について触れると長くなってしまうのでこちらのサイト様を参考にしてください。
OnRenderImage,Graphics.Blit
この関数はカメラによるレンダリングが完了した時に呼ばれるものです。
void OnRenderImage(RenderTexture source, RenderTexture dest)
sourceには、入力となる画像が入っています。
destには出力先の画像が渡されます。
sourceのtextureからMeshを生成して、destへ描画すれば良いのですがそれを自動でやってくれる関数がBlitになります。
Graphics.Blit(source, dest, _material);
Blitを用いることによって、sourceにmaterialをアタッチしたものをdestに渡すことができます。
ちなみに第2引数をnullにすることで画面をレンダリング対象にすることもできます。
結果
かなりわかりにくいですが、各オブジェクトのZ座標によって色が変わっています。
ソースコードにコメントを付与
Shaderのコード
Shader "Unlit/depthEffect" { SubShader { // 一般的なShaderを使用 Tags { "RenderType" = "Opaque"} // しきい値 LOD 200 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" // デプステクスチャを取得 sampler2D _CameraDepthTexture; // TRANSFORM_TEXを使用するのに必要 float4 _CameraDepthTexture_ST; struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; }; v2f vert(appdata v) { v2f o; // クリップ座標に変換 o.vertex = UnityObjectToClipPos(v.vertex); // テクスチャのスケールとオフセットを適応 o.uv = TRANSFORM_TEX(v.uv, _CameraDepthTexture); return o; } fixed4 frag(v2f i) : COLOR{ // 非線形深度データを線形スケールに変換 return UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture, i.uv)); } ENDCG } } }
Scriptのコード
using UnityEngine; public class PostEffect : MonoBehaviour { [SerializeField] private Shader _shader; private Material _material; void Start() { // デプステクスチャの生成 GetComponent<Camera>().depthTextureMode |= DepthTextureMode.Depth; _material = new Material(_shader); } // カメラによるレンダリング終了時に呼ばれる void OnRenderImage(RenderTexture source, RenderTexture dest) { // sourceのtextureを元に、_marerialを使用してdestに書き出し Graphics.Blit(source, dest, _material); } }
今回はここまでです。 ご視聴ありがとうございました。