デプステクスチャを用いてアウトラインを描画する方法です。
考え方
デプステクスチャの取得の仕方は下の記事と同様です。
デプスからアウトラインを取る方法は下の記事を参考にさせていただいています。
要は近隣のピクセルとの深度値が大幅に違えばそこをアウトラインとみなすという考え方です。
実装
まずはシェーダです。
ポストエフェクトで使うので、そのためのシェーダとして書きます。
Shader "DepthOutline" { SubShader { Cull Off ZTest Always ZWrite Off Tags { "RenderType"="Opaque" } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _CameraDepthTexture; float4 _CameraDepthTexture_ST; float4 _CameraDepthTexture_TexelSize; float _OutlineThreshold; float4 _OutlineColor; float _OutlineThick; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _CameraDepthTexture); return o; } fixed4 frag (v2f i) : SV_Target { float diffX = _CameraDepthTexture_TexelSize.x * _OutlineThick; float diffY = _CameraDepthTexture_TexelSize.y * _OutlineThick; float col00 = Linear01Depth(tex2D(_CameraDepthTexture, i.uv + half2(-diffX, -diffY)).r); float col10 = Linear01Depth(tex2D(_CameraDepthTexture, i.uv + half2(0, -diffY)).r); float col01 = Linear01Depth(tex2D(_CameraDepthTexture, i.uv + half2(-diffX, 0)).r); float col11 = Linear01Depth(tex2D(_CameraDepthTexture, i.uv + half2(0, 0)).r); float outlineValue = (col00 - col11) * (col00 - col11) + (col10 - col01) * (col10 - col01); clip(outlineValue - _OutlineThreshold); return _OutlineColor; } ENDCG } } }
次にスクリプトです。
using UnityEngine; using UnityEngine.Rendering; [RequireComponent(typeof(Camera))] public class DepthTexture : MonoBehaviour { [SerializeField] private Shader _shader; [SerializeField] private float _outlineThreshold = 0.01f; [SerializeField] private Color _outlineColor = Color.white; [SerializeField] private float _outlineThick = 1.0f; private Material _material; private void Awake() { Initialize(); } private void Update() { #if UNITY_EDITOR SetMaterialProperties(); #endif } private void Initialize() { var camera = GetComponent<Camera>(); camera.depthTextureMode |= DepthTextureMode.Depth; if (camera.allowMSAA || camera.allowHDR) { return; } _material = new Material(_shader); SetMaterialProperties(); var commandBuffer = new CommandBuffer(); int tempTextureIdentifier = Shader.PropertyToID("_PostEffectTempTexture"); commandBuffer.GetTemporaryRT(tempTextureIdentifier, -1, -1); commandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, tempTextureIdentifier); commandBuffer.Blit(tempTextureIdentifier, BuiltinRenderTextureType.CurrentActive, _material); commandBuffer.ReleaseTemporaryRT(tempTextureIdentifier); camera.AddCommandBuffer(CameraEvent.AfterEverything, commandBuffer); } private void SetMaterialProperties() { if (_material != null) { _material.SetFloat("_OutlineThreshold", _outlineThreshold); _material.SetColor("_OutlineColor", _outlineColor); _material.SetFloat("_OutlineThick", _outlineThick); } } }
スクリプトはデプステクスチャ取得の記事にあるものを少し書き換えたものになります。
結果
スクリプトをカメラにアタッチして、シェーダの参照を持たせます。
次のようなシーンを用意します。
再生をすると、
アウトラインが描画されました。
スクリプトのパラメータを編集すれば各Cubeが重なっている部分にもアウトラインを引けます。