176 lines
6.3 KiB
Plaintext
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;
|
|
}
|
|
|
|
|