Files
Fishing2/Packages/com.jbooth.microsplat.terrain-blending/Scripts/Editor/Fragments/microsplat_terrainblend_body.txt
2025-06-04 09:09:39 +08:00

176 lines
6.3 KiB
Plaintext

#if _TBOBJECTNORMALBLEND
sampler2D _NormalOriginal;
#endif
float4 SampleInstancedTerrainDesc(float2 uv)
{
float2 origUV = uv;
// because unity uses power of 2 + 1 texture sizes, the last pixel is a wrap pixel, so we have to
// futz the UVs
uv = (uv * (_PerPixelNormal_TexelSize.zw - 1.0f) + 0.5f) * _PerPixelNormal_TexelSize.xy;
// unity also only uses 0 to 0.5 in the texture, wasting half the precision for no reason and making
// us have to multiply by 2, which is undocumented of course.
float height = UnpackHeightmap(SAMPLE_TEXTURE2D(_TerrainHeightmapTexture, shared_linear_clamp_sampler, origUV)) * 2;
height *= _TerrainHeightmapScale.y;
float4 normSamp = SAMPLE_TEXTURE2D(_PerPixelNormal, shared_linear_clamp_sampler, uv);
float3 normal = normalize(normSamp.xyz * 2 - 1);
return float4(normal, height);
}
float4 SampleTerrainDesc(inout ShaderData d, out float normBlend)
{
float2 worldUV = (d.worldSpacePosition.xz - _TerrainBounds.xy);
float2 uv = worldUV / max(float2(0.001, 0.001), _TerrainBounds.zw);
float4 th = SampleInstancedTerrainDesc(uv);
th.w += _TerrainBlendParams.z; // add terrain height and center..
float db = abs(th.w - d.worldSpacePosition.y);
normBlend = saturate(db / max(0.0001, _SlopeBlendParams.w));
th.w = saturate(db / max(0.0001, _TerrainBlendParams.x));
th.w = pow(th.w, _TerrainBlendParams.w);
#if !_SNOW
clip(0.999-th.w * _FeatureFilters.y < 1);
#endif
return th;
}
float3x3 ComputeTerrainTBN(float4 th, out float3 terrainTangent, out float3 terrainBitangent)
{
terrainTangent = (cross(th.xyz, float3(0,0,-1)));
terrainBitangent = (cross(th.xyz, terrainTangent));
float3x3 tbn = float3x3(terrainTangent, terrainBitangent, th.xyz);
return tbn;
}
float3 GetWorldNormalBlend(ShaderData d, float4 th, float normBlend)
{
float3 worldNormalBlend = th.xyz;
#if _SNOW || _TRIPLANAR
worldNormalBlend = lerp(th.xyz, d.worldSpaceNormal, normBlend);
#endif
return worldNormalBlend;
}
float Dither8x8Bayer( int x, int y )
{
const float dither[ 64 ] = {
1, 49, 13, 61, 4, 52, 16, 64,
33, 17, 45, 29, 36, 20, 48, 32,
9, 57, 5, 53, 12, 60, 8, 56,
41, 25, 37, 21, 44, 28, 40, 24,
3, 51, 15, 63, 2, 50, 14, 62,
35, 19, 47, 31, 34, 18, 46, 30,
11, 59, 7, 55, 10, 58, 6, 54,
43, 27, 39, 23, 42, 26, 38, 22};
int r = y * 8 + x;
return dither[r] / 64;
}
void ApplyDitherFade(float2 vpos, float fadeValue)
{
if (fadeValue <= 0) clip(-1);
float dither = Dither8x8Bayer( fmod(vpos.x, 8), fmod(vpos.y, 8) );
float sgn = fadeValue > 0 ? 1.0f : -1.0f;
clip(dither - (1-fadeValue) * sgn);
}
MicroSplatLayer DoTerrainLayer(inout ShaderData d, float4 th, inout float3 worldNormalBlend, float3x3 tbn, out float rawalpha)
{
MicroSplatLayer terrainS = (MicroSplatLayer)0;
terrainS.Normal = half3(0, 1, 0);
Input input = DescToInput(d);
float2 worldUV = (d.worldSpacePosition.xz - _TerrainBounds.xy);
float2 uv = worldUV / max(float2(0.001, 0.001), _TerrainBounds.zw);
input.uv_Control0 = uv;
float alpha = 1;
float slope = 1;
rawalpha = 1;
if (_FeatureFilters.x < 1)
{
terrainS = SurfImpl(input, worldNormalBlend);
alpha = (1.0-th.w);
// slope
#if _TBOBJECTNORMALBLEND
float3 normalCustom = UnpackNormal (tex2D (_NormalOriginal, d.texcoord0.xy));
half3 slopeNormal = WorldNormalVector (input, normalCustom);
#else
half3 slopeNormal = d.worldSpaceNormal;
#endif
slopeNormal.xz += terrainS.Normal.xy * _SlopeBlendParams.z;
slopeNormal = normalize(slopeNormal);
slope = max(0, (dot(slopeNormal, half3(0, 1, 0)) - _SlopeBlendParams.x) * _SlopeBlendParams.y);
half noiseHeight = 0.5;
#if _TBNOISE
noiseHeight = Noise3D(d.worldSpacePosition * _TBNoiseScale);
#elif _TBNOISEFBM
noiseHeight = FBM3D(d.worldSpacePosition * _TBNoiseScale);
#endif
rawalpha = min(alpha, 1);
alpha = min(alpha + slope, 1);
alpha = lerp(alpha, HeightBlend(noiseHeight, terrainS.Height, alpha, _TerrainBlendParams.y), _TerrainBlendParams.y);
#if !_TBDISABLE_ALPHACONTROL
alpha *= d.vertexColor.a;
#endif
}
#if _SNOW
if (_FeatureFilters.y < 1)
{
worldNormalBlend = lerp(worldNormalBlend, half3(0,1,0), _SnowBlendParams.x);
alpha = max(alpha, DoSnowSimple(input, terrainS, uv, mul(terrainS.Normal, tbn), worldNormalBlend, d.worldSpacePosition, 0, 0.4));
}
#endif
terrainS.Alpha = alpha;
#if _TBDITHERALPHA
float4 screenPosNorm = d.screenPos / d.screenPos.w;
float2 clipScreen = screenPosNorm.xy * _ScreenParams.xy;
float camDist = distance(d.worldSpacePosition, _WorldSpaceCameraPos);
ApplyDitherFade(clipScreen, alpha);
alpha = 1;
#endif
return terrainS;
}
MicroSplatLayer BlendWithTerrain(inout ShaderData d)
{
float normBlend;
float4 th = SampleTerrainDesc(d, normBlend);
float3 tang; float3 bitang;
float3x3 tbn = ComputeTerrainTBN(th, tang, bitang);
float3 worldNormalBlend = GetWorldNormalBlend(d, th, normBlend);
float rawalpha = 1;
MicroSplatLayer l = DoTerrainLayer(d, th, worldNormalBlend, tbn, rawalpha);
rawalpha = pow(rawalpha, _TerrainBlendParams2.x);
rawalpha *= 1.0 - saturate(_TerrainBlendParams2.x / 80);
// blend matrix
d.TBNMatrix = lerp(d.TBNMatrix, tbn, rawalpha);
d.worldSpaceNormal = d.TBNMatrix[2];
d.worldSpaceTangent = d.TBNMatrix[0];
return l;
}