583 lines
23 KiB
Plaintext
583 lines
23 KiB
Plaintext
#if _SNOW
|
|
TEXTURE2D(_SnowDiff);
|
|
TEXTURE2D(_SnowNormal);
|
|
#endif
|
|
|
|
#if _SNOWNORMALNOISE
|
|
TEXTURE2D(_SnowNormalNoise);
|
|
#endif
|
|
|
|
#if _SNOWFOOTSTEPS
|
|
TEXTURE2D(_SnowTrackDiff);
|
|
TEXTURE2D(_SnowTrackNSAO);
|
|
#endif
|
|
|
|
#if _SNOWMASK
|
|
TEXTURE2D(_SnowMask);
|
|
#endif
|
|
|
|
#if _SNOWSPARKLE
|
|
TEXTURE2D(_SnowSparkleNoise);
|
|
#endif
|
|
|
|
|
|
|
|
float SnowFade(float worldHeight, float snowMin, float snowMax, half snowDot, half snowDotVertex, half snowLevel, half puddleHeight)
|
|
{
|
|
float snowHeightFade = saturate((worldHeight - snowMin) / max(snowMax, 0.001));
|
|
half snowAngleFade = max(0, (snowDotVertex - _SnowHeightAngleRange.z) * 6);
|
|
snowAngleFade = snowAngleFade * (1 - max(0, (snowDotVertex - _SnowHeightAngleRange.w) * 6));
|
|
return saturate((snowLevel * snowHeightFade * saturate(snowAngleFade)) - puddleHeight);
|
|
}
|
|
|
|
float DoSnowDisplace(float splat_height, float2 uv, float3 worldNormalVertex, float3 worldPos, float puddleHeight, Config config, half4 weights)
|
|
{
|
|
// could force a branch and avoid texsamples
|
|
#if _SNOW
|
|
|
|
#if _USEGLOBALSNOWLEVEL
|
|
float snowLevel = _Global_SnowLevel;
|
|
#else
|
|
float snowLevel = _SnowAmount;
|
|
#endif
|
|
|
|
#if _USEGLOBALSNOWHEIGHT
|
|
float snowMin = _Global_SnowMinMaxHeight.x;
|
|
float snowMax = _Global_SnowMinMaxHeight.y;
|
|
#else
|
|
float snowMin = _SnowHeightAngleRange.x;
|
|
float snowMax = _SnowHeightAngleRange.y;
|
|
#endif
|
|
|
|
|
|
|
|
float snowAge = _SnowParams.z;
|
|
|
|
|
|
#if _PERTEXSNOWSTRENGTH && !_SNOWSIMPLE
|
|
SAMPLE_PER_TEX(ptSnowStr, 8.5, config, half4(1.0, 0.0, 0.0, 0.0));
|
|
snowLevel *= ptSnowStr0.x * weights.x + ptSnowStr1.x * weights.y + ptSnowStr2.x * weights.z + ptSnowStr3.x * weights.w;
|
|
#endif
|
|
|
|
half2 levelMaxMin = half2(1, 0);
|
|
#if _SNOWMASK
|
|
levelMaxMin = SAMPLE_TEXTURE2D_LOD(_SnowMask, shared_linear_clamp_sampler, uv, 0).xy;
|
|
#endif
|
|
|
|
float3 snowUpVector = _SnowUpVector;
|
|
float worldHeight = worldPos.y;
|
|
|
|
half snowDot = saturate(dot(worldNormalVertex, snowUpVector));
|
|
half snowDotVertex = max(snowLevel/2, snowDot);
|
|
|
|
|
|
float snowFade = SnowFade(worldHeight, snowMin, snowMax, snowDotVertex, snowDotVertex, snowLevel, puddleHeight);
|
|
#if _SNOWMASK
|
|
snowFade = min(levelMaxMin.x, snowFade);
|
|
snowFade = max(levelMaxMin.y, snowFade);
|
|
#endif
|
|
|
|
float height = splat_height * _SnowParams.x;
|
|
float erosion = height * _SnowParams.y;
|
|
float snowMask = saturate((snowFade - erosion));
|
|
float snowMask2 = saturate(snowMask * 8);
|
|
snowMask *= snowMask * snowMask * snowMask * snowMask * snowMask2;
|
|
float snowAmount = snowMask * snowDot;
|
|
|
|
return snowAmount;
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
#if _SNOWSPARKLE
|
|
void DoSnowSparkle(Input i, inout MicroSplatLayer o, float3 viewDir, float3 worldPos, float3 worldNormalVertex, float snowLevel)
|
|
{
|
|
|
|
#if _DEBUG_SNOWSPARKLE
|
|
o.Albedo = 0;
|
|
o.Smoothness = 0;
|
|
o.Occlusion = 1;
|
|
o.Emission = 0;
|
|
|
|
#endif
|
|
|
|
|
|
// screen space method. Looks nice because it's in SS, but fails because clearly not
|
|
// combing from a single spot on the terrain.
|
|
|
|
float size = 1 - (_SnowSparkleSize * 0.001);
|
|
float density = _SnowSparkleDensity;
|
|
float noiseDensity = _SnowSparkleNoiseDensity;
|
|
float viewDep = _SnowSparkleViewDependency;
|
|
|
|
float3 wsView = worldPos - _WorldSpaceCameraPos;
|
|
float3 wsViewDir = normalize(wsView);
|
|
|
|
float z = length(wsView);
|
|
float e = floor(log2(0.3*z+3.0)/0.3785116);
|
|
float level_z = 0.1 * pow(1.3, e) - 0.2;
|
|
float level = 0.12 / level_z;
|
|
density *= level;
|
|
noiseDensity *= level;
|
|
|
|
float3 v = wsView / z;
|
|
float3 view_new = v * level_z;
|
|
view_new = sign(view_new) * frac(abs(view_new));
|
|
|
|
float3 pos = density*worldPos + viewDep * normalize(view_new);
|
|
|
|
float3 g_index = floor(pos);
|
|
float3 pc = g_index / density;
|
|
|
|
float3 noise = _SnowSparkleNoiseAmplitude * SAMPLE_TEXTURE2D_LOD( _SnowSparkleNoise, sampler_Diffuse, noiseDensity * pc.xz + pc.y, 0).rgb;
|
|
float3 offset = 0.75;
|
|
float3 px = pos - g_index + 0.5 * frac(noise)-offset;
|
|
|
|
float dotvn = dot(wsViewDir, worldNormalVertex);
|
|
float3 ma = v - dotvn*worldNormalVertex;
|
|
float3 px_proj = dot(px, ma) * ma;
|
|
px += (abs(dotvn)-1.0)*px_proj/dot(ma,ma);
|
|
|
|
float dist2 = dot(px, px);
|
|
float thresh = 1 - size;
|
|
|
|
|
|
float r = dist2 > thresh? 0 : 1-dist2/thresh;
|
|
|
|
r *= snowLevel * _SnowSparkleStrength;
|
|
float3 c = _SnowSparkleTint * r;
|
|
|
|
o.Albedo += c;
|
|
o.Emission += c * _SnowSparkleEmission;
|
|
o.Smoothness += r;
|
|
|
|
#if _DEBUG_SNOWSPARKLE
|
|
o.Albedo = c;
|
|
o.Emission = c * _SnowSparkleEmission;
|
|
o.Smoothness = r;
|
|
o.Normal = float3(0,0,1);
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
#endif
|
|
|
|
#if _SNOWRIM
|
|
void DoSnowRim(inout MicroSplatLayer o, Input i, float snowAmount)
|
|
{
|
|
float rim = 1.0 - saturate(dot(normalize(_WorldSpaceCameraPos - i.worldPos), WorldNormalVector(i, o.Normal)));
|
|
o.Emission += pow(rim, _SnowRimPower) * _SnowRimColor * snowAmount;
|
|
}
|
|
#endif
|
|
|
|
#if _SNOWSTOCHASTIC
|
|
void SampleSnowStochastic(float2 uv, float2 dx, float2 dy, out float4 albedo, out float4 nsao)
|
|
{
|
|
float2 uv1, uv2, uv3;
|
|
half3 w;
|
|
PrepareStochasticUVs(_SnowStochasticScale, uv, uv1, uv2, uv3, w);
|
|
|
|
half4 S1 = SAMPLE_TEXTURE2D_GRAD(_SnowDiff, sampler_Diffuse, uv1, dx, dy);
|
|
half4 S2 = SAMPLE_TEXTURE2D_GRAD(_SnowDiff, sampler_Diffuse, uv2, dx, dy);
|
|
half4 S3 = SAMPLE_TEXTURE2D_GRAD(_SnowDiff, sampler_Diffuse, uv3, dx, dy);
|
|
|
|
COUNTSAMPLE
|
|
COUNTSAMPLE
|
|
COUNTSAMPLE
|
|
|
|
half3 cw = BaryWeightBlend(w, S1.a, S2.a, S3.a, _SnowStochasticContrast);
|
|
|
|
half4 N1, N2, N3 = half4(0,0,1,0);
|
|
MSBRANCHCLUSTER(cw.x);
|
|
{
|
|
N1 = SAMPLE_TEXTURE2D_GRAD(_SnowNormal, sampler_NormalSAO, uv1, dx, dy);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHCLUSTER(cw.y);
|
|
{
|
|
N2 = SAMPLE_TEXTURE2D_GRAD(_SnowNormal, sampler_NormalSAO, uv2, dx, dy);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHCLUSTER(cw.z);
|
|
{
|
|
N3 = SAMPLE_TEXTURE2D_GRAD(_SnowNormal, sampler_NormalSAO, uv3, dx, dy);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
albedo = S1 * cw.x + S2 * cw.y + S3 * cw.z;
|
|
nsao = N1 * cw.x + N2 * cw.y + N3 * cw.z;
|
|
nsao = nsao.agrb;
|
|
}
|
|
#endif
|
|
|
|
|
|
float DoSnow(Input i, inout MicroSplatLayer o, float2 uv, float3 worldNormal, float3 worldNormalVertex,
|
|
float3 worldPos, float puddleHeight, half surfPorosity, float camDist, Config config, half4 weights,
|
|
inout half3 SSSTint, inout half SSSThickness, float traxBuffer, float3 traxNormal)
|
|
{
|
|
#if _SNOW
|
|
float2 maskUV = uv;
|
|
#if _SNOWWORLDSPACEUV
|
|
uv = worldPos.xz;
|
|
#endif
|
|
|
|
|
|
float2 dx = ddx(uv) * _SnowUVScales.xy;
|
|
float2 dy = ddy(uv) * _SnowUVScales.xy;
|
|
|
|
float3 wdx = ddx(worldPos) * _SnowUVScales.xxy;
|
|
float3 wdy = ddy(worldPos) * _SnowUVScales.xxy;
|
|
|
|
uv *= _SnowUVScales.xy;
|
|
float3 wuv = worldPos * _SnowUVScales.xxy;
|
|
|
|
#if _USEGLOBALSNOWLEVEL
|
|
float snowLevel = _Global_SnowLevel;
|
|
#else
|
|
float snowLevel = _SnowAmount;
|
|
#endif
|
|
|
|
#if _USEGLOBALSNOWHEIGHT
|
|
float snowMin = _Global_SnowMinMaxHeight.x;
|
|
float snowMax = _Global_SnowMinMaxHeight.y;
|
|
#else
|
|
float snowMin = _SnowHeightAngleRange.x;
|
|
float snowMax = _SnowHeightAngleRange.y;
|
|
#endif
|
|
|
|
|
|
|
|
|
|
float snowAge = _SnowParams.z;
|
|
float snowErosion = _SnowParams.y;
|
|
float snowHeight = _SnowParams.x;
|
|
|
|
|
|
|
|
#if _PERTEXSNOWSTRENGTH && !_SIMPLESNOW
|
|
SAMPLE_PER_TEX(ptSnowStr, 8.5, config, half4(1.0, 0.0, 0.0, 0.0));
|
|
snowLevel *= ptSnowStr0.x * weights.x + ptSnowStr1.x * weights.y + ptSnowStr2.x * weights.z + ptSnowStr3.x * weights.w;
|
|
#endif
|
|
|
|
half2 levelMaxMin = half2(1,0);
|
|
#if _SNOWMASK
|
|
#if _MEGASPLAT
|
|
levelMaxMin = i.fx2.yx;
|
|
#else
|
|
levelMaxMin = SAMPLE_TEXTURE2D_GRAD(_SnowMask, shared_linear_clamp_sampler, maskUV, ddx(maskUV), ddy(maskUV));
|
|
#endif
|
|
#endif
|
|
|
|
float3 snowUpVector = _SnowUpVector;
|
|
float worldHeight = i.worldHeight;
|
|
|
|
|
|
half snowDot = max(snowLevel/2, dot(worldNormal, snowUpVector));
|
|
half snowDotVertex = snowDot;
|
|
#if _SNOWSIMPLE
|
|
half ao = 1;
|
|
half oheight = 0;
|
|
half smoothness = 0;
|
|
#else
|
|
half ao = o.Occlusion;
|
|
half oheight = o.Height;
|
|
half smoothness = o.Smoothness;
|
|
#endif
|
|
|
|
|
|
float snowFade = SnowFade(worldHeight, snowMin, snowMax, snowDot, snowDotVertex, snowLevel, puddleHeight);
|
|
|
|
#if _SNOWMASK
|
|
snowFade = min(levelMaxMin.x, snowFade);
|
|
snowFade = max(levelMaxMin.y, snowFade);
|
|
#endif
|
|
|
|
//MSBRANCHOTHER(snowFade)
|
|
{
|
|
#if _SNOWSTOCHASTIC && _SNOWTRIPLANAR
|
|
|
|
float3 pn = pow(abs(worldNormal), 3);
|
|
pn = pn / (pn.x + pn.y + pn.z);
|
|
|
|
half3 axisSign = sign(worldNormal);
|
|
|
|
float2 uv0 = wuv.zy * axisSign.x;
|
|
float2 uv1 = wuv.xz * axisSign.y;
|
|
float2 uv2 = wuv.xy * axisSign.z;
|
|
|
|
half4 snowAlb0; half4 snowAlb1; half4 snowAlb2;
|
|
half4 snowNsao0; half4 snowNsao1; half4 snowNsao2;
|
|
|
|
SampleSnowStochastic(uv0, wdx.zy, wdy.zy, snowAlb0, snowNsao0);
|
|
SampleSnowStochastic(uv1, wdx.xz, wdy.xz, snowAlb1, snowNsao1);
|
|
SampleSnowStochastic(uv2, wdx.xy, wdy.xy, snowAlb2, snowNsao2);
|
|
|
|
half4 snowAlb = snowAlb0 * pn.x + snowAlb1 * pn.y + snowAlb2 * pn.z;
|
|
half4 snowNsao = snowNsao0 * pn.x + snowNsao1 * pn.y + snowNsao2 * pn.z;
|
|
|
|
#elif _SNOWTRIPLANAR
|
|
|
|
float3 pn = pow(abs(worldNormal), 3);
|
|
pn = pn / (pn.x + pn.y + pn.z);
|
|
|
|
half3 axisSign = sign(worldNormal);
|
|
|
|
float2 uv0 = wuv.zy * axisSign.x;
|
|
float2 uv1 = wuv.xz * axisSign.y;
|
|
float2 uv2 = wuv.xy * axisSign.z;
|
|
half4 snowAlb0 = SAMPLE_TEXTURE2D_GRAD(_SnowDiff, sampler_Diffuse, uv0, wdx.zy, wdy.zy);
|
|
half4 snowAlb1 = SAMPLE_TEXTURE2D_GRAD(_SnowDiff, sampler_Diffuse, uv1, wdx.xz, wdy.xz);
|
|
half4 snowAlb2 = SAMPLE_TEXTURE2D_GRAD(_SnowDiff, sampler_Diffuse, uv2, wdx.xy, wdy.xy);
|
|
half4 snowNsao0 = SAMPLE_TEXTURE2D_GRAD(_SnowNormal, sampler_NormalSAO, uv0, wdx.zy, wdy.zy).agrb;
|
|
half4 snowNsao1 = SAMPLE_TEXTURE2D_GRAD(_SnowNormal, sampler_NormalSAO, uv1, wdx.xz, wdy.xz).agrb;
|
|
half4 snowNsao2 = SAMPLE_TEXTURE2D_GRAD(_SnowNormal, sampler_NormalSAO, uv2, wdx.xy, wdy.xy).agrb;
|
|
half4 snowAlb = snowAlb0 * pn.x + snowAlb1 * pn.y + snowAlb2 * pn.z;
|
|
half4 snowNsao = snowNsao0 * pn.x + snowNsao1 * pn.y + snowNsao2 * pn.z;
|
|
COUNTSAMPLE
|
|
COUNTSAMPLE
|
|
COUNTSAMPLE
|
|
COUNTSAMPLE
|
|
COUNTSAMPLE
|
|
COUNTSAMPLE
|
|
|
|
#elif _SNOWSTOCHASTIC
|
|
half4 snowAlb;
|
|
half4 snowNsao;
|
|
|
|
SampleSnowStochastic(uv, dx, dy, snowAlb, snowNsao);
|
|
#else
|
|
half4 snowAlb = SAMPLE_TEXTURE2D_GRAD(_SnowDiff, sampler_Diffuse, uv, dx, dy);
|
|
half4 snowNsao = SAMPLE_TEXTURE2D_GRAD(_SnowNormal, sampler_NormalSAO, uv, dx, dy).agrb;
|
|
COUNTSAMPLE
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _SNOWDISTANCERESAMPLE
|
|
{
|
|
float fade = saturate ((camDist - _SnowDistanceResampleScaleStrengthFade.z) / _SnowDistanceResampleScaleStrengthFade.w);
|
|
fade *= _SnowDistanceResampleScaleStrengthFade.y;
|
|
MSBRANCHOTHER(fade)
|
|
{
|
|
float2 snowResampleUV = uv * _SnowDistanceResampleScaleStrengthFade.x;
|
|
float2 rsdx = dx * _SnowDistanceResampleScaleStrengthFade.x;
|
|
float2 rsdy = dy * _SnowDistanceResampleScaleStrengthFade.x;
|
|
half4 resSnowAlb = SAMPLE_TEXTURE2D_GRAD(_SnowDiff, sampler_Diffuse, snowResampleUV, rsdx, rsdy);
|
|
half4 resSnowNsao = SAMPLE_TEXTURE2D_GRAD(_SnowNormal, sampler_NormalSAO, snowResampleUV, rsdx, rsdy).grab;
|
|
COUNTSAMPLE
|
|
COUNTSAMPLE
|
|
|
|
snowAlb.rgb = lerp(snowAlb, resSnowAlb, fade);
|
|
snowNsao = lerp(snowNsao, resSnowNsao, fade);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if _SNOWNORMALNOISE
|
|
{
|
|
float2 normalUV = uv * _SnowNormalNoiseScaleStrength.x;
|
|
half3 noise = UnpackNormal(SAMPLE_TEXTURE2D_GRAD(_SnowNormalNoise, sampler_Diffuse, normalUV, dx * _SnowNormalNoiseScaleStrength.x, dy * _SnowNormalNoiseScaleStrength.x));
|
|
COUNTSAMPLE
|
|
snowNsao.xy = lerp(snowNsao.xy, BlendNormal2(snowNsao.xy, noise.xy), _SnowNormalNoiseScaleStrength.y);
|
|
}
|
|
#endif
|
|
|
|
#if _SNOWFOOTSTEPS
|
|
{
|
|
traxNormal.xy *= _SnowTraxNormalStrength;
|
|
float2 fsdx = dx * _SnowTraxUVScales;
|
|
float2 fsdy = dy * _SnowTraxUVScales;
|
|
traxBuffer = 1 - ((1 - traxBuffer) * _SnowTraxTextureBlend);
|
|
|
|
half4 traxDiffuse = SAMPLE_TEXTURE2D_GRAD(_SnowTrackDiff, sampler_Diffuse, uv * _SnowTraxUVScales, fsdx, fsdy);
|
|
half4 traxN = SAMPLE_TEXTURE2D_GRAD(_SnowTrackNSAO, sampler_NormalSAO, uv * _SnowTraxUVScales, fsdx, fsdy).agrb;
|
|
COUNTSAMPLE
|
|
COUNTSAMPLE
|
|
|
|
traxDiffuse.rgb *= _TraxSnowTint;
|
|
snowAlb.rgba = lerp(traxDiffuse, snowAlb.rgba, traxBuffer);
|
|
snowNsao.rgba = lerp(traxN + half4(traxNormal.xy, 0, 0), snowNsao.rgba, traxBuffer);
|
|
snowAge = lerp(_TraxSnowAge, snowAge, traxBuffer);
|
|
snowErosion = lerp(_TraxSnowErosion, snowErosion, traxBuffer);
|
|
snowHeight = lerp(_TraxSnowHeight, snowHeight, traxBuffer);
|
|
|
|
snowFade = saturate(snowFade - _TraxSnowRemoval * (1-saturate(traxBuffer)));
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
half3 snowNormal = float3(snowNsao.xy * 2 - 1, 1);
|
|
|
|
half height = saturate(oheight - (1.0 - snowHeight));
|
|
half erosion = saturate(ao * snowErosion);
|
|
erosion *= erosion;
|
|
half snowMask = saturate(snowFade - erosion - height);
|
|
snowMask = snowMask * snowMask * snowMask;
|
|
half snowAmount = snowMask * saturate(snowDot - (height + erosion) * 0.5); // up
|
|
snowAmount = saturate(snowAmount * 8);
|
|
|
|
float wetnessMask = saturate((_SnowParams.w * (4.0 * snowFade) - (snowNsao.b) * 0.5));
|
|
|
|
float snowNormalAmount = snowAmount * snowAmount;
|
|
|
|
float porosity = saturate((((1.0 - smoothness) - 0.5)) / max(surfPorosity, 0.001));
|
|
float factor = lerp(1, 0.4, porosity);
|
|
|
|
o.Albedo *= lerp(1.0, factor, wetnessMask);
|
|
o.Normal = lerp(o.Normal, float3(0,0,1), wetnessMask);
|
|
o.Smoothness = lerp(o.Smoothness, 0.8, wetnessMask);
|
|
|
|
|
|
#if _SNOWSSS
|
|
SSSTint = lerp(SSSTint, _SnowSSSTint.rgb, snowNormalAmount);
|
|
SSSThickness = lerp(SSSThickness, _SnowSSSTint.a * 2 * snowAlb.a, snowNormalAmount);
|
|
#endif
|
|
|
|
snowAlb.rgb *= _SnowTint.rgb;
|
|
|
|
|
|
o.Albedo = lerp(o.Albedo, snowAlb.rgb, snowAmount);
|
|
o.Normal = lerp(o.Normal, snowNormal, snowNormalAmount);
|
|
o.Smoothness = lerp(o.Smoothness, (snowNsao.b) * snowAge, snowAmount);
|
|
o.Occlusion = lerp(o.Occlusion, snowNsao.w, snowAmount);
|
|
o.Height = lerp(o.Height, snowAlb.a, snowAmount);
|
|
o.Metallic = lerp(o.Metallic, 0.01, snowAmount);
|
|
float crystals = saturate(0.65 - snowNsao.b);
|
|
o.Smoothness = lerp(o.Smoothness, crystals * snowAge, snowAmount);
|
|
|
|
#if _SNOWSPARKLE
|
|
DoSnowSparkle(i, o, i.viewDir, worldPos, worldNormalVertex, snowAmount);
|
|
#endif
|
|
|
|
#if _SNOWRIM
|
|
DoSnowRim(o, i, snowAmount);
|
|
#endif
|
|
|
|
return snowAmount;
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
// for object blend shader, must, unfortunately, keep in sync..
|
|
float DoSnowSimple(Input i, inout MicroSplatLayer o, float2 uv, float3 worldNormal, float3 worldNormalVertex,
|
|
float3 worldPos, float puddleHeight, half surfPorosity)
|
|
{
|
|
#if _SNOW
|
|
float2 maskUV = uv;
|
|
#if _SNOWWORLDSPACEUV
|
|
uv = worldPos.xz;
|
|
#endif
|
|
|
|
uv *= _SnowUVScales.xy;
|
|
float2 dx = ddx(uv);
|
|
float2 dy = ddy(uv);
|
|
|
|
#if _USEGLOBALSNOWLEVEL
|
|
float snowLevel = _Global_SnowLevel;
|
|
#else
|
|
float snowLevel = _SnowAmount;
|
|
#endif
|
|
|
|
#if _USEGLOBALSNOWHEIGHT
|
|
float snowMin = _Global_SnowMinMaxHeight.x;
|
|
float snowMax = _Global_SnowMinMaxHeight.y;
|
|
#else
|
|
float snowMin = _SnowHeightAngleRange.x;
|
|
float snowMax = _SnowHeightAngleRange.y;
|
|
#endif
|
|
|
|
half2 levelMaxMin = half2(1,0);
|
|
#if _SNOWMASK
|
|
#if _MEGASPLAT
|
|
levelMaxMin = i.fx2.yx;
|
|
#else
|
|
levelMaxMin = SAMPLE_TEXTURE2D_GRAD(_SnowMask, shared_linear_clamp_sampler, maskUV, ddx(maskUV), ddy(maskUV));
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
float snowAge = _SnowParams.z;
|
|
float snowErosion = _SnowParams.y;
|
|
float snowHeight = _SnowParams.x;
|
|
|
|
float3 snowUpVector = _SnowUpVector;
|
|
float worldHeight = i.worldHeight;
|
|
#if _PLANETVECTORS
|
|
snowUpVector = i.worldUpVector;
|
|
#endif
|
|
|
|
half snowDot = max(snowLevel/2, dot(worldNormal, snowUpVector));
|
|
half snowDotVertex = max(snowLevel/2, dot(worldNormalVertex, snowUpVector));
|
|
float snowFade = SnowFade(worldHeight, snowMin, snowMax, snowDot, snowDotVertex, snowLevel, puddleHeight);
|
|
|
|
|
|
MSBRANCHOTHER(snowFade)
|
|
{
|
|
|
|
half4 snowAlb = SAMPLE_TEXTURE2D_GRAD(_SnowDiff, sampler_Diffuse, uv, dx, dy);
|
|
half4 snowNsao = SAMPLE_TEXTURE2D_GRAD(_SnowNormal, sampler_NormalSAO, uv, dx, dy).agrb;
|
|
COUNTSAMPLE
|
|
COUNTSAMPLE
|
|
|
|
snowAlb.rgb *= _SnowTint.rgb;
|
|
|
|
#if _SNOWNORMALNOISE
|
|
{
|
|
float2 normalUV = uv * _SnowNormalNoiseScaleStrength.x;
|
|
half3 noise = UnpackNormal(SAMPLE_TEXTURE2D_GRAD(_SnowNormalNoise, sampler_Diffuse, normalUV, dx * _SnowNormalNoiseScaleStrength.x, dy * _SnowNormalNoiseScaleStrength.x));
|
|
|
|
snowNsao.xy = lerp(snowNsao.xy, BlendNormal2(snowNsao.xy, noise.xy), _SnowNormalNoiseScaleStrength.y);
|
|
}
|
|
|
|
#endif
|
|
|
|
half3 snowNormal = float3(snowNsao.xy * 2 - 1, 1);
|
|
half ao = o.Occlusion;
|
|
|
|
half height = saturate(o.Height - (1-snowHeight));
|
|
half erosion = saturate(ao * snowErosion);
|
|
erosion *= erosion;
|
|
half snowMask = saturate(snowFade - erosion - height);
|
|
snowMask = snowMask * snowMask * snowMask;
|
|
half snowAmount = snowMask * saturate(snowDot - (height + erosion) * 0.5); // up
|
|
snowAmount = saturate(snowAmount * 8);
|
|
|
|
float wetnessMask = saturate((_SnowParams.w * (4.0 * snowFade) - (snowNsao.b) * 0.5));
|
|
|
|
float snowNormalAmount = snowAmount * snowAmount;
|
|
|
|
float porosity = saturate((((1.0 - o.Smoothness) - 0.5)) / max(surfPorosity, 0.001));
|
|
float factor = lerp(1, 0.4, porosity);
|
|
|
|
o.Albedo *= lerp(1.0, factor, wetnessMask);
|
|
o.Normal = lerp(o.Normal, float3(0,0,1), wetnessMask);
|
|
o.Smoothness = lerp(o.Smoothness, 0.8, wetnessMask);
|
|
|
|
|
|
o.Albedo = lerp(o.Albedo, snowAlb.rgb, snowAmount);
|
|
o.Normal = lerp(o.Normal, snowNormal, snowNormalAmount);
|
|
o.Smoothness = lerp(o.Smoothness, (snowNsao.b) * snowAge, snowAmount);
|
|
o.Occlusion = lerp(o.Occlusion, snowNsao.w, snowAmount);
|
|
o.Height = lerp(o.Height, snowAlb.a, snowAmount);
|
|
o.Metallic = lerp(o.Metallic, 0.01, snowAmount);
|
|
float crystals = saturate(0.65 - snowNsao.b);
|
|
o.Smoothness = lerp(o.Smoothness, crystals * snowAge, snowAmount);
|
|
|
|
#if _SNOWSPARKLE
|
|
DoSnowSparkle(i, o, i.viewDir, worldPos, worldNormalVertex, snowAmount);
|
|
#endif
|
|
|
|
#if _SNOWRIM
|
|
DoSnowRim(o, i, snowAmount);
|
|
#endif
|
|
|
|
return snowAmount;
|
|
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|