深度値を使ったソフトパーティクルのシェーダを書いてみました。
Unity2019.2.10
ソフトパーティクル?
ソフトパーティクルとは、パーティクルが他の物体に近づいたときに、
他の物体に近い部分を半透明にフェードさせる仕組みです。
これにより、地面や壁に近いパーティクルの不自然さを解消できます。
本記事ではこのソフトパーティクルを実装する方法をまとめます。
シェーダ
それでは早速シェーダを書いてみます。
Shader "SoftParticle" { SubShader { Tags{ "Queue" = "Transparent" "RenderType" = "Transparent" } Blend SrcAlpha OneMinusSrcAlpha ColorMask RGB Cull Back Lighting Off ZWrite Off Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; }; struct v2f { float4 vertex : SV_POSITION; float4 projPos : TEXCOORD0; half depth : TEXCOORD1; }; sampler2D _CameraDepthTexture; #define INV_INTENSITY 1.0 v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.projPos = ComputeScreenPos(o.vertex); COMPUTE_EYEDEPTH(o.depth); return o; } fixed4 frag (v2f i) : SV_Target { half bgDepth = LinearEyeDepth(tex2Dproj(_CameraDepthTexture, i.projPos).r); float alpha = saturate((bgDepth - i.depth) * INV_INTENSITY); return fixed4(1, 1, 1, alpha); } ENDCG } } }
やっていることはシンプルで、_CameraDepthTextureに書かれた深度値と
今描画しようとしている部分の深度値を比較して、近かったら半透明にしています。
_CameraDepthTextureから深度値を取る方法は以下の記事にまとめていますので、必要に応じて参照してください。
また、描画地点の深度値を取得する方法は以下の記事にまとめています。
こちらも必要に応じて参照してください。
結果
まず、プラットフォームによっては深度テクスチャが生成されていない場合があるので、
CameraのdepthTextureModeを下記のように変更しておきます。
using UnityEngine; public class DepthTexture : MonoBehaviour { void Start () { GetComponent<Camera>().depthTextureMode |= DepthTextureMode.Depth; } }
深度テクスチャを生成した上で前節のシェーダをパーティクルに適用すると以下のような結果となります。
正常にソフトパーティクルが描画されていることが確認できました。