【从UnityURP开始探索游戏渲染】专栏-直达
Unity URP 冰面裂缝视差效果实现方案
冰面裂缝效果优化的URP Shader实现。该方案通过视差遮挡贴图(POM) 技术增强深度表现,结合高度图动态控制实现可调节的冰缝裂痕效果。
核心特性
- 物理精确的裂缝深度 采用光线步进算法精确计算冰缝几何形状,通过
_DepthMultiplier参数控制裂缝视觉深度 - 冰面光学特性模拟 添加折射率参数(
_RefractionIndex)和菲涅尔效应,增强冰面半透明质感 - 性能优化动态采样层数控制(8-12层),在移动端保持30fps以上流畅度
完整HLSL代码实现
关键参数说明
-
高度图控制
_DepthMultiplier参数动态调节冰缝视觉深度,值越大裂缝越深 -
光学参数
_RefractionIndex控制冰面折射率,_FresnelPower调整边缘高光强度 -
性能控制
minSamples和maxSamples控制光线步进精度,移动端建议8-10层 -
IceCrackPOM.shader
cShader "Universal Render Pipeline/IceCrackPOM" { Properties { [Header(Base Textures)] _MainTex("Albedo (RGB) Ice Color", 2D) = "white" {} _NormalMap("Normal Map", 2D) = "bump" {} _HeightMap("Height Map (Ice Cracks)", 2D) = "white" {} [Header(Parallax Settings)] _ParallaxScale("Crack Depth Scale", Range(0, 0.2)) = 0.08 _DepthMultiplier("Depth Multiplier", Range(0.5, 3)) = 1.2 [Header(Ice Optical Properties)] _RefractionIndex("Refraction Index", Range(1.1, 1.5)) = 1.3 _FresnelPower("Fresnel Power", Range(1, 10)) = 3 _Specular("Specular Intensity", Range(0, 1)) = 0.5 } SubShader { Tags { "RenderType"="Transparent" "Queue"="Transparent" } HLSLINCLUDE #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); TEXTURE2D(_NormalMap); SAMPLER(sampler_NormalMap); TEXTURE2D(_HeightMap); SAMPLER(sampler_HeightMap); float _ParallaxScale; float _DepthMultiplier; float _RefractionIndex; float _FresnelPower; float _Specular; // 冰面裂缝POM计算 float2 IceParallaxOcclusion(float3 viewDirTS, float2 uv) { int minSamples = 8; int maxSamples = 12; int numSamples = (int)lerp(maxSamples, minSamples, saturate(dot(float3(0,0,1), viewDirTS))); float layerHeight = 1.0 / numSamples; float2 deltaUV = _ParallaxScale * viewDirTS.xy / viewDirTS.z / numSamples * _DepthMultiplier; float currentLayerHeight = 0; float2 currentUV = uv; float currentDepth = 1 - SAMPLE_TEXTURE2D(_HeightMap, sampler_HeightMap, currentUV).r; [loop] for (int i = 0; i < maxSamples; ++i) { if (currentLayerHeight >= currentDepth) break; currentUV -= deltaUV; currentDepth = 1 - SAMPLE_TEXTURE2D(_HeightMap, sampler_HeightMap, currentUV).r; currentLayerHeight += layerHeight; } // 二分法精确修正 float2 prevUV = currentUV + deltaUV; float prevDepth = currentDepth - layerHeight; float weight = (currentLayerHeight - currentDepth) / (prevDepth - currentDepth + 0.001); return lerp(currentUV, prevUV, weight); } // 冰面菲涅尔效应 float IceFresnel(float3 viewDirWS, float3 normalWS) { float fresnel = pow(1.0 - saturate(dot(viewDirWS, normalWS)), _FresnelPower); return fresnel * 0.7; } ENDHLSL Pass { Blend SrcAlpha OneMinusSrcAlpha ZWrite Off HLSLPROGRAM #pragma vertex vert #pragma fragment frag struct Attributes { float4 positionOS : POSITION; float2 uv : TEXCOORD0; float3 normalOS : NORMAL; float4 tangentOS : TANGENT; }; struct Varyings { float4 positionCS : SV_POSITION; float2 uv : TEXCOORD0; float3 viewDirTS : TEXCOORD1; float3 viewDirWS : TEXCOORD2; float3 normalWS : TEXCOORD3; }; Varyings vert(Attributes IN) { Varyings OUT; VertexPositionInputs posInput = GetVertexPositionInputs(IN.positionOS.xyz); OUT.positionCS = posInput.positionCS; VertexNormalInputs normInput = GetVertexNormalInputs(IN.normalOS, IN.tangentOS); float3 viewDirWS = GetWorldSpaceViewDir(posInput.positionWS); OUT.viewDirTS = TransformWorldToTangent(viewDirWS, normInput.tangentWS, normInput.bitangentWS, normInput.normalWS); OUT.viewDirWS = viewDirWS; OUT.normalWS = normInput.normalWS; OUT.uv = IN.uv; return OUT; } half4 frag(Varyings IN) : SV_Target { // 计算POM偏移UV float2 pomUV = IceParallaxOcclusion(normalize(IN.viewDirTS), IN.uv); // 采样纹理 half4 albedo = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, pomUV); half3 normalTS = UnpackNormal(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, pomUV)); // 转换法线到世界空间 float3x3 TBN = float3x3( normalize(cross(IN.normalWS, IN.viewDirWS)), normalize(IN.normalWS), normalize(IN.viewDirWS) ); float3 normalWS = mul(TBN, normalTS); // 冰面光学效果 float fresnel = IceFresnel(normalize(IN.viewDirWS), normalWS); float3 refractedView = refract(-normalize(IN.viewDirWS), normalWS, 1.0/_RefractionIndex); // 合成最终颜色 half3 finalColor = albedo.rgb * (1 - fresnel) + fresnel * 0.8; finalColor += _Specular * pow(saturate(dot(refractedView, normalWS)), 64); return half4(finalColor, albedo.a * 0.9); } ENDHLSL } } }
材质配置建议
| 纹理类型 | 制作要求 | 示例用途 |
|---|---|---|
| 高度图 | 黑白分明,裂缝处为黑色(0值) | 控制裂缝形状和深度 |
| 法线贴图 | 配合高度图制作微观凹凸 | 增强冰面晶体质感 |
| 底色贴图 | 半透明蓝色调,带裂纹边缘高光 | 基础颜色和透明度控制 |
实际应用中可通过调整_ParallaxScale(0.05-0.1)和_DepthMultiplier(1.0-2.0)获得不同结冰程度效果
【从UnityURP开始探索游戏渲染】专栏-直达
(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,🙏)