Files
Fishing2/Packages/com.jbooth.microsplat.triplanar/Scripts/Editor/microsplat_func_triplanar.txt
2025-06-04 09:09:39 +08:00

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);
}