1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
| Shader "Custom/URP/CrackedGround" { Properties { _BaseColor ("基础颜色(土地)", Color) = (0.4, 0.28, 0.15, 1) _CrackColor ("裂缝颜色", Color) = (0.1, 0.05, 0.02, 1) _VoronoiScale ("Voronoi 缩放(裂纹密度)", Float) = 5.0 _CrackWidth ("裂缝宽度", Range(0, 0.1)) = 0.02 _CrackDepth ("裂缝深度(法线强度)", Float) = 2.0 _CrackBlend ("裂缝边缘过渡", Range(0, 0.05)) = 0.01 _SecondaryScale ("二级裂纹缩放", Float) = 15.0 _SecondaryStrength ("二级裂纹强度", Range(0, 1)) = 0.4 _DryMudTex ("干土纹理", 2D) = "white" {} _TextureScale ("纹理缩放", Float) = 2.0 }
SubShader { Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" }
Pass { Tags { "LightMode" = "UniversalForward" } HLSLPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
TEXTURE2D(_DryMudTex); SAMPLER(sampler_DryMudTex);
CBUFFER_START(UnityPerMaterial) float4 _BaseColor, _CrackColor; float _VoronoiScale, _CrackWidth, _CrackDepth, _CrackBlend; float _SecondaryScale, _SecondaryStrength; float4 _DryMudTex_ST; float _TextureScale; CBUFFER_END
struct Attributes { float4 posOS : POSITION; float3 normalOS : NORMAL; float4 tangentOS : TANGENT; float2 uv : TEXCOORD0; }; struct Varyings { float4 posCS : SV_POSITION; float3 posWS : TEXCOORD0; float3 normalWS : TEXCOORD1; float3 tangentWS : TEXCOORD2; float3 bitangentWS : TEXCOORD3; float2 uv : TEXCOORD4; };
float2 VoronoiHash(float2 p) { p = float2(dot(p, float2(127.1, 311.7)), dot(p, float2(269.5, 183.3))); return frac(sin(p) * 43758.5453); }
float VoronoiBorderDist(float2 x) { float2 ip = floor(x); float2 fp = frac(x); float2 mg, mr; float md = 8.0; for (int j = -1; j <= 1; j++) for (int i = -1; i <= 1; i++) { float2 g = float2(i, j); float2 o = VoronoiHash(ip + g); float2 r = g + o - fp; float d = dot(r, r); if (d < md) { md = d; mr = r; mg = g; } } md = 8.0; for (int j = -2; j <= 2; j++) for (int i = -2; i <= 2; i++) { float2 g = mg + float2(i, j); float2 o = VoronoiHash(ip + g); float2 r = g + o - fp; if (dot(mr - r, mr - r) > 0.00001) md = min(md, dot(0.5 * (mr + r), normalize(r - mr))); } return md; }
Varyings vert(Attributes IN) { Varyings OUT; OUT.posCS = TransformObjectToHClip(IN.posOS.xyz); OUT.posWS = TransformObjectToWorld(IN.posOS.xyz); OUT.normalWS = TransformObjectToWorldNormal(IN.normalOS); OUT.tangentWS = TransformObjectToWorldDir(IN.tangentOS.xyz); OUT.bitangentWS = cross(OUT.normalWS, OUT.tangentWS) * IN.tangentOS.w; OUT.uv = IN.uv; return OUT; }
half4 frag(Varyings IN) : SV_Target { float2 uv = IN.posWS.xz; // 使用世界坐标 XZ 驱动 Voronoi(避免 UV 拉伸)
// 主裂纹 float crack1 = VoronoiBorderDist(uv * _VoronoiScale); float crackMask1 = 1.0 - smoothstep(_CrackWidth - _CrackBlend, _CrackWidth + _CrackBlend, crack1);
// 二级裂纹(更细小) float crack2 = VoronoiBorderDist(uv * _SecondaryScale); float crackMask2 = 1.0 - smoothstep(_CrackWidth * 0.5, _CrackWidth, crack2); crackMask2 *= _SecondaryStrength;
float totalCrack = saturate(crackMask1 + crackMask2 * (1.0 - crackMask1));
// 采样基础纹理 half4 mudTex = SAMPLE_TEXTURE2D(_DryMudTex, sampler_DryMudTex, IN.uv * _TextureScale); half3 baseAlbedo = _BaseColor.rgb * mudTex.rgb;
// 颜色混合 half3 finalAlbedo = lerp(baseAlbedo, _CrackColor.rgb, totalCrack);
// 法线扰动(裂缝处法线向下倾斜) // 通过有限差分计算 Voronoi 的梯度作为法线贡献 float e = 0.01; float d_dx = VoronoiBorderDist((uv + float2(e, 0)) * _VoronoiScale) - VoronoiBorderDist((uv - float2(e, 0)) * _VoronoiScale); float d_dz = VoronoiBorderDist((uv + float2(0, e)) * _VoronoiScale) - VoronoiBorderDist((uv - float2(0, e)) * _VoronoiScale); float3 crackNormalTS = normalize(float3( d_dx * _CrackDepth * totalCrack, 1.0, d_dz * _CrackDepth * totalCrack ));
// 切线空间法线转世界空间 float3x3 TBN = float3x3( normalize(IN.tangentWS), normalize(IN.bitangentWS), normalize(IN.normalWS) ); float3 normalWS = normalize(mul(crackNormalTS, TBN));
// 光照 Light mainLight = GetMainLight(TransformWorldToShadowCoord(IN.posWS)); float NdotL = saturate(dot(normalWS, mainLight.direction)); half3 ambient = SampleSH(normalWS); half3 finalColor = finalAlbedo * (ambient + mainLight.color * NdotL * mainLight.shadowAttenuation);
return half4(finalColor, 1.0); } ENDHLSL } } }
|