You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
381 lines
15 KiB
Plaintext
381 lines
15 KiB
Plaintext
|
|
|
|
TEXTURE2D(_ScatterControl);
|
|
TEXTURE2D_ARRAY(_ScatterDiffuse); // use diffuse sampler
|
|
TEXTURE2D_ARRAY(_ScatterNSAO); // use normalNSAO sampler
|
|
SamplerState my_point_repeat_sampler;
|
|
|
|
struct ScatterVirtualMapping
|
|
{
|
|
float3 weights;
|
|
fixed4 c0, c1, c2;
|
|
};
|
|
|
|
float3 ScatterBarycentric(float2 p, float2 a, float2 b, float2 c)
|
|
{
|
|
float2 v0 = b - a;
|
|
float2 v1 = c - a;
|
|
float2 v2 = p - a;
|
|
float d00 = dot(v0, v0);
|
|
float d01 = dot(v0, v1);
|
|
float d11 = dot(v1, v1);
|
|
float d20 = dot(v2, v0);
|
|
float d21 = dot(v2, v1);
|
|
float denom = d00 * d11 - d01 * d01;
|
|
float v = (d11 * d20 - d01 * d21) / denom;
|
|
float w = (d00 * d21 - d01 * d20) / denom;
|
|
float u = 1.0f - v - w;
|
|
return float3(u, v, w);
|
|
}
|
|
|
|
|
|
ScatterVirtualMapping GenerateScatterMapping(float2 uv)
|
|
{
|
|
float2 texSize = _ScatterControl_TexelSize.zw;
|
|
float2 stp = _ScatterControl_TexelSize.xy;
|
|
// scale coords so we can take floor/frac to construct a cell
|
|
float2 stepped = uv.xy * texSize;
|
|
float2 uvBottom = floor(stepped);
|
|
float2 uvFrac = frac(stepped);
|
|
uvBottom /= texSize;
|
|
|
|
float2 center = stp * 0.5;
|
|
uvBottom += center;
|
|
|
|
// construct uv/positions of triangle based on our interpolation point
|
|
float2 cuv0, cuv1, cuv2;
|
|
// make virtual triangle
|
|
if (uvFrac.x > uvFrac.y)
|
|
{
|
|
cuv0 = uvBottom;
|
|
cuv1 = uvBottom + float2(stp.x, 0);
|
|
cuv2 = uvBottom + float2(stp.x, stp.y);
|
|
}
|
|
else
|
|
{
|
|
cuv0 = uvBottom;
|
|
cuv1 = uvBottom + float2(0, stp.y);
|
|
cuv2 = uvBottom + float2(stp.x, stp.y);
|
|
}
|
|
|
|
float2 uvBaryFrac = uvFrac * stp + uvBottom;
|
|
float3 weights = ScatterBarycentric(uvBaryFrac, cuv0, cuv1, cuv2);
|
|
ScatterVirtualMapping m = (ScatterVirtualMapping)0;
|
|
m.weights = weights;
|
|
m.c0 = SAMPLE_TEXTURE2D_LOD(_ScatterControl, shared_linear_clamp_sampler, cuv0, 0);
|
|
m.c1 = SAMPLE_TEXTURE2D_LOD(_ScatterControl, shared_linear_clamp_sampler, cuv1, 0);
|
|
m.c2 = SAMPLE_TEXTURE2D_LOD(_ScatterControl, shared_linear_clamp_sampler, cuv2, 0);
|
|
return m;
|
|
}
|
|
|
|
float ScatterFilter(float slope, float2 range, float contrast)
|
|
{
|
|
if (range.x > range.y)
|
|
{
|
|
slope = 1 - slope;
|
|
float t = range.x;
|
|
range.x = range.y;
|
|
range.y = t;
|
|
}
|
|
|
|
half w = max(0, (slope - range.x) * contrast);
|
|
w = w * (1 - max(0, (slope - range.y) * contrast));
|
|
return saturate(w);
|
|
}
|
|
|
|
half3 ScatterBlendAlbedo(half4 albedo, half4 a, float mode, float alpha, float alphaMult, float weight)
|
|
{
|
|
if (mode < 0.5) // alpha
|
|
{
|
|
return lerp(albedo.rgb, a.rgb, alpha * weight * a.a * alphaMult);
|
|
}
|
|
else if (mode < 1.5) // alpha clip
|
|
{
|
|
float faq = saturate(((alpha >= a.a)) * (a.a > 0.001));
|
|
return lerp(albedo.rgb, a.rgb, weight * alphaMult * faq);
|
|
}
|
|
else if (mode < 2.5) // overlay
|
|
{
|
|
return lerp(albedo.rgb, BlendOverlay(albedo.rgb, a.rgb), alpha * weight * a.a * alphaMult);
|
|
}
|
|
else if (mode < 3.5) // overlay
|
|
{
|
|
return lerp(albedo.rgb, BlendLighterColor(albedo.rgb, a.rgb), alpha * weight * a.a * alphaMult);
|
|
}
|
|
return albedo.rgb;
|
|
}
|
|
|
|
half4 ScatterBlendNormal(half4 normSAO, half4 n, half4 a, float mode, float alpha, float alphaMult, float weight)
|
|
{
|
|
if (mode < 0.5) // alpha
|
|
{
|
|
return lerp(normSAO, n, alpha * weight * a.a * alphaMult);
|
|
}
|
|
else if (mode < 1.5) // alpha clip
|
|
{
|
|
return (alpha >= a.a) ? lerp(normSAO, n, weight * alphaMult * (a.a > 0.001)) : normSAO;
|
|
}
|
|
else if (mode < 3.5) // overlay
|
|
{
|
|
half4 ret = lerp(normSAO, n, weight * a.a * alphaMult);
|
|
ret.xy = lerp(normSAO.xy, BlendNormal2(normSAO.xy, n.xy), alpha * weight * a.a * alphaMult);
|
|
return ret;
|
|
}
|
|
return normSAO;
|
|
}
|
|
#if _SURFACENORMALS
|
|
half3 ScatterBlendGradient(half3 surfGrad, half4 n, half4 a, float mode, float alpha, float alphaMult, float weight)
|
|
{
|
|
half3 grad = ConvertNormal2ToGradient(n.xy);
|
|
if (mode < 0.5) // alpha
|
|
{
|
|
return lerp(surfGrad, grad, alpha * weight * a.a * alphaMult);
|
|
}
|
|
else if (mode < 1.5) // alpha clip
|
|
{
|
|
return (alpha >= a.a) ? lerp(surfGrad, grad, weight * alphaMult * (a.a > 0.001)) : surfGrad;
|
|
}
|
|
else if (mode < 3.5) // overlay
|
|
{
|
|
return surfGrad + grad * alpha * weight * a.a * alphaMult;
|
|
}
|
|
return surfGrad;
|
|
}
|
|
#endif
|
|
|
|
void SampleLayer(Input i, inout half4 albedo, inout half4 normalSAO, inout half3 surfGrad, float2 uv, float camDist,
|
|
int i0, int i1, int i2, half3 weights, float alpha, float2 uvOffset)
|
|
{
|
|
|
|
float2 dx = ddx(uv);
|
|
float2 dy = ddy(uv);
|
|
|
|
half4 alb = half4(0,0,0,1);
|
|
half4 nsao = half4(0.5, 0.5, 0, 1);
|
|
|
|
|
|
half4 alphaDist0 = 1;
|
|
half4 alphaDist1 = 1;
|
|
|
|
float2 scale0 = 1;
|
|
float2 scale1 = 1;
|
|
float2 scale2 = 1;
|
|
float blend0 = 0;
|
|
float blend1 = 0;
|
|
float blend2 = 0;
|
|
float alphaMult0 = 1;
|
|
float alphaMult1 = 1;
|
|
float alphaMult2 = 1;
|
|
|
|
|
|
float mask0 = 1;
|
|
float mask1 = 1;
|
|
float mask2 = 1;
|
|
|
|
#if _PERTEXSCATTERUV || _PERTEXSCATTERBLENDMODE || _PERTEXSCATTERALPHABOOST
|
|
float4 pt0 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2((float)i0*_PerTexProps_TexelSize.x, 24.5/32), 0);
|
|
float4 pt1 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2((float)i1*_PerTexProps_TexelSize.x, 24.5/32), 0);
|
|
float4 pt2 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2((float)i2*_PerTexProps_TexelSize.x, 24.5/32), 0);
|
|
|
|
#if _PERTEXSCATTERUV
|
|
scale0 = pt0.xy; scale1 = pt1.xy; scale2 = pt2.xy;
|
|
#endif
|
|
|
|
#if _PERTEXSCATTERBLENDMODE
|
|
blend0 = pt0.b;
|
|
blend1 = pt1.b;
|
|
blend2 = pt2.b;
|
|
#endif
|
|
|
|
#if _PERTEXSCATTERALPHABOOST
|
|
alphaMult0 = pt0.a;
|
|
alphaMult1 = pt1.a;
|
|
alphaMult2 = pt2.a;
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if _PERTEXSCATTERHEIGHTFILTER || _PERTEXSCATTERSLOPEFILTER
|
|
float4 ptHS0 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2((float)i0*_PerTexProps_TexelSize.x, 25.5/32), 0);
|
|
float4 ptHS1 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2((float)i1*_PerTexProps_TexelSize.x, 25.5/32), 0);
|
|
float4 ptHS2 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2((float)i2*_PerTexProps_TexelSize.x, 25.5/32), 0);
|
|
|
|
ptHS0.x *= 2;
|
|
ptHS0.x -= 1;
|
|
ptHS1.x *= 2;
|
|
ptHS1.x -= 1;
|
|
ptHS2.x *= 2;
|
|
ptHS2.x -= 1;
|
|
|
|
#if _PERTEXSCATTERHEIGHTFILTER
|
|
mask0 *= ScatterFilter(albedo.a, ptHS0.xy, 6);
|
|
mask1 *= ScatterFilter(albedo.a, ptHS1.xy, 6);
|
|
mask2 *= ScatterFilter(albedo.a, ptHS2.xy, 6);
|
|
#endif
|
|
|
|
#if _PERTEXSCATTERSLOPEFILTER
|
|
float slope = sqrt(saturate(dot(normalSAO.xy, normalSAO.xy))); //dot(WorldNormalVector(i, float3(normalSAO.xy, 1)), float3(0,1,0));
|
|
mask0 *= ScatterFilter(slope, ptHS0.zw, 6);
|
|
mask1 *= ScatterFilter(slope, ptHS1.zw, 6);
|
|
mask2 *= ScatterFilter(slope, ptHS2.zw, 6);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
half4 a0 = SAMPLE_TEXTURE2D_ARRAY_GRAD(_ScatterDiffuse, sampler_Diffuse, uv * scale0 + uvOffset, i0, dx * scale0, dy * scale0);
|
|
half4 a1 = SAMPLE_TEXTURE2D_ARRAY_GRAD(_ScatterDiffuse, sampler_Diffuse, uv * scale1 + uvOffset, i1, dx * scale1, dy * scale1);
|
|
half4 a2 = SAMPLE_TEXTURE2D_ARRAY_GRAD(_ScatterDiffuse, sampler_Diffuse, uv * scale2 + uvOffset, i2, dx * scale2, dy * scale2);
|
|
|
|
if (blend0 == 1)
|
|
{
|
|
a0.a = SAMPLE_TEXTURE2D_ARRAY_GRAD(_ScatterDiffuse, my_point_repeat_sampler, uv * scale0 + uvOffset, i0, dx * scale0 * 0.3, dy * scale0 * 3).a;
|
|
}
|
|
if (blend1 == 1)
|
|
{
|
|
a1.a = SAMPLE_TEXTURE2D_ARRAY_GRAD(_ScatterDiffuse, my_point_repeat_sampler, uv * scale1 + uvOffset, i1, dx * scale1 * 0.3, dy * scale1 * 3).a;
|
|
}
|
|
if (blend2 == 1)
|
|
{
|
|
a2.a = SAMPLE_TEXTURE2D_ARRAY_GRAD(_ScatterDiffuse, my_point_repeat_sampler, uv * scale2 + uvOffset, i2, dx * scale2 * 0.3, dy * scale2 * 3).a;
|
|
}
|
|
|
|
half4 n0 = 0;
|
|
half4 n1 = 0;
|
|
half4 n2 = 0;
|
|
|
|
n0 = SAMPLE_TEXTURE2D_ARRAY_GRAD(_ScatterNSAO, sampler_NormalSAO, uv * scale0 + uvOffset, i0, dx * scale0, dy * scale0).agrb;
|
|
n1 = SAMPLE_TEXTURE2D_ARRAY_GRAD(_ScatterNSAO, sampler_NormalSAO, uv * scale1 + uvOffset, i1, dx * scale1, dy * scale1).agrb;
|
|
n2 = SAMPLE_TEXTURE2D_ARRAY_GRAD(_ScatterNSAO, sampler_NormalSAO, uv * scale2 + uvOffset, i2, dx * scale2, dy * scale2).agrb;
|
|
n0.xy *= 2;
|
|
n0.xy -= 1;
|
|
n1.xy *= 2;
|
|
n1.xy -= 1;
|
|
n2.xy *= 2;
|
|
n2.xy -= 1;
|
|
|
|
|
|
if (i0 < 0) { a0 = albedo; n0 = normalSAO; }
|
|
if (i1 < 0) { a1 = albedo; n1 = normalSAO; }
|
|
if (i2 < 0) { a2 = albedo; n2 = normalSAO; }
|
|
|
|
|
|
#if _STARREACHFORMAT
|
|
// this format has alpha in the AO channel, and height in the regular height channel.
|
|
// AO is computed analytically
|
|
a0.a = n0.w; n0.w = length(n0.xy);
|
|
a1.a = n1.w; n1.w = length(n1.xy);
|
|
a2.a = n2.w; n2.w = length(n2.xy);
|
|
#endif
|
|
|
|
// bias alpha to half current value over the mip range
|
|
#if _PERTEXSCATTERFADE
|
|
float4 ptDF0 = SAMPLE_TEXTURE_LOD(_PerTexProps, shared_point_clamp_sampler, float2((float)i0*_PerTexProps_TexelSize.x, 26.5/32), 0);
|
|
float4 ptDF1 = SAMPLE_TEXTURE_LOD(_PerTexProps, shared_point_clamp_sampler, float2((float)i1*_PerTexProps_TexelSize.x, 26.5/32), 0);
|
|
float4 ptDF2 = SAMPLE_TEXTURE_LOD(_PerTexProps, shared_point_clamp_sampler, float2((float)i2*_PerTexProps_TexelSize.x, 26.5/32), 0);
|
|
|
|
float mip0 = ComputeMipLevel(uv * scale0, _ScatterDiffuse_TexelSize.zw);
|
|
float mip1 = ComputeMipLevel(uv * scale1, _ScatterDiffuse_TexelSize.zw);
|
|
float mip2 = ComputeMipLevel(uv * scale2, _ScatterDiffuse_TexelSize.zw);
|
|
|
|
float mipDiv = log2(_ScatterDiffuse_TexelSize.zw);
|
|
mip0 = saturate((mip0 / mipDiv) * ptDF0.x);
|
|
mip1 = saturate((mip1 / mipDiv) * ptDF1.x);
|
|
mip2 = saturate((mip2 / mipDiv) * ptDF2.x);
|
|
|
|
alphaMult0 *= (1-mip0);
|
|
alphaMult1 *= (1-mip1);
|
|
alphaMult2 *= (1-mip2);
|
|
#endif
|
|
|
|
albedo.rgb = ScatterBlendAlbedo(albedo, a0, blend0, alpha * mask0, alphaMult0, weights.x);
|
|
albedo.rgb = ScatterBlendAlbedo(albedo, a1, blend1, alpha * mask1, alphaMult1, weights.y);
|
|
albedo.rgb = ScatterBlendAlbedo(albedo, a2, blend2, alpha * mask2, alphaMult2, weights.z);
|
|
|
|
normalSAO = ScatterBlendNormal(normalSAO, n0, a0, blend0, alpha * mask0, alphaMult0, weights.x);
|
|
normalSAO = ScatterBlendNormal(normalSAO, n1, a1, blend1, alpha * mask1, alphaMult1, weights.y);
|
|
normalSAO = ScatterBlendNormal(normalSAO, n2, a2, blend2, alpha * mask2, alphaMult2, weights.z);
|
|
|
|
|
|
#if _SURFACENORMALS
|
|
surfGrad = ScatterBlendGradient(surfGrad, n0, a0, blend0, alpha * mask0, alphaMult0, weights.x);
|
|
surfGrad = ScatterBlendGradient(surfGrad, n1, a1, blend1, alpha * mask1, alphaMult1, weights.y);
|
|
surfGrad = ScatterBlendGradient(surfGrad, n2, a2, blend2, alpha * mask2, alphaMult2, weights.z);
|
|
#endif
|
|
}
|
|
|
|
void ApplyScatter(
|
|
#if _MEGASPLAT
|
|
Config config,
|
|
#endif
|
|
Input i, inout half4 albedo, inout half4 normalSAO, inout half3 surfGrad, float2 controlUV, float camDist)
|
|
{
|
|
|
|
#if _MEGASPLAT
|
|
MSBRANCHOTHER(i.scatter0.w)
|
|
{
|
|
int i0 = round((i.scatter0.x * 255) / max(i.baryWeights.x, 0.00001));
|
|
int i1 = round((i.scatter0.y * 255) / max(i.baryWeights.y, 0.00001));
|
|
int i2 = round((i.scatter0.z * 255) / max(i.baryWeights.z, 0.00001));
|
|
#if _STARREACHFORMAT
|
|
if (i0 == 255) i0 = config.uv0.z;
|
|
if (i1 == 255) i1 = config.uv0.z;
|
|
if (i2 == 255) i2 = config.uv0.z;
|
|
#endif
|
|
SampleLayer(i, albedo, normalSAO, surfGrad, controlUV * _ScatterUVScale, camDist, i0, i1, i2, i.baryWeights.xyz, i.scatter0.w, float2(0, 0));
|
|
}
|
|
#if _SPLATTERSECONDLAYER
|
|
MSBRANCHOTHER(i.scatter1.w)
|
|
{
|
|
int i3 = round((i.scatter1.x * 255) / max(i.baryWeights.x, 0.00001));
|
|
int i4 = round((i.scatter1.y * 255) / max(i.baryWeights.y, 0.00001));
|
|
int i5 = round((i.scatter1.z * 255) / max(i.baryWeights.z, 0.00001));
|
|
#if _STARREACHFORMAT
|
|
if (i3 == 255) i3 = config.uv0.z;
|
|
if (i4 == 255) i4 = config.uv0.z;
|
|
if (i5 == 255) i5 = config.uv0.z;
|
|
#endif
|
|
SampleLayer(i, albedo, normalSAO, surfGrad, controlUV * _ScatterUVScale2.xy + _ScatterUVScale2.zw, camDist, i3, i4, i5, i.baryWeights.xyz, i.scatter1.w, float2(0.5, 0.5));
|
|
}
|
|
#endif
|
|
#else
|
|
half4 c = SAMPLE_TEXTURE2D(_ScatterControl, shared_linear_clamp_sampler, controlUV);
|
|
|
|
half brnch = c.g;
|
|
#if _SPLATTERSECONDLAYER
|
|
brnch += c.b;
|
|
#endif
|
|
|
|
// note, second layer is swizzled wz so alpha of 1 doesn't cause an issue.
|
|
|
|
MSBRANCHOTHER(brnch)
|
|
{
|
|
ScatterVirtualMapping m = GenerateScatterMapping(controlUV);
|
|
int i0, i1, i2;
|
|
|
|
MSBRANCHOTHER(c.g)
|
|
{
|
|
i0 = (m.c0.r * 64) - 1;
|
|
i1 = (m.c1.r * 64) - 1;
|
|
i2 = (m.c2.r * 64) - 1;
|
|
SampleLayer(i, albedo, normalSAO, surfGrad, controlUV * _ScatterUVScale, camDist, i0, i1, i2, m.weights.xyz, c.g, float2(0, 0));
|
|
}
|
|
|
|
#if _SPLATTERSECONDLAYER
|
|
MSBRANCHOTHER(c.b)
|
|
{
|
|
i0 = (m.c0.a * 64) - 1;
|
|
i1 = (m.c1.a * 64) - 1;
|
|
i2 = (m.c2.a * 64) - 1;
|
|
|
|
SampleLayer(i, albedo, normalSAO, surfGrad, controlUV * _ScatterUVScale2.xy + _ScatterUVScale2.zw, camDist, i0, i1, i2, m.weights.xyz, c.b, float2(0.5, 0.5));
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|