Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Use parallax in landscape texture blending #338

Merged
merged 11 commits into from
Jul 17, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -33,28 +33,51 @@ float GetMipLevel(float2 coords, Texture2D<float4> tex)
}

#if defined(LANDSCAPE)
# define HEIGHT_POWER 4.0
# define INV_HEIGHT_POWER 0.25

float GetTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6])
float GetTerrainHeight(PS_INPUT input, float2 coords, float mipLevels[6], float blendFactor, out float pixelOffset[6])
{
float height = 0.0;
if (input.LandBlendWeights1.x > 0.0)
height = TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w * input.LandBlendWeights1.x;
pixelOffset[0] = pow(input.LandBlendWeights1.x, 1 + 1 * blendFactor) * (pow(TexColorSampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[0]).w, blendFactor * HEIGHT_POWER));
ThePagi marked this conversation as resolved.
Show resolved Hide resolved
else
pixelOffset[0] = 0;
Copy link
Collaborator

@Pentalimbed Pentalimbed Jul 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same above, instead of branching here initialize the whole pixelOffset array to zero beforehand and save some elses. Or use inout on the argument since it is already initialised outside the function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made it a bit nicer. Idk if there is a faster way to zero-initialize, but I can't leave old values there with inout, otherwise they will be used when weight is 0.

if (input.LandBlendWeights1.y > 0.0)
height += TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w * input.LandBlendWeights1.y;
pixelOffset[1] = pow(input.LandBlendWeights1.y, 1 + 1 * blendFactor) * (pow(TexLandColor2Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[1]).w, blendFactor * HEIGHT_POWER));
else
pixelOffset[1] = 0;
if (input.LandBlendWeights1.z > 0.0)
height += TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w * input.LandBlendWeights1.z;
pixelOffset[2] = pow(input.LandBlendWeights1.z, 1 + 1 * blendFactor) * (pow(TexLandColor3Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[2]).w, blendFactor * HEIGHT_POWER));
else
pixelOffset[2] = 0;
if (input.LandBlendWeights1.w > 0.0)
height += TexLandColor4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).w * input.LandBlendWeights1.w;
pixelOffset[3] = pow(input.LandBlendWeights1.w, 1 + 1 * blendFactor) * (pow(TexLandColor4Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[3]).w, blendFactor * HEIGHT_POWER));
else
pixelOffset[3] = 0;
if (input.LandBlendWeights2.x > 0.0)
height += TexLandColor5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).w * input.LandBlendWeights2.x;
pixelOffset[4] = pow(input.LandBlendWeights2.x, 1 + 1 * blendFactor) * (pow(TexLandColor5Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[4]).w, blendFactor * HEIGHT_POWER));
else
pixelOffset[4] = 0;
if (input.LandBlendWeights2.y > 0.0)
height += TexLandColor6Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).w * input.LandBlendWeights2.y;
return height;
pixelOffset[5] = pow(input.LandBlendWeights2.y, 1 + 1 * blendFactor) * (pow(TexLandColor6Sampler.SampleLevel(SampTerrainParallaxSampler, coords, mipLevels[5]).w, blendFactor * HEIGHT_POWER));
else
pixelOffset[5] = 0;
float total = 0;
[unroll] for (int i = 0; i < 6; i++)
{
total += pixelOffset[i];
}
float invtotal = rcp(total);
[unroll] for (int i = 0; i < 6; i++)
{
pixelOffset[i] *= invtotal;
}
return pow(total, INV_HEIGHT_POWER * rcp(blendFactor));
}
#endif

