如何让Unity投影焦散Shader在阴影中不可见并贴近真实光线
解决水下焦散Shader的真实感提升与阴影隐藏问题
嘿,很高兴能帮你优化这个焦散投影Shader!针对你想要的更贴近真实光线和阴影区域不可见这两个需求,我给你整理了具体的修改方案,完全不用你自己从头写Shader,就在你现有代码基础上改就行~
一、先搞定「阴影区域不可见」的核心需求
要让焦散在阴影里消失,我们需要让Shader能读取当前像素的阴影信息,然后根据阴影强度把焦散颜色衰减到0。Unity提供了现成的阴影采样工具,咱们直接加进去:
修改思路:
- 在顶点着色器里传递阴影坐标
- 片段着色器中采样阴影贴图,用阴影值控制焦散的可见度
二、提升真实感的几个关键优化
真实的水下焦散有几个特点,咱们针对性调整:
- 焦散是光线聚焦的加亮效果,不是和底色混合,所以要改混合模式
- 水下越深,光线被水吸收越多,焦散应该越弱
- 焦散边缘要柔和过渡,避免硬 cutoff
- 可以调整默认颜色为更贴近水下的淡蓝色
三、修改后的完整Shader代码
我把所有修改都整合到你的原代码里了,每处修改都加了注释说明:
Shader "Projector/Caustics" { Properties { _Color ("Caustics Color", Color) = (0.2, 0.8, 1.0, 0) // 改成水下淡蓝色,更真实 [NoScaleOffset]_MainTex ("Caustics Texture", 2D) = "black" { } _Size ("Grid Size", Float) = 10 _Height ("Water Height", Float) = 2.0 _DepthBlend ("Depth Attenuation", Float) = 10.0 // 重命名更直观 _EdgeBlend ("Above Water Fade", Range (0, 100)) = 0.5 _Multiply ("Intensity", Range (0.5, 3)) = 1.5 // 调整范围更合理 _LOD ("LOD Bias", Range (1, 1000)) = 100 _ShadowFade ("Shadow Fade Strength", Range(0, 1)) = 1.0 // 新增:阴影中衰减的强度 } Subshader { Tags { "RenderType"="Transparent" "Queue"="Transparent+100" } Pass { ZWrite Off Offset -1, -1 Blend One One // 改成线性减淡,模拟真实焦散的亮度叠加效果 CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_fog #pragma multi_compile_shadowcaster // 新增:启用阴影编译支持 #include "UnityCG.cginc" #include "UnityLightingCommon.cginc" // 新增:引入阴影采样工具 struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float3 wPos : TEXCOORD1; UNITY_FOG_COORDS(2) UNITY_SHADOW_COORDS(3) // 新增:存储阴影坐标的变量 }; uniform sampler2D _MainTex; float4 _MainTex_ST; float4 _Color; float4x4 unity_Projector; float _Size; float _Height; float _DepthBlend; float _EdgeBlend; float _Multiply; float _LOD; float _ShadowFade; v2f vert (appdata_tan v) { v2f o; o.pos = UnityObjectToClipPos (v.vertex); o.wPos = mul(unity_ObjectToWorld, v.vertex).xyz; o.uv = TRANSFORM_TEX (mul (unity_Projector, v.vertex).xy, _MainTex); UNITY_TRANSFER_FOG(o,o.pos); UNITY_TRANSFER_SHADOW(o, v.vertex) // 新增:计算并传递阴影坐标 return o; } fixed4 frag (v2f i) : COLOR { float dist = distance(_WorldSpaceCameraPos, i.wPos); // 保持你的平铺纹理采样逻辑 fixed4 caustic = tex2Dlod (_MainTex, float4(fmod (i.uv, 1 / _Size)*_Size, 0, dist/_LOD)); // 1. 阴影衰减:阴影越浓,焦散越淡 fixed shadowAtten = UNITY_SHADOW_ATTENUATION(i, i.wPos); caustic.rgb *= lerp(1.0, shadowAtten, _ShadowFade); // 2. 深度衰减:水下越深,焦散越弱(优化为更平滑的过渡) if (i.wPos.y < _Height) { float depthFactor = saturate((_Height - i.wPos.y) / _DepthBlend); caustic.rgb *= depthFactor; } // 3. 水面上方淡入:保留原逻辑,用saturate避免颜色异常 else { float aboveFactor = saturate(1 - (i.wPos.y - _Height)/_EdgeBlend); caustic.rgb *= aboveFactor; } // 4. 应用最终颜色和雾效 caustic = saturate(caustic); UNITY_APPLY_FOG_COLOR(i.fogCoord, caustic, fixed4(0,0,0,0)); return caustic * _Color * _Multiply ; } ENDCG } } }
四、关键修改点说明
阴影处理:
- 加入
#pragma multi_compile_shadowcaster宏,让Shader支持阴影采样 - 通过
UNITY_SHADOW_COORDS和UNITY_TRANSFER_SHADOW传递阴影坐标 - 用
UNITY_SHADOW_ATTENUATION获取当前像素的阴影值,新增的_ShadowFade参数可以控制阴影中焦散消失的强度(设为1时完全消失,设为0时不受阴影影响)
- 加入
真实感优化:
- 混合模式改成
Blend One One,模拟真实焦散的亮度叠加效果,而非颜色混合 - 默认颜色调整为淡蓝色,更贴近水下环境
- 优化深度衰减逻辑,用
saturate确保参数值在0-1范围内,避免颜色异常 - 调整参数范围和命名,更直观好调试
- 混合模式改成
内容的提问来源于stack exchange,提问作者Trafel
相关产品推荐
相关产品推荐

