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

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
}