環境
Unity2021.2.18f1
概要
テクスチャを使用したコースティクスです。
参考リンクのものを実装しました。ルミナンスマスクは実装していません。
以下のサイトのテクスチャを使用させていただいています。
Water Caustics Effect (Small) | OpenGameArt.org
Shader "Custom/Caustics" { Properties { _CausticsTexture("Caustics Texture", 2D) = "white" {} _CausticsSpeed("CausticsSpeed", float) = 0.05 _CausticsScale("CausticsScale", float) = 3 _CausticsStrength("CausticsStrength", float) = 1 _CausticsSplit("CausticsSplit", float) = 0.002 _CausticsFadeRadius("CausticsFadeRadius", float) = 0.3 _CausticsFadeStrength("CausticsFadeStrength", float) = 0.6 } SubShader { Tags { "RenderType" = "Transparent" "Queue" = "Transparent" //"LightMode" = "ForwardBase" } Pass { ZWrite Off ZTest Always Cull Front Lighting Off Cull Back Blend SrcAlpha One//OneMinusSrcAlpha CGPROGRAM //#pragma multi_compile_fwdbase #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" //#include "AutoLight.cginc" //#include "Lighting.cginc" half4 _Color; sampler2D _CameraDepthTexture; float _CausticsSpeed; float _CausticsScale; float _CausticsStrength; float _CausticsSplit; float _CausticsFadeRadius; float _CausticsFadeStrength; struct VSInput { float4 vertex : POSITION; float3 texcoord : TEXCOORD0; }; struct VSOut { float4 positionCS :SV_POSITION; float4 positionSS : TEXCOORD0; float3 rayVS : TEXCOORD1; float radius : TEXCOORD3; }; half4x4 _MainLightDirection; sampler2D _CausticsTexture; VSOut vert(VSInput v) { VSOut o; o.positionCS = UnityObjectToClipPos(v.vertex); o.positionSS = ComputeScreenPos(o.positionCS); o.rayVS = UnityObjectToViewPos(v.vertex).xyz; o.rayVS.z *= -1; o.radius = length(UNITY_MATRIX_M._m01_m11_m21) * 0.5; return o; } half2 Panner(half2 uv, half speed, half tiling) { return (half2(1, 0) * _Time.y * speed) + (uv * tiling); } half3 SampleCaustics(half2 uv, half split) { half2 uv1 = uv + half2(split, split); half2 uv2 = uv + half2(split, -split); half2 uv3 = uv + half2(-split, -split); half r = tex2D(_CausticsTexture, uv1).r; half g = tex2D(_CausticsTexture, uv2).r; half b = tex2D(_CausticsTexture, uv3).r; return half3(r, g, b); } fixed4 frag(VSOut i) : Color { const float far = _ProjectionParams.z; i.rayVS = i.rayVS * (far / i.rayVS.z); float depth; float3 normalVS; float2 positionSS = i.positionSS.xy / i.positionSS.w; depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, positionSS); depth = Linear01Depth(depth); float4 positionVS = float4(i.rayVS * depth, 1); float3 positionWS = mul(unity_CameraToWorld, positionVS).xyz; /* half4 color = half4(frac(positionWS.xyz), 1.0); #if UNITY_REVERSED_Z if (depth < 0.0001) return half4(0,0,0,1); #else if (depth > 0.9999) return half4(0,0,0,1); #endif */ // calculate position in object-space coordinates float3 positionOS = mul(unity_WorldToObject, float4(positionWS, 1.0)).xyz; /* // create bounding box mask float boundingBoxMask = all(step(positionOS, 0.5) * (1 - step(positionOS, -0.5))); color.rgb = boundingBoxMask; */ half2 uv = mul(positionWS, _MainLightDirection).xy; half2 uv1 = Panner(uv, 0.75 * _CausticsSpeed, 1 / _CausticsScale); half2 uv2 = Panner(uv, 1 * _CausticsSpeed, -1 / _CausticsScale); half3 tex1 = SampleCaustics(uv1, _CausticsSplit); half3 tex2 = SampleCaustics(uv2, _CausticsSplit); half edgeFadeMask = 1 - saturate((distance(positionOS, 0) - _CausticsFadeRadius) / (1 - _CausticsFadeStrength)); half3 caustics = min(tex1, tex2) * _CausticsStrength * edgeFadeMask; return fixed4(caustics, 1); } ENDCG } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; [ExecuteInEditMode] public class Caustics : MonoBehaviour { private Material _causticsMaterial = null; private void OnEnable() { var renderer = GetComponent<Renderer>(); _causticsMaterial = renderer.sharedMaterial; } private void Update() { var sunMatrix = RenderSettings.sun.transform.localToWorldMatrix; _causticsMaterial.SetMatrix("_MainLightDirection", sunMatrix); } }
感想
色収差の部分のテクスチャフェッチは重いので、パラメータの値が決まったら、あらかじめテクスチャのUVにチャンネルごとにオフセットを入れておくと良いと思いました。