272 lines
10 KiB
Plaintext
272 lines
10 KiB
Plaintext
|
|
|
|
void TriplanarPrepSpace(inout float3 worldPos, inout float3 n)
|
|
{
|
|
#if _TRIPLANARLOCALSPACE && !_FORCELOCALSPACE
|
|
worldPos = mul(unity_WorldToObject, float4(worldPos, 1));
|
|
n = mul((float3x3)unity_WorldToObject, n).xyz;
|
|
#endif
|
|
}
|
|
|
|
|
|
float3 TerrainBarycentric(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);
|
|
}
|
|
|
|
float3 GetTerrainBary(float2 uv)
|
|
{
|
|
#if _CUSTOMSPLATTEXTURES
|
|
float2 texSize = _CustomControl0_TexelSize.zw;
|
|
float2 stp = _CustomControl0_TexelSize.xy;
|
|
#else
|
|
float2 texSize = _Control0_TexelSize.zw;
|
|
float2 stp = _Control0_TexelSize.xy;
|
|
#endif
|
|
// scale coords so we can take floor/frac to construct a cell
|
|
float2 stepped = uv * 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;
|
|
return TerrainBarycentric(uvBaryFrac, cuv0, cuv1, cuv2);
|
|
}
|
|
|
|
void TriplanarPrepSurfaceNormals(float4 uv0, inout float3 worldPos, inout float3 n)
|
|
{
|
|
|
|
#if _TRIPLANARUSEFACENORMALS
|
|
float3 dx = ddx(worldPos);
|
|
float3 dy = ddy(worldPos);
|
|
float3 flatNormal = normalize(cross(dy, dx));
|
|
float3 bary = GetTerrainBary(uv0.xy);
|
|
#if _MICROTERRAIN
|
|
float mb = min(bary.x, min(bary.y, bary.z));
|
|
n = lerp(n, flatNormal, saturate(mb * _TriplanarFaceBlend * 20));
|
|
#else
|
|
n = lerp(n, flatNormal, _TriplanarFaceBlend);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
void DoPrepTriplanar(float4 uv0, float3 n, float3 worldPos, Config c, inout TriplanarConfig tc, half4 weights, inout MIPFORMAT albedoLOD,
|
|
inout MIPFORMAT normalLOD, inout MIPFORMAT emisLOD, inout MIPFORMAT origAlbedoLOD)
|
|
{
|
|
|
|
|
|
n = normalize(n);
|
|
tc.pN = pow(abs(n), abs(_TriplanarContrast));
|
|
tc.pN = TotalOne(tc.pN);
|
|
|
|
// Get the sign (-1 or 1) of the surface normal
|
|
half3 axisSign = n < 0 ? -1 : 1;
|
|
axisSign.z *= -1;
|
|
tc.axisSign = axisSign;
|
|
tc.uv0 = float3x3(c.uv0, c.uv0, c.uv0);
|
|
tc.uv1 = float3x3(c.uv1, c.uv1, c.uv1);
|
|
tc.uv2 = float3x3(c.uv2, c.uv2, c.uv2);
|
|
tc.uv3 = float3x3(c.uv3, c.uv3, c.uv3);
|
|
tc.pN0 = tc.pN;
|
|
tc.pN1 = tc.pN;
|
|
tc.pN2 = tc.pN;
|
|
tc.pN3 = tc.pN;
|
|
|
|
|
|
float2 uscale = 0.1 * _TriplanarUVScale.xy; // this was a mistake, but too late to undo.
|
|
float4 triScale = _TriplanarUVScale;
|
|
#if _TERRAINBLENDABLESHADER && _TERRAINBLENDMATCHWORLDUV && _WORLDUV
|
|
uscale = _UVScale.xy;
|
|
triScale.zw = _UVScale.zw;
|
|
#endif
|
|
|
|
tc.uv0[0].xy = (worldPos.zy * uscale + triScale.zw);
|
|
tc.uv0[1].xy = (worldPos.xz * float2(-1,1) * uscale + triScale.zw);
|
|
tc.uv0[2].xy = (worldPos.xy * uscale + triScale.zw);
|
|
#if !_SURFACENORMALS
|
|
tc.uv0[0].x *= axisSign.x;
|
|
tc.uv0[1].x *= axisSign.y;
|
|
tc.uv0[2].x *= axisSign.z;
|
|
#endif
|
|
|
|
tc.uv1[0].xy = tc.uv0[0].xy;
|
|
tc.uv1[1].xy = tc.uv0[1].xy;
|
|
tc.uv1[2].xy = tc.uv0[2].xy;
|
|
|
|
tc.uv2[0].xy = tc.uv0[0].xy;
|
|
tc.uv2[1].xy = tc.uv0[1].xy;
|
|
tc.uv2[2].xy = tc.uv0[2].xy;
|
|
|
|
tc.uv3[0].xy = tc.uv0[0].xy;
|
|
tc.uv3[1].xy = tc.uv0[1].xy;
|
|
tc.uv3[2].xy = tc.uv0[2].xy;
|
|
|
|
|
|
|
|
#if _USEGRADMIP
|
|
albedoLOD.d0 = float4(ddx(tc.uv0[0].xy), ddy(tc.uv0[0].xy));
|
|
albedoLOD.d1 = float4(ddx(tc.uv0[1].xy), ddy(tc.uv0[1].xy));
|
|
albedoLOD.d2 = float4(ddx(tc.uv0[2].xy), ddy(tc.uv0[2].xy));
|
|
normalLOD = albedoLOD;
|
|
emisLOD = albedoLOD;
|
|
#elif _USELODMIP
|
|
albedoLOD.x = ComputeMipLevel(tc.uv0[0].xy, _Diffuse_TexelSize.zw);
|
|
albedoLOD.y = ComputeMipLevel(tc.uv0[1].xy, _Diffuse_TexelSize.zw);
|
|
albedoLOD.z = ComputeMipLevel(tc.uv0[2].xy, _Diffuse_TexelSize.zw);
|
|
normalLOD = albedoLOD;
|
|
emisLOD = albedoLOD;
|
|
#endif
|
|
|
|
origAlbedoLOD = albedoLOD;
|
|
|
|
#if _PERTEXUVSCALEOFFSET
|
|
SAMPLE_PER_TEX(ptUVScale, 0.5, c, half4(1,1,0,0));
|
|
tc.uv0[0].xy = tc.uv0[0].xy * ptUVScale0.xy + ptUVScale0.zw;
|
|
tc.uv0[1].xy = tc.uv0[1].xy * ptUVScale0.xy + ptUVScale0.zw;
|
|
tc.uv0[2].xy = tc.uv0[2].xy * ptUVScale0.xy + ptUVScale0.zw;
|
|
|
|
tc.uv1[0].xy = tc.uv1[0].xy * ptUVScale1.xy + ptUVScale1.zw;
|
|
tc.uv1[1].xy = tc.uv1[1].xy * ptUVScale1.xy + ptUVScale1.zw;
|
|
tc.uv1[2].xy = tc.uv1[2].xy * ptUVScale1.xy + ptUVScale1.zw;
|
|
|
|
#if !_MAX2LAYER
|
|
tc.uv2[0].xy = tc.uv2[0].xy * ptUVScale2.xy + ptUVScale2.zw;
|
|
tc.uv2[1].xy = tc.uv2[1].xy * ptUVScale2.xy + ptUVScale2.zw;
|
|
tc.uv2[2].xy = tc.uv2[2].xy * ptUVScale2.xy + ptUVScale2.zw;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
tc.uv3[0].xy = tc.uv3[0].xy * ptUVScale3.xy + ptUVScale3.zw;
|
|
tc.uv3[1].xy = tc.uv3[1].xy * ptUVScale3.xy + ptUVScale3.zw;
|
|
tc.uv3[2].xy = tc.uv3[2].xy * ptUVScale3.xy + ptUVScale3.zw;
|
|
#endif
|
|
|
|
#if _USEGRADMIP
|
|
albedoLOD.d0 = albedoLOD.d0 * ptUVScale0.xyxy * weights.x +
|
|
albedoLOD.d0 * ptUVScale1.xyxy * weights.y +
|
|
albedoLOD.d0 * ptUVScale2.xyxy * weights.z +
|
|
albedoLOD.d0 * ptUVScale3.xyxy * weights.w;
|
|
|
|
albedoLOD.d1 = albedoLOD.d1 * ptUVScale0.xyxy * weights.x +
|
|
albedoLOD.d1 * ptUVScale1.xyxy * weights.y +
|
|
albedoLOD.d1 * ptUVScale2.xyxy * weights.z +
|
|
albedoLOD.d1 * ptUVScale3.xyxy * weights.w;
|
|
|
|
albedoLOD.d2 = albedoLOD.d2 * ptUVScale0.xyxy * weights.x +
|
|
albedoLOD.d2 * ptUVScale1.xyxy * weights.y +
|
|
albedoLOD.d2 * ptUVScale2.xyxy * weights.z +
|
|
albedoLOD.d2 * ptUVScale3.xyxy * weights.w;
|
|
|
|
|
|
normalLOD.d0 = albedoLOD.d0;
|
|
normalLOD.d1 = albedoLOD.d1;
|
|
normalLOD.d2 = albedoLOD.d2;
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD.d0 = albedoLOD.d0;
|
|
emisLOD.d1 = albedoLOD.d1;
|
|
emisLOD.d2 = albedoLOD.d2;
|
|
#endif
|
|
|
|
#endif
|
|
#else
|
|
#if _USEGRADMIP
|
|
albedoLOD.d0 = albedoLOD.d0 * weights.x +
|
|
albedoLOD.d0 * weights.y +
|
|
albedoLOD.d0 * weights.z +
|
|
albedoLOD.d0 * weights.w;
|
|
|
|
albedoLOD.d1 = albedoLOD.d1 * weights.x +
|
|
albedoLOD.d1 * weights.y +
|
|
albedoLOD.d1 * weights.z +
|
|
albedoLOD.d1 * weights.w;
|
|
|
|
albedoLOD.d2 = albedoLOD.d2 * weights.x +
|
|
albedoLOD.d2 * weights.y +
|
|
albedoLOD.d2 * weights.z +
|
|
albedoLOD.d2 * weights.w;
|
|
|
|
|
|
normalLOD.d0 = albedoLOD.d0;
|
|
normalLOD.d1 = albedoLOD.d1;
|
|
normalLOD.d2 = albedoLOD.d2;
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD.d0 = albedoLOD.d0;
|
|
emisLOD.d1 = albedoLOD.d1;
|
|
emisLOD.d2 = albedoLOD.d2;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXUVROTATION
|
|
SAMPLE_PER_TEX(ptUVRot, 16.5, c, half4(0,0,0,0));
|
|
tc.uv0[0].xy = RotateUV(tc.uv0[0].xy, ptUVRot0.x);
|
|
tc.uv0[1].xy = RotateUV(tc.uv0[1].xy, ptUVRot0.y);
|
|
tc.uv0[2].xy = RotateUV(tc.uv0[2].xy, ptUVRot0.z);
|
|
|
|
tc.uv1[0].xy = RotateUV(tc.uv1[0].xy, ptUVRot1.x);
|
|
tc.uv1[1].xy = RotateUV(tc.uv1[1].xy, ptUVRot1.y);
|
|
tc.uv1[2].xy = RotateUV(tc.uv1[2].xy, ptUVRot1.z);
|
|
#if !_MAX2LAYER
|
|
tc.uv2[0].xy = RotateUV(tc.uv2[0].xy, ptUVRot2.x);
|
|
tc.uv2[1].xy = RotateUV(tc.uv2[1].xy, ptUVRot2.y);
|
|
tc.uv2[2].xy = RotateUV(tc.uv2[2].xy, ptUVRot2.z);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
tc.uv3[0].xy = RotateUV(tc.uv3[0].xy, ptUVRot3.x);
|
|
tc.uv3[1].xy = RotateUV(tc.uv3[1].xy, ptUVRot3.y);
|
|
tc.uv3[2].xy = RotateUV(tc.uv3[2].xy, ptUVRot3.z);
|
|
#endif
|
|
#endif
|
|
|
|
}
|
|
|
|
void PrepTriplanar(float4 uv0, float3 n, float3 worldPos, Config c, inout TriplanarConfig tc, half4 weights, inout MIPFORMAT albedoLOD,
|
|
inout MIPFORMAT normalLOD, inout MIPFORMAT emisLOD, inout MIPFORMAT origAlbedoLOD)
|
|
{
|
|
TriplanarPrepSpace(worldPos, n);
|
|
TriplanarPrepSurfaceNormals(uv0, worldPos, n);
|
|
DoPrepTriplanar(uv0, n, worldPos, c, tc, weights, albedoLOD, normalLOD, emisLOD, origAlbedoLOD);
|
|
}
|
|
|
|
void PrepTriplanarDisplace(float4 uv0, float3 n, float3 worldPos, Config c, inout TriplanarConfig tc, half4 weights, inout MIPFORMAT albedoLOD,
|
|
inout MIPFORMAT normalLOD, inout MIPFORMAT emisLOD, inout MIPFORMAT origAlbedoLOD)
|
|
{
|
|
TriplanarPrepSpace(worldPos, n);
|
|
DoPrepTriplanar(uv0, n, worldPos, c, tc, weights, albedoLOD, normalLOD, emisLOD, origAlbedoLOD);
|
|
}
|
|
|
|
|
|
|