From d2c5632c42efbfbce93bd66172744e0383285761 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Sat, 24 May 2025 22:50:41 +1000 Subject: [PATCH 01/53] Terrain Variation Lite --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 232 ++---------------- .../TerrainVariation/TerrainVariation.hlsli | 52 ++-- package/Shaders/Common/SharedData.hlsli | 12 +- package/Shaders/Lighting.hlsl | 63 ++--- src/Features/TerrainVariation.cpp | 84 +------ src/Features/TerrainVariation.h | 16 +- src/ShaderCache.cpp | 2 +- 7 files changed, 73 insertions(+), 388 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index 2a98c8e789..2eba434745 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -5,10 +5,6 @@ // http://www.diva-portal.org/smash/get/diva2:831762/FULLTEXT01.pdf // https://bartwronski.files.wordpress.com/2014/03/ac4_gdc.pdf -#if defined(LANDSCAPE) && defined(TERRAIN_VARIATION) -# include "TerrainVariation/TerrainVariation.hlsli" -#endif - struct DisplacementParams { float DisplacementScale; @@ -78,11 +74,7 @@ namespace ExtendedMaterials # if defined(TRUE_PBR) # define HEIGHT_POWER 2 # define HEIGHT_MULT 8 - float GetTerrainHeight(float screenNoise, PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, -# if defined(TERRAIN_VARIATION) - StochasticOffsets sharedOffset, float2 dx, float2 dy, float distance, -# endif - out float weights[6]) + float GetTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, out float weights[6]) { float heightBlend = 1 + blendFactor * HEIGHT_POWER; weights[0] = w1.x; @@ -92,76 +84,39 @@ namespace ExtendedMaterials weights[4] = w2.x; weights[5] = w2.y; float total = 0; - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.0) { -# if defined(TERRAIN_VARIATION) - float h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[0], TexLandDisplacement0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy, distance).x, params[0]); - if (SharedData::terrainVariationSettings.enableTilingFix) - h *= SharedData::terrainVariationSettings.heightCompensationFactor; // Semi-redundant with newer math, left for user preference/control. -# else float h = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); -# endif total += h * weights[0]; weights[0] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1HasDisplacement) != 0 && w1.y > 0.0) { -# if defined(TERRAIN_VARIATION) - float h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[1], TexLandDisplacement1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy, distance).x, params[1]); - if (SharedData::terrainVariationSettings.enableTilingFix) - h *= SharedData::terrainVariationSettings.heightCompensationFactor; -# else float h = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); -# endif total += h * weights[1]; weights[1] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2HasDisplacement) != 0 && w1.z > 0.0) { -# if defined(TERRAIN_VARIATION) - float h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[2], TexLandDisplacement2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy, distance).x, params[2]); - if (SharedData::terrainVariationSettings.enableTilingFix) - h *= SharedData::terrainVariationSettings.heightCompensationFactor; -# else float h = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); -# endif total += h * weights[2]; weights[2] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) { -# if defined(TERRAIN_VARIATION) - float h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy, distance).x, params[3]); - if (SharedData::terrainVariationSettings.enableTilingFix) - h *= SharedData::terrainVariationSettings.heightCompensationFactor; -# else float h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); -# endif total += h * weights[3]; weights[3] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) { -# if defined(TERRAIN_VARIATION) - float h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy, distance).x, params[4]); - if (SharedData::terrainVariationSettings.enableTilingFix) - h *= SharedData::terrainVariationSettings.heightCompensationFactor; -# else float h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); -# endif total += h * weights[4]; weights[4] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) { -# if defined(TERRAIN_VARIATION) - float h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy, distance).x, params[5]); - if (SharedData::terrainVariationSettings.enableTilingFix) - h *= SharedData::terrainVariationSettings.heightCompensationFactor; -# else float h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); -# endif total += h * weights[5]; weights[5] *= pow(heightBlend, HEIGHT_MULT * h); } @@ -184,11 +139,7 @@ namespace ExtendedMaterials # else # define HEIGHT_POWER 2 # define HEIGHT_MULT 8 - float GetTerrainHeight(float screenNoise, PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, -# if defined(TERRAIN_VARIATION) - StochasticOffsets sharedOffset, float2 dx, float2 dy, float distance, -# endif - out float weights[6]) + float GetTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, out float weights[6]) { float heightBlend = 1 + blendFactor * HEIGHT_POWER; weights[0] = w1.x; @@ -198,35 +149,15 @@ namespace ExtendedMaterials weights[4] = w2.x; weights[5] = w2.y; float total = 0; - if (w1.x > 0.0) { float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand0HasDisplacement) != 0) { - -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[0], TexLandTHDisp0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy, distance).x, params[0]); - if (SharedData::terrainVariationSettings.enableTilingFix) { - float blendProgress = saturate(distance / SharedData::terrainVariationSettings.maxDistance); - float dynamicHeightFactor = lerp( - SharedData::terrainVariationSettings.heightCompensationFactor, - SharedData::terrainVariationSettings.heightCompensationFactor * 1.5, - blendProgress); - h *= dynamicHeightFactor; - } -# else h = ScaleDisplacement(TexLandTHDisp0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); -# endif } else { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy, distance).w, params[0]); - if (SharedData::terrainVariationSettings.enableTilingFix) - h *= SharedData::terrainVariationSettings.heightCompensationFactor; -# else h = ScaleDisplacement(TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, params[0]); -# endif } total += h * weights[0]; weights[0] *= pow(heightBlend, HEIGHT_MULT * h); @@ -235,24 +166,11 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) { - -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[1], TexLandTHDisp1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy, distance).x, params[1]); - if (SharedData::terrainVariationSettings.enableTilingFix) - h *= SharedData::terrainVariationSettings.heightCompensationFactor; -# else h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); -# endif } else { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy, distance).w, params[1]); - if (SharedData::terrainVariationSettings.enableTilingFix) - h *= SharedData::terrainVariationSettings.heightCompensationFactor; -# else h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); -# endif } total += h * weights[1]; weights[1] *= pow(heightBlend, HEIGHT_MULT * h); @@ -261,24 +179,11 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) { - -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[2], TexLandTHDisp2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy, distance).x, params[2]); - if (SharedData::terrainVariationSettings.enableTilingFix) - h *= SharedData::terrainVariationSettings.heightCompensationFactor; -# else h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); -# endif } else { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy, distance).w, params[2]); - if (SharedData::terrainVariationSettings.enableTilingFix) - h *= SharedData::terrainVariationSettings.heightCompensationFactor; -# else h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); -# endif } total += h * weights[2]; weights[2] *= pow(heightBlend, HEIGHT_MULT * h); @@ -287,24 +192,11 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0) { - -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[3], TexLandTHDisp3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy, distance).x, params[3]); - if (SharedData::terrainVariationSettings.enableTilingFix) - h *= SharedData::terrainVariationSettings.heightCompensationFactor; -# else h = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); -# endif } else { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[3], TexLandColor4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy, distance).w, params[3]); - if (SharedData::terrainVariationSettings.enableTilingFix) - h *= SharedData::terrainVariationSettings.heightCompensationFactor; -# else h = ScaleDisplacement(TexLandColor4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).w, params[3]); -# endif } total += h * weights[3]; weights[3] *= pow(heightBlend, HEIGHT_MULT * h); @@ -313,24 +205,11 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0) { - -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[4], TexLandTHDisp4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy, distance).x, params[4]); - if (SharedData::terrainVariationSettings.enableTilingFix) - h *= SharedData::terrainVariationSettings.heightCompensationFactor; -# else h = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); -# endif } else { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[4], TexLandColor5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy, distance).w, params[4]); - if (SharedData::terrainVariationSettings.enableTilingFix) - h *= SharedData::terrainVariationSettings.heightCompensationFactor; -# else h = ScaleDisplacement(TexLandColor5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).w, params[4]); -# endif } total += h * weights[4]; weights[4] *= pow(heightBlend, HEIGHT_MULT * h); @@ -339,24 +218,11 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0) { - -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[5], TexLandTHDisp5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy, distance).x, params[5]); - if (SharedData::terrainVariationSettings.enableTilingFix) - h *= SharedData::terrainVariationSettings.heightCompensationFactor; -# else h = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); -# endif } else { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[5], TexLandColor6Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy, distance).w, params[5]); - if (SharedData::terrainVariationSettings.enableTilingFix) - h *= SharedData::terrainVariationSettings.heightCompensationFactor; -# else h = ScaleDisplacement(TexLandColor6Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).w, params[5]); -# endif } total += h * weights[5]; weights[5] *= pow(heightBlend, HEIGHT_MULT * h); @@ -382,11 +248,7 @@ namespace ExtendedMaterials #endif #if defined(LANDSCAPE) - float2 GetParallaxCoords(PS_INPUT input, float distance, float2 coords, float mipLevels[6], float3 viewDir, float3x3 tbn, float noise, DisplacementParams params[6], -# if defined(TERRAIN_VARIATION) - StochasticOffsets sharedOffset, float2 dx, float2 dy, -# endif - out float pixelOffset, out float weights[6]) + float2 GetParallaxCoords(PS_INPUT input, float distance, float2 coords, float mipLevels[6], float3 viewDir, float3x3 tbn, float noise, DisplacementParams params[6], out float pixelOffset, out float weights[6]) #else float2 GetParallaxCoords(float distance, float2 coords, float mipLevel, float3 viewDir, float3x3 tbn, float noise, Texture2D tex, SamplerState texSampler, uint channel, DisplacementParams params, out float pixelOffset) #endif @@ -460,29 +322,15 @@ namespace ExtendedMaterials float4 currHeight; #if defined(LANDSCAPE) # if defined(TRUE_PBR) -# if defined(TERRAIN_VARIATION) - currHeight.x = GetTerrainHeight(noise, input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, distance, weights) * scalercp + 0.5; - currHeight.y = GetTerrainHeight(noise, input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, distance, weights) * scalercp + 0.5; - currHeight.z = GetTerrainHeight(noise, input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, distance, weights) * scalercp + 0.5; - currHeight.w = GetTerrainHeight(noise, input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, distance, weights) * scalercp + 0.5; -# else - currHeight.x = GetTerrainHeight(noise, input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; - currHeight.y = GetTerrainHeight(noise, input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; - currHeight.z = GetTerrainHeight(noise, input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; - currHeight.w = GetTerrainHeight(noise, input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; -# endif + currHeight.x = GetTerrainHeight(input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; + currHeight.y = GetTerrainHeight(input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; + currHeight.z = GetTerrainHeight(input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; + currHeight.w = GetTerrainHeight(input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; # else -# if defined(TERRAIN_VARIATION) - currHeight.x = GetTerrainHeight(noise, input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, distance, weights) + 0.5; - currHeight.y = GetTerrainHeight(noise, input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, distance, weights) + 0.5; - currHeight.z = GetTerrainHeight(noise, input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, distance, weights) + 0.5; - currHeight.w = GetTerrainHeight(noise, input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, distance, weights) + 0.5; -# else - currHeight.x = GetTerrainHeight(noise, input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; - currHeight.y = GetTerrainHeight(noise, input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; - currHeight.z = GetTerrainHeight(noise, input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; - currHeight.w = GetTerrainHeight(noise, input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; -# endif + currHeight.x = GetTerrainHeight(input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; + currHeight.y = GetTerrainHeight(input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; + currHeight.z = GetTerrainHeight(input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; + currHeight.w = GetTerrainHeight(input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; # endif #else currHeight.x = tex.SampleLevel(texSampler, currentOffset[0].xy, mipLevel)[channel]; @@ -600,79 +448,39 @@ namespace ExtendedMaterials } #if defined(LANDSCAPE) -# if defined(TERRAIN_VARIATION) - float GetParallaxSoftShadowMultiplierTerrain(PS_INPUT input, float2 coords, float mipLevel[6], float3 L, float sh0, float quality, float noise, DisplacementParams params[6], StochasticOffsets sharedOffset, float2 dx, float2 dy, float distance) -# else float GetParallaxSoftShadowMultiplierTerrain(PS_INPUT input, float2 coords, float mipLevel[6], float3 L, float sh0, float quality, float noise, DisplacementParams params[6]) -# endif { if (quality > 0.0) { float4 multipliers = rcp((float4(1, 2, 3, 4) + noise)); float4 sh; float heights[6] = { 0, 0, 0, 0, 0, 0 }; float2 rayDir = L.xy * 0.1; - -# if defined(TERRAIN_VARIATION) - // Only apply the shadowRayDirFactor when tiling fix is enabled - if (SharedData::terrainVariationSettings.enableTilingFix) { - // Calculate a dynamic shadow ray factor that increases with distance (also not necessary with new math, kept for user preference. stoch. offsets can cause lower prlx shadows) - float blendProgress = saturate(distance / SharedData::terrainVariationSettings.maxDistance); - float dynamicShadowFactor = lerp( - SharedData::terrainVariationSettings.shadowRayDirFactor, - SharedData::terrainVariationSettings.shadowRayDirFactor * 1.75, - blendProgress); - rayDir *= dynamicShadowFactor; - } -# endif - # if defined(TRUE_PBR) float scale = max(params[0].HeightScale * input.LandBlendWeights1.x, max(params[1].HeightScale * input.LandBlendWeights1.y, max(params[2].HeightScale * input.LandBlendWeights1.z, max(params[3].HeightScale * input.LandBlendWeights1.w, max(params[4].HeightScale * input.LandBlendWeights2.x, params[5].HeightScale * input.LandBlendWeights2.y))))); if (scale < 0.01) return 1.0; rayDir *= scale; - -# if defined(TERRAIN_VARIATION) - sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, distance, heights); + sh = GetTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.25) - sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, distance, heights); + sh.y = GetTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.5) - sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, distance, heights); + sh.z = GetTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.75) - sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, distance, heights); -# else - sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); - if (quality > 0.25) - sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); - if (quality > 0.5) - sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); - if (quality > 0.75) - sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); -# endif + sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); return pow(1.0 - saturate(dot(max(0, sh - sh0) / scale, 1.0)) * quality, 2.0); # else -# if defined(TERRAIN_VARIATION) - sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, distance, heights); - if (quality > 0.25) - sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, distance, heights); - if (quality > 0.5) - sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, distance, heights); - if (quality > 0.75) - sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, distance, heights); -# else - sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh = GetTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.25) - sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.y = GetTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.5) - sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.z = GetTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.75) - sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); -# endif + sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); return pow(1.0 - saturate(dot(max(0, sh - sh0), 1.0)) * quality, 2.0); # endif } return 1.0; } #endif - -} +} \ No newline at end of file diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index e57a8bc148..c9d3bfac77 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -17,29 +17,22 @@ struct StochasticOffsets float3 weights; }; -// Compute a distance factor for scaling stochastic effect strength (0-1) -// Returns 0 for distances <= startDistance, 1 for distances >= maxDistance -inline float ComputeDistanceFactor(float distance) +// Compute terrain variation blend factor +// Returns blend factor between 0.0 (no stochastic) and 1.0 (full stochastic) +inline float ComputeTerrainVariationBlend(float viewDistance) { if (!SharedData::terrainVariationSettings.enableTilingFix) return 0.0; - return saturate((distance - SharedData::terrainVariationSettings.startDistance) * - SharedData::terrainVariationSettings.invDistanceRange); + float blendFactor = saturate((viewDistance - 1200.0) / 1000.0); + return smoothstep(0.0, 1.0, blendFactor); } // Hash function for stochastic sampling inline float2 hash2D2D(float2 s) { - // Choose hash implementation based on quality setting - if (SharedData::terrainVariationSettings.hashQuality == 0) { - // Low quality, no fmod, slight tiling, almost negligible difference, 0.05ms or so. s = s * float2(1271.5151, 3337.8237); return frac(sin(s.x + s.y) * float2(43758.5453, 28637.1369)); - } else { - // High quality, better blend with fmod funct. - return frac(sin(fmod(float2(dot(s, float2(127.1, 311.7)), dot(s, float2(269.5, 183.3))), 3.14159)) * 43758.5453); - } } // Compute offsets for stochastic sampling @@ -67,35 +60,28 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler { // If feature is disabled, return standard sample if (!SharedData::terrainVariationSettings.enableTilingFix) - return tex.SampleLevel(samp, uv, mipLevel); - - // Calculate distance factor (0 when close, 1 when far) - float distanceFactor = ComputeDistanceFactor(distance); + return tex.SampleLevel(samp, uv, mipLevel); // Compute terrain variation blend factor (0.0 = no stochastic, 1.0 = full stochastic) + float terrainVariationBlend = ComputeTerrainVariationBlend(distance); + float4 standardSample = tex.SampleLevel(samp, uv, mipLevel); - bool useParallax = SharedData::extendedMaterialSettings.EnableTerrainParallax; - float4 sample1, sample2, sample3, standardSample; - - // Get stochastic samples - if (useParallax) { - // Parallax enabled, can use SampleLevel for better perf - sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); - sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); - sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); - standardSample = tex.SampleLevel(samp, uv, mipLevel); - } else { - // When parallax disabled, samplelevel causes mipmap issues, it uses too low a mipmap level up close. - sample1 = tex.SampleGrad(samp, uv + offsets.offset1, dx, dy); - sample2 = tex.SampleGrad(samp, uv + offsets.offset2, dx, dy); - sample3 = tex.SampleGrad(samp, uv + offsets.offset3, dx, dy); - standardSample = tex.SampleGrad(samp, uv, dx, dy); + // If no terrain variation blend, return standard sample + if (terrainVariationBlend <= 0.0) { + return standardSample; } + // Get stochastic samples only when needed (at distance where parallax fades out) + // Use SampleLevel since we're at distance where mipmap issues don't matter + float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); + float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); + // Weight samples according to offsets float4 stochasticSample = sample1 * offsets.weights.x + sample2 * offsets.weights.y + sample3 * offsets.weights.z; - return lerp(standardSample, stochasticSample, distanceFactor); + // Smooth blend: lerp from standard to stochastic based on distance + return lerp(standardSample, stochasticSample, terrainVariationBlend); } #define StochasticSample(rnd, mipLevel, tex, samp, uv, dist) StochasticEffect(rnd, mipLevel, tex, samp, uv, ComputeStochasticOffsets(uv), ddx(uv), ddy(uv), dist).rgb diff --git a/package/Shaders/Common/SharedData.hlsli b/package/Shaders/Common/SharedData.hlsli index 61bca68556..f5639513a9 100644 --- a/package/Shaders/Common/SharedData.hlsli +++ b/package/Shaders/Common/SharedData.hlsli @@ -159,18 +159,12 @@ namespace SharedData float DiffuseIndirectMult; float BaseColorMult; float pad; - }; - + }; + struct TerrainVariationSettings { bool enableTilingFix; - float startDistance; - float maxDistance; - float invDistanceRange; // For distance calc optimisation - float heightCompensationFactor; // Compensation multiplier for terrain parallax - float shadowRayDirFactor; // Shadow ray direction multiplier - int hashQuality; // 0 = Low quality hash, 1 = High quality hash - float pad; + float3 pad0; }; struct IBLSettings diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 4910966193..5e2908cef2 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1274,7 +1274,6 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(TRUE_PBR) float4 blendedRMAOS = 0; # endif - float invwsum = totalWeight > 0.0 ? rcp(totalWeight) : 1.0; float viewDistance = length(viewPosition); float distanceFactor = 0.0; @@ -1283,6 +1282,8 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float2 dx = ddx(uv); float2 dy = ddy(uv); StochasticOffsets sharedOffset = ComputeStochasticOffsets(uv); + // Create terrain variation distance for smooth blend (2000-2048 units) + float terrainVariationDistance = viewDistance; # else distanceFactor = saturate(viewDistance * 0.00048828125); # endif @@ -1311,11 +1312,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif float weights[6]; -# if defined(TERRAIN_VARIATION) - uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, sharedOffset, dx, dy, pixelOffset, weights); -# else uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, pixelOffset, weights); -# endif if (SharedData::extendedMaterialSettings.EnableHeightBlending) { input.LandBlendWeights1.x = weights[0]; input.LandBlendWeights1.y = weights[1]; @@ -1323,14 +1320,9 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace input.LandBlendWeights1.w = weights[3]; input.LandBlendWeights2.x = weights[4]; input.LandBlendWeights2.y = weights[5]; - } + } if (SharedData::extendedMaterialSettings.EnableShadows && (parallaxShadowQuality > 0.0f || SharedData::extendedMaterialSettings.ExtendShadows)) { -# if defined(TERRAIN_VARIATION) - sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, viewDistance, weights); - float shadowMultiplier = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, DirLightDirection, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dx, dy, viewDistance); -# else - sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); -# endif + sh0 = ExtendedMaterials::GetTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); } } # endif // EMAT @@ -1364,7 +1356,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace if (input.LandBlendWeights1.x > 0.01) { float weight = input.LandBlendWeights1.x * invwsum; # if defined(TERRAIN_VARIATION) - float4 diffuse1 = StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampColorSampler, uv, sharedOffset, dx, dy, viewDistance); + float4 diffuse1 = StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampColorSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); # else float distanceFactor = smoothstep(0.0, 2048.0, viewDistance); float4 diffuse1 = lerp( @@ -1382,7 +1374,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float alpha1 = diffuse1.a; # if defined(TERRAIN_VARIATION) - float4 normal1 = StochasticEffect(screenNoise, mipLevels[0], TexNormalSampler, SampNormalSampler, uv, sharedOffset, dx, dy, viewDistance); + float4 normal1 = StochasticEffect(screenNoise, mipLevels[0], TexNormalSampler, SampNormalSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); # else float4 normal1 = lerp( TexNormalSampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), @@ -1393,7 +1385,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float normalAlpha1 = normal1.a; # if defined(TRUE_PBR) # if defined(TERRAIN_VARIATION) - float4 rmaos1 = StochasticEffect(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, viewDistance); + float4 rmaos1 = StochasticEffect(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); # else float4 rmaos1 = lerp( TexRMAOSSampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), @@ -1413,7 +1405,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace if (input.LandBlendWeights1.y > 0.01) { float weight = input.LandBlendWeights1.y * invwsum; # if defined(TERRAIN_VARIATION) - float4 diffuse2 = StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampColorSampler, uv, sharedOffset, dx, dy, viewDistance); + float4 diffuse2 = StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampColorSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); # else float distanceFactor = smoothstep(0.0, 2048.0, viewDistance); float4 diffuse2 = lerp( @@ -1431,7 +1423,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float alpha2 = diffuse2.a; # if defined(TERRAIN_VARIATION) - float4 normal2 = StochasticEffect(screenNoise, mipLevels[1], TexLandNormal2Sampler, SampNormalSampler, uv, sharedOffset, dx, dy, viewDistance); + float4 normal2 = StochasticEffect(screenNoise, mipLevels[1], TexLandNormal2Sampler, SampNormalSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); # else float4 normal2 = lerp( TexLandNormal2Sampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), @@ -1442,7 +1434,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float normalAlpha2 = normal2.a; # if defined(TRUE_PBR) # if defined(TERRAIN_VARIATION) - float4 rmaos2 = StochasticEffect(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, viewDistance); + float4 rmaos2 = StochasticEffect(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); # else float4 rmaos2 = lerp( TexLandRMAOS2Sampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), @@ -1462,7 +1454,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace if (input.LandBlendWeights1.z > 0.01) { float weight = input.LandBlendWeights1.z * invwsum; # if defined(TERRAIN_VARIATION) - float4 diffuse3 = StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampColorSampler, uv, sharedOffset, dx, dy, viewDistance); + float4 diffuse3 = StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampColorSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); # else float distanceFactor = smoothstep(0.0, 2048.0, viewDistance); float4 diffuse3 = lerp( @@ -1480,7 +1472,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float alpha3 = diffuse3.a; # if defined(TERRAIN_VARIATION) - float4 normal3 = StochasticEffect(screenNoise, mipLevels[2], TexLandNormal3Sampler, SampNormalSampler, uv, sharedOffset, dx, dy, viewDistance); + float4 normal3 = StochasticEffect(screenNoise, mipLevels[2], TexLandNormal3Sampler, SampNormalSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); # else float4 normal3 = lerp( TexLandNormal3Sampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), @@ -1491,7 +1483,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float normalAlpha3 = normal3.a; # if defined(TRUE_PBR) # if defined(TERRAIN_VARIATION) - float4 rmaos3 = StochasticEffect(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, viewDistance); + float4 rmaos3 = StochasticEffect(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); # else float4 rmaos3 = lerp( TexLandRMAOS3Sampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), @@ -1511,7 +1503,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace if (input.LandBlendWeights1.w > 0.01) { float weight = input.LandBlendWeights1.w * invwsum; # if defined(TERRAIN_VARIATION) - float4 diffuse4 = StochasticEffect(screenNoise, mipLevels[3], TexLandColor4Sampler, SampColorSampler, uv, sharedOffset, dx, dy, viewDistance); + float4 diffuse4 = StochasticEffect(screenNoise, mipLevels[3], TexLandColor4Sampler, SampColorSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); # else float distanceFactor = smoothstep(0.0, 2048.0, viewDistance); float4 diffuse4 = lerp( @@ -1529,7 +1521,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float alpha4 = diffuse4.a; # if defined(TERRAIN_VARIATION) - float4 normal4 = StochasticEffect(screenNoise, mipLevels[3], TexLandNormal4Sampler, SampNormalSampler, uv, sharedOffset, dx, dy, viewDistance); + float4 normal4 = StochasticEffect(screenNoise, mipLevels[3], TexLandNormal4Sampler, SampNormalSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); # else float4 normal4 = lerp( TexLandNormal4Sampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), @@ -1540,7 +1532,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float normalAlpha4 = normal4.a; # if defined(TRUE_PBR) # if defined(TERRAIN_VARIATION) - float4 rmaos4 = StochasticEffect(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, viewDistance); + float4 rmaos4 = StochasticEffect(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); # else float4 rmaos4 = lerp( TexLandRMAOS4Sampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), @@ -1560,7 +1552,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace if (input.LandBlendWeights2.x > 0.01) { float weight = input.LandBlendWeights2.x * invwsum; # if defined(TERRAIN_VARIATION) - float4 diffuse5 = StochasticEffect(screenNoise, mipLevels[4], TexLandColor5Sampler, SampColorSampler, uv, sharedOffset, dx, dy, viewDistance); + float4 diffuse5 = StochasticEffect(screenNoise, mipLevels[4], TexLandColor5Sampler, SampColorSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); # else float distanceFactor = smoothstep(0.0, 2048.0, viewDistance); float4 diffuse5 = lerp( @@ -1578,7 +1570,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float alpha5 = diffuse5.a; # if defined(TERRAIN_VARIATION) - float4 normal5 = StochasticEffect(screenNoise, mipLevels[4], TexLandNormal5Sampler, SampNormalSampler, uv, sharedOffset, dx, dy, viewDistance); + float4 normal5 = StochasticEffect(screenNoise, mipLevels[4], TexLandNormal5Sampler, SampNormalSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); # else float4 normal5 = lerp( TexLandNormal5Sampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), @@ -1589,7 +1581,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float normalAlpha5 = normal5.a; # if defined(TRUE_PBR) # if defined(TERRAIN_VARIATION) - float4 rmaos5 = StochasticEffect(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, viewDistance); + float4 rmaos5 = StochasticEffect(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); # else float4 rmaos5 = lerp( TexLandRMAOS5Sampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), @@ -1609,7 +1601,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace if (input.LandBlendWeights2.y > 0.01) { float weight = input.LandBlendWeights2.y * invwsum; # if defined(TERRAIN_VARIATION) - float4 diffuse6 = StochasticEffect(screenNoise, mipLevels[5], TexLandColor6Sampler, SampColorSampler, uv, sharedOffset, dx, dy, viewDistance); + float4 diffuse6 = StochasticEffect(screenNoise, mipLevels[5], TexLandColor6Sampler, SampColorSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); # else float distanceFactor = smoothstep(0.0, 2048.0, viewDistance); float4 diffuse6 = lerp( @@ -1627,7 +1619,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float alpha6 = diffuse6.a; # if defined(TERRAIN_VARIATION) - float4 normal6 = StochasticEffect(screenNoise, mipLevels[5], TexLandNormal6Sampler, SampNormalSampler, uv, sharedOffset, dx, dy, viewDistance); + float4 normal6 = StochasticEffect(screenNoise, mipLevels[5], TexLandNormal6Sampler, SampNormalSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); # else float4 normal6 = lerp( TexLandNormal6Sampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), @@ -1638,7 +1630,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float normalAlpha6 = normal6.a; # if defined(TRUE_PBR) # if defined(TERRAIN_VARIATION) - float4 rmaos6 = StochasticEffect(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, viewDistance); + float4 rmaos6 = StochasticEffect(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); # else float4 rmaos6 = lerp( TexLandRMAOS6Sampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), @@ -2267,16 +2259,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(LANDSCAPE) [branch] if (SharedData::extendedMaterialSettings.EnableTerrainParallax) { -# if defined(TERRAIN_VARIATION) - float weights[6]; - - float sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, viewDistance, weights); - - parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dx, dy, viewDistance); -# else - // Standard terrain parallax shadow without stochastic sampling parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams); -# endif } # elif defined(PARALLAX) [branch] if (SharedData::extendedMaterialSettings.EnableParallax) @@ -3228,4 +3211,4 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace return psout; } -#endif // PSHADER +#endif // PSHADER \ No newline at end of file diff --git a/src/Features/TerrainVariation.cpp b/src/Features/TerrainVariation.cpp index b79fddfefa..95b08f6e80 100644 --- a/src/Features/TerrainVariation.cpp +++ b/src/Features/TerrainVariation.cpp @@ -6,12 +6,7 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT( TerrainVariation::Settings, - enableTilingFix, - startDistance, - maxDistance, - heightCompensationFactor, - shadowRayDirFactor, - hashQuality) + enableTilingFix) void TerrainVariation::DrawSettings() { @@ -22,74 +17,18 @@ void TerrainVariation::DrawSettings() UpdateShaderSettings(); logger::info("TerrainVariation setting changed to: {}", settings.enableTilingFix); } - if (auto _tt = Util::HoverTooltipWrapper()) { ImGui::Text( "Reduces the repeating pattern effect on terrain textures.\n" - "This technique creates more natural-looking terrain by adding variation to texture sampling."); + "This technique creates more natural-looking terrain by adding variation to texture sampling.\n" + "Stochastic texturing is applied only when parallax effects are not active (beyond 2048 units from camera)."); } - if (settings.enableTilingFix) { ImGui::Separator(); bool paramsChanged = false; - // Add UI controls for distance-based parameters - paramsChanged |= ImGui::SliderFloat("Start Distance", &settings.startDistance, 0.0f, settings.maxDistance - 1.0f, "%.1f", ImGuiSliderFlags_AlwaysClamp); - if (auto _tt = Util::HoverTooltipWrapper()) { - ImGui::Text("Distance from camera where variation begins to blend in.\nCloser than this will have no variation applied."); - } - - paramsChanged |= ImGui::SliderFloat("Maximum Distance", &settings.maxDistance, settings.startDistance + 1.0f, 5000.0f, "%.1f", ImGuiSliderFlags_AlwaysClamp); - if (auto _tt = Util::HoverTooltipWrapper()) { - ImGui::Text( - "Distance from camera where variation reaches maximum intensity.\n" - "Generally, a distance of atleast 1000 between values is recommended for a smooth transition."); - } - - ImGui::SeparatorText("Advanced Options"); - - ImGui::Checkbox("Show Advanced Options", &showAdvanced); - - if (showAdvanced) { - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.7f, 0.0f, 1.0f)); - ImGui::TextWrapped( - "Warning: Only modify these values if you know what you're doing!\n" - "You may break the intended look of textures."); - ImGui::PopStyleColor(); - - paramsChanged |= ImGui::SliderFloat("Height Compensation Factor", &settings.heightCompensationFactor, 0.5f, 2.0f, "%.2f"); - if (auto _tt = Util::HoverTooltipWrapper()) { - ImGui::Text( - "Increasing the number will increase the height of all terrain parallax.\n" - "Compensation multiplier for terrain parallax when Terrain Variation is enabled.\n" - "This setting only applies when both Terrain Variation and Extended Materials' terrain parallax are enabled."); - } - - paramsChanged |= ImGui::SliderFloat("Shadow Ray Direction Factor", &settings.shadowRayDirFactor, 0.5f, 3.0f, "%.2f"); - if (auto _tt = Util::HoverTooltipWrapper()) { - ImGui::Text( - "Multiplier for shadow ray direction when calculating terrain parallax shadows.\n" - "Higher values make shadows appear stronger but may cause artifacts.\n" - "This setting only applies when both Terrain Variation and Extended Materials' terrain parallax are enabled."); // davo yappage - } - - const char* hashQualityItems[] = { "Low Quality", "High Quality" }; - paramsChanged |= ImGui::Combo("Hash Quality", &settings.hashQuality, hashQualityItems, IM_ARRAYSIZE(hashQualityItems)); - if (auto _tt = Util::HoverTooltipWrapper()) { - ImGui::Text( - "Low quality reduces most terrain tiling with a cheaper formula.\n" - "High quality is a more complex formula that completely removes terrain tiling.\n" - "Choose low quality if you experience performance issues."); - } - } - if (paramsChanged) { - // Ensure minimum distance between values for numerical stability - if (settings.maxDistance - settings.startDistance < 1.0f) { - settings.maxDistance = settings.startDistance + 1.0f; - } - UpdateShaderSettings(); logger::info("TerrainVariation parameters updated"); } @@ -102,18 +41,6 @@ void TerrainVariation::UpdateShaderSettings() return; } - // Calculate invDistanceRange for shader optimization - float distanceRange = settings.maxDistance - settings.startDistance; - if (distanceRange <= 0.0f) { - // Prevent division by zero - use a sensible default - distanceRange = 1.0f; - } - float invDistanceRange = 1.0f / distanceRange; - - // Update the settings struct with calculated values - // These will be picked up automatically by the feature buffer - settings.invDistanceRange = invDistanceRange; - // Mark the vertex descriptor as dirty to trigger an update if (globals::game::stateUpdateFlags) { globals::game::stateUpdateFlags->set(RE::BSGraphics::DIRTY_VERTEX_DESC); @@ -149,11 +76,12 @@ void TerrainVariation::DrawUnloadedUI() ImGui::Spacing(); ImGui::TextWrapped( "Terrain Variation reduces the repeating pattern effect on terrain textures.\n" - "This technique creates more natural-looking terrain by adding variation to texture sampling."); + "This technique creates more natural-looking terrain by adding variation to texture sampling.\n" + "Stochastic texturing is applied only when parallax effects are not active (beyond 2048 units from camera)."); ImGui::Spacing(); ImGui::TextWrapped("Key features:"); ImGui::BulletText("Reduces terrain texture tiling"); - ImGui::BulletText("Adjustable distance-based blending"); + ImGui::BulletText("Automatically activates when parallax effects end"); ImGui::Spacing(); } \ No newline at end of file diff --git a/src/Features/TerrainVariation.h b/src/Features/TerrainVariation.h index a8c0f6e1bf..88f5d0461f 100644 --- a/src/Features/TerrainVariation.h +++ b/src/Features/TerrainVariation.h @@ -15,30 +15,16 @@ struct TerrainVariation : Feature virtual inline bool HasShaderDefine(RE::BSShader::Type shaderType) override { return shaderType == RE::BSShader::Type::Lighting; } virtual bool IsCore() const override { return false; }; virtual bool SupportsVR() override { return true; } - struct Settings { uint enableTilingFix = true; - float startDistance = 200.0f; // No offset will be applied under this distance - float maxDistance = 2000.0f; // Maximum distance that the terrain will blend the stochastic effect to - float invDistanceRange = 0.00056f; // Precalculated 1.0f / (maxDistance - startDistance) for shader optimization - float heightCompensationFactor = 1.0f; // Compensation for terrain parallax when enabled - float shadowRayDirFactor = 1.0f; // Shadow ray direction multiplier for parallax shadows - int hashQuality = 1; // 0 = Low quality hash, 1 = High quality hash - float pad; + float3 pad0; }; Settings settings; bool showAdvanced = false; - Settings defaultSettings = { true, // enableTilingFix - 200.0f, // startDistance - 2000.0f, // maxDistance - 0.00056f, // invDistanceRange (precalculated 1.0f / (2000.0f - 200.0f)) - 1.0f, // heightCompensationFactor - 1.0f, // shadowRayDirFactor - 1 // hashQuality - default to high quality }; virtual void DrawSettings() override; diff --git a/src/ShaderCache.cpp b/src/ShaderCache.cpp index f4756244e4..b086c21868 100644 --- a/src/ShaderCache.cpp +++ b/src/ShaderCache.cpp @@ -2467,7 +2467,7 @@ namespace SIE } } - void ShaderCache::ProcessCompilationSet(std::stop_token stoken, SIE::ShaderCompilationTask task) + void ShaderCache::ProcessCompilationSet([[maybe_unused]] std::stop_token stoken, SIE::ShaderCompilationTask task) { SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL); task.Perform(); From 317b240940c5e2b3903adc21213765cf6b911aba Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Sun, 25 May 2025 10:40:23 +1000 Subject: [PATCH 02/53] Always on Height Operator build 1 --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 191 ++++++++++++++++-- .../TerrainVariation/TerrainVariation.hlsli | 96 ++++++--- package/Shaders/Lighting.hlsl | 71 ++++--- 3 files changed, 282 insertions(+), 76 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index 2eba434745..151a419560 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -5,6 +5,10 @@ // http://www.diva-portal.org/smash/get/diva2:831762/FULLTEXT01.pdf // https://bartwronski.files.wordpress.com/2014/03/ac4_gdc.pdf +#if defined(LANDSCAPE) && defined(TERRAIN_VARIATION) +# include "TerrainVariation/TerrainVariation.hlsli" +#endif + struct DisplacementParams { float DisplacementScale; @@ -74,7 +78,11 @@ namespace ExtendedMaterials # if defined(TRUE_PBR) # define HEIGHT_POWER 2 # define HEIGHT_MULT 8 - float GetTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, out float weights[6]) + float GetTerrainHeight(float screenNoise, PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, +# if defined(TERRAIN_VARIATION) + StochasticOffsets sharedOffset, float2 dx, float2 dy, +# endif + out float weights[6]) { float heightBlend = 1 + blendFactor * HEIGHT_POWER; weights[0] = w1.x; @@ -86,37 +94,66 @@ namespace ExtendedMaterials float total = 0; [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.0) { +# if defined(TERRAIN_VARIATION) + float h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[0], TexLandDisplacement0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); +# else float h = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); +# endif total += h * weights[0]; weights[0] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1HasDisplacement) != 0 && w1.y > 0.0) { +# if defined(TERRAIN_VARIATION) + float h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[1], TexLandDisplacement1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); + +# else float h = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); +# endif total += h * weights[1]; weights[1] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2HasDisplacement) != 0 && w1.z > 0.0) { +# if defined(TERRAIN_VARIATION) + float h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[2], TexLandDisplacement2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); + +# else float h = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); +# endif total += h * weights[2]; weights[2] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) { +# if defined(TERRAIN_VARIATION) + float h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); + +# else float h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); +# endif total += h * weights[3]; weights[3] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) { +# if defined(TERRAIN_VARIATION) + float h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); + +# else float h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); +# endif total += h * weights[4]; weights[4] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) { +# if defined(TERRAIN_VARIATION) + float h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); + +# else float h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); +# endif total += h * weights[5]; weights[5] *= pow(heightBlend, HEIGHT_MULT * h); } @@ -139,7 +176,11 @@ namespace ExtendedMaterials # else # define HEIGHT_POWER 2 # define HEIGHT_MULT 8 - float GetTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, out float weights[6]) + float GetTerrainHeight(float screenNoise, PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, +# if defined(TERRAIN_VARIATION) + StochasticOffsets sharedOffset, float2 dx, float2 dy, +# endif + out float weights[6]) { float heightBlend = 1 + blendFactor * HEIGHT_POWER; weights[0] = w1.x; @@ -149,15 +190,25 @@ namespace ExtendedMaterials weights[4] = w2.x; weights[5] = w2.y; float total = 0; + if (w1.x > 0.0) { - float h = 0.0; + float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand0HasDisplacement) != 0) { +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[0], TexLandTHDisp0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); +# else h = ScaleDisplacement(TexLandTHDisp0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); +# endif } else { +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[0]); + +# else h = ScaleDisplacement(TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, params[0]); +# endif } total += h * weights[0]; weights[0] *= pow(heightBlend, HEIGHT_MULT * h); @@ -166,11 +217,22 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) { + +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[1], TexLandTHDisp1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); + +# else h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); +# endif } else { +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[1]); + +# else h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); +# endif } total += h * weights[1]; weights[1] *= pow(heightBlend, HEIGHT_MULT * h); @@ -179,11 +241,22 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) { + +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[2], TexLandTHDisp2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); + +# else h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); +# endif } else { +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[2]); + +# else h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); +# endif } total += h * weights[2]; weights[2] *= pow(heightBlend, HEIGHT_MULT * h); @@ -192,11 +265,22 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0) { + +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[3], TexLandTHDisp3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); + +# else h = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); +# endif } else { +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[3], TexLandColor4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[3]); + +# else h = ScaleDisplacement(TexLandColor4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).w, params[3]); +# endif } total += h * weights[3]; weights[3] *= pow(heightBlend, HEIGHT_MULT * h); @@ -205,11 +289,22 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0) { + +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[4], TexLandTHDisp4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); + +# else h = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); +# endif } else { +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[4], TexLandColor5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[4]); + +# else h = ScaleDisplacement(TexLandColor5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).w, params[4]); +# endif } total += h * weights[4]; weights[4] *= pow(heightBlend, HEIGHT_MULT * h); @@ -218,11 +313,22 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0) { + +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[5], TexLandTHDisp5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); + +# else h = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); +# endif } else { +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[5], TexLandColor6Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[5]); + +# else h = ScaleDisplacement(TexLandColor6Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).w, params[5]); +# endif } total += h * weights[5]; weights[5] *= pow(heightBlend, HEIGHT_MULT * h); @@ -248,7 +354,11 @@ namespace ExtendedMaterials #endif #if defined(LANDSCAPE) - float2 GetParallaxCoords(PS_INPUT input, float distance, float2 coords, float mipLevels[6], float3 viewDir, float3x3 tbn, float noise, DisplacementParams params[6], out float pixelOffset, out float weights[6]) + float2 GetParallaxCoords(PS_INPUT input, float distance, float2 coords, float mipLevels[6], float3 viewDir, float3x3 tbn, float noise, DisplacementParams params[6], +# if defined(TERRAIN_VARIATION) + StochasticOffsets sharedOffset, float2 dx, float2 dy, +# endif + out float pixelOffset, out float weights[6]) #else float2 GetParallaxCoords(float distance, float2 coords, float mipLevel, float3 viewDir, float3x3 tbn, float noise, Texture2D tex, SamplerState texSampler, uint channel, DisplacementParams params, out float pixelOffset) #endif @@ -322,15 +432,29 @@ namespace ExtendedMaterials float4 currHeight; #if defined(LANDSCAPE) # if defined(TRUE_PBR) - currHeight.x = GetTerrainHeight(input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; - currHeight.y = GetTerrainHeight(input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; - currHeight.z = GetTerrainHeight(input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; - currHeight.w = GetTerrainHeight(input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; +# if defined(TERRAIN_VARIATION) + currHeight.x = GetTerrainHeight(noise, input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) * scalercp + 0.5; + currHeight.y = GetTerrainHeight(noise, input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) * scalercp + 0.5; + currHeight.z = GetTerrainHeight(noise, input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) * scalercp + 0.5; + currHeight.w = GetTerrainHeight(noise, input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) * scalercp + 0.5; +# else + currHeight.x = GetTerrainHeight(noise, input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; + currHeight.y = GetTerrainHeight(noise, input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; + currHeight.z = GetTerrainHeight(noise, input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; + currHeight.w = GetTerrainHeight(noise, input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; +# endif # else - currHeight.x = GetTerrainHeight(input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; - currHeight.y = GetTerrainHeight(input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; - currHeight.z = GetTerrainHeight(input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; - currHeight.w = GetTerrainHeight(input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; +# if defined(TERRAIN_VARIATION) + currHeight.x = GetTerrainHeight(noise, input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) + 0.5; + currHeight.y = GetTerrainHeight(noise, input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) + 0.5; + currHeight.z = GetTerrainHeight(noise, input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) + 0.5; + currHeight.w = GetTerrainHeight(noise, input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) + 0.5; +# else + currHeight.x = GetTerrainHeight(noise, input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; + currHeight.y = GetTerrainHeight(noise, input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; + currHeight.z = GetTerrainHeight(noise, input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; + currHeight.w = GetTerrainHeight(noise, input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; +# endif # endif #else currHeight.x = tex.SampleLevel(texSampler, currentOffset[0].xy, mipLevel)[channel]; @@ -448,39 +572,66 @@ namespace ExtendedMaterials } #if defined(LANDSCAPE) +# if defined(TERRAIN_VARIATION) + float GetParallaxSoftShadowMultiplierTerrain(PS_INPUT input, float2 coords, float mipLevel[6], float3 L, float sh0, float quality, float noise, DisplacementParams params[6], StochasticOffsets sharedOffset, float2 dx, float2 dy) +# else float GetParallaxSoftShadowMultiplierTerrain(PS_INPUT input, float2 coords, float mipLevel[6], float3 L, float sh0, float quality, float noise, DisplacementParams params[6]) +# endif { if (quality > 0.0) { float4 multipliers = rcp((float4(1, 2, 3, 4) + noise)); float4 sh; float heights[6] = { 0, 0, 0, 0, 0, 0 }; float2 rayDir = L.xy * 0.1; + # if defined(TRUE_PBR) float scale = max(params[0].HeightScale * input.LandBlendWeights1.x, max(params[1].HeightScale * input.LandBlendWeights1.y, max(params[2].HeightScale * input.LandBlendWeights1.z, max(params[3].HeightScale * input.LandBlendWeights1.w, max(params[4].HeightScale * input.LandBlendWeights2.x, params[5].HeightScale * input.LandBlendWeights2.y))))); if (scale < 0.01) return 1.0; rayDir *= scale; - sh = GetTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + +# if defined(TERRAIN_VARIATION) + sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + if (quality > 0.25) + sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + if (quality > 0.5) + sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + if (quality > 0.75) + sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); +# else + sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.25) - sh.y = GetTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.5) - sh.z = GetTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.75) - sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); +# endif return pow(1.0 - saturate(dot(max(0, sh - sh0) / scale, 1.0)) * quality, 2.0); # else - sh = GetTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); +# if defined(TERRAIN_VARIATION) + sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); if (quality > 0.25) - sh.y = GetTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); if (quality > 0.5) - sh.z = GetTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); if (quality > 0.75) - sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); +# else + sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (quality > 0.25) + sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (quality > 0.5) + sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (quality > 0.75) + sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); +# endif return pow(1.0 - saturate(dot(max(0, sh - sh0), 1.0)) * quality, 2.0); # endif } return 1.0; } #endif + } \ No newline at end of file diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index c9d3bfac77..f15e23ceb9 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -8,6 +8,11 @@ #include "Common/Random.hlsli" #include "Common/SharedData.hlsli" +// Height blend operator settings +static const float HEIGHT_BLEND_CONTRAST = 16.0; // Controls sharpness of height-based transitions +static const float CULLING_THRESHOLD = 0.01; // Minimum weight threshold for sample culling +static const float HEIGHT_INFLUENCE = 0.5; // How much height affects blending (0=pure stochastic, 1=pure height) + // Structure to hold stochastic sampling offsets and weights struct StochasticOffsets { @@ -17,15 +22,10 @@ struct StochasticOffsets float3 weights; }; -// Compute terrain variation blend factor -// Returns blend factor between 0.0 (no stochastic) and 1.0 (full stochastic) -inline float ComputeTerrainVariationBlend(float viewDistance) +// Check if terrain variation is enabled +inline bool IsTerrainVariationEnabled() { - if (!SharedData::terrainVariationSettings.enableTilingFix) - return 0.0; - - float blendFactor = saturate((viewDistance - 1200.0) / 1000.0); - return smoothstep(0.0, 1.0, blendFactor); + return SharedData::terrainVariationSettings.enableTilingFix; } // Hash function for stochastic sampling @@ -56,33 +56,71 @@ inline StochasticOffsets ComputeStochasticOffsets(float2 UV) } // Main stochastic sampling function -inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy, float distance = 0.0) +inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) { // If feature is disabled, return standard sample - if (!SharedData::terrainVariationSettings.enableTilingFix) - return tex.SampleLevel(samp, uv, mipLevel); // Compute terrain variation blend factor (0.0 = no stochastic, 1.0 = full stochastic) - float terrainVariationBlend = ComputeTerrainVariationBlend(distance); - float4 standardSample = tex.SampleLevel(samp, uv, mipLevel); - - // If no terrain variation blend, return standard sample - if (terrainVariationBlend <= 0.0) { - return standardSample; + [branch] if (!IsTerrainVariationEnabled()) + return tex.SampleLevel(samp, uv, mipLevel); + + bool useParallax = SharedData::extendedMaterialSettings.EnableTerrainParallax; + float4 sample1, sample2, sample3; + // Get stochastic samples + [branch] if (useParallax) { + // Parallax enabled, can use SampleLevel for better perf + sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); + sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); + } else { + // When parallax disabled, samplelevel causes mipmap issues, it uses too low a mipmap level up close. + sample1 = tex.SampleGrad(samp, uv + offsets.offset1, dx, dy); + sample2 = tex.SampleGrad(samp, uv + offsets.offset2, dx, dy); + sample3 = tex.SampleGrad(samp, uv + offsets.offset3, dx, dy); } - // Get stochastic samples only when needed (at distance where parallax fades out) - // Use SampleLevel since we're at distance where mipmap issues don't matter - float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); - float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); - float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); + // Extract height information from samples (use alpha channel if available, otherwise luminance) + float3 heights = float3( + sample1.a > 0 ? sample1.a : dot(sample1.rgb, float3(0.299, 0.587, 0.114)), + sample2.a > 0 ? sample2.a : dot(sample2.rgb, float3(0.299, 0.587, 0.114)), + sample3.a > 0 ? sample3.a : dot(sample3.rgb, float3(0.299, 0.587, 0.114)) + ); - // Weight samples according to offsets - float4 stochasticSample = sample1 * offsets.weights.x + - sample2 * offsets.weights.y + - sample3 * offsets.weights.z; + // Compute height-based blend weights + float3 heightBlendWeights = lerp(offsets.weights, heights, HEIGHT_INFLUENCE); + heightBlendWeights = pow(saturate(heightBlendWeights), HEIGHT_BLEND_CONTRAST); + + // Renormalize weights + float totalWeight = heightBlendWeights.x + heightBlendWeights.y + heightBlendWeights.z; + heightBlendWeights = (totalWeight > 0.0) ? heightBlendWeights / totalWeight : float3(0.33, 0.33, 0.34); + + // Adaptive culling - only blend samples that contribute meaningfully + float4 stochasticSample = float4(0, 0, 0, 0); + float culledWeightSum = 0.0; + + [branch] if (heightBlendWeights.x > CULLING_THRESHOLD) { + stochasticSample += sample1 * heightBlendWeights.x; + culledWeightSum += heightBlendWeights.x; + } + + [branch] if (heightBlendWeights.y > CULLING_THRESHOLD) { + stochasticSample += sample2 * heightBlendWeights.y; + culledWeightSum += heightBlendWeights.y; + } + + [branch] if (heightBlendWeights.z > CULLING_THRESHOLD) { + stochasticSample += sample3 * heightBlendWeights.z; + culledWeightSum += heightBlendWeights.z; + } + // Renormalize after culling, fallback to first sample if all culled + if (culledWeightSum > 0.0) { + stochasticSample /= culledWeightSum; + } else { + stochasticSample = sample1; // Fallback + } - // Smooth blend: lerp from standard to stochastic based on distance - return lerp(standardSample, stochasticSample, terrainVariationBlend); + return stochasticSample; } -#define StochasticSample(rnd, mipLevel, tex, samp, uv, dist) StochasticEffect(rnd, mipLevel, tex, samp, uv, ComputeStochasticOffsets(uv), ddx(uv), ddy(uv), dist).rgb + +#define StochasticSample(rnd, mipLevel, tex, samp, uv) StochasticEffect(rnd, mipLevel, tex, samp, uv, ComputeStochasticOffsets(uv), ddx(uv), ddy(uv)).rgb + #endif // TERRAIN_VARIATION_HLSLI \ No newline at end of file diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 5e2908cef2..e175979dde 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1274,6 +1274,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(TRUE_PBR) float4 blendedRMAOS = 0; # endif + float invwsum = totalWeight > 0.0 ? rcp(totalWeight) : 1.0; float viewDistance = length(viewPosition); float distanceFactor = 0.0; @@ -1282,8 +1283,6 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float2 dx = ddx(uv); float2 dy = ddy(uv); StochasticOffsets sharedOffset = ComputeStochasticOffsets(uv); - // Create terrain variation distance for smooth blend (2000-2048 units) - float terrainVariationDistance = viewDistance; # else distanceFactor = saturate(viewDistance * 0.00048828125); # endif @@ -1312,17 +1311,27 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif float weights[6]; +# if defined(TERRAIN_VARIATION) + uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, sharedOffset, dx, dy, pixelOffset, weights); +# else uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, pixelOffset, weights); +# endif if (SharedData::extendedMaterialSettings.EnableHeightBlending) { 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]; - } + input.LandBlendWeights2.x = weights[4]; + input.LandBlendWeights2.y = weights[5]; + } + if (SharedData::extendedMaterialSettings.EnableShadows && (parallaxShadowQuality > 0.0f || SharedData::extendedMaterialSettings.ExtendShadows)) { - sh0 = ExtendedMaterials::GetTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); +# if defined(TERRAIN_VARIATION) + sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); + float shadowMultiplier = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, DirLightDirection, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dx, dy); +# else + sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); +# endif } } # endif // EMAT @@ -1351,12 +1360,11 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif # endif -# if defined(LANDSCAPE) - // Layer 1 (LandBlendWeights1.x) +# if defined(LANDSCAPE) // Layer 1 (LandBlendWeights1.x) if (input.LandBlendWeights1.x > 0.01) { float weight = input.LandBlendWeights1.x * invwsum; # if defined(TERRAIN_VARIATION) - float4 diffuse1 = StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampColorSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); + float4 diffuse1 = StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampColorSampler, uv, sharedOffset, dx, dy); # else float distanceFactor = smoothstep(0.0, 2048.0, viewDistance); float4 diffuse1 = lerp( @@ -1371,21 +1379,22 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace diffuseRGB1 = diffuseRGB1 / Color::PBRLightingScale; } # endif + float alpha1 = diffuse1.a; # if defined(TERRAIN_VARIATION) - float4 normal1 = StochasticEffect(screenNoise, mipLevels[0], TexNormalSampler, SampNormalSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); + float4 normal1 = StochasticEffect(screenNoise, mipLevels[0], TexNormalSampler, SampNormalSampler, uv, sharedOffset, dx, dy); # else float4 normal1 = lerp( TexNormalSampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), TexNormalSampler.SampleLevel(SampNormalSampler, uv, distanceFactor * 3.0), distanceFactor); # endif - float3 normalRGB1 = normal1.rgb; + float3 normalRGB1 = normal1.rgb; float normalAlpha1 = normal1.a; # if defined(TRUE_PBR) # if defined(TERRAIN_VARIATION) - float4 rmaos1 = StochasticEffect(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); + float4 rmaos1 = StochasticEffect(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy); # else float4 rmaos1 = lerp( TexRMAOSSampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), @@ -1405,7 +1414,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace if (input.LandBlendWeights1.y > 0.01) { float weight = input.LandBlendWeights1.y * invwsum; # if defined(TERRAIN_VARIATION) - float4 diffuse2 = StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampColorSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); + float4 diffuse2 = StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampColorSampler, uv, sharedOffset, dx, dy); # else float distanceFactor = smoothstep(0.0, 2048.0, viewDistance); float4 diffuse2 = lerp( @@ -1423,7 +1432,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float alpha2 = diffuse2.a; # if defined(TERRAIN_VARIATION) - float4 normal2 = StochasticEffect(screenNoise, mipLevels[1], TexLandNormal2Sampler, SampNormalSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); + float4 normal2 = StochasticEffect(screenNoise, mipLevels[1], TexLandNormal2Sampler, SampNormalSampler, uv, sharedOffset, dx, dy); # else float4 normal2 = lerp( TexLandNormal2Sampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), @@ -1434,7 +1443,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float normalAlpha2 = normal2.a; # if defined(TRUE_PBR) # if defined(TERRAIN_VARIATION) - float4 rmaos2 = StochasticEffect(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); + float4 rmaos2 = StochasticEffect(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy); # else float4 rmaos2 = lerp( TexLandRMAOS2Sampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), @@ -1454,7 +1463,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace if (input.LandBlendWeights1.z > 0.01) { float weight = input.LandBlendWeights1.z * invwsum; # if defined(TERRAIN_VARIATION) - float4 diffuse3 = StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampColorSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); + float4 diffuse3 = StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampColorSampler, uv, sharedOffset, dx, dy); # else float distanceFactor = smoothstep(0.0, 2048.0, viewDistance); float4 diffuse3 = lerp( @@ -1472,7 +1481,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float alpha3 = diffuse3.a; # if defined(TERRAIN_VARIATION) - float4 normal3 = StochasticEffect(screenNoise, mipLevels[2], TexLandNormal3Sampler, SampNormalSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); + float4 normal3 = StochasticEffect(screenNoise, mipLevels[2], TexLandNormal3Sampler, SampNormalSampler, uv, sharedOffset, dx, dy); # else float4 normal3 = lerp( TexLandNormal3Sampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), @@ -1483,7 +1492,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float normalAlpha3 = normal3.a; # if defined(TRUE_PBR) # if defined(TERRAIN_VARIATION) - float4 rmaos3 = StochasticEffect(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); + float4 rmaos3 = StochasticEffect(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy); # else float4 rmaos3 = lerp( TexLandRMAOS3Sampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), @@ -1503,7 +1512,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace if (input.LandBlendWeights1.w > 0.01) { float weight = input.LandBlendWeights1.w * invwsum; # if defined(TERRAIN_VARIATION) - float4 diffuse4 = StochasticEffect(screenNoise, mipLevels[3], TexLandColor4Sampler, SampColorSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); + float4 diffuse4 = StochasticEffect(screenNoise, mipLevels[3], TexLandColor4Sampler, SampColorSampler, uv, sharedOffset, dx, dy); # else float distanceFactor = smoothstep(0.0, 2048.0, viewDistance); float4 diffuse4 = lerp( @@ -1521,7 +1530,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float alpha4 = diffuse4.a; # if defined(TERRAIN_VARIATION) - float4 normal4 = StochasticEffect(screenNoise, mipLevels[3], TexLandNormal4Sampler, SampNormalSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); + float4 normal4 = StochasticEffect(screenNoise, mipLevels[3], TexLandNormal4Sampler, SampNormalSampler, uv, sharedOffset, dx, dy); # else float4 normal4 = lerp( TexLandNormal4Sampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), @@ -1532,7 +1541,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float normalAlpha4 = normal4.a; # if defined(TRUE_PBR) # if defined(TERRAIN_VARIATION) - float4 rmaos4 = StochasticEffect(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); + float4 rmaos4 = StochasticEffect(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy); # else float4 rmaos4 = lerp( TexLandRMAOS4Sampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), @@ -1552,7 +1561,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace if (input.LandBlendWeights2.x > 0.01) { float weight = input.LandBlendWeights2.x * invwsum; # if defined(TERRAIN_VARIATION) - float4 diffuse5 = StochasticEffect(screenNoise, mipLevels[4], TexLandColor5Sampler, SampColorSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); + float4 diffuse5 = StochasticEffect(screenNoise, mipLevels[4], TexLandColor5Sampler, SampColorSampler, uv, sharedOffset, dx, dy); # else float distanceFactor = smoothstep(0.0, 2048.0, viewDistance); float4 diffuse5 = lerp( @@ -1570,7 +1579,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float alpha5 = diffuse5.a; # if defined(TERRAIN_VARIATION) - float4 normal5 = StochasticEffect(screenNoise, mipLevels[4], TexLandNormal5Sampler, SampNormalSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); + float4 normal5 = StochasticEffect(screenNoise, mipLevels[4], TexLandNormal5Sampler, SampNormalSampler, uv, sharedOffset, dx, dy); # else float4 normal5 = lerp( TexLandNormal5Sampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), @@ -1581,7 +1590,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float normalAlpha5 = normal5.a; # if defined(TRUE_PBR) # if defined(TERRAIN_VARIATION) - float4 rmaos5 = StochasticEffect(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); + float4 rmaos5 = StochasticEffect(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy); # else float4 rmaos5 = lerp( TexLandRMAOS5Sampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), @@ -1601,7 +1610,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace if (input.LandBlendWeights2.y > 0.01) { float weight = input.LandBlendWeights2.y * invwsum; # if defined(TERRAIN_VARIATION) - float4 diffuse6 = StochasticEffect(screenNoise, mipLevels[5], TexLandColor6Sampler, SampColorSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); + float4 diffuse6 = StochasticEffect(screenNoise, mipLevels[5], TexLandColor6Sampler, SampColorSampler, uv, sharedOffset, dx, dy); # else float distanceFactor = smoothstep(0.0, 2048.0, viewDistance); float4 diffuse6 = lerp( @@ -1619,7 +1628,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float alpha6 = diffuse6.a; # if defined(TERRAIN_VARIATION) - float4 normal6 = StochasticEffect(screenNoise, mipLevels[5], TexLandNormal6Sampler, SampNormalSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); + float4 normal6 = StochasticEffect(screenNoise, mipLevels[5], TexLandNormal6Sampler, SampNormalSampler, uv, sharedOffset, dx, dy); # else float4 normal6 = lerp( TexLandNormal6Sampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), @@ -1630,7 +1639,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float normalAlpha6 = normal6.a; # if defined(TRUE_PBR) # if defined(TERRAIN_VARIATION) - float4 rmaos6 = StochasticEffect(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, terrainVariationDistance); + float4 rmaos6 = StochasticEffect(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy); # else float4 rmaos6 = lerp( TexLandRMAOS6Sampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), @@ -2259,7 +2268,15 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(LANDSCAPE) [branch] if (SharedData::extendedMaterialSettings.EnableTerrainParallax) { +# if defined(TERRAIN_VARIATION) + float weights[6]; + sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); + + parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dx, dy); +# else + // Standard terrain parallax shadow without stochastic sampling parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams); +# endif } # elif defined(PARALLAX) [branch] if (SharedData::extendedMaterialSettings.EnableParallax) From f9b5c26c7fbf4516bc0a8a673fc3325e6a72d18b Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Sun, 25 May 2025 20:25:39 +1000 Subject: [PATCH 03/53] Update TerrainVariation.hlsli --- .../TerrainVariation/TerrainVariation.hlsli | 54 +++++++------------ 1 file changed, 20 insertions(+), 34 deletions(-) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index f15e23ceb9..d063dc4aa7 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -8,10 +8,10 @@ #include "Common/Random.hlsli" #include "Common/SharedData.hlsli" -// Height blend operator settings +// Height blend operator settings - DO NOT CHANGE THESE VALUES. static const float HEIGHT_BLEND_CONTRAST = 16.0; // Controls sharpness of height-based transitions -static const float CULLING_THRESHOLD = 0.01; // Minimum weight threshold for sample culling -static const float HEIGHT_INFLUENCE = 0.5; // How much height affects blending (0=pure stochastic, 1=pure height) +static const float CULLING_THRESHOLD = 0.001; // Minimum weight threshold for sample culling +static const float HEIGHT_INFLUENCE = 0.3; // How much height affects blending (0=pure stochastic, 1=pure height) // Structure to hold stochastic sampling offsets and weights struct StochasticOffsets @@ -22,12 +22,6 @@ struct StochasticOffsets float3 weights; }; -// Check if terrain variation is enabled -inline bool IsTerrainVariationEnabled() -{ - return SharedData::terrainVariationSettings.enableTilingFix; -} - // Hash function for stochastic sampling inline float2 hash2D2D(float2 s) { @@ -58,33 +52,23 @@ inline StochasticOffsets ComputeStochasticOffsets(float2 UV) // Main stochastic sampling function inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) { - // If feature is disabled, return standard sample - [branch] if (!IsTerrainVariationEnabled()) - return tex.SampleLevel(samp, uv, mipLevel); - - bool useParallax = SharedData::extendedMaterialSettings.EnableTerrainParallax; - float4 sample1, sample2, sample3; - // Get stochastic samples - [branch] if (useParallax) { - // Parallax enabled, can use SampleLevel for better perf - sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); - sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); - sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); - } else { - // When parallax disabled, samplelevel causes mipmap issues, it uses too low a mipmap level up close. - sample1 = tex.SampleGrad(samp, uv + offsets.offset1, dx, dy); - sample2 = tex.SampleGrad(samp, uv + offsets.offset2, dx, dy); - sample3 = tex.SampleGrad(samp, uv + offsets.offset3, dx, dy); + // Early return if terrain variation is disabled - provides zero overhead + [branch] if (!SharedData::terrainVariationSettings.enableTilingFix) { + return tex.SampleBias(samp, uv, SharedData::MipBias); } - + + float4 sample1, sample2, sample3; + // Get stochastic samples using SampleLevel for consistent mip selection + sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); + sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); // Extract height information from samples (use alpha channel if available, otherwise luminance) float3 heights = float3( - sample1.a > 0 ? sample1.a : dot(sample1.rgb, float3(0.299, 0.587, 0.114)), - sample2.a > 0 ? sample2.a : dot(sample2.rgb, float3(0.299, 0.587, 0.114)), - sample3.a > 0 ? sample3.a : dot(sample3.rgb, float3(0.299, 0.587, 0.114)) + sample1.a > 0 ? sample1.a : dot(sample1.rgb, float3(0.2126, 0.7152, 0.0722)), + sample2.a > 0 ? sample2.a : dot(sample2.rgb, float3(0.2126, 0.7152, 0.0722)), + sample3.a > 0 ? sample3.a : dot(sample3.rgb, float3(0.2126, 0.7152, 0.0722)) ); - // Compute height-based blend weights float3 heightBlendWeights = lerp(offsets.weights, heights, HEIGHT_INFLUENCE); heightBlendWeights = pow(saturate(heightBlendWeights), HEIGHT_BLEND_CONTRAST); @@ -116,11 +100,13 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler } else { stochasticSample = sample1; // Fallback } - return stochasticSample; } -#define StochasticSample(rnd, mipLevel, tex, samp, uv) StochasticEffect(rnd, mipLevel, tex, samp, uv, ComputeStochasticOffsets(uv), ddx(uv), ddy(uv)).rgb - +// Runtime macro that checks enableTilingFix and falls back to regular sampling when disabled +#define StochasticSample(rnd, mipLevel, tex, samp, uv) \ + (SharedData::terrainVariationSettings.enableTilingFix ? \ + StochasticEffect(rnd, mipLevel, tex, samp, uv, ComputeStochasticOffsets(uv), ddx(uv), ddy(uv)).rgb : \ + tex.SampleLevel(samp, uv, mipLevel).rgb) #endif // TERRAIN_VARIATION_HLSLI \ No newline at end of file From bf13dbb6a808002fd8791fa402ad267f7bc6a98a Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Sun, 25 May 2025 20:25:54 +1000 Subject: [PATCH 04/53] Update TerrainVariation.h --- src/Features/TerrainVariation.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Features/TerrainVariation.h b/src/Features/TerrainVariation.h index 88f5d0461f..eb5a8eea38 100644 --- a/src/Features/TerrainVariation.h +++ b/src/Features/TerrainVariation.h @@ -7,12 +7,12 @@ struct TerrainVariation : Feature static TerrainVariation singleton; return &singleton; } - virtual inline std::string GetName() override { return "Terrain Variation"; } virtual inline std::string GetShortName() override { return "TerrainVariation"; } virtual inline std::string GetFeatureModLink() override { return "https://www.nexusmods.com/skyrimspecialedition/mods/148123"; } - virtual inline std::string_view GetShaderDefineName() override { return "TERRAIN_VARIATION"; } - virtual inline bool HasShaderDefine(RE::BSShader::Type shaderType) override { return shaderType == RE::BSShader::Type::Lighting; } + virtual inline std::string_view GetShaderDefineName() override { return "TERRAIN_VARIATION"; } virtual inline bool HasShaderDefine(RE::BSShader::Type shaderType) override { + return (shaderType == RE::BSShader::Type::Lighting); + } virtual bool IsCore() const override { return false; }; virtual bool SupportsVR() override { return true; } struct Settings From 66dee34362f4643c68b88eddfbe18a92a1b0eb65 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Sun, 25 May 2025 22:26:42 +1000 Subject: [PATCH 05/53] Update 2, working. --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 423 ++++++-- .../TerrainVariation/TerrainVariation.hlsli | 76 +- package/Shaders/Lighting.hlsl | 940 +++++++++--------- 3 files changed, 901 insertions(+), 538 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index 151a419560..d6545b528d 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -195,20 +195,11 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand0HasDisplacement) != 0) { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[0], TexLandTHDisp0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); -# else h = ScaleDisplacement(TexLandTHDisp0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); -# endif } else { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[0]); - -# else h = ScaleDisplacement(TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, params[0]); -# endif } total += h * weights[0]; weights[0] *= pow(heightBlend, HEIGHT_MULT * h); @@ -217,22 +208,11 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) { - -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[1], TexLandTHDisp1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); - -# else h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); -# endif } else { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[1]); - -# else h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); -# endif } total += h * weights[1]; weights[1] *= pow(heightBlend, HEIGHT_MULT * h); @@ -241,22 +221,11 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) { - -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[2], TexLandTHDisp2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); - -# else h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); -# endif } else { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[2]); - -# else h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); -# endif } total += h * weights[2]; weights[2] *= pow(heightBlend, HEIGHT_MULT * h); @@ -265,22 +234,11 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0) { - -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[3], TexLandTHDisp3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); - -# else h = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); -# endif } else { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[3], TexLandColor4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[3]); - -# else h = ScaleDisplacement(TexLandColor4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).w, params[3]); -# endif } total += h * weights[3]; weights[3] *= pow(heightBlend, HEIGHT_MULT * h); @@ -289,22 +247,11 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0) { - -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[4], TexLandTHDisp4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); - -# else h = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); -# endif } else { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[4], TexLandColor5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[4]); - -# else h = ScaleDisplacement(TexLandColor5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).w, params[4]); -# endif } total += h * weights[4]; weights[4] *= pow(heightBlend, HEIGHT_MULT * h); @@ -313,22 +260,11 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0) { - -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[5], TexLandTHDisp5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); - -# else h = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); -# endif } else { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[5], TexLandColor6Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[5]); - -# else h = ScaleDisplacement(TexLandColor6Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).w, params[5]); -# endif } total += h * weights[5]; weights[5] *= pow(heightBlend, HEIGHT_MULT * h); @@ -633,5 +569,364 @@ namespace ExtendedMaterials return 1.0; } #endif +#if defined(LANDSCAPE) && defined(TERRAIN_VARIATION) + + // Overload for GetTerrainHeight WITHOUT StochasticOffsets (when enableTilingFix is false) +# if defined(TRUE_PBR) + float GetTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, out float weights[6]) + { + float heightBlend = 1 + blendFactor * HEIGHT_POWER; + weights[0] = w1.x; + weights[1] = w1.y; + weights[2] = w1.z; + weights[3] = w1.w; + weights[4] = w2.x; + weights[5] = w2.y; + float total = 0; + float screenNoise = 0; // Default noise value when no stochastic sampling + + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.0) + { + float h = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); + total += h * weights[0]; + weights[0] *= pow(heightBlend, HEIGHT_MULT * h); + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1HasDisplacement) != 0 && w1.y > 0.0) + { + float h = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); + total += h * weights[1]; + weights[1] *= pow(heightBlend, HEIGHT_MULT * h); + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2HasDisplacement) != 0 && w1.z > 0.0) + { + float h = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); + total += h * weights[2]; + weights[2] *= pow(heightBlend, HEIGHT_MULT * h); + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) + { + float h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); + total += h * weights[3]; + weights[3] *= pow(heightBlend, HEIGHT_MULT * h); + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) + { + float h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); + total += h * weights[4]; + weights[4] *= pow(heightBlend, HEIGHT_MULT * h); + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) + { + float h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); + total += h * weights[5]; + weights[5] *= pow(heightBlend, HEIGHT_MULT * h); + } + [unroll] for (int i = 0; i < 6; i++) + { + weights[i] = min(100, pow(weights[i], heightBlend)); + } + float wsum = 0; + [unroll] for (int i = 0; i < 6; i++) + { + wsum += weights[i]; + } + float invwsum = rcp(wsum); + [unroll] for (i = 0; i < 6; i++) + { + weights[i] *= invwsum; + } + return total; + } +# else + float GetTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, out float weights[6]) + { + float heightBlend = 1 + blendFactor * HEIGHT_POWER; + weights[0] = w1.x; + weights[1] = w1.y; + weights[2] = w1.z; + weights[3] = w1.w; + weights[4] = w2.x; + weights[5] = w2.y; + float total = 0; + float screenNoise = 0; // Default noise value when no stochastic sampling + + if (w1.x > 0.0) { + float h = 0.0; + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand0HasDisplacement) != 0) + { + h = ScaleDisplacement(TexLandTHDisp0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); + } + else + { + h = ScaleDisplacement(TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, params[0]); + } + total += h * weights[0]; + weights[0] *= pow(heightBlend, HEIGHT_MULT * h); + } + if (w1.y > 0.0) { + float h = 0.0; + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) + { + h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); + } + else + { + h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); + } + total += h * weights[1]; + weights[1] *= pow(heightBlend, HEIGHT_MULT * h); + } + if (w1.z > 0.0) { + float h = 0.0; + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) + { + h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); + } + else + { + h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); + } + total += h * weights[2]; + weights[2] *= pow(heightBlend, HEIGHT_MULT * h); + } + if (w1.w > 0.0) { + float h = 0.0; + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0) + { + h = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); + } + else + { + h = ScaleDisplacement(TexLandColor4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).w, params[3]); + } + total += h * weights[3]; + weights[3] *= pow(heightBlend, HEIGHT_MULT * h); + } + if (w2.x > 0.0) { + float h = 0.0; + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0) + { + h = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); + } + else + { + h = ScaleDisplacement(TexLandColor5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).w, params[4]); + } + total += h * weights[4]; + weights[4] *= pow(heightBlend, HEIGHT_MULT * h); + } + if (w2.y > 0.0) { + float h = 0.0; + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0) + { + h = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); + } + else + { + h = ScaleDisplacement(TexLandColor6Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).w, params[5]); + } + total += h * weights[5]; + weights[5] *= pow(heightBlend, HEIGHT_MULT * h); + } + [unroll] for (int i = 0; i < 6; i++) + { + weights[i] = min(100, pow(weights[i], heightBlend)); + } + float wsum = 0; + [unroll] for (int i = 0; i < 6; i++) + { + wsum += weights[i]; + } + float invwsum = rcp(wsum); + [unroll] for (i = 0; i < 6; i++) + { + weights[i] *= invwsum; + } + return total; + } +# endif + + // Overload for GetParallaxCoords WITHOUT StochasticOffsets (when enableTilingFix is false) + float2 GetParallaxCoords(PS_INPUT input, float distance, float2 coords, float mipLevels[6], float3 viewDir, float3x3 tbn, float noise, DisplacementParams params[6], out float pixelOffset, out float weights[6]) + { + float3 viewDirTS = normalize(mul(tbn, viewDir)); + viewDirTS.xy /= viewDirTS.z * 0.7 + 0.3 + params[0].FlattenAmount; // Fix for objects at extreme viewing angles + + float nearBlendToFar = saturate(distance / 2048.0); +# if defined(TRUE_PBR) + float blendFactor = SharedData::extendedMaterialSettings.EnableHeightBlending ? sqrt(saturate(1 - nearBlendToFar)) : 0; + float4 w1 = lerp(input.LandBlendWeights1, smoothstep(0, 1, input.LandBlendWeights1), blendFactor); + float2 w2 = lerp(input.LandBlendWeights2.xy, smoothstep(0, 1, input.LandBlendWeights2.xy), blendFactor); + float scale = max(params[0].HeightScale * w1.x, max(params[1].HeightScale * w1.y, max(params[2].HeightScale * w1.z, max(params[3].HeightScale * w1.w, max(params[4].HeightScale * w2.x, params[5].HeightScale * w2.y))))); + float scalercp = rcp(scale); + float maxHeight = 0.1 * scale; +# else + float blendFactor = SharedData::extendedMaterialSettings.EnableHeightBlending ? sqrt(saturate(1 - nearBlendToFar)) : 0; + float4 w1 = lerp(input.LandBlendWeights1, smoothstep(0, 1, input.LandBlendWeights1), blendFactor); + float2 w2 = lerp(input.LandBlendWeights2.xy, smoothstep(0, 1, input.LandBlendWeights2.xy), blendFactor); + float scale = 1; + float maxHeight = 0.1 * scale; +# endif + float minHeight = maxHeight * 0.5; + + if (nearBlendToFar < 1.0) { + uint numSteps = uint((max(6, scale * 8) * (1.0 - nearBlendToFar)) + 0.5); + numSteps = clamp((numSteps + 3) & ~0x03, 4, max(8, scale * 8)); + float stepSize = rcp(numSteps); + stepSize += (noise * 2.0 - 1.0) * stepSize * stepSize; + + float2 offsetPerStep = viewDirTS.xy * float2(maxHeight, maxHeight) * stepSize.xx; + float2 prevOffset = viewDirTS.xy * float2(minHeight, minHeight) + coords.xy; + + float prevBound = 1.0; + float prevHeight = 1.0; + + float2 pt1 = 0; + float2 pt2 = 0; + + uint numStepsTemp = numSteps; + bool contactRefinement = false; + + [loop] while (numSteps > 0) + { + float4 currentOffset[2]; + currentOffset[0] = prevOffset.xyxy - float4(1, 1, 2, 2) * offsetPerStep.xyxy; + currentOffset[1] = prevOffset.xyxy - float4(3, 3, 4, 4) * offsetPerStep.xyxy; + float4 currentBound = prevBound.xxxx - float4(1, 2, 3, 4) * stepSize; + + float4 currHeight; +# if defined(TRUE_PBR) + currHeight.x = GetTerrainHeight(input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; + currHeight.y = GetTerrainHeight(input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; + currHeight.z = GetTerrainHeight(input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; + currHeight.w = GetTerrainHeight(input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; +# else + currHeight.x = GetTerrainHeight(input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; + currHeight.y = GetTerrainHeight(input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; + currHeight.z = GetTerrainHeight(input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; + currHeight.w = GetTerrainHeight(input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; +# endif + + bool4 testResult = currHeight >= currentBound; + [branch] if (any(testResult)) + { + float2 outOffset = 0; + [flatten] if (testResult.w) + { + outOffset = currentOffset[1].xy; + pt1 = float2(currentBound.w, currHeight.w); + pt2 = float2(currentBound.z, currHeight.z); + } + [flatten] if (testResult.z) + { + outOffset = currentOffset[0].zw; + pt1 = float2(currentBound.z, currHeight.z); + pt2 = float2(currentBound.y, currHeight.y); + } + [flatten] if (testResult.y) + { + outOffset = currentOffset[0].xy; + pt1 = float2(currentBound.y, currHeight.y); + pt2 = float2(currentBound.x, currHeight.x); + } + [flatten] if (testResult.x) + { + outOffset = prevOffset; + pt1 = float2(currentBound.x, currHeight.x); + pt2 = float2(prevBound, prevHeight); + } + if (contactRefinement) { + break; + } else { + contactRefinement = true; + prevOffset = outOffset; + prevBound = pt2.x; + numSteps = numStepsTemp; + stepSize /= (float)numSteps; + offsetPerStep /= (float)numSteps; + continue; + } + } + + prevOffset = currentOffset[1].zw; + prevBound = currentBound.w; + prevHeight = currHeight.w; + numSteps -= 4; + } + + float delta2 = pt2.x - pt2.y; + float delta1 = pt1.x - pt1.y; + float denominator = delta2 - delta1; + + float parallaxAmount = 0.0; + [flatten] if (denominator == 0.0) + { + parallaxAmount = 0.0; + } + else + { + parallaxAmount = (pt1.x * delta2 - pt2.x * delta1) / denominator; + } + +# if defined(TRUE_PBR) + if ((PBRFlags & PBR::Flags::InterlayerParallax) != 0) + nearBlendToFar = 0; + else +# endif + nearBlendToFar *= nearBlendToFar; + float offset = (1.0 - parallaxAmount) * -maxHeight + minHeight; + pixelOffset = lerp(parallaxAmount * scale, 0, nearBlendToFar); + return lerp(viewDirTS.xy * offset + coords.xy, coords, nearBlendToFar); + } + + weights[0] = input.LandBlendWeights1.x; + weights[1] = input.LandBlendWeights1.y; + weights[2] = input.LandBlendWeights1.z; + weights[3] = input.LandBlendWeights1.w; + weights[4] = input.LandBlendWeights2.x; + weights[5] = input.LandBlendWeights2.y; + + pixelOffset = 0; + return coords; + } + + // Overload for GetParallaxSoftShadowMultiplierTerrain WITHOUT StochasticOffsets + float GetParallaxSoftShadowMultiplierTerrain(PS_INPUT input, float2 coords, float mipLevel[6], float3 L, float sh0, float quality, float noise, DisplacementParams params[6]) + { + if (quality > 0.0) { + float4 multipliers = rcp((float4(1, 2, 3, 4) + noise)); + float4 sh; + float heights[6] = { 0, 0, 0, 0, 0, 0 }; + float2 rayDir = L.xy * 0.1; + +# if defined(TRUE_PBR) + float scale = max(params[0].HeightScale * input.LandBlendWeights1.x, max(params[1].HeightScale * input.LandBlendWeights1.y, max(params[2].HeightScale * input.LandBlendWeights1.z, + max(params[3].HeightScale * input.LandBlendWeights1.w, max(params[4].HeightScale * input.LandBlendWeights2.x, params[5].HeightScale * input.LandBlendWeights2.y))))); + if (scale < 0.01) + return 1.0; + rayDir *= scale; + + sh = GetTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (quality > 0.25) + sh.y = GetTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (quality > 0.5) + sh.z = GetTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (quality > 0.75) + sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + return pow(1.0 - saturate(dot(max(0, sh - sh0) / scale, 1.0)) * quality, 2.0); +# else + sh = GetTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (quality > 0.25) + sh.y = GetTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (quality > 0.5) + sh.z = GetTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (quality > 0.75) + sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + return pow(1.0 - saturate(dot(max(0, sh - sh0), 1.0)) * quality, 2.0); +# endif + } + return 1.0; + } +#endif // defined(LANDSCAPE) && defined(TERRAIN_VARIATION) } \ No newline at end of file diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index d063dc4aa7..6f380478dd 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -52,53 +52,67 @@ inline StochasticOffsets ComputeStochasticOffsets(float2 UV) // Main stochastic sampling function inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) { - // Early return if terrain variation is disabled - provides zero overhead + // Early return if terrain variation is disabled [branch] if (!SharedData::terrainVariationSettings.enableTilingFix) { return tex.SampleBias(samp, uv, SharedData::MipBias); } - float4 sample1, sample2, sample3; - // Get stochastic samples using SampleLevel for consistent mip selection - sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); - sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); - sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); - // Extract height information from samples (use alpha channel if available, otherwise luminance) - float3 heights = float3( - sample1.a > 0 ? sample1.a : dot(sample1.rgb, float3(0.2126, 0.7152, 0.0722)), - sample2.a > 0 ? sample2.a : dot(sample2.rgb, float3(0.2126, 0.7152, 0.0722)), - sample3.a > 0 ? sample3.a : dot(sample3.rgb, float3(0.2126, 0.7152, 0.0722)) - ); - - float3 heightBlendWeights = lerp(offsets.weights, heights, HEIGHT_INFLUENCE); - heightBlendWeights = pow(saturate(heightBlendWeights), HEIGHT_BLEND_CONTRAST); + // First determine the weights based only on the offset weights (without height influence) + float3 blendWeights = offsets.weights; - // Renormalize weights - float totalWeight = heightBlendWeights.x + heightBlendWeights.y + heightBlendWeights.z; - heightBlendWeights = (totalWeight > 0.0) ? heightBlendWeights / totalWeight : float3(0.33, 0.33, 0.34); - - // Adaptive culling - only blend samples that contribute meaningfully + // Apply contrast and saturation to the initial blend weights + blendWeights = pow(saturate(blendWeights), HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE)); + + // Renormalize the weights + float totalWeight = blendWeights.x + blendWeights.y + blendWeights.z; + blendWeights = (totalWeight > 0.0) ? blendWeights / totalWeight : float3(0.33, 0.33, 0.34); + + // Storage for samples and accumulated results float4 stochasticSample = float4(0, 0, 0, 0); float culledWeightSum = 0.0; + float4 sample; - [branch] if (heightBlendWeights.x > CULLING_THRESHOLD) { - stochasticSample += sample1 * heightBlendWeights.x; - culledWeightSum += heightBlendWeights.x; + // Only sample textures when their weight exceeds the culling threshold + // This avoids fetching textures that would be discarded anyway + [branch] if (blendWeights.x > CULLING_THRESHOLD) { + sample = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + + // Adjust weight based on height if needed + float height = sample.a > 0 ? sample.a : dot(sample.rgb, float3(0.2126, 0.7152, 0.0722)); + float weight = lerp(blendWeights.x, height * blendWeights.x, HEIGHT_INFLUENCE); + + stochasticSample += sample * weight; + culledWeightSum += weight; } - [branch] if (heightBlendWeights.y > CULLING_THRESHOLD) { - stochasticSample += sample2 * heightBlendWeights.y; - culledWeightSum += heightBlendWeights.y; + [branch] if (blendWeights.y > CULLING_THRESHOLD) { + sample = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); + + // Adjust weight based on height if needed + float height = sample.a > 0 ? sample.a : dot(sample.rgb, float3(0.2126, 0.7152, 0.0722)); + float weight = lerp(blendWeights.y, height * blendWeights.y, HEIGHT_INFLUENCE); + + stochasticSample += sample * weight; + culledWeightSum += weight; } - [branch] if (heightBlendWeights.z > CULLING_THRESHOLD) { - stochasticSample += sample3 * heightBlendWeights.z; - culledWeightSum += heightBlendWeights.z; + [branch] if (blendWeights.z > CULLING_THRESHOLD) { + sample = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); + + // Adjust weight based on height if needed + float height = sample.a > 0 ? sample.a : dot(sample.rgb, float3(0.2126, 0.7152, 0.0722)); + float weight = lerp(blendWeights.z, height * blendWeights.z, HEIGHT_INFLUENCE); + + stochasticSample += sample * weight; + culledWeightSum += weight; } - // Renormalize after culling, fallback to first sample if all culled + + // Renormalize after culling if (culledWeightSum > 0.0) { stochasticSample /= culledWeightSum; } else { - stochasticSample = sample1; // Fallback + // If all samples were culled, get a single sample as fallback + stochasticSample = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); // Fallback } return stochasticSample; } diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index e175979dde..9fb704f02a 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1259,33 +1259,24 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif // SPARKLE # if defined(LANDSCAPE) - // Normalise blend weights + // Normalize blend weights float totalWeight = input.LandBlendWeights1.x + input.LandBlendWeights1.y + input.LandBlendWeights1.z + input.LandBlendWeights1.w + input.LandBlendWeights2.x + input.LandBlendWeights2.y; if (totalWeight > 0.0) { input.LandBlendWeights1 /= totalWeight; input.LandBlendWeights2.xy /= totalWeight; } - float3 blendedRGB = 0; - float blendedAlpha = 0; - float3 blendedNormalRGB = 0; - float blendedNormalAlpha = 0; -# if defined(TRUE_PBR) - float4 blendedRMAOS = 0; -# endif - - float invwsum = totalWeight > 0.0 ? rcp(totalWeight) : 1.0; - float viewDistance = length(viewPosition); - float distanceFactor = 0.0; - // Compute stochastic offsets and derivatives once for all layers -# if defined(TERRAIN_VARIATION) - float2 dx = ddx(uv); - float2 dy = ddy(uv); - StochasticOffsets sharedOffset = ComputeStochasticOffsets(uv); -# else - distanceFactor = saturate(viewDistance * 0.00048828125); -# endif + // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) +# if defined(TERRAIN_VARIATION) + float2 dx, dy; + StochasticOffsets sharedOffset; + if (SharedData::terrainVariationSettings.enableTilingFix) { + dx = ddx(uv); + dy = ddy(uv); + sharedOffset = ComputeStochasticOffsets(uv); + } +# endif # if defined(EMAT) if (SharedData::extendedMaterialSettings.EnableTerrainParallax) { @@ -1309,33 +1300,40 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace displacementParams[4].HeightScale *= LandscapeTexture5PBRParams.y; displacementParams[5].HeightScale *= LandscapeTexture6PBRParams.y; # endif - float weights[6]; -# if defined(TERRAIN_VARIATION) - uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, sharedOffset, dx, dy, pixelOffset, weights); -# else +# if defined(TERRAIN_VARIATION) + if (SharedData::terrainVariationSettings.enableTilingFix) { + uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, sharedOffset, dx, dy, pixelOffset, weights); + } else { + uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, pixelOffset, weights); + } +# else uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, pixelOffset, weights); -# endif +# endif + if (SharedData::extendedMaterialSettings.EnableHeightBlending) { 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]; - } - + input.LandBlendWeights2.x = weights[4]; + input.LandBlendWeights2.y = weights[5]; + } + if (SharedData::extendedMaterialSettings.EnableShadows && (parallaxShadowQuality > 0.0f || SharedData::extendedMaterialSettings.ExtendShadows)) { -# if defined(TERRAIN_VARIATION) +# if defined(TERRAIN_VARIATION) + if (SharedData::terrainVariationSettings.enableTilingFix) { sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); - float shadowMultiplier = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, DirLightDirection, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dx, dy); -# else - sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); -# endif + } else { + sh0 = ExtendedMaterials::GetTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); + } +# else + sh0 = ExtendedMaterials::GetTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); +# endif } } # endif // EMAT -# endif // LANDSCAPE +# endif // LANDSCAPE # if defined(SPARKLE) diffuseUv = ProjectedUVParams2.yy * (input.TexCoord0.zw + (uv - uvOriginal)); @@ -1346,11 +1344,8 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float4 baseColor = 0; float4 normal = 0; float glossiness = 0; - float4 rawRMAOS = 0; - float4 glintParameters = 0; - # if defined(SNOW) // Earlier snow definition for Terrain Variation rework. # if !defined(TRUE_PBR) float landSnowMask = 0.0; @@ -1361,322 +1356,460 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif # if defined(LANDSCAPE) // Layer 1 (LandBlendWeights1.x) - if (input.LandBlendWeights1.x > 0.01) { - float weight = input.LandBlendWeights1.x * invwsum; -# if defined(TERRAIN_VARIATION) - float4 diffuse1 = StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampColorSampler, uv, sharedOffset, dx, dy); -# else - float distanceFactor = smoothstep(0.0, 2048.0, viewDistance); - float4 diffuse1 = lerp( - TexColorSampler.SampleBias(SampColorSampler, uv, SharedData::MipBias), - TexColorSampler.SampleLevel(SampColorSampler, uv, distanceFactor * 3.0), - distanceFactor); -# endif - float3 diffuseRGB1 = diffuse1.rgb; -# if defined(TRUE_PBR) - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0PBR) == 0) - { - diffuseRGB1 = diffuseRGB1 / Color::PBRLightingScale; - } -# endif - - float alpha1 = diffuse1.a; - -# if defined(TERRAIN_VARIATION) - float4 normal1 = StochasticEffect(screenNoise, mipLevels[0], TexNormalSampler, SampNormalSampler, uv, sharedOffset, dx, dy); -# else - float4 normal1 = lerp( - TexNormalSampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), - TexNormalSampler.SampleLevel(SampNormalSampler, uv, distanceFactor * 3.0), - distanceFactor); -# endif - float3 normalRGB1 = normal1.rgb; - float normalAlpha1 = normal1.a; -# if defined(TRUE_PBR) + if (input.LandBlendWeights1.x > 0.0) { + // Sample layer 1 textures - use terrain variation if available and enabled # if defined(TERRAIN_VARIATION) - float4 rmaos1 = StochasticEffect(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy); + float4 landColor1; + if (SharedData::terrainVariationSettings.enableTilingFix) { + landColor1 = StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampColorSampler, uv, sharedOffset, dx, dy); + } else { + landColor1 = TexColorSampler.SampleBias(SampColorSampler, uv, SharedData::MipBias); + } # else - float4 rmaos1 = lerp( - TexRMAOSSampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), - TexRMAOSSampler.SampleLevel(SampRMAOSSampler, uv, distanceFactor * 3.0), - distanceFactor); + float4 landColor1 = TexColorSampler.SampleBias(SampColorSampler, uv, SharedData::MipBias); # endif - rmaos1 *= float4(PBRParams1.x, 1, 1, PBRParams1.z); - blendedRMAOS += rmaos1 * weight; // Blending Within Layers (Same for the rest of layers 2-6) -# endif - blendedRGB += diffuseRGB1 * weight; - blendedAlpha += alpha1 * weight; - blendedNormalRGB += normalRGB1 * weight; - blendedNormalAlpha += normalAlpha1 * weight; - } - - // Layer 2 (LandBlendWeights1.y) - if (input.LandBlendWeights1.y > 0.01) { - float weight = input.LandBlendWeights1.y * invwsum; -# if defined(TERRAIN_VARIATION) - float4 diffuse2 = StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampColorSampler, uv, sharedOffset, dx, dy); -# else - float distanceFactor = smoothstep(0.0, 2048.0, viewDistance); - float4 diffuse2 = lerp( - TexLandColor2Sampler.SampleBias(SampColorSampler, uv, SharedData::MipBias), - TexLandColor2Sampler.SampleLevel(SampColorSampler, uv, distanceFactor * 3.0), - distanceFactor); -# endif - float3 diffuseRGB2 = diffuse2.rgb; -# if defined(TRUE_PBR) - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1PBR) == 0) - { - diffuseRGB2 = diffuseRGB2 / Color::PBRLightingScale; - } -# endif - float alpha2 = diffuse2.a; -# if defined(TERRAIN_VARIATION) - float4 normal2 = StochasticEffect(screenNoise, mipLevels[1], TexLandNormal2Sampler, SampNormalSampler, uv, sharedOffset, dx, dy); -# else - float4 normal2 = lerp( - TexLandNormal2Sampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), - TexLandNormal2Sampler.SampleLevel(SampNormalSampler, uv, distanceFactor * 3.0), - distanceFactor); -# endif - float3 normalRGB2 = normal2.rgb; - float normalAlpha2 = normal2.a; -# if defined(TRUE_PBR) -# if defined(TERRAIN_VARIATION) - float4 rmaos2 = StochasticEffect(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy); -# else - float4 rmaos2 = lerp( - TexLandRMAOS2Sampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), - TexLandRMAOS2Sampler.SampleLevel(SampRMAOSSampler, uv, distanceFactor * 3.0), - distanceFactor); -# endif - rmaos2 *= float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); - blendedRMAOS += rmaos2 * weight; -# endif - blendedRGB += diffuseRGB2 * weight; - blendedAlpha += alpha2 * weight; - blendedNormalRGB += normalRGB2 * weight; - blendedNormalAlpha += normalAlpha2 * weight; - } +# if defined(TRUE_PBR) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0PBR) == 0) + { + landColor1 = float4(landColor1.rgb / Color::PBRLightingScale, landColor1.a); + } + else + { + landColor1.rgb = Color::Diffuse(landColor1.rgb); + } +# else + landColor1.rgb = Color::Diffuse(landColor1.rgb); +# endif + float landSnowMask1 = GetLandSnowMaskValue(landColor1.w); - // Layer 3 (LandBlendWeights1.z) - if (input.LandBlendWeights1.z > 0.01) { - float weight = input.LandBlendWeights1.z * invwsum; -# if defined(TERRAIN_VARIATION) - float4 diffuse3 = StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampColorSampler, uv, sharedOffset, dx, dy); -# else - float distanceFactor = smoothstep(0.0, 2048.0, viewDistance); - float4 diffuse3 = lerp( - TexLandColor3Sampler.SampleBias(SampColorSampler, uv, SharedData::MipBias), - TexLandColor3Sampler.SampleLevel(SampColorSampler, uv, distanceFactor * 3.0), - distanceFactor); -# endif - float3 diffuseRGB3 = diffuse3.rgb; -# if defined(TRUE_PBR) - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2PBR) == 0) - { - diffuseRGB3 = diffuseRGB3 / Color::PBRLightingScale; - } -# endif - float alpha3 = diffuse3.a; + // Sample normal texture for layer 1 + # if defined(TERRAIN_VARIATION) + float4 landNormal1; + if (SharedData::terrainVariationSettings.enableTilingFix) { + landNormal1 = StochasticEffect(screenNoise, mipLevels[0], TexNormalSampler, SampNormalSampler, uv, sharedOffset, dx, dy); + } else { + landNormal1 = TexNormalSampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias); + } + # else + float4 landNormal1 = TexNormalSampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias); + # endif + + landNormal1.xyz = GetLandNormal(landSnowMask1, landNormal1.xyz, uv, SampNormalSampler, TexNormalSampler); + normal.xyz += input.LandBlendWeights1.xxx * landNormal1.xyz; + glossiness += input.LandBlendWeights1.x * landNormal1.w; + # if defined(SNOW) && !defined(TRUE_PBR) + landSnowMask += LandscapeTexture1to4IsSnow.x * input.LandBlendWeights1.x * landSnowMask1; + # endif // SNOW + + # if defined(TRUE_PBR) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0PBR) != 0) + { + // Sample RMAOS texture for layer 1 + # if defined(TERRAIN_VARIATION) + if (SharedData::terrainVariationSettings.enableTilingFix) { + rawRMAOS += input.LandBlendWeights1.x * StochasticEffect(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + } else { + rawRMAOS += input.LandBlendWeights1.x * TexRMAOSSampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + } + # else + rawRMAOS += input.LandBlendWeights1.x * TexRMAOSSampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + # endif + if ((PBRFlags & PBR::TerrainFlags::LandTile0HasGlint) != 0) { + glintParameters += input.LandBlendWeights1.x * LandscapeTexture1GlintParameters; + } + } + else + { + rawRMAOS += input.LandBlendWeights1.x * float4(1 - landNormal1.w, 0, 1, 0); + } + # endif + baseColor += input.LandBlendWeights1.xxxx * landColor1; + } + // Layer 2 (LandBlendWeights1.y) + if (input.LandBlendWeights1.y > 0.0) { + // Sample layer 2 textures - use terrain variation if available and enabled + # if defined(TERRAIN_VARIATION) + float4 landColor2; + if (SharedData::terrainVariationSettings.enableTilingFix) { + landColor2 = StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampLandColor2Sampler, uv, sharedOffset, dx, dy); + } else { + landColor2 = TexLandColor2Sampler.SampleBias(SampLandColor2Sampler, uv, SharedData::MipBias); + } + # else + float4 landColor2 = TexLandColor2Sampler.SampleBias(SampLandColor2Sampler, uv, SharedData::MipBias); + # endif + +# if defined(TRUE_PBR) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1PBR) == 0) + { + landColor2 = float4(landColor2.rgb / Color::PBRLightingScale, landColor2.a); + } + else + { + landColor2.rgb = Color::Diffuse(landColor2.rgb); + } +# else + landColor2.rgb = Color::Diffuse(landColor2.rgb); +# endif + float landSnowMask2 = GetLandSnowMaskValue(landColor2.w); -# if defined(TERRAIN_VARIATION) - float4 normal3 = StochasticEffect(screenNoise, mipLevels[2], TexLandNormal3Sampler, SampNormalSampler, uv, sharedOffset, dx, dy); -# else - float4 normal3 = lerp( - TexLandNormal3Sampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), - TexLandNormal3Sampler.SampleLevel(SampNormalSampler, uv, distanceFactor * 3.0), - distanceFactor); -# endif - float3 normalRGB3 = normal3.rgb; - float normalAlpha3 = normal3.a; -# if defined(TRUE_PBR) -# if defined(TERRAIN_VARIATION) - float4 rmaos3 = StochasticEffect(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy); -# else - float4 rmaos3 = lerp( - TexLandRMAOS3Sampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), - TexLandRMAOS3Sampler.SampleLevel(SampRMAOSSampler, uv, distanceFactor * 3.0), - distanceFactor); -# endif - rmaos3 *= float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); - blendedRMAOS += rmaos3 * weight; -# endif - blendedRGB += diffuseRGB3 * weight; - blendedAlpha += alpha3 * weight; - blendedNormalRGB += normalRGB3 * weight; - blendedNormalAlpha += normalAlpha3 * weight; - } + // Sample normal texture for layer 2 + # if defined(TERRAIN_VARIATION) + float4 landNormal2; + if (SharedData::terrainVariationSettings.enableTilingFix) { + landNormal2 = StochasticEffect(screenNoise, mipLevels[1], TexLandNormal2Sampler, SampLandNormal2Sampler, uv, sharedOffset, dx, dy); + } else { + landNormal2 = TexLandNormal2Sampler.SampleBias(SampLandNormal2Sampler, uv, SharedData::MipBias); + } + # else + float4 landNormal2 = TexLandNormal2Sampler.SampleBias(SampLandNormal2Sampler, uv, SharedData::MipBias); + # endif + + landNormal2.xyz = GetLandNormal(landSnowMask2, landNormal2.xyz, uv, SampLandNormal2Sampler, TexLandNormal2Sampler); + normal.xyz += input.LandBlendWeights1.yyy * landNormal2.xyz; + glossiness += input.LandBlendWeights1.y * landNormal2.w; + # if defined(SNOW) && !defined(TRUE_PBR) + landSnowMask += LandscapeTexture1to4IsSnow.y * input.LandBlendWeights1.y * landSnowMask2; + # endif // SNOW + + # if defined(TRUE_PBR) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1PBR) != 0) + { + // Sample RMAOS texture for layer 2 + # if defined(TERRAIN_VARIATION) + if (SharedData::terrainVariationSettings.enableTilingFix) { + rawRMAOS += input.LandBlendWeights1.y * StochasticEffect(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampLandRMAOS2Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); + } else { + rawRMAOS += input.LandBlendWeights1.y * TexLandRMAOS2Sampler.SampleBias(SampLandRMAOS2Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); + } + # else + rawRMAOS += input.LandBlendWeights1.y * TexLandRMAOS2Sampler.SampleBias(SampLandRMAOS2Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); + # endif + if ((PBRFlags & PBR::TerrainFlags::LandTile1HasGlint) != 0) { + glintParameters += input.LandBlendWeights1.y * LandscapeTexture2GlintParameters; + } + } + else + { + rawRMAOS += input.LandBlendWeights1.y * float4(1 - landNormal2.w, 0, 1, 0); + } + # endif + baseColor += input.LandBlendWeights1.yyyy * landColor2; + } // Layer 3 (LandBlendWeights1.z) + if (input.LandBlendWeights1.z > 0.0) { + // Sample layer 3 textures - use terrain variation if available and enabled + # if defined(TERRAIN_VARIATION) + float4 landColor3; + if (SharedData::terrainVariationSettings.enableTilingFix) { + landColor3 = StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampLandColor3Sampler, uv, sharedOffset, dx, dy); + } else { + landColor3 = TexLandColor3Sampler.SampleBias(SampLandColor3Sampler, uv, SharedData::MipBias); + } + # else + float4 landColor3 = TexLandColor3Sampler.SampleBias(SampLandColor3Sampler, uv, SharedData::MipBias); + # endif + + # if defined(TRUE_PBR) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2PBR) == 0) + { + landColor3 = float4(landColor3.rgb / Color::PBRLightingScale, landColor3.a); + } + else + { + landColor3.rgb = Color::Diffuse(landColor3.rgb); + } + # else + landColor3.rgb = Color::Diffuse(landColor3.rgb); + # endif + float landSnowMask3 = GetLandSnowMaskValue(landColor3.w); + + // Sample normal texture for layer 3 + # if defined(TERRAIN_VARIATION) + float4 landNormal3; + if (SharedData::terrainVariationSettings.enableTilingFix) { + landNormal3 = StochasticEffect(screenNoise, mipLevels[2], TexLandNormal3Sampler, SampLandNormal3Sampler, uv, sharedOffset, dx, dy); + } else { + landNormal3 = TexLandNormal3Sampler.SampleBias(SampLandNormal3Sampler, uv, SharedData::MipBias); + } + # else + float4 landNormal3 = TexLandNormal3Sampler.SampleBias(SampLandNormal3Sampler, uv, SharedData::MipBias); + # endif + + landNormal3.xyz = GetLandNormal(landSnowMask3, landNormal3.xyz, uv, SampLandNormal3Sampler, TexLandNormal3Sampler); + normal.xyz += input.LandBlendWeights1.zzz * landNormal3.xyz; + glossiness += input.LandBlendWeights1.z * landNormal3.w; + # if defined(SNOW) && !defined(TRUE_PBR) + landSnowMask += LandscapeTexture1to4IsSnow.z * input.LandBlendWeights1.z * landSnowMask3; + # endif // SNOW + + # if defined(TRUE_PBR) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2PBR) != 0) + { + // Sample RMAOS texture for layer 3 + # if defined(TERRAIN_VARIATION) + if (SharedData::terrainVariationSettings.enableTilingFix) { + rawRMAOS += input.LandBlendWeights1.z * StochasticEffect(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampLandRMAOS3Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); + } else { + rawRMAOS += input.LandBlendWeights1.z * TexLandRMAOS3Sampler.SampleBias(SampLandRMAOS3Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); + } + # else + rawRMAOS += input.LandBlendWeights1.z * TexLandRMAOS3Sampler.SampleBias(SampLandRMAOS3Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); + # endif + if ((PBRFlags & PBR::TerrainFlags::LandTile2HasGlint) != 0) { + glintParameters += input.LandBlendWeights1.z * LandscapeTexture3GlintParameters; + } + } + else + { + rawRMAOS += input.LandBlendWeights1.z * float4(1 - landNormal3.w, 0, 1, 0); + } + # endif + baseColor += input.LandBlendWeights1.zzzz * landColor3; + } // Layer 4 (LandBlendWeights1.w) + if (input.LandBlendWeights1.w > 0.0) { + // Sample layer 4 textures - use terrain variation if available and enabled + # if defined(TERRAIN_VARIATION) + float4 landColor4; + if (SharedData::terrainVariationSettings.enableTilingFix) { + landColor4 = StochasticEffect(screenNoise, mipLevels[3], TexLandColor4Sampler, SampLandColor4Sampler, uv, sharedOffset, dx, dy); + } else { + landColor4 = TexLandColor4Sampler.SampleBias(SampLandColor4Sampler, uv, SharedData::MipBias); + } + # else + float4 landColor4 = TexLandColor4Sampler.SampleBias(SampLandColor4Sampler, uv, SharedData::MipBias); + # endif + + # if defined(TRUE_PBR) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3PBR) == 0) + { + landColor4 = float4(landColor4.rgb / Color::PBRLightingScale, landColor4.a); + } + else + { + landColor4.rgb = Color::Diffuse(landColor4.rgb); + } + # else + landColor4.rgb = Color::Diffuse(landColor4.rgb); + # endif - // Layer 4 (LandBlendWeights1.w) - if (input.LandBlendWeights1.w > 0.01) { - float weight = input.LandBlendWeights1.w * invwsum; -# if defined(TERRAIN_VARIATION) - float4 diffuse4 = StochasticEffect(screenNoise, mipLevels[3], TexLandColor4Sampler, SampColorSampler, uv, sharedOffset, dx, dy); -# else - float distanceFactor = smoothstep(0.0, 2048.0, viewDistance); - float4 diffuse4 = lerp( - TexLandColor4Sampler.SampleBias(SampColorSampler, uv, SharedData::MipBias), - TexLandColor4Sampler.SampleLevel(SampColorSampler, uv, distanceFactor * 3.0), - distanceFactor); -# endif - float3 diffuseRGB4 = diffuse4.rgb; -# if defined(TRUE_PBR) - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3PBR) == 0) - { - diffuseRGB4 = diffuseRGB4 / Color::PBRLightingScale; - } -# endif - float alpha4 = diffuse4.a; - -# if defined(TERRAIN_VARIATION) - float4 normal4 = StochasticEffect(screenNoise, mipLevels[3], TexLandNormal4Sampler, SampNormalSampler, uv, sharedOffset, dx, dy); -# else - float4 normal4 = lerp( - TexLandNormal4Sampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), - TexLandNormal4Sampler.SampleLevel(SampNormalSampler, uv, distanceFactor * 3.0), - distanceFactor); -# endif - float3 normalRGB4 = normal4.rgb; - float normalAlpha4 = normal4.a; -# if defined(TRUE_PBR) -# if defined(TERRAIN_VARIATION) - float4 rmaos4 = StochasticEffect(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy); -# else - float4 rmaos4 = lerp( - TexLandRMAOS4Sampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), - TexLandRMAOS4Sampler.SampleLevel(SampRMAOSSampler, uv, distanceFactor * 3.0), - distanceFactor); -# endif - rmaos4 *= float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); - blendedRMAOS += rmaos4 * weight; -# endif - blendedRGB += diffuseRGB4 * weight; - blendedAlpha += alpha4 * weight; - blendedNormalRGB += normalRGB4 * weight; - blendedNormalAlpha += normalAlpha4 * weight; - } + float landSnowMask4 = GetLandSnowMaskValue(landColor4.w); + // Sample normal texture for layer 4 + # if defined(TERRAIN_VARIATION) + float4 landNormal4; + if (SharedData::terrainVariationSettings.enableTilingFix) { + landNormal4 = StochasticEffect(screenNoise, mipLevels[3], TexLandNormal4Sampler, SampLandNormal4Sampler, uv, sharedOffset, dx, dy); + } else { + landNormal4 = TexLandNormal4Sampler.SampleBias(SampLandNormal4Sampler, uv, SharedData::MipBias); + } + # else + float4 landNormal4 = TexLandNormal4Sampler.SampleBias(SampLandNormal4Sampler, uv, SharedData::MipBias); + # endif + + landNormal4.xyz = GetLandNormal(landSnowMask4, landNormal4.xyz, uv, SampLandNormal4Sampler, TexLandNormal4Sampler); + normal.xyz += input.LandBlendWeights1.www * landNormal4.xyz; + glossiness += input.LandBlendWeights1.w * landNormal4.w; + # if defined(SNOW) && !defined(TRUE_PBR) + landSnowMask += LandscapeTexture1to4IsSnow.w * input.LandBlendWeights1.w * landSnowMask4; + # endif // SNOW + + # if defined(TRUE_PBR) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3PBR) != 0) + { + // Sample RMAOS texture for layer 4 + # if defined(TERRAIN_VARIATION) + if (SharedData::terrainVariationSettings.enableTilingFix) { + rawRMAOS += input.LandBlendWeights1.w * StochasticEffect(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampLandRMAOS4Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); + } else { + rawRMAOS += input.LandBlendWeights1.w * TexLandRMAOS4Sampler.SampleBias(SampLandRMAOS4Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); + } + # else + rawRMAOS += input.LandBlendWeights1.w * TexLandRMAOS4Sampler.SampleBias(SampLandRMAOS4Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); + # endif + if ((PBRFlags & PBR::TerrainFlags::LandTile3HasGlint) != 0) { + glintParameters += input.LandBlendWeights1.w * LandscapeTexture4GlintParameters; + } + } + else + { + rawRMAOS += input.LandBlendWeights1.w * float4(1 - landNormal4.w, 0, 1, 0); + } + # endif + baseColor += input.LandBlendWeights1.wwww * landColor4; + } // Layer 5 (LandBlendWeights2.x) - if (input.LandBlendWeights2.x > 0.01) { - float weight = input.LandBlendWeights2.x * invwsum; -# if defined(TERRAIN_VARIATION) - float4 diffuse5 = StochasticEffect(screenNoise, mipLevels[4], TexLandColor5Sampler, SampColorSampler, uv, sharedOffset, dx, dy); -# else - float distanceFactor = smoothstep(0.0, 2048.0, viewDistance); - float4 diffuse5 = lerp( - TexLandColor5Sampler.SampleBias(SampColorSampler, uv, SharedData::MipBias), - TexLandColor5Sampler.SampleLevel(SampColorSampler, uv, distanceFactor * 3.0), - distanceFactor); -# endif - float3 diffuseRGB5 = diffuse5.rgb; -# if defined(TRUE_PBR) - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4PBR) == 0) - { - diffuseRGB5 = diffuseRGB5 / Color::PBRLightingScale; - } -# endif - float alpha5 = diffuse5.a; - -# if defined(TERRAIN_VARIATION) - float4 normal5 = StochasticEffect(screenNoise, mipLevels[4], TexLandNormal5Sampler, SampNormalSampler, uv, sharedOffset, dx, dy); -# else - float4 normal5 = lerp( - TexLandNormal5Sampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), - TexLandNormal5Sampler.SampleLevel(SampNormalSampler, uv, distanceFactor * 3.0), - distanceFactor); -# endif - float3 normalRGB5 = normal5.rgb; - float normalAlpha5 = normal5.a; -# if defined(TRUE_PBR) -# if defined(TERRAIN_VARIATION) - float4 rmaos5 = StochasticEffect(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy); -# else - float4 rmaos5 = lerp( - TexLandRMAOS5Sampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), - TexLandRMAOS5Sampler.SampleLevel(SampRMAOSSampler, uv, distanceFactor * 3.0), - distanceFactor); -# endif - rmaos5 *= float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); - blendedRMAOS += rmaos5 * weight; -# endif - blendedRGB += diffuseRGB5 * weight; - blendedAlpha += alpha5 * weight; - blendedNormalRGB += normalRGB5 * weight; - blendedNormalAlpha += normalAlpha5 * weight; - } - + if (input.LandBlendWeights2.x > 0.0) { + // Sample layer 5 textures - use terrain variation if available and enabled + # if defined(TERRAIN_VARIATION) + float4 landColor5; + if (SharedData::terrainVariationSettings.enableTilingFix) { + landColor5 = StochasticEffect(screenNoise, mipLevels[4], TexLandColor5Sampler, SampLandColor5Sampler, uv, sharedOffset, dx, dy); + } else { + landColor5 = TexLandColor5Sampler.SampleBias(SampLandColor5Sampler, uv, SharedData::MipBias); + } + # else + float4 landColor5 = TexLandColor5Sampler.SampleBias(SampLandColor5Sampler, uv, SharedData::MipBias); + # endif + + # if defined(TRUE_PBR) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4PBR) == 0) + { + landColor5 = float4(landColor5.rgb / Color::PBRLightingScale, landColor5.a); + } + else + { + landColor5.rgb = Color::Diffuse(landColor5.rgb); + } + # else + landColor5.rgb = Color::Diffuse(landColor5.rgb); + # endif + float landSnowMask5 = GetLandSnowMaskValue(landColor5.w); + + // Sample normal texture for layer 5 + # if defined(TERRAIN_VARIATION) + float4 landNormal5; + if (SharedData::terrainVariationSettings.enableTilingFix) { + landNormal5 = StochasticEffect(screenNoise, mipLevels[4], TexLandNormal5Sampler, SampLandNormal5Sampler, uv, sharedOffset, dx, dy); + } else { + landNormal5 = TexLandNormal5Sampler.SampleBias(SampLandNormal5Sampler, uv, SharedData::MipBias); + } + # else + float4 landNormal5 = TexLandNormal5Sampler.SampleBias(SampLandNormal5Sampler, uv, SharedData::MipBias); + # endif + + landNormal5.xyz = GetLandNormal(landSnowMask5, landNormal5.xyz, uv, SampLandNormal5Sampler, TexLandNormal5Sampler); + normal.xyz += input.LandBlendWeights2.xxx * landNormal5.xyz; + glossiness += input.LandBlendWeights2.x * landNormal5.w; + # if defined(SNOW) && !defined(TRUE_PBR) + landSnowMask += LandscapeTexture5to6IsSnow.x * input.LandBlendWeights2.x * landSnowMask5; + # endif // SNOW + + # if defined(TRUE_PBR) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4PBR) != 0) + { + // Sample RMAOS texture for layer 5 + # if defined(TERRAIN_VARIATION) + if (SharedData::terrainVariationSettings.enableTilingFix) { + rawRMAOS += input.LandBlendWeights2.x * StochasticEffect(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampLandRMAOS5Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); + } else { + rawRMAOS += input.LandBlendWeights2.x * TexLandRMAOS5Sampler.SampleBias(SampLandRMAOS5Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); + } + # else + rawRMAOS += input.LandBlendWeights2.x * TexLandRMAOS5Sampler.SampleBias(SampLandRMAOS5Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); + # endif + if ((PBRFlags & PBR::TerrainFlags::LandTile4HasGlint) != 0) { + glintParameters += input.LandBlendWeights2.x * LandscapeTexture5GlintParameters; + } + } + else + { + rawRMAOS += input.LandBlendWeights2.x * float4(1 - landNormal5.w, 0, 1, 0); + } + # endif + baseColor += input.LandBlendWeights2.xxxx * landColor5; + } // Layer 6 (LandBlendWeights2.y) - if (input.LandBlendWeights2.y > 0.01) { - float weight = input.LandBlendWeights2.y * invwsum; -# if defined(TERRAIN_VARIATION) - float4 diffuse6 = StochasticEffect(screenNoise, mipLevels[5], TexLandColor6Sampler, SampColorSampler, uv, sharedOffset, dx, dy); -# else - float distanceFactor = smoothstep(0.0, 2048.0, viewDistance); - float4 diffuse6 = lerp( - TexLandColor6Sampler.SampleBias(SampColorSampler, uv, SharedData::MipBias), - TexLandColor6Sampler.SampleLevel(SampColorSampler, uv, distanceFactor * 3.0), - distanceFactor); -# endif - float3 diffuseRGB6 = diffuse6.rgb; -# if defined(TRUE_PBR) - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5PBR) == 0) - { - diffuseRGB6 = diffuseRGB6 / Color::PBRLightingScale; - } -# endif - float alpha6 = diffuse6.a; - -# if defined(TERRAIN_VARIATION) - float4 normal6 = StochasticEffect(screenNoise, mipLevels[5], TexLandNormal6Sampler, SampNormalSampler, uv, sharedOffset, dx, dy); -# else - float4 normal6 = lerp( - TexLandNormal6Sampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), - TexLandNormal6Sampler.SampleLevel(SampNormalSampler, uv, distanceFactor * 3.0), - distanceFactor); -# endif - float3 normalRGB6 = normal6.rgb; - float normalAlpha6 = normal6.a; -# if defined(TRUE_PBR) -# if defined(TERRAIN_VARIATION) - float4 rmaos6 = StochasticEffect(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy); -# else - float4 rmaos6 = lerp( - TexLandRMAOS6Sampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), - TexLandRMAOS6Sampler.SampleLevel(SampRMAOSSampler, uv, distanceFactor * 3.0), - distanceFactor); -# endif - rmaos6 *= float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); - blendedRMAOS += rmaos6 * weight; -# endif - blendedRGB += diffuseRGB6 * weight; - blendedAlpha += alpha6 * weight; - blendedNormalRGB += normalRGB6 * weight; - blendedNormalAlpha += normalAlpha6 * weight; - } - - float4 rawBaseColor = float4(blendedRGB, blendedAlpha); - baseColor = float4(Color::Diffuse(blendedRGB), blendedAlpha); - normal = float4(blendedNormalRGB, blendedNormalAlpha); -# if defined(TRUE_PBR) - rawRMAOS = blendedRMAOS; -# endif + if (input.LandBlendWeights2.y > 0.0) { + // Sample layer 6 textures - use terrain variation if available and enabled + # if defined(TERRAIN_VARIATION) + float4 landColor6; + if (SharedData::terrainVariationSettings.enableTilingFix) { + landColor6 = StochasticEffect(screenNoise, mipLevels[5], TexLandColor6Sampler, SampLandColor6Sampler, uv, sharedOffset, dx, dy); + } else { + landColor6 = TexLandColor6Sampler.SampleBias(SampLandColor6Sampler, uv, SharedData::MipBias); + } + # else + float4 landColor6 = TexLandColor6Sampler.SampleBias(SampLandColor6Sampler, uv, SharedData::MipBias); + # endif + + # if defined(TRUE_PBR) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5PBR) == 0) + { + landColor6 = float4(landColor6.rgb / Color::PBRLightingScale, landColor6.a); + } + else + { + landColor6.rgb = Color::Diffuse(landColor6.rgb); + } + # else + landColor6.rgb = Color::Diffuse(landColor6.rgb); + # endif + float landSnowMask6 = GetLandSnowMaskValue(landColor6.w); + + // Sample normal texture for layer 6 + # if defined(TERRAIN_VARIATION) + float4 landNormal6; + if (SharedData::terrainVariationSettings.enableTilingFix) { + landNormal6 = StochasticEffect(screenNoise, mipLevels[5], TexLandNormal6Sampler, SampLandNormal6Sampler, uv, sharedOffset, dx, dy); + } else { + landNormal6 = TexLandNormal6Sampler.SampleBias(SampLandNormal6Sampler, uv, SharedData::MipBias); + } + # else + float4 landNormal6 = TexLandNormal6Sampler.SampleBias(SampLandNormal6Sampler, uv, SharedData::MipBias); + # endif + + landNormal6.xyz = GetLandNormal(landSnowMask6, landNormal6.xyz, uv, SampLandNormal6Sampler, TexLandNormal6Sampler); + normal.xyz += input.LandBlendWeights2.yyy * landNormal6.xyz; + glossiness += input.LandBlendWeights2.y * landNormal6.w; + # if defined(SNOW) && !defined(TRUE_PBR) + landSnowMask += LandscapeTexture5to6IsSnow.y * input.LandBlendWeights2.y * landSnowMask6; + # endif // SNOW + + # if defined(TRUE_PBR) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5PBR) != 0) + { + // Sample RMAOS texture for layer 6 + # if defined(TERRAIN_VARIATION) + if (SharedData::terrainVariationSettings.enableTilingFix) { + rawRMAOS += input.LandBlendWeights2.y * StochasticEffect(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampLandRMAOS6Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); + } else { + rawRMAOS += input.LandBlendWeights2.y * TexLandRMAOS6Sampler.SampleBias(SampLandRMAOS6Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); + } + # else + rawRMAOS += input.LandBlendWeights2.y * TexLandRMAOS6Sampler.SampleBias(SampLandRMAOS6Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); + # endif + if ((PBRFlags & PBR::TerrainFlags::LandTile5HasGlint) != 0) { + glintParameters += input.LandBlendWeights2.y * LandscapeTexture6GlintParameters; + } + } + else + { + rawRMAOS += input.LandBlendWeights2.y * float4(1 - landNormal6.w, 0, 1, 0); + } + # endif + baseColor += input.LandBlendWeights2.yyyy * landColor6; + } + // Set rawBaseColor for later processing + float4 rawBaseColor = baseColor; # else - // Non-landscape code + // Non-landscape code float4 rawBaseColor = TexColorSampler.SampleBias(SampColorSampler, diffuseUv, SharedData::MipBias); baseColor = float4(Color::Diffuse(rawBaseColor.rgb), rawBaseColor.a); float4 normalColor = TexNormalSampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias); normal = normalColor; -# if defined(TRUE_PBR) - rawRMAOS = TexRMAOSSampler.SampleBias(SampRMAOSSampler, diffuseUv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); +# if defined(TRUE_PBR) +# if defined(LODLANDNOISE) + rawRMAOS = float4(1, 0, 1, 0); +# elif defined(LANDSCAPE) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0PBR) != 0) + { + rawRMAOS = input.LandBlendWeights1.x * TexRMAOSSampler.SampleBias(SampRMAOSSampler, diffuseUv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + if ((PBRFlags & PBR::TerrainFlags::LandTile0HasGlint) != 0) { + glintParameters += input.LandBlendWeights1.x * LandscapeTexture1GlintParameters; + } + } + else + { + rawRMAOS = input.LandBlendWeights1.x * float4(1 - glossiness.x, 0, 1, 0); + } +# else + rawRMAOS = TexRMAOSSampler.SampleBias(SampRMAOSSampler, diffuseUv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + if ((PBRFlags & PBR::Flags::Glint) != 0) { + glintParameters = MultiLayerParallaxData; + } # endif # endif - -# if defined(TRUE_PBR) && defined(LANDSCAPE) - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0PBR) == 0) - { - baseColor = float4(rawBaseColor.rgb / Color::PBRLightingScale, rawBaseColor.a); - } # endif # if defined(LOD_BLENDING) @@ -1687,7 +1820,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif # endif // LOD_BLENDING - float landSnowMask1 = GetLandSnowMaskValue(baseColor.w); + //float landSnowMask1 = GetLandSnowMaskValue(baseColor.w); # if defined(MODELSPACENORMALS) # if defined(LODLANDNOISE) @@ -1721,93 +1854,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif // WORLD_MAP # if defined(LANDSCAPE) -# if defined(SNOW) && !defined(TRUE_PBR) - landSnowMask = LandscapeTexture1to4IsSnow.x * input.LandBlendWeights1.x; -# endif // SNOW - - // Layer 1 (LandBlendWeights1.x) - if (input.LandBlendWeights1.x > 0.01) { -# if defined(SNOW) && !defined(TRUE_PBR) - float landSnowMask1 = GetLandSnowMaskValue(baseColor.w); - landSnowMask += LandscapeTexture1to4IsSnow.x * input.LandBlendWeights1.x * landSnowMask1; -# endif -# if defined(TRUE_PBR) - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasGlint) != 0) - { - glintParameters += input.LandBlendWeights1.x * LandscapeTexture1GlintParameters; - } -# endif - } - - // Layer 2 (LandBlendWeights1.y) - if (input.LandBlendWeights1.y > 0.01) { -# if defined(SNOW) && !defined(TRUE_PBR) - float landSnowMask2 = GetLandSnowMaskValue(baseColor.w); - landSnowMask += LandscapeTexture1to4IsSnow.y * input.LandBlendWeights1.y * landSnowMask2; -# endif -# if defined(TRUE_PBR) - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1HasGlint) != 0) - { - glintParameters += input.LandBlendWeights1.y * LandscapeTexture2GlintParameters; - } -# endif - } - - // Layer 3 (LandBlendWeights1.z) - if (input.LandBlendWeights1.z > 0.01) { -# if defined(SNOW) && !defined(TRUE_PBR) - float landSnowMask3 = GetLandSnowMaskValue(baseColor.w); - landSnowMask += LandscapeTexture1to4IsSnow.z * input.LandBlendWeights1.z * landSnowMask3; -# endif -# if defined(TRUE_PBR) - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2HasGlint) != 0) - { - glintParameters += input.LandBlendWeights1.z * LandscapeTexture3GlintParameters; - } -# endif - } - - // Layer 4 (LandBlendWeights1.w) - if (input.LandBlendWeights1.w > 0.01) { -# if defined(SNOW) && !defined(TRUE_PBR) - float landSnowMask4 = GetLandSnowMaskValue(baseColor.w); - landSnowMask += LandscapeTexture1to4IsSnow.w * input.LandBlendWeights1.w * landSnowMask4; -# endif -# if defined(TRUE_PBR) - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasGlint) != 0) - { - glintParameters += input.LandBlendWeights1.w * LandscapeTexture4GlintParameters; - } -# endif - } - - // Layer 5 (LandBlendWeights2.x) - if (input.LandBlendWeights2.x > 0.01) { -# if defined(SNOW) && !defined(TRUE_PBR) - float landSnowMask5 = GetLandSnowMaskValue(baseColor.w); - landSnowMask += LandscapeTexture5to6IsSnow.x * input.LandBlendWeights2.x * landSnowMask5; -# endif -# if defined(TRUE_PBR) - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasGlint) != 0) - { - glintParameters += input.LandBlendWeights2.x * LandscapeTexture5GlintParameters; - } -# endif - } - - // Layer 6 (LandBlendWeights2.y) - if (input.LandBlendWeights2.y > 0.01) { -# if defined(SNOW) && !defined(TRUE_PBR) - float landSnowMask6 = GetLandSnowMaskValue(baseColor.w); - landSnowMask += LandscapeTexture5to6IsSnow.y * input.LandBlendWeights2.y * landSnowMask6; -# endif -# if defined(TRUE_PBR) - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasGlint) != 0) - { - glintParameters += input.LandBlendWeights2.y * LandscapeTexture6GlintParameters; - } -# endif - } + float landSnowMask1 = GetLandSnowMaskValue(baseColor.w); # endif // LANDSCAPE # if defined(EMAT_ENVMAP) @@ -2262,33 +2309,40 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif # if defined(EMAT) && (defined(SKINNED) || !defined(MODELSPACENORMALS)) - [branch] if (inWorld && SharedData::extendedMaterialSettings.EnableShadows) - { - float3 dirLightDirectionTS = mul(refractedDirLightDirection, tbn).xyz; + [branch] if (inWorld && SharedData::extendedMaterialSettings.EnableShadows) + { + float3 dirLightDirectionTS = mul(refractedDirLightDirection, tbn).xyz; # if defined(LANDSCAPE) - [branch] if (SharedData::extendedMaterialSettings.EnableTerrainParallax) - { + [branch] if (SharedData::extendedMaterialSettings.EnableTerrainParallax) + { # if defined(TERRAIN_VARIATION) - float weights[6]; - sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); + if (SharedData::terrainVariationSettings.enableTilingFix) { + float weights[6]; + sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); + + parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dx, dy); + } else { + float weights[6]; + sh0 = ExtendedMaterials::GetTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); - parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dx, dy); + parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams); + } # else - // Standard terrain parallax shadow without stochastic sampling - parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams); + // Standard terrain parallax shadow without stochastic sampling + parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams); # endif - } + } # elif defined(PARALLAX) - [branch] if (SharedData::extendedMaterialSettings.EnableParallax) - parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplier(uv, mipLevel, dirLightDirectionTS, sh0, TexParallaxSampler, SampParallaxSampler, 0, lerp(parallaxShadowQuality, 1.0, SharedData::extendedMaterialSettings.ExtendShadows), screenNoise, displacementParams); + [branch] if (SharedData::extendedMaterialSettings.EnableParallax) + parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplier(uv, mipLevel, dirLightDirectionTS, sh0, TexParallaxSampler, SampParallaxSampler, 0, lerp(parallaxShadowQuality, 1.0, SharedData::extendedMaterialSettings.ExtendShadows), screenNoise, displacementParams); # elif defined(EMAT_ENVMAP) - [branch] if (complexMaterialParallax) - parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplier(uv, mipLevel, dirLightDirectionTS, sh0, TexEnvMaskSampler, SampEnvMaskSampler, 3, lerp(parallaxShadowQuality, 1.0, SharedData::extendedMaterialSettings.ExtendShadows), screenNoise, displacementParams); + [branch] if (complexMaterialParallax) + parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplier(uv, mipLevel, dirLightDirectionTS, sh0, TexEnvMaskSampler, SampEnvMaskSampler, 3, lerp(parallaxShadowQuality, 1.0, SharedData::extendedMaterialSettings.ExtendShadows), screenNoise, displacementParams); # elif defined(TRUE_PBR) && !defined(LODLANDSCAPE) - [branch] if (PBRParallax) - parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplier(uv, mipLevel, dirLightDirectionTS, sh0, TexParallaxSampler, SampParallaxSampler, 0, lerp(parallaxShadowQuality, 1.0, SharedData::extendedMaterialSettings.ExtendShadows), screenNoise, displacementParams); + [branch] if (PBRParallax) + parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplier(uv, mipLevel, dirLightDirectionTS, sh0, TexParallaxSampler, SampParallaxSampler, 0, lerp(parallaxShadowQuality, 1.0, SharedData::extendedMaterialSettings.ExtendShadows), screenNoise, displacementParams); # endif // LANDSCAPE - } + } # endif // defined(EMAT) && (defined(SKINNED) || !defined(MODELSPACENORMALS)) if (dirShadow != 0.0 && (inWorld || inReflection)) From ac43f4d767e7aa015779f84152b25ffeab010e7d Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Wed, 28 May 2025 13:36:54 +1000 Subject: [PATCH 06/53] update 3 --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 372 ++++++++++++------ .../TerrainVariation/TerrainVariation.hlsli | 111 +++--- package/Shaders/Lighting.hlsl | 335 ++++++++-------- 3 files changed, 464 insertions(+), 354 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index d6545b528d..1241fea105 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -6,7 +6,10 @@ // https://bartwronski.files.wordpress.com/2014/03/ac4_gdc.pdf #if defined(LANDSCAPE) && defined(TERRAIN_VARIATION) -# include "TerrainVariation/TerrainVariation.hlsli" +# define USE_TERRAIN_VARIATION 1 +# include "TerrainVariation/TerrainVariation.hlsli" +#else +# define USE_TERRAIN_VARIATION 0 #endif struct DisplacementParams @@ -91,68 +94,90 @@ namespace ExtendedMaterials weights[3] = w1.w; weights[4] = w2.x; weights[5] = w2.y; - float total = 0; - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.0) - { + float total = 0; + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.0) { + float h; # if defined(TERRAIN_VARIATION) - float h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[0], TexLandDisplacement0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexLandDisplacement0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); + } else { + h = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); + } # else - float h = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); + h = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); # endif total += h * weights[0]; weights[0] *= pow(heightBlend, HEIGHT_MULT * h); - } - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1HasDisplacement) != 0 && w1.y > 0.0) - { + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1HasDisplacement) != 0 && w1.y > 0.0) { + float h; # if defined(TERRAIN_VARIATION) - float h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[1], TexLandDisplacement1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); - + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandDisplacement1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); + } else { + h = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); + } # else - float h = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); + h = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); # endif total += h * weights[1]; weights[1] *= pow(heightBlend, HEIGHT_MULT * h); - } - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2HasDisplacement) != 0 && w1.z > 0.0) - { + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2HasDisplacement) != 0 && w1.z > 0.0) { + float h; # if defined(TERRAIN_VARIATION) - float h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[2], TexLandDisplacement2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); - + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandDisplacement2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); + } else { + h = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); + } # else - float h = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); + h = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); # endif total += h * weights[2]; weights[2] *= pow(heightBlend, HEIGHT_MULT * h); - } + } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) { + float h; # if defined(TERRAIN_VARIATION) - float h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); - + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); + } else { + h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); + } # else - float h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); + h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); # endif total += h * weights[3]; weights[3] *= pow(heightBlend, HEIGHT_MULT * h); - } + } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) { + float h; # if defined(TERRAIN_VARIATION) - float h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); - + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); + } else { + h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); + } # else - float h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); + h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); # endif total += h * weights[4]; weights[4] *= pow(heightBlend, HEIGHT_MULT * h); - } + } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) { + float h; # if defined(TERRAIN_VARIATION) - float h = ScaleDisplacement(StochasticEffect(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); - + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); + } else { + h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); + } # else - float h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); + h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); # endif total += h * weights[5]; weights[5] *= pow(heightBlend, HEIGHT_MULT * h); @@ -188,18 +213,33 @@ namespace ExtendedMaterials weights[2] = w1.z; weights[3] = w1.w; weights[4] = w2.x; - weights[5] = w2.y; - float total = 0; + weights[5] = w2.y; float total = 0; if (w1.x > 0.0) { float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand0HasDisplacement) != 0) { +# if defined(TERRAIN_VARIATION) + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexLandTHDisp0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); + } else { + h = ScaleDisplacement(TexLandTHDisp0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); + } +# else h = ScaleDisplacement(TexLandTHDisp0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); +# endif } else { +# if defined(TERRAIN_VARIATION) + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexColorSampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[0]); + } else { + h = ScaleDisplacement(TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, params[0]); + } +# else h = ScaleDisplacement(TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, params[0]); +# endif } total += h * weights[0]; weights[0] *= pow(heightBlend, HEIGHT_MULT * h); @@ -208,11 +248,27 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) { +# if defined(TERRAIN_VARIATION) + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandTHDisp1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); + } else { + h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); + } +# else h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); +# endif } else { +# if defined(TERRAIN_VARIATION) + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandColor2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[1]); + } else { + h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); + } +# else h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); +# endif } total += h * weights[1]; weights[1] *= pow(heightBlend, HEIGHT_MULT * h); @@ -221,51 +277,70 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) { +# if defined(TERRAIN_VARIATION) + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandTHDisp2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); + } else { + h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); + } +# else h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); +# endif } else { +# if defined(TERRAIN_VARIATION) + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandColor3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[2]); + } else { + h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); + } +# else h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); +# endif } total += h * weights[2]; weights[2] *= pow(heightBlend, HEIGHT_MULT * h); - } - if (w1.w > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0) - { - h = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); - } - else - { - h = ScaleDisplacement(TexLandColor4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).w, params[3]); + } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) + { + float h; +# if defined(TERRAIN_VARIATION) + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); + } else { + h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); } +# else + h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); +# endif total += h * weights[3]; weights[3] *= pow(heightBlend, HEIGHT_MULT * h); - } - if (w2.x > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0) - { - h = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); - } - else - { - h = ScaleDisplacement(TexLandColor5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).w, params[4]); + } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) + { + float h; +# if defined(TERRAIN_VARIATION) + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); + } else { + h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); } +# else + h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); +# endif total += h * weights[4]; weights[4] *= pow(heightBlend, HEIGHT_MULT * h); - } - if (w2.y > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0) - { - h = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); - } - else - { - h = ScaleDisplacement(TexLandColor6Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).w, params[5]); + } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) + { + float h; +# if defined(TERRAIN_VARIATION) + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); + } else { + h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); } +# else + h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); +# endif total += h * weights[5]; weights[5] *= pow(heightBlend, HEIGHT_MULT * h); } @@ -332,7 +407,7 @@ namespace ExtendedMaterials if (nearBlendToFar < 1.0) { uint numSteps = uint((max(6, scale * 8) * (1.0 - nearBlendToFar)) + 0.5); numSteps = clamp((numSteps + 3) & ~0x03, 4, max(8, scale * 8)); -#else +# else # if defined(TRUE_PBR) if ((PBRFlags & PBR::Flags::InterlayerParallax) != 0 || nearBlendToFar < 1.0) # else @@ -515,6 +590,13 @@ namespace ExtendedMaterials # endif { if (quality > 0.0) { +# if defined(TERRAIN_VARIATION) + // Reduce shadow quality when terrain variation is enabled to improve performance + // The stochastic sampling cost for shadows is high, so we scale back quality + float effectiveQuality = quality * 0.5; +# else + float effectiveQuality = quality; +# endif float4 multipliers = rcp((float4(1, 2, 3, 4) + noise)); float4 sh; float heights[6] = { 0, 0, 0, 0, 0, 0 }; @@ -528,42 +610,42 @@ namespace ExtendedMaterials rayDir *= scale; # if defined(TERRAIN_VARIATION) - sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); - if (quality > 0.25) - sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); - if (quality > 0.5) - sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); - if (quality > 0.75) - sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + if (effectiveQuality > 0.25) + sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + if (effectiveQuality > 0.5) + sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + if (effectiveQuality > 0.75) + sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); # else - sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); - if (quality > 0.25) - sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); - if (quality > 0.5) - sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); - if (quality > 0.75) - sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (effectiveQuality > 0.25) + sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (effectiveQuality > 0.5) + sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (effectiveQuality > 0.75) + sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); # endif - return pow(1.0 - saturate(dot(max(0, sh - sh0) / scale, 1.0)) * quality, 2.0); + return pow(1.0 - saturate(dot(max(0, sh - sh0) / scale, 1.0)) * effectiveQuality, 2.0); # else # if defined(TERRAIN_VARIATION) - sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); - if (quality > 0.25) - sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); - if (quality > 0.5) - sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); - if (quality > 0.75) - sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + if (effectiveQuality > 0.25) + sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + if (effectiveQuality > 0.5) + sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + if (effectiveQuality > 0.75) + sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); # else - sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); - if (quality > 0.25) - sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); - if (quality > 0.5) - sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); - if (quality > 0.75) - sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (effectiveQuality > 0.25) + sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (effectiveQuality > 0.5) + sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (effectiveQuality > 0.75) + sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); # endif - return pow(1.0 - saturate(dot(max(0, sh - sh0), 1.0)) * quality, 2.0); + return pow(1.0 - saturate(dot(max(0, sh - sh0), 1.0)) * effectiveQuality, 2.0); # endif } return 1.0; @@ -667,11 +749,27 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) { +# if defined(TERRAIN_VARIATION) + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandTHDisp1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); + } else { + h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); + } +# else h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); +# endif } else { +# if defined(TERRAIN_VARIATION) + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandColor2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[1]); + } else { + h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); + } +# else h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); +# endif } total += h * weights[1]; weights[1] *= pow(heightBlend, HEIGHT_MULT * h); @@ -680,51 +778,72 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) { +# if defined(TERRAIN_VARIATION) + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandTHDisp2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); + } else { + h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); + } +# else h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); +# endif } else { +# if defined(TERRAIN_VARIATION) + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandColor3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[2]); + } else { + h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); + } +# else h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); +# endif } total += h * weights[2]; weights[2] *= pow(heightBlend, HEIGHT_MULT * h); - } - if (w1.w > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0) - { - h = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); - } - else - { - h = ScaleDisplacement(TexLandColor4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).w, params[3]); + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) + { + float h; +# if defined(TERRAIN_VARIATION) + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); + } else { + h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); } +# else + h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); +# endif total += h * weights[3]; weights[3] *= pow(heightBlend, HEIGHT_MULT * h); - } - if (w2.x > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0) - { - h = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); - } - else - { - h = ScaleDisplacement(TexLandColor5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).w, params[4]); + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) + { + float h; +# if defined(TERRAIN_VARIATION) + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); + } else { + h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); } +# else + h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); +# endif total += h * weights[4]; weights[4] *= pow(heightBlend, HEIGHT_MULT * h); - } - if (w2.y > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0) - { - h = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); - } - else - { - h = ScaleDisplacement(TexLandColor6Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).w, params[5]); + } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) + { + float h; +# if defined(TERRAIN_VARIATION) + [branch] if (USE_TERRAIN_VARIATION) { + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); + } else { + h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); } +# else + h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); +# endif total += h * weights[5]; weights[5] *= pow(heightBlend, HEIGHT_MULT * h); } @@ -901,7 +1020,7 @@ namespace ExtendedMaterials # if defined(TRUE_PBR) float scale = max(params[0].HeightScale * input.LandBlendWeights1.x, max(params[1].HeightScale * input.LandBlendWeights1.y, max(params[2].HeightScale * input.LandBlendWeights1.z, - max(params[3].HeightScale * input.LandBlendWeights1.w, max(params[4].HeightScale * input.LandBlendWeights2.x, params[5].HeightScale * input.LandBlendWeights2.y))))); + max(params[3].HeightScale * input.LandBlendWeights1.w, max(params[4].HeightScale * input.LandBlendWeights2.x, params[5].HeightScale * input.LandBlendWeights2.y))))); if (scale < 0.01) return 1.0; rayDir *= scale; @@ -912,7 +1031,7 @@ namespace ExtendedMaterials if (quality > 0.5) sh.z = GetTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.75) - sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); return pow(1.0 - saturate(dot(max(0, sh - sh0) / scale, 1.0)) * quality, 2.0); # else sh = GetTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); @@ -927,6 +1046,5 @@ namespace ExtendedMaterials } return 1.0; } - #endif // defined(LANDSCAPE) && defined(TERRAIN_VARIATION) -} \ No newline at end of file +} diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index 6f380478dd..7709430f88 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -29,6 +29,21 @@ inline float2 hash2D2D(float2 s) return frac(sin(s.x + s.y) * float2(43758.5453, 28637.1369)); } +// Compute single offset for stochastic sampling (optimized for single sample) +inline float2 ComputeStochasticOffsets1(float2 UV) +{ + float2 skewUV = mul(float2x2(1.0, 0.0, -0.57735027, 1.15470054), UV * 3.464); + float2 vxID = floor(skewUV); + float3 barry = float3(frac(skewUV), 0.0); + barry.z = 1.0 - barry.x - barry.y; + + // Only compute the first vertex ID based on barycentric coordinates + float2 firstVertexID = (barry.z > 0) ? vxID : (vxID + float2(1, 1)); + + // Return only the first hash offset + return hash2D2D(firstVertexID); +} + // Compute offsets for stochastic sampling inline StochasticOffsets ComputeStochasticOffsets(float2 UV) { @@ -57,70 +72,60 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler return tex.SampleBias(samp, uv, SharedData::MipBias); } - // First determine the weights based only on the offset weights (without height influence) - float3 blendWeights = offsets.weights; - - // Apply contrast and saturation to the initial blend weights - blendWeights = pow(saturate(blendWeights), HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE)); + // Apply contrast to the initial blend weights (without height influence) + float3 blendWeights = pow(saturate(offsets.weights), HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE)); // Renormalize the weights float totalWeight = blendWeights.x + blendWeights.y + blendWeights.z; blendWeights = (totalWeight > 0.0) ? blendWeights / totalWeight : float3(0.33, 0.33, 0.34); - // Storage for samples and accumulated results - float4 stochasticSample = float4(0, 0, 0, 0); - float culledWeightSum = 0.0; - float4 sample; + // Sample all three locations + float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); + float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); - // Only sample textures when their weight exceeds the culling threshold - // This avoids fetching textures that would be discarded anyway - [branch] if (blendWeights.x > CULLING_THRESHOLD) { - sample = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); - - // Adjust weight based on height if needed - float height = sample.a > 0 ? sample.a : dot(sample.rgb, float3(0.2126, 0.7152, 0.0722)); - float weight = lerp(blendWeights.x, height * blendWeights.x, HEIGHT_INFLUENCE); - - stochasticSample += sample * weight; - culledWeightSum += weight; - } + // Apply height-based weight adjustments + float height1 = sample1.a > 0 ? sample1.a : dot(sample1.rgb, float3(0.2126, 0.7152, 0.0722)); + float height2 = sample2.a > 0 ? sample2.a : dot(sample2.rgb, float3(0.2126, 0.7152, 0.0722)); + float height3 = sample3.a > 0 ? sample3.a : dot(sample3.rgb, float3(0.2126, 0.7152, 0.0722)); - [branch] if (blendWeights.y > CULLING_THRESHOLD) { - sample = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); - - // Adjust weight based on height if needed - float height = sample.a > 0 ? sample.a : dot(sample.rgb, float3(0.2126, 0.7152, 0.0722)); - float weight = lerp(blendWeights.y, height * blendWeights.y, HEIGHT_INFLUENCE); - - stochasticSample += sample * weight; - culledWeightSum += weight; - } + float weight1 = lerp(blendWeights.x, height1 * blendWeights.x, HEIGHT_INFLUENCE); + float weight2 = lerp(blendWeights.y, height2 * blendWeights.y, HEIGHT_INFLUENCE); + float weight3 = lerp(blendWeights.z, height3 * blendWeights.z, HEIGHT_INFLUENCE); - [branch] if (blendWeights.z > CULLING_THRESHOLD) { - sample = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); - - // Adjust weight based on height if needed - float height = sample.a > 0 ? sample.a : dot(sample.rgb, float3(0.2126, 0.7152, 0.0722)); - float weight = lerp(blendWeights.z, height * blendWeights.z, HEIGHT_INFLUENCE); - - stochasticSample += sample * weight; - culledWeightSum += weight; - } + // Blend samples with height-adjusted weights + float4 result = sample1 * weight1 + sample2 * weight2 + sample3 * weight3; - // Renormalize after culling - if (culledWeightSum > 0.0) { - stochasticSample /= culledWeightSum; - } else { - // If all samples were culled, get a single sample as fallback - stochasticSample = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); // Fallback + // Renormalize final result + float finalWeightSum = weight1 + weight2 + weight3; + if (finalWeightSum > 0.0) { + result /= finalWeightSum; } - return stochasticSample; + + return result; +} + +inline float4 StochasticSample1(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) +{ + // Use the first offset from the provided offsets struct + // This maintains compatibility while still allowing the calling code to choose + // between ComputeStochasticOffsets() for full offsets or the optimized version + return tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); } -// Runtime macro that checks enableTilingFix and falls back to regular sampling when disabled -#define StochasticSample(rnd, mipLevel, tex, samp, uv) \ - (SharedData::terrainVariationSettings.enableTilingFix ? \ - StochasticEffect(rnd, mipLevel, tex, samp, uv, ComputeStochasticOffsets(uv), ddx(uv), ddy(uv)).rgb : \ - tex.SampleLevel(samp, uv, mipLevel).rgb) +inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) +{ + // Sample the three texture offsets using the provided mip level + float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); + float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); + + // Blend using the barycentric weights + float4 result = sample1 * offsets.weights.x + + sample2 * offsets.weights.y + + sample3 * offsets.weights.z; + + return result; +} #endif // TERRAIN_VARIATION_HLSLI \ No newline at end of file diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 9fb704f02a..41b8786031 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1258,8 +1258,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace diffuseUv = ProjectedUVParams2.yy * input.TexCoord0.zw; # endif // SPARKLE -# if defined(LANDSCAPE) - // Normalize blend weights +# if defined(LANDSCAPE) // Normalize blend weights float totalWeight = input.LandBlendWeights1.x + input.LandBlendWeights1.y + input.LandBlendWeights1.z + input.LandBlendWeights1.w + input.LandBlendWeights2.x + input.LandBlendWeights2.y; if (totalWeight > 0.0) { @@ -1267,11 +1266,21 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace input.LandBlendWeights2.xy /= totalWeight; } + float3 blendedRGB = 0; + float blendedAlpha = 0; + float3 blendedNormalRGB = 0; + float blendedNormalAlpha = 0; + +# if defined(TRUE_PBR) + float4 blendedRMAOS = 0; +# endif + float invwsum = 1.0; // Weights are already normalized above, so invwsum should be 1.0 // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) # if defined(TERRAIN_VARIATION) + bool useTerrainVariation = SharedData::terrainVariationSettings.enableTilingFix; float2 dx, dy; StochasticOffsets sharedOffset; - if (SharedData::terrainVariationSettings.enableTilingFix) { + [branch] if (useTerrainVariation) { dx = ddx(uv); dy = ddy(uv); sharedOffset = ComputeStochasticOffsets(uv); @@ -1302,7 +1311,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif float weights[6]; # if defined(TERRAIN_VARIATION) - if (SharedData::terrainVariationSettings.enableTilingFix) { + [branch] if (useTerrainVariation) { uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, sharedOffset, dx, dy, pixelOffset, weights); } else { uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, pixelOffset, weights); @@ -1319,10 +1328,9 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace input.LandBlendWeights2.x = weights[4]; input.LandBlendWeights2.y = weights[5]; } - if (SharedData::extendedMaterialSettings.EnableShadows && (parallaxShadowQuality > 0.0f || SharedData::extendedMaterialSettings.ExtendShadows)) { # if defined(TERRAIN_VARIATION) - if (SharedData::terrainVariationSettings.enableTilingFix) { + [branch] if (useTerrainVariation) { sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); } else { sh0 = ExtendedMaterials::GetTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); @@ -1355,12 +1363,14 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif # endif -# if defined(LANDSCAPE) // Layer 1 (LandBlendWeights1.x) - if (input.LandBlendWeights1.x > 0.0) { +# if defined(LANDSCAPE) +// Layer 1 (LandBlendWeights1.x) + if (input.LandBlendWeights1.x > 0.01) { + float weight = input.LandBlendWeights1.x * invwsum; // Sample layer 1 textures - use terrain variation if available and enabled # if defined(TERRAIN_VARIATION) float4 landColor1; - if (SharedData::terrainVariationSettings.enableTilingFix) { + [branch] if (useTerrainVariation) { landColor1 = StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampColorSampler, uv, sharedOffset, dx, dy); } else { landColor1 = TexColorSampler.SampleBias(SampColorSampler, uv, SharedData::MipBias); @@ -1368,25 +1378,20 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # else float4 landColor1 = TexColorSampler.SampleBias(SampColorSampler, uv, SharedData::MipBias); # endif - + float3 landColorRGB1 = landColor1.rgb; # if defined(TRUE_PBR) [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0PBR) == 0) { - landColor1 = float4(landColor1.rgb / Color::PBRLightingScale, landColor1.a); - } - else - { - landColor1.rgb = Color::Diffuse(landColor1.rgb); + landColorRGB1 = landColorRGB1 / Color::PBRLightingScale; } -# else - landColor1.rgb = Color::Diffuse(landColor1.rgb); # endif + float landAlpha1 = landColor1.a; float landSnowMask1 = GetLandSnowMaskValue(landColor1.w); - + // Sample normal texture for layer 1 # if defined(TERRAIN_VARIATION) float4 landNormal1; - if (SharedData::terrainVariationSettings.enableTilingFix) { + [branch] if (useTerrainVariation) { landNormal1 = StochasticEffect(screenNoise, mipLevels[0], TexNormalSampler, SampNormalSampler, uv, sharedOffset, dx, dy); } else { landNormal1 = TexNormalSampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias); @@ -1394,26 +1399,24 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # else float4 landNormal1 = TexNormalSampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias); # endif - - landNormal1.xyz = GetLandNormal(landSnowMask1, landNormal1.xyz, uv, SampNormalSampler, TexNormalSampler); - normal.xyz += input.LandBlendWeights1.xxx * landNormal1.xyz; - glossiness += input.LandBlendWeights1.x * landNormal1.w; + float3 landNormalRGB1 = landNormal1.rgb; + float landNormalAlpha1 = landNormal1.a; # if defined(SNOW) && !defined(TRUE_PBR) landSnowMask += LandscapeTexture1to4IsSnow.x * input.LandBlendWeights1.x * landSnowMask1; # endif // SNOW - + // Sample RMAOS texture for layer 1 # if defined(TRUE_PBR) + float4 currentRMAOS = 0; [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0PBR) != 0) { - // Sample RMAOS texture for layer 1 # if defined(TERRAIN_VARIATION) - if (SharedData::terrainVariationSettings.enableTilingFix) { - rawRMAOS += input.LandBlendWeights1.x * StochasticEffect(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + [branch] if (useTerrainVariation) { + currentRMAOS = StochasticSample1(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy) * float4(PBRParams1.x, 1, 1, PBRParams1.z); } else { - rawRMAOS += input.LandBlendWeights1.x * TexRMAOSSampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + currentRMAOS = TexRMAOSSampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); } # else - rawRMAOS += input.LandBlendWeights1.x * TexRMAOSSampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + currentRMAOS = TexRMAOSSampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); # endif if ((PBRFlags & PBR::TerrainFlags::LandTile0HasGlint) != 0) { glintParameters += input.LandBlendWeights1.x * LandscapeTexture1GlintParameters; @@ -1421,17 +1424,22 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace } else { - rawRMAOS += input.LandBlendWeights1.x * float4(1 - landNormal1.w, 0, 1, 0); + currentRMAOS = float4(1 - landNormal1.w, 0, 1, 0); } + blendedRMAOS += currentRMAOS * weight; # endif - baseColor += input.LandBlendWeights1.xxxx * landColor1; + blendedRGB += landColorRGB1 * weight; + blendedAlpha += landAlpha1 * weight; + blendedNormalRGB += landNormalRGB1 * weight; + blendedNormalAlpha += landNormalAlpha1 * weight; } // Layer 2 (LandBlendWeights1.y) - if (input.LandBlendWeights1.y > 0.0) { + if (input.LandBlendWeights1.y > 0.01) { + float weight = input.LandBlendWeights1.y * invwsum; // Sample layer 2 textures - use terrain variation if available and enabled # if defined(TERRAIN_VARIATION) float4 landColor2; - if (SharedData::terrainVariationSettings.enableTilingFix) { + [branch] if (useTerrainVariation) { landColor2 = StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampLandColor2Sampler, uv, sharedOffset, dx, dy); } else { landColor2 = TexLandColor2Sampler.SampleBias(SampLandColor2Sampler, uv, SharedData::MipBias); @@ -1439,25 +1447,20 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # else float4 landColor2 = TexLandColor2Sampler.SampleBias(SampLandColor2Sampler, uv, SharedData::MipBias); # endif - -# if defined(TRUE_PBR) + float3 landColorRGB2 = landColor2.rgb; + # if defined(TRUE_PBR) [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1PBR) == 0) { - landColor2 = float4(landColor2.rgb / Color::PBRLightingScale, landColor2.a); - } - else - { - landColor2.rgb = Color::Diffuse(landColor2.rgb); + landColorRGB2 = landColorRGB2 / Color::PBRLightingScale; } -# else - landColor2.rgb = Color::Diffuse(landColor2.rgb); -# endif + # endif + float landAlpha2 = landColor2.a; float landSnowMask2 = GetLandSnowMaskValue(landColor2.w); - + // Sample normal texture for layer 2 # if defined(TERRAIN_VARIATION) float4 landNormal2; - if (SharedData::terrainVariationSettings.enableTilingFix) { + [branch] if (useTerrainVariation) { landNormal2 = StochasticEffect(screenNoise, mipLevels[1], TexLandNormal2Sampler, SampLandNormal2Sampler, uv, sharedOffset, dx, dy); } else { landNormal2 = TexLandNormal2Sampler.SampleBias(SampLandNormal2Sampler, uv, SharedData::MipBias); @@ -1465,26 +1468,24 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # else float4 landNormal2 = TexLandNormal2Sampler.SampleBias(SampLandNormal2Sampler, uv, SharedData::MipBias); # endif - - landNormal2.xyz = GetLandNormal(landSnowMask2, landNormal2.xyz, uv, SampLandNormal2Sampler, TexLandNormal2Sampler); - normal.xyz += input.LandBlendWeights1.yyy * landNormal2.xyz; - glossiness += input.LandBlendWeights1.y * landNormal2.w; + float3 landNormalRGB2 = landNormal2.rgb; + float landNormalAlpha2 = landNormal2.a; # if defined(SNOW) && !defined(TRUE_PBR) landSnowMask += LandscapeTexture1to4IsSnow.y * input.LandBlendWeights1.y * landSnowMask2; # endif // SNOW - # if defined(TRUE_PBR) + float4 currentRMAOS = 0; [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1PBR) != 0) { // Sample RMAOS texture for layer 2 # if defined(TERRAIN_VARIATION) - if (SharedData::terrainVariationSettings.enableTilingFix) { - rawRMAOS += input.LandBlendWeights1.y * StochasticEffect(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampLandRMAOS2Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); + [branch] if (useTerrainVariation) { + currentRMAOS = StochasticSample1(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampLandRMAOS2Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); } else { - rawRMAOS += input.LandBlendWeights1.y * TexLandRMAOS2Sampler.SampleBias(SampLandRMAOS2Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); + currentRMAOS = TexLandRMAOS2Sampler.SampleBias(SampLandRMAOS2Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); } # else - rawRMAOS += input.LandBlendWeights1.y * TexLandRMAOS2Sampler.SampleBias(SampLandRMAOS2Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); + currentRMAOS = TexLandRMAOS2Sampler.SampleBias(SampLandRMAOS2Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); # endif if ((PBRFlags & PBR::TerrainFlags::LandTile1HasGlint) != 0) { glintParameters += input.LandBlendWeights1.y * LandscapeTexture2GlintParameters; @@ -1492,16 +1493,22 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace } else { - rawRMAOS += input.LandBlendWeights1.y * float4(1 - landNormal2.w, 0, 1, 0); + currentRMAOS = float4(1 - landNormal2.w, 0, 1, 0); } + blendedRMAOS += currentRMAOS * weight; # endif - baseColor += input.LandBlendWeights1.yyyy * landColor2; - } // Layer 3 (LandBlendWeights1.z) - if (input.LandBlendWeights1.z > 0.0) { + blendedRGB += landColorRGB2 * weight; + blendedAlpha += landAlpha2 * weight; + blendedNormalRGB += landNormalRGB2 * weight; + blendedNormalAlpha += landNormalAlpha2 * weight; + } + // Layer 3 (LandBlendWeights1.z) + if (input.LandBlendWeights1.z > 0.01) { + float weight = input.LandBlendWeights1.z * invwsum; // Sample layer 3 textures - use terrain variation if available and enabled # if defined(TERRAIN_VARIATION) float4 landColor3; - if (SharedData::terrainVariationSettings.enableTilingFix) { + [branch] if (useTerrainVariation) { landColor3 = StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampLandColor3Sampler, uv, sharedOffset, dx, dy); } else { landColor3 = TexLandColor3Sampler.SampleBias(SampLandColor3Sampler, uv, SharedData::MipBias); @@ -1509,25 +1516,20 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # else float4 landColor3 = TexLandColor3Sampler.SampleBias(SampLandColor3Sampler, uv, SharedData::MipBias); # endif - + float3 landColorRGB3 = landColor3.rgb; # if defined(TRUE_PBR) [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2PBR) == 0) { - landColor3 = float4(landColor3.rgb / Color::PBRLightingScale, landColor3.a); + landColorRGB3 = landColorRGB3 / Color::PBRLightingScale; } - else - { - landColor3.rgb = Color::Diffuse(landColor3.rgb); - } - # else - landColor3.rgb = Color::Diffuse(landColor3.rgb); # endif + float landAlpha3 = landColor3.a; float landSnowMask3 = GetLandSnowMaskValue(landColor3.w); // Sample normal texture for layer 3 # if defined(TERRAIN_VARIATION) float4 landNormal3; - if (SharedData::terrainVariationSettings.enableTilingFix) { + [branch] if (useTerrainVariation) { landNormal3 = StochasticEffect(screenNoise, mipLevels[2], TexLandNormal3Sampler, SampLandNormal3Sampler, uv, sharedOffset, dx, dy); } else { landNormal3 = TexLandNormal3Sampler.SampleBias(SampLandNormal3Sampler, uv, SharedData::MipBias); @@ -1535,26 +1537,25 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # else float4 landNormal3 = TexLandNormal3Sampler.SampleBias(SampLandNormal3Sampler, uv, SharedData::MipBias); # endif - - landNormal3.xyz = GetLandNormal(landSnowMask3, landNormal3.xyz, uv, SampLandNormal3Sampler, TexLandNormal3Sampler); - normal.xyz += input.LandBlendWeights1.zzz * landNormal3.xyz; - glossiness += input.LandBlendWeights1.z * landNormal3.w; + float3 landNormalRGB3 = landNormal3.rgb; + float landNormalAlpha3 = landNormal3.a; # if defined(SNOW) && !defined(TRUE_PBR) landSnowMask += LandscapeTexture1to4IsSnow.z * input.LandBlendWeights1.z * landSnowMask3; # endif // SNOW - # if defined(TRUE_PBR) + # if defined(TRUE_PBR) + float4 currentRMAOS = 0; [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2PBR) != 0) { // Sample RMAOS texture for layer 3 # if defined(TERRAIN_VARIATION) - if (SharedData::terrainVariationSettings.enableTilingFix) { - rawRMAOS += input.LandBlendWeights1.z * StochasticEffect(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampLandRMAOS3Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); + [branch] if (useTerrainVariation) { + currentRMAOS = StochasticSample1(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampLandRMAOS3Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); } else { - rawRMAOS += input.LandBlendWeights1.z * TexLandRMAOS3Sampler.SampleBias(SampLandRMAOS3Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); + currentRMAOS = TexLandRMAOS3Sampler.SampleBias(SampLandRMAOS3Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); } # else - rawRMAOS += input.LandBlendWeights1.z * TexLandRMAOS3Sampler.SampleBias(SampLandRMAOS3Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); + currentRMAOS = TexLandRMAOS3Sampler.SampleBias(SampLandRMAOS3Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); # endif if ((PBRFlags & PBR::TerrainFlags::LandTile2HasGlint) != 0) { glintParameters += input.LandBlendWeights1.z * LandscapeTexture3GlintParameters; @@ -1562,16 +1563,22 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace } else { - rawRMAOS += input.LandBlendWeights1.z * float4(1 - landNormal3.w, 0, 1, 0); + currentRMAOS = float4(1 - landNormal3.w, 0, 1, 0); } + blendedRMAOS += currentRMAOS * weight; # endif - baseColor += input.LandBlendWeights1.zzzz * landColor3; - } // Layer 4 (LandBlendWeights1.w) - if (input.LandBlendWeights1.w > 0.0) { + blendedRGB += landColorRGB3 * weight; + blendedAlpha += landAlpha3 * weight; + blendedNormalRGB += landNormalRGB3 * weight; + blendedNormalAlpha += landNormalAlpha3 * weight; + } + // Layer 4 (LandBlendWeights1.w) + if (input.LandBlendWeights1.w > 0.01) { + float weight = input.LandBlendWeights1.w * invwsum; // Sample layer 4 textures - use terrain variation if available and enabled # if defined(TERRAIN_VARIATION) float4 landColor4; - if (SharedData::terrainVariationSettings.enableTilingFix) { + [branch] if (useTerrainVariation) { landColor4 = StochasticEffect(screenNoise, mipLevels[3], TexLandColor4Sampler, SampLandColor4Sampler, uv, sharedOffset, dx, dy); } else { landColor4 = TexLandColor4Sampler.SampleBias(SampLandColor4Sampler, uv, SharedData::MipBias); @@ -1579,26 +1586,20 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # else float4 landColor4 = TexLandColor4Sampler.SampleBias(SampLandColor4Sampler, uv, SharedData::MipBias); # endif - + float3 landColorRGB4 = landColor4.rgb; # if defined(TRUE_PBR) [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3PBR) == 0) { - landColor4 = float4(landColor4.rgb / Color::PBRLightingScale, landColor4.a); - } - else - { - landColor4.rgb = Color::Diffuse(landColor4.rgb); + landColorRGB4 = landColorRGB4 / Color::PBRLightingScale; } - # else - landColor4.rgb = Color::Diffuse(landColor4.rgb); # endif - + float landAlpha4 = landColor4.a; float landSnowMask4 = GetLandSnowMaskValue(landColor4.w); // Sample normal texture for layer 4 # if defined(TERRAIN_VARIATION) float4 landNormal4; - if (SharedData::terrainVariationSettings.enableTilingFix) { + [branch] if (useTerrainVariation) { landNormal4 = StochasticEffect(screenNoise, mipLevels[3], TexLandNormal4Sampler, SampLandNormal4Sampler, uv, sharedOffset, dx, dy); } else { landNormal4 = TexLandNormal4Sampler.SampleBias(SampLandNormal4Sampler, uv, SharedData::MipBias); @@ -1606,26 +1607,25 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # else float4 landNormal4 = TexLandNormal4Sampler.SampleBias(SampLandNormal4Sampler, uv, SharedData::MipBias); # endif - - landNormal4.xyz = GetLandNormal(landSnowMask4, landNormal4.xyz, uv, SampLandNormal4Sampler, TexLandNormal4Sampler); - normal.xyz += input.LandBlendWeights1.www * landNormal4.xyz; - glossiness += input.LandBlendWeights1.w * landNormal4.w; + float3 landNormalRGB4 = landNormal4.rgb; + float landNormalAlpha4 = landNormal4.a; # if defined(SNOW) && !defined(TRUE_PBR) landSnowMask += LandscapeTexture1to4IsSnow.w * input.LandBlendWeights1.w * landSnowMask4; # endif // SNOW # if defined(TRUE_PBR) + float4 currentRMAOS = 0; [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3PBR) != 0) { // Sample RMAOS texture for layer 4 # if defined(TERRAIN_VARIATION) - if (SharedData::terrainVariationSettings.enableTilingFix) { - rawRMAOS += input.LandBlendWeights1.w * StochasticEffect(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampLandRMAOS4Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); + [branch] if (useTerrainVariation) { + currentRMAOS = StochasticSample1(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampLandRMAOS4Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); } else { - rawRMAOS += input.LandBlendWeights1.w * TexLandRMAOS4Sampler.SampleBias(SampLandRMAOS4Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); + currentRMAOS = TexLandRMAOS4Sampler.SampleBias(SampLandRMAOS4Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); } # else - rawRMAOS += input.LandBlendWeights1.w * TexLandRMAOS4Sampler.SampleBias(SampLandRMAOS4Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); + currentRMAOS = TexLandRMAOS4Sampler.SampleBias(SampLandRMAOS4Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); # endif if ((PBRFlags & PBR::TerrainFlags::LandTile3HasGlint) != 0) { glintParameters += input.LandBlendWeights1.w * LandscapeTexture4GlintParameters; @@ -1633,17 +1633,22 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace } else { - rawRMAOS += input.LandBlendWeights1.w * float4(1 - landNormal4.w, 0, 1, 0); + currentRMAOS = float4(1 - landNormal4.w, 0, 1, 0); } + blendedRMAOS += currentRMAOS * weight; # endif - baseColor += input.LandBlendWeights1.wwww * landColor4; + blendedRGB += landColorRGB4 * weight; + blendedAlpha += landAlpha4 * weight; + blendedNormalRGB += landNormalRGB4 * weight; + blendedNormalAlpha += landNormalAlpha4 * weight; } // Layer 5 (LandBlendWeights2.x) - if (input.LandBlendWeights2.x > 0.0) { + if (input.LandBlendWeights2.x > 0.01) { + float weight = input.LandBlendWeights2.x * invwsum; // Sample layer 5 textures - use terrain variation if available and enabled # if defined(TERRAIN_VARIATION) float4 landColor5; - if (SharedData::terrainVariationSettings.enableTilingFix) { + [branch] if (useTerrainVariation) { landColor5 = StochasticEffect(screenNoise, mipLevels[4], TexLandColor5Sampler, SampLandColor5Sampler, uv, sharedOffset, dx, dy); } else { landColor5 = TexLandColor5Sampler.SampleBias(SampLandColor5Sampler, uv, SharedData::MipBias); @@ -1651,25 +1656,20 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # else float4 landColor5 = TexLandColor5Sampler.SampleBias(SampLandColor5Sampler, uv, SharedData::MipBias); # endif - + float3 landColorRGB5 = landColor5.rgb; # if defined(TRUE_PBR) [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4PBR) == 0) { - landColor5 = float4(landColor5.rgb / Color::PBRLightingScale, landColor5.a); - } - else - { - landColor5.rgb = Color::Diffuse(landColor5.rgb); + landColorRGB5 = landColorRGB5 / Color::PBRLightingScale; } - # else - landColor5.rgb = Color::Diffuse(landColor5.rgb); # endif + float landAlpha5 = landColor5.a; float landSnowMask5 = GetLandSnowMaskValue(landColor5.w); // Sample normal texture for layer 5 # if defined(TERRAIN_VARIATION) float4 landNormal5; - if (SharedData::terrainVariationSettings.enableTilingFix) { + [branch] if (useTerrainVariation) { landNormal5 = StochasticEffect(screenNoise, mipLevels[4], TexLandNormal5Sampler, SampLandNormal5Sampler, uv, sharedOffset, dx, dy); } else { landNormal5 = TexLandNormal5Sampler.SampleBias(SampLandNormal5Sampler, uv, SharedData::MipBias); @@ -1677,26 +1677,26 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # else float4 landNormal5 = TexLandNormal5Sampler.SampleBias(SampLandNormal5Sampler, uv, SharedData::MipBias); # endif + float3 landNormalRGB5 = landNormal5.rgb; + float landNormalAlpha5 = landNormal5.a; - landNormal5.xyz = GetLandNormal(landSnowMask5, landNormal5.xyz, uv, SampLandNormal5Sampler, TexLandNormal5Sampler); - normal.xyz += input.LandBlendWeights2.xxx * landNormal5.xyz; - glossiness += input.LandBlendWeights2.x * landNormal5.w; # if defined(SNOW) && !defined(TRUE_PBR) landSnowMask += LandscapeTexture5to6IsSnow.x * input.LandBlendWeights2.x * landSnowMask5; # endif // SNOW # if defined(TRUE_PBR) - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4PBR) != 0) + float4 currentRMAOS = 0; + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4PBR) != 0) { // Sample RMAOS texture for layer 5 # if defined(TERRAIN_VARIATION) - if (SharedData::terrainVariationSettings.enableTilingFix) { - rawRMAOS += input.LandBlendWeights2.x * StochasticEffect(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampLandRMAOS5Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); + [branch] if (useTerrainVariation) { + currentRMAOS = StochasticSample1(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampLandRMAOS5Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); } else { - rawRMAOS += input.LandBlendWeights2.x * TexLandRMAOS5Sampler.SampleBias(SampLandRMAOS5Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); + currentRMAOS = TexLandRMAOS5Sampler.SampleBias(SampLandRMAOS5Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); } # else - rawRMAOS += input.LandBlendWeights2.x * TexLandRMAOS5Sampler.SampleBias(SampLandRMAOS5Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); + currentRMAOS = TexLandRMAOS5Sampler.SampleBias(SampLandRMAOS5Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); # endif if ((PBRFlags & PBR::TerrainFlags::LandTile4HasGlint) != 0) { glintParameters += input.LandBlendWeights2.x * LandscapeTexture5GlintParameters; @@ -1704,17 +1704,22 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace } else { - rawRMAOS += input.LandBlendWeights2.x * float4(1 - landNormal5.w, 0, 1, 0); + currentRMAOS = float4(1 - landNormal5.w, 0, 1, 0); } + blendedRMAOS += currentRMAOS * weight; # endif - baseColor += input.LandBlendWeights2.xxxx * landColor5; + blendedRGB += landColorRGB5 * weight; + blendedAlpha += landAlpha5 * weight; + blendedNormalRGB += landNormalRGB5 * weight; + blendedNormalAlpha += landNormalAlpha5 * weight; } // Layer 6 (LandBlendWeights2.y) - if (input.LandBlendWeights2.y > 0.0) { + if (input.LandBlendWeights2.y > 0.01) { + float weight = input.LandBlendWeights2.y * invwsum; // Sample layer 6 textures - use terrain variation if available and enabled # if defined(TERRAIN_VARIATION) float4 landColor6; - if (SharedData::terrainVariationSettings.enableTilingFix) { + [branch] if (useTerrainVariation) { landColor6 = StochasticEffect(screenNoise, mipLevels[5], TexLandColor6Sampler, SampLandColor6Sampler, uv, sharedOffset, dx, dy); } else { landColor6 = TexLandColor6Sampler.SampleBias(SampLandColor6Sampler, uv, SharedData::MipBias); @@ -1722,25 +1727,20 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # else float4 landColor6 = TexLandColor6Sampler.SampleBias(SampLandColor6Sampler, uv, SharedData::MipBias); # endif - + float3 landColorRGB6 = landColor6.rgb; # if defined(TRUE_PBR) [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5PBR) == 0) { - landColor6 = float4(landColor6.rgb / Color::PBRLightingScale, landColor6.a); - } - else - { - landColor6.rgb = Color::Diffuse(landColor6.rgb); + landColorRGB6 = landColorRGB6 / Color::PBRLightingScale; } - # else - landColor6.rgb = Color::Diffuse(landColor6.rgb); # endif + float landAlpha6 = landColor6.a; float landSnowMask6 = GetLandSnowMaskValue(landColor6.w); // Sample normal texture for layer 6 # if defined(TERRAIN_VARIATION) float4 landNormal6; - if (SharedData::terrainVariationSettings.enableTilingFix) { + [branch] if (useTerrainVariation) { landNormal6 = StochasticEffect(screenNoise, mipLevels[5], TexLandNormal6Sampler, SampLandNormal6Sampler, uv, sharedOffset, dx, dy); } else { landNormal6 = TexLandNormal6Sampler.SampleBias(SampLandNormal6Sampler, uv, SharedData::MipBias); @@ -1748,26 +1748,24 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # else float4 landNormal6 = TexLandNormal6Sampler.SampleBias(SampLandNormal6Sampler, uv, SharedData::MipBias); # endif - - landNormal6.xyz = GetLandNormal(landSnowMask6, landNormal6.xyz, uv, SampLandNormal6Sampler, TexLandNormal6Sampler); - normal.xyz += input.LandBlendWeights2.yyy * landNormal6.xyz; - glossiness += input.LandBlendWeights2.y * landNormal6.w; + float3 landNormalRGB6 = landNormal6.rgb; + float landNormalAlpha6 = landNormal6.a; # if defined(SNOW) && !defined(TRUE_PBR) landSnowMask += LandscapeTexture5to6IsSnow.y * input.LandBlendWeights2.y * landSnowMask6; # endif // SNOW # if defined(TRUE_PBR) + float4 currentRMAOS = 0; [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5PBR) != 0) - { - // Sample RMAOS texture for layer 6 + { // Sample RMAOS texture for layer 6 # if defined(TERRAIN_VARIATION) - if (SharedData::terrainVariationSettings.enableTilingFix) { - rawRMAOS += input.LandBlendWeights2.y * StochasticEffect(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampLandRMAOS6Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); + [branch] if (useTerrainVariation) { + currentRMAOS = StochasticSample1(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampLandRMAOS6Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); } else { - rawRMAOS += input.LandBlendWeights2.y * TexLandRMAOS6Sampler.SampleBias(SampLandRMAOS6Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); + currentRMAOS = TexLandRMAOS6Sampler.SampleBias(SampLandRMAOS6Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); } # else - rawRMAOS += input.LandBlendWeights2.y * TexLandRMAOS6Sampler.SampleBias(SampLandRMAOS6Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); + currentRMAOS = TexLandRMAOS6Sampler.SampleBias(SampLandRMAOS6Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); # endif if ((PBRFlags & PBR::TerrainFlags::LandTile5HasGlint) != 0) { glintParameters += input.LandBlendWeights2.y * LandscapeTexture6GlintParameters; @@ -1775,42 +1773,30 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace } else { - rawRMAOS += input.LandBlendWeights2.y * float4(1 - landNormal6.w, 0, 1, 0); + currentRMAOS = float4(1 - landNormal6.w, 0, 1, 0); } + blendedRMAOS += currentRMAOS * weight; +# endif + blendedRGB += landColorRGB6 * weight; + blendedAlpha += landAlpha6 * weight; + blendedNormalRGB += landNormalRGB6 * weight; + blendedNormalAlpha += landNormalAlpha6 * weight; + } + float4 rawBaseColor = float4(blendedRGB, blendedAlpha); + baseColor = float4(Color::Diffuse(blendedRGB), blendedAlpha); + normal = float4(blendedNormalRGB, blendedNormalAlpha); + # if defined(TRUE_PBR) + rawRMAOS = blendedRMAOS; # endif - baseColor += input.LandBlendWeights2.yyyy * landColor6; - } - // Set rawBaseColor for later processing - float4 rawBaseColor = baseColor; -# else - // Non-landscape code +# else // Non-landscape code float4 rawBaseColor = TexColorSampler.SampleBias(SampColorSampler, diffuseUv, SharedData::MipBias); baseColor = float4(Color::Diffuse(rawBaseColor.rgb), rawBaseColor.a); float4 normalColor = TexNormalSampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias); normal = normalColor; -# if defined(TRUE_PBR) -# if defined(LODLANDNOISE) - rawRMAOS = float4(1, 0, 1, 0); -# elif defined(LANDSCAPE) - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0PBR) != 0) - { - rawRMAOS = input.LandBlendWeights1.x * TexRMAOSSampler.SampleBias(SampRMAOSSampler, diffuseUv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); - if ((PBRFlags & PBR::TerrainFlags::LandTile0HasGlint) != 0) { - glintParameters += input.LandBlendWeights1.x * LandscapeTexture1GlintParameters; - } - } - else - { - rawRMAOS = input.LandBlendWeights1.x * float4(1 - glossiness.x, 0, 1, 0); - } -# else - rawRMAOS = TexRMAOSSampler.SampleBias(SampRMAOSSampler, diffuseUv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); - if ((PBRFlags & PBR::Flags::Glint) != 0) { - glintParameters = MultiLayerParallaxData; - } +# if defined(TRUE_PBR) + rawRMAOS = TexRMAOSSampler.SampleBias(SampRMAOSSampler, diffuseUv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); # endif # endif -# endif # if defined(LOD_BLENDING) # if defined(LODOBJECTS) || defined(LODOBJECTSHD) @@ -2316,7 +2302,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace [branch] if (SharedData::extendedMaterialSettings.EnableTerrainParallax) { # if defined(TERRAIN_VARIATION) - if (SharedData::terrainVariationSettings.enableTilingFix) { + [branch] if (useTerrainVariation) { float weights[6]; sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); @@ -3049,7 +3035,8 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace indirectSpecularLobeWeight = lerp(indirectSpecularLobeWeight, 0, lodLandBlendFactor); pbrGlossiness = lerp(pbrGlossiness, 0, lodLandBlendFactor); } -# elif defined(TRUE_PBR) +# elif defined(TRUE_PBR) && !defined(LANDSCAPE) + // Only apply final PBR scaling for non-landscape materials color.xyz *= Color::PBRLightingScale; specularColorPBR *= Color::PBRLightingScale; specularColor = specularColorPBR; From 1c9fccd65015058730866f52fce44771cd85c26e Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Wed, 28 May 2025 17:25:29 +1000 Subject: [PATCH 07/53] comment clean 1 --- .../Shaders/TerrainVariation/TerrainVariation.hlsli | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index 7709430f88..afc512842d 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -65,7 +65,7 @@ inline StochasticOffsets ComputeStochasticOffsets(float2 UV) } // Main stochastic sampling function -inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) +inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for normal/diffuse text. Luminence-based blending helps preserve details close to camera. { // Early return if terrain variation is disabled [branch] if (!SharedData::terrainVariationSettings.enableTilingFix) { @@ -105,15 +105,12 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler return result; } -inline float4 StochasticSample1(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) +inline float4 StochasticSample1(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for RMAOS (maybe LOD in future) { - // Use the first offset from the provided offsets struct - // This maintains compatibility while still allowing the calling code to choose - // between ComputeStochasticOffsets() for full offsets or the optimized version return tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); } -inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) +inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for parallaxcoords & getheight funct. { // Sample the three texture offsets using the provided mip level float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); From 55f3c10fa61811bcaf68d4338ed1f2dc944777e2 Mon Sep 17 00:00:00 2001 From: davo0411 Date: Wed, 28 May 2025 08:36:14 +0000 Subject: [PATCH 08/53] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20clang-for?= =?UTF-8?q?mat=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 216 ++-- .../TerrainVariation/TerrainVariation.hlsli | 45 +- package/Shaders/Common/SharedData.hlsli | 4 +- package/Shaders/Lighting.hlsl | 948 ++++++++++-------- src/Features/TerrainVariation.h | 8 +- 5 files changed, 681 insertions(+), 540 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index 1241fea105..4de234c54a 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -6,10 +6,10 @@ // https://bartwronski.files.wordpress.com/2014/03/ac4_gdc.pdf #if defined(LANDSCAPE) && defined(TERRAIN_VARIATION) -# define USE_TERRAIN_VARIATION 1 -# include "TerrainVariation/TerrainVariation.hlsli" +# define USE_TERRAIN_VARIATION 1 +# include "TerrainVariation/TerrainVariation.hlsli" #else -# define USE_TERRAIN_VARIATION 0 +# define USE_TERRAIN_VARIATION 0 #endif struct DisplacementParams @@ -94,13 +94,17 @@ namespace ExtendedMaterials weights[3] = w1.w; weights[4] = w2.x; weights[5] = w2.y; - float total = 0; - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.0) { + float total = 0; + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.0) + { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexLandDisplacement0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); - } else { + } + else + { h = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); } # else @@ -108,13 +112,17 @@ namespace ExtendedMaterials # endif total += h * weights[0]; weights[0] *= pow(heightBlend, HEIGHT_MULT * h); - } - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1HasDisplacement) != 0 && w1.y > 0.0) { + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1HasDisplacement) != 0 && w1.y > 0.0) + { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandDisplacement1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); - } else { + } + else + { h = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); } # else @@ -122,13 +130,17 @@ namespace ExtendedMaterials # endif total += h * weights[1]; weights[1] *= pow(heightBlend, HEIGHT_MULT * h); - } - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2HasDisplacement) != 0 && w1.z > 0.0) { + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2HasDisplacement) != 0 && w1.z > 0.0) + { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandDisplacement2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); - } else { + } + else + { h = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); } # else @@ -136,14 +148,17 @@ namespace ExtendedMaterials # endif total += h * weights[2]; weights[2] *= pow(heightBlend, HEIGHT_MULT * h); - } + } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); - } else { + } + else + { h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); } # else @@ -151,14 +166,17 @@ namespace ExtendedMaterials # endif total += h * weights[3]; weights[3] *= pow(heightBlend, HEIGHT_MULT * h); - } + } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); - } else { + } + else + { h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); } # else @@ -166,14 +184,17 @@ namespace ExtendedMaterials # endif total += h * weights[4]; weights[4] *= pow(heightBlend, HEIGHT_MULT * h); - } + } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); - } else { + } + else + { h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); } # else @@ -213,16 +234,20 @@ namespace ExtendedMaterials weights[2] = w1.z; weights[3] = w1.w; weights[4] = w2.x; - weights[5] = w2.y; float total = 0; + weights[5] = w2.y; + float total = 0; if (w1.x > 0.0) { - float h = 0.0; + float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand0HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexLandTHDisp0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); - } else { + } + else + { h = ScaleDisplacement(TexLandTHDisp0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); } # else @@ -232,9 +257,12 @@ namespace ExtendedMaterials else { # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexColorSampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[0]); - } else { + } + else + { h = ScaleDisplacement(TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, params[0]); } # else @@ -249,9 +277,12 @@ namespace ExtendedMaterials [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandTHDisp1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); - } else { + } + else + { h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); } # else @@ -261,9 +292,12 @@ namespace ExtendedMaterials else { # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandColor2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[1]); - } else { + } + else + { h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); } # else @@ -278,9 +312,12 @@ namespace ExtendedMaterials [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandTHDisp2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); - } else { + } + else + { h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); } # else @@ -290,9 +327,12 @@ namespace ExtendedMaterials else { # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandColor3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[2]); - } else { + } + else + { h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); } # else @@ -301,13 +341,17 @@ namespace ExtendedMaterials } total += h * weights[2]; weights[2] *= pow(heightBlend, HEIGHT_MULT * h); - } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); - } else { + } + else + { h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); } # else @@ -315,13 +359,17 @@ namespace ExtendedMaterials # endif total += h * weights[3]; weights[3] *= pow(heightBlend, HEIGHT_MULT * h); - } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); - } else { + } + else + { h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); } # else @@ -329,13 +377,17 @@ namespace ExtendedMaterials # endif total += h * weights[4]; weights[4] *= pow(heightBlend, HEIGHT_MULT * h); - } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); - } else { + } + else + { h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); } # else @@ -407,7 +459,7 @@ namespace ExtendedMaterials if (nearBlendToFar < 1.0) { uint numSteps = uint((max(6, scale * 8) * (1.0 - nearBlendToFar)) + 0.5); numSteps = clamp((numSteps + 3) & ~0x03, 4, max(8, scale * 8)); -# else +#else # if defined(TRUE_PBR) if ((PBRFlags & PBR::Flags::InterlayerParallax) != 0 || nearBlendToFar < 1.0) # else @@ -665,7 +717,7 @@ namespace ExtendedMaterials weights[4] = w2.x; weights[5] = w2.y; float total = 0; - float screenNoise = 0; // Default noise value when no stochastic sampling + float screenNoise = 0; // Default noise value when no stochastic sampling [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.0) { @@ -730,10 +782,10 @@ namespace ExtendedMaterials weights[4] = w2.x; weights[5] = w2.y; float total = 0; - float screenNoise = 0; // Default noise value when no stochastic sampling + float screenNoise = 0; // Default noise value when no stochastic sampling if (w1.x > 0.0) { - float h = 0.0; + float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand0HasDisplacement) != 0) { h = ScaleDisplacement(TexLandTHDisp0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); @@ -750,9 +802,12 @@ namespace ExtendedMaterials [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandTHDisp1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); - } else { + } + else + { h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); } # else @@ -762,9 +817,12 @@ namespace ExtendedMaterials else { # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandColor2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[1]); - } else { + } + else + { h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); } # else @@ -779,9 +837,12 @@ namespace ExtendedMaterials [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandTHDisp2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); - } else { + } + else + { h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); } # else @@ -791,9 +852,12 @@ namespace ExtendedMaterials else { # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandColor3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[2]); - } else { + } + else + { h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); } # else @@ -802,14 +866,17 @@ namespace ExtendedMaterials } total += h * weights[2]; weights[2] *= pow(heightBlend, HEIGHT_MULT * h); - } + } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); - } else { + } + else + { h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); } # else @@ -817,14 +884,17 @@ namespace ExtendedMaterials # endif total += h * weights[3]; weights[3] *= pow(heightBlend, HEIGHT_MULT * h); - } + } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); - } else { + } + else + { h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); } # else @@ -832,13 +902,17 @@ namespace ExtendedMaterials # endif total += h * weights[4]; weights[4] *= pow(heightBlend, HEIGHT_MULT * h); - } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) { + [branch] if (USE_TERRAIN_VARIATION) + { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); - } else { + } + else + { h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); } # else @@ -1020,7 +1094,7 @@ namespace ExtendedMaterials # if defined(TRUE_PBR) float scale = max(params[0].HeightScale * input.LandBlendWeights1.x, max(params[1].HeightScale * input.LandBlendWeights1.y, max(params[2].HeightScale * input.LandBlendWeights1.z, - max(params[3].HeightScale * input.LandBlendWeights1.w, max(params[4].HeightScale * input.LandBlendWeights2.x, params[5].HeightScale * input.LandBlendWeights2.y))))); + max(params[3].HeightScale * input.LandBlendWeights1.w, max(params[4].HeightScale * input.LandBlendWeights2.x, params[5].HeightScale * input.LandBlendWeights2.y))))); if (scale < 0.01) return 1.0; rayDir *= scale; @@ -1031,7 +1105,7 @@ namespace ExtendedMaterials if (quality > 0.5) sh.z = GetTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.75) - sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); return pow(1.0 - saturate(dot(max(0, sh - sh0) / scale, 1.0)) * quality, 2.0); # else sh = GetTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); @@ -1046,5 +1120,5 @@ namespace ExtendedMaterials } return 1.0; } -#endif // defined(LANDSCAPE) && defined(TERRAIN_VARIATION) +#endif // defined(LANDSCAPE) && defined(TERRAIN_VARIATION) } diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index afc512842d..43f803ec5d 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -9,9 +9,9 @@ #include "Common/SharedData.hlsli" // Height blend operator settings - DO NOT CHANGE THESE VALUES. -static const float HEIGHT_BLEND_CONTRAST = 16.0; // Controls sharpness of height-based transitions -static const float CULLING_THRESHOLD = 0.001; // Minimum weight threshold for sample culling -static const float HEIGHT_INFLUENCE = 0.3; // How much height affects blending (0=pure stochastic, 1=pure height) +static const float HEIGHT_BLEND_CONTRAST = 16.0; // Controls sharpness of height-based transitions +static const float CULLING_THRESHOLD = 0.001; // Minimum weight threshold for sample culling +static const float HEIGHT_INFLUENCE = 0.3; // How much height affects blending (0=pure stochastic, 1=pure height) // Structure to hold stochastic sampling offsets and weights struct StochasticOffsets @@ -25,8 +25,8 @@ struct StochasticOffsets // Hash function for stochastic sampling inline float2 hash2D2D(float2 s) { - s = s * float2(1271.5151, 3337.8237); - return frac(sin(s.x + s.y) * float2(43758.5453, 28637.1369)); + s = s * float2(1271.5151, 3337.8237); + return frac(sin(s.x + s.y) * float2(43758.5453, 28637.1369)); } // Compute single offset for stochastic sampling (optimized for single sample) @@ -39,7 +39,7 @@ inline float2 ComputeStochasticOffsets1(float2 UV) // Only compute the first vertex ID based on barycentric coordinates float2 firstVertexID = (barry.z > 0) ? vxID : (vxID + float2(1, 1)); - + // Return only the first hash offset return hash2D2D(firstVertexID); } @@ -65,63 +65,64 @@ inline StochasticOffsets ComputeStochasticOffsets(float2 UV) } // Main stochastic sampling function -inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for normal/diffuse text. Luminence-based blending helps preserve details close to camera. +inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for normal/diffuse text. Luminence-based blending helps preserve details close to camera. { // Early return if terrain variation is disabled - [branch] if (!SharedData::terrainVariationSettings.enableTilingFix) { + [branch] if (!SharedData::terrainVariationSettings.enableTilingFix) + { return tex.SampleBias(samp, uv, SharedData::MipBias); } - + // Apply contrast to the initial blend weights (without height influence) float3 blendWeights = pow(saturate(offsets.weights), HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE)); - + // Renormalize the weights float totalWeight = blendWeights.x + blendWeights.y + blendWeights.z; blendWeights = (totalWeight > 0.0) ? blendWeights / totalWeight : float3(0.33, 0.33, 0.34); - + // Sample all three locations float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); - + // Apply height-based weight adjustments float height1 = sample1.a > 0 ? sample1.a : dot(sample1.rgb, float3(0.2126, 0.7152, 0.0722)); float height2 = sample2.a > 0 ? sample2.a : dot(sample2.rgb, float3(0.2126, 0.7152, 0.0722)); float height3 = sample3.a > 0 ? sample3.a : dot(sample3.rgb, float3(0.2126, 0.7152, 0.0722)); - + float weight1 = lerp(blendWeights.x, height1 * blendWeights.x, HEIGHT_INFLUENCE); float weight2 = lerp(blendWeights.y, height2 * blendWeights.y, HEIGHT_INFLUENCE); float weight3 = lerp(blendWeights.z, height3 * blendWeights.z, HEIGHT_INFLUENCE); - + // Blend samples with height-adjusted weights float4 result = sample1 * weight1 + sample2 * weight2 + sample3 * weight3; - + // Renormalize final result float finalWeightSum = weight1 + weight2 + weight3; if (finalWeightSum > 0.0) { result /= finalWeightSum; } - + return result; } -inline float4 StochasticSample1(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for RMAOS (maybe LOD in future) +inline float4 StochasticSample1(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for RMAOS (maybe LOD in future) { return tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); } -inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for parallaxcoords & getheight funct. +inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for parallaxcoords & getheight funct. { // Sample the three texture offsets using the provided mip level float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); - + // Blend using the barycentric weights - float4 result = sample1 * offsets.weights.x + - sample2 * offsets.weights.y + + float4 result = sample1 * offsets.weights.x + + sample2 * offsets.weights.y + sample3 * offsets.weights.z; - + return result; } diff --git a/package/Shaders/Common/SharedData.hlsli b/package/Shaders/Common/SharedData.hlsli index f5639513a9..2b61d6d6a8 100644 --- a/package/Shaders/Common/SharedData.hlsli +++ b/package/Shaders/Common/SharedData.hlsli @@ -159,8 +159,8 @@ namespace SharedData float DiffuseIndirectMult; float BaseColorMult; float pad; - }; - + }; + struct TerrainVariationSettings { bool enableTilingFix; diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 41b8786031..8d20abc2db 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1258,7 +1258,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace diffuseUv = ProjectedUVParams2.yy * input.TexCoord0.zw; # endif // SPARKLE -# if defined(LANDSCAPE) // Normalize blend weights +# if defined(LANDSCAPE) // Normalize blend weights float totalWeight = input.LandBlendWeights1.x + input.LandBlendWeights1.y + input.LandBlendWeights1.z + input.LandBlendWeights1.w + input.LandBlendWeights2.x + input.LandBlendWeights2.y; if (totalWeight > 0.0) { @@ -1274,18 +1274,19 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(TRUE_PBR) float4 blendedRMAOS = 0; # endif - float invwsum = 1.0; // Weights are already normalized above, so invwsum should be 1.0 - // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) -# if defined(TERRAIN_VARIATION) + float invwsum = 1.0; // Weights are already normalized above, so invwsum should be 1.0 + // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) +# if defined(TERRAIN_VARIATION) bool useTerrainVariation = SharedData::terrainVariationSettings.enableTilingFix; float2 dx, dy; StochasticOffsets sharedOffset; - [branch] if (useTerrainVariation) { + [branch] if (useTerrainVariation) + { dx = ddx(uv); dy = ddy(uv); sharedOffset = ComputeStochasticOffsets(uv); } -# endif +# endif # if defined(EMAT) if (SharedData::extendedMaterialSettings.EnableTerrainParallax) { @@ -1310,15 +1311,18 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace displacementParams[5].HeightScale *= LandscapeTexture6PBRParams.y; # endif float weights[6]; -# if defined(TERRAIN_VARIATION) - [branch] if (useTerrainVariation) { +# if defined(TERRAIN_VARIATION) + [branch] if (useTerrainVariation) + { uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, sharedOffset, dx, dy, pixelOffset, weights); - } else { + } + else + { uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, pixelOffset, weights); } -# else +# else uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, pixelOffset, weights); -# endif +# endif if (SharedData::extendedMaterialSettings.EnableHeightBlending) { input.LandBlendWeights1.x = weights[0]; @@ -1329,19 +1333,22 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace input.LandBlendWeights2.y = weights[5]; } if (SharedData::extendedMaterialSettings.EnableShadows && (parallaxShadowQuality > 0.0f || SharedData::extendedMaterialSettings.ExtendShadows)) { -# if defined(TERRAIN_VARIATION) - [branch] if (useTerrainVariation) { +# if defined(TERRAIN_VARIATION) + [branch] if (useTerrainVariation) + { sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); - } else { + } + else + { sh0 = ExtendedMaterials::GetTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); } -# else +# else sh0 = ExtendedMaterials::GetTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); -# endif +# endif } } # endif // EMAT -# endif // LANDSCAPE +# endif // LANDSCAPE # if defined(SPARKLE) diffuseUv = ProjectedUVParams2.yy * (input.TexCoord0.zw + (uv - uvOriginal)); @@ -1363,438 +1370,492 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif # endif -# if defined(LANDSCAPE) -// Layer 1 (LandBlendWeights1.x) +# if defined(LANDSCAPE) + // Layer 1 (LandBlendWeights1.x) if (input.LandBlendWeights1.x > 0.01) { float weight = input.LandBlendWeights1.x * invwsum; // Sample layer 1 textures - use terrain variation if available and enabled +# if defined(TERRAIN_VARIATION) + float4 landColor1; + [branch] if (useTerrainVariation) + { + landColor1 = StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampColorSampler, uv, sharedOffset, dx, dy); + } + else + { + landColor1 = TexColorSampler.SampleBias(SampColorSampler, uv, SharedData::MipBias); + } +# else + float4 landColor1 = TexColorSampler.SampleBias(SampColorSampler, uv, SharedData::MipBias); +# endif + float3 landColorRGB1 = landColor1.rgb; +# if defined(TRUE_PBR) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0PBR) == 0) + { + landColorRGB1 = landColorRGB1 / Color::PBRLightingScale; + } +# endif + float landAlpha1 = landColor1.a; + float landSnowMask1 = GetLandSnowMaskValue(landColor1.w); + + // Sample normal texture for layer 1 +# if defined(TERRAIN_VARIATION) + float4 landNormal1; + [branch] if (useTerrainVariation) + { + landNormal1 = StochasticEffect(screenNoise, mipLevels[0], TexNormalSampler, SampNormalSampler, uv, sharedOffset, dx, dy); + } + else + { + landNormal1 = TexNormalSampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias); + } +# else + float4 landNormal1 = TexNormalSampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias); +# endif + float3 landNormalRGB1 = landNormal1.rgb; + float landNormalAlpha1 = landNormal1.a; +# if defined(SNOW) && !defined(TRUE_PBR) + landSnowMask += LandscapeTexture1to4IsSnow.x * input.LandBlendWeights1.x * landSnowMask1; +# endif // SNOW \ + // Sample RMAOS texture for layer 1 +# if defined(TRUE_PBR) + float4 currentRMAOS = 0; + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0PBR) != 0) + { # if defined(TERRAIN_VARIATION) - float4 landColor1; - [branch] if (useTerrainVariation) { - landColor1 = StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampColorSampler, uv, sharedOffset, dx, dy); - } else { - landColor1 = TexColorSampler.SampleBias(SampColorSampler, uv, SharedData::MipBias); - } + [branch] if (useTerrainVariation) + { + currentRMAOS = StochasticSample1(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + } + else + { + currentRMAOS = TexRMAOSSampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + } # else - float4 landColor1 = TexColorSampler.SampleBias(SampColorSampler, uv, SharedData::MipBias); + currentRMAOS = TexRMAOSSampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); # endif - float3 landColorRGB1 = landColor1.rgb; -# if defined(TRUE_PBR) - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0PBR) == 0) - { - landColorRGB1 = landColorRGB1 / Color::PBRLightingScale; - } -# endif - float landAlpha1 = landColor1.a; - float landSnowMask1 = GetLandSnowMaskValue(landColor1.w); - - // Sample normal texture for layer 1 - # if defined(TERRAIN_VARIATION) - float4 landNormal1; - [branch] if (useTerrainVariation) { - landNormal1 = StochasticEffect(screenNoise, mipLevels[0], TexNormalSampler, SampNormalSampler, uv, sharedOffset, dx, dy); - } else { - landNormal1 = TexNormalSampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias); - } - # else - float4 landNormal1 = TexNormalSampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias); - # endif - float3 landNormalRGB1 = landNormal1.rgb; - float landNormalAlpha1 = landNormal1.a; - # if defined(SNOW) && !defined(TRUE_PBR) - landSnowMask += LandscapeTexture1to4IsSnow.x * input.LandBlendWeights1.x * landSnowMask1; - # endif // SNOW - // Sample RMAOS texture for layer 1 - # if defined(TRUE_PBR) - float4 currentRMAOS = 0; - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0PBR) != 0) - { - # if defined(TERRAIN_VARIATION) - [branch] if (useTerrainVariation) { - currentRMAOS = StochasticSample1(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy) * float4(PBRParams1.x, 1, 1, PBRParams1.z); - } else { - currentRMAOS = TexRMAOSSampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); - } - # else - currentRMAOS = TexRMAOSSampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); - # endif - if ((PBRFlags & PBR::TerrainFlags::LandTile0HasGlint) != 0) { - glintParameters += input.LandBlendWeights1.x * LandscapeTexture1GlintParameters; - } - } - else - { - currentRMAOS = float4(1 - landNormal1.w, 0, 1, 0); - } - blendedRMAOS += currentRMAOS * weight; - # endif - blendedRGB += landColorRGB1 * weight; - blendedAlpha += landAlpha1 * weight; - blendedNormalRGB += landNormalRGB1 * weight; - blendedNormalAlpha += landNormalAlpha1 * weight; + if ((PBRFlags & PBR::TerrainFlags::LandTile0HasGlint) != 0) { + glintParameters += input.LandBlendWeights1.x * LandscapeTexture1GlintParameters; } + } + else + { + currentRMAOS = float4(1 - landNormal1.w, 0, 1, 0); + } + blendedRMAOS += currentRMAOS * weight; +# endif + blendedRGB += landColorRGB1 * weight; + blendedAlpha += landAlpha1 * weight; + blendedNormalRGB += landNormalRGB1 * weight; + blendedNormalAlpha += landNormalAlpha1 * weight; + } // Layer 2 (LandBlendWeights1.y) if (input.LandBlendWeights1.y > 0.01) { float weight = input.LandBlendWeights1.y * invwsum; - // Sample layer 2 textures - use terrain variation if available and enabled - # if defined(TERRAIN_VARIATION) - float4 landColor2; - [branch] if (useTerrainVariation) { - landColor2 = StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampLandColor2Sampler, uv, sharedOffset, dx, dy); - } else { - landColor2 = TexLandColor2Sampler.SampleBias(SampLandColor2Sampler, uv, SharedData::MipBias); - } - # else - float4 landColor2 = TexLandColor2Sampler.SampleBias(SampLandColor2Sampler, uv, SharedData::MipBias); - # endif - float3 landColorRGB2 = landColor2.rgb; - # if defined(TRUE_PBR) - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1PBR) == 0) - { - landColorRGB2 = landColorRGB2 / Color::PBRLightingScale; - } - # endif - float landAlpha2 = landColor2.a; - float landSnowMask2 = GetLandSnowMaskValue(landColor2.w); - - // Sample normal texture for layer 2 - # if defined(TERRAIN_VARIATION) - float4 landNormal2; - [branch] if (useTerrainVariation) { - landNormal2 = StochasticEffect(screenNoise, mipLevels[1], TexLandNormal2Sampler, SampLandNormal2Sampler, uv, sharedOffset, dx, dy); - } else { - landNormal2 = TexLandNormal2Sampler.SampleBias(SampLandNormal2Sampler, uv, SharedData::MipBias); - } - # else - float4 landNormal2 = TexLandNormal2Sampler.SampleBias(SampLandNormal2Sampler, uv, SharedData::MipBias); - # endif - float3 landNormalRGB2 = landNormal2.rgb; - float landNormalAlpha2 = landNormal2.a; - # if defined(SNOW) && !defined(TRUE_PBR) - landSnowMask += LandscapeTexture1to4IsSnow.y * input.LandBlendWeights1.y * landSnowMask2; - # endif // SNOW - # if defined(TRUE_PBR) - float4 currentRMAOS = 0; - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1PBR) != 0) - { - // Sample RMAOS texture for layer 2 - # if defined(TERRAIN_VARIATION) - [branch] if (useTerrainVariation) { - currentRMAOS = StochasticSample1(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampLandRMAOS2Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); - } else { - currentRMAOS = TexLandRMAOS2Sampler.SampleBias(SampLandRMAOS2Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); - } - # else - currentRMAOS = TexLandRMAOS2Sampler.SampleBias(SampLandRMAOS2Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); - # endif - if ((PBRFlags & PBR::TerrainFlags::LandTile1HasGlint) != 0) { - glintParameters += input.LandBlendWeights1.y * LandscapeTexture2GlintParameters; - } - } - else - { - currentRMAOS = float4(1 - landNormal2.w, 0, 1, 0); - } - blendedRMAOS += currentRMAOS * weight; - # endif - blendedRGB += landColorRGB2 * weight; - blendedAlpha += landAlpha2 * weight; - blendedNormalRGB += landNormalRGB2 * weight; - blendedNormalAlpha += landNormalAlpha2 * weight; - } +// Sample layer 2 textures - use terrain variation if available and enabled +# if defined(TERRAIN_VARIATION) + float4 landColor2; + [branch] if (useTerrainVariation) + { + landColor2 = StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampLandColor2Sampler, uv, sharedOffset, dx, dy); + } + else + { + landColor2 = TexLandColor2Sampler.SampleBias(SampLandColor2Sampler, uv, SharedData::MipBias); + } +# else + float4 landColor2 = TexLandColor2Sampler.SampleBias(SampLandColor2Sampler, uv, SharedData::MipBias); +# endif + float3 landColorRGB2 = landColor2.rgb; +# if defined(TRUE_PBR) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1PBR) == 0) + { + landColorRGB2 = landColorRGB2 / Color::PBRLightingScale; + } +# endif + float landAlpha2 = landColor2.a; + float landSnowMask2 = GetLandSnowMaskValue(landColor2.w); + + // Sample normal texture for layer 2 +# if defined(TERRAIN_VARIATION) + float4 landNormal2; + [branch] if (useTerrainVariation) + { + landNormal2 = StochasticEffect(screenNoise, mipLevels[1], TexLandNormal2Sampler, SampLandNormal2Sampler, uv, sharedOffset, dx, dy); + } + else + { + landNormal2 = TexLandNormal2Sampler.SampleBias(SampLandNormal2Sampler, uv, SharedData::MipBias); + } +# else + float4 landNormal2 = TexLandNormal2Sampler.SampleBias(SampLandNormal2Sampler, uv, SharedData::MipBias); +# endif + float3 landNormalRGB2 = landNormal2.rgb; + float landNormalAlpha2 = landNormal2.a; +# if defined(SNOW) && !defined(TRUE_PBR) + landSnowMask += LandscapeTexture1to4IsSnow.y * input.LandBlendWeights1.y * landSnowMask2; +# endif // SNOW +# if defined(TRUE_PBR) + float4 currentRMAOS = 0; + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1PBR) != 0) + { + // Sample RMAOS texture for layer 2 +# if defined(TERRAIN_VARIATION) + [branch] if (useTerrainVariation) + { + currentRMAOS = StochasticSample1(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampLandRMAOS2Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); + } + else + { + currentRMAOS = TexLandRMAOS2Sampler.SampleBias(SampLandRMAOS2Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); + } +# else + currentRMAOS = TexLandRMAOS2Sampler.SampleBias(SampLandRMAOS2Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); +# endif + if ((PBRFlags & PBR::TerrainFlags::LandTile1HasGlint) != 0) { + glintParameters += input.LandBlendWeights1.y * LandscapeTexture2GlintParameters; + } + } + else + { + currentRMAOS = float4(1 - landNormal2.w, 0, 1, 0); + } + blendedRMAOS += currentRMAOS * weight; +# endif + blendedRGB += landColorRGB2 * weight; + blendedAlpha += landAlpha2 * weight; + blendedNormalRGB += landNormalRGB2 * weight; + blendedNormalAlpha += landNormalAlpha2 * weight; + } // Layer 3 (LandBlendWeights1.z) if (input.LandBlendWeights1.z > 0.01) { float weight = input.LandBlendWeights1.z * invwsum; - // Sample layer 3 textures - use terrain variation if available and enabled - # if defined(TERRAIN_VARIATION) - float4 landColor3; - [branch] if (useTerrainVariation) { - landColor3 = StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampLandColor3Sampler, uv, sharedOffset, dx, dy); - } else { - landColor3 = TexLandColor3Sampler.SampleBias(SampLandColor3Sampler, uv, SharedData::MipBias); - } - # else - float4 landColor3 = TexLandColor3Sampler.SampleBias(SampLandColor3Sampler, uv, SharedData::MipBias); - # endif - float3 landColorRGB3 = landColor3.rgb; - # if defined(TRUE_PBR) - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2PBR) == 0) - { - landColorRGB3 = landColorRGB3 / Color::PBRLightingScale; - } - # endif - float landAlpha3 = landColor3.a; - float landSnowMask3 = GetLandSnowMaskValue(landColor3.w); - - // Sample normal texture for layer 3 - # if defined(TERRAIN_VARIATION) - float4 landNormal3; - [branch] if (useTerrainVariation) { - landNormal3 = StochasticEffect(screenNoise, mipLevels[2], TexLandNormal3Sampler, SampLandNormal3Sampler, uv, sharedOffset, dx, dy); - } else { - landNormal3 = TexLandNormal3Sampler.SampleBias(SampLandNormal3Sampler, uv, SharedData::MipBias); - } - # else - float4 landNormal3 = TexLandNormal3Sampler.SampleBias(SampLandNormal3Sampler, uv, SharedData::MipBias); - # endif - float3 landNormalRGB3 = landNormal3.rgb; - float landNormalAlpha3 = landNormal3.a; - # if defined(SNOW) && !defined(TRUE_PBR) - landSnowMask += LandscapeTexture1to4IsSnow.z * input.LandBlendWeights1.z * landSnowMask3; - # endif // SNOW - - # if defined(TRUE_PBR) - float4 currentRMAOS = 0; - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2PBR) != 0) - { - // Sample RMAOS texture for layer 3 - # if defined(TERRAIN_VARIATION) - [branch] if (useTerrainVariation) { - currentRMAOS = StochasticSample1(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampLandRMAOS3Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); - } else { - currentRMAOS = TexLandRMAOS3Sampler.SampleBias(SampLandRMAOS3Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); - } - # else - currentRMAOS = TexLandRMAOS3Sampler.SampleBias(SampLandRMAOS3Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); - # endif - if ((PBRFlags & PBR::TerrainFlags::LandTile2HasGlint) != 0) { - glintParameters += input.LandBlendWeights1.z * LandscapeTexture3GlintParameters; - } - } - else - { - currentRMAOS = float4(1 - landNormal3.w, 0, 1, 0); - } - blendedRMAOS += currentRMAOS * weight; - # endif - blendedRGB += landColorRGB3 * weight; - blendedAlpha += landAlpha3 * weight; - blendedNormalRGB += landNormalRGB3 * weight; - blendedNormalAlpha += landNormalAlpha3 * weight; - } +// Sample layer 3 textures - use terrain variation if available and enabled +# if defined(TERRAIN_VARIATION) + float4 landColor3; + [branch] if (useTerrainVariation) + { + landColor3 = StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampLandColor3Sampler, uv, sharedOffset, dx, dy); + } + else + { + landColor3 = TexLandColor3Sampler.SampleBias(SampLandColor3Sampler, uv, SharedData::MipBias); + } +# else + float4 landColor3 = TexLandColor3Sampler.SampleBias(SampLandColor3Sampler, uv, SharedData::MipBias); +# endif + float3 landColorRGB3 = landColor3.rgb; +# if defined(TRUE_PBR) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2PBR) == 0) + { + landColorRGB3 = landColorRGB3 / Color::PBRLightingScale; + } +# endif + float landAlpha3 = landColor3.a; + float landSnowMask3 = GetLandSnowMaskValue(landColor3.w); + + // Sample normal texture for layer 3 +# if defined(TERRAIN_VARIATION) + float4 landNormal3; + [branch] if (useTerrainVariation) + { + landNormal3 = StochasticEffect(screenNoise, mipLevels[2], TexLandNormal3Sampler, SampLandNormal3Sampler, uv, sharedOffset, dx, dy); + } + else + { + landNormal3 = TexLandNormal3Sampler.SampleBias(SampLandNormal3Sampler, uv, SharedData::MipBias); + } +# else + float4 landNormal3 = TexLandNormal3Sampler.SampleBias(SampLandNormal3Sampler, uv, SharedData::MipBias); +# endif + float3 landNormalRGB3 = landNormal3.rgb; + float landNormalAlpha3 = landNormal3.a; +# if defined(SNOW) && !defined(TRUE_PBR) + landSnowMask += LandscapeTexture1to4IsSnow.z * input.LandBlendWeights1.z * landSnowMask3; +# endif // SNOW + +# if defined(TRUE_PBR) + float4 currentRMAOS = 0; + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2PBR) != 0) + { + // Sample RMAOS texture for layer 3 +# if defined(TERRAIN_VARIATION) + [branch] if (useTerrainVariation) + { + currentRMAOS = StochasticSample1(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampLandRMAOS3Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); + } + else + { + currentRMAOS = TexLandRMAOS3Sampler.SampleBias(SampLandRMAOS3Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); + } +# else + currentRMAOS = TexLandRMAOS3Sampler.SampleBias(SampLandRMAOS3Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); +# endif + if ((PBRFlags & PBR::TerrainFlags::LandTile2HasGlint) != 0) { + glintParameters += input.LandBlendWeights1.z * LandscapeTexture3GlintParameters; + } + } + else + { + currentRMAOS = float4(1 - landNormal3.w, 0, 1, 0); + } + blendedRMAOS += currentRMAOS * weight; +# endif + blendedRGB += landColorRGB3 * weight; + blendedAlpha += landAlpha3 * weight; + blendedNormalRGB += landNormalRGB3 * weight; + blendedNormalAlpha += landNormalAlpha3 * weight; + } // Layer 4 (LandBlendWeights1.w) if (input.LandBlendWeights1.w > 0.01) { float weight = input.LandBlendWeights1.w * invwsum; - // Sample layer 4 textures - use terrain variation if available and enabled - # if defined(TERRAIN_VARIATION) - float4 landColor4; - [branch] if (useTerrainVariation) { - landColor4 = StochasticEffect(screenNoise, mipLevels[3], TexLandColor4Sampler, SampLandColor4Sampler, uv, sharedOffset, dx, dy); - } else { - landColor4 = TexLandColor4Sampler.SampleBias(SampLandColor4Sampler, uv, SharedData::MipBias); - } - # else - float4 landColor4 = TexLandColor4Sampler.SampleBias(SampLandColor4Sampler, uv, SharedData::MipBias); - # endif - float3 landColorRGB4 = landColor4.rgb; - # if defined(TRUE_PBR) - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3PBR) == 0) - { - landColorRGB4 = landColorRGB4 / Color::PBRLightingScale; - } - # endif - float landAlpha4 = landColor4.a; - float landSnowMask4 = GetLandSnowMaskValue(landColor4.w); - - // Sample normal texture for layer 4 - # if defined(TERRAIN_VARIATION) - float4 landNormal4; - [branch] if (useTerrainVariation) { - landNormal4 = StochasticEffect(screenNoise, mipLevels[3], TexLandNormal4Sampler, SampLandNormal4Sampler, uv, sharedOffset, dx, dy); - } else { - landNormal4 = TexLandNormal4Sampler.SampleBias(SampLandNormal4Sampler, uv, SharedData::MipBias); - } - # else - float4 landNormal4 = TexLandNormal4Sampler.SampleBias(SampLandNormal4Sampler, uv, SharedData::MipBias); - # endif - float3 landNormalRGB4 = landNormal4.rgb; - float landNormalAlpha4 = landNormal4.a; - # if defined(SNOW) && !defined(TRUE_PBR) - landSnowMask += LandscapeTexture1to4IsSnow.w * input.LandBlendWeights1.w * landSnowMask4; - # endif // SNOW - - # if defined(TRUE_PBR) - float4 currentRMAOS = 0; - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3PBR) != 0) - { - // Sample RMAOS texture for layer 4 - # if defined(TERRAIN_VARIATION) - [branch] if (useTerrainVariation) { - currentRMAOS = StochasticSample1(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampLandRMAOS4Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); - } else { - currentRMAOS = TexLandRMAOS4Sampler.SampleBias(SampLandRMAOS4Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); - } - # else - currentRMAOS = TexLandRMAOS4Sampler.SampleBias(SampLandRMAOS4Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); - # endif - if ((PBRFlags & PBR::TerrainFlags::LandTile3HasGlint) != 0) { - glintParameters += input.LandBlendWeights1.w * LandscapeTexture4GlintParameters; - } - } - else - { - currentRMAOS = float4(1 - landNormal4.w, 0, 1, 0); - } - blendedRMAOS += currentRMAOS * weight; - # endif - blendedRGB += landColorRGB4 * weight; - blendedAlpha += landAlpha4 * weight; - blendedNormalRGB += landNormalRGB4 * weight; - blendedNormalAlpha += landNormalAlpha4 * weight; +// Sample layer 4 textures - use terrain variation if available and enabled +# if defined(TERRAIN_VARIATION) + float4 landColor4; + [branch] if (useTerrainVariation) + { + landColor4 = StochasticEffect(screenNoise, mipLevels[3], TexLandColor4Sampler, SampLandColor4Sampler, uv, sharedOffset, dx, dy); + } + else + { + landColor4 = TexLandColor4Sampler.SampleBias(SampLandColor4Sampler, uv, SharedData::MipBias); + } +# else + float4 landColor4 = TexLandColor4Sampler.SampleBias(SampLandColor4Sampler, uv, SharedData::MipBias); +# endif + float3 landColorRGB4 = landColor4.rgb; +# if defined(TRUE_PBR) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3PBR) == 0) + { + landColorRGB4 = landColorRGB4 / Color::PBRLightingScale; + } +# endif + float landAlpha4 = landColor4.a; + float landSnowMask4 = GetLandSnowMaskValue(landColor4.w); + + // Sample normal texture for layer 4 +# if defined(TERRAIN_VARIATION) + float4 landNormal4; + [branch] if (useTerrainVariation) + { + landNormal4 = StochasticEffect(screenNoise, mipLevels[3], TexLandNormal4Sampler, SampLandNormal4Sampler, uv, sharedOffset, dx, dy); + } + else + { + landNormal4 = TexLandNormal4Sampler.SampleBias(SampLandNormal4Sampler, uv, SharedData::MipBias); + } +# else + float4 landNormal4 = TexLandNormal4Sampler.SampleBias(SampLandNormal4Sampler, uv, SharedData::MipBias); +# endif + float3 landNormalRGB4 = landNormal4.rgb; + float landNormalAlpha4 = landNormal4.a; +# if defined(SNOW) && !defined(TRUE_PBR) + landSnowMask += LandscapeTexture1to4IsSnow.w * input.LandBlendWeights1.w * landSnowMask4; +# endif // SNOW + +# if defined(TRUE_PBR) + float4 currentRMAOS = 0; + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3PBR) != 0) + { + // Sample RMAOS texture for layer 4 +# if defined(TERRAIN_VARIATION) + [branch] if (useTerrainVariation) + { + currentRMAOS = StochasticSample1(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampLandRMAOS4Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); + } + else + { + currentRMAOS = TexLandRMAOS4Sampler.SampleBias(SampLandRMAOS4Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); + } +# else + currentRMAOS = TexLandRMAOS4Sampler.SampleBias(SampLandRMAOS4Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); +# endif + if ((PBRFlags & PBR::TerrainFlags::LandTile3HasGlint) != 0) { + glintParameters += input.LandBlendWeights1.w * LandscapeTexture4GlintParameters; } + } + else + { + currentRMAOS = float4(1 - landNormal4.w, 0, 1, 0); + } + blendedRMAOS += currentRMAOS * weight; +# endif + blendedRGB += landColorRGB4 * weight; + blendedAlpha += landAlpha4 * weight; + blendedNormalRGB += landNormalRGB4 * weight; + blendedNormalAlpha += landNormalAlpha4 * weight; + } // Layer 5 (LandBlendWeights2.x) if (input.LandBlendWeights2.x > 0.01) { float weight = input.LandBlendWeights2.x * invwsum; - // Sample layer 5 textures - use terrain variation if available and enabled - # if defined(TERRAIN_VARIATION) - float4 landColor5; - [branch] if (useTerrainVariation) { - landColor5 = StochasticEffect(screenNoise, mipLevels[4], TexLandColor5Sampler, SampLandColor5Sampler, uv, sharedOffset, dx, dy); - } else { - landColor5 = TexLandColor5Sampler.SampleBias(SampLandColor5Sampler, uv, SharedData::MipBias); - } - # else - float4 landColor5 = TexLandColor5Sampler.SampleBias(SampLandColor5Sampler, uv, SharedData::MipBias); - # endif - float3 landColorRGB5 = landColor5.rgb; - # if defined(TRUE_PBR) - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4PBR) == 0) - { - landColorRGB5 = landColorRGB5 / Color::PBRLightingScale; - } - # endif - float landAlpha5 = landColor5.a; - float landSnowMask5 = GetLandSnowMaskValue(landColor5.w); - - // Sample normal texture for layer 5 - # if defined(TERRAIN_VARIATION) - float4 landNormal5; - [branch] if (useTerrainVariation) { - landNormal5 = StochasticEffect(screenNoise, mipLevels[4], TexLandNormal5Sampler, SampLandNormal5Sampler, uv, sharedOffset, dx, dy); - } else { - landNormal5 = TexLandNormal5Sampler.SampleBias(SampLandNormal5Sampler, uv, SharedData::MipBias); - } - # else - float4 landNormal5 = TexLandNormal5Sampler.SampleBias(SampLandNormal5Sampler, uv, SharedData::MipBias); - # endif - float3 landNormalRGB5 = landNormal5.rgb; - float landNormalAlpha5 = landNormal5.a; - - # if defined(SNOW) && !defined(TRUE_PBR) - landSnowMask += LandscapeTexture5to6IsSnow.x * input.LandBlendWeights2.x * landSnowMask5; - # endif // SNOW - - # if defined(TRUE_PBR) - float4 currentRMAOS = 0; - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4PBR) != 0) - { - // Sample RMAOS texture for layer 5 - # if defined(TERRAIN_VARIATION) - [branch] if (useTerrainVariation) { - currentRMAOS = StochasticSample1(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampLandRMAOS5Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); - } else { - currentRMAOS = TexLandRMAOS5Sampler.SampleBias(SampLandRMAOS5Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); - } - # else - currentRMAOS = TexLandRMAOS5Sampler.SampleBias(SampLandRMAOS5Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); - # endif - if ((PBRFlags & PBR::TerrainFlags::LandTile4HasGlint) != 0) { - glintParameters += input.LandBlendWeights2.x * LandscapeTexture5GlintParameters; - } - } - else - { - currentRMAOS = float4(1 - landNormal5.w, 0, 1, 0); - } - blendedRMAOS += currentRMAOS * weight; - # endif - blendedRGB += landColorRGB5 * weight; - blendedAlpha += landAlpha5 * weight; - blendedNormalRGB += landNormalRGB5 * weight; - blendedNormalAlpha += landNormalAlpha5 * weight; +// Sample layer 5 textures - use terrain variation if available and enabled +# if defined(TERRAIN_VARIATION) + float4 landColor5; + [branch] if (useTerrainVariation) + { + landColor5 = StochasticEffect(screenNoise, mipLevels[4], TexLandColor5Sampler, SampLandColor5Sampler, uv, sharedOffset, dx, dy); + } + else + { + landColor5 = TexLandColor5Sampler.SampleBias(SampLandColor5Sampler, uv, SharedData::MipBias); + } +# else + float4 landColor5 = TexLandColor5Sampler.SampleBias(SampLandColor5Sampler, uv, SharedData::MipBias); +# endif + float3 landColorRGB5 = landColor5.rgb; +# if defined(TRUE_PBR) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4PBR) == 0) + { + landColorRGB5 = landColorRGB5 / Color::PBRLightingScale; + } +# endif + float landAlpha5 = landColor5.a; + float landSnowMask5 = GetLandSnowMaskValue(landColor5.w); + + // Sample normal texture for layer 5 +# if defined(TERRAIN_VARIATION) + float4 landNormal5; + [branch] if (useTerrainVariation) + { + landNormal5 = StochasticEffect(screenNoise, mipLevels[4], TexLandNormal5Sampler, SampLandNormal5Sampler, uv, sharedOffset, dx, dy); + } + else + { + landNormal5 = TexLandNormal5Sampler.SampleBias(SampLandNormal5Sampler, uv, SharedData::MipBias); + } +# else + float4 landNormal5 = TexLandNormal5Sampler.SampleBias(SampLandNormal5Sampler, uv, SharedData::MipBias); +# endif + float3 landNormalRGB5 = landNormal5.rgb; + float landNormalAlpha5 = landNormal5.a; + +# if defined(SNOW) && !defined(TRUE_PBR) + landSnowMask += LandscapeTexture5to6IsSnow.x * input.LandBlendWeights2.x * landSnowMask5; +# endif // SNOW + +# if defined(TRUE_PBR) + float4 currentRMAOS = 0; + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4PBR) != 0) + { + // Sample RMAOS texture for layer 5 +# if defined(TERRAIN_VARIATION) + [branch] if (useTerrainVariation) + { + currentRMAOS = StochasticSample1(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampLandRMAOS5Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); + } + else + { + currentRMAOS = TexLandRMAOS5Sampler.SampleBias(SampLandRMAOS5Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); + } +# else + currentRMAOS = TexLandRMAOS5Sampler.SampleBias(SampLandRMAOS5Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); +# endif + if ((PBRFlags & PBR::TerrainFlags::LandTile4HasGlint) != 0) { + glintParameters += input.LandBlendWeights2.x * LandscapeTexture5GlintParameters; } + } + else + { + currentRMAOS = float4(1 - landNormal5.w, 0, 1, 0); + } + blendedRMAOS += currentRMAOS * weight; +# endif + blendedRGB += landColorRGB5 * weight; + blendedAlpha += landAlpha5 * weight; + blendedNormalRGB += landNormalRGB5 * weight; + blendedNormalAlpha += landNormalAlpha5 * weight; + } // Layer 6 (LandBlendWeights2.y) if (input.LandBlendWeights2.y > 0.01) { float weight = input.LandBlendWeights2.y * invwsum; - // Sample layer 6 textures - use terrain variation if available and enabled - # if defined(TERRAIN_VARIATION) - float4 landColor6; - [branch] if (useTerrainVariation) { - landColor6 = StochasticEffect(screenNoise, mipLevels[5], TexLandColor6Sampler, SampLandColor6Sampler, uv, sharedOffset, dx, dy); - } else { - landColor6 = TexLandColor6Sampler.SampleBias(SampLandColor6Sampler, uv, SharedData::MipBias); - } - # else - float4 landColor6 = TexLandColor6Sampler.SampleBias(SampLandColor6Sampler, uv, SharedData::MipBias); - # endif - float3 landColorRGB6 = landColor6.rgb; - # if defined(TRUE_PBR) - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5PBR) == 0) - { - landColorRGB6 = landColorRGB6 / Color::PBRLightingScale; - } - # endif - float landAlpha6 = landColor6.a; - float landSnowMask6 = GetLandSnowMaskValue(landColor6.w); - - // Sample normal texture for layer 6 - # if defined(TERRAIN_VARIATION) - float4 landNormal6; - [branch] if (useTerrainVariation) { - landNormal6 = StochasticEffect(screenNoise, mipLevels[5], TexLandNormal6Sampler, SampLandNormal6Sampler, uv, sharedOffset, dx, dy); - } else { - landNormal6 = TexLandNormal6Sampler.SampleBias(SampLandNormal6Sampler, uv, SharedData::MipBias); - } - # else - float4 landNormal6 = TexLandNormal6Sampler.SampleBias(SampLandNormal6Sampler, uv, SharedData::MipBias); - # endif - float3 landNormalRGB6 = landNormal6.rgb; - float landNormalAlpha6 = landNormal6.a; - # if defined(SNOW) && !defined(TRUE_PBR) - landSnowMask += LandscapeTexture5to6IsSnow.y * input.LandBlendWeights2.y * landSnowMask6; - # endif // SNOW - - # if defined(TRUE_PBR) - float4 currentRMAOS = 0; - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5PBR) != 0) - { // Sample RMAOS texture for layer 6 - # if defined(TERRAIN_VARIATION) - [branch] if (useTerrainVariation) { - currentRMAOS = StochasticSample1(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampLandRMAOS6Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); - } else { - currentRMAOS = TexLandRMAOS6Sampler.SampleBias(SampLandRMAOS6Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); - } - # else - currentRMAOS = TexLandRMAOS6Sampler.SampleBias(SampLandRMAOS6Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); - # endif - if ((PBRFlags & PBR::TerrainFlags::LandTile5HasGlint) != 0) { - glintParameters += input.LandBlendWeights2.y * LandscapeTexture6GlintParameters; - } - } - else - { - currentRMAOS = float4(1 - landNormal6.w, 0, 1, 0); - } - blendedRMAOS += currentRMAOS * weight; +// Sample layer 6 textures - use terrain variation if available and enabled +# if defined(TERRAIN_VARIATION) + float4 landColor6; + [branch] if (useTerrainVariation) + { + landColor6 = StochasticEffect(screenNoise, mipLevels[5], TexLandColor6Sampler, SampLandColor6Sampler, uv, sharedOffset, dx, dy); + } + else + { + landColor6 = TexLandColor6Sampler.SampleBias(SampLandColor6Sampler, uv, SharedData::MipBias); + } +# else + float4 landColor6 = TexLandColor6Sampler.SampleBias(SampLandColor6Sampler, uv, SharedData::MipBias); +# endif + float3 landColorRGB6 = landColor6.rgb; +# if defined(TRUE_PBR) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5PBR) == 0) + { + landColorRGB6 = landColorRGB6 / Color::PBRLightingScale; + } +# endif + float landAlpha6 = landColor6.a; + float landSnowMask6 = GetLandSnowMaskValue(landColor6.w); + + // Sample normal texture for layer 6 +# if defined(TERRAIN_VARIATION) + float4 landNormal6; + [branch] if (useTerrainVariation) + { + landNormal6 = StochasticEffect(screenNoise, mipLevels[5], TexLandNormal6Sampler, SampLandNormal6Sampler, uv, sharedOffset, dx, dy); + } + else + { + landNormal6 = TexLandNormal6Sampler.SampleBias(SampLandNormal6Sampler, uv, SharedData::MipBias); + } +# else + float4 landNormal6 = TexLandNormal6Sampler.SampleBias(SampLandNormal6Sampler, uv, SharedData::MipBias); # endif - blendedRGB += landColorRGB6 * weight; - blendedAlpha += landAlpha6 * weight; - blendedNormalRGB += landNormalRGB6 * weight; - blendedNormalAlpha += landNormalAlpha6 * weight; + float3 landNormalRGB6 = landNormal6.rgb; + float landNormalAlpha6 = landNormal6.a; +# if defined(SNOW) && !defined(TRUE_PBR) + landSnowMask += LandscapeTexture5to6IsSnow.y * input.LandBlendWeights2.y * landSnowMask6; +# endif // SNOW + +# if defined(TRUE_PBR) + float4 currentRMAOS = 0; + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5PBR) != 0) + { // Sample RMAOS texture for layer 6 +# if defined(TERRAIN_VARIATION) + [branch] if (useTerrainVariation) + { + currentRMAOS = StochasticSample1(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampLandRMAOS6Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); + } + else + { + currentRMAOS = TexLandRMAOS6Sampler.SampleBias(SampLandRMAOS6Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); + } +# else + currentRMAOS = TexLandRMAOS6Sampler.SampleBias(SampLandRMAOS6Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); +# endif + if ((PBRFlags & PBR::TerrainFlags::LandTile5HasGlint) != 0) { + glintParameters += input.LandBlendWeights2.y * LandscapeTexture6GlintParameters; } - float4 rawBaseColor = float4(blendedRGB, blendedAlpha); - baseColor = float4(Color::Diffuse(blendedRGB), blendedAlpha); - normal = float4(blendedNormalRGB, blendedNormalAlpha); - # if defined(TRUE_PBR) - rawRMAOS = blendedRMAOS; - # endif -# else // Non-landscape code + } + else + { + currentRMAOS = float4(1 - landNormal6.w, 0, 1, 0); + } + blendedRMAOS += currentRMAOS * weight; +# endif + blendedRGB += landColorRGB6 * weight; + blendedAlpha += landAlpha6 * weight; + blendedNormalRGB += landNormalRGB6 * weight; + blendedNormalAlpha += landNormalAlpha6 * weight; + } + float4 rawBaseColor = float4(blendedRGB, blendedAlpha); + baseColor = float4(Color::Diffuse(blendedRGB), blendedAlpha); + normal = float4(blendedNormalRGB, blendedNormalAlpha); +# if defined(TRUE_PBR) + rawRMAOS = blendedRMAOS; +# endif +# else // Non-landscape code float4 rawBaseColor = TexColorSampler.SampleBias(SampColorSampler, diffuseUv, SharedData::MipBias); baseColor = float4(Color::Diffuse(rawBaseColor.rgb), rawBaseColor.a); float4 normalColor = TexNormalSampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias); normal = normalColor; # if defined(TRUE_PBR) - rawRMAOS = TexRMAOSSampler.SampleBias(SampRMAOSSampler, diffuseUv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + rawRMAOS = TexRMAOSSampler.SampleBias(SampRMAOSSampler, diffuseUv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); # endif # endif @@ -2295,40 +2356,43 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif # if defined(EMAT) && (defined(SKINNED) || !defined(MODELSPACENORMALS)) - [branch] if (inWorld && SharedData::extendedMaterialSettings.EnableShadows) - { - float3 dirLightDirectionTS = mul(refractedDirLightDirection, tbn).xyz; + [branch] if (inWorld && SharedData::extendedMaterialSettings.EnableShadows) + { + float3 dirLightDirectionTS = mul(refractedDirLightDirection, tbn).xyz; # if defined(LANDSCAPE) - [branch] if (SharedData::extendedMaterialSettings.EnableTerrainParallax) - { + [branch] if (SharedData::extendedMaterialSettings.EnableTerrainParallax) + { # if defined(TERRAIN_VARIATION) - [branch] if (useTerrainVariation) { - float weights[6]; - sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); + [branch] if (useTerrainVariation) + { + float weights[6]; + sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); - parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dx, dy); - } else { - float weights[6]; - sh0 = ExtendedMaterials::GetTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); + parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dx, dy); + } + else + { + float weights[6]; + sh0 = ExtendedMaterials::GetTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); - parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams); - } + parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams); + } # else - // Standard terrain parallax shadow without stochastic sampling - parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams); + // Standard terrain parallax shadow without stochastic sampling + parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams); # endif - } + } # elif defined(PARALLAX) - [branch] if (SharedData::extendedMaterialSettings.EnableParallax) - parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplier(uv, mipLevel, dirLightDirectionTS, sh0, TexParallaxSampler, SampParallaxSampler, 0, lerp(parallaxShadowQuality, 1.0, SharedData::extendedMaterialSettings.ExtendShadows), screenNoise, displacementParams); + [branch] if (SharedData::extendedMaterialSettings.EnableParallax) + parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplier(uv, mipLevel, dirLightDirectionTS, sh0, TexParallaxSampler, SampParallaxSampler, 0, lerp(parallaxShadowQuality, 1.0, SharedData::extendedMaterialSettings.ExtendShadows), screenNoise, displacementParams); # elif defined(EMAT_ENVMAP) - [branch] if (complexMaterialParallax) - parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplier(uv, mipLevel, dirLightDirectionTS, sh0, TexEnvMaskSampler, SampEnvMaskSampler, 3, lerp(parallaxShadowQuality, 1.0, SharedData::extendedMaterialSettings.ExtendShadows), screenNoise, displacementParams); + [branch] if (complexMaterialParallax) + parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplier(uv, mipLevel, dirLightDirectionTS, sh0, TexEnvMaskSampler, SampEnvMaskSampler, 3, lerp(parallaxShadowQuality, 1.0, SharedData::extendedMaterialSettings.ExtendShadows), screenNoise, displacementParams); # elif defined(TRUE_PBR) && !defined(LODLANDSCAPE) - [branch] if (PBRParallax) - parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplier(uv, mipLevel, dirLightDirectionTS, sh0, TexParallaxSampler, SampParallaxSampler, 0, lerp(parallaxShadowQuality, 1.0, SharedData::extendedMaterialSettings.ExtendShadows), screenNoise, displacementParams); + [branch] if (PBRParallax) + parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplier(uv, mipLevel, dirLightDirectionTS, sh0, TexParallaxSampler, SampParallaxSampler, 0, lerp(parallaxShadowQuality, 1.0, SharedData::extendedMaterialSettings.ExtendShadows), screenNoise, displacementParams); # endif // LANDSCAPE - } + } # endif // defined(EMAT) && (defined(SKINNED) || !defined(MODELSPACENORMALS)) if (dirShadow != 0.0 && (inWorld || inReflection)) diff --git a/src/Features/TerrainVariation.h b/src/Features/TerrainVariation.h index eb5a8eea38..3d771749e5 100644 --- a/src/Features/TerrainVariation.h +++ b/src/Features/TerrainVariation.h @@ -10,8 +10,10 @@ struct TerrainVariation : Feature virtual inline std::string GetName() override { return "Terrain Variation"; } virtual inline std::string GetShortName() override { return "TerrainVariation"; } virtual inline std::string GetFeatureModLink() override { return "https://www.nexusmods.com/skyrimspecialedition/mods/148123"; } - virtual inline std::string_view GetShaderDefineName() override { return "TERRAIN_VARIATION"; } virtual inline bool HasShaderDefine(RE::BSShader::Type shaderType) override { - return (shaderType == RE::BSShader::Type::Lighting); + virtual inline std::string_view GetShaderDefineName() override { return "TERRAIN_VARIATION"; } + virtual inline bool HasShaderDefine(RE::BSShader::Type shaderType) override + { + return (shaderType == RE::BSShader::Type::Lighting); } virtual bool IsCore() const override { return false; }; virtual bool SupportsVR() override { return true; } @@ -24,7 +26,7 @@ struct TerrainVariation : Feature Settings settings; bool showAdvanced = false; Settings defaultSettings = { - true, // enableTilingFix + true, // enableTilingFix }; virtual void DrawSettings() override; From 0c8d34223aa1dd6385847e98dfa25676fd9f80ad Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Wed, 28 May 2025 22:39:38 +1000 Subject: [PATCH 09/53] LOD v1 --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 9 +- .../TerrainVariation/TerrainVariation.hlsli | 100 ++++++++++++++++++ package/Shaders/Common/SharedData.hlsli | 6 +- package/Shaders/Lighting.hlsl | 44 ++++++-- src/Features/TerrainVariation.cpp | 23 +++- src/Features/TerrainVariation.h | 27 ++--- 6 files changed, 177 insertions(+), 32 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index 1241fea105..d59c94b868 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -301,7 +301,8 @@ namespace ExtendedMaterials } total += h * weights[2]; weights[2] *= pow(heightBlend, HEIGHT_MULT * h); - } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) { float h; # if defined(TERRAIN_VARIATION) @@ -315,7 +316,8 @@ namespace ExtendedMaterials # endif total += h * weights[3]; weights[3] *= pow(heightBlend, HEIGHT_MULT * h); - } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) { float h; # if defined(TERRAIN_VARIATION) @@ -329,7 +331,8 @@ namespace ExtendedMaterials # endif total += h * weights[4]; weights[4] *= pow(heightBlend, HEIGHT_MULT * h); - } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) { float h; # if defined(TERRAIN_VARIATION) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index afc512842d..dd42f5d2d2 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -44,6 +44,37 @@ inline float2 ComputeStochasticOffsets1(float2 UV) return hash2D2D(firstVertexID); } +inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 UV) +{ + // Use a much smaller scale factor for LOD terrain to create subtle variation + // instead of dramatic pattern changes + float2 skewUV = mul(float2x2(1.0, 0.0, -0.57735027, 1.15470054), UV * 1.5); + float2 vxID = floor(skewUV); + float3 barry = float3(frac(skewUV), 0.0); + barry.z = 1.0 - barry.x - barry.y; + + // Create a more stable triangle pattern + float4x3 BW_vx = (barry.z > 0) ? + float4x3(float3(vxID, 0), float3(vxID + float2(0, 1), 0), float3(vxID + float2(1, 0), 0), barry.zyx) : + float4x3(float3(vxID + float2(1, 1), 0), float3(vxID + float2(1, 0), 0), float3(vxID + float2(0, 1), 0), float3(-barry.z, 1.0 - barry.y, 1.0 - barry.x)); + + // Generate smaller offsets for more subtle variation + StochasticOffsets offsetsLOD; + offsetsLOD.offset1 = hash2D2D(BW_vx[0].xy) * 0.15; // Reduced offset magnitude + offsetsLOD.offset2 = hash2D2D(BW_vx[1].xy) * 0.15; + offsetsLOD.offset3 = hash2D2D(BW_vx[2].xy) * 0.15; + + // Use smoother weights with less contrast + float3 smoothWeights = BW_vx[3]; + // Apply mild smoothing to weights + smoothWeights = pow(smoothWeights, 0.8); + // Renormalize + smoothWeights /= (smoothWeights.x + smoothWeights.y + smoothWeights.z); + + offsetsLOD.weights = smoothWeights; + return offsetsLOD; +} + // Compute offsets for stochastic sampling inline StochasticOffsets ComputeStochasticOffsets(float2 UV) { @@ -105,11 +136,13 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler return result; } +// Cheap Stochastic Effect for single sample. Used for RMAOS. inline float4 StochasticSample1(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for RMAOS (maybe LOD in future) { return tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); } +// Same as StochasticEffect but no height/luminescence influence, so much cheaper but worse quality, doesn't matter for the use case. inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for parallaxcoords & getheight funct. { // Sample the three texture offsets using the provided mip level @@ -125,4 +158,71 @@ inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, Sample return result; } +// Special version for LOD mask textures that should have minimal blurring +inline float4 StochasticSampleLODMask(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) +{ + float offsetScale = 0.04; + + // Add simple rotation to each offset (using the random value to vary rotation per pixel) + float angle1 = rnd * 3.14; // Random base angle between 0-2π + float angle2 = angle1 + 1.04; // ~120° offset + float angle3 = angle1 + 2.09; // ~240° offset + + // Create rotation matrices + float2x2 rot1 = float2x2(cos(angle1), -sin(angle1), sin(angle1), cos(angle1)); + float2x2 rot2 = float2x2(cos(angle2), -sin(angle2), sin(angle2), cos(angle2)); + float2x2 rot3 = float2x2(cos(angle3), -sin(angle3), sin(angle3), cos(angle3)); + + // Apply rotation to offsets before scaling them down + float2 microOffset1 = mul(rot1, offsets.offset1) * offsetScale; + float2 microOffset2 = mul(rot2, offsets.offset2) * offsetScale; + float2 microOffset3 = mul(rot3, offsets.offset3) * offsetScale; + + // Sample with rotated micro-offsets + float tinyMipBias = 0.05; + float4 sample1 = tex.SampleLevel(samp, uv + microOffset1, mipLevel + tinyMipBias); + float4 sample2 = tex.SampleLevel(samp, uv + microOffset2, mipLevel + tinyMipBias); + float4 sample3 = tex.SampleLevel(samp, uv + microOffset3, mipLevel + tinyMipBias); + + // Blend using the barycentric weights (unchanged) + float4 result = sample1 * offsets.weights.x + + sample2 * offsets.weights.y + + sample3 * offsets.weights.z; + + return result; +} + +// Stochastic sampling function for Full Terrain LOD. Uses rotated offsets for more variation. +inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) +{ + float offsetScale = 0.15; + + // Add simple rotation to each offset (using the random value to vary rotation per pixel) + float angle1 = rnd * 6.28; // Random base angle between 0-2π + float angle2 = angle1 + 2.09; // ~120° offset + float angle3 = angle1 + 4.18; // ~240° offset + + // Create rotation matrices + float2x2 rot1 = float2x2(cos(angle1), -sin(angle1), sin(angle1), cos(angle1)); + float2x2 rot2 = float2x2(cos(angle2), -sin(angle2), sin(angle2), cos(angle2)); + float2x2 rot3 = float2x2(cos(angle3), -sin(angle3), sin(angle3), cos(angle3)); + + // Apply rotation to offsets before scaling them down + float2 microOffset1 = mul(rot1, offsets.offset1) * offsetScale; + float2 microOffset2 = mul(rot2, offsets.offset2) * offsetScale; + float2 microOffset3 = mul(rot3, offsets.offset3) * offsetScale; + + // Sample with rotated micro-offsets (everything else stays the same) + float4 sample1 = tex.SampleLevel(samp, uv + microOffset1, mipLevel); + float4 sample2 = tex.SampleLevel(samp, uv + microOffset2, mipLevel); + float4 sample3 = tex.SampleLevel(samp, uv + microOffset3, mipLevel); + + // Blend using the barycentric weights (unchanged) + float4 result = sample1 * offsets.weights.x + + sample2 * offsets.weights.y + + sample3 * offsets.weights.z; + + return result; +} + #endif // TERRAIN_VARIATION_HLSLI \ No newline at end of file diff --git a/package/Shaders/Common/SharedData.hlsli b/package/Shaders/Common/SharedData.hlsli index f5639513a9..f98bd13266 100644 --- a/package/Shaders/Common/SharedData.hlsli +++ b/package/Shaders/Common/SharedData.hlsli @@ -160,11 +160,11 @@ namespace SharedData float BaseColorMult; float pad; }; - - struct TerrainVariationSettings + struct TerrainVariationSettings { bool enableTilingFix; - float3 pad0; + bool enableLODTerrainTilingFix; + float2 pad0; }; struct IBLSettings diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 41b8786031..71daff54c8 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1800,13 +1800,24 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(LOD_BLENDING) # if defined(LODOBJECTS) || defined(LODOBJECTSHD) - baseColor.xyz *= SharedData::lodBlendingSettings.LODObjectBrightness; + baseColor.xyz *= SharedData::lodBlendingSettings.LODObjectBrightness; # elif defined(LODLANDSCAPE) - baseColor.xyz *= SharedData::lodBlendingSettings.LODTerrainBrightness; + // First apply terrain variation if enabled + # if defined(TERRAIN_VARIATION) + if (SharedData::terrainVariationSettings.enableLODTerrainTilingFix) { + float2 dx = ddx(uv); + float2 dy = ddy(uv); + StochasticOffsets lodOffset = ComputeStochasticOffsetsLOD(uv); + float4 lodStochasticColor = StochasticSampleLOD(screenNoise, 0, TexColorSampler, SampColorSampler, uv, lodOffset, dx, dy); + + // Apply the stochastic result directly + baseColor.xyz = Color::Diffuse(lodStochasticColor.rgb); + } + # endif + baseColor.xyz *= SharedData::lodBlendingSettings.LODTerrainBrightness; # endif # endif // LOD_BLENDING - //float landSnowMask1 = GetLandSnowMaskValue(baseColor.w); # if defined(MODELSPACENORMALS) # if defined(LODLANDNOISE) @@ -1874,10 +1885,27 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif # if defined(LOD_LAND_BLEND) - float4 lodLandColor = TexLandLodBlend1Sampler.Sample(SampLandLodBlend1Sampler, input.TexCoord0.zw); + float4 lodLandColor; + + # if defined(TERRAIN_VARIATION) + if (SharedData::terrainVariationSettings.enableLODTerrainTilingFix) { + // Apply stochastic sampling to LOD_LAND_BLEND color texture + float2 blendColorUV = input.TexCoord0.zw; + float2 dx = ddx(blendColorUV); + float2 dy = ddy(blendColorUV); + StochasticOffsets lodBlendColorOffset = ComputeStochasticOffsetsLOD(blendColorUV); + lodLandColor = StochasticSampleLODMask(screenNoise, 0, TexLandLodBlend1Sampler, SampLandLodBlend1Sampler, blendColorUV, lodBlendColorOffset, dx, dy); + } else { + lodLandColor = TexLandLodBlend1Sampler.Sample(SampLandLodBlend1Sampler, input.TexCoord0.zw); + } + # else + lodLandColor = TexLandLodBlend1Sampler.Sample(SampLandLodBlend1Sampler, input.TexCoord0.zw); + # endif + # if defined(LOD_BLENDING) - lodLandColor.xyz *= SharedData::lodBlendingSettings.LODTerrainBrightness; + lodLandColor.xyz *= SharedData::lodBlendingSettings.LODTerrainBrightness; # endif // LOD_BLENDING + float lodBlendParameter = GetLodLandBlendParameter(lodLandColor.xyz); float lodBlendMask = TexLandLodBlend2Sampler.Sample(SampLandLodBlend2Sampler, 3.0.xx * input.TexCoord0.zw).x; float lodLandFadeFactor = GetLodLandBlendMultiplier(lodBlendParameter, lodBlendMask); @@ -1885,9 +1913,9 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace normal.xyz = lerp(normal.xyz, float3(0, 0, 1), lodLandBlendFactor); # if !defined(TRUE_PBR) - baseColor.w = 0; - baseColor = lerp(baseColor, lodLandColor * lodLandFadeFactor, lodLandBlendFactor); - glossiness = lerp(glossiness, 0, lodLandBlendFactor); + baseColor.w = 0; + baseColor = lerp(baseColor, lodLandColor * lodLandFadeFactor, lodLandBlendFactor); + glossiness = lerp(glossiness, 0, lodLandBlendFactor); # endif # endif // LOD_LAND_BLEND diff --git a/src/Features/TerrainVariation.cpp b/src/Features/TerrainVariation.cpp index 95b08f6e80..c943fcf72a 100644 --- a/src/Features/TerrainVariation.cpp +++ b/src/Features/TerrainVariation.cpp @@ -6,7 +6,8 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT( TerrainVariation::Settings, - enableTilingFix) + enableTilingFix, + enableLODTerrainTilingFix) void TerrainVariation::DrawSettings() { @@ -26,6 +27,20 @@ void TerrainVariation::DrawSettings() if (settings.enableTilingFix) { ImGui::Separator(); + bool oldLODEnabled = settings.enableLODTerrainTilingFix; + ImGui::Checkbox("Apply to LOD Terrain", (bool*)&settings.enableLODTerrainTilingFix); + if (oldLODEnabled != (bool)settings.enableLODTerrainTilingFix) { + UpdateShaderSettings(); + logger::info("TerrainVariation LOD setting changed to: {}", settings.enableLODTerrainTilingFix); + } + if (auto _tt = Util::HoverTooltipWrapper()) { + ImGui::Text( + "Applies the tiling fix to LOD terrain objects.\n" + "This helps reduce the visible tiling effect on distant terrain."); + } + + ImGui::Separator(); + bool paramsChanged = false; if (paramsChanged) { @@ -64,6 +79,11 @@ void TerrainVariation::SaveSettings(json& o_json) o_json = settings; } +void TerrainVariation::RestoreDefaultSettings() +{ + settings = {}; +} + bool TerrainVariation::DrawFailLoadMessage() const { return false; @@ -83,5 +103,6 @@ void TerrainVariation::DrawUnloadedUI() ImGui::TextWrapped("Key features:"); ImGui::BulletText("Reduces terrain texture tiling"); ImGui::BulletText("Automatically activates when parallax effects end"); + ImGui::BulletText("Can be applied to LOD terrain for more consistent appearance"); ImGui::Spacing(); } \ No newline at end of file diff --git a/src/Features/TerrainVariation.h b/src/Features/TerrainVariation.h index eb5a8eea38..ccc08f52cc 100644 --- a/src/Features/TerrainVariation.h +++ b/src/Features/TerrainVariation.h @@ -10,32 +10,25 @@ struct TerrainVariation : Feature virtual inline std::string GetName() override { return "Terrain Variation"; } virtual inline std::string GetShortName() override { return "TerrainVariation"; } virtual inline std::string GetFeatureModLink() override { return "https://www.nexusmods.com/skyrimspecialedition/mods/148123"; } - virtual inline std::string_view GetShaderDefineName() override { return "TERRAIN_VARIATION"; } virtual inline bool HasShaderDefine(RE::BSShader::Type shaderType) override { + virtual inline std::string_view GetShaderDefineName() override { return "TERRAIN_VARIATION"; } + virtual inline bool HasShaderDefine(RE::BSShader::Type shaderType) override { return (shaderType == RE::BSShader::Type::Lighting); } virtual bool IsCore() const override { return false; }; - virtual bool SupportsVR() override { return true; } - struct Settings + virtual bool SupportsVR() override { return true; } + + struct alignas(16) Settings { uint enableTilingFix = true; - float3 pad0; - }; - - Settings settings; - bool showAdvanced = false; - Settings defaultSettings = { - true, // enableTilingFix - }; + uint enableLODTerrainTilingFix = true; + float pad0[2]; + } settings; virtual void DrawSettings() override; virtual bool DrawFailLoadMessage() const override; virtual void LoadSettings(json& o_json) override; - virtual void SaveSettings(json& o_json) override; - virtual void RestoreDefaultSettings() override - { - settings = defaultSettings; - UpdateShaderSettings(); - } + virtual void SaveSettings(json& o_json) override; + virtual void RestoreDefaultSettings() override; virtual void PostPostLoad() override; void UpdateShaderSettings(); From 2aadd82442d5724783070896a206fb8e313992af Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Thu, 29 May 2025 12:57:37 +1000 Subject: [PATCH 10/53] fix for mipmap issues & not compiling --- .../TerrainVariation/TerrainVariation.hlsli | 19 ++++++++++++++----- package/Shaders/Lighting.hlsl | 2 +- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index dd42f5d2d2..6c70c70cfb 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -111,9 +111,18 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler blendWeights = (totalWeight > 0.0) ? blendWeights / totalWeight : float3(0.33, 0.33, 0.34); // Sample all three locations - float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); - float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); - float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); + float4 sample1, sample2, sample3; + [branch] if (SharedData::extendedMaterialSettings.EnableTerrainParallax) { + // Parallax enabled, can use SampleLevel for better perf + sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); + sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); + } else { + // When parallax disabled, samplelevel causes mipmap issues, it uses too low a mipmap level up close. + sample1 = tex.SampleGrad(samp, uv + offsets.offset1, dx, dy); + sample2 = tex.SampleGrad(samp, uv + offsets.offset2, dx, dy); + sample3 = tex.SampleGrad(samp, uv + offsets.offset3, dx, dy); + } // Apply height-based weight adjustments float height1 = sample1.a > 0 ? sample1.a : dot(sample1.rgb, float3(0.2126, 0.7152, 0.0722)); @@ -212,12 +221,12 @@ inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, Samp float2 microOffset2 = mul(rot2, offsets.offset2) * offsetScale; float2 microOffset3 = mul(rot3, offsets.offset3) * offsetScale; - // Sample with rotated micro-offsets (everything else stays the same) + // Sample with rotated micro-offsets float4 sample1 = tex.SampleLevel(samp, uv + microOffset1, mipLevel); float4 sample2 = tex.SampleLevel(samp, uv + microOffset2, mipLevel); float4 sample3 = tex.SampleLevel(samp, uv + microOffset3, mipLevel); - // Blend using the barycentric weights (unchanged) + // Blend using the barycentric weights float4 result = sample1 * offsets.weights.x + sample2 * offsets.weights.y + sample3 * offsets.weights.z; diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 71daff54c8..48e0af7fde 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1336,7 +1336,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace sh0 = ExtendedMaterials::GetTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); } # else - sh0 = ExtendedMaterials::GetTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); + sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); # endif } } From 076495bf4de4cd075c4b955ade9791005a168a8e Mon Sep 17 00:00:00 2001 From: davo0411 Date: Thu, 29 May 2025 03:00:36 +0000 Subject: [PATCH 11/53] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20clang-for?= =?UTF-8?q?mat=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TerrainVariation/TerrainVariation.hlsli | 187 +++++++++--------- package/Shaders/Lighting.hlsl | 75 ++++--- src/Features/TerrainVariation.h | 6 +- 3 files changed, 135 insertions(+), 133 deletions(-) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index 1274ba3548..94eca6f2af 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -46,33 +46,33 @@ inline float2 ComputeStochasticOffsets1(float2 UV) inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 UV) { - // Use a much smaller scale factor for LOD terrain to create subtle variation - // instead of dramatic pattern changes - float2 skewUV = mul(float2x2(1.0, 0.0, -0.57735027, 1.15470054), UV * 1.5); - float2 vxID = floor(skewUV); - float3 barry = float3(frac(skewUV), 0.0); - barry.z = 1.0 - barry.x - barry.y; - - // Create a more stable triangle pattern - float4x3 BW_vx = (barry.z > 0) ? - float4x3(float3(vxID, 0), float3(vxID + float2(0, 1), 0), float3(vxID + float2(1, 0), 0), barry.zyx) : - float4x3(float3(vxID + float2(1, 1), 0), float3(vxID + float2(1, 0), 0), float3(vxID + float2(0, 1), 0), float3(-barry.z, 1.0 - barry.y, 1.0 - barry.x)); - - // Generate smaller offsets for more subtle variation - StochasticOffsets offsetsLOD; - offsetsLOD.offset1 = hash2D2D(BW_vx[0].xy) * 0.15; // Reduced offset magnitude - offsetsLOD.offset2 = hash2D2D(BW_vx[1].xy) * 0.15; - offsetsLOD.offset3 = hash2D2D(BW_vx[2].xy) * 0.15; - - // Use smoother weights with less contrast - float3 smoothWeights = BW_vx[3]; - // Apply mild smoothing to weights - smoothWeights = pow(smoothWeights, 0.8); - // Renormalize - smoothWeights /= (smoothWeights.x + smoothWeights.y + smoothWeights.z); - - offsetsLOD.weights = smoothWeights; - return offsetsLOD; + // Use a much smaller scale factor for LOD terrain to create subtle variation + // instead of dramatic pattern changes + float2 skewUV = mul(float2x2(1.0, 0.0, -0.57735027, 1.15470054), UV * 1.5); + float2 vxID = floor(skewUV); + float3 barry = float3(frac(skewUV), 0.0); + barry.z = 1.0 - barry.x - barry.y; + + // Create a more stable triangle pattern + float4x3 BW_vx = (barry.z > 0) ? + float4x3(float3(vxID, 0), float3(vxID + float2(0, 1), 0), float3(vxID + float2(1, 0), 0), barry.zyx) : + float4x3(float3(vxID + float2(1, 1), 0), float3(vxID + float2(1, 0), 0), float3(vxID + float2(0, 1), 0), float3(-barry.z, 1.0 - barry.y, 1.0 - barry.x)); + + // Generate smaller offsets for more subtle variation + StochasticOffsets offsetsLOD; + offsetsLOD.offset1 = hash2D2D(BW_vx[0].xy) * 0.15; // Reduced offset magnitude + offsetsLOD.offset2 = hash2D2D(BW_vx[1].xy) * 0.15; + offsetsLOD.offset3 = hash2D2D(BW_vx[2].xy) * 0.15; + + // Use smoother weights with less contrast + float3 smoothWeights = BW_vx[3]; + // Apply mild smoothing to weights + smoothWeights = pow(smoothWeights, 0.8); + // Renormalize + smoothWeights /= (smoothWeights.x + smoothWeights.y + smoothWeights.z); + + offsetsLOD.weights = smoothWeights; + return offsetsLOD; } // Compute offsets for stochastic sampling @@ -113,18 +113,21 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler // Sample all three locations float4 sample1, sample2, sample3; - [branch] if (SharedData::extendedMaterialSettings.EnableTerrainParallax) { + [branch] if (SharedData::extendedMaterialSettings.EnableTerrainParallax) + { // Parallax enabled, can use SampleLevel for better perf sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); - } else { + } + else + { // When parallax disabled, samplelevel causes mipmap issues, it uses too low a mipmap level up close. sample1 = tex.SampleGrad(samp, uv + offsets.offset1, dx, dy); sample2 = tex.SampleGrad(samp, uv + offsets.offset2, dx, dy); sample3 = tex.SampleGrad(samp, uv + offsets.offset3, dx, dy); } - + // Apply height-based weight adjustments float height1 = sample1.a > 0 ? sample1.a : dot(sample1.rgb, float3(0.2126, 0.7152, 0.0722)); float height2 = sample2.a > 0 ? sample2.a : dot(sample2.rgb, float3(0.2126, 0.7152, 0.0722)); @@ -147,92 +150,92 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler } // Cheap Stochastic Effect for single sample. Used for RMAOS. -inline float4 StochasticSample1(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for RMAOS (maybe LOD in future) +inline float4 StochasticSample1(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for RMAOS (maybe LOD in future) { return tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); } // Same as StochasticEffect but no height/luminescence influence, so much cheaper but worse quality, doesn't matter for the use case. -inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for parallaxcoords & getheight funct. +inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for parallaxcoords & getheight funct. { // Sample the three texture offsets using the provided mip level float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); - + // Blend using the barycentric weights - float4 result = sample1 * offsets.weights.x + - sample2 * offsets.weights.y + + float4 result = sample1 * offsets.weights.x + + sample2 * offsets.weights.y + sample3 * offsets.weights.z; - + return result; } // Special version for LOD mask textures that should have minimal blurring inline float4 StochasticSampleLODMask(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) { - float offsetScale = 0.04; - - // Add simple rotation to each offset (using the random value to vary rotation per pixel) - float angle1 = rnd * 3.14; // Random base angle between 0-2π - float angle2 = angle1 + 1.04; // ~120° offset - float angle3 = angle1 + 2.09; // ~240° offset - - // Create rotation matrices - float2x2 rot1 = float2x2(cos(angle1), -sin(angle1), sin(angle1), cos(angle1)); - float2x2 rot2 = float2x2(cos(angle2), -sin(angle2), sin(angle2), cos(angle2)); - float2x2 rot3 = float2x2(cos(angle3), -sin(angle3), sin(angle3), cos(angle3)); - - // Apply rotation to offsets before scaling them down - float2 microOffset1 = mul(rot1, offsets.offset1) * offsetScale; - float2 microOffset2 = mul(rot2, offsets.offset2) * offsetScale; - float2 microOffset3 = mul(rot3, offsets.offset3) * offsetScale; - - // Sample with rotated micro-offsets + float offsetScale = 0.04; + + // Add simple rotation to each offset (using the random value to vary rotation per pixel) + float angle1 = rnd * 3.14; // Random base angle between 0-2π + float angle2 = angle1 + 1.04; // ~120° offset + float angle3 = angle1 + 2.09; // ~240° offset + + // Create rotation matrices + float2x2 rot1 = float2x2(cos(angle1), -sin(angle1), sin(angle1), cos(angle1)); + float2x2 rot2 = float2x2(cos(angle2), -sin(angle2), sin(angle2), cos(angle2)); + float2x2 rot3 = float2x2(cos(angle3), -sin(angle3), sin(angle3), cos(angle3)); + + // Apply rotation to offsets before scaling them down + float2 microOffset1 = mul(rot1, offsets.offset1) * offsetScale; + float2 microOffset2 = mul(rot2, offsets.offset2) * offsetScale; + float2 microOffset3 = mul(rot3, offsets.offset3) * offsetScale; + + // Sample with rotated micro-offsets float tinyMipBias = 0.05; - float4 sample1 = tex.SampleLevel(samp, uv + microOffset1, mipLevel + tinyMipBias); - float4 sample2 = tex.SampleLevel(samp, uv + microOffset2, mipLevel + tinyMipBias); - float4 sample3 = tex.SampleLevel(samp, uv + microOffset3, mipLevel + tinyMipBias); - - // Blend using the barycentric weights (unchanged) - float4 result = sample1 * offsets.weights.x + - sample2 * offsets.weights.y + - sample3 * offsets.weights.z; - - return result; + float4 sample1 = tex.SampleLevel(samp, uv + microOffset1, mipLevel + tinyMipBias); + float4 sample2 = tex.SampleLevel(samp, uv + microOffset2, mipLevel + tinyMipBias); + float4 sample3 = tex.SampleLevel(samp, uv + microOffset3, mipLevel + tinyMipBias); + + // Blend using the barycentric weights (unchanged) + float4 result = sample1 * offsets.weights.x + + sample2 * offsets.weights.y + + sample3 * offsets.weights.z; + + return result; } // Stochastic sampling function for Full Terrain LOD. Uses rotated offsets for more variation. inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) { - float offsetScale = 0.15; - - // Add simple rotation to each offset (using the random value to vary rotation per pixel) - float angle1 = rnd * 6.28; // Random base angle between 0-2π - float angle2 = angle1 + 2.09; // ~120° offset - float angle3 = angle1 + 4.18; // ~240° offset - - // Create rotation matrices - float2x2 rot1 = float2x2(cos(angle1), -sin(angle1), sin(angle1), cos(angle1)); - float2x2 rot2 = float2x2(cos(angle2), -sin(angle2), sin(angle2), cos(angle2)); - float2x2 rot3 = float2x2(cos(angle3), -sin(angle3), sin(angle3), cos(angle3)); - - // Apply rotation to offsets before scaling them down - float2 microOffset1 = mul(rot1, offsets.offset1) * offsetScale; - float2 microOffset2 = mul(rot2, offsets.offset2) * offsetScale; - float2 microOffset3 = mul(rot3, offsets.offset3) * offsetScale; - - // Sample with rotated micro-offsets - float4 sample1 = tex.SampleLevel(samp, uv + microOffset1, mipLevel); - float4 sample2 = tex.SampleLevel(samp, uv + microOffset2, mipLevel); - float4 sample3 = tex.SampleLevel(samp, uv + microOffset3, mipLevel); - - // Blend using the barycentric weights - float4 result = sample1 * offsets.weights.x + - sample2 * offsets.weights.y + - sample3 * offsets.weights.z; - - return result; + float offsetScale = 0.15; + + // Add simple rotation to each offset (using the random value to vary rotation per pixel) + float angle1 = rnd * 6.28; // Random base angle between 0-2π + float angle2 = angle1 + 2.09; // ~120° offset + float angle3 = angle1 + 4.18; // ~240° offset + + // Create rotation matrices + float2x2 rot1 = float2x2(cos(angle1), -sin(angle1), sin(angle1), cos(angle1)); + float2x2 rot2 = float2x2(cos(angle2), -sin(angle2), sin(angle2), cos(angle2)); + float2x2 rot3 = float2x2(cos(angle3), -sin(angle3), sin(angle3), cos(angle3)); + + // Apply rotation to offsets before scaling them down + float2 microOffset1 = mul(rot1, offsets.offset1) * offsetScale; + float2 microOffset2 = mul(rot2, offsets.offset2) * offsetScale; + float2 microOffset3 = mul(rot3, offsets.offset3) * offsetScale; + + // Sample with rotated micro-offsets + float4 sample1 = tex.SampleLevel(samp, uv + microOffset1, mipLevel); + float4 sample2 = tex.SampleLevel(samp, uv + microOffset2, mipLevel); + float4 sample3 = tex.SampleLevel(samp, uv + microOffset3, mipLevel); + + // Blend using the barycentric weights + float4 result = sample1 * offsets.weights.x + + sample2 * offsets.weights.y + + sample3 * offsets.weights.z; + + return result; } #endif // TERRAIN_VARIATION_HLSLI \ No newline at end of file diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 94ab3e42d9..d4954fc36d 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1342,9 +1342,9 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace { sh0 = ExtendedMaterials::GetTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); } -# else +# else sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); -# endif +# endif } } # endif // EMAT @@ -1861,25 +1861,24 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(LOD_BLENDING) # if defined(LODOBJECTS) || defined(LODOBJECTSHD) - baseColor.xyz *= SharedData::lodBlendingSettings.LODObjectBrightness; + baseColor.xyz *= SharedData::lodBlendingSettings.LODObjectBrightness; # elif defined(LODLANDSCAPE) - // First apply terrain variation if enabled - # if defined(TERRAIN_VARIATION) - if (SharedData::terrainVariationSettings.enableLODTerrainTilingFix) { - float2 dx = ddx(uv); - float2 dy = ddy(uv); - StochasticOffsets lodOffset = ComputeStochasticOffsetsLOD(uv); - float4 lodStochasticColor = StochasticSampleLOD(screenNoise, 0, TexColorSampler, SampColorSampler, uv, lodOffset, dx, dy); - - // Apply the stochastic result directly - baseColor.xyz = Color::Diffuse(lodStochasticColor.rgb); - } - # endif - baseColor.xyz *= SharedData::lodBlendingSettings.LODTerrainBrightness; +// First apply terrain variation if enabled +# if defined(TERRAIN_VARIATION) + if (SharedData::terrainVariationSettings.enableLODTerrainTilingFix) { + float2 dx = ddx(uv); + float2 dy = ddy(uv); + StochasticOffsets lodOffset = ComputeStochasticOffsetsLOD(uv); + float4 lodStochasticColor = StochasticSampleLOD(screenNoise, 0, TexColorSampler, SampColorSampler, uv, lodOffset, dx, dy); + + // Apply the stochastic result directly + baseColor.xyz = Color::Diffuse(lodStochasticColor.rgb); + } +# endif + baseColor.xyz *= SharedData::lodBlendingSettings.LODTerrainBrightness; # endif # endif // LOD_BLENDING - # if defined(MODELSPACENORMALS) # if defined(LODLANDNOISE) normal.xyz = normal.xzy - 0.5.xxx; @@ -1946,25 +1945,25 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif # if defined(LOD_LAND_BLEND) - float4 lodLandColor; - - # if defined(TERRAIN_VARIATION) - if (SharedData::terrainVariationSettings.enableLODTerrainTilingFix) { - // Apply stochastic sampling to LOD_LAND_BLEND color texture - float2 blendColorUV = input.TexCoord0.zw; - float2 dx = ddx(blendColorUV); - float2 dy = ddy(blendColorUV); - StochasticOffsets lodBlendColorOffset = ComputeStochasticOffsetsLOD(blendColorUV); - lodLandColor = StochasticSampleLODMask(screenNoise, 0, TexLandLodBlend1Sampler, SampLandLodBlend1Sampler, blendColorUV, lodBlendColorOffset, dx, dy); - } else { - lodLandColor = TexLandLodBlend1Sampler.Sample(SampLandLodBlend1Sampler, input.TexCoord0.zw); - } - # else - lodLandColor = TexLandLodBlend1Sampler.Sample(SampLandLodBlend1Sampler, input.TexCoord0.zw); - # endif - + float4 lodLandColor; + +# if defined(TERRAIN_VARIATION) + if (SharedData::terrainVariationSettings.enableLODTerrainTilingFix) { + // Apply stochastic sampling to LOD_LAND_BLEND color texture + float2 blendColorUV = input.TexCoord0.zw; + float2 dx = ddx(blendColorUV); + float2 dy = ddy(blendColorUV); + StochasticOffsets lodBlendColorOffset = ComputeStochasticOffsetsLOD(blendColorUV); + lodLandColor = StochasticSampleLODMask(screenNoise, 0, TexLandLodBlend1Sampler, SampLandLodBlend1Sampler, blendColorUV, lodBlendColorOffset, dx, dy); + } else { + lodLandColor = TexLandLodBlend1Sampler.Sample(SampLandLodBlend1Sampler, input.TexCoord0.zw); + } +# else + lodLandColor = TexLandLodBlend1Sampler.Sample(SampLandLodBlend1Sampler, input.TexCoord0.zw); +# endif + # if defined(LOD_BLENDING) - lodLandColor.xyz *= SharedData::lodBlendingSettings.LODTerrainBrightness; + lodLandColor.xyz *= SharedData::lodBlendingSettings.LODTerrainBrightness; # endif // LOD_BLENDING float lodBlendParameter = GetLodLandBlendParameter(lodLandColor.xyz); @@ -1974,9 +1973,9 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace normal.xyz = lerp(normal.xyz, float3(0, 0, 1), lodLandBlendFactor); # if !defined(TRUE_PBR) - baseColor.w = 0; - baseColor = lerp(baseColor, lodLandColor * lodLandFadeFactor, lodLandBlendFactor); - glossiness = lerp(glossiness, 0, lodLandBlendFactor); + baseColor.w = 0; + baseColor = lerp(baseColor, lodLandColor * lodLandFadeFactor, lodLandBlendFactor); + glossiness = lerp(glossiness, 0, lodLandBlendFactor); # endif # endif // LOD_LAND_BLEND diff --git a/src/Features/TerrainVariation.h b/src/Features/TerrainVariation.h index d5454c68d6..18cf699e1a 100644 --- a/src/Features/TerrainVariation.h +++ b/src/Features/TerrainVariation.h @@ -16,8 +16,8 @@ struct TerrainVariation : Feature return (shaderType == RE::BSShader::Type::Lighting); } virtual bool IsCore() const override { return false; }; - virtual bool SupportsVR() override { return true; } - + virtual bool SupportsVR() override { return true; } + struct alignas(16) Settings { uint enableTilingFix = true; @@ -28,7 +28,7 @@ struct TerrainVariation : Feature virtual void DrawSettings() override; virtual bool DrawFailLoadMessage() const override; virtual void LoadSettings(json& o_json) override; - virtual void SaveSettings(json& o_json) override; + virtual void SaveSettings(json& o_json) override; virtual void RestoreDefaultSettings() override; virtual void PostPostLoad() override; From b7257df3affb6821674ac627520acb9a0b4ddab3 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Sun, 1 Jun 2025 15:55:23 +1000 Subject: [PATCH 12/53] Fixed all bugs, comment cleanup --- .../TerrainVariation/TerrainVariation.hlsli | 8 +- package/Shaders/Lighting.hlsl | 129 ++++++++++-------- 2 files changed, 73 insertions(+), 64 deletions(-) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index 94eca6f2af..ca1e22bd41 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -60,14 +60,14 @@ inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 UV) // Generate smaller offsets for more subtle variation StochasticOffsets offsetsLOD; - offsetsLOD.offset1 = hash2D2D(BW_vx[0].xy) * 0.15; // Reduced offset magnitude - offsetsLOD.offset2 = hash2D2D(BW_vx[1].xy) * 0.15; - offsetsLOD.offset3 = hash2D2D(BW_vx[2].xy) * 0.15; + offsetsLOD.offset1 = hash2D2D(BW_vx[0].xy) * 0.08; + offsetsLOD.offset2 = hash2D2D(BW_vx[1].xy) * 0.08; + offsetsLOD.offset3 = hash2D2D(BW_vx[2].xy) * 0.08; // Use smoother weights with less contrast float3 smoothWeights = BW_vx[3]; // Apply mild smoothing to weights - smoothWeights = pow(smoothWeights, 0.8); + smoothWeights = pow(smoothWeights, 0.15); // Renormalize smoothWeights /= (smoothWeights.x + smoothWeights.y + smoothWeights.z); diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index d4954fc36d..cc7e761c3a 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1274,8 +1274,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(TRUE_PBR) float4 blendedRMAOS = 0; # endif - float invwsum = 1.0; // Weights are already normalized above, so invwsum should be 1.0 - // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) + // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) # if defined(TERRAIN_VARIATION) bool useTerrainVariation = SharedData::terrainVariationSettings.enableTilingFix; float2 dx, dy; @@ -1373,8 +1372,9 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(LANDSCAPE) // Layer 1 (LandBlendWeights1.x) if (input.LandBlendWeights1.x > 0.01) { - float weight = input.LandBlendWeights1.x * invwsum; - // Sample layer 1 textures - use terrain variation if available and enabled + float weight = input.LandBlendWeights1.x; + + // Sample diffuse texture for layer 1 # if defined(TERRAIN_VARIATION) float4 landColor1; [branch] if (useTerrainVariation) @@ -1416,23 +1416,24 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float landNormalAlpha1 = landNormal1.a; # if defined(SNOW) && !defined(TRUE_PBR) landSnowMask += LandscapeTexture1to4IsSnow.x * input.LandBlendWeights1.x * landSnowMask1; -# endif // SNOW \ - // Sample RMAOS texture for layer 1 +# endif // SNOW + + // Sample RMAOS texture for layer 1 # if defined(TRUE_PBR) - float4 currentRMAOS = 0; + float4 landRMAOS1; [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0PBR) != 0) { # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - currentRMAOS = StochasticSample1(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + landRMAOS1 = StochasticEffect(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy) * float4(PBRParams1.x, 1, 1, PBRParams1.z); } else { - currentRMAOS = TexRMAOSSampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + landRMAOS1 = TexRMAOSSampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); } # else - currentRMAOS = TexRMAOSSampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + landRMAOS1 = TexRMAOSSampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); # endif if ((PBRFlags & PBR::TerrainFlags::LandTile0HasGlint) != 0) { glintParameters += input.LandBlendWeights1.x * LandscapeTexture1GlintParameters; @@ -1440,19 +1441,21 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace } else { - currentRMAOS = float4(1 - landNormal1.w, 0, 1, 0); + landRMAOS1 = float4(1 - landNormal1.w, 0, 1, 0); } - blendedRMAOS += currentRMAOS * weight; + blendedRMAOS += landRMAOS1 * weight; # endif blendedRGB += landColorRGB1 * weight; blendedAlpha += landAlpha1 * weight; blendedNormalRGB += landNormalRGB1 * weight; blendedNormalAlpha += landNormalAlpha1 * weight; } + // Layer 2 (LandBlendWeights1.y) if (input.LandBlendWeights1.y > 0.01) { - float weight = input.LandBlendWeights1.y * invwsum; -// Sample layer 2 textures - use terrain variation if available and enabled + float weight = input.LandBlendWeights1.y; + + // Sample diffuse texture for layer 2 # if defined(TERRAIN_VARIATION) float4 landColor2; [branch] if (useTerrainVariation) @@ -1495,22 +1498,23 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(SNOW) && !defined(TRUE_PBR) landSnowMask += LandscapeTexture1to4IsSnow.y * input.LandBlendWeights1.y * landSnowMask2; # endif // SNOW + + // Sample RMAOS texture for layer 2 # if defined(TRUE_PBR) - float4 currentRMAOS = 0; + float4 landRMAOS2; [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1PBR) != 0) { - // Sample RMAOS texture for layer 2 # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - currentRMAOS = StochasticSample1(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampLandRMAOS2Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); + landRMAOS2 = StochasticEffect(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampLandRMAOS2Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); } else { - currentRMAOS = TexLandRMAOS2Sampler.SampleBias(SampLandRMAOS2Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); + landRMAOS2 = TexLandRMAOS2Sampler.SampleBias(SampLandRMAOS2Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); } # else - currentRMAOS = TexLandRMAOS2Sampler.SampleBias(SampLandRMAOS2Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); + landRMAOS2 = TexLandRMAOS2Sampler.SampleBias(SampLandRMAOS2Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); # endif if ((PBRFlags & PBR::TerrainFlags::LandTile1HasGlint) != 0) { glintParameters += input.LandBlendWeights1.y * LandscapeTexture2GlintParameters; @@ -1518,19 +1522,20 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace } else { - currentRMAOS = float4(1 - landNormal2.w, 0, 1, 0); + landRMAOS2 = float4(1 - landNormal2.w, 0, 1, 0); } - blendedRMAOS += currentRMAOS * weight; + blendedRMAOS += landRMAOS2 * weight; # endif blendedRGB += landColorRGB2 * weight; blendedAlpha += landAlpha2 * weight; blendedNormalRGB += landNormalRGB2 * weight; blendedNormalAlpha += landNormalAlpha2 * weight; - } + } + // Layer 3 (LandBlendWeights1.z) if (input.LandBlendWeights1.z > 0.01) { - float weight = input.LandBlendWeights1.z * invwsum; -// Sample layer 3 textures - use terrain variation if available and enabled + float weight = input.LandBlendWeights1.z; + // Sample diffuse texture for layer 3 # if defined(TERRAIN_VARIATION) float4 landColor3; [branch] if (useTerrainVariation) @@ -1574,22 +1579,22 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace landSnowMask += LandscapeTexture1to4IsSnow.z * input.LandBlendWeights1.z * landSnowMask3; # endif // SNOW + // Sample RMAOS texture for layer 3 # if defined(TRUE_PBR) - float4 currentRMAOS = 0; + float4 landRMAOS3; [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2PBR) != 0) { - // Sample RMAOS texture for layer 3 # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - currentRMAOS = StochasticSample1(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampLandRMAOS3Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); + landRMAOS3 = StochasticEffect(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampLandRMAOS3Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); } else { - currentRMAOS = TexLandRMAOS3Sampler.SampleBias(SampLandRMAOS3Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); + landRMAOS3 = TexLandRMAOS3Sampler.SampleBias(SampLandRMAOS3Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); } # else - currentRMAOS = TexLandRMAOS3Sampler.SampleBias(SampLandRMAOS3Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); + landRMAOS3 = TexLandRMAOS3Sampler.SampleBias(SampLandRMAOS3Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); # endif if ((PBRFlags & PBR::TerrainFlags::LandTile2HasGlint) != 0) { glintParameters += input.LandBlendWeights1.z * LandscapeTexture3GlintParameters; @@ -1597,9 +1602,9 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace } else { - currentRMAOS = float4(1 - landNormal3.w, 0, 1, 0); + landRMAOS3 = float4(1 - landNormal3.w, 0, 1, 0); } - blendedRMAOS += currentRMAOS * weight; + blendedRMAOS += landRMAOS3 * weight; # endif blendedRGB += landColorRGB3 * weight; blendedAlpha += landAlpha3 * weight; @@ -1608,8 +1613,9 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace } // Layer 4 (LandBlendWeights1.w) if (input.LandBlendWeights1.w > 0.01) { - float weight = input.LandBlendWeights1.w * invwsum; -// Sample layer 4 textures - use terrain variation if available and enabled + float weight = input.LandBlendWeights1.w; + + // Sample diffuse texture for layer 4 # if defined(TERRAIN_VARIATION) float4 landColor4; [branch] if (useTerrainVariation) @@ -1653,22 +1659,22 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace landSnowMask += LandscapeTexture1to4IsSnow.w * input.LandBlendWeights1.w * landSnowMask4; # endif // SNOW + // Sample RMAOS texture for layer 4 # if defined(TRUE_PBR) - float4 currentRMAOS = 0; + float4 landRMAOS4; [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3PBR) != 0) { - // Sample RMAOS texture for layer 4 # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - currentRMAOS = StochasticSample1(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampLandRMAOS4Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); + landRMAOS4 = StochasticEffect(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampLandRMAOS4Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); } else { - currentRMAOS = TexLandRMAOS4Sampler.SampleBias(SampLandRMAOS4Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); + landRMAOS4 = TexLandRMAOS4Sampler.SampleBias(SampLandRMAOS4Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); } # else - currentRMAOS = TexLandRMAOS4Sampler.SampleBias(SampLandRMAOS4Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); + landRMAOS4 = TexLandRMAOS4Sampler.SampleBias(SampLandRMAOS4Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); # endif if ((PBRFlags & PBR::TerrainFlags::LandTile3HasGlint) != 0) { glintParameters += input.LandBlendWeights1.w * LandscapeTexture4GlintParameters; @@ -1676,19 +1682,20 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace } else { - currentRMAOS = float4(1 - landNormal4.w, 0, 1, 0); + landRMAOS4 = float4(1 - landNormal4.w, 0, 1, 0); } - blendedRMAOS += currentRMAOS * weight; + blendedRMAOS += landRMAOS4 * weight; # endif blendedRGB += landColorRGB4 * weight; blendedAlpha += landAlpha4 * weight; blendedNormalRGB += landNormalRGB4 * weight; blendedNormalAlpha += landNormalAlpha4 * weight; } + // Layer 5 (LandBlendWeights2.x) if (input.LandBlendWeights2.x > 0.01) { - float weight = input.LandBlendWeights2.x * invwsum; -// Sample layer 5 textures - use terrain variation if available and enabled + float weight = input.LandBlendWeights2.x; + // Sample diffuse texture for layer 5 # if defined(TERRAIN_VARIATION) float4 landColor5; [branch] if (useTerrainVariation) @@ -1733,22 +1740,22 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace landSnowMask += LandscapeTexture5to6IsSnow.x * input.LandBlendWeights2.x * landSnowMask5; # endif // SNOW + // Sample RMAOS texture for layer 5 # if defined(TRUE_PBR) - float4 currentRMAOS = 0; + float4 landRMAOS5; [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4PBR) != 0) { - // Sample RMAOS texture for layer 5 # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - currentRMAOS = StochasticSample1(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampLandRMAOS5Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); + landRMAOS5 = StochasticEffect(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampLandRMAOS5Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); } else { - currentRMAOS = TexLandRMAOS5Sampler.SampleBias(SampLandRMAOS5Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); + landRMAOS5 = TexLandRMAOS5Sampler.SampleBias(SampLandRMAOS5Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); } # else - currentRMAOS = TexLandRMAOS5Sampler.SampleBias(SampLandRMAOS5Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); + landRMAOS5 = TexLandRMAOS5Sampler.SampleBias(SampLandRMAOS5Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); # endif if ((PBRFlags & PBR::TerrainFlags::LandTile4HasGlint) != 0) { glintParameters += input.LandBlendWeights2.x * LandscapeTexture5GlintParameters; @@ -1756,9 +1763,9 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace } else { - currentRMAOS = float4(1 - landNormal5.w, 0, 1, 0); + landRMAOS5 = float4(1 - landNormal5.w, 0, 1, 0); } - blendedRMAOS += currentRMAOS * weight; + blendedRMAOS += landRMAOS5 * weight; # endif blendedRGB += landColorRGB5 * weight; blendedAlpha += landAlpha5 * weight; @@ -1767,8 +1774,9 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace } // Layer 6 (LandBlendWeights2.y) if (input.LandBlendWeights2.y > 0.01) { - float weight = input.LandBlendWeights2.y * invwsum; -// Sample layer 6 textures - use terrain variation if available and enabled + float weight = input.LandBlendWeights2.y; + + // Sample layer 6 textures # if defined(TERRAIN_VARIATION) float4 landColor6; [branch] if (useTerrainVariation) @@ -1812,21 +1820,22 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace landSnowMask += LandscapeTexture5to6IsSnow.y * input.LandBlendWeights2.y * landSnowMask6; # endif // SNOW + // Sample RMAOS texture for layer 6 # if defined(TRUE_PBR) - float4 currentRMAOS = 0; + float4 landRMAOS6; [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5PBR) != 0) - { // Sample RMAOS texture for layer 6 + { # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - currentRMAOS = StochasticSample1(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampLandRMAOS6Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); + landRMAOS6 = StochasticEffect(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampLandRMAOS6Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); } else { - currentRMAOS = TexLandRMAOS6Sampler.SampleBias(SampLandRMAOS6Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); + landRMAOS6 = TexLandRMAOS6Sampler.SampleBias(SampLandRMAOS6Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); } # else - currentRMAOS = TexLandRMAOS6Sampler.SampleBias(SampLandRMAOS6Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); + landRMAOS6 = TexLandRMAOS6Sampler.SampleBias(SampLandRMAOS6Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); # endif if ((PBRFlags & PBR::TerrainFlags::LandTile5HasGlint) != 0) { glintParameters += input.LandBlendWeights2.y * LandscapeTexture6GlintParameters; @@ -1834,15 +1843,16 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace } else { - currentRMAOS = float4(1 - landNormal6.w, 0, 1, 0); + landRMAOS6 = float4(1 - landNormal6.w, 0, 1, 0); } - blendedRMAOS += currentRMAOS * weight; + blendedRMAOS += landRMAOS6 * weight; # endif blendedRGB += landColorRGB6 * weight; blendedAlpha += landAlpha6 * weight; blendedNormalRGB += landNormalRGB6 * weight; blendedNormalAlpha += landNormalAlpha6 * weight; } + float4 rawBaseColor = float4(blendedRGB, blendedAlpha); baseColor = float4(Color::Diffuse(blendedRGB), blendedAlpha); normal = float4(blendedNormalRGB, blendedNormalAlpha); @@ -3126,8 +3136,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace indirectSpecularLobeWeight = lerp(indirectSpecularLobeWeight, 0, lodLandBlendFactor); pbrGlossiness = lerp(pbrGlossiness, 0, lodLandBlendFactor); } -# elif defined(TRUE_PBR) && !defined(LANDSCAPE) - // Only apply final PBR scaling for non-landscape materials +# elif defined(TRUE_PBR) color.xyz *= Color::PBRLightingScale; specularColorPBR *= Color::PBRLightingScale; specularColor = specularColorPBR; From 2884302ffdf729c4a9485ff0c438cc7a538d4122 Mon Sep 17 00:00:00 2001 From: davo0411 Date: Sun, 1 Jun 2025 05:55:55 +0000 Subject: [PATCH 13/53] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20clang-for?= =?UTF-8?q?mat=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package/Shaders/Lighting.hlsl | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index cc7e761c3a..3d48fa92bf 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1274,7 +1274,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(TRUE_PBR) float4 blendedRMAOS = 0; # endif - // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) + // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) # if defined(TERRAIN_VARIATION) bool useTerrainVariation = SharedData::terrainVariationSettings.enableTilingFix; float2 dx, dy; @@ -1373,7 +1373,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace // Layer 1 (LandBlendWeights1.x) if (input.LandBlendWeights1.x > 0.01) { float weight = input.LandBlendWeights1.x; - + // Sample diffuse texture for layer 1 # if defined(TERRAIN_VARIATION) float4 landColor1; @@ -1416,8 +1416,8 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float landNormalAlpha1 = landNormal1.a; # if defined(SNOW) && !defined(TRUE_PBR) landSnowMask += LandscapeTexture1to4IsSnow.x * input.LandBlendWeights1.x * landSnowMask1; -# endif // SNOW - +# endif // SNOW + // Sample RMAOS texture for layer 1 # if defined(TRUE_PBR) float4 landRMAOS1; @@ -1530,8 +1530,8 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace blendedAlpha += landAlpha2 * weight; blendedNormalRGB += landNormalRGB2 * weight; blendedNormalAlpha += landNormalAlpha2 * weight; - } - + } + // Layer 3 (LandBlendWeights1.z) if (input.LandBlendWeights1.z > 0.01) { float weight = input.LandBlendWeights1.z; @@ -1614,7 +1614,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace // Layer 4 (LandBlendWeights1.w) if (input.LandBlendWeights1.w > 0.01) { float weight = input.LandBlendWeights1.w; - + // Sample diffuse texture for layer 4 # if defined(TERRAIN_VARIATION) float4 landColor4; @@ -1775,7 +1775,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace // Layer 6 (LandBlendWeights2.y) if (input.LandBlendWeights2.y > 0.01) { float weight = input.LandBlendWeights2.y; - + // Sample layer 6 textures # if defined(TERRAIN_VARIATION) float4 landColor6; @@ -1824,7 +1824,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(TRUE_PBR) float4 landRMAOS6; [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5PBR) != 0) - { + { # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { @@ -1852,7 +1852,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace blendedNormalRGB += landNormalRGB6 * weight; blendedNormalAlpha += landNormalAlpha6 * weight; } - + float4 rawBaseColor = float4(blendedRGB, blendedAlpha); baseColor = float4(Color::Diffuse(blendedRGB), blendedAlpha); normal = float4(blendedNormalRGB, blendedNormalAlpha); From 38df2424a0795f2d718c203296d1fec92c819e79 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Sun, 1 Jun 2025 20:18:10 +1000 Subject: [PATCH 14/53] Worldspace based --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 13 +- .../TerrainVariation/TerrainVariation.hlsli | 120 ++++++++++-------- package/Shaders/Lighting.hlsl | 2 +- 3 files changed, 72 insertions(+), 63 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index 4de234c54a..5a16510fef 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -83,7 +83,7 @@ namespace ExtendedMaterials # define HEIGHT_MULT 8 float GetTerrainHeight(float screenNoise, PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, # if defined(TERRAIN_VARIATION) - StochasticOffsets sharedOffset, float2 dx, float2 dy, + float2 dx, float2 dy, uint eyeIndex, # endif out float weights[6]) { @@ -642,13 +642,6 @@ namespace ExtendedMaterials # endif { if (quality > 0.0) { -# if defined(TERRAIN_VARIATION) - // Reduce shadow quality when terrain variation is enabled to improve performance - // The stochastic sampling cost for shadows is high, so we scale back quality - float effectiveQuality = quality * 0.5; -# else - float effectiveQuality = quality; -# endif float4 multipliers = rcp((float4(1, 2, 3, 4) + noise)); float4 sh; float heights[6] = { 0, 0, 0, 0, 0, 0 }; @@ -678,7 +671,7 @@ namespace ExtendedMaterials if (effectiveQuality > 0.75) sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); # endif - return pow(1.0 - saturate(dot(max(0, sh - sh0) / scale, 1.0)) * effectiveQuality, 2.0); + return pow(1.0 - saturate(dot(max(0, sh - sh0) / scale, 1.0)) * quality, 2.0); # else # if defined(TERRAIN_VARIATION) sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); @@ -697,7 +690,7 @@ namespace ExtendedMaterials if (effectiveQuality > 0.75) sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); # endif - return pow(1.0 - saturate(dot(max(0, sh - sh0), 1.0)) * effectiveQuality, 2.0); + return pow(1.0 - saturate(dot(max(0, sh - sh0), 1.0)) * quality, 2.0); # endif } return 1.0; diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index ca1e22bd41..b667924c1c 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -7,6 +7,7 @@ #include "Common/Random.hlsli" #include "Common/SharedData.hlsli" +#include "Common/FrameBuffer.hlsli" // Height blend operator settings - DO NOT CHANGE THESE VALUES. static const float HEIGHT_BLEND_CONTRAST = 16.0; // Controls sharpness of height-based transitions @@ -30,9 +31,11 @@ inline float2 hash2D2D(float2 s) } // Compute single offset for stochastic sampling (optimized for single sample) -inline float2 ComputeStochasticOffsets1(float2 UV) +inline float2 ComputeStochasticOffsets1(float3 worldPos, uint eyeIndex = 0) { - float2 skewUV = mul(float2x2(1.0, 0.0, -0.57735027, 1.15470054), UV * 3.464); + // Add CameraPosAdjust to stabilize pattern with camera movement + float2 worldUV = worldPos.xy + FrameBuffer::CameraPosAdjust[eyeIndex].xy; + float2 skewUV = mul(float2x2(1.0, 0.0, -0.57735027, 1.15470054), worldUV * 0.03464); float2 vxID = floor(skewUV); float3 barry = float3(frac(skewUV), 0.0); barry.z = 1.0 - barry.x - barry.y; @@ -44,59 +47,32 @@ inline float2 ComputeStochasticOffsets1(float2 UV) return hash2D2D(firstVertexID); } -inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 UV) +// Generate world-position based stochastic offsets for terrain. Fixes cell border issues. +inline StochasticOffsets ComputeStochasticOffsets(float3 worldPos, uint eyeIndex = 0) { - // Use a much smaller scale factor for LOD terrain to create subtle variation - // instead of dramatic pattern changes - float2 skewUV = mul(float2x2(1.0, 0.0, -0.57735027, 1.15470054), UV * 1.5); - float2 vxID = floor(skewUV); - float3 barry = float3(frac(skewUV), 0.0); - barry.z = 1.0 - barry.x - barry.y; - - // Create a more stable triangle pattern - float4x3 BW_vx = (barry.z > 0) ? - float4x3(float3(vxID, 0), float3(vxID + float2(0, 1), 0), float3(vxID + float2(1, 0), 0), barry.zyx) : - float4x3(float3(vxID + float2(1, 1), 0), float3(vxID + float2(1, 0), 0), float3(vxID + float2(0, 1), 0), float3(-barry.z, 1.0 - barry.y, 1.0 - barry.x)); - - // Generate smaller offsets for more subtle variation - StochasticOffsets offsetsLOD; - offsetsLOD.offset1 = hash2D2D(BW_vx[0].xy) * 0.08; - offsetsLOD.offset2 = hash2D2D(BW_vx[1].xy) * 0.08; - offsetsLOD.offset3 = hash2D2D(BW_vx[2].xy) * 0.08; - - // Use smoother weights with less contrast - float3 smoothWeights = BW_vx[3]; - // Apply mild smoothing to weights - smoothWeights = pow(smoothWeights, 0.15); - // Renormalize - smoothWeights /= (smoothWeights.x + smoothWeights.y + smoothWeights.z); - - offsetsLOD.weights = smoothWeights; - return offsetsLOD; + float2 worldUV = worldPos.xy + FrameBuffer::CameraPosAdjust[eyeIndex].xy; + + float2 skewUV = mul(float2x2(1.0, 0.0, -0.57735027, 1.15470054), worldUV * 0.03464); + float2 vxID = floor(skewUV); + float3 barry = float3(frac(skewUV), 0.0); + barry.z = 1.0 - barry.x - barry.y; + + float4x3 BW_vx = (barry.z > 0) ? + float4x3(float3(vxID, 0), float3(vxID + float2(0, 1), 0), float3(vxID + float2(1, 0), 0), barry.zyx) : + float4x3(float3(vxID + float2(1, 1), 0), float3(vxID + float2(1, 0), 0), float3(vxID + float2(0, 1), 0), float3(-barry.z, 1.0 - barry.y, 1.0 - barry.x)); + + StochasticOffsets offsets; + offsets.offset1 = hash2D2D(BW_vx[0].xy); + offsets.offset2 = hash2D2D(BW_vx[1].xy); + offsets.offset3 = hash2D2D(BW_vx[2].xy); + offsets.weights = BW_vx[3]; + + return offsets; } -// Compute offsets for stochastic sampling -inline StochasticOffsets ComputeStochasticOffsets(float2 UV) -{ - float2 skewUV = mul(float2x2(1.0, 0.0, -0.57735027, 1.15470054), UV * 3.464); - float2 vxID = floor(skewUV); - float3 barry = float3(frac(skewUV), 0.0); - barry.z = 1.0 - barry.x - barry.y; - - float4x3 BW_vx = (barry.z > 0) ? - float4x3(float3(vxID, 0), float3(vxID + float2(0, 1), 0), float3(vxID + float2(1, 0), 0), barry.zyx) : - float4x3(float3(vxID + float2(1, 1), 0), float3(vxID + float2(1, 0), 0), float3(vxID + float2(0, 1), 0), float3(-barry.z, 1.0 - barry.y, 1.0 - barry.x)); - - StochasticOffsets offsets; - offsets.offset1 = hash2D2D(BW_vx[0].xy); - offsets.offset2 = hash2D2D(BW_vx[1].xy); - offsets.offset3 = hash2D2D(BW_vx[2].xy); - offsets.weights = BW_vx[3]; - return offsets; -} // Main stochastic sampling function -inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for normal/diffuse text. Luminence-based blending helps preserve details close to camera. +inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy, float3 worldPos = float3(0,0,0)) // Used for normal/diffuse text. Luminence-based blending helps preserve details close to camera. { // Early return if terrain variation is disabled [branch] if (!SharedData::terrainVariationSettings.enableTilingFix) @@ -150,9 +126,16 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler } // Cheap Stochastic Effect for single sample. Used for RMAOS. -inline float4 StochasticSample1(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for RMAOS (maybe LOD in future) +inline float4 StochasticSample1(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy, float3 worldPos = float3(0,0,0), uint eyeIndex = 0) { - return tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + // Directly compute a single offset using the faster dedicated function - use worldPos if available + float2 singleOffset; + if (worldPos.x != 0 || worldPos.y != 0 || worldPos.z != 0) + singleOffset = ComputeStochasticOffsets1(worldPos, eyeIndex); + else + singleOffset = offsets.offset1; // Fall back to pre-computed offset if no worldPos + + return tex.SampleLevel(samp, uv + singleOffset, mipLevel); } // Same as StochasticEffect but no height/luminescence influence, so much cheaper but worse quality, doesn't matter for the use case. @@ -171,6 +154,39 @@ inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, Sample return result; } +// --------------------- LOD SAMPLING FUNCTIONS --------------------- // + +inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 UV) +{ + // Use a much smaller scale factor for LOD terrain to create subtle variation + // instead of dramatic pattern changes + float2 skewUV = mul(float2x2(1.0, 0.0, -0.57735027, 1.15470054), UV * 1.5); + float2 vxID = floor(skewUV); + float3 barry = float3(frac(skewUV), 0.0); + barry.z = 1.0 - barry.x - barry.y; + + // Create a more stable triangle pattern + float4x3 BW_vx = (barry.z > 0) ? + float4x3(float3(vxID, 0), float3(vxID + float2(0, 1), 0), float3(vxID + float2(1, 0), 0), barry.zyx) : + float4x3(float3(vxID + float2(1, 1), 0), float3(vxID + float2(1, 0), 0), float3(vxID + float2(0, 1), 0), float3(-barry.z, 1.0 - barry.y, 1.0 - barry.x)); + + // Generate smaller offsets for more subtle variation + StochasticOffsets offsetsLOD; + offsetsLOD.offset1 = hash2D2D(BW_vx[0].xy) * 0.08; + offsetsLOD.offset2 = hash2D2D(BW_vx[1].xy) * 0.08; + offsetsLOD.offset3 = hash2D2D(BW_vx[2].xy) * 0.08; + + // Use smoother weights with less contrast + float3 smoothWeights = BW_vx[3]; + // Apply mild smoothing to weights + smoothWeights = pow(smoothWeights, 0.15); + // Renormalize + smoothWeights /= (smoothWeights.x + smoothWeights.y + smoothWeights.z); + + offsetsLOD.weights = smoothWeights; + return offsetsLOD; +} + // Special version for LOD mask textures that should have minimal blurring inline float4 StochasticSampleLODMask(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) { diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index cc7e761c3a..cab9d99288 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1283,7 +1283,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace { dx = ddx(uv); dy = ddy(uv); - sharedOffset = ComputeStochasticOffsets(uv); + sharedOffsets = ComputeStochasticOffsets(input.WorldPosition.xyz, eyeIndex); } # endif From b496ffd6ac80e7c75ec368b81ec77dfafd10781f Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Mon, 2 Jun 2025 09:36:04 +1000 Subject: [PATCH 15/53] Fix --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 58 ++++++------ .../TerrainVariation/TerrainVariation.hlsli | 91 +++++++++++++------ 2 files changed, 94 insertions(+), 55 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index 5a16510fef..33554b464d 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -83,7 +83,7 @@ namespace ExtendedMaterials # define HEIGHT_MULT 8 float GetTerrainHeight(float screenNoise, PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, # if defined(TERRAIN_VARIATION) - float2 dx, float2 dy, uint eyeIndex, + StochasticOffsets sharedOffset, float2 dx, float2 dy, # endif out float weights[6]) { @@ -655,40 +655,40 @@ namespace ExtendedMaterials rayDir *= scale; # if defined(TERRAIN_VARIATION) - sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); - if (effectiveQuality > 0.25) - sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); - if (effectiveQuality > 0.5) - sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); - if (effectiveQuality > 0.75) - sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + if (quality > 0.25) + sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + if (quality > 0.5) + sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + if (quality > 0.75) + sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); # else - sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); - if (effectiveQuality > 0.25) - sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); - if (effectiveQuality > 0.5) - sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); - if (effectiveQuality > 0.75) - sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (quality > 0.25) + sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (quality > 0.5) + sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (quality > 0.75) + sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); # endif return pow(1.0 - saturate(dot(max(0, sh - sh0) / scale, 1.0)) * quality, 2.0); # else # if defined(TERRAIN_VARIATION) - sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); - if (effectiveQuality > 0.25) - sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); - if (effectiveQuality > 0.5) - sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); - if (effectiveQuality > 0.75) - sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + if (quality > 0.25) + sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + if (quality > 0.5) + sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + if (quality > 0.75) + sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); # else - sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); - if (effectiveQuality > 0.25) - sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); - if (effectiveQuality > 0.5) - sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); - if (effectiveQuality > 0.75) - sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, effectiveQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (quality > 0.25) + sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (quality > 0.5) + sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (quality > 0.75) + sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); # endif return pow(1.0 - saturate(dot(max(0, sh - sh0), 1.0)) * quality, 2.0); # endif diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index b667924c1c..f45e78a44f 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -9,10 +9,21 @@ #include "Common/SharedData.hlsli" #include "Common/FrameBuffer.hlsli" +// --------------------- CONSTANTS AND STRUCTURES --------------------- // // Height blend operator settings - DO NOT CHANGE THESE VALUES. static const float HEIGHT_BLEND_CONTRAST = 16.0; // Controls sharpness of height-based transitions static const float CULLING_THRESHOLD = 0.001; // Minimum weight threshold for sample culling static const float HEIGHT_INFLUENCE = 0.3; // How much height affects blending (0=pure stochastic, 1=pure height) +// Pre-computed constants to avoid runtime calculations +static const float2x2 SKEW_MATRIX = float2x2(1.0, 0.0, -0.57735027, 1.15470054); +static const float WORLD_SCALE = 0.03464; +static const float INV_SQRT3 = 0.57735027; +// Blending constants +static const float3 DEFAULT_WEIGHTS = float3(0.33, 0.33, 0.34); +static const float3 LUMINANCE_WEIGHTS = float3(0.2126, 0.7152, 0.0722); +// Hash constants +static const float2 HASH_MULTIPLIER = float2(1271.5151, 3337.8237); +static const float2 HASH_SINE_MULTIPLIER = float2(43758.5453, 28637.1369); // Structure to hold stochastic sampling offsets and weights struct StochasticOffsets @@ -26,12 +37,11 @@ struct StochasticOffsets // Hash function for stochastic sampling inline float2 hash2D2D(float2 s) { - s = s * float2(1271.5151, 3337.8237); - return frac(sin(s.x + s.y) * float2(43758.5453, 28637.1369)); + s = s * HASH_MULTIPLIER; + return frac(sin(s.x + s.y) * HASH_SINE_MULTIPLIER); } // Compute single offset for stochastic sampling (optimized for single sample) -inline float2 ComputeStochasticOffsets1(float3 worldPos, uint eyeIndex = 0) { // Add CameraPosAdjust to stabilize pattern with camera movement float2 worldUV = worldPos.xy + FrameBuffer::CameraPosAdjust[eyeIndex].xy; @@ -45,28 +55,54 @@ inline float2 ComputeStochasticOffsets1(float3 worldPos, uint eyeIndex = 0) // Return only the first hash offset return hash2D2D(firstVertexID); +inline float2 ComputeWorldUV(float3 worldPos, uint eyeIndex = 0) +{ + return (worldPos.xy + FrameBuffer::CameraPosAdjust[eyeIndex].xy) * WORLD_SCALE; } + // Generate world-position based stochastic offsets for terrain. Fixes cell border issues. inline StochasticOffsets ComputeStochasticOffsets(float3 worldPos, uint eyeIndex = 0) { float2 worldUV = worldPos.xy + FrameBuffer::CameraPosAdjust[eyeIndex].xy; float2 skewUV = mul(float2x2(1.0, 0.0, -0.57735027, 1.15470054), worldUV * 0.03464); +inline StochasticOffsets ComputeStochasticOffsets(float2 precomputedWorldUV, float2 screenPos = float2(0, 0)) +{ + float2 skewUV = mul(SKEW_MATRIX, precomputedWorldUV); float2 vxID = floor(skewUV); float3 barry = float3(frac(skewUV), 0.0); barry.z = 1.0 - barry.x - barry.y; + float2 frac_uv = frac(skewUV); + float barry_z = 1.0 - frac_uv.x - frac_uv.y; + float3 barry = float3(frac_uv, barry_z); + // Calculate vertex IDs and barycentric weights for the triangle float4x3 BW_vx = (barry.z > 0) ? float4x3(float3(vxID, 0), float3(vxID + float2(0, 1), 0), float3(vxID + float2(1, 0), 0), barry.zyx) : float4x3(float3(vxID + float2(1, 1), 0), float3(vxID + float2(1, 0), 0), float3(vxID + float2(0, 1), 0), float3(-barry.z, 1.0 - barry.y, 1.0 - barry.x)); + // Generate offsets and store weights StochasticOffsets offsets; offsets.offset1 = hash2D2D(BW_vx[0].xy); offsets.offset2 = hash2D2D(BW_vx[1].xy); offsets.offset3 = hash2D2D(BW_vx[2].xy); offsets.weights = BW_vx[3]; + // Apply checkerboard dithering to reduce computation cost + [branch] if (SharedData::terrainVariationSettings.frameIndex > 10 && any(screenPos)) + { + float ditherMask = ComputeCheckerboardDither(screenPos, SharedData::terrainVariationSettings.frameIndex); + + // For pixels that are "off" in the checkerboard, reduce computation by using simpler interpolation + if (ditherMask < 0.5) + { + // Use simplified sampling - blend first two offsets only for performance + offsets.offset3 = lerp(offsets.offset1, offsets.offset2, 0.5); + offsets.weights = float3(offsets.weights.x * 0.6, offsets.weights.y * 0.6, 0.4); + } + } + return offsets; } @@ -109,37 +145,41 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler float height2 = sample2.a > 0 ? sample2.a : dot(sample2.rgb, float3(0.2126, 0.7152, 0.0722)); float height3 = sample3.a > 0 ? sample3.a : dot(sample3.rgb, float3(0.2126, 0.7152, 0.0722)); - float weight1 = lerp(blendWeights.x, height1 * blendWeights.x, HEIGHT_INFLUENCE); - float weight2 = lerp(blendWeights.y, height2 * blendWeights.y, HEIGHT_INFLUENCE); - float weight3 = lerp(blendWeights.z, height3 * blendWeights.z, HEIGHT_INFLUENCE); + float3 heights = float3(height1, height2, height3); + float3 weights = blendWeights * (1.0 + HEIGHT_INFLUENCE * (heights - 1.0)); // Blend samples with height-adjusted weights - float4 result = sample1 * weight1 + sample2 * weight2 + sample3 * weight3; + float4 result = sample1 * weights.x + sample2 * weights.y + sample3 * weights.z; // Renormalize final result - float finalWeightSum = weight1 + weight2 + weight3; - if (finalWeightSum > 0.0) { - result /= finalWeightSum; - } + float finalWeightSum = weights.x + weights.y + weights.z; return result; } -// Cheap Stochastic Effect for single sample. Used for RMAOS. -inline float4 StochasticSample1(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy, float3 worldPos = float3(0,0,0), uint eyeIndex = 0) -{ - // Directly compute a single offset using the faster dedicated function - use worldPos if available - float2 singleOffset; - if (worldPos.x != 0 || worldPos.y != 0 || worldPos.z != 0) - singleOffset = ComputeStochasticOffsets1(worldPos, eyeIndex); - else - singleOffset = offsets.offset1; // Fall back to pre-computed offset if no worldPos - - return tex.SampleLevel(samp, uv + singleOffset, mipLevel); -} +// --------------------- SPECIAL USE CASES --------------------- // + +// // Compute single offset for stochastic sampling (optimized for single sample) +// inline float2 ComputeStochasticOffsets1(float2 precomputedWorldUV) +// { +// float2 skewUV = mul(SKEW_MATRIX, precomputedWorldUV); +// float2 vxID = floor(skewUV); +// float3 barry = float3(frac(skewUV), 0.0); +// barry.z = 1.0 - barry.x - barry.y; + +// float2 firstVertexID = (barry.z > 0) ? vxID : (vxID + float2(1, 1)); +// return hash2D2D(firstVertexID); +// } + +// // Cheap Stochastic Effect for single sample. Used for RMAOS. +// inline float4 StochasticSample1(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) +// { +// float2 precomputedWorldUV = ComputeWorldUV(worldPos, eyeIndex); +// float2 singleOffset = ComputeStochasticOffsets1(precomputedWorldUV); +// return tex.SampleLevel(samp, uv + singleOffset, mipLevel); +// } // Same as StochasticEffect but no height/luminescence influence, so much cheaper but worse quality, doesn't matter for the use case. -inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for parallaxcoords & getheight funct. { // Sample the three texture offsets using the provided mip level float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); @@ -158,8 +198,7 @@ inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, Sample inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 UV) { - // Use a much smaller scale factor for LOD terrain to create subtle variation - // instead of dramatic pattern changes + // Use a much smaller scale factor for LOD terrain to create subtle variation instead of dramatic pattern changes float2 skewUV = mul(float2x2(1.0, 0.0, -0.57735027, 1.15470054), UV * 1.5); float2 vxID = floor(skewUV); float3 barry = float3(frac(skewUV), 0.0); From 29bf64435d85fde78a259546dc0222bddef80aa0 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Mon, 2 Jun 2025 09:36:52 +1000 Subject: [PATCH 16/53] Update Lighting.hlsl --- package/Shaders/Lighting.hlsl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index cab9d99288..ed4b01f999 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1278,12 +1278,14 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(TERRAIN_VARIATION) bool useTerrainVariation = SharedData::terrainVariationSettings.enableTilingFix; float2 dx, dy; + float2 precomputedWorldUV; StochasticOffsets sharedOffset; [branch] if (useTerrainVariation) { dx = ddx(uv); dy = ddy(uv); - sharedOffsets = ComputeStochasticOffsets(input.WorldPosition.xyz, eyeIndex); + precomputedWorldUV = ComputeWorldUV(input.WorldPosition.xyz, eyeIndex); + sharedOffset = ComputeStochasticOffsets(precomputedWorldUV); } # endif From 6e97b8531572dac1ff933bdc75bf41f8dcad942e Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Mon, 2 Jun 2025 10:00:35 +1000 Subject: [PATCH 17/53] Update TerrainVariation.hlsli --- .../TerrainVariation/TerrainVariation.hlsli | 36 +------------------ 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index f45e78a44f..b3002856bd 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -41,20 +41,6 @@ inline float2 hash2D2D(float2 s) return frac(sin(s.x + s.y) * HASH_SINE_MULTIPLIER); } -// Compute single offset for stochastic sampling (optimized for single sample) -{ - // Add CameraPosAdjust to stabilize pattern with camera movement - float2 worldUV = worldPos.xy + FrameBuffer::CameraPosAdjust[eyeIndex].xy; - float2 skewUV = mul(float2x2(1.0, 0.0, -0.57735027, 1.15470054), worldUV * 0.03464); - float2 vxID = floor(skewUV); - float3 barry = float3(frac(skewUV), 0.0); - barry.z = 1.0 - barry.x - barry.y; - - // Only compute the first vertex ID based on barycentric coordinates - float2 firstVertexID = (barry.z > 0) ? vxID : (vxID + float2(1, 1)); - - // Return only the first hash offset - return hash2D2D(firstVertexID); inline float2 ComputeWorldUV(float3 worldPos, uint eyeIndex = 0) { return (worldPos.xy + FrameBuffer::CameraPosAdjust[eyeIndex].xy) * WORLD_SCALE; @@ -62,17 +48,10 @@ inline float2 ComputeWorldUV(float3 worldPos, uint eyeIndex = 0) // Generate world-position based stochastic offsets for terrain. Fixes cell border issues. -inline StochasticOffsets ComputeStochasticOffsets(float3 worldPos, uint eyeIndex = 0) -{ - float2 worldUV = worldPos.xy + FrameBuffer::CameraPosAdjust[eyeIndex].xy; - - float2 skewUV = mul(float2x2(1.0, 0.0, -0.57735027, 1.15470054), worldUV * 0.03464); inline StochasticOffsets ComputeStochasticOffsets(float2 precomputedWorldUV, float2 screenPos = float2(0, 0)) { float2 skewUV = mul(SKEW_MATRIX, precomputedWorldUV); float2 vxID = floor(skewUV); - float3 barry = float3(frac(skewUV), 0.0); - barry.z = 1.0 - barry.x - barry.y; float2 frac_uv = frac(skewUV); float barry_z = 1.0 - frac_uv.x - frac_uv.y; float3 barry = float3(frac_uv, barry_z); @@ -89,20 +68,6 @@ inline StochasticOffsets ComputeStochasticOffsets(float2 precomputedWorldUV, flo offsets.offset3 = hash2D2D(BW_vx[2].xy); offsets.weights = BW_vx[3]; - // Apply checkerboard dithering to reduce computation cost - [branch] if (SharedData::terrainVariationSettings.frameIndex > 10 && any(screenPos)) - { - float ditherMask = ComputeCheckerboardDither(screenPos, SharedData::terrainVariationSettings.frameIndex); - - // For pixels that are "off" in the checkerboard, reduce computation by using simpler interpolation - if (ditherMask < 0.5) - { - // Use simplified sampling - blend first two offsets only for performance - offsets.offset3 = lerp(offsets.offset1, offsets.offset2, 0.5); - offsets.weights = float3(offsets.weights.x * 0.6, offsets.weights.y * 0.6, 0.4); - } - } - return offsets; } @@ -180,6 +145,7 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler // } // Same as StochasticEffect but no height/luminescence influence, so much cheaper but worse quality, doesn't matter for the use case. +inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy, float2 screenPos = float2(0, 0)) { // Sample the three texture offsets using the provided mip level float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); From 87accaac5f977030a216d1d3c4455b05d72de843 Mon Sep 17 00:00:00 2001 From: davo0411 Date: Mon, 2 Jun 2025 00:01:01 +0000 Subject: [PATCH 18/53] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20clang-for?= =?UTF-8?q?mat=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TerrainVariation/TerrainVariation.hlsli | 50 +++++++++---------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index b3002856bd..e2567c9f83 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -5,9 +5,9 @@ #ifndef TERRAIN_VARIATION_HLSLI #define TERRAIN_VARIATION_HLSLI +#include "Common/FrameBuffer.hlsli" #include "Common/Random.hlsli" #include "Common/SharedData.hlsli" -#include "Common/FrameBuffer.hlsli" // --------------------- CONSTANTS AND STRUCTURES --------------------- // // Height blend operator settings - DO NOT CHANGE THESE VALUES. @@ -43,37 +43,35 @@ inline float2 hash2D2D(float2 s) inline float2 ComputeWorldUV(float3 worldPos, uint eyeIndex = 0) { - return (worldPos.xy + FrameBuffer::CameraPosAdjust[eyeIndex].xy) * WORLD_SCALE; + return (worldPos.xy + FrameBuffer::CameraPosAdjust[eyeIndex].xy) * WORLD_SCALE; } - // Generate world-position based stochastic offsets for terrain. Fixes cell border issues. inline StochasticOffsets ComputeStochasticOffsets(float2 precomputedWorldUV, float2 screenPos = float2(0, 0)) -{ - float2 skewUV = mul(SKEW_MATRIX, precomputedWorldUV); - float2 vxID = floor(skewUV); - float2 frac_uv = frac(skewUV); - float barry_z = 1.0 - frac_uv.x - frac_uv.y; - float3 barry = float3(frac_uv, barry_z); - - // Calculate vertex IDs and barycentric weights for the triangle - float4x3 BW_vx = (barry.z > 0) ? - float4x3(float3(vxID, 0), float3(vxID + float2(0, 1), 0), float3(vxID + float2(1, 0), 0), barry.zyx) : - float4x3(float3(vxID + float2(1, 1), 0), float3(vxID + float2(1, 0), 0), float3(vxID + float2(0, 1), 0), float3(-barry.z, 1.0 - barry.y, 1.0 - barry.x)); - - // Generate offsets and store weights - StochasticOffsets offsets; - offsets.offset1 = hash2D2D(BW_vx[0].xy); - offsets.offset2 = hash2D2D(BW_vx[1].xy); - offsets.offset3 = hash2D2D(BW_vx[2].xy); - offsets.weights = BW_vx[3]; - - return offsets; -} +{ + float2 skewUV = mul(SKEW_MATRIX, precomputedWorldUV); + float2 vxID = floor(skewUV); + float2 frac_uv = frac(skewUV); + float barry_z = 1.0 - frac_uv.x - frac_uv.y; + float3 barry = float3(frac_uv, barry_z); + // Calculate vertex IDs and barycentric weights for the triangle + float4x3 BW_vx = (barry.z > 0) ? + float4x3(float3(vxID, 0), float3(vxID + float2(0, 1), 0), float3(vxID + float2(1, 0), 0), barry.zyx) : + float4x3(float3(vxID + float2(1, 1), 0), float3(vxID + float2(1, 0), 0), float3(vxID + float2(0, 1), 0), float3(-barry.z, 1.0 - barry.y, 1.0 - barry.x)); + + // Generate offsets and store weights + StochasticOffsets offsets; + offsets.offset1 = hash2D2D(BW_vx[0].xy); + offsets.offset2 = hash2D2D(BW_vx[1].xy); + offsets.offset3 = hash2D2D(BW_vx[2].xy); + offsets.weights = BW_vx[3]; + + return offsets; +} // Main stochastic sampling function -inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy, float3 worldPos = float3(0,0,0)) // Used for normal/diffuse text. Luminence-based blending helps preserve details close to camera. +inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy, float3 worldPos = float3(0, 0, 0)) // Used for normal/diffuse text. Luminence-based blending helps preserve details close to camera. { // Early return if terrain variation is disabled [branch] if (!SharedData::terrainVariationSettings.enableTilingFix) @@ -110,7 +108,7 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler float height2 = sample2.a > 0 ? sample2.a : dot(sample2.rgb, float3(0.2126, 0.7152, 0.0722)); float height3 = sample3.a > 0 ? sample3.a : dot(sample3.rgb, float3(0.2126, 0.7152, 0.0722)); - float3 heights = float3(height1, height2, height3); + float3 heights = float3(height1, height2, height3); float3 weights = blendWeights * (1.0 + HEIGHT_INFLUENCE * (heights - 1.0)); // Blend samples with height-adjusted weights From f027838ee00b2f7c55ce681bf813a0cd82da942d Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Mon, 2 Jun 2025 11:00:24 +1000 Subject: [PATCH 19/53] Lod optimisations 1 --- .../TerrainVariation/TerrainVariation.hlsli | 114 +++++------------- 1 file changed, 27 insertions(+), 87 deletions(-) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index b3002856bd..9263fef9fa 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -124,26 +124,6 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler // --------------------- SPECIAL USE CASES --------------------- // -// // Compute single offset for stochastic sampling (optimized for single sample) -// inline float2 ComputeStochasticOffsets1(float2 precomputedWorldUV) -// { -// float2 skewUV = mul(SKEW_MATRIX, precomputedWorldUV); -// float2 vxID = floor(skewUV); -// float3 barry = float3(frac(skewUV), 0.0); -// barry.z = 1.0 - barry.x - barry.y; - -// float2 firstVertexID = (barry.z > 0) ? vxID : (vxID + float2(1, 1)); -// return hash2D2D(firstVertexID); -// } - -// // Cheap Stochastic Effect for single sample. Used for RMAOS. -// inline float4 StochasticSample1(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) -// { -// float2 precomputedWorldUV = ComputeWorldUV(worldPos, eyeIndex); -// float2 singleOffset = ComputeStochasticOffsets1(precomputedWorldUV); -// return tex.SampleLevel(samp, uv + singleOffset, mipLevel); -// } - // Same as StochasticEffect but no height/luminescence influence, so much cheaper but worse quality, doesn't matter for the use case. inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy, float2 screenPos = float2(0, 0)) { @@ -162,94 +142,53 @@ inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, Sample // --------------------- LOD SAMPLING FUNCTIONS --------------------- // -inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 UV) -{ - // Use a much smaller scale factor for LOD terrain to create subtle variation instead of dramatic pattern changes - float2 skewUV = mul(float2x2(1.0, 0.0, -0.57735027, 1.15470054), UV * 1.5); - float2 vxID = floor(skewUV); - float3 barry = float3(frac(skewUV), 0.0); - barry.z = 1.0 - barry.x - barry.y; - - // Create a more stable triangle pattern - float4x3 BW_vx = (barry.z > 0) ? - float4x3(float3(vxID, 0), float3(vxID + float2(0, 1), 0), float3(vxID + float2(1, 0), 0), barry.zyx) : - float4x3(float3(vxID + float2(1, 1), 0), float3(vxID + float2(1, 0), 0), float3(vxID + float2(0, 1), 0), float3(-barry.z, 1.0 - barry.y, 1.0 - barry.x)); - - // Generate smaller offsets for more subtle variation - StochasticOffsets offsetsLOD; - offsetsLOD.offset1 = hash2D2D(BW_vx[0].xy) * 0.08; - offsetsLOD.offset2 = hash2D2D(BW_vx[1].xy) * 0.08; - offsetsLOD.offset3 = hash2D2D(BW_vx[2].xy) * 0.08; - - // Use smoother weights with less contrast - float3 smoothWeights = BW_vx[3]; - // Apply mild smoothing to weights - smoothWeights = pow(smoothWeights, 0.15); - // Renormalize - smoothWeights /= (smoothWeights.x + smoothWeights.y + smoothWeights.z); - - offsetsLOD.weights = smoothWeights; - return offsetsLOD; +inline float2 hashLOD(float2 p) { + p = frac(p * 0.3183099); + return frac(17.0 * p.yx + p.x * p.y); } -// Special version for LOD mask textures that should have minimal blurring -inline float4 StochasticSampleLODMask(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) +inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 UV) { - float offsetScale = 0.04; - - // Add simple rotation to each offset (using the random value to vary rotation per pixel) - float angle1 = rnd * 3.14; // Random base angle between 0-2π - float angle2 = angle1 + 1.04; // ~120° offset - float angle3 = angle1 + 2.09; // ~240° offset - - // Create rotation matrices - float2x2 rot1 = float2x2(cos(angle1), -sin(angle1), sin(angle1), cos(angle1)); - float2x2 rot2 = float2x2(cos(angle2), -sin(angle2), sin(angle2), cos(angle2)); - float2x2 rot3 = float2x2(cos(angle3), -sin(angle3), sin(angle3), cos(angle3)); - - // Apply rotation to offsets before scaling them down - float2 microOffset1 = mul(rot1, offsets.offset1) * offsetScale; - float2 microOffset2 = mul(rot2, offsets.offset2) * offsetScale; - float2 microOffset3 = mul(rot3, offsets.offset3) * offsetScale; - - // Sample with rotated micro-offsets - float tinyMipBias = 0.05; - float4 sample1 = tex.SampleLevel(samp, uv + microOffset1, mipLevel + tinyMipBias); - float4 sample2 = tex.SampleLevel(samp, uv + microOffset2, mipLevel + tinyMipBias); - float4 sample3 = tex.SampleLevel(samp, uv + microOffset3, mipLevel + tinyMipBias); - - // Blend using the barycentric weights (unchanged) - float4 result = sample1 * offsets.weights.x + - sample2 * offsets.weights.y + - sample3 * offsets.weights.z; + // Simplified LOD offset calculation - much cheaper than full stochastic + float2 scaledUV = UV * 8.0; // Simple scaling instead of complex skew matrix + float2 cellID = floor(scaledUV); + float2 localUV = frac(scaledUV); + + // Simple hash-based offsets without complex triangle calculations + StochasticOffsets offsetsLOD; + offsetsLOD.offset1 = hashLOD(cellID) * 0.08; + offsetsLOD.offset2 = hashLOD(cellID + float2(1, 0)) * 0.08; - return result; + // Simplified weights based on local UV position + float3 simpleWeights = float3(0.4, 0.35, 0.25); + offsetsLOD.weights = simpleWeights; + + return offsetsLOD; } -// Stochastic sampling function for Full Terrain LOD. Uses rotated offsets for more variation. +// Stochastic sampling function for Terrain LOD & LOD Mask. inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) { float offsetScale = 0.15; - // Add simple rotation to each offset (using the random value to vary rotation per pixel) + // Add simple rotation to only two offsets (using the random value to vary rotation per pixel) float angle1 = rnd * 6.28; // Random base angle between 0-2π float angle2 = angle1 + 2.09; // ~120° offset - float angle3 = angle1 + 4.18; // ~240° offset - // Create rotation matrices + // Create rotation matrices for only two samples float2x2 rot1 = float2x2(cos(angle1), -sin(angle1), sin(angle1), cos(angle1)); float2x2 rot2 = float2x2(cos(angle2), -sin(angle2), sin(angle2), cos(angle2)); - float2x2 rot3 = float2x2(cos(angle3), -sin(angle3), sin(angle3), cos(angle3)); // Apply rotation to offsets before scaling them down float2 microOffset1 = mul(rot1, offsets.offset1) * offsetScale; float2 microOffset2 = mul(rot2, offsets.offset2) * offsetScale; - float2 microOffset3 = mul(rot3, offsets.offset3) * offsetScale; - // Sample with rotated micro-offsets + // Sample with rotated micro-offsets (only two samples) float4 sample1 = tex.SampleLevel(samp, uv + microOffset1, mipLevel); float4 sample2 = tex.SampleLevel(samp, uv + microOffset2, mipLevel); - float4 sample3 = tex.SampleLevel(samp, uv + microOffset3, mipLevel); + + // Interpolate the third sample from the first two + float4 sample3 = lerp(sample1, sample2, 0.5); // Blend using the barycentric weights float4 result = sample1 * offsets.weights.x + @@ -259,4 +198,5 @@ inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, Samp return result; } -#endif // TERRAIN_VARIATION_HLSLI \ No newline at end of file + +#endif // TERRAIN_VARIATION_HLSLI \ No newline at end of file From 406dcd381f2f3fa1b6dddca13720814563843144 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Mon, 2 Jun 2025 12:30:42 +1000 Subject: [PATCH 20/53] Big fix, uses texcoord0 now. --- .../TerrainVariation/TerrainVariation.hlsli | 85 ++++++++----------- package/Shaders/Lighting.hlsl | 13 ++- 2 files changed, 42 insertions(+), 56 deletions(-) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index 30bef0dc51..5f67102aac 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -5,19 +5,16 @@ #ifndef TERRAIN_VARIATION_HLSLI #define TERRAIN_VARIATION_HLSLI -#include "Common/FrameBuffer.hlsli" #include "Common/Random.hlsli" #include "Common/SharedData.hlsli" // --------------------- CONSTANTS AND STRUCTURES --------------------- // // Height blend operator settings - DO NOT CHANGE THESE VALUES. static const float HEIGHT_BLEND_CONTRAST = 16.0; // Controls sharpness of height-based transitions -static const float CULLING_THRESHOLD = 0.001; // Minimum weight threshold for sample culling static const float HEIGHT_INFLUENCE = 0.3; // How much height affects blending (0=pure stochastic, 1=pure height) // Pre-computed constants to avoid runtime calculations static const float2x2 SKEW_MATRIX = float2x2(1.0, 0.0, -0.57735027, 1.15470054); -static const float WORLD_SCALE = 0.03464; -static const float INV_SQRT3 = 0.57735027; +static const float WORLD_SCALE = 332.54; // Blending constants static const float3 DEFAULT_WEIGHTS = float3(0.33, 0.33, 0.34); static const float3 LUMINANCE_WEIGHTS = float3(0.2126, 0.7152, 0.0722); @@ -41,52 +38,43 @@ inline float2 hash2D2D(float2 s) return frac(sin(s.x + s.y) * HASH_SINE_MULTIPLIER); } -inline float2 ComputeWorldUV(float3 worldPos, uint eyeIndex = 0) -{ - return (worldPos.xy + FrameBuffer::CameraPosAdjust[eyeIndex].xy) * WORLD_SCALE; -} - -// Generate world-position based stochastic offsets for terrain. Fixes cell border issues. -inline StochasticOffsets ComputeStochasticOffsets(float2 precomputedWorldUV, float2 screenPos = float2(0, 0)) -{ - float2 skewUV = mul(SKEW_MATRIX, precomputedWorldUV); - float2 vxID = floor(skewUV); - float2 frac_uv = frac(skewUV); - float barry_z = 1.0 - frac_uv.x - frac_uv.y; - float3 barry = float3(frac_uv, barry_z); - - // Calculate vertex IDs and barycentric weights for the triangle - float4x3 BW_vx = (barry.z > 0) ? - float4x3(float3(vxID, 0), float3(vxID + float2(0, 1), 0), float3(vxID + float2(1, 0), 0), barry.zyx) : - float4x3(float3(vxID + float2(1, 1), 0), float3(vxID + float2(1, 0), 0), float3(vxID + float2(0, 1), 0), float3(-barry.z, 1.0 - barry.y, 1.0 - barry.x)); - - // Generate offsets and store weights - StochasticOffsets offsets; - offsets.offset1 = hash2D2D(BW_vx[0].xy); - offsets.offset2 = hash2D2D(BW_vx[1].xy); - offsets.offset3 = hash2D2D(BW_vx[2].xy); - offsets.weights = BW_vx[3]; - - return offsets; +inline StochasticOffsets ComputeStochasticOffsets(float2 landscapeUV) +{ + float2 scaledUV = landscapeUV * (WORLD_SCALE); + float2 skewUV = mul(SKEW_MATRIX, scaledUV); + float2 vxID = floor(skewUV); + float2 frac_uv = frac(skewUV); + float barry_z = 1.0 - frac_uv.x - frac_uv.y; + float3 barry = float3(frac_uv, barry_z); + float4x3 BW_vx = (barry.z > 0) ? + float4x3(float3(vxID, 0), float3(vxID + float2(0, 1), 0), float3(vxID + float2(1, 0), 0), barry.zyx) : + float4x3(float3(vxID + float2(1, 1), 0), float3(vxID + float2(1, 0), 0), float3(vxID + float2(0, 1), 0), float3(-barry.z, 1.0 - barry.y, 1.0 - barry.x)); + + StochasticOffsets offsets; + offsets.offset1 = hash2D2D(BW_vx[0].xy); + offsets.offset2 = hash2D2D(BW_vx[1].xy); + offsets.offset3 = hash2D2D(BW_vx[2].xy); + offsets.weights = BW_vx[3]; + + return offsets; } // Main stochastic sampling function -inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy, float3 worldPos = float3(0, 0, 0)) // Used for normal/diffuse text. Luminence-based blending helps preserve details close to camera. +inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for normal/diffuse text. Luminence-based blending helps preserve details close to camera. { // Early return if terrain variation is disabled [branch] if (!SharedData::terrainVariationSettings.enableTilingFix) { return tex.SampleBias(samp, uv, SharedData::MipBias); } - // Apply contrast to the initial blend weights (without height influence) float3 blendWeights = pow(saturate(offsets.weights), HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE)); // Renormalize the weights float totalWeight = blendWeights.x + blendWeights.y + blendWeights.z; - blendWeights = (totalWeight > 0.0) ? blendWeights / totalWeight : float3(0.33, 0.33, 0.34); + blendWeights = (totalWeight > 0.0) ? blendWeights / totalWeight : DEFAULT_WEIGHTS; - // Sample all three locations + // Sample all three locations using hash-based offsets float4 sample1, sample2, sample3; [branch] if (SharedData::extendedMaterialSettings.EnableTerrainParallax) { @@ -104,11 +92,11 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler } // Apply height-based weight adjustments - float height1 = sample1.a > 0 ? sample1.a : dot(sample1.rgb, float3(0.2126, 0.7152, 0.0722)); - float height2 = sample2.a > 0 ? sample2.a : dot(sample2.rgb, float3(0.2126, 0.7152, 0.0722)); - float height3 = sample3.a > 0 ? sample3.a : dot(sample3.rgb, float3(0.2126, 0.7152, 0.0722)); + float height1 = sample1.a > 0 ? sample1.a : dot(sample1.rgb, LUMINANCE_WEIGHTS); + float height2 = sample2.a > 0 ? sample2.a : dot(sample2.rgb, LUMINANCE_WEIGHTS); + float height3 = sample3.a > 0 ? sample3.a : dot(sample3.rgb, LUMINANCE_WEIGHTS); - float3 heights = float3(height1, height2, height3); + float3 heights = float3(height1, height2, height3); float3 weights = blendWeights * (1.0 + HEIGHT_INFLUENCE * (heights - 1.0)); // Blend samples with height-adjusted weights @@ -123,7 +111,7 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler // --------------------- SPECIAL USE CASES --------------------- // // Same as StochasticEffect but no height/luminescence influence, so much cheaper but worse quality, doesn't matter for the use case. -inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy, float2 screenPos = float2(0, 0)) +inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) { // Sample the three texture offsets using the provided mip level float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); @@ -141,23 +129,19 @@ inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, Sample // --------------------- LOD SAMPLING FUNCTIONS --------------------- // inline float2 hashLOD(float2 p) { - p = frac(p * 0.3183099); - return frac(17.0 * p.yx + p.x * p.y); + p = frac(p * 0.318); + return frac(p.x + p.y * 17.0); } -inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 UV) +inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 landscapeUV) { - // Simplified LOD offset calculation - much cheaper than full stochastic - float2 scaledUV = UV * 8.0; // Simple scaling instead of complex skew matrix + float2 scaledUV = landscapeUV * (WORLD_SCALE / 0.010416667) * 8.0; float2 cellID = floor(scaledUV); - float2 localUV = frac(scaledUV); - // Simple hash-based offsets without complex triangle calculations StochasticOffsets offsetsLOD; offsetsLOD.offset1 = hashLOD(cellID) * 0.08; offsetsLOD.offset2 = hashLOD(cellID + float2(1, 0)) * 0.08; - // Simplified weights based on local UV position float3 simpleWeights = float3(0.4, 0.35, 0.25); offsetsLOD.weights = simpleWeights; @@ -167,6 +151,11 @@ inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 UV) // Stochastic sampling function for Terrain LOD & LOD Mask. inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) { + // Early return if terrain variation is disabled + [branch] if (!SharedData::terrainVariationSettings.enableTilingFix) + { + return tex.SampleBias(samp, uv, SharedData::MipBias); + } float offsetScale = 0.15; // Add simple rotation to only two offsets (using the random value to vary rotation per pixel) diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 4ec090d2a3..8e5d1491fb 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1273,19 +1273,16 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(TRUE_PBR) float4 blendedRMAOS = 0; -# endif - // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) +# endif // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) # if defined(TERRAIN_VARIATION) bool useTerrainVariation = SharedData::terrainVariationSettings.enableTilingFix; float2 dx, dy; - float2 precomputedWorldUV; StochasticOffsets sharedOffset; [branch] if (useTerrainVariation) { - dx = ddx(uv); - dy = ddy(uv); - precomputedWorldUV = ComputeWorldUV(input.WorldPosition.xyz, eyeIndex); - sharedOffset = ComputeStochasticOffsets(precomputedWorldUV); + dx = ddx(input.TexCoord0.zw); + dy = ddy(input.TexCoord0.zw); + sharedOffset = ComputeStochasticOffsets(input.TexCoord0.zw); } # endif @@ -1966,7 +1963,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float2 dx = ddx(blendColorUV); float2 dy = ddy(blendColorUV); StochasticOffsets lodBlendColorOffset = ComputeStochasticOffsetsLOD(blendColorUV); - lodLandColor = StochasticSampleLODMask(screenNoise, 0, TexLandLodBlend1Sampler, SampLandLodBlend1Sampler, blendColorUV, lodBlendColorOffset, dx, dy); + lodLandColor = StochasticSampleLOD(screenNoise, 0, TexLandLodBlend1Sampler, SampLandLodBlend1Sampler, blendColorUV, lodBlendColorOffset, dx, dy); } else { lodLandColor = TexLandLodBlend1Sampler.Sample(SampLandLodBlend1Sampler, input.TexCoord0.zw); } From 8e935afc42908adbe03f4937ee20a5f1129a8fff Mon Sep 17 00:00:00 2001 From: davo0411 Date: Mon, 2 Jun 2025 02:31:12 +0000 Subject: [PATCH 21/53] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20clang-for?= =?UTF-8?q?mat=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TerrainVariation/TerrainVariation.hlsli | 48 +++++++++---------- package/Shaders/Lighting.hlsl | 2 +- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index 5f67102aac..763a7a8f13 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -39,24 +39,24 @@ inline float2 hash2D2D(float2 s) } inline StochasticOffsets ComputeStochasticOffsets(float2 landscapeUV) -{ +{ float2 scaledUV = landscapeUV * (WORLD_SCALE); float2 skewUV = mul(SKEW_MATRIX, scaledUV); - float2 vxID = floor(skewUV); - float2 frac_uv = frac(skewUV); - float barry_z = 1.0 - frac_uv.x - frac_uv.y; - float3 barry = float3(frac_uv, barry_z); - float4x3 BW_vx = (barry.z > 0) ? - float4x3(float3(vxID, 0), float3(vxID + float2(0, 1), 0), float3(vxID + float2(1, 0), 0), barry.zyx) : - float4x3(float3(vxID + float2(1, 1), 0), float3(vxID + float2(1, 0), 0), float3(vxID + float2(0, 1), 0), float3(-barry.z, 1.0 - barry.y, 1.0 - barry.x)); - - StochasticOffsets offsets; - offsets.offset1 = hash2D2D(BW_vx[0].xy); - offsets.offset2 = hash2D2D(BW_vx[1].xy); - offsets.offset3 = hash2D2D(BW_vx[2].xy); - offsets.weights = BW_vx[3]; - - return offsets; + float2 vxID = floor(skewUV); + float2 frac_uv = frac(skewUV); + float barry_z = 1.0 - frac_uv.x - frac_uv.y; + float3 barry = float3(frac_uv, barry_z); + float4x3 BW_vx = (barry.z > 0) ? + float4x3(float3(vxID, 0), float3(vxID + float2(0, 1), 0), float3(vxID + float2(1, 0), 0), barry.zyx) : + float4x3(float3(vxID + float2(1, 1), 0), float3(vxID + float2(1, 0), 0), float3(vxID + float2(0, 1), 0), float3(-barry.z, 1.0 - barry.y, 1.0 - barry.x)); + + StochasticOffsets offsets; + offsets.offset1 = hash2D2D(BW_vx[0].xy); + offsets.offset2 = hash2D2D(BW_vx[1].xy); + offsets.offset3 = hash2D2D(BW_vx[2].xy); + offsets.weights = BW_vx[3]; + + return offsets; } // Main stochastic sampling function @@ -96,7 +96,7 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler float height2 = sample2.a > 0 ? sample2.a : dot(sample2.rgb, LUMINANCE_WEIGHTS); float height3 = sample3.a > 0 ? sample3.a : dot(sample3.rgb, LUMINANCE_WEIGHTS); - float3 heights = float3(height1, height2, height3); + float3 heights = float3(height1, height2, height3); float3 weights = blendWeights * (1.0 + HEIGHT_INFLUENCE * (heights - 1.0)); // Blend samples with height-adjusted weights @@ -128,8 +128,9 @@ inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, Sample // --------------------- LOD SAMPLING FUNCTIONS --------------------- // -inline float2 hashLOD(float2 p) { - p = frac(p * 0.318); +inline float2 hashLOD(float2 p) +{ + p = frac(p * 0.318); return frac(p.x + p.y * 17.0); } @@ -137,14 +138,14 @@ inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 landscapeUV) { float2 scaledUV = landscapeUV * (WORLD_SCALE / 0.010416667) * 8.0; float2 cellID = floor(scaledUV); - + StochasticOffsets offsetsLOD; offsetsLOD.offset1 = hashLOD(cellID) * 0.08; offsetsLOD.offset2 = hashLOD(cellID + float2(1, 0)) * 0.08; float3 simpleWeights = float3(0.4, 0.35, 0.25); offsetsLOD.weights = simpleWeights; - + return offsetsLOD; } @@ -173,7 +174,7 @@ inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, Samp // Sample with rotated micro-offsets (only two samples) float4 sample1 = tex.SampleLevel(samp, uv + microOffset1, mipLevel); float4 sample2 = tex.SampleLevel(samp, uv + microOffset2, mipLevel); - + // Interpolate the third sample from the first two float4 sample3 = lerp(sample1, sample2, 0.5); @@ -185,5 +186,4 @@ inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, Samp return result; } - -#endif // TERRAIN_VARIATION_HLSLI \ No newline at end of file +#endif // TERRAIN_VARIATION_HLSLI \ No newline at end of file diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 8e5d1491fb..254c81788f 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1273,7 +1273,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(TRUE_PBR) float4 blendedRMAOS = 0; -# endif // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) +# endif // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) # if defined(TERRAIN_VARIATION) bool useTerrainVariation = SharedData::terrainVariationSettings.enableTilingFix; float2 dx, dy; From 654fbff2b73ae4de36705405787365b77a9c3d39 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Mon, 2 Jun 2025 17:00:30 +1000 Subject: [PATCH 22/53] Mipmap fixes --- .../TerrainVariation/TerrainVariation.hlsli | 21 +++------------- package/Shaders/Lighting.hlsl | 25 +++++++++++++------ 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index 763a7a8f13..5899836b25 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -65,7 +65,7 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler // Early return if terrain variation is disabled [branch] if (!SharedData::terrainVariationSettings.enableTilingFix) { - return tex.SampleBias(samp, uv, SharedData::MipBias); + return tex.SampleLevel(samp, uv, mipLevel); } // Apply contrast to the initial blend weights (without height influence) float3 blendWeights = pow(saturate(offsets.weights), HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE)); @@ -74,22 +74,9 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler float totalWeight = blendWeights.x + blendWeights.y + blendWeights.z; blendWeights = (totalWeight > 0.0) ? blendWeights / totalWeight : DEFAULT_WEIGHTS; - // Sample all three locations using hash-based offsets - float4 sample1, sample2, sample3; - [branch] if (SharedData::extendedMaterialSettings.EnableTerrainParallax) - { - // Parallax enabled, can use SampleLevel for better perf - sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); - sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); - sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); - } - else - { - // When parallax disabled, samplelevel causes mipmap issues, it uses too low a mipmap level up close. - sample1 = tex.SampleGrad(samp, uv + offsets.offset1, dx, dy); - sample2 = tex.SampleGrad(samp, uv + offsets.offset2, dx, dy); - sample3 = tex.SampleGrad(samp, uv + offsets.offset3, dx, dy); - } + float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); + float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); // Apply height-based weight adjustments float height1 = sample1.a > 0 ? sample1.a : dot(sample1.rgb, LUMINANCE_WEIGHTS); diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 254c81788f..0fdc428c2b 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1285,7 +1285,18 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace sharedOffset = ComputeStochasticOffsets(input.TexCoord0.zw); } # endif - +// Calculate mip levels for terrain variation when parallax is disabled +# if defined(TERRAIN_VARIATION) && defined(EMAT) && defined(TRUE_PBR) + if (useTerrainVariation && !SharedData::extendedMaterialSettings.EnableTerrainParallax) { + // Calculate basic mip level for terrain textures + mipLevels[0] = ExtendedMaterials::GetMipLevel(uv, TexColorSampler); + mipLevels[1] = ExtendedMaterials::GetMipLevel(uv, TexLandColor2Sampler); + mipLevels[2] = ExtendedMaterials::GetMipLevel(uv, TexLandColor3Sampler); + mipLevels[3] = ExtendedMaterials::GetMipLevel(uv, TexLandColor4Sampler); + mipLevels[4] = ExtendedMaterials::GetMipLevel(uv, TexLandColor5Sampler); + mipLevels[5] = ExtendedMaterials::GetMipLevel(uv, TexLandColor6Sampler); + } +# endif # if defined(EMAT) if (SharedData::extendedMaterialSettings.EnableTerrainParallax) { mipLevels[0] = ExtendedMaterials::GetMipLevel(uv, TexColorSampler); @@ -1425,7 +1436,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS1 = StochasticEffect(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + landRMAOS1 = StochasticSample3(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy) * float4(PBRParams1.x, 1, 1, PBRParams1.z); } else { @@ -1506,7 +1517,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS2 = StochasticEffect(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampLandRMAOS2Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); + landRMAOS2 = StochasticSample3(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampLandRMAOS2Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); } else { @@ -1563,7 +1574,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float4 landNormal3; [branch] if (useTerrainVariation) { - landNormal3 = StochasticEffect(screenNoise, mipLevels[2], TexLandNormal3Sampler, SampLandNormal3Sampler, uv, sharedOffset, dx, dy); + landNormal3 = StochasticSample3(screenNoise, mipLevels[2], TexLandNormal3Sampler, SampLandNormal3Sampler, uv, sharedOffset, dx, dy); } else { @@ -1586,7 +1597,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS3 = StochasticEffect(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampLandRMAOS3Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); + landRMAOS3 = StochasticSample3(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampLandRMAOS3Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); } else { @@ -1666,7 +1677,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS4 = StochasticEffect(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampLandRMAOS4Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); + landRMAOS4 = StochasticSample3(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampLandRMAOS4Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); } else { @@ -1747,7 +1758,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS5 = StochasticEffect(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampLandRMAOS5Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); + landRMAOS5 = StochasticSample3(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampLandRMAOS5Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); } else { From 677b26883bbf94f2695b1d69794aa7df58b53ded Mon Sep 17 00:00:00 2001 From: davo0411 Date: Mon, 2 Jun 2025 07:00:57 +0000 Subject: [PATCH 23/53] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20clang-for?= =?UTF-8?q?mat=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TerrainVariation/TerrainVariation.hlsli | 2 +- package/Shaders/Lighting.hlsl | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index 5899836b25..51b7f07226 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -74,7 +74,7 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler float totalWeight = blendWeights.x + blendWeights.y + blendWeights.z; blendWeights = (totalWeight > 0.0) ? blendWeights / totalWeight : DEFAULT_WEIGHTS; - float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 0fdc428c2b..ca64c9ec1d 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1287,15 +1287,15 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif // Calculate mip levels for terrain variation when parallax is disabled # if defined(TERRAIN_VARIATION) && defined(EMAT) && defined(TRUE_PBR) - if (useTerrainVariation && !SharedData::extendedMaterialSettings.EnableTerrainParallax) { - // Calculate basic mip level for terrain textures - mipLevels[0] = ExtendedMaterials::GetMipLevel(uv, TexColorSampler); - mipLevels[1] = ExtendedMaterials::GetMipLevel(uv, TexLandColor2Sampler); - mipLevels[2] = ExtendedMaterials::GetMipLevel(uv, TexLandColor3Sampler); - mipLevels[3] = ExtendedMaterials::GetMipLevel(uv, TexLandColor4Sampler); - mipLevels[4] = ExtendedMaterials::GetMipLevel(uv, TexLandColor5Sampler); - mipLevels[5] = ExtendedMaterials::GetMipLevel(uv, TexLandColor6Sampler); - } + if (useTerrainVariation && !SharedData::extendedMaterialSettings.EnableTerrainParallax) { + // Calculate basic mip level for terrain textures + mipLevels[0] = ExtendedMaterials::GetMipLevel(uv, TexColorSampler); + mipLevels[1] = ExtendedMaterials::GetMipLevel(uv, TexLandColor2Sampler); + mipLevels[2] = ExtendedMaterials::GetMipLevel(uv, TexLandColor3Sampler); + mipLevels[3] = ExtendedMaterials::GetMipLevel(uv, TexLandColor4Sampler); + mipLevels[4] = ExtendedMaterials::GetMipLevel(uv, TexLandColor5Sampler); + mipLevels[5] = ExtendedMaterials::GetMipLevel(uv, TexLandColor6Sampler); + } # endif # if defined(EMAT) if (SharedData::extendedMaterialSettings.EnableTerrainParallax) { From bdb32b73015b11ac1901db91ec8cea5b81d82dbb Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Tue, 3 Jun 2025 08:29:50 +1000 Subject: [PATCH 24/53] LOD Optimisation --- .../TerrainVariation/TerrainVariation.hlsli | 69 ++++++++----------- 1 file changed, 28 insertions(+), 41 deletions(-) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index 51b7f07226..9a723727ca 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -62,11 +62,6 @@ inline StochasticOffsets ComputeStochasticOffsets(float2 landscapeUV) // Main stochastic sampling function inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for normal/diffuse text. Luminence-based blending helps preserve details close to camera. { - // Early return if terrain variation is disabled - [branch] if (!SharedData::terrainVariationSettings.enableTilingFix) - { - return tex.SampleLevel(samp, uv, mipLevel); - } // Apply contrast to the initial blend weights (without height influence) float3 blendWeights = pow(saturate(offsets.weights), HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE)); @@ -74,7 +69,7 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler float totalWeight = blendWeights.x + blendWeights.y + blendWeights.z; blendWeights = (totalWeight > 0.0) ? blendWeights / totalWeight : DEFAULT_WEIGHTS; - float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); @@ -123,15 +118,22 @@ inline float2 hashLOD(float2 p) inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 landscapeUV) { - float2 scaledUV = landscapeUV * (WORLD_SCALE / 0.010416667) * 8.0; + // Precomputed scaling: (WORLD_SCALE / 0.010416667) * 8.0 = ~255437 + static const float LOD_SCALE = 255437.0; + + float2 scaledUV = landscapeUV * LOD_SCALE; float2 cellID = floor(scaledUV); StochasticOffsets offsetsLOD; - offsetsLOD.offset1 = hashLOD(cellID) * 0.08; - offsetsLOD.offset2 = hashLOD(cellID + float2(1, 0)) * 0.08; - - float3 simpleWeights = float3(0.4, 0.35, 0.25); - offsetsLOD.weights = simpleWeights; + // Generate both offsets from single hash to reduce calls + float2 hash1 = hashLOD(cellID); + float2 hash2 = hashLOD(cellID + 127.0); // Different offset for variation + + offsetsLOD.offset1 = hash1 * 0.08; + offsetsLOD.offset2 = hash2 * 0.08; + + // Simplified weights since we only use 2 samples now + offsetsLOD.weights = float3(0.65, 0.35, 0.0); return offsetsLOD; } @@ -139,38 +141,23 @@ inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 landscapeUV) // Stochastic sampling function for Terrain LOD & LOD Mask. inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) { - // Early return if terrain variation is disabled - [branch] if (!SharedData::terrainVariationSettings.enableTilingFix) - { - return tex.SampleBias(samp, uv, SharedData::MipBias); - } - float offsetScale = 0.15; - - // Add simple rotation to only two offsets (using the random value to vary rotation per pixel) - float angle1 = rnd * 6.28; // Random base angle between 0-2π - float angle2 = angle1 + 2.09; // ~120° offset - - // Create rotation matrices for only two samples - float2x2 rot1 = float2x2(cos(angle1), -sin(angle1), sin(angle1), cos(angle1)); - float2x2 rot2 = float2x2(cos(angle2), -sin(angle2), sin(angle2), cos(angle2)); - - // Apply rotation to offsets before scaling them down - float2 microOffset1 = mul(rot1, offsets.offset1) * offsetScale; - float2 microOffset2 = mul(rot2, offsets.offset2) * offsetScale; - - // Sample with rotated micro-offsets (only two samples) - float4 sample1 = tex.SampleLevel(samp, uv + microOffset1, mipLevel); - float4 sample2 = tex.SampleLevel(samp, uv + microOffset2, mipLevel); + float offsetScale = 0.01; - // Interpolate the third sample from the first two - float4 sample3 = lerp(sample1, sample2, 0.5); + // Cheap pseudo-rotation using simple transforms + float2 dir1 = float2(rnd - 0.5, frac(rnd * 1.618) - 0.5); + float2 dir2 = float2(dir1.y, -dir1.x); + + // Apply simple scaled offsets + float2 microOffset1 = (offsets.offset1 + dir1) * offsetScale; + float2 microOffset2 = (offsets.offset2 + dir2) * offsetScale; - // Blend using the barycentric weights - float4 result = sample1 * offsets.weights.x + - sample2 * offsets.weights.y + - sample3 * offsets.weights.z; + // Sample only two offsets + float4 sample1 = tex.SampleLevel(samp, uv + microOffset1, mipLevel); + float4 sample2 = tex.SampleLevel(samp, uv + microOffset2, mipLevel); - return result; + // Simple 2-sample blend weighted toward first sample + return lerp(sample2, sample1, 0.65); } + #endif // TERRAIN_VARIATION_HLSLI \ No newline at end of file From c119fddb84e275d2a61c22e012054090a21d4c99 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Tue, 3 Jun 2025 13:38:22 +1000 Subject: [PATCH 25/53] Mipmap fixes --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 67 +++++---- .../TerrainVariation/TerrainVariation.hlsli | 140 ++++++++++++------ package/Shaders/Lighting.hlsl | 2 + 3 files changed, 132 insertions(+), 77 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index 33554b464d..e1859882da 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -44,35 +44,46 @@ namespace ExtendedMaterials float2 textureDims; tex.GetDimensions(textureDims.x, textureDims.y); -#if !defined(PARALLAX) && !defined(TRUE_PBR) - textureDims /= 2.0; -#endif - -#if defined(VR) - textureDims /= 2.0; -#endif - - float2 texCoordsPerSize = coords * textureDims; - - float2 dxSize = ddx(texCoordsPerSize); - float2 dySize = ddy(texCoordsPerSize); - - // Find min of change in u and v across quad: compute du and dv magnitude across quad - //float2 dTexCoords = dxSize * dxSize + dySize * dySize; - - // Standard mipmapping uses max here - float minTexCoordDelta = min(dot(dxSize, dxSize), dot(dySize, dySize)); - - // Compute the current mip level (* 0.5 is effectively computing a square root before ) - float mipLevel = max(0.5 * log2(minTexCoordDelta), 0); - -#if !defined(PARALLAX) && !defined(TRUE_PBR) - mipLevel++; -#endif + #if !defined(TERRAIN_VARIATION) + textureDims /= 2.0; + #endif + + #if !defined(PARALLAX) && !defined(TRUE_PBR) + textureDims /= 2.0; + #endif + + #if defined(VR) + textureDims /= 2.0; + #endif + + float2 texCoordsPerSize = coords * textureDims; + + float2 dxSize = ddx(texCoordsPerSize); + float2 dySize = ddy(texCoordsPerSize); + + // Find min of change in u and v across quad: compute du and dv magnitude across quad + //float2 dTexCoords = dxSize * dxSize + dySize * dySize; + + // Standard mipmapping uses max here + float minTexCoordDelta = min(dot(dxSize, dxSize), dot(dySize, dySize)); + + // Compute the current mip level (* 0.5 is effectively computing a square root before ) + float mipLevel = max(0.5 * log2(minTexCoordDelta), 0); + + #if !defined(PARALLAX) && !defined(TRUE_PBR) + mipLevel++; + #endif + + #if defined(TERRAIN_VARIATION) + [branch] if (SharedData::extendedMaterialSettings.EnableTerrainParallax) + { + mipLevel++; + } + #endif -#if defined(VR) - mipLevel++; -#endif + #if defined(VR) + mipLevel++; + #endif return mipLevel; } diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index 9a723727ca..8ca34b749e 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -38,74 +38,117 @@ inline float2 hash2D2D(float2 s) return frac(sin(s.x + s.y) * HASH_SINE_MULTIPLIER); } +// Common barycentric coordinate calculation for stochastic sampling +inline float4x3 ComputeBarycentricVerts(float2 landscapeUV) +{ + float2 scaledUV = landscapeUV * (WORLD_SCALE); + float2 skewUV = mul(SKEW_MATRIX, scaledUV); + float2 vxID = floor(skewUV); + float2 frac_uv = frac(skewUV); + float barry_z = 1.0 - frac_uv.x - frac_uv.y; + float3 barry = float3(frac_uv, barry_z); + + return (barry.z > 0) ? + float4x3(float3(vxID, 0), float3(vxID + float2(0, 1), 0), float3(vxID + float2(1, 0), 0), barry.zyx) : + float4x3(float3(vxID + float2(1, 1), 0), float3(vxID + float2(1, 0), 0), float3(vxID + float2(0, 1), 0), float3(-barry.z, 1.0 - barry.y, 1.0 - barry.x)); +} + inline StochasticOffsets ComputeStochasticOffsets(float2 landscapeUV) { - float2 scaledUV = landscapeUV * (WORLD_SCALE); - float2 skewUV = mul(SKEW_MATRIX, scaledUV); - float2 vxID = floor(skewUV); - float2 frac_uv = frac(skewUV); - float barry_z = 1.0 - frac_uv.x - frac_uv.y; - float3 barry = float3(frac_uv, barry_z); - float4x3 BW_vx = (barry.z > 0) ? - float4x3(float3(vxID, 0), float3(vxID + float2(0, 1), 0), float3(vxID + float2(1, 0), 0), barry.zyx) : - float4x3(float3(vxID + float2(1, 1), 0), float3(vxID + float2(1, 0), 0), float3(vxID + float2(0, 1), 0), float3(-barry.z, 1.0 - barry.y, 1.0 - barry.x)); - - StochasticOffsets offsets; - offsets.offset1 = hash2D2D(BW_vx[0].xy); - offsets.offset2 = hash2D2D(BW_vx[1].xy); - offsets.offset3 = hash2D2D(BW_vx[2].xy); - offsets.weights = BW_vx[3]; - - return offsets; + float4x3 BW_vx = ComputeBarycentricVerts(landscapeUV); + + StochasticOffsets offsets; + offsets.offset1 = hash2D2D(BW_vx[0].xy); + offsets.offset2 = hash2D2D(BW_vx[1].xy); + offsets.offset3 = hash2D2D(BW_vx[2].xy); + offsets.weights = BW_vx[3]; + + return offsets; } // Main stochastic sampling function inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for normal/diffuse text. Luminence-based blending helps preserve details close to camera. -{ - // Apply contrast to the initial blend weights (without height influence) - float3 blendWeights = pow(saturate(offsets.weights), HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE)); +{ + // Apply contrast to the initial blend weights (without height influence) + float3 blendWeights = pow(saturate(offsets.weights), HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE)); - // Renormalize the weights - float totalWeight = blendWeights.x + blendWeights.y + blendWeights.z; - blendWeights = (totalWeight > 0.0) ? blendWeights / totalWeight : DEFAULT_WEIGHTS; + // Renormalize the weights + float totalWeight = blendWeights.x + blendWeights.y + blendWeights.z; + blendWeights = (totalWeight > 0.0) ? blendWeights / totalWeight : DEFAULT_WEIGHTS; - float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); - float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); - float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); + float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); + float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); - // Apply height-based weight adjustments - float height1 = sample1.a > 0 ? sample1.a : dot(sample1.rgb, LUMINANCE_WEIGHTS); - float height2 = sample2.a > 0 ? sample2.a : dot(sample2.rgb, LUMINANCE_WEIGHTS); - float height3 = sample3.a > 0 ? sample3.a : dot(sample3.rgb, LUMINANCE_WEIGHTS); + // Apply height-based weight adjustments + float height1 = sample1.a > 0 ? sample1.a : dot(sample1.rgb, LUMINANCE_WEIGHTS); + float height2 = sample2.a > 0 ? sample2.a : dot(sample2.rgb, LUMINANCE_WEIGHTS); + float height3 = sample3.a > 0 ? sample3.a : dot(sample3.rgb, LUMINANCE_WEIGHTS); - float3 heights = float3(height1, height2, height3); - float3 weights = blendWeights * (1.0 + HEIGHT_INFLUENCE * (heights - 1.0)); + float3 heights = float3(height1, height2, height3); + float3 weights = blendWeights * (1.0 + HEIGHT_INFLUENCE * (heights - 1.0)); - // Blend samples with height-adjusted weights - float4 result = sample1 * weights.x + sample2 * weights.y + sample3 * weights.z; + // Blend samples with height-adjusted weights + float4 result = sample1 * weights.x + sample2 * weights.y + sample3 * weights.z; - // Renormalize final result - float finalWeightSum = weights.x + weights.y + weights.z; + // Renormalize final result + float finalWeightSum = weights.x + weights.y + weights.z; - return result; + return result; } // --------------------- SPECIAL USE CASES --------------------- // // Same as StochasticEffect but no height/luminescence influence, so much cheaper but worse quality, doesn't matter for the use case. inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) -{ - // Sample the three texture offsets using the provided mip level - float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); - float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); - float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); +{ + // Sample the three texture offsets + float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); + float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); + + // Blend using the barycentric weights + float4 result = sample1 * offsets.weights.x + + sample2 * offsets.weights.y + + sample3 * offsets.weights.z; + + return result; +} - // Blend using the barycentric weights - float4 result = sample1 * offsets.weights.x + - sample2 * offsets.weights.y + - sample3 * offsets.weights.z; +// Simplified version for functions that only need 2 offsets +inline StochasticOffsets ComputeStochasticOffsets2(float2 landscapeUV) +{ + float4x3 BW_vx = ComputeBarycentricVerts(landscapeUV); + + StochasticOffsets offsets2; + offsets2.offset1 = hash2D2D(BW_vx[0].xy); + offsets2.offset2 = hash2D2D(BW_vx[1].xy); + offsets2.offset3 = float2(0, 0); + offsets2.weights = float3(BW_vx[3].x, BW_vx[3].y, 0.0); + + return offsets2; +} - return result; +// Cheap 2 sample version. +inline float4 StochasticSample2(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) +{ + // Sample only two texture offsets using the provided mip level + float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); + + // Use proper weight normalization to avoid artifacts + float2 weights2D = offsets.weights.xy; + float totalWeight = weights2D.x + weights2D.y; + if (totalWeight > 0.0) { + weights2D /= totalWeight; + } else { + weights2D = float2(0.5, 0.5); + } + + // Direct blend without third interpolated sample + float4 result = sample1 * weights2D.x + sample2 * weights2D.y; + + return result; } // --------------------- LOD SAMPLING FUNCTIONS --------------------- // @@ -127,7 +170,7 @@ inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 landscapeUV) StochasticOffsets offsetsLOD; // Generate both offsets from single hash to reduce calls float2 hash1 = hashLOD(cellID); - float2 hash2 = hashLOD(cellID + 127.0); // Different offset for variation + float2 hash2 = hashLOD(cellID + 127.0); offsetsLOD.offset1 = hash1 * 0.08; offsetsLOD.offset2 = hash2 * 0.08; @@ -159,5 +202,4 @@ inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, Samp return lerp(sample2, sample1, 0.65); } - #endif // TERRAIN_VARIATION_HLSLI \ No newline at end of file diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index ca64c9ec1d..430e7f2121 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1278,11 +1278,13 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace bool useTerrainVariation = SharedData::terrainVariationSettings.enableTilingFix; float2 dx, dy; StochasticOffsets sharedOffset; + StochasticOffsets sharedOffset2; [branch] if (useTerrainVariation) { dx = ddx(input.TexCoord0.zw); dy = ddy(input.TexCoord0.zw); sharedOffset = ComputeStochasticOffsets(input.TexCoord0.zw); + sharedOffset2 = ComputeStochasticOffsets2(input.TexCoord0.zw); } # endif // Calculate mip levels for terrain variation when parallax is disabled From 6442286c2ad7684a19f401e9139d1051b67fefb6 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Tue, 3 Jun 2025 14:45:20 +1000 Subject: [PATCH 26/53] tidy --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 160 +----------------- 1 file changed, 2 insertions(+), 158 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index e1859882da..43a5e29e45 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -5,11 +5,8 @@ // http://www.diva-portal.org/smash/get/diva2:831762/FULLTEXT01.pdf // https://bartwronski.files.wordpress.com/2014/03/ac4_gdc.pdf -#if defined(LANDSCAPE) && defined(TERRAIN_VARIATION) -# define USE_TERRAIN_VARIATION 1 +#if defined(TERRAIN_VARIATION) # include "TerrainVariation/TerrainVariation.hlsli" -#else -# define USE_TERRAIN_VARIATION 0 #endif struct DisplacementParams @@ -110,14 +107,8 @@ namespace ExtendedMaterials { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexLandDisplacement0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); - } - else - { - h = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); - } + # else h = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); # endif @@ -128,14 +119,7 @@ namespace ExtendedMaterials { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandDisplacement1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); - } - else - { - h = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); - } # else h = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); # endif @@ -146,14 +130,7 @@ namespace ExtendedMaterials { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandDisplacement2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); - } - else - { - h = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); - } # else h = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); # endif @@ -164,14 +141,7 @@ namespace ExtendedMaterials { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); - } - else - { - h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); - } # else h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); # endif @@ -182,14 +152,7 @@ namespace ExtendedMaterials { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); - } - else - { - h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); - } # else h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); # endif @@ -200,14 +163,7 @@ namespace ExtendedMaterials { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); - } - else - { - h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); - } # else h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); # endif @@ -253,14 +209,7 @@ namespace ExtendedMaterials [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand0HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexLandTHDisp0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); - } - else - { - h = ScaleDisplacement(TexLandTHDisp0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); - } # else h = ScaleDisplacement(TexLandTHDisp0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); # endif @@ -268,14 +217,7 @@ namespace ExtendedMaterials else { # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexColorSampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[0]); - } - else - { - h = ScaleDisplacement(TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, params[0]); - } # else h = ScaleDisplacement(TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, params[0]); # endif @@ -288,14 +230,7 @@ namespace ExtendedMaterials [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandTHDisp1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); - } - else - { - h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); - } # else h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); # endif @@ -303,14 +238,7 @@ namespace ExtendedMaterials else { # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandColor2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[1]); - } - else - { - h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); - } # else h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); # endif @@ -323,14 +251,7 @@ namespace ExtendedMaterials [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandTHDisp2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); - } - else - { - h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); - } # else h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); # endif @@ -338,14 +259,7 @@ namespace ExtendedMaterials else { # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandColor3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[2]); - } - else - { - h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); - } # else h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); # endif @@ -357,14 +271,7 @@ namespace ExtendedMaterials { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); - } - else - { - h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); - } # else h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); # endif @@ -375,14 +282,7 @@ namespace ExtendedMaterials { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); - } - else - { - h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); - } # else h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); # endif @@ -393,14 +293,7 @@ namespace ExtendedMaterials { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); - } - else - { - h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); - } # else h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); # endif @@ -806,14 +699,7 @@ namespace ExtendedMaterials [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandTHDisp1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); - } - else - { - h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); - } # else h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); # endif @@ -821,14 +707,7 @@ namespace ExtendedMaterials else { # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandColor2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[1]); - } - else - { - h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); - } # else h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); # endif @@ -841,14 +720,7 @@ namespace ExtendedMaterials [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandTHDisp2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); - } - else - { - h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); - } # else h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); # endif @@ -856,14 +728,7 @@ namespace ExtendedMaterials else { # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandColor3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[2]); - } - else - { - h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); - } # else h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); # endif @@ -875,14 +740,7 @@ namespace ExtendedMaterials { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); - } - else - { - h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); - } # else h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); # endif @@ -893,14 +751,7 @@ namespace ExtendedMaterials { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); - } - else - { - h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); - } # else h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); # endif @@ -911,14 +762,7 @@ namespace ExtendedMaterials { float h; # if defined(TERRAIN_VARIATION) - [branch] if (USE_TERRAIN_VARIATION) - { h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); - } - else - { - h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); - } # else h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); # endif From 507fc56f6b4a12c34f9393f75328892618a2c629 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Tue, 3 Jun 2025 15:22:19 +1000 Subject: [PATCH 27/53] fix --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index 43a5e29e45..bdeeaf5ff9 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -70,12 +70,8 @@ namespace ExtendedMaterials #if !defined(PARALLAX) && !defined(TRUE_PBR) mipLevel++; #endif - #if defined(TERRAIN_VARIATION) - [branch] if (SharedData::extendedMaterialSettings.EnableTerrainParallax) - { - mipLevel++; - } + mipLevel += 1.5; #endif #if defined(VR) @@ -267,7 +263,7 @@ namespace ExtendedMaterials total += h * weights[2]; weights[2] *= pow(heightBlend, HEIGHT_MULT * h); } - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0 && w1.w > 0.0) { float h; # if defined(TERRAIN_VARIATION) @@ -278,7 +274,7 @@ namespace ExtendedMaterials total += h * weights[3]; weights[3] *= pow(heightBlend, HEIGHT_MULT * h); } - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0 && w2.x > 0.0) { float h; # if defined(TERRAIN_VARIATION) @@ -289,7 +285,7 @@ namespace ExtendedMaterials total += h * weights[4]; weights[4] *= pow(heightBlend, HEIGHT_MULT * h); } - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0 && w2.y > 0.0) { float h; # if defined(TERRAIN_VARIATION) @@ -716,8 +712,7 @@ namespace ExtendedMaterials weights[1] *= pow(heightBlend, HEIGHT_MULT * h); } if (w1.z > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) + float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandTHDisp2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); @@ -736,7 +731,7 @@ namespace ExtendedMaterials total += h * weights[2]; weights[2] *= pow(heightBlend, HEIGHT_MULT * h); } - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0 && w1.w > 0.0) { float h; # if defined(TERRAIN_VARIATION) @@ -747,7 +742,7 @@ namespace ExtendedMaterials total += h * weights[3]; weights[3] *= pow(heightBlend, HEIGHT_MULT * h); } - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0 && w2.x > 0.0) { float h; # if defined(TERRAIN_VARIATION) @@ -758,7 +753,7 @@ namespace ExtendedMaterials total += h * weights[4]; weights[4] *= pow(heightBlend, HEIGHT_MULT * h); } - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0 && w2.y > 0.0) { float h; # if defined(TERRAIN_VARIATION) From 6d8989828e378471dd87c9eaf72a717e385e4728 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Tue, 3 Jun 2025 15:48:45 +1000 Subject: [PATCH 28/53] fix for dumb mistakes. --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 143 ++++++------------ 1 file changed, 50 insertions(+), 93 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index bdeeaf5ff9..c9f743790b 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -267,9 +267,9 @@ namespace ExtendedMaterials { float h; # if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandTHDisp3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); # else - h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); + h = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); # endif total += h * weights[3]; weights[3] *= pow(heightBlend, HEIGHT_MULT * h); @@ -278,9 +278,9 @@ namespace ExtendedMaterials { float h; # if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandTHDisp4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); # else - h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); + h = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); # endif total += h * weights[4]; weights[4] *= pow(heightBlend, HEIGHT_MULT * h); @@ -289,9 +289,9 @@ namespace ExtendedMaterials { float h; # if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandTHDisp5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); # else - h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); + h = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); # endif total += h * weights[5]; weights[5] *= pow(heightBlend, HEIGHT_MULT * h); @@ -677,93 +677,50 @@ namespace ExtendedMaterials float total = 0; float screenNoise = 0; // Default noise value when no stochastic sampling - if (w1.x > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand0HasDisplacement) != 0) - { - h = ScaleDisplacement(TexLandTHDisp0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); - } - else - { - h = ScaleDisplacement(TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, params[0]); - } - total += h * weights[0]; - weights[0] *= pow(heightBlend, HEIGHT_MULT * h); - } - if (w1.y > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) - { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandTHDisp1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); -# else - h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); -# endif - } - else - { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandColor2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[1]); -# else - h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); -# endif - } - total += h * weights[1]; - weights[1] *= pow(heightBlend, HEIGHT_MULT * h); - } - if (w1.z > 0.0) { - float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) - { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandTHDisp2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); -# else - h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); -# endif - } - else - { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandColor3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[2]); -# else - h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); -# endif - } - total += h * weights[2]; - weights[2] *= pow(heightBlend, HEIGHT_MULT * h); - } - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0 && w1.w > 0.0) - { - float h; -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); -# else - h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); -# endif - total += h * weights[3]; - weights[3] *= pow(heightBlend, HEIGHT_MULT * h); - } - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0 && w2.x > 0.0) - { - float h; -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); -# else - h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); -# endif - total += h * weights[4]; - weights[4] *= pow(heightBlend, HEIGHT_MULT * h); - } - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0 && w2.y > 0.0) - { - float h; -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); -# else - h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); -# endif - total += h * weights[5]; - weights[5] *= pow(heightBlend, HEIGHT_MULT * h); - } + if (w1.y > 0.0) { + float h = 0.0; + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) + { + h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); + } + else + { + h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); + } + total += h * weights[1]; + weights[1] *= pow(heightBlend, HEIGHT_MULT * h); + } + if (w1.z > 0.0) { + float h = 0.0; + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) + { + h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); + } + else + { + h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); + } + total += h * weights[2]; + weights[2] *= pow(heightBlend, HEIGHT_MULT * h); + } + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0 && w1.w > 0.0) + { + float h = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); + total += h * weights[3]; + weights[3] *= pow(heightBlend, HEIGHT_MULT * h); + } + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0 && w2.x > 0.0) + { + float h = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); + total += h * weights[4]; + weights[4] *= pow(heightBlend, HEIGHT_MULT * h); + } + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0 && w2.y > 0.0) + { + float h = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); + total += h * weights[5]; + weights[5] *= pow(heightBlend, HEIGHT_MULT * h); + } [unroll] for (int i = 0; i < 6; i++) { weights[i] = min(100, pow(weights[i], heightBlend)); From 50c7b37294f85b33624b7a08bfc9817a54fb1253 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Tue, 3 Jun 2025 19:06:01 +1000 Subject: [PATCH 29/53] accidental push --- src/ShaderCache.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ShaderCache.cpp b/src/ShaderCache.cpp index e910fbcacc..126f17740f 100644 --- a/src/ShaderCache.cpp +++ b/src/ShaderCache.cpp @@ -2467,7 +2467,7 @@ namespace SIE } } - void ShaderCache::ProcessCompilationSet([[maybe_unused]] std::stop_token stoken, SIE::ShaderCompilationTask task) + void ShaderCache::ProcessCompilationSet(std::stop_token stoken, SIE::ShaderCompilationTask task) { SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL); task.Perform(); @@ -2715,4 +2715,4 @@ namespace SIE queue.push_back({ watchid, dir, filename, action, oldFilename }); } } -} \ No newline at end of file +} From 6d4ce2d943a0fe01e593c830513fd906700aa056 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Tue, 3 Jun 2025 19:07:07 +1000 Subject: [PATCH 30/53] Update TerrainVariation.cpp --- src/Features/TerrainVariation.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Features/TerrainVariation.cpp b/src/Features/TerrainVariation.cpp index c943fcf72a..f8849e05f0 100644 --- a/src/Features/TerrainVariation.cpp +++ b/src/Features/TerrainVariation.cpp @@ -96,8 +96,7 @@ void TerrainVariation::DrawUnloadedUI() ImGui::Spacing(); ImGui::TextWrapped( "Terrain Variation reduces the repeating pattern effect on terrain textures.\n" - "This technique creates more natural-looking terrain by adding variation to texture sampling.\n" - "Stochastic texturing is applied only when parallax effects are not active (beyond 2048 units from camera)."); + "This technique creates more natural-looking terrain by adding variation to texture sampling."); ImGui::Spacing(); ImGui::TextWrapped("Key features:"); @@ -105,4 +104,4 @@ void TerrainVariation::DrawUnloadedUI() ImGui::BulletText("Automatically activates when parallax effects end"); ImGui::BulletText("Can be applied to LOD terrain for more consistent appearance"); ImGui::Spacing(); -} \ No newline at end of file +} From e46c99ac2cb095b55da5c6072bde156d6693c982 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Wed, 4 Jun 2025 19:03:45 +1000 Subject: [PATCH 31/53] fixes --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 2 +- package/Shaders/Lighting.hlsl | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index c9f743790b..2ba9821848 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -71,7 +71,7 @@ namespace ExtendedMaterials mipLevel++; #endif #if defined(TERRAIN_VARIATION) - mipLevel += 1.5; + mipLevel++; #endif #if defined(VR) diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 8fca0401b9..9aaa54217e 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1382,7 +1382,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(LANDSCAPE) // Layer 1 (LandBlendWeights1.x) - if (input.LandBlendWeights1.x > 0.01) { + if (input.LandBlendWeights1.x > 0.0) { float weight = input.LandBlendWeights1.x; // Sample diffuse texture for layer 1 @@ -1463,7 +1463,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) } // Layer 2 (LandBlendWeights1.y) - if (input.LandBlendWeights1.y > 0.01) { + if (input.LandBlendWeights1.y > 0.0) { float weight = input.LandBlendWeights1.y; // Sample diffuse texture for layer 2 @@ -1544,7 +1544,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) } // Layer 3 (LandBlendWeights1.z) - if (input.LandBlendWeights1.z > 0.01) { + if (input.LandBlendWeights1.z > 0.0) { float weight = input.LandBlendWeights1.z; // Sample diffuse texture for layer 3 # if defined(TERRAIN_VARIATION) @@ -1623,7 +1623,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) blendedNormalAlpha += landNormalAlpha3 * weight; } // Layer 4 (LandBlendWeights1.w) - if (input.LandBlendWeights1.w > 0.01) { + if (input.LandBlendWeights1.w > 0.0) { float weight = input.LandBlendWeights1.w; // Sample diffuse texture for layer 4 @@ -1704,7 +1704,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) } // Layer 5 (LandBlendWeights2.x) - if (input.LandBlendWeights2.x > 0.01) { + if (input.LandBlendWeights2.x > 0.0) { float weight = input.LandBlendWeights2.x; // Sample diffuse texture for layer 5 # if defined(TERRAIN_VARIATION) @@ -1784,7 +1784,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) blendedNormalAlpha += landNormalAlpha5 * weight; } // Layer 6 (LandBlendWeights2.y) - if (input.LandBlendWeights2.y > 0.01) { + if (input.LandBlendWeights2.y > 0.0) { float weight = input.LandBlendWeights2.y; // Sample layer 6 textures From 820783beb77623d3a9f01203e7003e342f99a404 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 4 Jun 2025 09:07:36 +0000 Subject: [PATCH 32/53] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20pre-commi?= =?UTF-8?q?t.ci=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated formatting by clang-format, prettier, and other hooks. See https://pre-commit.ci for details. --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 4 ++-- .../TerrainVariation/TerrainVariation.hlsli | 20 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index 2ba9821848..7057ca1d8a 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -60,13 +60,13 @@ namespace ExtendedMaterials // Find min of change in u and v across quad: compute du and dv magnitude across quad //float2 dTexCoords = dxSize * dxSize + dySize * dySize; - + // Standard mipmapping uses max here float minTexCoordDelta = min(dot(dxSize, dxSize), dot(dySize, dySize)); // Compute the current mip level (* 0.5 is effectively computing a square root before ) float mipLevel = max(0.5 * log2(minTexCoordDelta), 0); - + #if !defined(PARALLAX) && !defined(TRUE_PBR) mipLevel++; #endif diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index 8ca34b749e..e6b3c46de9 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -47,7 +47,7 @@ inline float4x3 ComputeBarycentricVerts(float2 landscapeUV) float2 frac_uv = frac(skewUV); float barry_z = 1.0 - frac_uv.x - frac_uv.y; float3 barry = float3(frac_uv, barry_z); - + return (barry.z > 0) ? float4x3(float3(vxID, 0), float3(vxID + float2(0, 1), 0), float3(vxID + float2(1, 0), 0), barry.zyx) : float4x3(float3(vxID + float2(1, 1), 0), float3(vxID + float2(1, 0), 0), float3(vxID + float2(0, 1), 0), float3(-barry.z, 1.0 - barry.y, 1.0 - barry.x)); @@ -68,7 +68,7 @@ inline StochasticOffsets ComputeStochasticOffsets(float2 landscapeUV) // Main stochastic sampling function inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for normal/diffuse text. Luminence-based blending helps preserve details close to camera. -{ +{ // Apply contrast to the initial blend weights (without height influence) float3 blendWeights = pow(saturate(offsets.weights), HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE)); @@ -101,7 +101,7 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler // Same as StochasticEffect but no height/luminescence influence, so much cheaper but worse quality, doesn't matter for the use case. inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) -{ +{ // Sample the three texture offsets float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); @@ -125,7 +125,7 @@ inline StochasticOffsets ComputeStochasticOffsets2(float2 landscapeUV) offsets2.offset2 = hash2D2D(BW_vx[1].xy); offsets2.offset3 = float2(0, 0); offsets2.weights = float3(BW_vx[3].x, BW_vx[3].y, 0.0); - + return offsets2; } @@ -135,7 +135,7 @@ inline float4 StochasticSample2(float rnd, float mipLevel, Texture2D tex, Sample // Sample only two texture offsets using the provided mip level float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); - + // Use proper weight normalization to avoid artifacts float2 weights2D = offsets.weights.xy; float totalWeight = weights2D.x + weights2D.y; @@ -144,7 +144,7 @@ inline float4 StochasticSample2(float rnd, float mipLevel, Texture2D tex, Sample } else { weights2D = float2(0.5, 0.5); } - + // Direct blend without third interpolated sample float4 result = sample1 * weights2D.x + sample2 * weights2D.y; @@ -163,7 +163,7 @@ inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 landscapeUV) { // Precomputed scaling: (WORLD_SCALE / 0.010416667) * 8.0 = ~255437 static const float LOD_SCALE = 255437.0; - + float2 scaledUV = landscapeUV * LOD_SCALE; float2 cellID = floor(scaledUV); @@ -171,10 +171,10 @@ inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 landscapeUV) // Generate both offsets from single hash to reduce calls float2 hash1 = hashLOD(cellID); float2 hash2 = hashLOD(cellID + 127.0); - + offsetsLOD.offset1 = hash1 * 0.08; offsetsLOD.offset2 = hash2 * 0.08; - + // Simplified weights since we only use 2 samples now offsetsLOD.weights = float3(0.65, 0.35, 0.0); @@ -189,7 +189,7 @@ inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, Samp // Cheap pseudo-rotation using simple transforms float2 dir1 = float2(rnd - 0.5, frac(rnd * 1.618) - 0.5); float2 dir2 = float2(dir1.y, -dir1.x); - + // Apply simple scaled offsets float2 microOffset1 = (offsets.offset1 + dir1) * offsetScale; float2 microOffset2 = (offsets.offset2 + dir2) * offsetScale; From 606e556168e9a6457ccf1390f467ff9f9c155d38 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Thu, 5 Jun 2025 20:57:12 +1000 Subject: [PATCH 33/53] Minor height changes, +.5ms. --- .../TerrainVariation/TerrainVariation.hlsli | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index e6b3c46de9..59773f6d96 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -68,24 +68,24 @@ inline StochasticOffsets ComputeStochasticOffsets(float2 landscapeUV) // Main stochastic sampling function inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for normal/diffuse text. Luminence-based blending helps preserve details close to camera. -{ - // Apply contrast to the initial blend weights (without height influence) +{ // Apply contrast to the initial blend weights (without height influence) float3 blendWeights = pow(saturate(offsets.weights), HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE)); // Renormalize the weights float totalWeight = blendWeights.x + blendWeights.y + blendWeights.z; - blendWeights = (totalWeight > 0.0) ? blendWeights / totalWeight : DEFAULT_WEIGHTS; - + blendWeights /= totalWeight; float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); // Apply height-based weight adjustments - float height1 = sample1.a > 0 ? sample1.a : dot(sample1.rgb, LUMINANCE_WEIGHTS); - float height2 = sample2.a > 0 ? sample2.a : dot(sample2.rgb, LUMINANCE_WEIGHTS); - float height3 = sample3.a > 0 ? sample3.a : dot(sample3.rgb, LUMINANCE_WEIGHTS); - - float3 heights = float3(height1, height2, height3); + float3x3 rgbMatrix = float3x3(sample1.rgb, sample2.rgb, sample3.rgb); + float3 luminanceHeights = mul(rgbMatrix, LUMINANCE_WEIGHTS); + float3 heights = float3( + sample1.a > 0 ? sample1.a : luminanceHeights.x, + sample2.a > 0 ? sample2.a : luminanceHeights.y, + sample3.a > 0 ? sample3.a : luminanceHeights.z + ); float3 weights = blendWeights * (1.0 + HEIGHT_INFLUENCE * (heights - 1.0)); // Blend samples with height-adjusted weights From 9fd37715e5be950f21bae46a9f5cedce37b493bf Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Fri, 6 Jun 2025 16:02:35 +1000 Subject: [PATCH 34/53] Distance blend, much better perf. --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 4 - .../TerrainVariation/TerrainVariation.hlsli | 187 ++++++++++-------- package/Shaders/Lighting.hlsl | 33 ++-- 3 files changed, 129 insertions(+), 95 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index 7057ca1d8a..42994fe79d 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -66,13 +66,9 @@ namespace ExtendedMaterials // Compute the current mip level (* 0.5 is effectively computing a square root before ) float mipLevel = max(0.5 * log2(minTexCoordDelta), 0); - #if !defined(PARALLAX) && !defined(TRUE_PBR) mipLevel++; #endif - #if defined(TERRAIN_VARIATION) - mipLevel++; - #endif #if defined(VR) mipLevel++; diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index 59773f6d96..84c0616041 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -10,7 +10,7 @@ // --------------------- CONSTANTS AND STRUCTURES --------------------- // // Height blend operator settings - DO NOT CHANGE THESE VALUES. -static const float HEIGHT_BLEND_CONTRAST = 16.0; // Controls sharpness of height-based transitions +static const float HEIGHT_BLEND_CONTRAST = 12.0; // Controls sharpness of height-based transitions (reduced from 16.0 for performance) static const float HEIGHT_INFLUENCE = 0.3; // How much height affects blending (0=pure stochastic, 1=pure height) // Pre-computed constants to avoid runtime calculations static const float2x2 SKEW_MATRIX = float2x2(1.0, 0.0, -0.57735027, 1.15470054); @@ -18,6 +18,9 @@ static const float WORLD_SCALE = 332.54; // Blending constants static const float3 DEFAULT_WEIGHTS = float3(0.33, 0.33, 0.34); static const float3 LUMINANCE_WEIGHTS = float3(0.2126, 0.7152, 0.0722); +// Distance-based LOD optimization constants +static const float DISTANCE_LOD_THRESHOLD = 4096.0; // Distance threshold for fast path optimization +static const float DISTANCE_LOD_TRANSITION = 200.0; // Transition zone width (units) // Hash constants static const float2 HASH_MULTIPLIER = float2(1271.5151, 3337.8237); static const float2 HASH_SINE_MULTIPLIER = float2(43758.5453, 28637.1369); @@ -31,6 +34,8 @@ struct StochasticOffsets float3 weights; }; +// --------------------- COMPUTE FUNCTIONS --------------------- // + // Hash function for stochastic sampling inline float2 hash2D2D(float2 s) { @@ -38,6 +43,12 @@ inline float2 hash2D2D(float2 s) return frac(sin(s.x + s.y) * HASH_SINE_MULTIPLIER); } +inline float2 hashLOD(float2 p) +{ + p = frac(p * 0.318); + return frac(p.x + p.y * 17.0); +} + // Common barycentric coordinate calculation for stochastic sampling inline float4x3 ComputeBarycentricVerts(float2 landscapeUV) { @@ -66,67 +77,65 @@ inline StochasticOffsets ComputeStochasticOffsets(float2 landscapeUV) return offsets; } -// Main stochastic sampling function -inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) // Used for normal/diffuse text. Luminence-based blending helps preserve details close to camera. -{ // Apply contrast to the initial blend weights (without height influence) - float3 blendWeights = pow(saturate(offsets.weights), HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE)); +// Simplified version for functions that only need 2 offsets +inline StochasticOffsets ComputeStochasticOffsets2(float2 landscapeUV) +{ + float4x3 BW_vx = ComputeBarycentricVerts(landscapeUV); - // Renormalize the weights - float totalWeight = blendWeights.x + blendWeights.y + blendWeights.z; - blendWeights /= totalWeight; - float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); - float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); - float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); + StochasticOffsets offsets2; + offsets2.offset1 = hash2D2D(BW_vx[0].xy); + offsets2.offset2 = hash2D2D(BW_vx[1].xy); + offsets2.offset3 = float2(0, 0); + offsets2.weights = float3(BW_vx[3].x, BW_vx[3].y, 0.0); - // Apply height-based weight adjustments - float3x3 rgbMatrix = float3x3(sample1.rgb, sample2.rgb, sample3.rgb); - float3 luminanceHeights = mul(rgbMatrix, LUMINANCE_WEIGHTS); - float3 heights = float3( - sample1.a > 0 ? sample1.a : luminanceHeights.x, - sample2.a > 0 ? sample2.a : luminanceHeights.y, - sample3.a > 0 ? sample3.a : luminanceHeights.z - ); - float3 weights = blendWeights * (1.0 + HEIGHT_INFLUENCE * (heights - 1.0)); + return offsets2; +} +// Some triangular artifacts, but really not obvious at distance. +inline StochasticOffsets ComputeStochasticOffsetsLow(float2 landscapeUV) +{ + float2 scaledUV = landscapeUV * (WORLD_SCALE); + float2 cellID = floor(scaledUV); - // Blend samples with height-adjusted weights - float4 result = sample1 * weights.x + sample2 * weights.y + sample3 * weights.z; + StochasticOffsets offsetsLow; + // Only need 1 hash since we only take 1 real texture sample + float2 hash1 = hashLOD(cellID); - // Renormalize final result - float finalWeightSum = weights.x + weights.y + weights.z; + offsetsLow.offset1 = hash1 * 0.65; + offsetsLow.offset2 = hash1; // Reuse for synthetic variation + offsetsLow.weights = float3(1.0, 0.0, 0.0); // Only first weight matters - return result; + return offsetsLow; } -// --------------------- SPECIAL USE CASES --------------------- // - -// Same as StochasticEffect but no height/luminescence influence, so much cheaper but worse quality, doesn't matter for the use case. -inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) +inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 landscapeUV) { - // Sample the three texture offsets - float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); - float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); - float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); + // Precomputed scaling: (WORLD_SCALE / 0.010416667) * 8.0 = ~255437 + static const float LOD_SCALE = 255437.0; - // Blend using the barycentric weights - float4 result = sample1 * offsets.weights.x + - sample2 * offsets.weights.y + - sample3 * offsets.weights.z; + float2 scaledUV = landscapeUV * LOD_SCALE; + float2 cellID = floor(scaledUV); - return result; -} + StochasticOffsets offsetsLOD; + // Generate both offsets from single hash to reduce calls + float2 hash1 = hashLOD(cellID); + float2 hash2 = hashLOD(cellID + 127.0); -// Simplified version for functions that only need 2 offsets -inline StochasticOffsets ComputeStochasticOffsets2(float2 landscapeUV) -{ - float4x3 BW_vx = ComputeBarycentricVerts(landscapeUV); + offsetsLOD.offset1 = hash1 * 0.08; + offsetsLOD.offset2 = hash2 * 0.08; - StochasticOffsets offsets2; - offsets2.offset1 = hash2D2D(BW_vx[0].xy); - offsets2.offset2 = hash2D2D(BW_vx[1].xy); - offsets2.offset3 = float2(0, 0); - offsets2.weights = float3(BW_vx[3].x, BW_vx[3].y, 0.0); + // Simplified weights since we only use 2 samples now + offsetsLOD.weights = float3(0.65, 0.35, 0.0); - return offsets2; + return offsetsLOD; +} + +// --------------------- STOCHASTIC SAMPLING FUNCTIONS --------------------- // + +// Ultra-cheap stochastic sampling - 1 texture sample with hash-based offset variation +inline float4 StochasticSampleLow(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsetsLow, float2 dx, float2 dy) +{ + // Single texture sample with stochastic offset - no blending, maximum performance + return tex.SampleLevel(samp, uv + offsetsLow.offset1, mipLevel); } // Cheap 2 sample version. @@ -151,38 +160,24 @@ inline float4 StochasticSample2(float rnd, float mipLevel, Texture2D tex, Sample return result; } -// --------------------- LOD SAMPLING FUNCTIONS --------------------- // - -inline float2 hashLOD(float2 p) -{ - p = frac(p * 0.318); - return frac(p.x + p.y * 17.0); -} - -inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 landscapeUV) +// Same as StochasticEffect but no height/luminescence influence, so much cheaper but worse quality, doesn't matter for the use case. +inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) { - // Precomputed scaling: (WORLD_SCALE / 0.010416667) * 8.0 = ~255437 - static const float LOD_SCALE = 255437.0; - - float2 scaledUV = landscapeUV * LOD_SCALE; - float2 cellID = floor(scaledUV); - - StochasticOffsets offsetsLOD; - // Generate both offsets from single hash to reduce calls - float2 hash1 = hashLOD(cellID); - float2 hash2 = hashLOD(cellID + 127.0); - - offsetsLOD.offset1 = hash1 * 0.08; - offsetsLOD.offset2 = hash2 * 0.08; + // Sample the three texture offsets + float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); + float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); - // Simplified weights since we only use 2 samples now - offsetsLOD.weights = float3(0.65, 0.35, 0.0); + // Blend using the barycentric weights + float4 result = sample1 * offsets.weights.x + + sample2 * offsets.weights.y + + sample3 * offsets.weights.z; - return offsetsLOD; + return result; } // Stochastic sampling function for Terrain LOD & LOD Mask. -inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) +inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsetsLOD, float2 dx, float2 dy) { float offsetScale = 0.01; @@ -191,8 +186,8 @@ inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, Samp float2 dir2 = float2(dir1.y, -dir1.x); // Apply simple scaled offsets - float2 microOffset1 = (offsets.offset1 + dir1) * offsetScale; - float2 microOffset2 = (offsets.offset2 + dir2) * offsetScale; + float2 microOffset1 = (offsetsLOD.offset1 + dir1) * offsetScale; + float2 microOffset2 = (offsetsLOD.offset2 + dir2) * offsetScale; // Sample only two offsets float4 sample1 = tex.SampleLevel(samp, uv + microOffset1, mipLevel); @@ -202,4 +197,42 @@ inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, Samp return lerp(sample2, sample1, 0.65); } +// Main stochastic sampling function +inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy, float distance) +{ + // Distance-based LOD with smooth transition + float distanceFactor = saturate((distance - DISTANCE_LOD_THRESHOLD) / DISTANCE_LOD_TRANSITION); + // Low sample (always computed for transition) + float4 lowSample = StochasticSampleLow(rnd, max(mipLevel - 1.5, 0.0), tex, samp, uv, offsets, dx, dy); + + // Full quality path for near terrain + // Apply contrast to the initial blend weights (without height influence) + float3 blendWeights = pow(saturate(offsets.weights), HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE)); + + // Renormalize the weights + float totalWeight = blendWeights.x + blendWeights.y + blendWeights.z; + blendWeights /= totalWeight; + float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); + float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); + + // Apply height-based weight adjustments + float3x3 rgbMatrix = float3x3(sample1.rgb, sample2.rgb, sample3.rgb); + float3 luminanceHeights = mul(rgbMatrix, LUMINANCE_WEIGHTS); + float3 alphaValues = float3(sample1.a, sample2.a, sample3.a); + float3 alphaMask = step(0.001, alphaValues); + float3 heights = lerp(luminanceHeights, alphaValues, alphaMask); + float3 weights = blendWeights * (1.0 + HEIGHT_INFLUENCE * heights); + // Blend samples with height-adjusted weights + float4 highQualitySample = sample1 * weights.x + sample2 * weights.y + sample3 * weights.z; + + // Renormalize final result + float finalWeightSum = weights.x + weights.y + weights.z; + highQualitySample /= finalWeightSum; + + // Smooth transition between high quality and LOD samples + return lerp(highQualitySample, lowSample, distanceFactor); +} + + #endif // TERRAIN_VARIATION_HLSLI \ No newline at end of file diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 9aaa54217e..68ac1ccb59 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1272,7 +1272,12 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TRUE_PBR) float4 blendedRMAOS = 0; -# endif // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) +# endif + + // Calculate view distance once for terrain optimizations + float distance = length(viewPosition); + + // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) # if defined(TERRAIN_VARIATION) bool useTerrainVariation = SharedData::terrainVariationSettings.enableTilingFix; float2 dx, dy; @@ -1390,7 +1395,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landColor1; [branch] if (useTerrainVariation) { - landColor1 = StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampColorSampler, uv, sharedOffset, dx, dy); + landColor1 = StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampColorSampler, uv, sharedOffset, dx, dy, distance); } else { @@ -1414,7 +1419,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landNormal1; [branch] if (useTerrainVariation) { - landNormal1 = StochasticEffect(screenNoise, mipLevels[0], TexNormalSampler, SampNormalSampler, uv, sharedOffset, dx, dy); + landNormal1 = StochasticEffect(screenNoise, mipLevels[0], TexNormalSampler, SampNormalSampler, uv, sharedOffset, dx, dy, distance); } else { @@ -1471,7 +1476,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landColor2; [branch] if (useTerrainVariation) { - landColor2 = StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampLandColor2Sampler, uv, sharedOffset, dx, dy); + landColor2 = StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampLandColor2Sampler, uv, sharedOffset, dx, dy, distance); } else { @@ -1495,7 +1500,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landNormal2; [branch] if (useTerrainVariation) { - landNormal2 = StochasticEffect(screenNoise, mipLevels[1], TexLandNormal2Sampler, SampLandNormal2Sampler, uv, sharedOffset, dx, dy); + landNormal2 = StochasticEffect(screenNoise, mipLevels[1], TexLandNormal2Sampler, SampLandNormal2Sampler, uv, sharedOffset, dx, dy, distance); } else { @@ -1551,7 +1556,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landColor3; [branch] if (useTerrainVariation) { - landColor3 = StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampLandColor3Sampler, uv, sharedOffset, dx, dy); + landColor3 = StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampLandColor3Sampler, uv, sharedOffset, dx, dy, distance); } else { @@ -1575,7 +1580,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landNormal3; [branch] if (useTerrainVariation) { - landNormal3 = StochasticSample3(screenNoise, mipLevels[2], TexLandNormal3Sampler, SampLandNormal3Sampler, uv, sharedOffset, dx, dy); + landNormal3 = StochasticEffect(screenNoise, mipLevels[2], TexLandNormal3Sampler, SampLandNormal3Sampler, uv, sharedOffset, dx, dy, distance); } else { @@ -1631,7 +1636,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landColor4; [branch] if (useTerrainVariation) { - landColor4 = StochasticEffect(screenNoise, mipLevels[3], TexLandColor4Sampler, SampLandColor4Sampler, uv, sharedOffset, dx, dy); + landColor4 = StochasticEffect(screenNoise, mipLevels[3], TexLandColor4Sampler, SampLandColor4Sampler, uv, sharedOffset, dx, dy, distance); } else { @@ -1655,7 +1660,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landNormal4; [branch] if (useTerrainVariation) { - landNormal4 = StochasticEffect(screenNoise, mipLevels[3], TexLandNormal4Sampler, SampLandNormal4Sampler, uv, sharedOffset, dx, dy); + landNormal4 = StochasticEffect(screenNoise, mipLevels[3], TexLandNormal4Sampler, SampLandNormal4Sampler, uv, sharedOffset, dx, dy, distance); } else { @@ -1711,7 +1716,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landColor5; [branch] if (useTerrainVariation) { - landColor5 = StochasticEffect(screenNoise, mipLevels[4], TexLandColor5Sampler, SampLandColor5Sampler, uv, sharedOffset, dx, dy); + landColor5 = StochasticEffect(screenNoise, mipLevels[4], TexLandColor5Sampler, SampLandColor5Sampler, uv, sharedOffset, dx, dy, distance); } else { @@ -1735,7 +1740,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landNormal5; [branch] if (useTerrainVariation) { - landNormal5 = StochasticEffect(screenNoise, mipLevels[4], TexLandNormal5Sampler, SampLandNormal5Sampler, uv, sharedOffset, dx, dy); + landNormal5 = StochasticEffect(screenNoise, mipLevels[4], TexLandNormal5Sampler, SampLandNormal5Sampler, uv, sharedOffset, dx, dy, distance); } else { @@ -1792,7 +1797,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landColor6; [branch] if (useTerrainVariation) { - landColor6 = StochasticEffect(screenNoise, mipLevels[5], TexLandColor6Sampler, SampLandColor6Sampler, uv, sharedOffset, dx, dy); + landColor6 = StochasticEffect(screenNoise, mipLevels[5], TexLandColor6Sampler, SampLandColor6Sampler, uv, sharedOffset, dx, dy, distance); } else { @@ -1816,7 +1821,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landNormal6; [branch] if (useTerrainVariation) { - landNormal6 = StochasticEffect(screenNoise, mipLevels[5], TexLandNormal6Sampler, SampLandNormal6Sampler, uv, sharedOffset, dx, dy); + landNormal6 = StochasticEffect(screenNoise, mipLevels[5], TexLandNormal6Sampler, SampLandNormal6Sampler, uv, sharedOffset, dx, dy, distance); } else { @@ -1839,7 +1844,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS6 = StochasticEffect(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampLandRMAOS6Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); + landRMAOS6 = StochasticSample3(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampLandRMAOS6Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); } else { From 1bf1a5b20a27dad9c17a2cca0d02b690ac503796 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Fri, 6 Jun 2025 17:41:57 +1000 Subject: [PATCH 35/53] Update TerrainVariation.hlsli --- .../Shaders/TerrainVariation/TerrainVariation.hlsli | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index 84c0616041..fcb2dc1861 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -19,7 +19,7 @@ static const float WORLD_SCALE = 332.54; static const float3 DEFAULT_WEIGHTS = float3(0.33, 0.33, 0.34); static const float3 LUMINANCE_WEIGHTS = float3(0.2126, 0.7152, 0.0722); // Distance-based LOD optimization constants -static const float DISTANCE_LOD_THRESHOLD = 4096.0; // Distance threshold for fast path optimization +static const float DISTANCE_LOD_THRESHOLD = 1024.0; // Distance threshold for fast path optimization static const float DISTANCE_LOD_TRANSITION = 200.0; // Transition zone width (units) // Hash constants static const float2 HASH_MULTIPLIER = float2(1271.5151, 3337.8237); @@ -203,7 +203,7 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler // Distance-based LOD with smooth transition float distanceFactor = saturate((distance - DISTANCE_LOD_THRESHOLD) / DISTANCE_LOD_TRANSITION); // Low sample (always computed for transition) - float4 lowSample = StochasticSampleLow(rnd, max(mipLevel - 1.5, 0.0), tex, samp, uv, offsets, dx, dy); + float4 lowSample = StochasticSampleLow(rnd, mipLevel, tex, samp, uv, offsets, dx, dy); // Full quality path for near terrain // Apply contrast to the initial blend weights (without height influence) From 94dfe1a60ee280568c4737d5365965f946355ec2 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Fri, 6 Jun 2025 18:19:03 +1000 Subject: [PATCH 36/53] Emat separated --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 515 +++++++++--------- package/Shaders/Lighting.hlsl | 52 +- 2 files changed, 281 insertions(+), 286 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index 42994fe79d..4d6f597a6b 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -5,10 +5,6 @@ // http://www.diva-portal.org/smash/get/diva2:831762/FULLTEXT01.pdf // https://bartwronski.files.wordpress.com/2014/03/ac4_gdc.pdf -#if defined(TERRAIN_VARIATION) -# include "TerrainVariation/TerrainVariation.hlsli" -#endif - struct DisplacementParams { float DisplacementScale; @@ -17,6 +13,10 @@ struct DisplacementParams float FlattenAmount; }; +#if defined(TERRAIN_VARIATION) +# include "TerrainVariation/TerrainVariation.hlsli" +#endif + namespace ExtendedMaterials { @@ -41,38 +41,35 @@ namespace ExtendedMaterials float2 textureDims; tex.GetDimensions(textureDims.x, textureDims.y); - #if !defined(TERRAIN_VARIATION) - textureDims /= 2.0; - #endif +#if !defined(PARALLAX) && !defined(TRUE_PBR) + textureDims /= 2.0; +#endif - #if !defined(PARALLAX) && !defined(TRUE_PBR) - textureDims /= 2.0; - #endif +#if defined(VR) + textureDims /= 2.0; +#endif - #if defined(VR) - textureDims /= 2.0; - #endif + float2 texCoordsPerSize = coords * textureDims; - float2 texCoordsPerSize = coords * textureDims; + float2 dxSize = ddx(texCoordsPerSize); + float2 dySize = ddy(texCoordsPerSize); - float2 dxSize = ddx(texCoordsPerSize); - float2 dySize = ddy(texCoordsPerSize); + // Find min of change in u and v across quad: compute du and dv magnitude across quad + //float2 dTexCoords = dxSize * dxSize + dySize * dySize; - // Find min of change in u and v across quad: compute du and dv magnitude across quad - //float2 dTexCoords = dxSize * dxSize + dySize * dySize; + // Standard mipmapping uses max here + float minTexCoordDelta = min(dot(dxSize, dxSize), dot(dySize, dySize)); - // Standard mipmapping uses max here - float minTexCoordDelta = min(dot(dxSize, dxSize), dot(dySize, dySize)); + // Compute the current mip level (* 0.5 is effectively computing a square root before ) + float mipLevel = max(0.5 * log2(minTexCoordDelta), 0); - // Compute the current mip level (* 0.5 is effectively computing a square root before ) - float mipLevel = max(0.5 * log2(minTexCoordDelta), 0); - #if !defined(PARALLAX) && !defined(TRUE_PBR) - mipLevel++; - #endif +#if !defined(PARALLAX) && !defined(TRUE_PBR) + mipLevel++; +#endif - #if defined(VR) - mipLevel++; - #endif +#if defined(VR) + mipLevel++; +#endif return mipLevel; } @@ -81,11 +78,7 @@ namespace ExtendedMaterials # if defined(TRUE_PBR) # define HEIGHT_POWER 2 # define HEIGHT_MULT 8 - float GetTerrainHeight(float screenNoise, PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, -# if defined(TERRAIN_VARIATION) - StochasticOffsets sharedOffset, float2 dx, float2 dy, -# endif - out float weights[6]) + float GetTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, out float weights[6]) { float heightBlend = 1 + blendFactor * HEIGHT_POWER; weights[0] = w1.x; @@ -97,68 +90,37 @@ namespace ExtendedMaterials float total = 0; [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.0) { - float h; -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexLandDisplacement0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); - -# else - h = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); -# endif + float h = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); total += h * weights[0]; weights[0] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1HasDisplacement) != 0 && w1.y > 0.0) { - float h; -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandDisplacement1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); -# else - h = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); -# endif + float h = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); total += h * weights[1]; weights[1] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2HasDisplacement) != 0 && w1.z > 0.0) { - float h; -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandDisplacement2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); -# else - h = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); -# endif + float h = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); total += h * weights[2]; weights[2] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) { - float h; -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); -# else - h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); -# endif + float h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); total += h * weights[3]; weights[3] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) { - float h; -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); -# else - h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); -# endif + float h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); total += h * weights[4]; weights[4] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) { - float h; -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); -# else - h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); -# endif + float h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); total += h * weights[5]; weights[5] *= pow(heightBlend, HEIGHT_MULT * h); } @@ -181,11 +143,7 @@ namespace ExtendedMaterials # else # define HEIGHT_POWER 2 # define HEIGHT_MULT 8 - float GetTerrainHeight(float screenNoise, PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, -# if defined(TERRAIN_VARIATION) - StochasticOffsets sharedOffset, float2 dx, float2 dy, -# endif - out float weights[6]) + float GetTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, out float weights[6]) { float heightBlend = 1 + blendFactor * HEIGHT_POWER; weights[0] = w1.x; @@ -195,24 +153,15 @@ namespace ExtendedMaterials weights[4] = w2.x; weights[5] = w2.y; float total = 0; - if (w1.x > 0.0) { float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand0HasDisplacement) != 0) { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexLandTHDisp0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); -# else h = ScaleDisplacement(TexLandTHDisp0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); -# endif } else { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexColorSampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[0]); -# else h = ScaleDisplacement(TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, params[0]); -# endif } total += h * weights[0]; weights[0] *= pow(heightBlend, HEIGHT_MULT * h); @@ -221,19 +170,11 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandTHDisp1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); -# else h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); -# endif } else { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandColor2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[1]); -# else h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); -# endif } total += h * weights[1]; weights[1] *= pow(heightBlend, HEIGHT_MULT * h); @@ -242,53 +183,51 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandTHDisp2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); -# else h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); -# endif } else { -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandColor3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[2]); -# else h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); -# endif } total += h * weights[2]; weights[2] *= pow(heightBlend, HEIGHT_MULT * h); } - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0 && w1.w > 0.0) - { - float h; -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandTHDisp3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); -# else - h = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); -# endif + if (w1.w > 0.0) { + float h = 0.0; + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0) + { + h = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); + } + else + { + h = ScaleDisplacement(TexLandColor4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).w, params[3]); + } total += h * weights[3]; weights[3] *= pow(heightBlend, HEIGHT_MULT * h); } - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0 && w2.x > 0.0) - { - float h; -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandTHDisp4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); -# else - h = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); -# endif + if (w2.x > 0.0) { + float h = 0.0; + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0) + { + h = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); + } + else + { + h = ScaleDisplacement(TexLandColor5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).w, params[4]); + } total += h * weights[4]; weights[4] *= pow(heightBlend, HEIGHT_MULT * h); } - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0 && w2.y > 0.0) - { - float h; -# if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandTHDisp5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); -# else - h = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); -# endif + if (w2.y > 0.0) { + float h = 0.0; + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0) + { + h = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); + } + else + { + h = ScaleDisplacement(TexLandColor6Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).w, params[5]); + } total += h * weights[5]; weights[5] *= pow(heightBlend, HEIGHT_MULT * h); } @@ -313,11 +252,7 @@ namespace ExtendedMaterials #endif #if defined(LANDSCAPE) - float2 GetParallaxCoords(PS_INPUT input, float distance, float2 coords, float mipLevels[6], float3 viewDir, float3x3 tbn, float noise, DisplacementParams params[6], -# if defined(TERRAIN_VARIATION) - StochasticOffsets sharedOffset, float2 dx, float2 dy, -# endif - out float pixelOffset, out float weights[6]) + float2 GetParallaxCoords(PS_INPUT input, float distance, float2 coords, float mipLevels[6], float3 viewDir, float3x3 tbn, float noise, DisplacementParams params[6], out float pixelOffset, out float weights[6]) #else float2 GetParallaxCoords(float distance, float2 coords, float mipLevel, float3 viewDir, float3x3 tbn, float noise, Texture2D tex, SamplerState texSampler, uint channel, DisplacementParams params, out float pixelOffset) #endif @@ -391,29 +326,15 @@ namespace ExtendedMaterials float4 currHeight; #if defined(LANDSCAPE) # if defined(TRUE_PBR) -# if defined(TERRAIN_VARIATION) - currHeight.x = GetTerrainHeight(noise, input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) * scalercp + 0.5; - currHeight.y = GetTerrainHeight(noise, input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) * scalercp + 0.5; - currHeight.z = GetTerrainHeight(noise, input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) * scalercp + 0.5; - currHeight.w = GetTerrainHeight(noise, input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) * scalercp + 0.5; -# else - currHeight.x = GetTerrainHeight(noise, input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; - currHeight.y = GetTerrainHeight(noise, input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; - currHeight.z = GetTerrainHeight(noise, input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; - currHeight.w = GetTerrainHeight(noise, input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; -# endif + currHeight.x = GetTerrainHeight(input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; + currHeight.y = GetTerrainHeight(input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; + currHeight.z = GetTerrainHeight(input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; + currHeight.w = GetTerrainHeight(input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; # else -# if defined(TERRAIN_VARIATION) - currHeight.x = GetTerrainHeight(noise, input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) + 0.5; - currHeight.y = GetTerrainHeight(noise, input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) + 0.5; - currHeight.z = GetTerrainHeight(noise, input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) + 0.5; - currHeight.w = GetTerrainHeight(noise, input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) + 0.5; -# else - currHeight.x = GetTerrainHeight(noise, input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; - currHeight.y = GetTerrainHeight(noise, input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; - currHeight.z = GetTerrainHeight(noise, input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; - currHeight.w = GetTerrainHeight(noise, input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; -# endif + currHeight.x = GetTerrainHeight(input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; + currHeight.y = GetTerrainHeight(input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; + currHeight.z = GetTerrainHeight(input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; + currHeight.w = GetTerrainHeight(input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; # endif #else currHeight.x = tex.SampleLevel(texSampler, currentOffset[0].xy, mipLevel)[channel]; @@ -531,72 +452,52 @@ namespace ExtendedMaterials } #if defined(LANDSCAPE) -# if defined(TERRAIN_VARIATION) - float GetParallaxSoftShadowMultiplierTerrain(PS_INPUT input, float2 coords, float mipLevel[6], float3 L, float sh0, float quality, float noise, DisplacementParams params[6], StochasticOffsets sharedOffset, float2 dx, float2 dy) -# else float GetParallaxSoftShadowMultiplierTerrain(PS_INPUT input, float2 coords, float mipLevel[6], float3 L, float sh0, float quality, float noise, DisplacementParams params[6]) -# endif { if (quality > 0.0) { float4 multipliers = rcp((float4(1, 2, 3, 4) + noise)); float4 sh; float heights[6] = { 0, 0, 0, 0, 0, 0 }; float2 rayDir = L.xy * 0.1; - # if defined(TRUE_PBR) float scale = max(params[0].HeightScale * input.LandBlendWeights1.x, max(params[1].HeightScale * input.LandBlendWeights1.y, max(params[2].HeightScale * input.LandBlendWeights1.z, max(params[3].HeightScale * input.LandBlendWeights1.w, max(params[4].HeightScale * input.LandBlendWeights2.x, params[5].HeightScale * input.LandBlendWeights2.y))))); if (scale < 0.01) return 1.0; rayDir *= scale; - -# if defined(TERRAIN_VARIATION) - sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); - if (quality > 0.25) - sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); - if (quality > 0.5) - sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); - if (quality > 0.75) - sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); -# else - sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh = GetTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.25) - sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.y = GetTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.5) - sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.z = GetTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.75) - sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); -# endif + sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); return pow(1.0 - saturate(dot(max(0, sh - sh0) / scale, 1.0)) * quality, 2.0); # else -# if defined(TERRAIN_VARIATION) - sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); - if (quality > 0.25) - sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); - if (quality > 0.5) - sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); - if (quality > 0.75) - sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); -# else - sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh = GetTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.25) - sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.y = GetTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.5) - sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.z = GetTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.75) - sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); -# endif + sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); return pow(1.0 - saturate(dot(max(0, sh - sh0), 1.0)) * quality, 2.0); # endif } return 1.0; } #endif + + #if defined(LANDSCAPE) && defined(TERRAIN_VARIATION) + // ============================================ + // STOCHASTIC PARALLAX SYSTEM + // ============================================ + // Complete parallax system for terrain variation with stochastic sampling + // Separate implementation to avoid per-line integration performance overhead - // Overload for GetTerrainHeight WITHOUT StochasticOffsets (when enableTilingFix is false) # if defined(TRUE_PBR) - float GetTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, out float weights[6]) + float GetStochasticTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, StochasticOffsets sharedOffset, float2 dx, float2 dy, out float weights[6]) { float heightBlend = 1 + blendFactor * HEIGHT_POWER; weights[0] = w1.x; @@ -606,41 +507,57 @@ namespace ExtendedMaterials weights[4] = w2.x; weights[5] = w2.y; float total = 0; - float screenNoise = 0; // Default noise value when no stochastic sampling - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.0) { - float h = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); + float h1 = ScaleDisplacement(TexLandDisplacement0Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[0]); + float h2 = ScaleDisplacement(TexLandDisplacement0Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[0]); + float h3 = ScaleDisplacement(TexLandDisplacement0Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[0]); + float h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; total += h * weights[0]; weights[0] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1HasDisplacement) != 0 && w1.y > 0.0) { - float h = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); + float h1 = ScaleDisplacement(TexLandDisplacement1Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[1]); + float h2 = ScaleDisplacement(TexLandDisplacement1Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[1]); + float h3 = ScaleDisplacement(TexLandDisplacement1Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[1]); + float h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; total += h * weights[1]; weights[1] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2HasDisplacement) != 0 && w1.z > 0.0) { - float h = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); + float h1 = ScaleDisplacement(TexLandDisplacement2Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[2]); + float h2 = ScaleDisplacement(TexLandDisplacement2Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[2]); + float h3 = ScaleDisplacement(TexLandDisplacement2Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[2]); + float h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; total += h * weights[2]; weights[2] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) { - float h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); + float h1 = ScaleDisplacement(TexLandDisplacement3Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[3]); + float h2 = ScaleDisplacement(TexLandDisplacement3Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[3]); + float h3 = ScaleDisplacement(TexLandDisplacement3Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[3]); + float h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; total += h * weights[3]; weights[3] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) { - float h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); + float h1 = ScaleDisplacement(TexLandDisplacement4Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[4]); + float h2 = ScaleDisplacement(TexLandDisplacement4Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[4]); + float h3 = ScaleDisplacement(TexLandDisplacement4Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[4]); + float h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; total += h * weights[4]; weights[4] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) { - float h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); + float h1 = ScaleDisplacement(TexLandDisplacement5Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[5]); + float h2 = ScaleDisplacement(TexLandDisplacement5Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[5]); + float h3 = ScaleDisplacement(TexLandDisplacement5Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[5]); + float h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; total += h * weights[5]; weights[5] *= pow(heightBlend, HEIGHT_MULT * h); } @@ -661,7 +578,7 @@ namespace ExtendedMaterials return total; } # else - float GetTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, out float weights[6]) + float GetStochasticTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, StochasticOffsets sharedOffset, float2 dx, float2 dy, out float weights[6]) { float heightBlend = 1 + blendFactor * HEIGHT_POWER; weights[0] = w1.x; @@ -671,52 +588,120 @@ namespace ExtendedMaterials weights[4] = w2.x; weights[5] = w2.y; float total = 0; - float screenNoise = 0; // Default noise value when no stochastic sampling - - if (w1.y > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) - { - h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); - } - else - { - h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); - } - total += h * weights[1]; - weights[1] *= pow(heightBlend, HEIGHT_MULT * h); - } - if (w1.z > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) - { - h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); - } - else - { - h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); - } - total += h * weights[2]; - weights[2] *= pow(heightBlend, HEIGHT_MULT * h); - } - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0 && w1.w > 0.0) - { - float h = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); - total += h * weights[3]; - weights[3] *= pow(heightBlend, HEIGHT_MULT * h); - } - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0 && w2.x > 0.0) - { - float h = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); - total += h * weights[4]; - weights[4] *= pow(heightBlend, HEIGHT_MULT * h); - } - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0 && w2.y > 0.0) - { - float h = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); - total += h * weights[5]; - weights[5] *= pow(heightBlend, HEIGHT_MULT * h); - } + if (w1.x > 0.0) { + float h = 0.0; + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand0HasDisplacement) != 0) + { + float h1 = ScaleDisplacement(TexLandTHDisp0Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[0]); + float h2 = ScaleDisplacement(TexLandTHDisp0Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[0]); + float h3 = ScaleDisplacement(TexLandTHDisp0Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[0]); + h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; + } + else + { + float h1 = ScaleDisplacement(TexColorSampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).w, params[0]); + float h2 = ScaleDisplacement(TexColorSampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).w, params[0]); + float h3 = ScaleDisplacement(TexColorSampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).w, params[0]); + h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; + } + total += h * weights[0]; + weights[0] *= pow(heightBlend, HEIGHT_MULT * h); + } + if (w1.y > 0.0) { + float h = 0.0; + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) + { + float h1 = ScaleDisplacement(TexLandTHDisp1Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[1]); + float h2 = ScaleDisplacement(TexLandTHDisp1Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[1]); + float h3 = ScaleDisplacement(TexLandTHDisp1Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[1]); + h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; + } + else + { + float h1 = ScaleDisplacement(TexLandColor2Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).w, params[1]); + float h2 = ScaleDisplacement(TexLandColor2Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).w, params[1]); + float h3 = ScaleDisplacement(TexLandColor2Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).w, params[1]); + h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; + } + total += h * weights[1]; + weights[1] *= pow(heightBlend, HEIGHT_MULT * h); + } + if (w1.z > 0.0) { + float h = 0.0; + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) + { + float h1 = ScaleDisplacement(TexLandTHDisp2Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[2]); + float h2 = ScaleDisplacement(TexLandTHDisp2Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[2]); + float h3 = ScaleDisplacement(TexLandTHDisp2Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[2]); + h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; + } + else + { + float h1 = ScaleDisplacement(TexLandColor3Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).w, params[2]); + float h2 = ScaleDisplacement(TexLandColor3Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).w, params[2]); + float h3 = ScaleDisplacement(TexLandColor3Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).w, params[2]); + h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; + } + total += h * weights[2]; + weights[2] *= pow(heightBlend, HEIGHT_MULT * h); + } + if (w1.w > 0.0) { + float h = 0.0; + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0) + { + float h1 = ScaleDisplacement(TexLandTHDisp3Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[3]); + float h2 = ScaleDisplacement(TexLandTHDisp3Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[3]); + float h3 = ScaleDisplacement(TexLandTHDisp3Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[3]); + h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; + } + else + { + float h1 = ScaleDisplacement(TexLandColor4Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).w, params[3]); + float h2 = ScaleDisplacement(TexLandColor4Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).w, params[3]); + float h3 = ScaleDisplacement(TexLandColor4Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).w, params[3]); + h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; + } + total += h * weights[3]; + weights[3] *= pow(heightBlend, HEIGHT_MULT * h); + } + if (w2.x > 0.0) { + float h = 0.0; + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0) + { + float h1 = ScaleDisplacement(TexLandTHDisp4Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[4]); + float h2 = ScaleDisplacement(TexLandTHDisp4Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[4]); + float h3 = ScaleDisplacement(TexLandTHDisp4Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[4]); + h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; + } + else + { + float h1 = ScaleDisplacement(TexLandColor5Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).w, params[4]); + float h2 = ScaleDisplacement(TexLandColor5Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).w, params[4]); + float h3 = ScaleDisplacement(TexLandColor5Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).w, params[4]); + h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; + } + total += h * weights[4]; + weights[4] *= pow(heightBlend, HEIGHT_MULT * h); + } + if (w2.y > 0.0) { + float h = 0.0; + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0) + { + float h1 = ScaleDisplacement(TexLandTHDisp5Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[5]); + float h2 = ScaleDisplacement(TexLandTHDisp5Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[5]); + float h3 = ScaleDisplacement(TexLandTHDisp5Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[5]); + h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; + } + else + { + float h1 = ScaleDisplacement(TexLandColor6Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).w, params[5]); + float h2 = ScaleDisplacement(TexLandColor6Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).w, params[5]); + float h3 = ScaleDisplacement(TexLandColor6Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).w, params[5]); + h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; + } + total += h * weights[5]; + weights[5] *= pow(heightBlend, HEIGHT_MULT * h); + } [unroll] for (int i = 0; i < 6; i++) { weights[i] = min(100, pow(weights[i], heightBlend)); @@ -735,11 +720,10 @@ namespace ExtendedMaterials } # endif - // Overload for GetParallaxCoords WITHOUT StochasticOffsets (when enableTilingFix is false) - float2 GetParallaxCoords(PS_INPUT input, float distance, float2 coords, float mipLevels[6], float3 viewDir, float3x3 tbn, float noise, DisplacementParams params[6], out float pixelOffset, out float weights[6]) + float2 GetStochasticParallaxCoords(PS_INPUT input, float distance, float2 coords, float mipLevels[6], float3 viewDir, float3x3 tbn, float noise, DisplacementParams params[6], StochasticOffsets sharedOffset, float2 dx, float2 dy, out float pixelOffset, out float weights[6]) { float3 viewDirTS = normalize(mul(tbn, viewDir)); - viewDirTS.xy /= viewDirTS.z * 0.7 + 0.3 + params[0].FlattenAmount; // Fix for objects at extreme viewing angles + viewDirTS.xy /= viewDirTS.z * 0.7 + 0.3 + params[0].FlattenAmount; float nearBlendToFar = saturate(distance / 2048.0); # if defined(TRUE_PBR) @@ -785,15 +769,15 @@ namespace ExtendedMaterials float4 currHeight; # if defined(TRUE_PBR) - currHeight.x = GetTerrainHeight(input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; - currHeight.y = GetTerrainHeight(input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; - currHeight.z = GetTerrainHeight(input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; - currHeight.w = GetTerrainHeight(input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; + currHeight.x = GetStochasticTerrainHeight(input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) * scalercp + 0.5; + currHeight.y = GetStochasticTerrainHeight(input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) * scalercp + 0.5; + currHeight.z = GetStochasticTerrainHeight(input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) * scalercp + 0.5; + currHeight.w = GetStochasticTerrainHeight(input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) * scalercp + 0.5; # else - currHeight.x = GetTerrainHeight(input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; - currHeight.y = GetTerrainHeight(input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; - currHeight.z = GetTerrainHeight(input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; - currHeight.w = GetTerrainHeight(input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; + currHeight.x = GetStochasticTerrainHeight(input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) + 0.5; + currHeight.y = GetStochasticTerrainHeight(input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) + 0.5; + currHeight.z = GetStochasticTerrainHeight(input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) + 0.5; + currHeight.w = GetStochasticTerrainHeight(input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) + 0.5; # endif bool4 testResult = currHeight >= currentBound; @@ -879,42 +863,41 @@ namespace ExtendedMaterials return coords; } - // Overload for GetParallaxSoftShadowMultiplierTerrain WITHOUT StochasticOffsets - float GetParallaxSoftShadowMultiplierTerrain(PS_INPUT input, float2 coords, float mipLevel[6], float3 L, float sh0, float quality, float noise, DisplacementParams params[6]) + float GetStochasticParallaxSoftShadowMultiplierTerrain(PS_INPUT input, float2 coords, float mipLevel[6], float3 L, float sh0, float quality, float noise, DisplacementParams params[6], StochasticOffsets sharedOffset, float2 dx, float2 dy) { if (quality > 0.0) { float4 multipliers = rcp((float4(1, 2, 3, 4) + noise)); float4 sh; float heights[6] = { 0, 0, 0, 0, 0, 0 }; float2 rayDir = L.xy * 0.1; - # if defined(TRUE_PBR) float scale = max(params[0].HeightScale * input.LandBlendWeights1.x, max(params[1].HeightScale * input.LandBlendWeights1.y, max(params[2].HeightScale * input.LandBlendWeights1.z, max(params[3].HeightScale * input.LandBlendWeights1.w, max(params[4].HeightScale * input.LandBlendWeights2.x, params[5].HeightScale * input.LandBlendWeights2.y))))); if (scale < 0.01) return 1.0; rayDir *= scale; - - sh = GetTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh = GetStochasticTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); if (quality > 0.25) - sh.y = GetTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.y = GetStochasticTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); if (quality > 0.5) - sh.z = GetTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.z = GetStochasticTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); if (quality > 0.75) - sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.w = GetStochasticTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); return pow(1.0 - saturate(dot(max(0, sh - sh0) / scale, 1.0)) * quality, 2.0); # else - sh = GetTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh = GetStochasticTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); if (quality > 0.25) - sh.y = GetTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.y = GetStochasticTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); if (quality > 0.5) - sh.z = GetTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.z = GetStochasticTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); if (quality > 0.75) - sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.w = GetStochasticTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); return pow(1.0 - saturate(dot(max(0, sh - sh0), 1.0)) * quality, 2.0); # endif } return 1.0; } + // ============================================ + #endif // defined(LANDSCAPE) && defined(TERRAIN_VARIATION) -} +} \ No newline at end of file diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 68ac1ccb59..98d43963e2 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1325,19 +1325,21 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) displacementParams[4].HeightScale *= LandscapeTexture5PBRParams.y; displacementParams[5].HeightScale *= LandscapeTexture6PBRParams.y; # endif - float weights[6]; -# if defined(TERRAIN_VARIATION) + +float weights[6]; +# if defined(TERRAIN_VARIATION) + // Use stochastic parallax system for terrain variation when enabled [branch] if (useTerrainVariation) { - uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, sharedOffset, dx, dy, pixelOffset, weights); + uv = ExtendedMaterials::GetStochasticParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, sharedOffset, dx, dy, pixelOffset, weights); } else { uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, pixelOffset, weights); } -# else +# else uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, pixelOffset, weights); -# endif +# endif if (SharedData::extendedMaterialSettings.EnableHeightBlending) { input.LandBlendWeights1.x = weights[0]; @@ -1348,18 +1350,20 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) input.LandBlendWeights2.y = weights[5]; } if (SharedData::extendedMaterialSettings.EnableShadows && (parallaxShadowQuality > 0.0f || SharedData::extendedMaterialSettings.ExtendShadows)) { -# if defined(TERRAIN_VARIATION) + float weights[6]; +# if defined(TERRAIN_VARIATION) + // Use stochastic terrain height system for terrain variation when enabled [branch] if (useTerrainVariation) { - sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); + sh0 = ExtendedMaterials::GetStochasticTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); } else { sh0 = ExtendedMaterials::GetTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); } -# else - sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); -# endif +# else + sh0 = ExtendedMaterials::GetTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); +# endif } } # endif // EMAT @@ -2414,26 +2418,34 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float3 dirLightDirectionTS = mul(refractedDirLightDirection, tbn).xyz; # if defined(LANDSCAPE) [branch] if (SharedData::extendedMaterialSettings.EnableTerrainParallax) - { -# if defined(TERRAIN_VARIATION) + { float weights[6]; +# if defined(TERRAIN_VARIATION) + // Use stochastic terrain height system for terrain variation when enabled [branch] if (useTerrainVariation) { - float weights[6]; - sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); - - parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dx, dy); + sh0 = ExtendedMaterials::GetStochasticTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); } else { - float weights[6]; sh0 = ExtendedMaterials::GetTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); + } +# else + sh0 = ExtendedMaterials::GetTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); +# endif +# if defined(TERRAIN_VARIATION) + // Use stochastic parallax soft shadow system for terrain variation when enabled + [branch] if (useTerrainVariation) + { + parallaxShadow = ExtendedMaterials::GetStochasticParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dx, dy); + } + else + { parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams); } -# else - // Standard terrain parallax shadow without stochastic sampling +# else parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams); -# endif +# endif } # elif defined(PARALLAX) [branch] if (SharedData::extendedMaterialSettings.EnableParallax) From 8f42fdb60c010b460af164772e2a8c57f5237abf Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Sun, 8 Jun 2025 18:38:22 +1000 Subject: [PATCH 37/53] Update TerrainVariation.hlsli --- .../Shaders/TerrainVariation/TerrainVariation.hlsli | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index fcb2dc1861..4f4a38d7a0 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -134,7 +134,7 @@ inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 landscapeUV) // Ultra-cheap stochastic sampling - 1 texture sample with hash-based offset variation inline float4 StochasticSampleLow(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsetsLow, float2 dx, float2 dy) { - // Single texture sample with stochastic offset - no blending, maximum performance + // Single texture sample with stochastic offset. return tex.SampleLevel(samp, uv + offsetsLow.offset1, mipLevel); } @@ -202,10 +202,17 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler { // Distance-based LOD with smooth transition float distanceFactor = saturate((distance - DISTANCE_LOD_THRESHOLD) / DISTANCE_LOD_TRANSITION); - // Low sample (always computed for transition) + + // Early exit for distant terrain - avoid computing high quality samples that would be discarded + if (distanceFactor >= 0.999) + { + return StochasticSampleLow(rnd, mipLevel, tex, samp, uv, offsets, dx, dy); + } + + // Low sample (always computed for partial transition) float4 lowSample = StochasticSampleLow(rnd, mipLevel, tex, samp, uv, offsets, dx, dy); - // Full quality path for near terrain + // Only do expensive computation if we're going to use at least some of it // Apply contrast to the initial blend weights (without height influence) float3 blendWeights = pow(saturate(offsets.weights), HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE)); From 2435e418378954d7af8df11dadcd35aa672b3907 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 8 Jun 2025 08:38:41 +0000 Subject: [PATCH 38/53] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20pre-commi?= =?UTF-8?q?t.ci=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated formatting by clang-format, prettier, and other hooks. See https://pre-commit.ci for details. --- .../Shaders/TerrainVariation/TerrainVariation.hlsli | 8 ++++---- package/Shaders/Lighting.hlsl | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index 4f4a38d7a0..42d86ed217 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -202,16 +202,16 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler { // Distance-based LOD with smooth transition float distanceFactor = saturate((distance - DISTANCE_LOD_THRESHOLD) / DISTANCE_LOD_TRANSITION); - + // Early exit for distant terrain - avoid computing high quality samples that would be discarded if (distanceFactor >= 0.999) { return StochasticSampleLow(rnd, mipLevel, tex, samp, uv, offsets, dx, dy); } - + // Low sample (always computed for partial transition) float4 lowSample = StochasticSampleLow(rnd, mipLevel, tex, samp, uv, offsets, dx, dy); - + // Only do expensive computation if we're going to use at least some of it // Apply contrast to the initial blend weights (without height influence) float3 blendWeights = pow(saturate(offsets.weights), HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE)); @@ -222,7 +222,7 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); - + // Apply height-based weight adjustments float3x3 rgbMatrix = float3x3(sample1.rgb, sample2.rgb, sample3.rgb); float3 luminanceHeights = mul(rgbMatrix, LUMINANCE_WEIGHTS); diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 98d43963e2..64a4ff3d18 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1273,10 +1273,10 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TRUE_PBR) float4 blendedRMAOS = 0; # endif - + // Calculate view distance once for terrain optimizations float distance = length(viewPosition); - + // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) # if defined(TERRAIN_VARIATION) bool useTerrainVariation = SharedData::terrainVariationSettings.enableTilingFix; @@ -1325,7 +1325,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) displacementParams[4].HeightScale *= LandscapeTexture5PBRParams.y; displacementParams[5].HeightScale *= LandscapeTexture6PBRParams.y; # endif - + float weights[6]; # if defined(TERRAIN_VARIATION) // Use stochastic parallax system for terrain variation when enabled From ccacd071cb4b705169b6d7a52592217bb2b83c4b Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Mon, 9 Jun 2025 10:26:33 +1000 Subject: [PATCH 39/53] undo to emat changes --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 513 +++++++++--------- package/Shaders/Lighting.hlsl | 56 +- 2 files changed, 287 insertions(+), 282 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index 4d6f597a6b..7f6f64ed2e 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -5,6 +5,10 @@ // http://www.diva-portal.org/smash/get/diva2:831762/FULLTEXT01.pdf // https://bartwronski.files.wordpress.com/2014/03/ac4_gdc.pdf +#if defined(TERRAIN_VARIATION) +# include "TerrainVariation/TerrainVariation.hlsli" +#endif + struct DisplacementParams { float DisplacementScale; @@ -13,10 +17,6 @@ struct DisplacementParams float FlattenAmount; }; -#if defined(TERRAIN_VARIATION) -# include "TerrainVariation/TerrainVariation.hlsli" -#endif - namespace ExtendedMaterials { @@ -41,35 +41,38 @@ namespace ExtendedMaterials float2 textureDims; tex.GetDimensions(textureDims.x, textureDims.y); -#if !defined(PARALLAX) && !defined(TRUE_PBR) - textureDims /= 2.0; -#endif + #if !defined(TERRAIN_VARIATION) + textureDims /= 2.0; + #endif -#if defined(VR) - textureDims /= 2.0; -#endif + #if !defined(PARALLAX) && !defined(TRUE_PBR) + textureDims /= 2.0; + #endif - float2 texCoordsPerSize = coords * textureDims; + #if defined(VR) + textureDims /= 2.0; + #endif - float2 dxSize = ddx(texCoordsPerSize); - float2 dySize = ddy(texCoordsPerSize); + float2 texCoordsPerSize = coords * textureDims; - // Find min of change in u and v across quad: compute du and dv magnitude across quad - //float2 dTexCoords = dxSize * dxSize + dySize * dySize; + float2 dxSize = ddx(texCoordsPerSize); + float2 dySize = ddy(texCoordsPerSize); - // Standard mipmapping uses max here - float minTexCoordDelta = min(dot(dxSize, dxSize), dot(dySize, dySize)); + // Find min of change in u and v across quad: compute du and dv magnitude across quad + //float2 dTexCoords = dxSize * dxSize + dySize * dySize; - // Compute the current mip level (* 0.5 is effectively computing a square root before ) - float mipLevel = max(0.5 * log2(minTexCoordDelta), 0); + // Standard mipmapping uses max here + float minTexCoordDelta = min(dot(dxSize, dxSize), dot(dySize, dySize)); -#if !defined(PARALLAX) && !defined(TRUE_PBR) - mipLevel++; -#endif + // Compute the current mip level (* 0.5 is effectively computing a square root before ) + float mipLevel = max(0.5 * log2(minTexCoordDelta), 0); + #if !defined(PARALLAX) && !defined(TRUE_PBR) + mipLevel++; + #endif -#if defined(VR) - mipLevel++; -#endif + #if defined(VR) + mipLevel++; + #endif return mipLevel; } @@ -78,7 +81,11 @@ namespace ExtendedMaterials # if defined(TRUE_PBR) # define HEIGHT_POWER 2 # define HEIGHT_MULT 8 - float GetTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, out float weights[6]) + float GetTerrainHeight(float screenNoise, PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, +# if defined(TERRAIN_VARIATION) + StochasticOffsets sharedOffset, float2 dx, float2 dy, +# endif + out float weights[6]) { float heightBlend = 1 + blendFactor * HEIGHT_POWER; weights[0] = w1.x; @@ -90,37 +97,68 @@ namespace ExtendedMaterials float total = 0; [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.0) { - float h = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); + float h; +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexLandDisplacement0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); + +# else + h = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); +# endif total += h * weights[0]; weights[0] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1HasDisplacement) != 0 && w1.y > 0.0) { - float h = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); + float h; +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandDisplacement1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); +# else + h = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); +# endif total += h * weights[1]; weights[1] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2HasDisplacement) != 0 && w1.z > 0.0) { - float h = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); + float h; +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandDisplacement2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); +# else + h = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); +# endif total += h * weights[2]; weights[2] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) { - float h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); + float h; +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); +# else + h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); +# endif total += h * weights[3]; weights[3] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) { - float h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); + float h; +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); +# else + h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); +# endif total += h * weights[4]; weights[4] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) { - float h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); + float h; +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); +# else + h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); +# endif total += h * weights[5]; weights[5] *= pow(heightBlend, HEIGHT_MULT * h); } @@ -143,7 +181,11 @@ namespace ExtendedMaterials # else # define HEIGHT_POWER 2 # define HEIGHT_MULT 8 - float GetTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, out float weights[6]) + float GetTerrainHeight(float screenNoise, PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, +# if defined(TERRAIN_VARIATION) + StochasticOffsets sharedOffset, float2 dx, float2 dy, +# endif + out float weights[6]) { float heightBlend = 1 + blendFactor * HEIGHT_POWER; weights[0] = w1.x; @@ -153,15 +195,24 @@ namespace ExtendedMaterials weights[4] = w2.x; weights[5] = w2.y; float total = 0; + if (w1.x > 0.0) { float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand0HasDisplacement) != 0) { +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexLandTHDisp0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); +# else h = ScaleDisplacement(TexLandTHDisp0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); +# endif } else { +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexColorSampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[0]); +# else h = ScaleDisplacement(TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, params[0]); +# endif } total += h * weights[0]; weights[0] *= pow(heightBlend, HEIGHT_MULT * h); @@ -170,11 +221,19 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) { +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandTHDisp1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); +# else h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); +# endif } else { +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandColor2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[1]); +# else h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); +# endif } total += h * weights[1]; weights[1] *= pow(heightBlend, HEIGHT_MULT * h); @@ -183,51 +242,53 @@ namespace ExtendedMaterials float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) { +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandTHDisp2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); +# else h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); +# endif } else { +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandColor3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[2]); +# else h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); +# endif } total += h * weights[2]; weights[2] *= pow(heightBlend, HEIGHT_MULT * h); } - if (w1.w > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0) - { - h = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); - } - else - { - h = ScaleDisplacement(TexLandColor4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).w, params[3]); - } + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0 && w1.w > 0.0) + { + float h; +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandTHDisp3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); +# else + h = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); +# endif total += h * weights[3]; weights[3] *= pow(heightBlend, HEIGHT_MULT * h); } - if (w2.x > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0) - { - h = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); - } - else - { - h = ScaleDisplacement(TexLandColor5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).w, params[4]); - } + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0 && w2.x > 0.0) + { + float h; +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandTHDisp4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); +# else + h = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); +# endif total += h * weights[4]; weights[4] *= pow(heightBlend, HEIGHT_MULT * h); } - if (w2.y > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0) - { - h = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); - } - else - { - h = ScaleDisplacement(TexLandColor6Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).w, params[5]); - } + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0 && w2.y > 0.0) + { + float h; +# if defined(TERRAIN_VARIATION) + h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandTHDisp5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); +# else + h = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); +# endif total += h * weights[5]; weights[5] *= pow(heightBlend, HEIGHT_MULT * h); } @@ -252,7 +313,11 @@ namespace ExtendedMaterials #endif #if defined(LANDSCAPE) - float2 GetParallaxCoords(PS_INPUT input, float distance, float2 coords, float mipLevels[6], float3 viewDir, float3x3 tbn, float noise, DisplacementParams params[6], out float pixelOffset, out float weights[6]) + float2 GetParallaxCoords(PS_INPUT input, float distance, float2 coords, float mipLevels[6], float3 viewDir, float3x3 tbn, float noise, DisplacementParams params[6], +# if defined(TERRAIN_VARIATION) + StochasticOffsets sharedOffset, float2 dx, float2 dy, +# endif + out float pixelOffset, out float weights[6]) #else float2 GetParallaxCoords(float distance, float2 coords, float mipLevel, float3 viewDir, float3x3 tbn, float noise, Texture2D tex, SamplerState texSampler, uint channel, DisplacementParams params, out float pixelOffset) #endif @@ -326,15 +391,29 @@ namespace ExtendedMaterials float4 currHeight; #if defined(LANDSCAPE) # if defined(TRUE_PBR) - currHeight.x = GetTerrainHeight(input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; - currHeight.y = GetTerrainHeight(input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; - currHeight.z = GetTerrainHeight(input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; - currHeight.w = GetTerrainHeight(input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; +# if defined(TERRAIN_VARIATION) + currHeight.x = GetTerrainHeight(noise, input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) * scalercp + 0.5; + currHeight.y = GetTerrainHeight(noise, input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) * scalercp + 0.5; + currHeight.z = GetTerrainHeight(noise, input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) * scalercp + 0.5; + currHeight.w = GetTerrainHeight(noise, input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) * scalercp + 0.5; +# else + currHeight.x = GetTerrainHeight(noise, input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; + currHeight.y = GetTerrainHeight(noise, input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; + currHeight.z = GetTerrainHeight(noise, input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; + currHeight.w = GetTerrainHeight(noise, input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; +# endif # else - currHeight.x = GetTerrainHeight(input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; - currHeight.y = GetTerrainHeight(input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; - currHeight.z = GetTerrainHeight(input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; - currHeight.w = GetTerrainHeight(input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; +# if defined(TERRAIN_VARIATION) + currHeight.x = GetTerrainHeight(noise, input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) + 0.5; + currHeight.y = GetTerrainHeight(noise, input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) + 0.5; + currHeight.z = GetTerrainHeight(noise, input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) + 0.5; + currHeight.w = GetTerrainHeight(noise, input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) + 0.5; +# else + currHeight.x = GetTerrainHeight(noise, input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; + currHeight.y = GetTerrainHeight(noise, input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; + currHeight.z = GetTerrainHeight(noise, input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; + currHeight.w = GetTerrainHeight(noise, input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; +# endif # endif #else currHeight.x = tex.SampleLevel(texSampler, currentOffset[0].xy, mipLevel)[channel]; @@ -452,52 +531,72 @@ namespace ExtendedMaterials } #if defined(LANDSCAPE) +# if defined(TERRAIN_VARIATION) + float GetParallaxSoftShadowMultiplierTerrain(PS_INPUT input, float2 coords, float mipLevel[6], float3 L, float sh0, float quality, float noise, DisplacementParams params[6], StochasticOffsets sharedOffset, float2 dx, float2 dy) +# else float GetParallaxSoftShadowMultiplierTerrain(PS_INPUT input, float2 coords, float mipLevel[6], float3 L, float sh0, float quality, float noise, DisplacementParams params[6]) +# endif { if (quality > 0.0) { float4 multipliers = rcp((float4(1, 2, 3, 4) + noise)); float4 sh; float heights[6] = { 0, 0, 0, 0, 0, 0 }; float2 rayDir = L.xy * 0.1; + # if defined(TRUE_PBR) float scale = max(params[0].HeightScale * input.LandBlendWeights1.x, max(params[1].HeightScale * input.LandBlendWeights1.y, max(params[2].HeightScale * input.LandBlendWeights1.z, max(params[3].HeightScale * input.LandBlendWeights1.w, max(params[4].HeightScale * input.LandBlendWeights2.x, params[5].HeightScale * input.LandBlendWeights2.y))))); if (scale < 0.01) return 1.0; rayDir *= scale; - sh = GetTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + +# if defined(TERRAIN_VARIATION) + sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); if (quality > 0.25) - sh.y = GetTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); if (quality > 0.5) - sh.z = GetTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); if (quality > 0.75) - sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); +# else + sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (quality > 0.25) + sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (quality > 0.5) + sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (quality > 0.75) + sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); +# endif return pow(1.0 - saturate(dot(max(0, sh - sh0) / scale, 1.0)) * quality, 2.0); # else - sh = GetTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); +# if defined(TERRAIN_VARIATION) + sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); if (quality > 0.25) - sh.y = GetTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); if (quality > 0.5) - sh.z = GetTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); if (quality > 0.75) - sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); +# else + sh = GetTerrainHeight(noise, input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (quality > 0.25) + sh.y = GetTerrainHeight(noise, input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (quality > 0.5) + sh.z = GetTerrainHeight(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); + if (quality > 0.75) + sh.w = GetTerrainHeight(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); +# endif return pow(1.0 - saturate(dot(max(0, sh - sh0), 1.0)) * quality, 2.0); # endif } return 1.0; } #endif - - #if defined(LANDSCAPE) && defined(TERRAIN_VARIATION) - // ============================================ - // STOCHASTIC PARALLAX SYSTEM - // ============================================ - // Complete parallax system for terrain variation with stochastic sampling - // Separate implementation to avoid per-line integration performance overhead + // Overload for GetTerrainHeight WITHOUT StochasticOffsets (when enableTilingFix is false) # if defined(TRUE_PBR) - float GetStochasticTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, StochasticOffsets sharedOffset, float2 dx, float2 dy, out float weights[6]) + float GetTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, out float weights[6]) { float heightBlend = 1 + blendFactor * HEIGHT_POWER; weights[0] = w1.x; @@ -507,57 +606,41 @@ namespace ExtendedMaterials weights[4] = w2.x; weights[5] = w2.y; float total = 0; + float screenNoise = 0; // Default noise value when no stochastic sampling + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.0) { - float h1 = ScaleDisplacement(TexLandDisplacement0Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[0]); - float h2 = ScaleDisplacement(TexLandDisplacement0Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[0]); - float h3 = ScaleDisplacement(TexLandDisplacement0Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[0]); - float h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; + float h = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); total += h * weights[0]; weights[0] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1HasDisplacement) != 0 && w1.y > 0.0) { - float h1 = ScaleDisplacement(TexLandDisplacement1Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[1]); - float h2 = ScaleDisplacement(TexLandDisplacement1Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[1]); - float h3 = ScaleDisplacement(TexLandDisplacement1Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[1]); - float h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; + float h = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); total += h * weights[1]; weights[1] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2HasDisplacement) != 0 && w1.z > 0.0) { - float h1 = ScaleDisplacement(TexLandDisplacement2Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[2]); - float h2 = ScaleDisplacement(TexLandDisplacement2Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[2]); - float h3 = ScaleDisplacement(TexLandDisplacement2Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[2]); - float h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; + float h = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); total += h * weights[2]; weights[2] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) { - float h1 = ScaleDisplacement(TexLandDisplacement3Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[3]); - float h2 = ScaleDisplacement(TexLandDisplacement3Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[3]); - float h3 = ScaleDisplacement(TexLandDisplacement3Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[3]); - float h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; + float h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); total += h * weights[3]; weights[3] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) { - float h1 = ScaleDisplacement(TexLandDisplacement4Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[4]); - float h2 = ScaleDisplacement(TexLandDisplacement4Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[4]); - float h3 = ScaleDisplacement(TexLandDisplacement4Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[4]); - float h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; + float h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); total += h * weights[4]; weights[4] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) { - float h1 = ScaleDisplacement(TexLandDisplacement5Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[5]); - float h2 = ScaleDisplacement(TexLandDisplacement5Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[5]); - float h3 = ScaleDisplacement(TexLandDisplacement5Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[5]); - float h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; + float h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); total += h * weights[5]; weights[5] *= pow(heightBlend, HEIGHT_MULT * h); } @@ -578,7 +661,7 @@ namespace ExtendedMaterials return total; } # else - float GetStochasticTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, StochasticOffsets sharedOffset, float2 dx, float2 dy, out float weights[6]) + float GetTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, out float weights[6]) { float heightBlend = 1 + blendFactor * HEIGHT_POWER; weights[0] = w1.x; @@ -588,120 +671,52 @@ namespace ExtendedMaterials weights[4] = w2.x; weights[5] = w2.y; float total = 0; - if (w1.x > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand0HasDisplacement) != 0) - { - float h1 = ScaleDisplacement(TexLandTHDisp0Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[0]); - float h2 = ScaleDisplacement(TexLandTHDisp0Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[0]); - float h3 = ScaleDisplacement(TexLandTHDisp0Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[0]); - h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; - } - else - { - float h1 = ScaleDisplacement(TexColorSampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).w, params[0]); - float h2 = ScaleDisplacement(TexColorSampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).w, params[0]); - float h3 = ScaleDisplacement(TexColorSampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).w, params[0]); - h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; - } - total += h * weights[0]; - weights[0] *= pow(heightBlend, HEIGHT_MULT * h); - } - if (w1.y > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) - { - float h1 = ScaleDisplacement(TexLandTHDisp1Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[1]); - float h2 = ScaleDisplacement(TexLandTHDisp1Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[1]); - float h3 = ScaleDisplacement(TexLandTHDisp1Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[1]); - h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; - } - else - { - float h1 = ScaleDisplacement(TexLandColor2Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).w, params[1]); - float h2 = ScaleDisplacement(TexLandColor2Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).w, params[1]); - float h3 = ScaleDisplacement(TexLandColor2Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).w, params[1]); - h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; - } - total += h * weights[1]; - weights[1] *= pow(heightBlend, HEIGHT_MULT * h); - } - if (w1.z > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) - { - float h1 = ScaleDisplacement(TexLandTHDisp2Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[2]); - float h2 = ScaleDisplacement(TexLandTHDisp2Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[2]); - float h3 = ScaleDisplacement(TexLandTHDisp2Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[2]); - h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; - } - else - { - float h1 = ScaleDisplacement(TexLandColor3Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).w, params[2]); - float h2 = ScaleDisplacement(TexLandColor3Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).w, params[2]); - float h3 = ScaleDisplacement(TexLandColor3Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).w, params[2]); - h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; - } - total += h * weights[2]; - weights[2] *= pow(heightBlend, HEIGHT_MULT * h); - } - if (w1.w > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0) - { - float h1 = ScaleDisplacement(TexLandTHDisp3Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[3]); - float h2 = ScaleDisplacement(TexLandTHDisp3Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[3]); - float h3 = ScaleDisplacement(TexLandTHDisp3Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[3]); - h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; - } - else - { - float h1 = ScaleDisplacement(TexLandColor4Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).w, params[3]); - float h2 = ScaleDisplacement(TexLandColor4Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).w, params[3]); - float h3 = ScaleDisplacement(TexLandColor4Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).w, params[3]); - h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; - } - total += h * weights[3]; - weights[3] *= pow(heightBlend, HEIGHT_MULT * h); - } - if (w2.x > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0) - { - float h1 = ScaleDisplacement(TexLandTHDisp4Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[4]); - float h2 = ScaleDisplacement(TexLandTHDisp4Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[4]); - float h3 = ScaleDisplacement(TexLandTHDisp4Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[4]); - h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; - } - else - { - float h1 = ScaleDisplacement(TexLandColor5Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).w, params[4]); - float h2 = ScaleDisplacement(TexLandColor5Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).w, params[4]); - float h3 = ScaleDisplacement(TexLandColor5Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).w, params[4]); - h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; - } - total += h * weights[4]; - weights[4] *= pow(heightBlend, HEIGHT_MULT * h); - } - if (w2.y > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0) - { - float h1 = ScaleDisplacement(TexLandTHDisp5Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).x, params[5]); - float h2 = ScaleDisplacement(TexLandTHDisp5Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).x, params[5]); - float h3 = ScaleDisplacement(TexLandTHDisp5Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).x, params[5]); - h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; - } - else - { - float h1 = ScaleDisplacement(TexLandColor6Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset1, dx, dy).w, params[5]); - float h2 = ScaleDisplacement(TexLandColor6Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset2, dx, dy).w, params[5]); - float h3 = ScaleDisplacement(TexLandColor6Sampler.SampleGrad(SampTerrainParallaxSampler, coords + sharedOffset.offset3, dx, dy).w, params[5]); - h = h1 * sharedOffset.weights.x + h2 * sharedOffset.weights.y + h3 * sharedOffset.weights.z; - } - total += h * weights[5]; - weights[5] *= pow(heightBlend, HEIGHT_MULT * h); - } + float screenNoise = 0; // Default noise value when no stochastic sampling + + if (w1.y > 0.0) { + float h = 0.0; + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) + { + h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); + } + else + { + h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); + } + total += h * weights[1]; + weights[1] *= pow(heightBlend, HEIGHT_MULT * h); + } + if (w1.z > 0.0) { + float h = 0.0; + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) + { + h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); + } + else + { + h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); + } + total += h * weights[2]; + weights[2] *= pow(heightBlend, HEIGHT_MULT * h); + } + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0 && w1.w > 0.0) + { + float h = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); + total += h * weights[3]; + weights[3] *= pow(heightBlend, HEIGHT_MULT * h); + } + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0 && w2.x > 0.0) + { + float h = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); + total += h * weights[4]; + weights[4] *= pow(heightBlend, HEIGHT_MULT * h); + } + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0 && w2.y > 0.0) + { + float h = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); + total += h * weights[5]; + weights[5] *= pow(heightBlend, HEIGHT_MULT * h); + } [unroll] for (int i = 0; i < 6; i++) { weights[i] = min(100, pow(weights[i], heightBlend)); @@ -720,10 +735,11 @@ namespace ExtendedMaterials } # endif - float2 GetStochasticParallaxCoords(PS_INPUT input, float distance, float2 coords, float mipLevels[6], float3 viewDir, float3x3 tbn, float noise, DisplacementParams params[6], StochasticOffsets sharedOffset, float2 dx, float2 dy, out float pixelOffset, out float weights[6]) + // Overload for GetParallaxCoords WITHOUT StochasticOffsets (when enableTilingFix is false) + float2 GetParallaxCoords(PS_INPUT input, float distance, float2 coords, float mipLevels[6], float3 viewDir, float3x3 tbn, float noise, DisplacementParams params[6], out float pixelOffset, out float weights[6]) { float3 viewDirTS = normalize(mul(tbn, viewDir)); - viewDirTS.xy /= viewDirTS.z * 0.7 + 0.3 + params[0].FlattenAmount; + viewDirTS.xy /= viewDirTS.z * 0.7 + 0.3 + params[0].FlattenAmount; // Fix for objects at extreme viewing angles float nearBlendToFar = saturate(distance / 2048.0); # if defined(TRUE_PBR) @@ -769,15 +785,15 @@ namespace ExtendedMaterials float4 currHeight; # if defined(TRUE_PBR) - currHeight.x = GetStochasticTerrainHeight(input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) * scalercp + 0.5; - currHeight.y = GetStochasticTerrainHeight(input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) * scalercp + 0.5; - currHeight.z = GetStochasticTerrainHeight(input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) * scalercp + 0.5; - currHeight.w = GetStochasticTerrainHeight(input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) * scalercp + 0.5; + currHeight.x = GetTerrainHeight(input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; + currHeight.y = GetTerrainHeight(input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; + currHeight.z = GetTerrainHeight(input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; + currHeight.w = GetTerrainHeight(input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) * scalercp + 0.5; # else - currHeight.x = GetStochasticTerrainHeight(input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) + 0.5; - currHeight.y = GetStochasticTerrainHeight(input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) + 0.5; - currHeight.z = GetStochasticTerrainHeight(input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) + 0.5; - currHeight.w = GetStochasticTerrainHeight(input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, sharedOffset, dx, dy, weights) + 0.5; + currHeight.x = GetTerrainHeight(input, currentOffset[0].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; + currHeight.y = GetTerrainHeight(input, currentOffset[0].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; + currHeight.z = GetTerrainHeight(input, currentOffset[1].xy, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; + currHeight.w = GetTerrainHeight(input, currentOffset[1].zw, mipLevels, params, blendFactor, w1, w2, weights) + 0.5; # endif bool4 testResult = currHeight >= currentBound; @@ -863,41 +879,42 @@ namespace ExtendedMaterials return coords; } - float GetStochasticParallaxSoftShadowMultiplierTerrain(PS_INPUT input, float2 coords, float mipLevel[6], float3 L, float sh0, float quality, float noise, DisplacementParams params[6], StochasticOffsets sharedOffset, float2 dx, float2 dy) + // Overload for GetParallaxSoftShadowMultiplierTerrain WITHOUT StochasticOffsets + float GetParallaxSoftShadowMultiplierTerrain(PS_INPUT input, float2 coords, float mipLevel[6], float3 L, float sh0, float quality, float noise, DisplacementParams params[6]) { if (quality > 0.0) { float4 multipliers = rcp((float4(1, 2, 3, 4) + noise)); float4 sh; float heights[6] = { 0, 0, 0, 0, 0, 0 }; float2 rayDir = L.xy * 0.1; + # if defined(TRUE_PBR) float scale = max(params[0].HeightScale * input.LandBlendWeights1.x, max(params[1].HeightScale * input.LandBlendWeights1.y, max(params[2].HeightScale * input.LandBlendWeights1.z, max(params[3].HeightScale * input.LandBlendWeights1.w, max(params[4].HeightScale * input.LandBlendWeights2.x, params[5].HeightScale * input.LandBlendWeights2.y))))); if (scale < 0.01) return 1.0; rayDir *= scale; - sh = GetStochasticTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + + sh = GetTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.25) - sh.y = GetStochasticTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + sh.y = GetTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.5) - sh.z = GetStochasticTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + sh.z = GetTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.75) - sh.w = GetStochasticTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); return pow(1.0 - saturate(dot(max(0, sh - sh0) / scale, 1.0)) * quality, 2.0); # else - sh = GetStochasticTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + sh = GetTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.25) - sh.y = GetStochasticTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + sh.y = GetTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.5) - sh.z = GetStochasticTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + sh.z = GetTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); if (quality > 0.75) - sh.w = GetStochasticTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, heights); + sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, heights); return pow(1.0 - saturate(dot(max(0, sh - sh0), 1.0)) * quality, 2.0); # endif } return 1.0; } - // ============================================ - #endif // defined(LANDSCAPE) && defined(TERRAIN_VARIATION) } \ No newline at end of file diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 64a4ff3d18..68ac1ccb59 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1273,10 +1273,10 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TRUE_PBR) float4 blendedRMAOS = 0; # endif - + // Calculate view distance once for terrain optimizations float distance = length(viewPosition); - + // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) # if defined(TERRAIN_VARIATION) bool useTerrainVariation = SharedData::terrainVariationSettings.enableTilingFix; @@ -1325,21 +1325,19 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) displacementParams[4].HeightScale *= LandscapeTexture5PBRParams.y; displacementParams[5].HeightScale *= LandscapeTexture6PBRParams.y; # endif - -float weights[6]; -# if defined(TERRAIN_VARIATION) - // Use stochastic parallax system for terrain variation when enabled + float weights[6]; +# if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - uv = ExtendedMaterials::GetStochasticParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, sharedOffset, dx, dy, pixelOffset, weights); + uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, sharedOffset, dx, dy, pixelOffset, weights); } else { uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, pixelOffset, weights); } -# else +# else uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, pixelOffset, weights); -# endif +# endif if (SharedData::extendedMaterialSettings.EnableHeightBlending) { input.LandBlendWeights1.x = weights[0]; @@ -1350,20 +1348,18 @@ float weights[6]; input.LandBlendWeights2.y = weights[5]; } if (SharedData::extendedMaterialSettings.EnableShadows && (parallaxShadowQuality > 0.0f || SharedData::extendedMaterialSettings.ExtendShadows)) { - float weights[6]; -# if defined(TERRAIN_VARIATION) - // Use stochastic terrain height system for terrain variation when enabled +# if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - sh0 = ExtendedMaterials::GetStochasticTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); + sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); } else { sh0 = ExtendedMaterials::GetTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); } -# else - sh0 = ExtendedMaterials::GetTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); -# endif +# else + sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); +# endif } } # endif // EMAT @@ -2418,34 +2414,26 @@ float weights[6]; float3 dirLightDirectionTS = mul(refractedDirLightDirection, tbn).xyz; # if defined(LANDSCAPE) [branch] if (SharedData::extendedMaterialSettings.EnableTerrainParallax) - { float weights[6]; -# if defined(TERRAIN_VARIATION) - // Use stochastic terrain height system for terrain variation when enabled + { +# if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - sh0 = ExtendedMaterials::GetStochasticTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); + float weights[6]; + sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); + + parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dx, dy); } else { + float weights[6]; sh0 = ExtendedMaterials::GetTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); - } -# else - sh0 = ExtendedMaterials::GetTerrainHeight(input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); -# endif -# if defined(TERRAIN_VARIATION) - // Use stochastic parallax soft shadow system for terrain variation when enabled - [branch] if (useTerrainVariation) - { - parallaxShadow = ExtendedMaterials::GetStochasticParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dx, dy); - } - else - { parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams); } -# else +# else + // Standard terrain parallax shadow without stochastic sampling parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams); -# endif +# endif } # elif defined(PARALLAX) [branch] if (SharedData::extendedMaterialSettings.EnableParallax) From cc076a607170cccdd656064d365d4ef98449a11f Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Mon, 9 Jun 2025 12:33:58 +1000 Subject: [PATCH 40/53] Update ExtendedMaterials.hlsli --- .../Shaders/ExtendedMaterials/ExtendedMaterials.hlsli | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index 7f6f64ed2e..93287992d0 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -41,10 +41,6 @@ namespace ExtendedMaterials float2 textureDims; tex.GetDimensions(textureDims.x, textureDims.y); - #if !defined(TERRAIN_VARIATION) - textureDims /= 2.0; - #endif - #if !defined(PARALLAX) && !defined(TRUE_PBR) textureDims /= 2.0; #endif @@ -66,6 +62,7 @@ namespace ExtendedMaterials // Compute the current mip level (* 0.5 is effectively computing a square root before ) float mipLevel = max(0.5 * log2(minTexCoordDelta), 0); + #if !defined(PARALLAX) && !defined(TRUE_PBR) mipLevel++; #endif From 33f58b844fd18393fe4c3df9d762e54441f00d23 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Tue, 10 Jun 2025 18:57:21 +1000 Subject: [PATCH 41/53] Updates --- .../TerrainVariation/TerrainVariation.hlsli | 130 ++++++------------ package/Shaders/Lighting.hlsl | 1 - 2 files changed, 40 insertions(+), 91 deletions(-) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index 42d86ed217..5354589c98 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -20,7 +20,7 @@ static const float3 DEFAULT_WEIGHTS = float3(0.33, 0.33, 0.34); static const float3 LUMINANCE_WEIGHTS = float3(0.2126, 0.7152, 0.0722); // Distance-based LOD optimization constants static const float DISTANCE_LOD_THRESHOLD = 1024.0; // Distance threshold for fast path optimization -static const float DISTANCE_LOD_TRANSITION = 200.0; // Transition zone width (units) +static const float DISTANCE_LOD_TRANSITION = 300.0; // Transition zone width (units) // Hash constants static const float2 HASH_MULTIPLIER = float2(1271.5151, 3337.8237); static const float2 HASH_SINE_MULTIPLIER = float2(43758.5453, 28637.1369); @@ -77,36 +77,6 @@ inline StochasticOffsets ComputeStochasticOffsets(float2 landscapeUV) return offsets; } -// Simplified version for functions that only need 2 offsets -inline StochasticOffsets ComputeStochasticOffsets2(float2 landscapeUV) -{ - float4x3 BW_vx = ComputeBarycentricVerts(landscapeUV); - - StochasticOffsets offsets2; - offsets2.offset1 = hash2D2D(BW_vx[0].xy); - offsets2.offset2 = hash2D2D(BW_vx[1].xy); - offsets2.offset3 = float2(0, 0); - offsets2.weights = float3(BW_vx[3].x, BW_vx[3].y, 0.0); - - return offsets2; -} -// Some triangular artifacts, but really not obvious at distance. -inline StochasticOffsets ComputeStochasticOffsetsLow(float2 landscapeUV) -{ - float2 scaledUV = landscapeUV * (WORLD_SCALE); - float2 cellID = floor(scaledUV); - - StochasticOffsets offsetsLow; - // Only need 1 hash since we only take 1 real texture sample - float2 hash1 = hashLOD(cellID); - - offsetsLow.offset1 = hash1 * 0.65; - offsetsLow.offset2 = hash1; // Reuse for synthetic variation - offsetsLow.weights = float3(1.0, 0.0, 0.0); // Only first weight matters - - return offsetsLow; -} - inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 landscapeUV) { // Precomputed scaling: (WORLD_SCALE / 0.010416667) * 8.0 = ~255437 @@ -131,42 +101,22 @@ inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 landscapeUV) // --------------------- STOCHASTIC SAMPLING FUNCTIONS --------------------- // -// Ultra-cheap stochastic sampling - 1 texture sample with hash-based offset variation -inline float4 StochasticSampleLow(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsetsLow, float2 dx, float2 dy) -{ - // Single texture sample with stochastic offset. - return tex.SampleLevel(samp, uv + offsetsLow.offset1, mipLevel); -} - -// Cheap 2 sample version. -inline float4 StochasticSample2(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) -{ - // Sample only two texture offsets using the provided mip level - float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); - float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); - - // Use proper weight normalization to avoid artifacts - float2 weights2D = offsets.weights.xy; - float totalWeight = weights2D.x + weights2D.y; - if (totalWeight > 0.0) { - weights2D /= totalWeight; - } else { - weights2D = float2(0.5, 0.5); - } - - // Direct blend without third interpolated sample - float4 result = sample1 * weights2D.x + sample2 * weights2D.y; - - return result; -} - // Same as StochasticEffect but no height/luminescence influence, so much cheaper but worse quality, doesn't matter for the use case. inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) { - // Sample the three texture offsets - float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); - float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); - float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); + // // Distance-based LOD with smooth transition + // float distanceFactor = saturate((distance - DISTANCE_LOD_THRESHOLD) / DISTANCE_LOD_TRANSITION); + + // Take 3 samples always + float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); + float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); + + // // Early exit for distant terrain - return single sample with cheap offset + // if (distanceFactor >= 0.9) + // { + // return sample1; + // } // Blend using the barycentric weights float4 result = sample1 * offsets.weights.x + @@ -199,46 +149,46 @@ inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, Samp // Main stochastic sampling function inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy, float distance) -{ - // Distance-based LOD with smooth transition +{ // Distance-based LOD with smooth transition float distanceFactor = saturate((distance - DISTANCE_LOD_THRESHOLD) / DISTANCE_LOD_TRANSITION); - // Early exit for distant terrain - avoid computing high quality samples that would be discarded - if (distanceFactor >= 0.999) + // Take first sample (always needed) + float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + + // Early exit for distant terrain - avoid expensive computation + if (distanceFactor >= 0.9) { - return StochasticSampleLow(rnd, mipLevel, tex, samp, uv, offsets, dx, dy); + return sample1; } - // Low sample (always computed for partial transition) - float4 lowSample = StochasticSampleLow(rnd, mipLevel, tex, samp, uv, offsets, dx, dy); - - // Only do expensive computation if we're going to use at least some of it - // Apply contrast to the initial blend weights (without height influence) - float3 blendWeights = pow(saturate(offsets.weights), HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE)); - - // Renormalize the weights - float totalWeight = blendWeights.x + blendWeights.y + blendWeights.z; - blendWeights /= totalWeight; - float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + // Take remaining samples for blending float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); - // Apply height-based weight adjustments - float3x3 rgbMatrix = float3x3(sample1.rgb, sample2.rgb, sample3.rgb); - float3 luminanceHeights = mul(rgbMatrix, LUMINANCE_WEIGHTS); + // Pre-compute contrast factor + float contrastFactor = HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE); + float3 blendWeights = pow(saturate(offsets.weights), contrastFactor); + + // Direct height calculation without matrix + float3 luminanceHeights = float3( + dot(sample1.rgb, LUMINANCE_WEIGHTS), + dot(sample2.rgb, LUMINANCE_WEIGHTS), + dot(sample3.rgb, LUMINANCE_WEIGHTS) + ); float3 alphaValues = float3(sample1.a, sample2.a, sample3.a); float3 alphaMask = step(0.001, alphaValues); float3 heights = lerp(luminanceHeights, alphaValues, alphaMask); + + // Combined weight calculation and normalization float3 weights = blendWeights * (1.0 + HEIGHT_INFLUENCE * heights); - // Blend samples with height-adjusted weights - float4 highQualitySample = sample1 * weights.x + sample2 * weights.y + sample3 * weights.z; + float rcpWeightSum = rcp(weights.x + weights.y + weights.z); + weights *= rcpWeightSum; - // Renormalize final result - float finalWeightSum = weights.x + weights.y + weights.z; - highQualitySample /= finalWeightSum; + // Direct blend without intermediate variable + float4 highQualitySample = sample1 * weights.x + sample2 * weights.y + sample3 * weights.z; - // Smooth transition between high quality and LOD samples - return lerp(highQualitySample, lowSample, distanceFactor); + // Smooth transition between high quality and single sample + return lerp(highQualitySample, sample1, distanceFactor); } diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 68ac1ccb59..920f4b750a 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1288,7 +1288,6 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) dx = ddx(input.TexCoord0.zw); dy = ddy(input.TexCoord0.zw); sharedOffset = ComputeStochasticOffsets(input.TexCoord0.zw); - sharedOffset2 = ComputeStochasticOffsets2(input.TexCoord0.zw); } # endif // Calculate mip levels for terrain variation when parallax is disabled From fcf61c35ad4e3bba21ac25718600d4e0309e6114 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Tue, 10 Jun 2025 20:45:04 +1000 Subject: [PATCH 42/53] update --- .../TerrainVariation/TerrainVariation.hlsli | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index 5354589c98..974fa496a6 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -156,16 +156,27 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); // Early exit for distant terrain - avoid expensive computation - if (distanceFactor >= 0.9) + if (distanceFactor >= 0.7) { - return sample1; + return sample1; // Miplevel at this distance should entirely hide any triangular artifacts. } // Take remaining samples for blending float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); - // Pre-compute contrast factor + // Early exit for mid-distance - skip expensive height blending + if (distanceFactor >= 0.4) + { + // Simple barycentric blend without height influence + float3 weights = saturate(offsets.weights); + float rcpWeightSum = rcp(weights.x + weights.y + weights.z); + weights *= rcpWeightSum; + float4 simpleSample = sample1 * weights.x + sample2 * weights.y + sample3 * weights.z; + return lerp(simpleSample, sample1, distanceFactor); + } + + // Full height-based blending for close terrain float contrastFactor = HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE); float3 blendWeights = pow(saturate(offsets.weights), contrastFactor); From 8197ae1e5dbe43b05f8a1e516c36a4dfaeaa236b Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Tue, 10 Jun 2025 21:42:54 +1000 Subject: [PATCH 43/53] EMAT Refactor part 1 --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 353 +++++++----------- 1 file changed, 132 insertions(+), 221 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index 93287992d0..5a8622bee8 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -71,13 +71,47 @@ namespace ExtendedMaterials mipLevel++; #endif - return mipLevel; - } + return mipLevel; } #if defined(LANDSCAPE) +# define HEIGHT_POWER 2 +# define HEIGHT_MULT 8 + + void ProcessTerrainHeightWeights(float heightBlend, float4 w1, float2 w2, float heights[6], inout float weights[6], out float totalHeight) + { + weights[0] = w1.x; + weights[1] = w1.y; + weights[2] = w1.z; + weights[3] = w1.w; + weights[4] = w2.x; + weights[5] = w2.y; + + totalHeight = 0; + [unroll] for (int i = 0; i < 6; i++) + { + totalHeight += heights[i] * weights[i]; + weights[i] *= pow(heightBlend, HEIGHT_MULT * heights[i]); + } + + [unroll] for (int i = 0; i < 6; i++) + { + weights[i] = min(100, pow(weights[i], heightBlend)); + } + + float wsum = 0; + [unroll] for (int i = 0; i < 6; i++) + { + wsum += weights[i]; + } + + float invwsum = rcp(wsum); + [unroll] for (int i = 0; i < 6; i++) + { + weights[i] *= invwsum; + } + } + # if defined(TRUE_PBR) -# define HEIGHT_POWER 2 -# define HEIGHT_MULT 8 float GetTerrainHeight(float screenNoise, PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, # if defined(TERRAIN_VARIATION) StochasticOffsets sharedOffset, float2 dx, float2 dy, @@ -85,99 +119,61 @@ namespace ExtendedMaterials out float weights[6]) { float heightBlend = 1 + blendFactor * HEIGHT_POWER; - weights[0] = w1.x; - weights[1] = w1.y; - weights[2] = w1.z; - weights[3] = w1.w; - weights[4] = w2.x; - weights[5] = w2.y; - float total = 0; + float heights[6] = { 0, 0, 0, 0, 0, 0 }; + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.0) { - float h; # if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexLandDisplacement0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); - + heights[0] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexLandDisplacement0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); # else - h = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); + heights[0] = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); # endif - total += h * weights[0]; - weights[0] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1HasDisplacement) != 0 && w1.y > 0.0) { - float h; # if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandDisplacement1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); + heights[1] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandDisplacement1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); # else - h = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); + heights[1] = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); # endif - total += h * weights[1]; - weights[1] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2HasDisplacement) != 0 && w1.z > 0.0) { - float h; # if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandDisplacement2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); + heights[2] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandDisplacement2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); # else - h = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); + heights[2] = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); # endif - total += h * weights[2]; - weights[2] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) { - float h; # if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); + heights[3] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); # else - h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); + heights[3] = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); # endif - total += h * weights[3]; - weights[3] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) { - float h; # if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); + heights[4] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); # else - h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); + heights[4] = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); # endif - total += h * weights[4]; - weights[4] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) { - float h; # if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); + heights[5] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); # else - h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); + heights[5] = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); # endif - total += h * weights[5]; - weights[5] *= pow(heightBlend, HEIGHT_MULT * h); } - [unroll] for (int i = 0; i < 6; i++) - { - weights[i] = min(100, pow(weights[i], heightBlend)); - } - float wsum = 0; - [unroll] for (int i = 0; i < 6; i++) - { - wsum += weights[i]; - } - float invwsum = rcp(wsum); - [unroll] for (i = 0; i < 6; i++) - { - weights[i] *= invwsum; - } - return total; - } + + float total; + ProcessTerrainHeightWeights(heightBlend, w1, w2, heights, weights, total); + return total; } # else -# define HEIGHT_POWER 2 -# define HEIGHT_MULT 8 float GetTerrainHeight(float screenNoise, PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, # if defined(TERRAIN_VARIATION) StochasticOffsets sharedOffset, float2 dx, float2 dy, @@ -185,124 +181,89 @@ namespace ExtendedMaterials out float weights[6]) { float heightBlend = 1 + blendFactor * HEIGHT_POWER; - weights[0] = w1.x; - weights[1] = w1.y; - weights[2] = w1.z; - weights[3] = w1.w; - weights[4] = w2.x; - weights[5] = w2.y; - float total = 0; + float heights[6] = { 0, 0, 0, 0, 0, 0 }; if (w1.x > 0.0) { - float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand0HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexLandTHDisp0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); + heights[0] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexLandTHDisp0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); # else - h = ScaleDisplacement(TexLandTHDisp0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); + heights[0] = ScaleDisplacement(TexLandTHDisp0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); # endif } else { # if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexColorSampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[0]); + heights[0] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexColorSampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[0]); # else - h = ScaleDisplacement(TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, params[0]); + heights[0] = ScaleDisplacement(TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, params[0]); # endif } - total += h * weights[0]; - weights[0] *= pow(heightBlend, HEIGHT_MULT * h); } if (w1.y > 0.0) { - float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandTHDisp1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); + heights[1] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandTHDisp1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); # else - h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); + heights[1] = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); # endif } else { # if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandColor2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[1]); + heights[1] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandColor2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[1]); # else - h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); + heights[1] = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); # endif } - total += h * weights[1]; - weights[1] *= pow(heightBlend, HEIGHT_MULT * h); } if (w1.z > 0.0) { - float h = 0.0; [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandTHDisp2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); + heights[2] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandTHDisp2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); # else - h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); + heights[2] = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); # endif } else { # if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandColor3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[2]); + heights[2] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandColor3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[2]); # else - h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); + heights[2] = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); # endif } - total += h * weights[2]; - weights[2] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0 && w1.w > 0.0) { - float h; # if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandTHDisp3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); + heights[3] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandTHDisp3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); # else - h = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); + heights[3] = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); # endif - total += h * weights[3]; - weights[3] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0 && w2.x > 0.0) { - float h; # if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandTHDisp4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); + heights[4] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandTHDisp4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); # else - h = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); + heights[4] = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); # endif - total += h * weights[4]; - weights[4] *= pow(heightBlend, HEIGHT_MULT * h); } [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0 && w2.y > 0.0) { - float h; # if defined(TERRAIN_VARIATION) - h = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandTHDisp5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); + heights[5] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandTHDisp5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); # else - h = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); + heights[5] = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); # endif - total += h * weights[5]; - weights[5] *= pow(heightBlend, HEIGHT_MULT * h); - } - [unroll] for (int i = 0; i < 6; i++) - { - weights[i] = min(100, pow(weights[i], heightBlend)); - } - float wsum = 0; - [unroll] for (int i = 0; i < 6; i++) - { - wsum += weights[i]; - } - float invwsum = rcp(wsum); - [unroll] for (i = 0; i < 6; i++) - { - weights[i] *= invwsum; } + + float total; + ProcessTerrainHeightWeights(heightBlend, w1, w2, heights, weights, total); return total; } # endif @@ -588,146 +549,95 @@ namespace ExtendedMaterials } return 1.0; } -#endif + #if defined(LANDSCAPE) && defined(TERRAIN_VARIATION) - // Overload for GetTerrainHeight WITHOUT StochasticOffsets (when enableTilingFix is false) # if defined(TRUE_PBR) float GetTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, out float weights[6]) { float heightBlend = 1 + blendFactor * HEIGHT_POWER; - weights[0] = w1.x; - weights[1] = w1.y; - weights[2] = w1.z; - weights[3] = w1.w; - weights[4] = w2.x; - weights[5] = w2.y; - float total = 0; - float screenNoise = 0; // Default noise value when no stochastic sampling + float heights[6] = { 0, 0, 0, 0, 0, 0 }; [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.0) { - float h = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); - total += h * weights[0]; - weights[0] *= pow(heightBlend, HEIGHT_MULT * h); + heights[0] = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1HasDisplacement) != 0 && w1.y > 0.0) { - float h = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); - total += h * weights[1]; - weights[1] *= pow(heightBlend, HEIGHT_MULT * h); + heights[1] = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2HasDisplacement) != 0 && w1.z > 0.0) { - float h = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); - total += h * weights[2]; - weights[2] *= pow(heightBlend, HEIGHT_MULT * h); + heights[2] = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) { - float h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); - total += h * weights[3]; - weights[3] *= pow(heightBlend, HEIGHT_MULT * h); + heights[3] = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) { - float h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); - total += h * weights[4]; - weights[4] *= pow(heightBlend, HEIGHT_MULT * h); + heights[4] = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); } [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) { - float h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); - total += h * weights[5]; - weights[5] *= pow(heightBlend, HEIGHT_MULT * h); - } - [unroll] for (int i = 0; i < 6; i++) - { - weights[i] = min(100, pow(weights[i], heightBlend)); - } - float wsum = 0; - [unroll] for (int i = 0; i < 6; i++) - { - wsum += weights[i]; - } - float invwsum = rcp(wsum); - [unroll] for (i = 0; i < 6; i++) - { - weights[i] *= invwsum; + heights[5] = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); } + + float total; + ProcessTerrainHeightWeights(heightBlend, w1, w2, heights, weights, total); return total; } # else float GetTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], DisplacementParams params[6], float blendFactor, float4 w1, float2 w2, out float weights[6]) { float heightBlend = 1 + blendFactor * HEIGHT_POWER; - weights[0] = w1.x; - weights[1] = w1.y; - weights[2] = w1.z; - weights[3] = w1.w; - weights[4] = w2.x; - weights[5] = w2.y; - float total = 0; - float screenNoise = 0; // Default noise value when no stochastic sampling - - if (w1.y > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) - { - h = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); - } - else - { - h = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); - } - total += h * weights[1]; - weights[1] *= pow(heightBlend, HEIGHT_MULT * h); - } - if (w1.z > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) - { - h = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); - } - else - { - h = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); - } - total += h * weights[2]; - weights[2] *= pow(heightBlend, HEIGHT_MULT * h); - } - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0 && w1.w > 0.0) - { - float h = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); - total += h * weights[3]; - weights[3] *= pow(heightBlend, HEIGHT_MULT * h); - } - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0 && w2.x > 0.0) - { - float h = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); - total += h * weights[4]; - weights[4] *= pow(heightBlend, HEIGHT_MULT * h); - } - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0 && w2.y > 0.0) - { - float h = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); - total += h * weights[5]; - weights[5] *= pow(heightBlend, HEIGHT_MULT * h); - } - [unroll] for (int i = 0; i < 6; i++) + float heights[6] = { 0, 0, 0, 0, 0, 0 }; + + if (w1.x > 0.0) { + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand0HasDisplacement) != 0) + { + heights[0] = ScaleDisplacement(TexLandTHDisp0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); + } + else + { + heights[0] = ScaleDisplacement(TexLandColor1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, params[0]); + } + } + if (w1.y > 0.0) { + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) + { + heights[1] = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); + } + else + { + heights[1] = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); + } + } + if (w1.z > 0.0) { + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) + { + heights[2] = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); + } + else + { + heights[2] = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); + } + } + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0 && w1.w > 0.0) { - weights[i] = min(100, pow(weights[i], heightBlend)); + heights[3] = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); } - float wsum = 0; - [unroll] for (int i = 0; i < 6; i++) + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0 && w2.x > 0.0) { - wsum += weights[i]; + heights[4] = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); } - float invwsum = rcp(wsum); - [unroll] for (i = 0; i < 6; i++) + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0 && w2.y > 0.0) { - weights[i] *= invwsum; + heights[5] = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); } + + float total; + ProcessTerrainHeightWeights(heightBlend, w1, w2, heights, weights, total); return total; } # endif @@ -871,6 +781,7 @@ namespace ExtendedMaterials weights[3] = input.LandBlendWeights1.w; weights[4] = input.LandBlendWeights2.x; weights[5] = input.LandBlendWeights2.y; +#endif // defined(LANDSCAPE) && defined(TERRAIN_VARIATION) pixelOffset = 0; return coords; @@ -914,4 +825,4 @@ namespace ExtendedMaterials return 1.0; } #endif // defined(LANDSCAPE) && defined(TERRAIN_VARIATION) -} \ No newline at end of file + } \ No newline at end of file From 5f891011c0edbad408e420deb8ee874fa8abcccc Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Fri, 13 Jun 2025 16:14:33 +1000 Subject: [PATCH 44/53] glint fix --- package/Shaders/Lighting.hlsl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 920f4b750a..e6c37b9789 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1881,6 +1881,9 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) normal = normalColor; # if defined(TRUE_PBR) rawRMAOS = TexRMAOSSampler.SampleBias(SampRMAOSSampler, diffuseUv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + if ((PBRFlags & PBR::Flags::Glint) != 0) { + glintParameters = MultiLayerParallaxData; + } # endif # endif From e30a7cccb93a69a712373da132d36f1d41f9d592 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Fri, 13 Jun 2025 16:36:04 +1000 Subject: [PATCH 45/53] Swap to Miplevel over distance --- .../TerrainVariation/TerrainVariation.hlsli | 30 +++++++------ package/Shaders/Lighting.hlsl | 42 +++++++++---------- 2 files changed, 33 insertions(+), 39 deletions(-) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index 974fa496a6..fae52f6b08 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -18,9 +18,6 @@ static const float WORLD_SCALE = 332.54; // Blending constants static const float3 DEFAULT_WEIGHTS = float3(0.33, 0.33, 0.34); static const float3 LUMINANCE_WEIGHTS = float3(0.2126, 0.7152, 0.0722); -// Distance-based LOD optimization constants -static const float DISTANCE_LOD_THRESHOLD = 1024.0; // Distance threshold for fast path optimization -static const float DISTANCE_LOD_TRANSITION = 300.0; // Transition zone width (units) // Hash constants static const float2 HASH_MULTIPLIER = float2(1271.5151, 3337.8237); static const float2 HASH_SINE_MULTIPLIER = float2(43758.5453, 28637.1369); @@ -148,35 +145,36 @@ inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, Samp } // Main stochastic sampling function -inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy, float distance) -{ // Distance-based LOD with smooth transition - float distanceFactor = saturate((distance - DISTANCE_LOD_THRESHOLD) / DISTANCE_LOD_TRANSITION); - +inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) +{ // Take first sample (always needed) float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); - // Early exit for distant terrain - avoid expensive computation - if (distanceFactor >= 0.7) + // Early exit for high mip levels - single sample is sufficient + if (mipLevel >= 4.0) { - return sample1; // Miplevel at this distance should entirely hide any triangular artifacts. + return sample1; } // Take remaining samples for blending float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); - // Early exit for mid-distance - skip expensive height blending - if (distanceFactor >= 0.4) + // Use mip level to determine blending complexity + float mipFactor = saturate(mipLevel / 4.0); + + // Early exit for mid-range mip levels - skip expensive height blending + if (mipLevel >= 2.0) { // Simple barycentric blend without height influence float3 weights = saturate(offsets.weights); float rcpWeightSum = rcp(weights.x + weights.y + weights.z); weights *= rcpWeightSum; float4 simpleSample = sample1 * weights.x + sample2 * weights.y + sample3 * weights.z; - return lerp(simpleSample, sample1, distanceFactor); + return lerp(simpleSample, sample1, mipFactor); } - // Full height-based blending for close terrain + // Full height-based blending for low mip levels (close terrain) float contrastFactor = HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE); float3 blendWeights = pow(saturate(offsets.weights), contrastFactor); @@ -198,8 +196,8 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler // Direct blend without intermediate variable float4 highQualitySample = sample1 * weights.x + sample2 * weights.y + sample3 * weights.z; - // Smooth transition between high quality and single sample - return lerp(highQualitySample, sample1, distanceFactor); + // Smooth transition between high quality and single sample based on mip level + return lerp(highQualitySample, sample1, mipFactor); } diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index e6c37b9789..8b4a679007 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1273,11 +1273,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TRUE_PBR) float4 blendedRMAOS = 0; # endif - - // Calculate view distance once for terrain optimizations - float distance = length(viewPosition); - - // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) + // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) # if defined(TERRAIN_VARIATION) bool useTerrainVariation = SharedData::terrainVariationSettings.enableTilingFix; float2 dx, dy; @@ -1394,7 +1390,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landColor1; [branch] if (useTerrainVariation) { - landColor1 = StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampColorSampler, uv, sharedOffset, dx, dy, distance); + landColor1 = StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampColorSampler, uv, sharedOffset, dx, dy); } else { @@ -1418,7 +1414,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landNormal1; [branch] if (useTerrainVariation) { - landNormal1 = StochasticEffect(screenNoise, mipLevels[0], TexNormalSampler, SampNormalSampler, uv, sharedOffset, dx, dy, distance); + landNormal1 = StochasticEffect(screenNoise, mipLevels[0], TexNormalSampler, SampNormalSampler, uv, sharedOffset, dx, dy); } else { @@ -1441,7 +1437,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS1 = StochasticSample3(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + landRMAOS1 = StochasticEffect(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy) * float4(PBRParams1.x, 1, 1, PBRParams1.z); } else { @@ -1475,7 +1471,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landColor2; [branch] if (useTerrainVariation) { - landColor2 = StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampLandColor2Sampler, uv, sharedOffset, dx, dy, distance); + landColor2 = StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampLandColor2Sampler, uv, sharedOffset, dx, dy); } else { @@ -1499,7 +1495,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landNormal2; [branch] if (useTerrainVariation) { - landNormal2 = StochasticEffect(screenNoise, mipLevels[1], TexLandNormal2Sampler, SampLandNormal2Sampler, uv, sharedOffset, dx, dy, distance); + landNormal2 = StochasticEffect(screenNoise, mipLevels[1], TexLandNormal2Sampler, SampLandNormal2Sampler, uv, sharedOffset, dx, dy); } else { @@ -1522,7 +1518,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS2 = StochasticSample3(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampLandRMAOS2Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); + landRMAOS2 = StochasticEffect(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampLandRMAOS2Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); } else { @@ -1555,7 +1551,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landColor3; [branch] if (useTerrainVariation) { - landColor3 = StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampLandColor3Sampler, uv, sharedOffset, dx, dy, distance); + landColor3 = StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampLandColor3Sampler, uv, sharedOffset, dx, dy); } else { @@ -1579,7 +1575,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landNormal3; [branch] if (useTerrainVariation) { - landNormal3 = StochasticEffect(screenNoise, mipLevels[2], TexLandNormal3Sampler, SampLandNormal3Sampler, uv, sharedOffset, dx, dy, distance); + landNormal3 = StochasticEffect(screenNoise, mipLevels[2], TexLandNormal3Sampler, SampLandNormal3Sampler, uv, sharedOffset, dx, dy); } else { @@ -1602,7 +1598,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS3 = StochasticSample3(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampLandRMAOS3Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); + landRMAOS3 = StochasticEffect(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampLandRMAOS3Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); } else { @@ -1635,7 +1631,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landColor4; [branch] if (useTerrainVariation) { - landColor4 = StochasticEffect(screenNoise, mipLevels[3], TexLandColor4Sampler, SampLandColor4Sampler, uv, sharedOffset, dx, dy, distance); + landColor4 = StochasticEffect(screenNoise, mipLevels[3], TexLandColor4Sampler, SampLandColor4Sampler, uv, sharedOffset, dx, dy); } else { @@ -1659,7 +1655,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landNormal4; [branch] if (useTerrainVariation) { - landNormal4 = StochasticEffect(screenNoise, mipLevels[3], TexLandNormal4Sampler, SampLandNormal4Sampler, uv, sharedOffset, dx, dy, distance); + landNormal4 = StochasticEffect(screenNoise, mipLevels[3], TexLandNormal4Sampler, SampLandNormal4Sampler, uv, sharedOffset, dx, dy); } else { @@ -1682,7 +1678,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS4 = StochasticSample3(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampLandRMAOS4Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); + landRMAOS4 = StochasticEffect(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampLandRMAOS4Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); } else { @@ -1715,7 +1711,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landColor5; [branch] if (useTerrainVariation) { - landColor5 = StochasticEffect(screenNoise, mipLevels[4], TexLandColor5Sampler, SampLandColor5Sampler, uv, sharedOffset, dx, dy, distance); + landColor5 = StochasticEffect(screenNoise, mipLevels[4], TexLandColor5Sampler, SampLandColor5Sampler, uv, sharedOffset, dx, dy); } else { @@ -1739,7 +1735,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landNormal5; [branch] if (useTerrainVariation) { - landNormal5 = StochasticEffect(screenNoise, mipLevels[4], TexLandNormal5Sampler, SampLandNormal5Sampler, uv, sharedOffset, dx, dy, distance); + landNormal5 = StochasticEffect(screenNoise, mipLevels[4], TexLandNormal5Sampler, SampLandNormal5Sampler, uv, sharedOffset, dx, dy); } else { @@ -1763,7 +1759,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS5 = StochasticSample3(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampLandRMAOS5Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); + landRMAOS5 = StochasticEffect(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampLandRMAOS5Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); } else { @@ -1796,7 +1792,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landColor6; [branch] if (useTerrainVariation) { - landColor6 = StochasticEffect(screenNoise, mipLevels[5], TexLandColor6Sampler, SampLandColor6Sampler, uv, sharedOffset, dx, dy, distance); + landColor6 = StochasticEffect(screenNoise, mipLevels[5], TexLandColor6Sampler, SampLandColor6Sampler, uv, sharedOffset, dx, dy); } else { @@ -1820,7 +1816,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landNormal6; [branch] if (useTerrainVariation) { - landNormal6 = StochasticEffect(screenNoise, mipLevels[5], TexLandNormal6Sampler, SampLandNormal6Sampler, uv, sharedOffset, dx, dy, distance); + landNormal6 = StochasticEffect(screenNoise, mipLevels[5], TexLandNormal6Sampler, SampLandNormal6Sampler, uv, sharedOffset, dx, dy); } else { @@ -1843,7 +1839,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS6 = StochasticSample3(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampLandRMAOS6Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); + landRMAOS6 = StochasticEffect(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampLandRMAOS6Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); } else { From 5ca8b95614ad17e8d310f3e747caff6d2469c439 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Fri, 13 Jun 2025 19:33:28 +1000 Subject: [PATCH 46/53] Miplevel final --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 30 ++++----- .../TerrainVariation/TerrainVariation.hlsli | 67 +++++++++---------- package/Shaders/Lighting.hlsl | 12 ++-- 3 files changed, 52 insertions(+), 57 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index 5a8622bee8..859f1b7824 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -124,7 +124,7 @@ namespace ExtendedMaterials [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.0) { # if defined(TERRAIN_VARIATION) - heights[0] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexLandDisplacement0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); + heights[0] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[0], TexLandDisplacement0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); # else heights[0] = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); # endif @@ -132,7 +132,7 @@ namespace ExtendedMaterials [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1HasDisplacement) != 0 && w1.y > 0.0) { # if defined(TERRAIN_VARIATION) - heights[1] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandDisplacement1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); + heights[1] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[1], TexLandDisplacement1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); # else heights[1] = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); # endif @@ -140,7 +140,7 @@ namespace ExtendedMaterials [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2HasDisplacement) != 0 && w1.z > 0.0) { # if defined(TERRAIN_VARIATION) - heights[2] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandDisplacement2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); + heights[2] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[2], TexLandDisplacement2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); # else heights[2] = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); # endif @@ -148,7 +148,7 @@ namespace ExtendedMaterials [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) { # if defined(TERRAIN_VARIATION) - heights[3] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); + heights[3] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); # else heights[3] = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); # endif @@ -156,7 +156,7 @@ namespace ExtendedMaterials [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) { # if defined(TERRAIN_VARIATION) - heights[4] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); + heights[4] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); # else heights[4] = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); # endif @@ -164,7 +164,7 @@ namespace ExtendedMaterials [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) { # if defined(TERRAIN_VARIATION) - heights[5] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); + heights[5] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); # else heights[5] = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); # endif @@ -187,7 +187,7 @@ namespace ExtendedMaterials [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand0HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - heights[0] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexLandTHDisp0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); + heights[0] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[0], TexLandTHDisp0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); # else heights[0] = ScaleDisplacement(TexLandTHDisp0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); # endif @@ -195,7 +195,7 @@ namespace ExtendedMaterials else { # if defined(TERRAIN_VARIATION) - heights[0] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[0], TexColorSampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[0]); + heights[0] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[0], TexColorSampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[0]); # else heights[0] = ScaleDisplacement(TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, params[0]); # endif @@ -205,7 +205,7 @@ namespace ExtendedMaterials [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - heights[1] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandTHDisp1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); + heights[1] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[1], TexLandTHDisp1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); # else heights[1] = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); # endif @@ -213,7 +213,7 @@ namespace ExtendedMaterials else { # if defined(TERRAIN_VARIATION) - heights[1] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[1], TexLandColor2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[1]); + heights[1] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[1], TexLandColor2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[1]); # else heights[1] = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); # endif @@ -223,7 +223,7 @@ namespace ExtendedMaterials [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - heights[2] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandTHDisp2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); + heights[2] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[2], TexLandTHDisp2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); # else heights[2] = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); # endif @@ -231,7 +231,7 @@ namespace ExtendedMaterials else { # if defined(TERRAIN_VARIATION) - heights[2] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[2], TexLandColor3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[2]); + heights[2] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[2], TexLandColor3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[2]); # else heights[2] = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); # endif @@ -240,7 +240,7 @@ namespace ExtendedMaterials [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0 && w1.w > 0.0) { # if defined(TERRAIN_VARIATION) - heights[3] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[3], TexLandTHDisp3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); + heights[3] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[3], TexLandTHDisp3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); # else heights[3] = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); # endif @@ -248,7 +248,7 @@ namespace ExtendedMaterials [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0 && w2.x > 0.0) { # if defined(TERRAIN_VARIATION) - heights[4] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[4], TexLandTHDisp4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); + heights[4] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[4], TexLandTHDisp4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); # else heights[4] = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); # endif @@ -256,7 +256,7 @@ namespace ExtendedMaterials [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0 && w2.y > 0.0) { # if defined(TERRAIN_VARIATION) - heights[5] = ScaleDisplacement(StochasticSample3(screenNoise, mipLevels[5], TexLandTHDisp5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); + heights[5] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[5], TexLandTHDisp5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); # else heights[5] = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); # endif diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index fae52f6b08..36e1e69e2a 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -98,29 +98,10 @@ inline StochasticOffsets ComputeStochasticOffsetsLOD(float2 landscapeUV) // --------------------- STOCHASTIC SAMPLING FUNCTIONS --------------------- // -// Same as StochasticEffect but no height/luminescence influence, so much cheaper but worse quality, doesn't matter for the use case. -inline float4 StochasticSample3(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) +inline float3 NormalizeWeights(float3 weights) { - // // Distance-based LOD with smooth transition - // float distanceFactor = saturate((distance - DISTANCE_LOD_THRESHOLD) / DISTANCE_LOD_TRANSITION); - - // Take 3 samples always - float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); - float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); - float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); - - // // Early exit for distant terrain - return single sample with cheap offset - // if (distanceFactor >= 0.9) - // { - // return sample1; - // } - - // Blend using the barycentric weights - float4 result = sample1 * offsets.weights.x + - sample2 * offsets.weights.y + - sample3 * offsets.weights.z; - - return result; + float rcpWeightSum = rcp(weights.x + weights.y + weights.z); + return weights * rcpWeightSum; } // Stochastic sampling function for Terrain LOD & LOD Mask. @@ -163,17 +144,6 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler // Use mip level to determine blending complexity float mipFactor = saturate(mipLevel / 4.0); - // Early exit for mid-range mip levels - skip expensive height blending - if (mipLevel >= 2.0) - { - // Simple barycentric blend without height influence - float3 weights = saturate(offsets.weights); - float rcpWeightSum = rcp(weights.x + weights.y + weights.z); - weights *= rcpWeightSum; - float4 simpleSample = sample1 * weights.x + sample2 * weights.y + sample3 * weights.z; - return lerp(simpleSample, sample1, mipFactor); - } - // Full height-based blending for low mip levels (close terrain) float contrastFactor = HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE); float3 blendWeights = pow(saturate(offsets.weights), contrastFactor); @@ -189,9 +159,7 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler float3 heights = lerp(luminanceHeights, alphaValues, alphaMask); // Combined weight calculation and normalization - float3 weights = blendWeights * (1.0 + HEIGHT_INFLUENCE * heights); - float rcpWeightSum = rcp(weights.x + weights.y + weights.z); - weights *= rcpWeightSum; + float3 weights = NormalizeWeights(blendWeights * (1.0 + HEIGHT_INFLUENCE * heights)); // Direct blend without intermediate variable float4 highQualitySample = sample1 * weights.x + sample2 * weights.y + sample3 * weights.z; @@ -200,5 +168,32 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler return lerp(highQualitySample, sample1, mipFactor); } +// Stochastic sampling function without height blending for better performance +inline float4 StochasticEffectNoHeight(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) +{ + // Take first sample (always needed) + float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + + // Early exit for high mip levels - single sample is sufficient + if (mipLevel >= 4.0) + { + return sample1; + } + + // Take remaining samples for blending + float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); + float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); + + // Use mip level to determine blending complexity + float mipFactor = saturate(mipLevel / 4.0); + + // Simple barycentric blend without height influence + float3 weights = NormalizeWeights(saturate(offsets.weights)); + float4 blendedSample = sample1 * weights.x + sample2 * weights.y + sample3 * weights.z; + + // Smooth transition between blended and single sample based on mip level + return lerp(blendedSample, sample1, mipFactor); +} + #endif // TERRAIN_VARIATION_HLSLI \ No newline at end of file diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 8b4a679007..ec05b5678a 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1437,7 +1437,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS1 = StochasticEffect(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + landRMAOS1 = StochasticEffectNoHeight(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy) * float4(PBRParams1.x, 1, 1, PBRParams1.z); } else { @@ -1518,7 +1518,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS2 = StochasticEffect(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampLandRMAOS2Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); + landRMAOS2 = StochasticEffectNoHeight(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampLandRMAOS2Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); } else { @@ -1598,7 +1598,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS3 = StochasticEffect(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampLandRMAOS3Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); + landRMAOS3 = StochasticEffectNoHeight(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampLandRMAOS3Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); } else { @@ -1678,7 +1678,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS4 = StochasticEffect(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampLandRMAOS4Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); + landRMAOS4 = StochasticEffectNoHeight(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampLandRMAOS4Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); } else { @@ -1759,7 +1759,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS5 = StochasticEffect(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampLandRMAOS5Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); + landRMAOS5 = StochasticEffectNoHeight(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampLandRMAOS5Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); } else { @@ -1839,7 +1839,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS6 = StochasticEffect(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampLandRMAOS6Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); + landRMAOS6 = StochasticEffectNoHeight(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampLandRMAOS6Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); } else { From 03ff75cbe44deaf33a4b173823a399e436de6118 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Fri, 13 Jun 2025 20:12:23 +1000 Subject: [PATCH 47/53] perf updates --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 25 +++--- package/Shaders/Lighting.hlsl | 86 ++++++++++--------- 2 files changed, 58 insertions(+), 53 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index 859f1b7824..449c2c2441 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -121,7 +121,7 @@ namespace ExtendedMaterials float heightBlend = 1 + blendFactor * HEIGHT_POWER; float heights[6] = { 0, 0, 0, 0, 0, 0 }; - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.0) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.01) { # if defined(TERRAIN_VARIATION) heights[0] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[0], TexLandDisplacement0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); @@ -129,7 +129,7 @@ namespace ExtendedMaterials heights[0] = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); # endif } - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1HasDisplacement) != 0 && w1.y > 0.0) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1HasDisplacement) != 0 && w1.y > 0.01) { # if defined(TERRAIN_VARIATION) heights[1] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[1], TexLandDisplacement1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); @@ -137,7 +137,7 @@ namespace ExtendedMaterials heights[1] = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); # endif } - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2HasDisplacement) != 0 && w1.z > 0.0) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2HasDisplacement) != 0 && w1.z > 0.01) { # if defined(TERRAIN_VARIATION) heights[2] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[2], TexLandDisplacement2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); @@ -145,7 +145,7 @@ namespace ExtendedMaterials heights[2] = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); # endif } - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.01) { # if defined(TERRAIN_VARIATION) heights[3] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); @@ -153,7 +153,7 @@ namespace ExtendedMaterials heights[3] = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); # endif } - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.01) { # if defined(TERRAIN_VARIATION) heights[4] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); @@ -161,7 +161,7 @@ namespace ExtendedMaterials heights[4] = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); # endif } - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.01) { # if defined(TERRAIN_VARIATION) heights[5] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); @@ -182,8 +182,7 @@ namespace ExtendedMaterials { float heightBlend = 1 + blendFactor * HEIGHT_POWER; float heights[6] = { 0, 0, 0, 0, 0, 0 }; - - if (w1.x > 0.0) { + if (w1.x > 0.01) { [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand0HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) @@ -201,7 +200,7 @@ namespace ExtendedMaterials # endif } } - if (w1.y > 0.0) { + if (w1.y > 0.01) { [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) @@ -219,7 +218,7 @@ namespace ExtendedMaterials # endif } } - if (w1.z > 0.0) { + if (w1.z > 0.01) { [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) @@ -237,7 +236,7 @@ namespace ExtendedMaterials # endif } } - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0 && w1.w > 0.0) + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0 && w1.w > 0.01) { # if defined(TERRAIN_VARIATION) heights[3] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[3], TexLandTHDisp3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); @@ -245,7 +244,7 @@ namespace ExtendedMaterials heights[3] = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); # endif } - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0 && w2.x > 0.0) + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0 && w2.x > 0.01) { # if defined(TERRAIN_VARIATION) heights[4] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[4], TexLandTHDisp4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); @@ -253,7 +252,7 @@ namespace ExtendedMaterials heights[4] = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); # endif } - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0 && w2.y > 0.0) + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0 && w2.y > 0.01) { # if defined(TERRAIN_VARIATION) heights[5] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[5], TexLandTHDisp5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index ec05b5678a..90940b2972 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1250,7 +1250,6 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # else bool useSnowDecalSpecular = false; # endif // defined(SPARKLE) || !defined(PROJECTED_UV) - float2 diffuseUv = uv; # if defined(SPARKLE) @@ -1258,6 +1257,12 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # endif // SPARKLE # if defined(LANDSCAPE) // Normalize blend weights + // Pre-calculate derivatives for UV coordinates (used by terrain variation) + float2 dxUV = ddx(uv); + float2 dyUV = ddy(uv); + float2 dxTexCoord = ddx(input.TexCoord0.zw); + float2 dyTexCoord = ddy(input.TexCoord0.zw); + float totalWeight = input.LandBlendWeights1.x + input.LandBlendWeights1.y + input.LandBlendWeights1.z + input.LandBlendWeights1.w + input.LandBlendWeights2.x + input.LandBlendWeights2.y; if (totalWeight > 0.0) { @@ -1273,16 +1278,14 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TRUE_PBR) float4 blendedRMAOS = 0; # endif + // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) # if defined(TERRAIN_VARIATION) bool useTerrainVariation = SharedData::terrainVariationSettings.enableTilingFix; - float2 dx, dy; StochasticOffsets sharedOffset; StochasticOffsets sharedOffset2; [branch] if (useTerrainVariation) { - dx = ddx(input.TexCoord0.zw); - dy = ddy(input.TexCoord0.zw); sharedOffset = ComputeStochasticOffsets(input.TexCoord0.zw); } # endif @@ -1324,7 +1327,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, sharedOffset, dx, dy, pixelOffset, weights); + uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, sharedOffset, dxTexCoord, dyTexCoord, pixelOffset, weights); } else { @@ -1346,7 +1349,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); + sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dxTexCoord, dyTexCoord, weights); } else { @@ -1380,9 +1383,8 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # endif # endif -# if defined(LANDSCAPE) - // Layer 1 (LandBlendWeights1.x) - if (input.LandBlendWeights1.x > 0.0) { +# if defined(LANDSCAPE) // Layer 1 (LandBlendWeights1.x) + if (input.LandBlendWeights1.x > 0.01) { float weight = input.LandBlendWeights1.x; // Sample diffuse texture for layer 1 @@ -1390,7 +1392,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landColor1; [branch] if (useTerrainVariation) { - landColor1 = StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampColorSampler, uv, sharedOffset, dx, dy); + landColor1 = StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampColorSampler, uv, sharedOffset, dxUV, dyUV); } else { @@ -1414,7 +1416,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landNormal1; [branch] if (useTerrainVariation) { - landNormal1 = StochasticEffect(screenNoise, mipLevels[0], TexNormalSampler, SampNormalSampler, uv, sharedOffset, dx, dy); + landNormal1 = StochasticEffect(screenNoise, mipLevels[0], TexNormalSampler, SampNormalSampler, uv, sharedOffset, dxUV, dyUV); } else { @@ -1437,7 +1439,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS1 = StochasticEffectNoHeight(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + landRMAOS1 = StochasticEffectNoHeight(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dxUV, dyUV) * float4(PBRParams1.x, 1, 1, PBRParams1.z); } else { @@ -1463,7 +1465,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) } // Layer 2 (LandBlendWeights1.y) - if (input.LandBlendWeights1.y > 0.0) { + if (input.LandBlendWeights1.y > 0.01) { float weight = input.LandBlendWeights1.y; // Sample diffuse texture for layer 2 @@ -1471,7 +1473,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landColor2; [branch] if (useTerrainVariation) { - landColor2 = StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampLandColor2Sampler, uv, sharedOffset, dx, dy); + landColor2 = StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampLandColor2Sampler, uv, sharedOffset, dxUV, dyUV); } else { @@ -1495,7 +1497,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landNormal2; [branch] if (useTerrainVariation) { - landNormal2 = StochasticEffect(screenNoise, mipLevels[1], TexLandNormal2Sampler, SampLandNormal2Sampler, uv, sharedOffset, dx, dy); + landNormal2 = StochasticEffect(screenNoise, mipLevels[1], TexLandNormal2Sampler, SampLandNormal2Sampler, uv, sharedOffset, dxUV, dyUV); } else { @@ -1518,7 +1520,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS2 = StochasticEffectNoHeight(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampLandRMAOS2Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); + landRMAOS2 = StochasticEffectNoHeight(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampLandRMAOS2Sampler, uv, sharedOffset, dxUV, dyUV) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); } else { @@ -1544,14 +1546,14 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) } // Layer 3 (LandBlendWeights1.z) - if (input.LandBlendWeights1.z > 0.0) { + if (input.LandBlendWeights1.z > 0.01) { float weight = input.LandBlendWeights1.z; // Sample diffuse texture for layer 3 # if defined(TERRAIN_VARIATION) float4 landColor3; [branch] if (useTerrainVariation) { - landColor3 = StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampLandColor3Sampler, uv, sharedOffset, dx, dy); + landColor3 = StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampLandColor3Sampler, uv, sharedOffset, dxUV, dyUV); } else { @@ -1575,7 +1577,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landNormal3; [branch] if (useTerrainVariation) { - landNormal3 = StochasticEffect(screenNoise, mipLevels[2], TexLandNormal3Sampler, SampLandNormal3Sampler, uv, sharedOffset, dx, dy); + landNormal3 = StochasticEffect(screenNoise, mipLevels[2], TexLandNormal3Sampler, SampLandNormal3Sampler, uv, sharedOffset, dxUV, dyUV); } else { @@ -1598,7 +1600,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS3 = StochasticEffectNoHeight(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampLandRMAOS3Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); + landRMAOS3 = StochasticEffectNoHeight(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampLandRMAOS3Sampler, uv, sharedOffset, dxUV, dyUV) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); } else { @@ -1622,8 +1624,9 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) blendedNormalRGB += landNormalRGB3 * weight; blendedNormalAlpha += landNormalAlpha3 * weight; } + // Layer 4 (LandBlendWeights1.w) - if (input.LandBlendWeights1.w > 0.0) { + if (input.LandBlendWeights1.w > 0.01) { float weight = input.LandBlendWeights1.w; // Sample diffuse texture for layer 4 @@ -1631,7 +1634,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landColor4; [branch] if (useTerrainVariation) { - landColor4 = StochasticEffect(screenNoise, mipLevels[3], TexLandColor4Sampler, SampLandColor4Sampler, uv, sharedOffset, dx, dy); + landColor4 = StochasticEffect(screenNoise, mipLevels[3], TexLandColor4Sampler, SampLandColor4Sampler, uv, sharedOffset, dxUV, dyUV); } else { @@ -1655,7 +1658,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landNormal4; [branch] if (useTerrainVariation) { - landNormal4 = StochasticEffect(screenNoise, mipLevels[3], TexLandNormal4Sampler, SampLandNormal4Sampler, uv, sharedOffset, dx, dy); + landNormal4 = StochasticEffect(screenNoise, mipLevels[3], TexLandNormal4Sampler, SampLandNormal4Sampler, uv, sharedOffset, dxUV, dyUV); } else { @@ -1678,7 +1681,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS4 = StochasticEffectNoHeight(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampLandRMAOS4Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); + landRMAOS4 = StochasticEffectNoHeight(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampLandRMAOS4Sampler, uv, sharedOffset, dxUV, dyUV) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); } else { @@ -1704,14 +1707,14 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) } // Layer 5 (LandBlendWeights2.x) - if (input.LandBlendWeights2.x > 0.0) { + if (input.LandBlendWeights2.x > 0.01) { float weight = input.LandBlendWeights2.x; // Sample diffuse texture for layer 5 # if defined(TERRAIN_VARIATION) float4 landColor5; [branch] if (useTerrainVariation) { - landColor5 = StochasticEffect(screenNoise, mipLevels[4], TexLandColor5Sampler, SampLandColor5Sampler, uv, sharedOffset, dx, dy); + landColor5 = StochasticEffect(screenNoise, mipLevels[4], TexLandColor5Sampler, SampLandColor5Sampler, uv, sharedOffset, dxUV, dyUV); } else { @@ -1735,7 +1738,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landNormal5; [branch] if (useTerrainVariation) { - landNormal5 = StochasticEffect(screenNoise, mipLevels[4], TexLandNormal5Sampler, SampLandNormal5Sampler, uv, sharedOffset, dx, dy); + landNormal5 = StochasticEffect(screenNoise, mipLevels[4], TexLandNormal5Sampler, SampLandNormal5Sampler, uv, sharedOffset, dxUV, dyUV); } else { @@ -1759,7 +1762,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS5 = StochasticEffectNoHeight(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampLandRMAOS5Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); + landRMAOS5 = StochasticEffectNoHeight(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampLandRMAOS5Sampler, uv, sharedOffset, dxUV, dyUV) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); } else { @@ -1784,7 +1787,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) blendedNormalAlpha += landNormalAlpha5 * weight; } // Layer 6 (LandBlendWeights2.y) - if (input.LandBlendWeights2.y > 0.0) { + if (input.LandBlendWeights2.y > 0.01) { float weight = input.LandBlendWeights2.y; // Sample layer 6 textures @@ -1792,7 +1795,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landColor6; [branch] if (useTerrainVariation) { - landColor6 = StochasticEffect(screenNoise, mipLevels[5], TexLandColor6Sampler, SampLandColor6Sampler, uv, sharedOffset, dx, dy); + landColor6 = StochasticEffect(screenNoise, mipLevels[5], TexLandColor6Sampler, SampLandColor6Sampler, uv, sharedOffset, dxUV, dyUV); } else { @@ -1816,7 +1819,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) float4 landNormal6; [branch] if (useTerrainVariation) { - landNormal6 = StochasticEffect(screenNoise, mipLevels[5], TexLandNormal6Sampler, SampLandNormal6Sampler, uv, sharedOffset, dx, dy); + landNormal6 = StochasticEffect(screenNoise, mipLevels[5], TexLandNormal6Sampler, SampLandNormal6Sampler, uv, sharedOffset, dxUV, dyUV); } else { @@ -1839,7 +1842,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS6 = StochasticEffectNoHeight(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampLandRMAOS6Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); + landRMAOS6 = StochasticEffectNoHeight(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampLandRMAOS6Sampler, uv, sharedOffset, dxUV, dyUV) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); } else { @@ -1890,10 +1893,12 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) // First apply terrain variation if enabled # if defined(TERRAIN_VARIATION) if (SharedData::terrainVariationSettings.enableLODTerrainTilingFix) { - float2 dx = ddx(uv); - float2 dy = ddy(uv); + // Pre-calculate derivatives for LODLANDSCAPE terrain variation + float2 dxUV = ddx(uv); + float2 dyUV = ddy(uv); + StochasticOffsets lodOffset = ComputeStochasticOffsetsLOD(uv); - float4 lodStochasticColor = StochasticSampleLOD(screenNoise, 0, TexColorSampler, SampColorSampler, uv, lodOffset, dx, dy); + float4 lodStochasticColor = StochasticSampleLOD(screenNoise, 0, TexColorSampler, SampColorSampler, uv, lodOffset, dxUV, dyUV); // Apply the stochastic result directly baseColor.xyz = Color::Diffuse(lodStochasticColor.rgb); @@ -1975,10 +1980,11 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) if (SharedData::terrainVariationSettings.enableLODTerrainTilingFix) { // Apply stochastic sampling to LOD_LAND_BLEND color texture float2 blendColorUV = input.TexCoord0.zw; - float2 dx = ddx(blendColorUV); - float2 dy = ddy(blendColorUV); + float2 dxTexCoord = ddx(blendColorUV); + float2 dyTexCoord = ddy(blendColorUV); + StochasticOffsets lodBlendColorOffset = ComputeStochasticOffsetsLOD(blendColorUV); - lodLandColor = StochasticSampleLOD(screenNoise, 0, TexLandLodBlend1Sampler, SampLandLodBlend1Sampler, blendColorUV, lodBlendColorOffset, dx, dy); + lodLandColor = StochasticSampleLOD(screenNoise, 0, TexLandLodBlend1Sampler, SampLandLodBlend1Sampler, blendColorUV, lodBlendColorOffset, dxTexCoord, dyTexCoord); } else { lodLandColor = TexLandLodBlend1Sampler.Sample(SampLandLodBlend1Sampler, input.TexCoord0.zw); } @@ -2417,9 +2423,9 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) [branch] if (useTerrainVariation) { float weights[6]; - sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); + sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dxTexCoord, dyTexCoord, weights); - parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dx, dy); + parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dxUV, dyUV); } else { From 57882188776f55adfc45108f3d3b028fd394aaa0 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Mon, 16 Jun 2025 22:57:57 +1000 Subject: [PATCH 48/53] Weight aware blend & sample gathering --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 45 ++++---- .../TerrainVariation/TerrainVariation.hlsli | 109 ++++++++---------- package/Shaders/Lighting.hlsl | 101 ++++++++-------- 3 files changed, 117 insertions(+), 138 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index 449c2c2441..ef5aafd0fc 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -120,11 +120,10 @@ namespace ExtendedMaterials { float heightBlend = 1 + blendFactor * HEIGHT_POWER; float heights[6] = { 0, 0, 0, 0, 0, 0 }; - - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.01) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.01) { # if defined(TERRAIN_VARIATION) - heights[0] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[0], TexLandDisplacement0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); + heights[0] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandDisplacement0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[0], 0.0, w1.x, float4(0.5, 0.5, 0.5, 1.0)).x, params[0]); # else heights[0] = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); # endif @@ -132,7 +131,7 @@ namespace ExtendedMaterials [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1HasDisplacement) != 0 && w1.y > 0.01) { # if defined(TERRAIN_VARIATION) - heights[1] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[1], TexLandDisplacement1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); + heights[1] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandDisplacement1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[1], 0.0, w1.y, float4(0.5, 0.5, 0.5, 1.0)).x, params[1]); # else heights[1] = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); # endif @@ -140,7 +139,7 @@ namespace ExtendedMaterials [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2HasDisplacement) != 0 && w1.z > 0.01) { # if defined(TERRAIN_VARIATION) - heights[2] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[2], TexLandDisplacement2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); + heights[2] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandDisplacement2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[2], 0.0, w1.z, float4(0.5, 0.5, 0.5, 1.0)).x, params[2]); # else heights[2] = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); # endif @@ -148,7 +147,7 @@ namespace ExtendedMaterials [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.01) { # if defined(TERRAIN_VARIATION) - heights[3] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); + heights[3] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[3], 0.0, w1.w, float4(0.5, 0.5, 0.5, 1.0)).x, params[3]); # else heights[3] = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); # endif @@ -156,7 +155,7 @@ namespace ExtendedMaterials [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.01) { # if defined(TERRAIN_VARIATION) - heights[4] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); + heights[4] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[4], 0.0, w2.x, float4(0.5, 0.5, 0.5, 1.0)).x, params[4]); # else heights[4] = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); # endif @@ -164,7 +163,7 @@ namespace ExtendedMaterials [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.01) { # if defined(TERRAIN_VARIATION) - heights[5] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); + heights[5] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[5], 0.0, w2.y, float4(0.5, 0.5, 0.5, 1.0)).x, params[5]); # else heights[5] = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); # endif @@ -181,12 +180,11 @@ namespace ExtendedMaterials out float weights[6]) { float heightBlend = 1 + blendFactor * HEIGHT_POWER; - float heights[6] = { 0, 0, 0, 0, 0, 0 }; - if (w1.x > 0.01) { + float heights[6] = { 0, 0, 0, 0, 0, 0 }; if (w1.x > 0.01) { [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand0HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - heights[0] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[0], TexLandTHDisp0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); + heights[0] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandTHDisp0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[0], 0.0, w1.x, float4(0.5, 0.5, 0.5, 1.0)).x, params[0]); # else heights[0] = ScaleDisplacement(TexLandTHDisp0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); # endif @@ -194,17 +192,16 @@ namespace ExtendedMaterials else { # if defined(TERRAIN_VARIATION) - heights[0] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[0], TexColorSampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[0]); + heights[0] = ScaleDisplacement(StochasticEffectNoHeight(2, TexColorSampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[0], 0.0, w1.x, float4(0.5, 0.5, 0.5, 1.0)).w, params[0]); # else heights[0] = ScaleDisplacement(TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, params[0]); # endif } - } - if (w1.y > 0.01) { + } if (w1.y > 0.01) { [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - heights[1] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[1], TexLandTHDisp1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); + heights[1] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandTHDisp1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[1], 0.0, w1.y, float4(0.5, 0.5, 0.5, 1.0)).x, params[1]); # else heights[1] = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); # endif @@ -212,17 +209,16 @@ namespace ExtendedMaterials else { # if defined(TERRAIN_VARIATION) - heights[1] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[1], TexLandColor2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[1]); + heights[1] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandColor2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[1], 0.0, w1.y, float4(0.5, 0.5, 0.5, 1.0)).w, params[1]); # else heights[1] = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); # endif } - } - if (w1.z > 0.01) { + } if (w1.z > 0.01) { [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - heights[2] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[2], TexLandTHDisp2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); + heights[2] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandTHDisp2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[2], 0.0, w1.z, float4(0.5, 0.5, 0.5, 1.0)).x, params[2]); # else heights[2] = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); # endif @@ -230,16 +226,15 @@ namespace ExtendedMaterials else { # if defined(TERRAIN_VARIATION) - heights[2] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[2], TexLandColor3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[2]); + heights[2] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandColor3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[2], 0.0, w1.z, float4(0.5, 0.5, 0.5, 1.0)).w, params[2]); # else heights[2] = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); # endif } - } - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0 && w1.w > 0.01) + } [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0 && w1.w > 0.01) { # if defined(TERRAIN_VARIATION) - heights[3] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[3], TexLandTHDisp3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); + heights[3] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandTHDisp3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[3], 0.0, w1.w, float4(0.5, 0.5, 0.5, 1.0)).x, params[3]); # else heights[3] = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); # endif @@ -247,7 +242,7 @@ namespace ExtendedMaterials [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0 && w2.x > 0.01) { # if defined(TERRAIN_VARIATION) - heights[4] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[4], TexLandTHDisp4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); + heights[4] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandTHDisp4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[4], 0.0, w2.x, float4(0.5, 0.5, 0.5, 1.0)).x, params[4]); # else heights[4] = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); # endif @@ -255,7 +250,7 @@ namespace ExtendedMaterials [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0 && w2.y > 0.01) { # if defined(TERRAIN_VARIATION) - heights[5] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[5], TexLandTHDisp5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); + heights[5] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandTHDisp5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[5], 0.0, w2.y, float4(0.5, 0.5, 0.5, 1.0)).x, params[5]); # else heights[5] = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); # endif diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index 36e1e69e2a..637778a1f4 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -22,6 +22,14 @@ static const float3 LUMINANCE_WEIGHTS = float3(0.2126, 0.7152, 0.0722); static const float2 HASH_MULTIPLIER = float2(1271.5151, 3337.8237); static const float2 HASH_SINE_MULTIPLIER = float2(43758.5453, 28637.1369); +// Early termination thresholds for progressive sampling - optimized for GPU performance +static const float WEIGHT_THRESHOLD_SKIP = 0.005; // Skip layer entirely if weight is below this +static const float WEIGHT_THRESHOLD_MINIMAL = 0.02; // Use minimal sampling if weight is below this + +// Default values for low-contribution layers +static const float4 DEFAULT_NORMAL = float4(0.5, 0.5, 1.0, 1.0); // Default normal map (pointing up) +static const float4 DEFAULT_RMAOS = float4(1.0, 0.0, 1.0, 0.0); // Default RMAOS (non-metallic, smooth) + // Structure to hold stochastic sampling offsets and weights struct StochasticOffsets { @@ -125,75 +133,56 @@ inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, Samp return lerp(sample2, sample1, 0.65); } -// Main stochastic sampling function -inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) +// Unified stochastic sampling function with weight-aware optimization +inline float4 StochasticEffect(uint blendingMode, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float mipLevel, float mipFactor, float layerWeight, float4 defaultValue, bool enableHeightBlend = true) { - // Take first sample (always needed) - float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); - - // Early exit for high mip levels - single sample is sufficient - if (mipLevel >= 4.0) - { - return sample1; + // Early termination for very low weights - blend with default + float minimalThreshold = step(layerWeight, WEIGHT_THRESHOLD_MINIMAL); + [branch] if (minimalThreshold > 0.5) { + float4 singleSample = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + return lerp(singleSample, defaultValue, saturate((WEIGHT_THRESHOLD_MINIMAL - layerWeight) / WEIGHT_THRESHOLD_MINIMAL)); } - - // Take remaining samples for blending - float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); - float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); - - // Use mip level to determine blending complexity - float mipFactor = saturate(mipLevel / 4.0); - - // Full height-based blending for low mip levels (close terrain) - float contrastFactor = HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE); - float3 blendWeights = pow(saturate(offsets.weights), contrastFactor); - - // Direct height calculation without matrix - float3 luminanceHeights = float3( - dot(sample1.rgb, LUMINANCE_WEIGHTS), - dot(sample2.rgb, LUMINANCE_WEIGHTS), - dot(sample3.rgb, LUMINANCE_WEIGHTS) - ); - float3 alphaValues = float3(sample1.a, sample2.a, sample3.a); - float3 alphaMask = step(0.001, alphaValues); - float3 heights = lerp(luminanceHeights, alphaValues, alphaMask); - // Combined weight calculation and normalization - float3 weights = NormalizeWeights(blendWeights * (1.0 + HEIGHT_INFLUENCE * heights)); - - // Direct blend without intermediate variable - float4 highQualitySample = sample1 * weights.x + sample2 * weights.y + sample3 * weights.z; - - // Smooth transition between high quality and single sample based on mip level - return lerp(highQualitySample, sample1, mipFactor); -} - -// Stochastic sampling function without height blending for better performance -inline float4 StochasticEffectNoHeight(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) -{ - // Take first sample (always needed) - float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); - - // Early exit for high mip levels - single sample is sufficient - if (mipLevel >= 4.0) - { - return sample1; + // Single sample for high mip levels or simple mode + if (blendingMode == 0 || mipLevel >= 4.0) { + return tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); } - - // Take remaining samples for blending + + // Multi-sample stochastic blending + float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); - - // Use mip level to determine blending complexity - float mipFactor = saturate(mipLevel / 4.0); - - // Simple barycentric blend without height influence - float3 weights = NormalizeWeights(saturate(offsets.weights)); + + float3 weights; + if (enableHeightBlend && blendingMode == 2) { + // Height-based blending + float contrastFactor = HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE); + float3 blendWeights = pow(saturate(offsets.weights), contrastFactor); + + float3 luminanceHeights = float3( + dot(sample1.rgb, LUMINANCE_WEIGHTS), + dot(sample2.rgb, LUMINANCE_WEIGHTS), + dot(sample3.rgb, LUMINANCE_WEIGHTS) + ); + float3 alphaValues = float3(sample1.a, sample2.a, sample3.a); + float3 alphaMask = step(0.001, alphaValues); + float3 heights = lerp(luminanceHeights, alphaValues, alphaMask); + + weights = NormalizeWeights(blendWeights * (1.0 + HEIGHT_INFLUENCE * heights)); + } else { + // Simple barycentric blending + weights = NormalizeWeights(saturate(offsets.weights)); + } + float4 blendedSample = sample1 * weights.x + sample2 * weights.y + sample3 * weights.z; - - // Smooth transition between blended and single sample based on mip level return lerp(blendedSample, sample1, mipFactor); } +// Simplified stochastic sampling for RMAOS textures (no height blending) +inline float4 StochasticEffectNoHeight(uint blendingMode, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float mipLevel, float mipFactor, float layerWeight, float4 defaultValue) +{ + return StochasticEffect(blendingMode, tex, samp, uv, offsets, mipLevel, mipFactor, layerWeight, defaultValue, false); +} + #endif // TERRAIN_VARIATION_HLSLI \ No newline at end of file diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 90940b2972..d0d153d9b1 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1278,8 +1278,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TRUE_PBR) float4 blendedRMAOS = 0; # endif - - // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) + // Compute stochastic offsets once for all layers (only when terrain variation is enabled) # if defined(TERRAIN_VARIATION) bool useTerrainVariation = SharedData::terrainVariationSettings.enableTilingFix; StochasticOffsets sharedOffset; @@ -1361,6 +1360,20 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) } } # endif // EMAT + + // Pre-compute shared blending parameters for terrain variation optimization +# if defined(TERRAIN_VARIATION) + uint sharedBlendingMode = 0; // 0=single sample, 1=simple blend, 2=height blend + float sharedMipFactor = 0; + [branch] if (useTerrainVariation) + { + // Use average mip level to determine shared blending strategy + float avgMipLevel = (mipLevels[0] + mipLevels[1] + mipLevels[2] + mipLevels[3] + mipLevels[4] + mipLevels[5]) / 6.0; + sharedBlendingMode = (avgMipLevel >= 4.0) ? 0 : 2; // 0=single sample, 2=height blend for quality + sharedMipFactor = saturate(avgMipLevel / 4.0); + } +# endif + # endif // LANDSCAPE # if defined(SPARKLE) @@ -1384,15 +1397,14 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # endif # if defined(LANDSCAPE) // Layer 1 (LandBlendWeights1.x) - if (input.LandBlendWeights1.x > 0.01) { + if (input.LandBlendWeights1.x > WEIGHT_THRESHOLD_SKIP) { float weight = input.LandBlendWeights1.x; - - // Sample diffuse texture for layer 1 + // Sample diffuse texture for layer 1 # if defined(TERRAIN_VARIATION) float4 landColor1; [branch] if (useTerrainVariation) { - landColor1 = StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampColorSampler, uv, sharedOffset, dxUV, dyUV); + landColor1 = StochasticEffect(sharedBlendingMode, TexColorSampler, SampColorSampler, uv, sharedOffset, mipLevels[0], sharedMipFactor, weight, float4(0.5, 0.5, 0.5, 1.0)); } else { @@ -1410,13 +1422,12 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # endif float landAlpha1 = landColor1.a; float landSnowMask1 = GetLandSnowMaskValue(landColor1.w); - - // Sample normal texture for layer 1 + // Sample normal texture for layer 1 (weight-aware) # if defined(TERRAIN_VARIATION) float4 landNormal1; [branch] if (useTerrainVariation) { - landNormal1 = StochasticEffect(screenNoise, mipLevels[0], TexNormalSampler, SampNormalSampler, uv, sharedOffset, dxUV, dyUV); + landNormal1 = StochasticEffect(sharedBlendingMode, TexNormalSampler, SampNormalSampler, uv, sharedOffset, mipLevels[0], sharedMipFactor, weight, DEFAULT_NORMAL); } else { @@ -1431,7 +1442,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) landSnowMask += LandscapeTexture1to4IsSnow.x * input.LandBlendWeights1.x * landSnowMask1; # endif // SNOW - // Sample RMAOS texture for layer 1 + // Sample RMAOS texture for layer 1 (weight-aware) # if defined(TRUE_PBR) float4 landRMAOS1; [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0PBR) != 0) @@ -1439,7 +1450,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS1 = StochasticEffectNoHeight(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dxUV, dyUV) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + landRMAOS1 = StochasticEffectNoHeight(sharedBlendingMode, TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, mipLevels[0], sharedMipFactor, weight, DEFAULT_RMAOS) * float4(PBRParams1.x, 1, 1, PBRParams1.z); } else { @@ -1463,17 +1474,15 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) blendedNormalRGB += landNormalRGB1 * weight; blendedNormalAlpha += landNormalAlpha1 * weight; } - // Layer 2 (LandBlendWeights1.y) - if (input.LandBlendWeights1.y > 0.01) { + if (input.LandBlendWeights1.y > WEIGHT_THRESHOLD_SKIP) { float weight = input.LandBlendWeights1.y; - // Sample diffuse texture for layer 2 # if defined(TERRAIN_VARIATION) float4 landColor2; [branch] if (useTerrainVariation) { - landColor2 = StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampLandColor2Sampler, uv, sharedOffset, dxUV, dyUV); + landColor2 = StochasticEffect(sharedBlendingMode, TexLandColor2Sampler, SampLandColor2Sampler, uv, sharedOffset, mipLevels[1], sharedMipFactor, weight, float4(0.5, 0.5, 0.5, 1.0)); } else { @@ -1490,14 +1499,12 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) } # endif float landAlpha2 = landColor2.a; - float landSnowMask2 = GetLandSnowMaskValue(landColor2.w); - - // Sample normal texture for layer 2 + float landSnowMask2 = GetLandSnowMaskValue(landColor2.w); // Sample normal texture for layer 2 # if defined(TERRAIN_VARIATION) float4 landNormal2; [branch] if (useTerrainVariation) { - landNormal2 = StochasticEffect(screenNoise, mipLevels[1], TexLandNormal2Sampler, SampLandNormal2Sampler, uv, sharedOffset, dxUV, dyUV); + landNormal2 = StochasticEffect(sharedBlendingMode, TexLandNormal2Sampler, SampLandNormal2Sampler, uv, sharedOffset, mipLevels[1], sharedMipFactor, weight, DEFAULT_NORMAL); } else { @@ -1520,7 +1527,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS2 = StochasticEffectNoHeight(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampLandRMAOS2Sampler, uv, sharedOffset, dxUV, dyUV) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); + landRMAOS2 = StochasticEffectNoHeight(sharedBlendingMode, TexLandRMAOS2Sampler, SampLandRMAOS2Sampler, uv, sharedOffset, mipLevels[1], sharedMipFactor, weight, DEFAULT_RMAOS) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); } else { @@ -1544,16 +1551,14 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) blendedNormalRGB += landNormalRGB2 * weight; blendedNormalAlpha += landNormalAlpha2 * weight; } - // Layer 3 (LandBlendWeights1.z) - if (input.LandBlendWeights1.z > 0.01) { - float weight = input.LandBlendWeights1.z; - // Sample diffuse texture for layer 3 + if (input.LandBlendWeights1.z > WEIGHT_THRESHOLD_SKIP) { + float weight = input.LandBlendWeights1.z;// Sample diffuse texture for layer 3 # if defined(TERRAIN_VARIATION) float4 landColor3; [branch] if (useTerrainVariation) { - landColor3 = StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampLandColor3Sampler, uv, sharedOffset, dxUV, dyUV); + landColor3 = StochasticEffect(sharedBlendingMode, TexLandColor3Sampler, SampLandColor3Sampler, uv, sharedOffset, mipLevels[2], sharedMipFactor, weight, float4(0.5, 0.5, 0.5, 1.0)); } else { @@ -1571,13 +1576,12 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # endif float landAlpha3 = landColor3.a; float landSnowMask3 = GetLandSnowMaskValue(landColor3.w); - // Sample normal texture for layer 3 # if defined(TERRAIN_VARIATION) float4 landNormal3; [branch] if (useTerrainVariation) { - landNormal3 = StochasticEffect(screenNoise, mipLevels[2], TexLandNormal3Sampler, SampLandNormal3Sampler, uv, sharedOffset, dxUV, dyUV); + landNormal3 = StochasticEffect(sharedBlendingMode, TexLandNormal3Sampler, SampLandNormal3Sampler, uv, sharedOffset, mipLevels[2], sharedMipFactor, weight, DEFAULT_NORMAL); } else { @@ -1600,7 +1604,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS3 = StochasticEffectNoHeight(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampLandRMAOS3Sampler, uv, sharedOffset, dxUV, dyUV) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); + landRMAOS3 = StochasticEffectNoHeight(sharedBlendingMode, TexLandRMAOS3Sampler, SampLandRMAOS3Sampler, uv, sharedOffset, mipLevels[2], sharedMipFactor, weight, DEFAULT_RMAOS) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); } else { @@ -1624,17 +1628,15 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) blendedNormalRGB += landNormalRGB3 * weight; blendedNormalAlpha += landNormalAlpha3 * weight; } - - // Layer 4 (LandBlendWeights1.w) - if (input.LandBlendWeights1.w > 0.01) { + // Layer 4 (LandBlendWeights1.w) + if (input.LandBlendWeights1.w > WEIGHT_THRESHOLD_SKIP) { float weight = input.LandBlendWeights1.w; - // Sample diffuse texture for layer 4 # if defined(TERRAIN_VARIATION) float4 landColor4; [branch] if (useTerrainVariation) { - landColor4 = StochasticEffect(screenNoise, mipLevels[3], TexLandColor4Sampler, SampLandColor4Sampler, uv, sharedOffset, dxUV, dyUV); + landColor4 = StochasticEffect(sharedBlendingMode, TexLandColor4Sampler, SampLandColor4Sampler, uv, sharedOffset, mipLevels[3], sharedMipFactor, weight, float4(0.5, 0.5, 0.5, 1.0)); } else { @@ -1652,13 +1654,12 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # endif float landAlpha4 = landColor4.a; float landSnowMask4 = GetLandSnowMaskValue(landColor4.w); - // Sample normal texture for layer 4 # if defined(TERRAIN_VARIATION) float4 landNormal4; [branch] if (useTerrainVariation) { - landNormal4 = StochasticEffect(screenNoise, mipLevels[3], TexLandNormal4Sampler, SampLandNormal4Sampler, uv, sharedOffset, dxUV, dyUV); + landNormal4 = StochasticEffect(sharedBlendingMode, TexLandNormal4Sampler, SampLandNormal4Sampler, uv, sharedOffset, mipLevels[3], sharedMipFactor, weight, DEFAULT_NORMAL); } else { @@ -1681,7 +1682,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS4 = StochasticEffectNoHeight(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampLandRMAOS4Sampler, uv, sharedOffset, dxUV, dyUV) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); + landRMAOS4 = StochasticEffectNoHeight(sharedBlendingMode, TexLandRMAOS4Sampler, SampLandRMAOS4Sampler, uv, sharedOffset, mipLevels[3], sharedMipFactor, weight, DEFAULT_RMAOS) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); } else { @@ -1705,16 +1706,15 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) blendedNormalRGB += landNormalRGB4 * weight; blendedNormalAlpha += landNormalAlpha4 * weight; } - // Layer 5 (LandBlendWeights2.x) - if (input.LandBlendWeights2.x > 0.01) { + if (input.LandBlendWeights2.x > WEIGHT_THRESHOLD_SKIP) { float weight = input.LandBlendWeights2.x; // Sample diffuse texture for layer 5 # if defined(TERRAIN_VARIATION) float4 landColor5; [branch] if (useTerrainVariation) { - landColor5 = StochasticEffect(screenNoise, mipLevels[4], TexLandColor5Sampler, SampLandColor5Sampler, uv, sharedOffset, dxUV, dyUV); + landColor5 = StochasticEffect(sharedBlendingMode, TexLandColor5Sampler, SampLandColor5Sampler, uv, sharedOffset, mipLevels[4], sharedMipFactor, weight, float4(0.5, 0.5, 0.5, 1.0)); } else { @@ -1731,14 +1731,12 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) } # endif float landAlpha5 = landColor5.a; - float landSnowMask5 = GetLandSnowMaskValue(landColor5.w); - - // Sample normal texture for layer 5 + float landSnowMask5 = GetLandSnowMaskValue(landColor5.w); // Sample normal texture for layer 5 # if defined(TERRAIN_VARIATION) float4 landNormal5; [branch] if (useTerrainVariation) { - landNormal5 = StochasticEffect(screenNoise, mipLevels[4], TexLandNormal5Sampler, SampLandNormal5Sampler, uv, sharedOffset, dxUV, dyUV); + landNormal5 = StochasticEffect(sharedBlendingMode, TexLandNormal5Sampler, SampLandNormal5Sampler, uv, sharedOffset, mipLevels[4], sharedMipFactor, weight, DEFAULT_NORMAL); } else { @@ -1762,7 +1760,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS5 = StochasticEffectNoHeight(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampLandRMAOS5Sampler, uv, sharedOffset, dxUV, dyUV) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); + landRMAOS5 = StochasticEffectNoHeight(sharedBlendingMode, TexLandRMAOS5Sampler, SampLandRMAOS5Sampler, uv, sharedOffset, mipLevels[4], sharedMipFactor, weight, DEFAULT_RMAOS) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); } else { @@ -1785,17 +1783,15 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) blendedAlpha += landAlpha5 * weight; blendedNormalRGB += landNormalRGB5 * weight; blendedNormalAlpha += landNormalAlpha5 * weight; - } - // Layer 6 (LandBlendWeights2.y) - if (input.LandBlendWeights2.y > 0.01) { - float weight = input.LandBlendWeights2.y; - + } // Layer 6 (LandBlendWeights2.y) + if (input.LandBlendWeights2.y > WEIGHT_THRESHOLD_SKIP) { + float weight = input.LandBlendWeights2.y; // Sample layer 6 textures # if defined(TERRAIN_VARIATION) float4 landColor6; [branch] if (useTerrainVariation) { - landColor6 = StochasticEffect(screenNoise, mipLevels[5], TexLandColor6Sampler, SampLandColor6Sampler, uv, sharedOffset, dxUV, dyUV); + landColor6 = StochasticEffect(sharedBlendingMode, TexLandColor6Sampler, SampLandColor6Sampler, uv, sharedOffset, mipLevels[5], sharedMipFactor, weight, float4(0.5, 0.5, 0.5, 1.0)); } else { @@ -1813,13 +1809,12 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # endif float landAlpha6 = landColor6.a; float landSnowMask6 = GetLandSnowMaskValue(landColor6.w); - // Sample normal texture for layer 6 # if defined(TERRAIN_VARIATION) float4 landNormal6; [branch] if (useTerrainVariation) { - landNormal6 = StochasticEffect(screenNoise, mipLevels[5], TexLandNormal6Sampler, SampLandNormal6Sampler, uv, sharedOffset, dxUV, dyUV); + landNormal6 = StochasticEffect(sharedBlendingMode, TexLandNormal6Sampler, SampLandNormal6Sampler, uv, sharedOffset, mipLevels[5], sharedMipFactor, weight, DEFAULT_NORMAL); } else { @@ -1842,7 +1837,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS6 = StochasticEffectNoHeight(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampLandRMAOS6Sampler, uv, sharedOffset, dxUV, dyUV) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); + landRMAOS6 = StochasticEffectNoHeight(sharedBlendingMode, TexLandRMAOS6Sampler, SampLandRMAOS6Sampler, uv, sharedOffset, mipLevels[5], sharedMipFactor, weight, DEFAULT_RMAOS) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); } else { From 035cbb6918831fe0534c7353ca3391b588697342 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Mon, 16 Jun 2025 23:13:47 +1000 Subject: [PATCH 49/53] reintroduced miplevel fixes --- .../Shaders/ExtendedMaterials/ExtendedMaterials.hlsli | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index ef5aafd0fc..47fb04dff8 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -41,6 +41,10 @@ namespace ExtendedMaterials float2 textureDims; tex.GetDimensions(textureDims.x, textureDims.y); + #if !defined(TERRAIN_VARIATION) + textureDims /= 2.0; + #endif + #if !defined(PARALLAX) && !defined(TRUE_PBR) textureDims /= 2.0; #endif @@ -67,8 +71,11 @@ namespace ExtendedMaterials mipLevel++; #endif - #if defined(VR) + #if defined(TERRAIN_VARIATION) + [branch] if (SharedData::extendedMaterialSettings.EnableTerrainParallax) + { mipLevel++; + } #endif return mipLevel; } From f5f9b0a329e01e333890c0a5e9d41b6349e04196 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Fri, 20 Jun 2025 15:12:17 +1000 Subject: [PATCH 50/53] Quality & Performance Fix, no lines in terrain. --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 96 +++++++++---- .../TerrainVariation/TerrainVariation.hlsli | 109 +++++++------- package/Shaders/Lighting.hlsl | 135 +++++++++--------- 3 files changed, 198 insertions(+), 142 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index 47fb04dff8..bdef9e9050 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -41,11 +41,11 @@ namespace ExtendedMaterials float2 textureDims; tex.GetDimensions(textureDims.x, textureDims.y); - #if !defined(TERRAIN_VARIATION) + #if !defined(PARALLAX) && !defined(TRUE_PBR) textureDims /= 2.0; #endif - #if !defined(PARALLAX) && !defined(TRUE_PBR) + #if !defined(TERRAIN_VARIATION) textureDims /= 2.0; #endif @@ -71,6 +71,10 @@ namespace ExtendedMaterials mipLevel++; #endif + #if defined(VR) + mipLevel++; + #endif + #if defined(TERRAIN_VARIATION) [branch] if (SharedData::extendedMaterialSettings.EnableTerrainParallax) { @@ -127,10 +131,11 @@ namespace ExtendedMaterials { float heightBlend = 1 + blendFactor * HEIGHT_POWER; float heights[6] = { 0, 0, 0, 0, 0, 0 }; - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.01) + + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.01) { # if defined(TERRAIN_VARIATION) - heights[0] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandDisplacement0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[0], 0.0, w1.x, float4(0.5, 0.5, 0.5, 1.0)).x, params[0]); + heights[0] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[0], TexLandDisplacement0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); # else heights[0] = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); # endif @@ -138,7 +143,7 @@ namespace ExtendedMaterials [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1HasDisplacement) != 0 && w1.y > 0.01) { # if defined(TERRAIN_VARIATION) - heights[1] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandDisplacement1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[1], 0.0, w1.y, float4(0.5, 0.5, 0.5, 1.0)).x, params[1]); + heights[1] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[1], TexLandDisplacement1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); # else heights[1] = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); # endif @@ -146,7 +151,7 @@ namespace ExtendedMaterials [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2HasDisplacement) != 0 && w1.z > 0.01) { # if defined(TERRAIN_VARIATION) - heights[2] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandDisplacement2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[2], 0.0, w1.z, float4(0.5, 0.5, 0.5, 1.0)).x, params[2]); + heights[2] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[2], TexLandDisplacement2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); # else heights[2] = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); # endif @@ -154,7 +159,7 @@ namespace ExtendedMaterials [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.01) { # if defined(TERRAIN_VARIATION) - heights[3] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[3], 0.0, w1.w, float4(0.5, 0.5, 0.5, 1.0)).x, params[3]); + heights[3] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); # else heights[3] = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); # endif @@ -162,7 +167,7 @@ namespace ExtendedMaterials [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.01) { # if defined(TERRAIN_VARIATION) - heights[4] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[4], 0.0, w2.x, float4(0.5, 0.5, 0.5, 1.0)).x, params[4]); + heights[4] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); # else heights[4] = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); # endif @@ -170,7 +175,7 @@ namespace ExtendedMaterials [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.01) { # if defined(TERRAIN_VARIATION) - heights[5] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[5], 0.0, w2.y, float4(0.5, 0.5, 0.5, 1.0)).x, params[5]); + heights[5] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[5], TexLandDisplacement5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); # else heights[5] = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); # endif @@ -187,11 +192,13 @@ namespace ExtendedMaterials out float weights[6]) { float heightBlend = 1 + blendFactor * HEIGHT_POWER; - float heights[6] = { 0, 0, 0, 0, 0, 0 }; if (w1.x > 0.01) { + float heights[6] = { 0, 0, 0, 0, 0, 0 }; + + if (w1.x > 0.01) { [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand0HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - heights[0] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandTHDisp0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[0], 0.0, w1.x, float4(0.5, 0.5, 0.5, 1.0)).x, params[0]); + heights[0] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[0], TexLandTHDisp0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); # else heights[0] = ScaleDisplacement(TexLandTHDisp0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); # endif @@ -199,16 +206,17 @@ namespace ExtendedMaterials else { # if defined(TERRAIN_VARIATION) - heights[0] = ScaleDisplacement(StochasticEffectNoHeight(2, TexColorSampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[0], 0.0, w1.x, float4(0.5, 0.5, 0.5, 1.0)).w, params[0]); + heights[0] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[0], TexColorSampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[0]); # else heights[0] = ScaleDisplacement(TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, params[0]); # endif } - } if (w1.y > 0.01) { + } + if (w1.y > 0.01) { [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand1HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - heights[1] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandTHDisp1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[1], 0.0, w1.y, float4(0.5, 0.5, 0.5, 1.0)).x, params[1]); + heights[1] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[1], TexLandTHDisp1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); # else heights[1] = ScaleDisplacement(TexLandTHDisp1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); # endif @@ -216,16 +224,17 @@ namespace ExtendedMaterials else { # if defined(TERRAIN_VARIATION) - heights[1] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandColor2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[1], 0.0, w1.y, float4(0.5, 0.5, 0.5, 1.0)).w, params[1]); + heights[1] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[1], TexLandColor2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[1]); # else heights[1] = ScaleDisplacement(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, params[1]); # endif } - } if (w1.z > 0.01) { + } + if (w1.z > 0.01) { [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand2HasDisplacement) != 0) { # if defined(TERRAIN_VARIATION) - heights[2] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandTHDisp2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[2], 0.0, w1.z, float4(0.5, 0.5, 0.5, 1.0)).x, params[2]); + heights[2] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[2], TexLandTHDisp2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); # else heights[2] = ScaleDisplacement(TexLandTHDisp2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); # endif @@ -233,35 +242,60 @@ namespace ExtendedMaterials else { # if defined(TERRAIN_VARIATION) - heights[2] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandColor3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[2], 0.0, w1.z, float4(0.5, 0.5, 0.5, 1.0)).w, params[2]); + heights[2] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[2], TexLandColor3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[2]); # else heights[2] = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); # endif } - } [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0 && w1.w > 0.01) + } + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0 && w1.w > 0.01) { # if defined(TERRAIN_VARIATION) - heights[3] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandTHDisp3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[3], 0.0, w1.w, float4(0.5, 0.5, 0.5, 1.0)).x, params[3]); + heights[3] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[3], TexLandTHDisp3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); # else heights[3] = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); +# endif + } + else if (w1.w > 0.01) + { +# if defined(TERRAIN_VARIATION) + heights[3] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[3], TexLandColor4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[3]); +# else + heights[3] = ScaleDisplacement(TexLandColor4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).w, params[3]); # endif } [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0 && w2.x > 0.01) { # if defined(TERRAIN_VARIATION) - heights[4] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandTHDisp4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[4], 0.0, w2.x, float4(0.5, 0.5, 0.5, 1.0)).x, params[4]); + heights[4] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[4], TexLandTHDisp4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); # else heights[4] = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); # endif } - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0 && w2.y > 0.01) + else if (w2.x > 0.01) { # if defined(TERRAIN_VARIATION) - heights[5] = ScaleDisplacement(StochasticEffectNoHeight(2, TexLandTHDisp5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, mipLevels[5], 0.0, w2.y, float4(0.5, 0.5, 0.5, 1.0)).x, params[5]); + heights[4] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[4], TexLandColor5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[4]); +# else + heights[4] = ScaleDisplacement(TexLandColor5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).w, params[4]); +# endif + } + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0 && w2.y > 0.01) + { +# if defined(TERRAIN_VARIATION) + heights[5] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[5], TexLandTHDisp5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[5]); # else heights[5] = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); # endif } + else if (w2.y > 0.01) + { +# if defined(TERRAIN_VARIATION) + heights[5] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[5], TexLandColor6Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[5]); +# else + heights[5] = ScaleDisplacement(TexLandColor6Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).w, params[5]); +# endif + } float total; ProcessTerrainHeightWeights(heightBlend, w1, w2, heights, weights, total); @@ -601,7 +635,7 @@ namespace ExtendedMaterials } else { - heights[0] = ScaleDisplacement(TexLandColor1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, params[0]); + heights[0] = ScaleDisplacement(TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, params[0]); } } if (w1.y > 0.0) { @@ -624,18 +658,30 @@ namespace ExtendedMaterials heights[2] = ScaleDisplacement(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, params[2]); } } - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0 && w1.w > 0.0) + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0 && w1.w > 0.01) { heights[3] = ScaleDisplacement(TexLandTHDisp3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); } + else if (w1.w > 0.01) + { + heights[3] = ScaleDisplacement(TexLandColor4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).w, params[3]); + } [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0 && w2.x > 0.0) { heights[4] = ScaleDisplacement(TexLandTHDisp4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); } + else if (w2.x > 0.01) + { + heights[4] = ScaleDisplacement(TexLandColor5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).w, params[4]); + } [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0 && w2.y > 0.0) { heights[5] = ScaleDisplacement(TexLandTHDisp5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); } + else if (w2.y > 0.01) + { + heights[5] = ScaleDisplacement(TexLandColor6Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).w, params[5]); + } float total; ProcessTerrainHeightWeights(heightBlend, w1, w2, heights, weights, total); diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index 637778a1f4..8b648c4d26 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -22,14 +22,6 @@ static const float3 LUMINANCE_WEIGHTS = float3(0.2126, 0.7152, 0.0722); static const float2 HASH_MULTIPLIER = float2(1271.5151, 3337.8237); static const float2 HASH_SINE_MULTIPLIER = float2(43758.5453, 28637.1369); -// Early termination thresholds for progressive sampling - optimized for GPU performance -static const float WEIGHT_THRESHOLD_SKIP = 0.005; // Skip layer entirely if weight is below this -static const float WEIGHT_THRESHOLD_MINIMAL = 0.02; // Use minimal sampling if weight is below this - -// Default values for low-contribution layers -static const float4 DEFAULT_NORMAL = float4(0.5, 0.5, 1.0, 1.0); // Default normal map (pointing up) -static const float4 DEFAULT_RMAOS = float4(1.0, 0.0, 1.0, 0.0); // Default RMAOS (non-metallic, smooth) - // Structure to hold stochastic sampling offsets and weights struct StochasticOffsets { @@ -133,55 +125,74 @@ inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, Samp return lerp(sample2, sample1, 0.65); } -// Unified stochastic sampling function with weight-aware optimization -inline float4 StochasticEffect(uint blendingMode, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float mipLevel, float mipFactor, float layerWeight, float4 defaultValue, bool enableHeightBlend = true) +// Main stochastic sampling function +inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) { - // Early termination for very low weights - blend with default - float minimalThreshold = step(layerWeight, WEIGHT_THRESHOLD_MINIMAL); - [branch] if (minimalThreshold > 0.5) { - float4 singleSample = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); - return lerp(singleSample, defaultValue, saturate((WEIGHT_THRESHOLD_MINIMAL - layerWeight) / WEIGHT_THRESHOLD_MINIMAL)); - } - - // Single sample for high mip levels or simple mode - if (blendingMode == 0 || mipLevel >= 4.0) { - return tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); - } - - // Multi-sample stochastic blending + // Take first sample (always needed) float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + + // Calculate smooth transition factor - starts blending at mip 2.5, fully single sample at mip 5.0 + float mipFactor = saturate((mipLevel - 2.5) / 2.5); + + // Early exit for very high mip levels - single sample is sufficient + if (mipFactor >= 0.8) + { + return sample1; + } + + // Take remaining samples for blending float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); + + // Full height-based blending for low mip levels (close terrain) + float contrastFactor = HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE); + float3 blendWeights = pow(saturate(offsets.weights), contrastFactor); + + // Direct height calculation without matrix + float3 luminanceHeights = float3( + dot(sample1.rgb, LUMINANCE_WEIGHTS), + dot(sample2.rgb, LUMINANCE_WEIGHTS), + dot(sample3.rgb, LUMINANCE_WEIGHTS) + ); + float3 alphaValues = float3(sample1.a, sample2.a, sample3.a); + float3 alphaMask = step(0.001, alphaValues); + float3 heights = lerp(luminanceHeights, alphaValues, alphaMask); - float3 weights; - if (enableHeightBlend && blendingMode == 2) { - // Height-based blending - float contrastFactor = HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE); - float3 blendWeights = pow(saturate(offsets.weights), contrastFactor); - - float3 luminanceHeights = float3( - dot(sample1.rgb, LUMINANCE_WEIGHTS), - dot(sample2.rgb, LUMINANCE_WEIGHTS), - dot(sample3.rgb, LUMINANCE_WEIGHTS) - ); - float3 alphaValues = float3(sample1.a, sample2.a, sample3.a); - float3 alphaMask = step(0.001, alphaValues); - float3 heights = lerp(luminanceHeights, alphaValues, alphaMask); - - weights = NormalizeWeights(blendWeights * (1.0 + HEIGHT_INFLUENCE * heights)); - } else { - // Simple barycentric blending - weights = NormalizeWeights(saturate(offsets.weights)); - } - - float4 blendedSample = sample1 * weights.x + sample2 * weights.y + sample3 * weights.z; - return lerp(blendedSample, sample1, mipFactor); + // Combined weight calculation and normalization + float3 weights = NormalizeWeights(blendWeights * (1.0 + HEIGHT_INFLUENCE * heights)); + + // Direct blend without intermediate variable + float4 highQualitySample = sample1 * weights.x + sample2 * weights.y + sample3 * weights.z; + + // Smooth transition between high quality and single sample based on mip level + return lerp(highQualitySample, sample1, mipFactor); } -// Simplified stochastic sampling for RMAOS textures (no height blending) -inline float4 StochasticEffectNoHeight(uint blendingMode, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float mipLevel, float mipFactor, float layerWeight, float4 defaultValue) +// Stochastic sampling function without height blending for better performance +inline float4 StochasticEffectNoHeight(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) { - return StochasticEffect(blendingMode, tex, samp, uv, offsets, mipLevel, mipFactor, layerWeight, defaultValue, false); + // Take first sample (always needed) + float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + + // Calculate smooth transition factor - starts blending at mip 2.5, fully single sample at mip 5.0 + float mipFactor = saturate((mipLevel - 2.5) / 2.5); + + // Early exit for very high mip levels - single sample is sufficient + if (mipFactor >= 0.8) + { + return sample1; + } + + // Take remaining samples for blending + float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); + float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); + + // Simple barycentric blend without height influence + float3 weights = NormalizeWeights(saturate(offsets.weights)); + float4 blendedSample = sample1 * weights.x + sample2 * weights.y + sample3 * weights.z; + + // Smooth transition between blended and single sample based on mip level + return lerp(blendedSample, sample1, mipFactor); } diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index d0d153d9b1..362e5fb904 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1250,6 +1250,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # else bool useSnowDecalSpecular = false; # endif // defined(SPARKLE) || !defined(PROJECTED_UV) + float2 diffuseUv = uv; # if defined(SPARKLE) @@ -1257,12 +1258,6 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # endif // SPARKLE # if defined(LANDSCAPE) // Normalize blend weights - // Pre-calculate derivatives for UV coordinates (used by terrain variation) - float2 dxUV = ddx(uv); - float2 dyUV = ddy(uv); - float2 dxTexCoord = ddx(input.TexCoord0.zw); - float2 dyTexCoord = ddy(input.TexCoord0.zw); - float totalWeight = input.LandBlendWeights1.x + input.LandBlendWeights1.y + input.LandBlendWeights1.z + input.LandBlendWeights1.w + input.LandBlendWeights2.x + input.LandBlendWeights2.y; if (totalWeight > 0.0) { @@ -1278,13 +1273,16 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TRUE_PBR) float4 blendedRMAOS = 0; # endif - // Compute stochastic offsets once for all layers (only when terrain variation is enabled) + // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) # if defined(TERRAIN_VARIATION) bool useTerrainVariation = SharedData::terrainVariationSettings.enableTilingFix; + float2 dx, dy; StochasticOffsets sharedOffset; StochasticOffsets sharedOffset2; [branch] if (useTerrainVariation) { + dx = ddx(input.TexCoord0.zw); + dy = ddy(input.TexCoord0.zw); sharedOffset = ComputeStochasticOffsets(input.TexCoord0.zw); } # endif @@ -1326,7 +1324,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, sharedOffset, dxTexCoord, dyTexCoord, pixelOffset, weights); + uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, sharedOffset, dx, dy, pixelOffset, weights); } else { @@ -1348,7 +1346,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dxTexCoord, dyTexCoord, weights); + sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); } else { @@ -1360,20 +1358,6 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) } } # endif // EMAT - - // Pre-compute shared blending parameters for terrain variation optimization -# if defined(TERRAIN_VARIATION) - uint sharedBlendingMode = 0; // 0=single sample, 1=simple blend, 2=height blend - float sharedMipFactor = 0; - [branch] if (useTerrainVariation) - { - // Use average mip level to determine shared blending strategy - float avgMipLevel = (mipLevels[0] + mipLevels[1] + mipLevels[2] + mipLevels[3] + mipLevels[4] + mipLevels[5]) / 6.0; - sharedBlendingMode = (avgMipLevel >= 4.0) ? 0 : 2; // 0=single sample, 2=height blend for quality - sharedMipFactor = saturate(avgMipLevel / 4.0); - } -# endif - # endif // LANDSCAPE # if defined(SPARKLE) @@ -1396,15 +1380,17 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # endif # endif -# if defined(LANDSCAPE) // Layer 1 (LandBlendWeights1.x) - if (input.LandBlendWeights1.x > WEIGHT_THRESHOLD_SKIP) { +# if defined(LANDSCAPE) + // Layer 1 (LandBlendWeights1.x) + if (input.LandBlendWeights1.x > 0.01) { float weight = input.LandBlendWeights1.x; - // Sample diffuse texture for layer 1 + + // Sample diffuse texture for layer 1 # if defined(TERRAIN_VARIATION) float4 landColor1; [branch] if (useTerrainVariation) { - landColor1 = StochasticEffect(sharedBlendingMode, TexColorSampler, SampColorSampler, uv, sharedOffset, mipLevels[0], sharedMipFactor, weight, float4(0.5, 0.5, 0.5, 1.0)); + landColor1 = StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampColorSampler, uv, sharedOffset, dx, dy); } else { @@ -1422,12 +1408,13 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # endif float landAlpha1 = landColor1.a; float landSnowMask1 = GetLandSnowMaskValue(landColor1.w); - // Sample normal texture for layer 1 (weight-aware) + + // Sample normal texture for layer 1 # if defined(TERRAIN_VARIATION) float4 landNormal1; [branch] if (useTerrainVariation) { - landNormal1 = StochasticEffect(sharedBlendingMode, TexNormalSampler, SampNormalSampler, uv, sharedOffset, mipLevels[0], sharedMipFactor, weight, DEFAULT_NORMAL); + landNormal1 = StochasticEffect(screenNoise, mipLevels[0], TexNormalSampler, SampNormalSampler, uv, sharedOffset, dx, dy); } else { @@ -1442,7 +1429,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) landSnowMask += LandscapeTexture1to4IsSnow.x * input.LandBlendWeights1.x * landSnowMask1; # endif // SNOW - // Sample RMAOS texture for layer 1 (weight-aware) + // Sample RMAOS texture for layer 1 # if defined(TRUE_PBR) float4 landRMAOS1; [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0PBR) != 0) @@ -1450,7 +1437,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS1 = StochasticEffectNoHeight(sharedBlendingMode, TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, mipLevels[0], sharedMipFactor, weight, DEFAULT_RMAOS) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + landRMAOS1 = StochasticEffectNoHeight(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy) * float4(PBRParams1.x, 1, 1, PBRParams1.z); } else { @@ -1474,15 +1461,17 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) blendedNormalRGB += landNormalRGB1 * weight; blendedNormalAlpha += landNormalAlpha1 * weight; } + // Layer 2 (LandBlendWeights1.y) - if (input.LandBlendWeights1.y > WEIGHT_THRESHOLD_SKIP) { + if (input.LandBlendWeights1.y > 0.01) { float weight = input.LandBlendWeights1.y; + // Sample diffuse texture for layer 2 # if defined(TERRAIN_VARIATION) float4 landColor2; [branch] if (useTerrainVariation) { - landColor2 = StochasticEffect(sharedBlendingMode, TexLandColor2Sampler, SampLandColor2Sampler, uv, sharedOffset, mipLevels[1], sharedMipFactor, weight, float4(0.5, 0.5, 0.5, 1.0)); + landColor2 = StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampLandColor2Sampler, uv, sharedOffset, dx, dy); } else { @@ -1499,12 +1488,14 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) } # endif float landAlpha2 = landColor2.a; - float landSnowMask2 = GetLandSnowMaskValue(landColor2.w); // Sample normal texture for layer 2 + float landSnowMask2 = GetLandSnowMaskValue(landColor2.w); + + // Sample normal texture for layer 2 # if defined(TERRAIN_VARIATION) float4 landNormal2; [branch] if (useTerrainVariation) { - landNormal2 = StochasticEffect(sharedBlendingMode, TexLandNormal2Sampler, SampLandNormal2Sampler, uv, sharedOffset, mipLevels[1], sharedMipFactor, weight, DEFAULT_NORMAL); + landNormal2 = StochasticEffect(screenNoise, mipLevels[1], TexLandNormal2Sampler, SampLandNormal2Sampler, uv, sharedOffset, dx, dy); } else { @@ -1527,7 +1518,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS2 = StochasticEffectNoHeight(sharedBlendingMode, TexLandRMAOS2Sampler, SampLandRMAOS2Sampler, uv, sharedOffset, mipLevels[1], sharedMipFactor, weight, DEFAULT_RMAOS) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); + landRMAOS2 = StochasticEffectNoHeight(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampLandRMAOS2Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); } else { @@ -1551,14 +1542,16 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) blendedNormalRGB += landNormalRGB2 * weight; blendedNormalAlpha += landNormalAlpha2 * weight; } + // Layer 3 (LandBlendWeights1.z) - if (input.LandBlendWeights1.z > WEIGHT_THRESHOLD_SKIP) { - float weight = input.LandBlendWeights1.z;// Sample diffuse texture for layer 3 + if (input.LandBlendWeights1.z > 0.01) { + float weight = input.LandBlendWeights1.z; + // Sample diffuse texture for layer 3 # if defined(TERRAIN_VARIATION) float4 landColor3; [branch] if (useTerrainVariation) { - landColor3 = StochasticEffect(sharedBlendingMode, TexLandColor3Sampler, SampLandColor3Sampler, uv, sharedOffset, mipLevels[2], sharedMipFactor, weight, float4(0.5, 0.5, 0.5, 1.0)); + landColor3 = StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampLandColor3Sampler, uv, sharedOffset, dx, dy); } else { @@ -1576,12 +1569,13 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # endif float landAlpha3 = landColor3.a; float landSnowMask3 = GetLandSnowMaskValue(landColor3.w); + // Sample normal texture for layer 3 # if defined(TERRAIN_VARIATION) float4 landNormal3; [branch] if (useTerrainVariation) { - landNormal3 = StochasticEffect(sharedBlendingMode, TexLandNormal3Sampler, SampLandNormal3Sampler, uv, sharedOffset, mipLevels[2], sharedMipFactor, weight, DEFAULT_NORMAL); + landNormal3 = StochasticEffect(screenNoise, mipLevels[2], TexLandNormal3Sampler, SampLandNormal3Sampler, uv, sharedOffset, dx, dy); } else { @@ -1604,7 +1598,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS3 = StochasticEffectNoHeight(sharedBlendingMode, TexLandRMAOS3Sampler, SampLandRMAOS3Sampler, uv, sharedOffset, mipLevels[2], sharedMipFactor, weight, DEFAULT_RMAOS) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); + landRMAOS3 = StochasticEffectNoHeight(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampLandRMAOS3Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); } else { @@ -1628,15 +1622,16 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) blendedNormalRGB += landNormalRGB3 * weight; blendedNormalAlpha += landNormalAlpha3 * weight; } - // Layer 4 (LandBlendWeights1.w) - if (input.LandBlendWeights1.w > WEIGHT_THRESHOLD_SKIP) { + // Layer 4 (LandBlendWeights1.w) + if (input.LandBlendWeights1.w > 0.01) { float weight = input.LandBlendWeights1.w; + // Sample diffuse texture for layer 4 # if defined(TERRAIN_VARIATION) float4 landColor4; [branch] if (useTerrainVariation) { - landColor4 = StochasticEffect(sharedBlendingMode, TexLandColor4Sampler, SampLandColor4Sampler, uv, sharedOffset, mipLevels[3], sharedMipFactor, weight, float4(0.5, 0.5, 0.5, 1.0)); + landColor4 = StochasticEffect(screenNoise, mipLevels[3], TexLandColor4Sampler, SampLandColor4Sampler, uv, sharedOffset, dx, dy); } else { @@ -1654,12 +1649,13 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # endif float landAlpha4 = landColor4.a; float landSnowMask4 = GetLandSnowMaskValue(landColor4.w); + // Sample normal texture for layer 4 # if defined(TERRAIN_VARIATION) float4 landNormal4; [branch] if (useTerrainVariation) { - landNormal4 = StochasticEffect(sharedBlendingMode, TexLandNormal4Sampler, SampLandNormal4Sampler, uv, sharedOffset, mipLevels[3], sharedMipFactor, weight, DEFAULT_NORMAL); + landNormal4 = StochasticEffect(screenNoise, mipLevels[3], TexLandNormal4Sampler, SampLandNormal4Sampler, uv, sharedOffset, dx, dy); } else { @@ -1682,7 +1678,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS4 = StochasticEffectNoHeight(sharedBlendingMode, TexLandRMAOS4Sampler, SampLandRMAOS4Sampler, uv, sharedOffset, mipLevels[3], sharedMipFactor, weight, DEFAULT_RMAOS) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); + landRMAOS4 = StochasticEffectNoHeight(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampLandRMAOS4Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); } else { @@ -1706,15 +1702,16 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) blendedNormalRGB += landNormalRGB4 * weight; blendedNormalAlpha += landNormalAlpha4 * weight; } + // Layer 5 (LandBlendWeights2.x) - if (input.LandBlendWeights2.x > WEIGHT_THRESHOLD_SKIP) { + if (input.LandBlendWeights2.x > 0.01) { float weight = input.LandBlendWeights2.x; // Sample diffuse texture for layer 5 # if defined(TERRAIN_VARIATION) float4 landColor5; [branch] if (useTerrainVariation) { - landColor5 = StochasticEffect(sharedBlendingMode, TexLandColor5Sampler, SampLandColor5Sampler, uv, sharedOffset, mipLevels[4], sharedMipFactor, weight, float4(0.5, 0.5, 0.5, 1.0)); + landColor5 = StochasticEffect(screenNoise, mipLevels[4], TexLandColor5Sampler, SampLandColor5Sampler, uv, sharedOffset, dx, dy); } else { @@ -1731,12 +1728,14 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) } # endif float landAlpha5 = landColor5.a; - float landSnowMask5 = GetLandSnowMaskValue(landColor5.w); // Sample normal texture for layer 5 + float landSnowMask5 = GetLandSnowMaskValue(landColor5.w); + + // Sample normal texture for layer 5 # if defined(TERRAIN_VARIATION) float4 landNormal5; [branch] if (useTerrainVariation) { - landNormal5 = StochasticEffect(sharedBlendingMode, TexLandNormal5Sampler, SampLandNormal5Sampler, uv, sharedOffset, mipLevels[4], sharedMipFactor, weight, DEFAULT_NORMAL); + landNormal5 = StochasticEffect(screenNoise, mipLevels[4], TexLandNormal5Sampler, SampLandNormal5Sampler, uv, sharedOffset, dx, dy); } else { @@ -1760,7 +1759,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS5 = StochasticEffectNoHeight(sharedBlendingMode, TexLandRMAOS5Sampler, SampLandRMAOS5Sampler, uv, sharedOffset, mipLevels[4], sharedMipFactor, weight, DEFAULT_RMAOS) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); + landRMAOS5 = StochasticEffectNoHeight(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampLandRMAOS5Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); } else { @@ -1783,15 +1782,17 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) blendedAlpha += landAlpha5 * weight; blendedNormalRGB += landNormalRGB5 * weight; blendedNormalAlpha += landNormalAlpha5 * weight; - } // Layer 6 (LandBlendWeights2.y) - if (input.LandBlendWeights2.y > WEIGHT_THRESHOLD_SKIP) { - float weight = input.LandBlendWeights2.y; + } + // Layer 6 (LandBlendWeights2.y) + if (input.LandBlendWeights2.y > 0.01) { + float weight = input.LandBlendWeights2.y; + // Sample layer 6 textures # if defined(TERRAIN_VARIATION) float4 landColor6; [branch] if (useTerrainVariation) { - landColor6 = StochasticEffect(sharedBlendingMode, TexLandColor6Sampler, SampLandColor6Sampler, uv, sharedOffset, mipLevels[5], sharedMipFactor, weight, float4(0.5, 0.5, 0.5, 1.0)); + landColor6 = StochasticEffect(screenNoise, mipLevels[5], TexLandColor6Sampler, SampLandColor6Sampler, uv, sharedOffset, dx, dy); } else { @@ -1809,12 +1810,13 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # endif float landAlpha6 = landColor6.a; float landSnowMask6 = GetLandSnowMaskValue(landColor6.w); + // Sample normal texture for layer 6 # if defined(TERRAIN_VARIATION) float4 landNormal6; [branch] if (useTerrainVariation) { - landNormal6 = StochasticEffect(sharedBlendingMode, TexLandNormal6Sampler, SampLandNormal6Sampler, uv, sharedOffset, mipLevels[5], sharedMipFactor, weight, DEFAULT_NORMAL); + landNormal6 = StochasticEffect(screenNoise, mipLevels[5], TexLandNormal6Sampler, SampLandNormal6Sampler, uv, sharedOffset, dx, dy); } else { @@ -1837,7 +1839,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TERRAIN_VARIATION) [branch] if (useTerrainVariation) { - landRMAOS6 = StochasticEffectNoHeight(sharedBlendingMode, TexLandRMAOS6Sampler, SampLandRMAOS6Sampler, uv, sharedOffset, mipLevels[5], sharedMipFactor, weight, DEFAULT_RMAOS) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); + landRMAOS6 = StochasticEffectNoHeight(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampLandRMAOS6Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); } else { @@ -1888,12 +1890,10 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) // First apply terrain variation if enabled # if defined(TERRAIN_VARIATION) if (SharedData::terrainVariationSettings.enableLODTerrainTilingFix) { - // Pre-calculate derivatives for LODLANDSCAPE terrain variation - float2 dxUV = ddx(uv); - float2 dyUV = ddy(uv); - + float2 dx = ddx(uv); + float2 dy = ddy(uv); StochasticOffsets lodOffset = ComputeStochasticOffsetsLOD(uv); - float4 lodStochasticColor = StochasticSampleLOD(screenNoise, 0, TexColorSampler, SampColorSampler, uv, lodOffset, dxUV, dyUV); + float4 lodStochasticColor = StochasticSampleLOD(screenNoise, 0, TexColorSampler, SampColorSampler, uv, lodOffset, dx, dy); // Apply the stochastic result directly baseColor.xyz = Color::Diffuse(lodStochasticColor.rgb); @@ -1975,11 +1975,10 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) if (SharedData::terrainVariationSettings.enableLODTerrainTilingFix) { // Apply stochastic sampling to LOD_LAND_BLEND color texture float2 blendColorUV = input.TexCoord0.zw; - float2 dxTexCoord = ddx(blendColorUV); - float2 dyTexCoord = ddy(blendColorUV); - + float2 dx = ddx(blendColorUV); + float2 dy = ddy(blendColorUV); StochasticOffsets lodBlendColorOffset = ComputeStochasticOffsetsLOD(blendColorUV); - lodLandColor = StochasticSampleLOD(screenNoise, 0, TexLandLodBlend1Sampler, SampLandLodBlend1Sampler, blendColorUV, lodBlendColorOffset, dxTexCoord, dyTexCoord); + lodLandColor = StochasticSampleLOD(screenNoise, 0, TexLandLodBlend1Sampler, SampLandLodBlend1Sampler, blendColorUV, lodBlendColorOffset, dx, dy); } else { lodLandColor = TexLandLodBlend1Sampler.Sample(SampLandLodBlend1Sampler, input.TexCoord0.zw); } @@ -2418,9 +2417,9 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) [branch] if (useTerrainVariation) { float weights[6]; - sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dxTexCoord, dyTexCoord, weights); + sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); - parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dxUV, dyUV); + parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, dirLightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dx, dy); } else { From 4c5197ac968ac0c97e6ca1f839301258c770b26d Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Sat, 21 Jun 2025 10:36:40 +1000 Subject: [PATCH 51/53] Complex material fixes --- .../TerrainVariation/TerrainVariation.hlsli | 31 ++++++++++++++----- package/Shaders/Lighting.hlsl | 2 +- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index 8b648c4d26..8aacf3ca5e 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -107,6 +107,8 @@ inline float3 NormalizeWeights(float3 weights) // Stochastic sampling function for Terrain LOD & LOD Mask. inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsetsLOD, float2 dx, float2 dy) { + // Apply mip bias to match normal sampling behavior + float adjustedMipLevel = mipLevel + SharedData::MipBias; float offsetScale = 0.01; // Cheap pseudo-rotation using simple transforms @@ -118,8 +120,8 @@ inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, Samp float2 microOffset2 = (offsetsLOD.offset2 + dir2) * offsetScale; // Sample only two offsets - float4 sample1 = tex.SampleLevel(samp, uv + microOffset1, mipLevel); - float4 sample2 = tex.SampleLevel(samp, uv + microOffset2, mipLevel); + float4 sample1 = tex.SampleLevel(samp, uv + microOffset1, adjustedMipLevel); + float4 sample2 = tex.SampleLevel(samp, uv + microOffset2, adjustedMipLevel); // Simple 2-sample blend weighted toward first sample return lerp(sample2, sample1, 0.65); @@ -128,8 +130,11 @@ inline float4 StochasticSampleLOD(float rnd, float mipLevel, Texture2D tex, Samp // Main stochastic sampling function inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) { + // Apply mip bias to match normal sampling behavior + float adjustedMipLevel = mipLevel + SharedData::MipBias; + // Take first sample (always needed) - float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, adjustedMipLevel); // Calculate smooth transition factor - starts blending at mip 2.5, fully single sample at mip 5.0 float mipFactor = saturate((mipLevel - 2.5) / 2.5); @@ -141,8 +146,8 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler } // Take remaining samples for blending - float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); - float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); + float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, adjustedMipLevel); + float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, adjustedMipLevel); // Full height-based blending for low mip levels (close terrain) float contrastFactor = HEIGHT_BLEND_CONTRAST * (1.0 - HEIGHT_INFLUENCE); @@ -154,9 +159,16 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler dot(sample2.rgb, LUMINANCE_WEIGHTS), dot(sample3.rgb, LUMINANCE_WEIGHTS) ); + + // Use alpha for height only for PBR systems, fallback to luminance for Complex Material + #if defined(TRUE_PBR) float3 alphaValues = float3(sample1.a, sample2.a, sample3.a); float3 alphaMask = step(0.001, alphaValues); float3 heights = lerp(luminanceHeights, alphaValues, alphaMask); + #else + // For Complex Material systems, use luminance-based height to avoid alpha channel conflicts + float3 heights = luminanceHeights; + #endif // Combined weight calculation and normalization float3 weights = NormalizeWeights(blendWeights * (1.0 + HEIGHT_INFLUENCE * heights)); @@ -171,8 +183,11 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler // Stochastic sampling function without height blending for better performance inline float4 StochasticEffectNoHeight(float rnd, float mipLevel, Texture2D tex, SamplerState samp, float2 uv, StochasticOffsets offsets, float2 dx, float2 dy) { + // Apply mip bias to match normal sampling behavior + float adjustedMipLevel = mipLevel + SharedData::MipBias; + // Take first sample (always needed) - float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, mipLevel); + float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, adjustedMipLevel); // Calculate smooth transition factor - starts blending at mip 2.5, fully single sample at mip 5.0 float mipFactor = saturate((mipLevel - 2.5) / 2.5); @@ -184,8 +199,8 @@ inline float4 StochasticEffectNoHeight(float rnd, float mipLevel, Texture2D tex, } // Take remaining samples for blending - float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, mipLevel); - float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, mipLevel); + float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, adjustedMipLevel); + float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, adjustedMipLevel); // Simple barycentric blend without height influence float3 weights = NormalizeWeights(saturate(offsets.weights)); diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 362e5fb904..46827f7267 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1287,7 +1287,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) } # endif // Calculate mip levels for terrain variation when parallax is disabled -# if defined(TERRAIN_VARIATION) && defined(EMAT) && defined(TRUE_PBR) +# if defined(TERRAIN_VARIATION) && defined(EMAT) if (useTerrainVariation && !SharedData::extendedMaterialSettings.EnableTerrainParallax) { // Calculate basic mip level for terrain textures mipLevels[0] = ExtendedMaterials::GetMipLevel(uv, TexColorSampler); From 098627b5edc12b32746af729e0f8f54c60fdef15 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 21 Jun 2025 00:41:46 +0000 Subject: [PATCH 52/53] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20pre-commi?= =?UTF-8?q?t.ci=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated formatting by clang-format, prettier, and other hooks. See https://pre-commit.ci for details. --- .../ExtendedMaterials/ExtendedMaterials.hlsli | 20 +++++++++---------- .../TerrainVariation/TerrainVariation.hlsli | 8 ++++---- src/Features/TerrainVariation.cpp | 1 - 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index bdef9e9050..606be2284a 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -96,25 +96,25 @@ namespace ExtendedMaterials weights[3] = w1.w; weights[4] = w2.x; weights[5] = w2.y; - + totalHeight = 0; [unroll] for (int i = 0; i < 6; i++) { totalHeight += heights[i] * weights[i]; weights[i] *= pow(heightBlend, HEIGHT_MULT * heights[i]); } - + [unroll] for (int i = 0; i < 6; i++) { weights[i] = min(100, pow(weights[i], heightBlend)); } - + float wsum = 0; [unroll] for (int i = 0; i < 6; i++) { wsum += weights[i]; } - + float invwsum = rcp(wsum); [unroll] for (int i = 0; i < 6; i++) { @@ -131,7 +131,7 @@ namespace ExtendedMaterials { float heightBlend = 1 + blendFactor * HEIGHT_POWER; float heights[6] = { 0, 0, 0, 0, 0, 0 }; - + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.01) { # if defined(TERRAIN_VARIATION) @@ -180,7 +180,7 @@ namespace ExtendedMaterials heights[5] = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); # endif } - + float total; ProcessTerrainHeightWeights(heightBlend, w1, w2, heights, weights, total); return total; } @@ -296,7 +296,7 @@ namespace ExtendedMaterials heights[5] = ScaleDisplacement(TexLandColor6Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).w, params[5]); # endif } - + float total; ProcessTerrainHeightWeights(heightBlend, w1, w2, heights, weights, total); return total; @@ -584,7 +584,7 @@ namespace ExtendedMaterials } return 1.0; } - + #if defined(LANDSCAPE) && defined(TERRAIN_VARIATION) // Overload for GetTerrainHeight WITHOUT StochasticOffsets (when enableTilingFix is false) # if defined(TRUE_PBR) @@ -617,7 +617,7 @@ namespace ExtendedMaterials { heights[5] = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); } - + float total; ProcessTerrainHeightWeights(heightBlend, w1, w2, heights, weights, total); return total; @@ -682,7 +682,7 @@ namespace ExtendedMaterials { heights[5] = ScaleDisplacement(TexLandColor6Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).w, params[5]); } - + float total; ProcessTerrainHeightWeights(heightBlend, w1, w2, heights, weights, total); return total; diff --git a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli index 2ff0b60b5e..76c9a0f770 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -133,7 +133,7 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler // Apply mip bias to match normal sampling behavior float adjustedMipLevel = mipLevel + SharedData::MipBias; - + // Take first sample (always needed) float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, adjustedMipLevel); @@ -160,7 +160,7 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler dot(sample2.rgb, LUMINANCE_WEIGHTS), dot(sample3.rgb, LUMINANCE_WEIGHTS) ); - + // Use alpha for height only for PBR systems, fallback to luminance for Complex Material #if defined(TRUE_PBR) float3 alphaValues = float3(sample1.a, sample2.a, sample3.a); @@ -170,7 +170,7 @@ inline float4 StochasticEffect(float rnd, float mipLevel, Texture2D tex, Sampler // For Complex Material systems, use luminance-based height to avoid alpha channel conflicts float3 heights = luminanceHeights; #endif - + // Combined weight calculation and normalization float3 weights = NormalizeWeights(blendWeights * (1.0 + HEIGHT_INFLUENCE * heights)); @@ -186,7 +186,7 @@ inline float4 StochasticEffectNoHeight(float rnd, float mipLevel, Texture2D tex, { // Apply mip bias to match normal sampling behavior float adjustedMipLevel = mipLevel + SharedData::MipBias; - + // Take first sample (always needed) float4 sample1 = tex.SampleLevel(samp, uv + offsets.offset1, adjustedMipLevel); diff --git a/src/Features/TerrainVariation.cpp b/src/Features/TerrainVariation.cpp index 91530eb54b..cb8d3198a1 100644 --- a/src/Features/TerrainVariation.cpp +++ b/src/Features/TerrainVariation.cpp @@ -88,4 +88,3 @@ bool TerrainVariation::DrawFailLoadMessage() const { return false; } - From f2a478e25582f58497a21de300961abda07d62b6 Mon Sep 17 00:00:00 2001 From: David Kehoe Date: Sat, 21 Jun 2025 12:05:22 +1000 Subject: [PATCH 53/53] fix for parallaxsoftshadow --- package/Shaders/Lighting.hlsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index cc40b1a966..1b51a502f3 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -2694,7 +2694,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # elif defined(LANDSCAPE) [branch] if (SharedData::extendedMaterialSettings.EnableTerrainParallax) # if defined(TERRAIN_VARIATION) - parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, lightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dx, dy, viewDistance); + parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, lightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dx, dy); # else parallaxShadow = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, lightDirectionTS, sh0, parallaxShadowQuality, screenNoise, displacementParams); # endif