#if defined(LANDSCAPE)
float2 GetParallaxCoords(PS_INPUT input, float distance, float2 coords, float mipLevels[6], float3 viewDir, float3x3 tbn, float noise, out float pixelOffset)
float2 GetParallaxCoords(PS_INPUT input, float distance, float2 coords, float mipLevels[6], float3 viewDir, float3x3 tbn, float noise, out float pixelOffset, out float heights[6])
#else
float2 GetParallaxCoords(float distance, float2 coords, float mipLevel, float3 viewDir, float3x3 tbn, float noise, Texture2D<float4> tex, SamplerState texSampler, uint channel, out float pixelOffset)
#endif
Expand All @@ -63,6 +86,10 @@ float2 GetParallaxCoords(float distance, float2 coords, float mipLevel, float3 v
viewDirTS.xy /= viewDirTS.z * 0.7 + 0.3; // Fix for objects at extreme viewing angles

float nearBlendToFar = saturate(distance / 2048.0);
#if defined(LANDSCAPE)
// When CPM flag is disabled, will use linear blending as before.
float blendFactor = extendedMaterialSettings.EnableComplexMaterial ? saturate(1 - nearBlendToFar) : INV_HEIGHT_POWER;
#endif

float maxHeight = 0.1;
float minHeight = maxHeight * 0.5;
Expand Down Expand Up @@ -91,10 +118,10 @@ float2 GetParallaxCoords(float distance, float2 coords, float mipLevel, float3 v

#if defined(LANDSCAPE)
float4 currHeight;
currHeight.x = GetTerrainHeight(input, currentOffset[0].xy, mipLevels);
currHeight.y = GetTerrainHeight(input, currentOffset[0].zw, mipLevels);
currHeight.z = GetTerrainHeight(input, currentOffset[1].xy, mipLevels);
currHeight.w = GetTerrainHeight(input, currentOffset[1].zw, mipLevels);
currHeight.x = GetTerrainHeight(input, currentOffset[0].xy, mipLevels, blendFactor, heights);
currHeight.y = GetTerrainHeight(input, currentOffset[0].zw, mipLevels, blendFactor, heights);
currHeight.z = GetTerrainHeight(input, currentOffset[1].xy, mipLevels, blendFactor, heights);
currHeight.w = GetTerrainHeight(input, currentOffset[1].zw, mipLevels, blendFactor, heights);
#else
float4 currHeight;
currHeight.x = tex.SampleLevel(texSampler, currentOffset[0].xy, mipLevel)[channel];
Expand Down Expand Up @@ -156,6 +183,15 @@ float2 GetParallaxCoords(float distance, float2 coords, float mipLevel, float3 v
return lerp(viewDirTS.xy * offset + coords.xy, coords, nearBlendToFar);
}

#if defined(LANDSCAPE)
heights[0] = input.LandBlendWeights1.x;
heights[1] = input.LandBlendWeights1.y;
heights[2] = input.LandBlendWeights1.z;
heights[3] = input.LandBlendWeights1.w;
heights[4] = input.LandBlendWeights2.x;
heights[5] = input.LandBlendWeights2.y;
#endif

pixelOffset = 0.5;
return coords;
}
Expand Down Expand Up @@ -186,10 +222,11 @@ float GetParallaxSoftShadowMultiplierTerrain(PS_INPUT input, float2 coords, floa
float2 rayDir = L.xy * 0.1;
float4 multipliers = rcp((float4(4, 3, 2, 1) + noise));
float4 sh;
sh.x = GetTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel);
sh.y = GetTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel);
sh.z = GetTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel);
sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel);
float heights[6] = { 0, 0, 0, 0, 0, 0 };
sh.x = GetTerrainHeight(input, coords + rayDir * multipliers.x, mipLevel, quality, heights);
sh.y = GetTerrainHeight(input, coords + rayDir * multipliers.y, mipLevel, quality, heights);
sh.z = GetTerrainHeight(input, coords + rayDir * multipliers.z, mipLevel, quality, heights);
sh.w = GetTerrainHeight(input, coords + rayDir * multipliers.w, mipLevel, quality, heights);
return 1.0 - saturate(dot(max(0, sh - sh0), 1.0) * 2.0) * quality;
}
return 1.0;
Expand Down
16 changes: 13 additions & 3 deletions package/Shaders/Lighting.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -1087,9 +1087,19 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace
mipLevels[3] = GetMipLevel(uv, TexLandColor4Sampler);
mipLevels[4] = GetMipLevel(uv, TexLandColor5Sampler);
mipLevels[5] = GetMipLevel(uv, TexLandColor6Sampler);
uv = GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, pixelOffset);
if (extendedMaterialSettings.EnableShadows && parallaxShadowQuality > 0.0f)
sh0 = GetTerrainHeight(input, uv, mipLevels);
float weights[6];
uv = GetParallaxCoords(input, viewPosition.z, uv, mipLevels, viewDirection, tbnTr, screenNoise, pixelOffset, weights);
if (extendedMaterialSettings.EnableComplexMaterial) {
input.LandBlendWeights1.x = weights[0];
input.LandBlendWeights1.y = weights[1];
input.LandBlendWeights1.z = weights[2];
input.LandBlendWeights1.w = weights[3];
input.LandBlendWeights2.x = weights[4];
input.LandBlendWeights2.y = weights[5];
}
if (extendedMaterialSettings.EnableShadows && parallaxShadowQuality > 0.0f) {
sh0 = GetTerrainHeight(input, uv, mipLevels, parallaxShadowQuality, weights);
}
}
# endif // EMAT
# endif // LANDSCAPE
Expand Down