diff --git a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli index 2a98c8e789..606be2284a 100644 --- a/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli +++ b/features/Extended Materials/Shaders/ExtendedMaterials/ExtendedMaterials.hlsli @@ -5,7 +5,7 @@ // 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) +#if defined(TERRAIN_VARIATION) # include "TerrainVariation/TerrainVariation.hlsli" #endif @@ -41,340 +41,264 @@ namespace ExtendedMaterials float2 textureDims; tex.GetDimensions(textureDims.x, textureDims.y); -#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(TERRAIN_VARIATION) + 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(VR) - mipLevel++; -#endif + #if !defined(PARALLAX) && !defined(TRUE_PBR) + mipLevel++; + #endif - return mipLevel; - } + #if defined(VR) + mipLevel++; + #endif + + #if defined(TERRAIN_VARIATION) + [branch] if (SharedData::extendedMaterialSettings.EnableTerrainParallax) + { + mipLevel++; + } + #endif + + return mipLevel; } #if defined(LANDSCAPE) -# 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]) +# 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) { - 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; - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.0) + 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) + 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) - 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]); + StochasticOffsets sharedOffset, float2 dx, float2 dy, # endif - total += h * weights[0]; - weights[0] *= pow(heightBlend, HEIGHT_MULT * h); - } - [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1HasDisplacement) != 0 && w1.y > 0.0) + out float weights[6]) + { + 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) - 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; + heights[0] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[0], TexLandDisplacement0Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[0]); # else - float h = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); + heights[0] = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); # 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::LandTile1HasDisplacement) != 0 && w1.y > 0.01) { # 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; + heights[1] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[1], TexLandDisplacement1Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[1]); # else - float h = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); + heights[1] = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); # endif - 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::LandTile2HasDisplacement) != 0 && w1.z > 0.01) { # 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; + heights[2] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[2], TexLandDisplacement2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[2]); # else - float h = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); + heights[2] = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); # 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::LandTile3HasDisplacement) != 0 && w1.w > 0.01) { # 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; + heights[3] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[3], TexLandDisplacement3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[3]); # else - float h = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); + heights[3] = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); # 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::LandTile4HasDisplacement) != 0 && w2.x > 0.01) { # 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; + heights[4] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[4], TexLandDisplacement4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).x, params[4]); # else - float h = ScaleDisplacement(TexLandDisplacement5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).x, params[5]); + heights[4] = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); # endif - total += h * weights[5]; - weights[5] *= pow(heightBlend, HEIGHT_MULT * h); } - [unroll] for (int i = 0; i < 6; i++) + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.01) { - 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; +# if defined(TERRAIN_VARIATION) + 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 } - 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, float distance, + StochasticOffsets sharedOffset, float2 dx, float2 dy, # endif 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; + if (w1.x > 0.01) { [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; - } + heights[0] = ScaleDisplacement(StochasticEffectNoHeight(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(StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy, distance).w, params[0]); - if (SharedData::terrainVariationSettings.enableTilingFix) - h *= SharedData::terrainVariationSettings.heightCompensationFactor; + heights[0] = ScaleDisplacement(StochasticEffectNoHeight(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; + if (w1.y > 0.01) { [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; + heights[1] = ScaleDisplacement(StochasticEffectNoHeight(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(StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy, distance).w, params[1]); - if (SharedData::terrainVariationSettings.enableTilingFix) - h *= SharedData::terrainVariationSettings.heightCompensationFactor; + heights[1] = ScaleDisplacement(StochasticEffectNoHeight(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; + if (w1.z > 0.01) { [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; + heights[2] = ScaleDisplacement(StochasticEffectNoHeight(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(StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy, distance).w, params[2]); - if (SharedData::terrainVariationSettings.enableTilingFix) - h *= SharedData::terrainVariationSettings.heightCompensationFactor; + heights[2] = ScaleDisplacement(StochasticEffectNoHeight(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); } - if (w1.w > 0.0) { - float h = 0.0; - [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0) - { - + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand3HasDisplacement) != 0 && w1.w > 0.01) + { # 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; + heights[3] = ScaleDisplacement(StochasticEffectNoHeight(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 - } - else - { + } + else if (w1.w > 0.01) + { # 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; + heights[3] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[3], TexLandColor4Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[3]); # else - h = ScaleDisplacement(TexLandColor4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).w, params[3]); + heights[3] = ScaleDisplacement(TexLandColor4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).w, 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) - { - + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand4HasDisplacement) != 0 && w2.x > 0.01) + { # 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; + heights[4] = ScaleDisplacement(StochasticEffectNoHeight(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 - } - else - { + } + else if (w2.x > 0.01) + { # 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; + heights[4] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[4], TexLandColor5Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[4]); # else - h = ScaleDisplacement(TexLandColor5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).w, params[4]); + heights[4] = ScaleDisplacement(TexLandColor5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).w, 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) - { - + [branch] if ((Permutation::ExtraFeatureDescriptor & Permutation::ExtraFeatureFlags::THLand5HasDisplacement) != 0 && w2.y > 0.01) + { # 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; + heights[5] = ScaleDisplacement(StochasticEffectNoHeight(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 - } - else - { + } + else if (w2.y > 0.01) + { # 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; + heights[5] = ScaleDisplacement(StochasticEffectNoHeight(screenNoise, mipLevels[5], TexLandColor6Sampler, SampTerrainParallaxSampler, coords, sharedOffset, dx, dy).w, params[5]); # else - h = ScaleDisplacement(TexLandColor6Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).w, params[5]); + heights[5] = ScaleDisplacement(TexLandColor6Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).w, 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 @@ -461,10 +385,10 @@ namespace ExtendedMaterials #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; + 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; @@ -473,10 +397,10 @@ namespace ExtendedMaterials # endif # 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; + 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; @@ -601,7 +525,7 @@ 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) + 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 @@ -612,19 +536,6 @@ namespace ExtendedMaterials 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))))); @@ -633,13 +544,13 @@ 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, distance, 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, distance, 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(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, distance, 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(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, distance, 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) @@ -652,13 +563,13 @@ namespace ExtendedMaterials 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); + 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, distance, 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(noise, input, coords + rayDir * multipliers.z, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, distance, 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(noise, input, coords + rayDir * multipliers.w, mipLevel, params, quality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, distance, 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) @@ -673,6 +584,292 @@ 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; + float heights[6] = { 0, 0, 0, 0, 0, 0 }; + + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0HasDisplacement) != 0 && w1.x > 0.0) + { + heights[0] = ScaleDisplacement(TexLandDisplacement0Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).x, params[0]); + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1HasDisplacement) != 0 && w1.y > 0.0) + { + heights[1] = ScaleDisplacement(TexLandDisplacement1Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).x, params[1]); + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2HasDisplacement) != 0 && w1.z > 0.0) + { + heights[2] = ScaleDisplacement(TexLandDisplacement2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).x, params[2]); + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3HasDisplacement) != 0 && w1.w > 0.0) + { + heights[3] = ScaleDisplacement(TexLandDisplacement3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).x, params[3]); + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4HasDisplacement) != 0 && w2.x > 0.0) + { + heights[4] = ScaleDisplacement(TexLandDisplacement4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).x, params[4]); + } + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5HasDisplacement) != 0 && w2.y > 0.0) + { + 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; + 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(TexColorSampler.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.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); + 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; +#endif // defined(LANDSCAPE) && defined(TERRAIN_VARIATION) + + 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 348003c0ec..76c9a0f770 100644 --- a/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli +++ b/features/Terrain Variation/Shaders/TerrainVariation/TerrainVariation.hlsli @@ -8,6 +8,20 @@ #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 = 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); +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); +// 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 { @@ -17,86 +31,185 @@ 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 FUNCTIONS --------------------- // + +// Hash function for stochastic sampling +inline float2 hash2D2D(float2 s) { - if (!SharedData::terrainVariationSettings.enableTilingFix) - return 0.0; + s = s * HASH_MULTIPLIER; + return frac(sin(s.x + s.y) * HASH_SINE_MULTIPLIER); +} - return saturate((distance - SharedData::terrainVariationSettings.startDistance) * - SharedData::terrainVariationSettings.invDistanceRange); +inline float2 hashLOD(float2 p) +{ + p = frac(p * 0.318); + return frac(p.x + p.y * 17.0); } -// Hash function for stochastic sampling -inline float2 hash2D2D(float2 s) +// Common barycentric coordinate calculation for stochastic sampling +inline float4x3 ComputeBarycentricVerts(float2 landscapeUV) { - // 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); - } + 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) +{ + 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; +} + +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); + + 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; + + // Simplified weights since we only use 2 samples now + offsetsLOD.weights = float3(0.65, 0.35, 0.0); + + return offsetsLOD; } -// Compute offsets for stochastic sampling -inline StochasticOffsets ComputeStochasticOffsets(float2 UV) +// --------------------- STOCHASTIC SAMPLING FUNCTIONS --------------------- // + +inline float3 NormalizeWeights(float3 weights) { - 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; + float rcpWeightSum = rcp(weights.x + weights.y + weights.z); + return weights * rcpWeightSum; +} + +// 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 + 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 = (offsetsLOD.offset1 + dir1) * offsetScale; + float2 microOffset2 = (offsetsLOD.offset2 + dir2) * offsetScale; + + // Sample only two offsets + 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); } // 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) +{ + + // 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); + + // 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, 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); + 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) + ); + + // 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)); + + // 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) { - // If feature is disabled, return standard sample - if (!SharedData::terrainVariationSettings.enableTilingFix) - return tex.SampleGrad(samp, uv, dx, dy); - - // Calculate distance factor (0 when close, 1 when far) - float distanceFactor = ComputeDistanceFactor(distance); - - 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); + // 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); + + // 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; } - // Weight samples according to offsets - float4 stochasticSample = sample1 * offsets.weights.x + - sample2 * offsets.weights.y + - sample3 * offsets.weights.z; + // Take remaining samples for blending + float4 sample2 = tex.SampleLevel(samp, uv + offsets.offset2, adjustedMipLevel); + float4 sample3 = tex.SampleLevel(samp, uv + offsets.offset3, adjustedMipLevel); - return lerp(standardSample, stochasticSample, distanceFactor); + // 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); } -#define StochasticSample(rnd, mipLevel, tex, samp, uv, dist) StochasticEffect(rnd, mipLevel, tex, samp, uv, ComputeStochasticOffsets(uv), ddx(uv), ddy(uv), dist).rgb + #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 a38b2cabc5..b306f92ede 100644 --- a/package/Shaders/Common/SharedData.hlsli +++ b/package/Shaders/Common/SharedData.hlsli @@ -165,13 +165,8 @@ namespace SharedData 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; + bool enableLODTerrainTilingFix; + float2 pad0; }; struct IBLSettings diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 2542bc8941..1b51a502f3 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1257,14 +1257,14 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) diffuseUv = ProjectedUVParams2.yy * input.TexCoord0.zw; # endif // SPARKLE -# if defined(LANDSCAPE) - // Normalise 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) { input.LandBlendWeights1 /= totalWeight; input.LandBlendWeights2.xy /= totalWeight; } + float3 blendedRGB = 0; float blendedAlpha = 0; float3 blendedNormalRGB = 0; @@ -1273,19 +1273,31 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # 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 + // Compute stochastic offsets and derivatives once for all layers (only when terrain variation is enabled) # if defined(TERRAIN_VARIATION) - float2 dx = ddx(uv); - float2 dy = ddy(uv); - StochasticOffsets sharedOffset = ComputeStochasticOffsets(uv); -# else - distanceFactor = saturate(viewDistance * 0.00048828125); + 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 +// Calculate mip levels for terrain variation when parallax is disabled +# if defined(TERRAIN_VARIATION) && defined(EMAT) + 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); @@ -1308,13 +1320,20 @@ 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) - uv = ExtendedMaterials::GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, displacementParams, sharedOffset, dx, dy, pixelOffset, weights); + [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); + } # 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]; @@ -1325,8 +1344,14 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) } 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); + [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); + } # else sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); # endif @@ -1344,11 +1369,8 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) 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,296 +1383,485 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(LANDSCAPE) // Layer 1 (LandBlendWeights1.x) if (input.LandBlendWeights1.x > 0.01) { - float weight = input.LandBlendWeights1.x * invwsum; + float weight = input.LandBlendWeights1.x; + + // Sample diffuse texture for layer 1 # if defined(TERRAIN_VARIATION) - float4 diffuse1 = StochasticEffect(screenNoise, mipLevels[0], TexColorSampler, SampColorSampler, uv, sharedOffset, dx, dy, viewDistance); + 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 - 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); + float4 landColor1 = TexColorSampler.SampleBias(SampColorSampler, uv, SharedData::MipBias); # endif - float3 diffuseRGB1 = diffuse1.rgb; + float3 landColorRGB1 = landColor1.rgb; # if defined(TRUE_PBR) [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0PBR) == 0) { - diffuseRGB1 = diffuseRGB1 / Color::PBRLightingScale; + landColorRGB1 = landColorRGB1 / Color::PBRLightingScale; } # endif - float alpha1 = diffuse1.a; + float landAlpha1 = landColor1.a; + float landSnowMask1 = GetLandSnowMaskValue(landColor1.w); + // Sample normal texture for layer 1 # if defined(TERRAIN_VARIATION) - float4 normal1 = StochasticEffect(screenNoise, mipLevels[0], TexNormalSampler, SampNormalSampler, uv, sharedOffset, dx, dy, viewDistance); + 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 normal1 = lerp( - TexNormalSampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), - TexNormalSampler.SampleLevel(SampNormalSampler, uv, distanceFactor * 3.0), - distanceFactor); + float4 landNormal1 = TexNormalSampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias); # endif - float3 normalRGB1 = normal1.rgb; - float normalAlpha1 = normal1.a; + 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 landRMAOS1; + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile0PBR) != 0) + { # if defined(TERRAIN_VARIATION) - float4 rmaos1 = StochasticEffect(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, viewDistance); + [branch] if (useTerrainVariation) + { + landRMAOS1 = StochasticEffectNoHeight(screenNoise, mipLevels[0], TexRMAOSSampler, SampRMAOSSampler, uv, sharedOffset, dx, dy) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + } + else + { + landRMAOS1 = TexRMAOSSampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); + } # else - float4 rmaos1 = lerp( - TexRMAOSSampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), - TexRMAOSSampler.SampleLevel(SampRMAOSSampler, uv, distanceFactor * 3.0), - distanceFactor); + landRMAOS1 = TexRMAOSSampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias) * float4(PBRParams1.x, 1, 1, PBRParams1.z); # endif - rmaos1 *= float4(PBRParams1.x, 1, 1, PBRParams1.z); - blendedRMAOS += rmaos1 * weight; // Blending Within Layers (Same for the rest of layers 2-6) + if ((PBRFlags & PBR::TerrainFlags::LandTile0HasGlint) != 0) { + glintParameters += input.LandBlendWeights1.x * LandscapeTexture1GlintParameters; + } + } + else + { + landRMAOS1 = float4(1 - landNormal1.w, 0, 1, 0); + } + blendedRMAOS += landRMAOS1 * weight; # endif - blendedRGB += diffuseRGB1 * weight; - blendedAlpha += alpha1 * weight; - blendedNormalRGB += normalRGB1 * weight; - blendedNormalAlpha += normalAlpha1 * weight; + 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; + float weight = input.LandBlendWeights1.y; + + // Sample diffuse texture for layer 2 # if defined(TERRAIN_VARIATION) - float4 diffuse2 = StochasticEffect(screenNoise, mipLevels[1], TexLandColor2Sampler, SampColorSampler, uv, sharedOffset, dx, dy, viewDistance); + 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 - 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); + float4 landColor2 = TexLandColor2Sampler.SampleBias(SampLandColor2Sampler, uv, SharedData::MipBias); # endif - float3 diffuseRGB2 = diffuse2.rgb; + float3 landColorRGB2 = landColor2.rgb; # if defined(TRUE_PBR) [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1PBR) == 0) { - diffuseRGB2 = diffuseRGB2 / Color::PBRLightingScale; + landColorRGB2 = landColorRGB2 / Color::PBRLightingScale; } # endif - float alpha2 = diffuse2.a; + float landAlpha2 = landColor2.a; + float landSnowMask2 = GetLandSnowMaskValue(landColor2.w); + // Sample normal texture for layer 2 # if defined(TERRAIN_VARIATION) - float4 normal2 = StochasticEffect(screenNoise, mipLevels[1], TexLandNormal2Sampler, SampNormalSampler, uv, sharedOffset, dx, dy, viewDistance); + 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 normal2 = lerp( - TexLandNormal2Sampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), - TexLandNormal2Sampler.SampleLevel(SampNormalSampler, uv, distanceFactor * 3.0), - distanceFactor); + float4 landNormal2 = TexLandNormal2Sampler.SampleBias(SampLandNormal2Sampler, uv, SharedData::MipBias); # endif - float3 normalRGB2 = normal2.rgb; - float normalAlpha2 = normal2.a; + float3 landNormalRGB2 = landNormal2.rgb; + float landNormalAlpha2 = landNormal2.a; +# 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 landRMAOS2; + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile1PBR) != 0) + { # if defined(TERRAIN_VARIATION) - float4 rmaos2 = StochasticEffect(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, viewDistance); + [branch] if (useTerrainVariation) + { + landRMAOS2 = StochasticEffectNoHeight(screenNoise, mipLevels[1], TexLandRMAOS2Sampler, SampLandRMAOS2Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); + } + else + { + landRMAOS2 = TexLandRMAOS2Sampler.SampleBias(SampLandRMAOS2Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); + } # else - float4 rmaos2 = lerp( - TexLandRMAOS2Sampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), - TexLandRMAOS2Sampler.SampleLevel(SampRMAOSSampler, uv, distanceFactor * 3.0), - distanceFactor); + landRMAOS2 = TexLandRMAOS2Sampler.SampleBias(SampLandRMAOS2Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); # endif - rmaos2 *= float4(LandscapeTexture2PBRParams.x, 1, 1, LandscapeTexture2PBRParams.z); - blendedRMAOS += rmaos2 * weight; + if ((PBRFlags & PBR::TerrainFlags::LandTile1HasGlint) != 0) { + glintParameters += input.LandBlendWeights1.y * LandscapeTexture2GlintParameters; + } + } + else + { + landRMAOS2 = float4(1 - landNormal2.w, 0, 1, 0); + } + blendedRMAOS += landRMAOS2 * weight; # endif - blendedRGB += diffuseRGB2 * weight; - blendedAlpha += alpha2 * weight; - blendedNormalRGB += normalRGB2 * weight; - blendedNormalAlpha += normalAlpha2 * weight; + 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; + float weight = input.LandBlendWeights1.z; + // Sample diffuse texture for layer 3 # if defined(TERRAIN_VARIATION) - float4 diffuse3 = StochasticEffect(screenNoise, mipLevels[2], TexLandColor3Sampler, SampColorSampler, uv, sharedOffset, dx, dy, viewDistance); + 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 - 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); + float4 landColor3 = TexLandColor3Sampler.SampleBias(SampLandColor3Sampler, uv, SharedData::MipBias); # endif - float3 diffuseRGB3 = diffuse3.rgb; + float3 landColorRGB3 = landColor3.rgb; # if defined(TRUE_PBR) [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2PBR) == 0) { - diffuseRGB3 = diffuseRGB3 / Color::PBRLightingScale; + landColorRGB3 = landColorRGB3 / Color::PBRLightingScale; } # endif - float alpha3 = diffuse3.a; + float landAlpha3 = landColor3.a; + float landSnowMask3 = GetLandSnowMaskValue(landColor3.w); + // Sample normal texture for layer 3 # if defined(TERRAIN_VARIATION) - float4 normal3 = StochasticEffect(screenNoise, mipLevels[2], TexLandNormal3Sampler, SampNormalSampler, uv, sharedOffset, dx, dy, viewDistance); + 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 normal3 = lerp( - TexLandNormal3Sampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), - TexLandNormal3Sampler.SampleLevel(SampNormalSampler, uv, distanceFactor * 3.0), - distanceFactor); + float4 landNormal3 = TexLandNormal3Sampler.SampleBias(SampLandNormal3Sampler, uv, SharedData::MipBias); # endif - float3 normalRGB3 = normal3.rgb; - float normalAlpha3 = normal3.a; + float3 landNormalRGB3 = landNormal3.rgb; + float landNormalAlpha3 = landNormal3.a; +# if defined(SNOW) && !defined(TRUE_PBR) + landSnowMask += LandscapeTexture1to4IsSnow.z * input.LandBlendWeights1.z * landSnowMask3; +# endif // SNOW + + // Sample RMAOS texture for layer 3 # if defined(TRUE_PBR) + float4 landRMAOS3; + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile2PBR) != 0) + { # if defined(TERRAIN_VARIATION) - float4 rmaos3 = StochasticEffect(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, viewDistance); + [branch] if (useTerrainVariation) + { + landRMAOS3 = StochasticEffectNoHeight(screenNoise, mipLevels[2], TexLandRMAOS3Sampler, SampLandRMAOS3Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); + } + else + { + landRMAOS3 = TexLandRMAOS3Sampler.SampleBias(SampLandRMAOS3Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); + } # else - float4 rmaos3 = lerp( - TexLandRMAOS3Sampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), - TexLandRMAOS3Sampler.SampleLevel(SampRMAOSSampler, uv, distanceFactor * 3.0), - distanceFactor); + landRMAOS3 = TexLandRMAOS3Sampler.SampleBias(SampLandRMAOS3Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); # endif - rmaos3 *= float4(LandscapeTexture3PBRParams.x, 1, 1, LandscapeTexture3PBRParams.z); - blendedRMAOS += rmaos3 * weight; + if ((PBRFlags & PBR::TerrainFlags::LandTile2HasGlint) != 0) { + glintParameters += input.LandBlendWeights1.z * LandscapeTexture3GlintParameters; + } + } + else + { + landRMAOS3 = float4(1 - landNormal3.w, 0, 1, 0); + } + blendedRMAOS += landRMAOS3 * weight; # endif - blendedRGB += diffuseRGB3 * weight; - blendedAlpha += alpha3 * weight; - blendedNormalRGB += normalRGB3 * weight; - blendedNormalAlpha += normalAlpha3 * weight; + 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; + float weight = input.LandBlendWeights1.w; + + // Sample diffuse texture for layer 4 # if defined(TERRAIN_VARIATION) - float4 diffuse4 = StochasticEffect(screenNoise, mipLevels[3], TexLandColor4Sampler, SampColorSampler, uv, sharedOffset, dx, dy, viewDistance); + 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 - 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); + float4 landColor4 = TexLandColor4Sampler.SampleBias(SampLandColor4Sampler, uv, SharedData::MipBias); # endif - float3 diffuseRGB4 = diffuse4.rgb; + float3 landColorRGB4 = landColor4.rgb; # if defined(TRUE_PBR) [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3PBR) == 0) { - diffuseRGB4 = diffuseRGB4 / Color::PBRLightingScale; + landColorRGB4 = landColorRGB4 / Color::PBRLightingScale; } # endif - float alpha4 = diffuse4.a; + float landAlpha4 = landColor4.a; + float landSnowMask4 = GetLandSnowMaskValue(landColor4.w); + // Sample normal texture for layer 4 # if defined(TERRAIN_VARIATION) - float4 normal4 = StochasticEffect(screenNoise, mipLevels[3], TexLandNormal4Sampler, SampNormalSampler, uv, sharedOffset, dx, dy, viewDistance); + 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 normal4 = lerp( - TexLandNormal4Sampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), - TexLandNormal4Sampler.SampleLevel(SampNormalSampler, uv, distanceFactor * 3.0), - distanceFactor); + float4 landNormal4 = TexLandNormal4Sampler.SampleBias(SampLandNormal4Sampler, uv, SharedData::MipBias); # endif - float3 normalRGB4 = normal4.rgb; - float normalAlpha4 = normal4.a; + float3 landNormalRGB4 = landNormal4.rgb; + float landNormalAlpha4 = landNormal4.a; +# if defined(SNOW) && !defined(TRUE_PBR) + landSnowMask += LandscapeTexture1to4IsSnow.w * input.LandBlendWeights1.w * landSnowMask4; +# endif // SNOW + + // Sample RMAOS texture for layer 4 # if defined(TRUE_PBR) + float4 landRMAOS4; + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile3PBR) != 0) + { # if defined(TERRAIN_VARIATION) - float4 rmaos4 = StochasticEffect(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, viewDistance); + [branch] if (useTerrainVariation) + { + landRMAOS4 = StochasticEffectNoHeight(screenNoise, mipLevels[3], TexLandRMAOS4Sampler, SampLandRMAOS4Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); + } + else + { + landRMAOS4 = TexLandRMAOS4Sampler.SampleBias(SampLandRMAOS4Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); + } # else - float4 rmaos4 = lerp( - TexLandRMAOS4Sampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), - TexLandRMAOS4Sampler.SampleLevel(SampRMAOSSampler, uv, distanceFactor * 3.0), - distanceFactor); + landRMAOS4 = TexLandRMAOS4Sampler.SampleBias(SampLandRMAOS4Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); # endif - rmaos4 *= float4(LandscapeTexture4PBRParams.x, 1, 1, LandscapeTexture4PBRParams.z); - blendedRMAOS += rmaos4 * weight; + if ((PBRFlags & PBR::TerrainFlags::LandTile3HasGlint) != 0) { + glintParameters += input.LandBlendWeights1.w * LandscapeTexture4GlintParameters; + } + } + else + { + landRMAOS4 = float4(1 - landNormal4.w, 0, 1, 0); + } + blendedRMAOS += landRMAOS4 * weight; # endif - blendedRGB += diffuseRGB4 * weight; - blendedAlpha += alpha4 * weight; - blendedNormalRGB += normalRGB4 * weight; - blendedNormalAlpha += normalAlpha4 * weight; + 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; + float weight = input.LandBlendWeights2.x; + // Sample diffuse texture for layer 5 # if defined(TERRAIN_VARIATION) - float4 diffuse5 = StochasticEffect(screenNoise, mipLevels[4], TexLandColor5Sampler, SampColorSampler, uv, sharedOffset, dx, dy, viewDistance); + 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 - 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); + float4 landColor5 = TexLandColor5Sampler.SampleBias(SampLandColor5Sampler, uv, SharedData::MipBias); # endif - float3 diffuseRGB5 = diffuse5.rgb; + float3 landColorRGB5 = landColor5.rgb; # if defined(TRUE_PBR) [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4PBR) == 0) { - diffuseRGB5 = diffuseRGB5 / Color::PBRLightingScale; + landColorRGB5 = landColorRGB5 / Color::PBRLightingScale; } # endif - float alpha5 = diffuse5.a; + float landAlpha5 = landColor5.a; + float landSnowMask5 = GetLandSnowMaskValue(landColor5.w); + // Sample normal texture for layer 5 # if defined(TERRAIN_VARIATION) - float4 normal5 = StochasticEffect(screenNoise, mipLevels[4], TexLandNormal5Sampler, SampNormalSampler, uv, sharedOffset, dx, dy, viewDistance); + 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 normal5 = lerp( - TexLandNormal5Sampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), - TexLandNormal5Sampler.SampleLevel(SampNormalSampler, uv, distanceFactor * 3.0), - distanceFactor); + float4 landNormal5 = TexLandNormal5Sampler.SampleBias(SampLandNormal5Sampler, uv, SharedData::MipBias); # endif - float3 normalRGB5 = normal5.rgb; - float normalAlpha5 = normal5.a; + float3 landNormalRGB5 = landNormal5.rgb; + float landNormalAlpha5 = landNormal5.a; + +# if defined(SNOW) && !defined(TRUE_PBR) + landSnowMask += LandscapeTexture5to6IsSnow.x * input.LandBlendWeights2.x * landSnowMask5; +# endif // SNOW + + // Sample RMAOS texture for layer 5 # if defined(TRUE_PBR) + float4 landRMAOS5; + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile4PBR) != 0) + { # if defined(TERRAIN_VARIATION) - float4 rmaos5 = StochasticEffect(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, viewDistance); + [branch] if (useTerrainVariation) + { + landRMAOS5 = StochasticEffectNoHeight(screenNoise, mipLevels[4], TexLandRMAOS5Sampler, SampLandRMAOS5Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); + } + else + { + landRMAOS5 = TexLandRMAOS5Sampler.SampleBias(SampLandRMAOS5Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); + } # else - float4 rmaos5 = lerp( - TexLandRMAOS5Sampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), - TexLandRMAOS5Sampler.SampleLevel(SampRMAOSSampler, uv, distanceFactor * 3.0), - distanceFactor); + landRMAOS5 = TexLandRMAOS5Sampler.SampleBias(SampLandRMAOS5Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); # endif - rmaos5 *= float4(LandscapeTexture5PBRParams.x, 1, 1, LandscapeTexture5PBRParams.z); - blendedRMAOS += rmaos5 * weight; + if ((PBRFlags & PBR::TerrainFlags::LandTile4HasGlint) != 0) { + glintParameters += input.LandBlendWeights2.x * LandscapeTexture5GlintParameters; + } + } + else + { + landRMAOS5 = float4(1 - landNormal5.w, 0, 1, 0); + } + blendedRMAOS += landRMAOS5 * weight; # endif - blendedRGB += diffuseRGB5 * weight; - blendedAlpha += alpha5 * weight; - blendedNormalRGB += normalRGB5 * weight; - blendedNormalAlpha += normalAlpha5 * weight; + 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; + float weight = input.LandBlendWeights2.y; + + // Sample layer 6 textures # if defined(TERRAIN_VARIATION) - float4 diffuse6 = StochasticEffect(screenNoise, mipLevels[5], TexLandColor6Sampler, SampColorSampler, uv, sharedOffset, dx, dy, viewDistance); + 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 - 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); + float4 landColor6 = TexLandColor6Sampler.SampleBias(SampLandColor6Sampler, uv, SharedData::MipBias); # endif - float3 diffuseRGB6 = diffuse6.rgb; + float3 landColorRGB6 = landColor6.rgb; # if defined(TRUE_PBR) [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5PBR) == 0) { - diffuseRGB6 = diffuseRGB6 / Color::PBRLightingScale; + landColorRGB6 = landColorRGB6 / Color::PBRLightingScale; } # endif - float alpha6 = diffuse6.a; + float landAlpha6 = landColor6.a; + float landSnowMask6 = GetLandSnowMaskValue(landColor6.w); + // Sample normal texture for layer 6 # if defined(TERRAIN_VARIATION) - float4 normal6 = StochasticEffect(screenNoise, mipLevels[5], TexLandNormal6Sampler, SampNormalSampler, uv, sharedOffset, dx, dy, viewDistance); + 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 normal6 = lerp( - TexLandNormal6Sampler.SampleBias(SampNormalSampler, uv, SharedData::MipBias), - TexLandNormal6Sampler.SampleLevel(SampNormalSampler, uv, distanceFactor * 3.0), - distanceFactor); + float4 landNormal6 = TexLandNormal6Sampler.SampleBias(SampLandNormal6Sampler, uv, SharedData::MipBias); # endif - float3 normalRGB6 = normal6.rgb; - float normalAlpha6 = normal6.a; + float3 landNormalRGB6 = landNormal6.rgb; + float landNormalAlpha6 = landNormal6.a; +# if defined(SNOW) && !defined(TRUE_PBR) + landSnowMask += LandscapeTexture5to6IsSnow.y * input.LandBlendWeights2.y * landSnowMask6; +# endif // SNOW + + // Sample RMAOS texture for layer 6 # if defined(TRUE_PBR) + float4 landRMAOS6; + [branch] if ((PBRFlags & PBR::TerrainFlags::LandTile5PBR) != 0) + { # if defined(TERRAIN_VARIATION) - float4 rmaos6 = StochasticEffect(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampRMAOSSampler, uv, sharedOffset, dx, dy, viewDistance); + [branch] if (useTerrainVariation) + { + landRMAOS6 = StochasticEffectNoHeight(screenNoise, mipLevels[5], TexLandRMAOS6Sampler, SampLandRMAOS6Sampler, uv, sharedOffset, dx, dy) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); + } + else + { + landRMAOS6 = TexLandRMAOS6Sampler.SampleBias(SampLandRMAOS6Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); + } # else - float4 rmaos6 = lerp( - TexLandRMAOS6Sampler.SampleBias(SampRMAOSSampler, uv, SharedData::MipBias), - TexLandRMAOS6Sampler.SampleLevel(SampRMAOSSampler, uv, distanceFactor * 3.0), - distanceFactor); + landRMAOS6 = TexLandRMAOS6Sampler.SampleBias(SampLandRMAOS6Sampler, uv, SharedData::MipBias) * float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); # endif - rmaos6 *= float4(LandscapeTexture6PBRParams.x, 1, 1, LandscapeTexture6PBRParams.z); - blendedRMAOS += rmaos6 * weight; + if ((PBRFlags & PBR::TerrainFlags::LandTile5HasGlint) != 0) { + glintParameters += input.LandBlendWeights2.y * LandscapeTexture6GlintParameters; + } + } + else + { + landRMAOS6 = float4(1 - landNormal6.w, 0, 1, 0); + } + blendedRMAOS += landRMAOS6 * weight; # endif - blendedRGB += diffuseRGB6 * weight; - blendedAlpha += alpha6 * weight; - blendedNormalRGB += normalRGB6 * weight; - blendedNormalAlpha += normalAlpha6 * weight; + blendedRGB += landColorRGB6 * weight; + blendedAlpha += landAlpha6 * weight; + blendedNormalRGB += landNormalRGB6 * weight; + blendedNormalAlpha += landNormalAlpha6 * weight; } float4 rawBaseColor = float4(blendedRGB, blendedAlpha); @@ -1659,34 +1870,39 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(TRUE_PBR) rawRMAOS = blendedRMAOS; # endif -# 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) 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) # if defined(LODOBJECTS) || defined(LODOBJECTSHD) 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; # endif # endif // LOD_BLENDING - float landSnowMask1 = GetLandSnowMaskValue(baseColor.w); - # if defined(MODELSPACENORMALS) # if defined(LODLANDNOISE) normal.xyz = normal.xzy - 0.5.xxx; @@ -1719,93 +1935,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # 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) @@ -1839,10 +1969,27 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # 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 = StochasticSampleLOD(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; # 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); @@ -2267,11 +2414,20 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) [branch] if (SharedData::extendedMaterialSettings.EnableTerrainParallax) { # if defined(TERRAIN_VARIATION) - float weights[6]; + [branch] if (useTerrainVariation) + { + float weights[6]; + sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); - 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); + } + 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, viewDistance); + 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); @@ -2538,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 @@ -3256,4 +3412,4 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) 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 83e8b53a37..cb8d3198a1 100644 --- a/src/Features/TerrainVariation.cpp +++ b/src/Features/TerrainVariation.cpp @@ -7,11 +7,7 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT( TerrainVariation::Settings, enableTilingFix, - startDistance, - maxDistance, - heightCompensationFactor, - shadowRayDirFactor, - hashQuality) + enableLODTerrainTilingFix) void TerrainVariation::DrawSettings() { @@ -22,74 +18,32 @@ 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."); + 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); } - - 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."); + "Applies the tiling fix to LOD terrain objects.\n" + "This helps reduce the visible tiling effect on distant terrain."); } - 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 - } + ImGui::Separator(); - 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."); - } - } + bool paramsChanged = false; 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 +56,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); @@ -137,7 +79,12 @@ void TerrainVariation::SaveSettings(json& o_json) o_json = settings; } +void TerrainVariation::RestoreDefaultSettings() +{ + settings = {}; +} + bool TerrainVariation::DrawFailLoadMessage() const { return false; -} \ No newline at end of file +} diff --git a/src/Features/TerrainVariation.h b/src/Features/TerrainVariation.h index 51b61eb41f..c06064e063 100644 --- a/src/Features/TerrainVariation.h +++ b/src/Features/TerrainVariation.h @@ -15,7 +15,10 @@ struct TerrainVariation : Feature virtual inline std::string GetShortName() override { return "TerrainVariation"; } virtual inline std::string GetFeatureModLink() override { return MakeNexusModURL(MOD_ID); } 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 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; } virtual std::string_view GetCategory() const override { return "Landscape & Textures"; } @@ -32,40 +35,18 @@ struct TerrainVariation : Feature }; } - struct Settings + struct alignas(16) 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; - }; - - 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 - }; + 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 RestoreDefaultSettings() override; virtual void PostPostLoad() override; void UpdateShaderSettings(); diff --git a/src/ShaderCache.cpp b/src/ShaderCache.cpp index 0f05860137..64f3b10238 100644 --- a/src/ShaderCache.cpp +++ b/src/ShaderCache.cpp @@ -2724,4 +2724,4 @@ namespace SIE queue.push_back({ watchid, dir, filename, action, oldFilename }); } } -} \ No newline at end of file +}