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 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
| Shader "Custom/URP/LavaFlow" { Properties { _LavaRamp ("熔岩颜色渐变 (Gradient Ramp)", 2D) = "white" {} _NoiseTex ("噪波纹理", 2D) = "gray" {} _CrackTex ("裂缝纹理", 2D) = "white" {}
_FlowSpeed ("流动速度", Range(0, 2)) = 0.3 _FlowDirection ("流动方向 (XY)", Vector) = (0, -1, 0, 0) _WarpStrength ("域扭曲强度", Range(0, 0.5)) = 0.2 _WarpScale ("扭曲尺度", Range(1, 8)) = 3.0
_LavaIntensity ("熔岩发光强度", Range(1, 20)) = 8.0 _CrackWidth ("裂缝宽度", Range(0, 1)) = 0.3 _RockColor ("岩石颜色", Color) = (0.08, 0.06, 0.05, 1) _CoolLavaColor ("冷却熔岩颜色", Color) = (0.3, 0.1, 0.05, 1)
_Roughness ("岩石粗糙度", Range(0, 1)) = 0.95 _NormalStrength ("法线强度", Range(0, 2)) = 0.8 }
SubShader { Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" }
Pass { Name "ForwardLit" Tags { "LightMode" = "UniversalForward" }
HLSLPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE #pragma multi_compile _ _SHADOWS_SOFT
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
TEXTURE2D(_LavaRamp); SAMPLER(sampler_LavaRamp); TEXTURE2D(_NoiseTex); SAMPLER(sampler_NoiseTex); TEXTURE2D(_CrackTex); SAMPLER(sampler_CrackTex);
CBUFFER_START(UnityPerMaterial) float4 _LavaRamp_ST; float4 _NoiseTex_ST; float4 _CrackTex_ST; float _FlowSpeed; float4 _FlowDirection; float _WarpStrength; float _WarpScale; float _LavaIntensity; float _CrackWidth; float4 _RockColor; float4 _CoolLavaColor; float _Roughness; float _NormalStrength; CBUFFER_END
struct Attributes { float4 positionOS : POSITION; float3 normalOS : NORMAL; float4 tangentOS : TANGENT; float2 uv : TEXCOORD0; };
struct Varyings { float4 positionHCS : SV_POSITION; float3 worldPos : TEXCOORD0; float3 worldNormal : TEXCOORD1; float3 worldTangent : TEXCOORD2; float3 worldBitangent : TEXCOORD3; float2 uv : TEXCOORD4; float4 shadowCoord : TEXCOORD5; };
float Hash(float2 p) { p = frac(p * float2(0.1031, 0.1030)); p += dot(p, p.yx + 33.33); return frac((p.x + p.y) * p.x); }
float Noise(float2 p) { float2 i = floor(p); float2 f = frac(p); f = f * f * (3.0 - 2.0 * f); return lerp(lerp(Hash(i), Hash(i + float2(1,0)), f.x), lerp(Hash(i + float2(0,1)), Hash(i + float2(1,1)), f.x), f.y); }
// 带方向流动的 FBM float FlowFBM(float2 p, float2 flowDir, float t) { const float2x2 m = float2x2(0.80, 0.60, -0.60, 0.80); float v = 0.0, a = 0.5, norm = 0.0;
// 流动:沿方向平移 p += flowDir * t * _FlowSpeed;
v += a * Noise(p); norm += a; a *= 0.5; p = mul(m, p) * 2.02; v += a * Noise(p); norm += a; a *= 0.5; p = mul(m, p) * 2.03; v += a * Noise(p); norm += a; a *= 0.5; p = mul(m, p) * 2.01; v += a * Noise(p); norm += a;
return v / norm; }
Varyings vert(Attributes input) { Varyings output; VertexPositionInputs posInputs = GetVertexPositionInputs(input.positionOS.xyz); VertexNormalInputs norInputs = GetVertexNormalInputs(input.normalOS, input.tangentOS);
output.positionHCS = posInputs.positionCS; output.worldPos = posInputs.positionWS; output.worldNormal = norInputs.normalWS; output.worldTangent = norInputs.tangentWS; output.worldBitangent = norInputs.bitangentWS; output.uv = TRANSFORM_TEX(input.uv, _NoiseTex); output.shadowCoord = GetShadowCoord(posInputs); return output; }
half4 frag(Varyings input) : SV_Target { float2 uv = input.uv; float t = _Time.y; float2 flowDir = normalize(_FlowDirection.xy);
// ---- 域扭曲:两层嵌套 FBM ---- float2 scaledUV = uv * _WarpScale;
// 第一层扭曲偏移(带流动方向) float2 warp1 = float2( FlowFBM(scaledUV + float2(0, 0), flowDir, t), FlowFBM(scaledUV + float2(5.2, 1.3), flowDir, t) ) * 2.0 - 1.0;
float2 warpedUV1 = uv + warp1 * _WarpStrength;
// 第二层扭曲(在第一层扭曲后的坐标上再次扭曲,速度稍慢) float2 warp2 = float2( FlowFBM(warpedUV1 * _WarpScale + float2(1.7, 9.2), flowDir, t * 0.6), FlowFBM(warpedUV1 * _WarpScale + float2(8.3, 2.8), flowDir, t * 0.6) ) * 2.0 - 1.0;
float2 finalUV = warpedUV1 + warp2 * _WarpStrength * 0.5;
// ---- 熔岩图案(域扭曲后的 FBM 值)---- float lavaPattern = FlowFBM(finalUV * _WarpScale, flowDir, t * 0.3);
// 裂缝贴图(控制熔岩裂缝的形态) float crack = SAMPLE_TEXTURE2D(_CrackTex, sampler_CrackTex, finalUV).r;
// 熔岩值:FBM 图案 + 裂缝叠加 float lavaVal = lavaPattern * (0.6 + 0.4 * crack);
// ---- 颜色映射 ---- // 熔岩渐变:黑色岩石 -> 冷却熔岩(暗红)-> 热熔岩(橙红)-> 中心高温(黄白) float3 lavaColor = SAMPLE_TEXTURE2D(_LavaRamp, sampler_LavaRamp, float2(lavaVal, 0.5)).rgb;
// 岩石/熔岩混合(超过阈值才显示熔岩发光) float lavaMask = smoothstep(_CrackWidth, _CrackWidth + 0.1, lavaVal);
float3 rockColor = lerp(_RockColor.rgb, _CoolLavaColor.rgb, lavaVal * 0.3); float3 albedo = lerp(rockColor, lavaColor, lavaMask);
// 熔岩自发光(HDR 强度,配合 Bloom 产生辉光) float3 emission = lavaColor * lavaMask * _LavaIntensity;
// ---- 法线扰动(模拟熔岩表面起伏)---- float3 n = normalize(input.worldNormal); // 通过对 lavaPattern 的有限差分估算表面法线 float eps = 0.01; float dx = FlowFBM((finalUV + float2(eps, 0)) * _WarpScale, flowDir, t * 0.3) - FlowFBM((finalUV - float2(eps, 0)) * _WarpScale, flowDir, t * 0.3); float dy = FlowFBM((finalUV + float2(0, eps)) * _WarpScale, flowDir, t * 0.3) - FlowFBM((finalUV - float2(0, eps)) * _WarpScale, flowDir, t * 0.3);
float3 tangent = normalize(input.worldTangent); float3 bitangent = normalize(input.worldBitangent); float3 bumpNormal = normalize(n + tangent * (-dx * _NormalStrength) + bitangent * (-dy * _NormalStrength));
// ---- URP PBR 光照 ---- Light mainLight = GetMainLight(input.shadowCoord); float NdotL = saturate(dot(bumpNormal, mainLight.direction)); float3 diffuse = mainLight.color * NdotL * mainLight.shadowAttenuation;
float3 ambient = SampleSH(bumpNormal);
// 粗糙度随熔岩状态变化:冷却岩石粗糙,热熔岩略微有反光 float roughness = lerp(_Roughness, 0.3, lavaMask);
float3 finalColor = albedo * (ambient * 0.3 + diffuse); finalColor += emission; // 发光叠加(不受光照影响)
return half4(finalColor, 1.0); } ENDHLSL } } }
|