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

Implement normal-offset bias for shadow mapping #100

Closed
darksylinc opened this issue Jun 9, 2020 · 0 comments
Closed

Implement normal-offset bias for shadow mapping #100

darksylinc opened this issue Jun 9, 2020 · 0 comments
Assignees
Labels
enhancement New feature or request Task

Comments

@darksylinc
Copy link
Member

darksylinc commented Jun 9, 2020

https://mynameismjp.wordpress.com/2013/09/10/shadow-maps/ (look for "The normal-based offset, called Offset Scale...")
http://c0de517e.blogspot.com/2011/05/shadowmap-bias-notes.html
https://ndotl.wordpress.com/2014/12/19/notes-on-shadow-bias/

There are two ways:

  1. Displace during the caster pass
triangle.xyz += normal.xyz * ( 1.0f - abs( dot( normal, lightdir ) ) ) * normal_bias;

I'm not sure if that's the exact formula, MJP has a demo with code.

ass, thus make sure that the shadow map optimization is turned off (because it strips everything except position data). msOptimizeForShadowMapping should be set to false and hasIndependentShadowMappingVaos should be returning false.

Once the PR is done we can modify VertexShadowMapHelper::optimizeForShadowMapping to keep normals in a lightweight manner (probably 8bpp per component is enough?, adding only 4 bytes per vertex)

  1. Displace during the normal rendering pass by the geometric normal, before sampling the shadow map. This should be more accurate.

This is what MJP demo does:

float3 GetShadowPosOffset(in float nDotL, in float3 normal)
{
    float2 shadowMapSize;
    float numSlices;
    ShadowMap.GetDimensions(shadowMapSize.x, shadowMapSize.y, numSlices);
    float texelSize = 2.0f / shadowMapSize.x;
    float nmlOffsetScale = saturate(1.0f - nDotL);
    return texelSize * OffsetScale * nmlOffsetScale * normal;
}

float3 offset = GetShadowPosOffset(nDotL, normal) / abs(CascadeScales[cascadeIdx].z);

// Project into shadow space
float3 samplePos = positionWS + offset;
...

It seems MJP uses saturate() instead of abs()

It divides the offset by the shadow map size in order to apply the offset in texels, making this effect account shadow map resolution.

Also see forum thread.

@darksylinc darksylinc added help wanted Extra attention is needed Task labels Jun 9, 2020
darksylinc added a commit that referenced this issue Jun 11, 2020
This feature produces MUCH better shadow results using front faces.
It has overall fewer artifacts

New features:
- Added normal_offset_bias / ShadowTextureDefinition::normalOffsetBias
to globally control this normal offset bias per shadow map / cascade
- Added constant_bias_scale /
ShadowTextureDefinition::constantBiasScale. Constant bias is still
per-material, but it can be globally amplified/decrease per shadow map /
cascade
- Constant bias is again automatically amplified with deeper shadow
maps, as otherwise acne becomes visible (most obvious when using PSSM on
the higher cascades). With the previous commit it was constant across
all ranges and cascades

Default mShadowMappingUseBackFaces to false, but it will be removed in
the next commit. This feature is much more accuratem, we don't have the
resources to maintain two codepaths, and the switching between the two
requires aligning many variables (shader changes so constant bias is
constant across regardless of depth range, set normal offset bias to 0,
set mShadowMappingUseBackFaces to true)
@darksylinc darksylinc self-assigned this Jun 11, 2020
@darksylinc darksylinc added enhancement New feature or request and removed help wanted Extra attention is needed labels Jun 11, 2020
darksylinc added a commit that referenced this issue Jun 15, 2020
This feature produces MUCH better shadow results using front faces.
It has overall fewer artifacts

New features:
- Added normal_offset_bias / ShadowTextureDefinition::normalOffsetBias
to globally control this normal offset bias per shadow map / cascade
- Added constant_bias_scale /
ShadowTextureDefinition::constantBiasScale. Constant bias is still
per-material, but it can be globally amplified/decrease per shadow map /
cascade
- Constant bias is again automatically amplified with deeper shadow
maps, as otherwise acne becomes visible (most obvious when using PSSM on
the higher cascades). With the previous commit it was constant across
all ranges and cascades

Default mShadowMappingUseBackFaces to false, but it will be removed in
the next commit. This feature is much more accuratem, we don't have the
resources to maintain two codepaths, and the switching between the two
requires aligning many variables (shader changes so constant bias is
constant across regardless of depth range, set normal offset bias to 0,
set mShadowMappingUseBackFaces to true)
darksylinc added a commit that referenced this issue Jun 15, 2020
This feature produces MUCH better shadow results using front faces.
It has overall fewer artifacts

New features:
- Added normal_offset_bias / ShadowTextureDefinition::normalOffsetBias
to globally control this normal offset bias per shadow map / cascade
- Added constant_bias_scale /
ShadowTextureDefinition::constantBiasScale. Constant bias is still
per-material, but it can be globally amplified/decrease per shadow map /
cascade
- Constant bias is again automatically amplified with deeper shadow
maps, as otherwise acne becomes visible (most obvious when using PSSM on
the higher cascades). With the previous commit it was constant across
all ranges and cascades

Default mShadowMappingUseBackFaces to false, but it will be removed in
the next commit. This feature is much more accuratem, we don't have the
resources to maintain two codepaths, and the switching between the two
requires aligning many variables (shader changes so constant bias is
constant across regardless of depth range, set normal offset bias to 0,
set mShadowMappingUseBackFaces to true)
@darksylinc darksylinc mentioned this issue Jun 15, 2020
12 tasks
darksylinc added a commit that referenced this issue Jun 19, 2020
Changes:
- Added HlmsMacroblock::mDepthClamp
- Added RSC_DEPTH_CLAMP, present almost anywhere except A7, A8 iOS HW
- Added shadow map pancacking using mDepthClamp to
FocusedShadowCameraSetup for directional shadow maps. This tightens
depth range, increasing precision and decreasing the need for 32-bit
depth buffers
- Fix normal offset bias heavily dependent on shadow map resolution
- Point lights' normal offset bias was accidentally hardcoded
- shadowConstantBias in the caster shader no longer varies implicitly
due to depth range. It was a cryptic (user hostile) way of increasing
bias to higher splits.
- Changed default value of constantBiasScale
- Changed default value of normalOffsetBias
- Added autoConstantBiasScale and autoNormalOffsetBiasScale. This value
adjusts the bias based on the size of the shadow camera. Shadow cameras
covering more area require bigger biases. This setting is a much
user-friendlier way of automatically scaling the bias to higher splits.
darksylinc added a commit that referenced this issue Jun 20, 2020
darksylinc added a commit that referenced this issue Jun 22, 2020
OpenGL was looking fine
Metal was possibly affected
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request Task
Projects
None yet
Development

No branches or pull requests

1 participant