環境
Unity2022.2.14f1
概要
フェイクポイントライトにCubeMapを使用したものです。
Sphereモデルを影響範囲までスケールしたものにシェーダを適用します。
こちらはフェイクなので遮蔽されなかったりしますが、「PRINCIPLES」のランタンのような使い方は効果高いと思います。
コード
Shader "Custom/SSCubeDecalLight" { Properties { [HDR] _Color("Color", Color) = (1, 1, 1, 1) _MainTex("MainTexe", CUBE) = "white" {} _FadeStart("FadeStart", Range(0, 1)) = 0.3 _FadeStrength("FadeStrength", Range(0, 1)) = 0.6 } SubShader { Tags { "RenderType" = "Transparent" "Queue" = "Transparent" } Pass { ZWrite Off ZTest Always Lighting Off Cull Front Blend SrcAlpha One CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" half4 _Color; sampler2D _CameraDepthTexture; sampler2D _CameraDepthNormalsTexture; UNITY_DECLARE_TEXCUBE(_MainTex); float _FadeStart; float _FadeStrength; struct VSInput { float4 vertex : POSITION; float3 texcoord : TEXCOORD0; }; struct VSOut { float4 posCS :SV_POSITION; float4 posSS : TEXCOORD0; float3 rayVS : TEXCOORD1; }; VSOut vert(VSInput v) { VSOut o; o.posCS = UnityObjectToClipPos(v.vertex); o.posSS = ComputeScreenPos(o.posCS); o.rayVS = UnityObjectToViewPos(v.vertex).xyz; o.rayVS.z *= -1; return o; } fixed4 frag(VSOut i) : Color { const float far = _ProjectionParams.z; i.rayVS = i.rayVS * (far / i.rayVS.z); float depth; float3 depthNormalVS; float2 posSS = i.posSS.xy / i.posSS.w; float4 depthAndNormal = tex2D(_CameraDepthNormalsTexture, posSS); DecodeDepthNormal(depthAndNormal, depth, depthNormalVS); depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, posSS); depth = Linear01Depth(depth); float4 depthPosVS = float4(i.rayVS * depth, 1); float3 depthPosWS = mul(unity_CameraToWorld, depthPosVS).xyz; float3 depthPosOS = mul(unity_WorldToObject, float4(depthPosWS, 1.0)).xyz; float3 depthNormalOS = normalize(mul(depthNormalVS, UNITY_MATRIX_MV)); float3 lightDirOS = normalize(-depthPosOS); float NdotL = saturate(dot(depthNormalOS, lightDirOS)); float dist = saturate(length(depthPosOS)); float mask = 1 - dist; float fade = 1.0 - saturate((dist - _FadeStart) / _FadeStrength); fixed3 diffuse = UNITY_SAMPLE_TEXCUBE(_MainTex, -lightDirOS); fixed3 rgb = diffuse * _Color.rgb * mask * NdotL * fade; return fixed4(rgb, 1); } ENDCG } } }
参考
フェイクポイントライト - テキトープログラム( ..)φメモ
フェイクスポットライト - テキトープログラム( ..)φメモ
Texture2D代用版(6面すべて同じ)
Shader "Custom/SSCubeLikeDecalLight" { Properties { [HDR] _Color("Color", Color) = (1, 1, 1, 1) _MainTex("MainTex", 2D) = "white" {} _FadeStart("FadeStart", Range(0, 1)) = 0.3 _FadeStrength("FadeStrength", Range(0, 1)) = 0.6 } SubShader { Tags { "RenderType" = "Transparent" "Queue" = "Transparent" } Pass { ZWrite Off ZTest Always Lighting Off Cull Front Blend SrcAlpha One CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" half4 _Color; sampler2D _CameraDepthTexture; sampler2D _CameraDepthNormalsTexture; sampler2D _MainTex; float _FadeStart; float _FadeStrength; struct VSInput { float4 vertex : POSITION; float3 texcoord : TEXCOORD0; }; struct VSOut { float4 posCS : SV_POSITION; float4 posSS : TEXCOORD0; float3 rayVS : TEXCOORD1; }; VSOut vert(VSInput v) { VSOut o; o.posCS = UnityObjectToClipPos(v.vertex); o.posSS = ComputeScreenPos(o.posCS); o.rayVS = UnityObjectToViewPos(v.vertex).xyz; o.rayVS.z *= -1; return o; } fixed4 frag(VSOut i) : SV_Target { const float far = _ProjectionParams.z; i.rayVS = i.rayVS * (far / i.rayVS.z); float depth; float3 depthNormalVS; float2 posSS = i.posSS.xy / i.posSS.w; float4 depthAndNormal = tex2D(_CameraDepthNormalsTexture, posSS); DecodeDepthNormal(depthAndNormal, depth, depthNormalVS); depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, posSS); depth = Linear01Depth(depth); float4 depthPosVS = float4(i.rayVS * depth, 1); float3 depthPosWS = mul(unity_CameraToWorld, depthPosVS).xyz; float3 depthPosOS = mul(unity_WorldToObject, float4(depthPosWS, 1.0)).xyz; float3 depthNormalOS = normalize(mul(depthNormalVS, UNITY_MATRIX_MV)); float3 lightDirOS = normalize(-depthPosOS); float NdotL = saturate(dot(depthNormalOS, lightDirOS)); float dist = saturate(length(depthPosOS)); float mask = 1 - dist; float fade = 1.0 - saturate((dist - _FadeStart) / _FadeStrength); float3 absLightDirOS = abs(lightDirOS); float2 uv; if (absLightDirOS.x >= absLightDirOS.y && absLightDirOS.x >= absLightDirOS.z) { // Major axis is X if (lightDirOS.x > 0) { // +X face uv = float2(-lightDirOS.z, -lightDirOS.y) / absLightDirOS.x * 0.5 + 0.5; } else { // -X face uv = float2(lightDirOS.z, -lightDirOS.y) / absLightDirOS.x * 0.5 + 0.5; } } else if (absLightDirOS.y >= absLightDirOS.x && absLightDirOS.y >= absLightDirOS.z) { // Major axis is Y if (lightDirOS.y > 0) { // +Y face uv = float2(lightDirOS.x, lightDirOS.z) / absLightDirOS.y * 0.5 + 0.5; } else { // -Y face uv = float2(lightDirOS.x, -lightDirOS.z) / absLightDirOS.y * 0.5 + 0.5; } } else { // Major axis is Z if (lightDirOS.z < 0) { // +Z face uv = float2(lightDirOS.x, -lightDirOS.y) / absLightDirOS.z * 0.5 + 0.5; } else { // -Z face uv = float2(-lightDirOS.x, -lightDirOS.y) / absLightDirOS.z * 0.5 + 0.5; } } fixed3 diffuse = tex2D(_MainTex, uv).rgb; fixed3 rgb = diffuse * _Color.rgb * mask * NdotL * fade; return fixed4(rgb, 1); } ENDCG } } }