half FilterParticulateRange(float4 range, float y) { half w = saturate((y - range.x) / max(range.y - range.x, 0.0001)); w *= 1.0 - saturate((y - range.z) / max(range.w - range.z, 0.0001)); return w; } half FilterParticulateSlope(float4 range, float3 worldNormalVertex, float windRot) { float2 windDir = RotateUV(float2(1, 0), windRot); // fix for denormalization from normalize float2 flow = worldNormalVertex.y < 0.99 ? lerp(worldNormalVertex.xz, normalize(worldNormalVertex.xz), max(0.1, worldNormalVertex.z)) : worldNormalVertex.xz; float cofacing = dot(windDir, flow); // 1 going downhill, -1 going uphill return FilterParticulateRange(range, cofacing); } fixed ComputeParticulateMask(float2 wuv, float4 parms) { wuv *= float2(parms.z, 1) * parms.w; float speed = _Time.x * parms.x; fixed w1 = SAMPLE_TEXTURE2D(_GlitterWind, sampler_Diffuse, wuv * 3 + speed * float2(1,0)).a; fixed w2 = SAMPLE_TEXTURE2D(_GlitterWind, sampler_Diffuse, wuv + speed * float2(1.1,0)).a; return (w1 * w2); } fixed ProcessParticulateMask(inout fixed mask, float contrast) { mask = pow(mask, abs(contrast)); fixed invMask = 1.0 - mask; invMask *= invMask; invMask *= invMask; return invMask; } void DoWindParticulate(Input i, inout MicroSplatLayer o, Config config, half4 weights, float camDist, float3 worldNormalVertex, half snowWeight) { #if defined(UNITY_PASS_FORWARDBASE) || defined(UNITY_PASS_DEFERRED) || (defined(_HDRP) || _URP) float3 lightTS = GetGlobalLightDirTS(i); float3 upVector = float3(0,0,1); half upDot = max(0.0, dot(worldNormalVertex, i.worldUpVector)); float2 uv = i.worldPos.xz * 0.01; #if _PLANETVECTORS uv = i.uv_Control0.xy; #endif #if _GLOBALPARTICULATEROTATION float windRotation = _Global_WindParticulateRotation; #else float windRotation = _WindParticulateRotation; #endif float2 wuv = RotateUV(uv, windRotation); half windBlend = 1.0; #if _PERTEXWINDPARTICULATE SAMPLE_PER_TEX(ptWind, 7.5, config, half4(1,1,1,1)); windBlend = BlendWeights(ptWind0.a, ptWind1.a, ptWind2.a, ptWind3.a, weights); #endif #if _WINDPARTICULATE || _WINDSHADOWS float windWorldMask = FilterParticulateRange(_WindParticulateHeightMask, i.worldPos.y); windWorldMask *= FilterParticulateRange(_WindParticulateAngleMask, upDot); #if _WINDPARTICULATEUPFILTER windWorldMask *= FilterParticulateSlope(_WindParticulateUpMask, worldNormalVertex, windRotation); #endif #endif #if _WINDSHADOWS float2 offset = lightTS.yx * _WindParticulateShadow.x; fixed shadowMask = ComputeParticulateMask(wuv + offset.xy, _WindParticulateParams); #if _GLOBALWINDPARTICULATESTRENGTH float shadowWindStrength = _Global_WindParticulateStrength; #else float shadowWindStrength = _WindParticulateStrength; #endif shadowMask *= shadowWindStrength * windBlend * windWorldMask; shadowMask *= (1.0 - snowWeight); fixed shadowInvMask = ProcessParticulateMask(shadowMask, _WindParticulateParams.y); o.Albedo = lerp(o.Albedo, o.Albedo * _WindParticulateShadowColor.rgb * _WindParticulateShadowColor.a, saturate(shadowMask * _WindParticulateShadow.y)); o.Normal.xy *= shadowInvMask; o.Occlusion -= shadowMask * 0.5 * _WindParticulateOcclusionStrength; o.Smoothness *= shadowInvMask; o.Metallic *= shadowInvMask; #endif #if _WINDPARTICULATE // compute mask fixed windMask = ComputeParticulateMask(wuv, _WindParticulateParams); #if _GLOBALWINDPARTICULATESTRENGTH float windStrength = _Global_WindParticulateStrength; #else float windStrength = _WindParticulateStrength; #endif windMask *= windStrength * windBlend * windWorldMask; windMask *= (1.0 - snowWeight); fixed windInvMask = ProcessParticulateMask(windMask, _WindParticulateParams.y); o.Albedo = lerp(o.Albedo, _WindParticulateColor.rgb, windMask * _WindParticulateColor.a); o.Emission += _WindParticulateColor.rgb * windMask * _WindParticulateColor.a * _WindEmissive.x; o.Normal.xy *= windInvMask; o.Smoothness *= windInvMask; o.Occlusion -= (1.0 - windInvMask) * _WindParticulateOcclusionStrength; o.Metallic *= windInvMask; #endif #if _SNOWPARTICULATE || _SNOWSHADOWS float snowWorldMask = FilterParticulateRange(_SnowParticulateHeightMask, i.worldPos.y); snowWorldMask *= FilterParticulateRange(_SnowParticulateAngleMask, upDot); #if _WINDPARTICULATEUPFILTER snowWorldMask *= FilterParticulateSlope(_SnowParticulateUpMask, worldNormalVertex, windRotation); #endif #endif #if _SNOWSHADOWS float2 snowOffset = lightTS.yx * _SnowParticulateShadow.x; #if _GLOBALSNOWPARTICULATESTRENGTH float snowShadowStrength = _Global_SnowParticulateStrength; #else float snowShadowStrength = _SnowParticulateStrength; #endif fixed snowShadowMask = ComputeParticulateMask(wuv + snowOffset.xy, _SnowParticulateParams) * snowShadowStrength; snowShadowMask *= snowWeight * snowWorldMask; fixed snowShadowInvMask = ProcessParticulateMask(snowShadowMask, _SnowParticulateParams.y); o.Albedo = lerp(o.Albedo, o.Albedo * _SnowParticulateShadowColor.rgb * _SnowParticulateShadowColor.a, saturate(snowShadowMask * _SnowParticulateShadow.y)); o.Normal.xy *= snowShadowInvMask; o.Occlusion -= snowShadowMask * 0.5 * _SnowParticulateOcclusionStrength; o.Smoothness *= snowShadowInvMask; o.Metallic *= snowShadowInvMask; #endif #if _SNOWPARTICULATE // compute mask #if _GLOBALSNOWPARTICULATESTRENGTH float snowStrength = _Global_SnowParticulateStrength; #else float snowStrength = _SnowParticulateStrength; #endif fixed snowMask = ComputeParticulateMask(wuv, _SnowParticulateParams) * snowStrength; snowMask *= snowWeight * snowWorldMask; fixed snowInvMask = ProcessParticulateMask(snowMask, _SnowParticulateParams.y); o.Albedo = lerp(o.Albedo, _SnowParticulateColor.rgb, snowMask * _SnowParticulateColor.a); o.Emission += _SnowParticulateColor.rgb * _SnowParticulateColor.a * snowMask * _WindEmissive.y; o.Normal.xy *= snowInvMask; o.Smoothness *= snowInvMask; o.Occlusion -= (1-snowInvMask) * _SnowParticulateOcclusionStrength; o.Metallic *= snowInvMask; #endif #endif }