diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index 4377ebb65..2a29bf13d 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -33,28 +33,49 @@ float GetMipLevel(float2 coords, Texture2D tex) } #if defined(LANDSCAPE) +# define HEIGHT_POWER 4.0 +# define INV_HEIGHT_POWER 0.25 -float GetTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6]) +float GetTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], float blendFactor, out float pixelOffset[6]) { - float height = 0.0; - if (input.LandBlendWeights1.x > 0.0) - height = TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w * input.LandBlendWeights1.x; - if (input.LandBlendWeights1.y > 0.0) - height += TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w * input.LandBlendWeights1.y; - if (input.LandBlendWeights1.z > 0.0) - height += TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w * input.LandBlendWeights1.z; - if (input.LandBlendWeights1.w > 0.0) - height += TexLandColor4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).w * input.LandBlendWeights1.w; - if (input.LandBlendWeights2.x > 0.0) - height += TexLandColor5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).w * input.LandBlendWeights2.x; - if (input.LandBlendWeights2.y > 0.0) - height += TexLandColor6Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).w * input.LandBlendWeights2.y; - return height; + float4 w1 = pow(input.LandBlendWeights1, 1 + 1 * blendFactor); + float2 w2 = pow(input.LandBlendWeights2.xy, 1 + 1 * blendFactor); + float blendPower = blendFactor * HEIGHT_POWER; + // important to zero initialize, otherwise invalid/old values will be used here and as weights in Lighting.hlsl + pixelOffset[0] = 0; // can't init whole 'out' array by = {...} + pixelOffset[1] = 0; + pixelOffset[2] = 0; + pixelOffset[3] = 0; + pixelOffset[4] = 0; + pixelOffset[5] = 0; + if (w1.x > 0.0) + pixelOffset[0] = w1.x * pow(TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, blendPower); + if (w1.y > 0.0) + pixelOffset[1] = w1.y * pow(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, blendPower); + if (w1.z > 0.0) + pixelOffset[2] = w1.z * pow(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, blendPower); + if (w1.w > 0.0) + pixelOffset[3] = w1.w * pow(TexLandColor4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).w, blendPower); + if (w2.x > 0.0) + pixelOffset[4] = w2.x * pow(TexLandColor5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).w, blendPower); + if (w2.y > 0.0) + pixelOffset[5] = w2.y * pow(TexLandColor6Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).w, blendPower); + float total = 0; + [unroll] for (int i = 0; i < 6; i++) + { + total += pixelOffset[i]; + } + float invtotal = rcp(total); + [unroll] for (int i = 0; i < 6; i++) + { + pixelOffset[i] *= invtotal; + } + return pow(total, INV_HEIGHT_POWER * rcp(blendFactor)); } #endif #if defined(LANDSCAPE) -float2 GetParallaxCoords(PS_INPUT input, float distance, float2 coords, float mipLevels[6], float3 viewDir, float3x3 tbn, float noise, out float pixelOffset) +float2 GetParallaxCoords(PS_INPUT input, float distance, float2 coords, float mipLevels[6], float3 viewDir, float3x3 tbn, float noise, out float pixelOffset, out float heights[6]) #else float2 GetParallaxCoords(float distance, float2 coords, float mipLevel, float3 viewDir, float3x3 tbn, float noise, Texture2D tex, SamplerState texSampler, uint channel, out float pixelOffset) #endif @@ -63,6 +84,10 @@ float2 GetParallaxCoords(float distance, float2 coords, float mipLevel, float3 v viewDirTS.xy /= viewDirTS.z * 0.7 + 0.3; // Fix for objects at extreme viewing angles float nearBlendToFar = saturate(distance / 2048.0); +#if defined(LANDSCAPE) + // When CPM flag is disabled, will use linear blending as before. + float blendFactor = extendedMaterialSettings.EnableComplexMaterial ? saturate(1 - nearBlendToFar) : INV_HEIGHT_POWER; +#endif float maxHeight = 0.1; float minHeight = maxHeight * 0.5; @@ -91,10 +116,10 @@ float2 GetParallaxCoords(float distance, float2 coords, float mipLevel, float3 v #if defined(LANDSCAPE) float4 currHeight; - currHeight.x = GetTerrainHeight(input, currentOffset[0].xy, mipLevels); - currHeight.y = GetTerrainHeight(input, currentOffset[0].zw, mipLevels); - currHeight.z = GetTerrainHeight(input, currentOffset[1].xy, mipLevels); - currHeight.w = GetTerrainHeight(input, currentOffset[1].zw, mipLevels); + currHeight.x = GetTerrainHeight(input, currentOffset[0].xy, mipLevels, blendFactor, heights); + currHeight.y = GetTerrainHeight(input, currentOffset[0].zw, mipLevels, blendFactor, heights); + currHeight.z = GetTerrainHeight(input, currentOffset[1].xy, mipLevels, blendFactor, heights); + currHeight.w = GetTerrainHeight(input, currentOffset[1].zw, mipLevels, blendFactor, heights); #else float4 currHeight; currHeight.x = tex.SampleLevel(texSampler, currentOffset[0].xy, mipLevel)[channel]; @@ -156,6 +181,15 @@ float2 GetParallaxCoords(float distance, float2 coords, float mipLevel, float3 v return lerp(viewDirTS.xy * offset + coords.xy, coords, nearBlendToFar); } +#if defined(LANDSCAPE) + heights[0] = input.LandBlendWeights1.x; + heights[1] = input.LandBlendWeights1.y; + heights[2] = input.LandBlendWeights1.z; + heights[3] = input.LandBlendWeights1.w; + heights[4] = input.LandBlendWeights2.x; + heights[5] = input.LandBlendWeights2.y; +#endif + pixelOffset = 0.5; return coords; } @@ -186,10 +220,11 @@ float GetParallaxSoftShadowMultiplierTerrain(PS_INPUT input, float2 coords, floa float2 rayDir = L.xy * 0.1; float4 multipliers = rcp((float4(4, 3, 2, 1) + noise)); float4 sh; - sh.x = GetTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel); - sh.y = GetTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel); - sh.z = GetTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel); - sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel); + float heights[6] = { 0, 0, 0, 0, 0, 0 }; + sh.x = GetTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, quality, heights); + sh.y = GetTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel, quality, heights); + sh.z = GetTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, quality, heights); + sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, quality, heights); return 1.0 - saturate(dot(max(0, sh - sh0), 1.0) * 2.0) * quality; } return 1.0; diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 336537e48..6cde5a193 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1087,9 +1087,19 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace mipLevels[3] = GetMipLevel(uv, TexLandColor4Sampler); mipLevels[4] = GetMipLevel(uv, TexLandColor5Sampler); mipLevels[5] = GetMipLevel(uv, TexLandColor6Sampler); - uv = GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, pixelOffset); - if (extendedMaterialSettings.EnableShadows && parallaxShadowQuality > 0.0f) - sh0 = GetTerrainHeight(input, uv, mipLevels); + float weights[6]; + uv = GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, pixelOffset, weights); + if (extendedMaterialSettings.EnableComplexMaterial) { + input.LandBlendWeights1.x = weights[0]; + input.LandBlendWeights1.y = weights[1]; + input.LandBlendWeights1.z = weights[2]; + input.LandBlendWeights1.w = weights[3]; + input.LandBlendWeights2.x = weights[4]; + input.LandBlendWeights2.y = weights[5]; + } + if (extendedMaterialSettings.EnableShadows && parallaxShadowQuality > 0.0f) { + sh0 = GetTerrainHeight(input, uv, mipLevels, parallaxShadowQuality, weights); + } } # endif // EMAT # endif // LANDSCAPE