diff --git a/Content/Editor/MaterialTemplates/Terrain.shader b/Content/Editor/MaterialTemplates/Terrain.shader index abc444316..63313e304 100644 --- a/Content/Editor/MaterialTemplates/Terrain.shader +++ b/Content/Editor/MaterialTemplates/Terrain.shader @@ -15,6 +15,7 @@ #include "./Flax/Common.hlsl" #include "./Flax/MaterialCommon.hlsl" #include "./Flax/GBufferCommon.hlsl" +#include "./Flax/TerrainCommon.hlsl" @7 // Primary constant buffer (with additional material parameters) META_CB_BEGIN(0, Data) @@ -334,7 +335,7 @@ VertexOutput VS(TerrainVertexInput input) float lodValue = CurrentLOD; float morphAlpha = lodCalculated - CurrentLOD; - // Sample heightmap + // Sample heightmap and splatmaps float2 heightmapUVs = input.TexCoord * HeightmapUVScaleBias.xy + HeightmapUVScaleBias.zw; #if USE_SMOOTH_LOD_TRANSITION float4 heightmapValueThisLOD = Heightmap.SampleLevel(SamplerPointClamp, heightmapUVs, lodValue); @@ -342,7 +343,6 @@ VertexOutput VS(TerrainVertexInput input) float2 heightmapUVsNextLOD = nextLODPos * HeightmapUVScaleBias.xy + HeightmapUVScaleBias.zw; float4 heightmapValueNextLOD = Heightmap.SampleLevel(SamplerPointClamp, heightmapUVsNextLOD, lodValue + 1); float4 heightmapValue = lerp(heightmapValueThisLOD, heightmapValueNextLOD, morphAlpha); - bool isHole = max(heightmapValueThisLOD.b + heightmapValueThisLOD.a, heightmapValueNextLOD.b + heightmapValueNextLOD.a) >= 1.9f; #if USE_TERRAIN_LAYERS float4 splatmapValueThisLOD = Splatmap0.SampleLevel(SamplerPointClamp, heightmapUVs, lodValue); float4 splatmapValueNextLOD = Splatmap0.SampleLevel(SamplerPointClamp, heightmapUVsNextLOD, lodValue + 1); @@ -355,7 +355,6 @@ VertexOutput VS(TerrainVertexInput input) #endif #else float4 heightmapValue = Heightmap.SampleLevel(SamplerPointClamp, heightmapUVs, lodValue); - bool isHole = (heightmapValue.b + heightmapValue.a) >= 1.9f; #if USE_TERRAIN_LAYERS float4 splatmap0Value = Splatmap0.SampleLevel(SamplerPointClamp, heightmapUVs, lodValue); #if TERRAIN_LAYERS_DATA_SIZE > 1 @@ -363,12 +362,11 @@ VertexOutput VS(TerrainVertexInput input) #endif #endif #endif - float height = (float)((int)(heightmapValue.x * 255.0) + ((int)(heightmapValue.y * 255) << 8)) / 65535.0; + float height = DecodeHeightmapHeight(heightmapValue); // Extract normal and the holes mask - float2 normalTemp = float2(heightmapValue.b, heightmapValue.a) * 2.0f - 1.0f; - float3 normal = float3(normalTemp.x, sqrt(1.0 - saturate(dot(normalTemp, normalTemp))), normalTemp.y); - normal = normalize(normal); + bool isHole; + float3 normal = DecodeHeightmapNormal(heightmapValue, isHole); output.Geometry.HolesMask = isHole ? 0 : 1; if (isHole) { diff --git a/Source/Engine/Visject/ShaderGraph.cpp b/Source/Engine/Visject/ShaderGraph.cpp index ef4f53cf9..b6616d159 100644 --- a/Source/Engine/Visject/ShaderGraph.cpp +++ b/Source/Engine/Visject/ShaderGraph.cpp @@ -286,7 +286,7 @@ void ShaderGenerator::ProcessGroupMath(Box* box, Node* node, Value& value) case 29: { Value inXY = tryGetValue(node->GetBox(0), Value::Zero).AsFloat2(); - value = writeLocal(ValueType::Float3, String::Format(TEXT("float3({0}, sqrt(saturate(1.0 - dot({0}.xy, {0}.xy))))"), inXY.Value), node); + value = writeLocal(ValueType::Float3, String::Format(TEXT("float3({0}, sqrt(saturate(1.0 - dot({0}, {0}))))"), inXY.Value), node); break; } // Mad diff --git a/Source/Shaders/TerrainCommon.hlsl b/Source/Shaders/TerrainCommon.hlsl index a4db9bd4f..0c2f57168 100644 --- a/Source/Shaders/TerrainCommon.hlsl +++ b/Source/Shaders/TerrainCommon.hlsl @@ -5,28 +5,30 @@ #include "./Flax/Common.hlsl" +float DecodeHeightmapHeight(float4 value) +{ + return (float)((int)(value.x * 255.0) + ((int)(value.y * 255) << 8)) / 65535.0; +} + +float3 DecodeHeightmapNormal(float4 value, out bool isHole) +{ + isHole = (value.b + value.a) >= 1.9f; + float2 normalTemp = float2(value.b, value.a) * 2.0f - 1.0f; + float3 normal = float3(normalTemp.x, sqrt(1.0 - saturate(dot(normalTemp, normalTemp))), normalTemp.y); + return normalize(normal); +} + float SampleHeightmap(Texture2D heightmap, float2 uv, float mipOffset = 0.0f) { - // Sample heightmap float4 value = heightmap.SampleLevel(SamplerPointClamp, uv, mipOffset); - - // Decode heightmap - float height = (float)((int)(value.x * 255.0) + ((int)(value.y * 255) << 8)) / 65535.0; - return height; + return DecodeHeightmapHeight(value); } float SampleHeightmap(Texture2D heightmap, float2 uv, out float3 normal, out bool isHole, float mipOffset = 0.0f) { - // Sample heightmap float4 value = heightmap.SampleLevel(SamplerPointClamp, uv, mipOffset); - - // Decode heightmap - float height = (float)((int)(value.x * 255.0) + ((int)(value.y * 255) << 8)) / 65535.0; - float2 normalTemp = float2(value.b, value.a) * 2.0f - 1.0f; - normal = float3(normalTemp.x, sqrt(1.0 - saturate(dot(normalTemp, normalTemp))), normalTemp.y); - isHole = (value.b + value.a) >= 1.9f; - normal = normalize(normal); - return height; + normal = DecodeHeightmapNormal(value, isHole); + return DecodeHeightmapHeight(value); } float3 SampleHeightmap(Texture2D heightmap, float3 localPosition, float4 localToUV, out float3 normal, out bool isHole, float mipOffset = 0.0f) @@ -36,12 +38,9 @@ float3 SampleHeightmap(Texture2D heightmap, float3 localPosition, float4 float4 value = heightmap.SampleLevel(SamplerPointClamp, uv, mipOffset); // Decode heightmap - isHole = (value.b + value.a) >= 1.9f; - float height = (float)((int)(value.x * 255.0) + ((int)(value.y * 255) << 8)) / 65535.0; + normal = DecodeHeightmapNormal(value, isHole); + float height = DecodeHeightmapHeight(value);; float3 position = float3(localPosition.x, height, localPosition.z); - float2 normalTemp = float2(value.b, value.a) * 2.0f - 1.0f; - normal = float3(normalTemp.x, sqrt(1.0 - saturate(dot(normalTemp, normalTemp))), normalTemp.y); - normal = normalize(normal); // UVs outside the heightmap are empty isHole = isHole || any(uv < 0.0f) || any(uv > 1.0f);