Skip to content

Commit

Permalink
Multiple shadow mapping improvements (#100). See description
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
darksylinc committed Jun 19, 2020
1 parent 50d84a8 commit 652acb3
Show file tree
Hide file tree
Showing 16 changed files with 123 additions and 18 deletions.
17 changes: 15 additions & 2 deletions OgreMain/include/Compositor/OgreCompositorShadowNodeDef.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,21 @@ namespace Ogre
/// Constant bias is per material (tweak HlmsDatablock::mShadowConstantBias).
/// This value lets you multiply it 'mShadowConstantBias * constantBiasScale'
/// per cascade / shadow map
///
/// This is applied on top of the autocalculated bias from autoConstantBiasScale
float constantBiasScale;
/// Normal offset bias is per cascade / shadow map
///
/// This is applied on top of the autocalculated bias from autoNormalOffsetBiasScale
float normalOffsetBias;

/// 0 to disable.
/// Non-zero to increase bias based on orthographic projection's window size.
float autoConstantBiasScale;
/// 0 to disable.
/// Non-zero to increase bias based on orthographic projection's window size.
float autoNormalOffsetBiasScale;

ShadowMapTechniques shadowMapTechnique;

//PSSM params
Expand All @@ -94,8 +105,10 @@ namespace Ogre
arrayIdx( _arrayIdx ),
light( _light ),
split( _split ),
constantBiasScale( 0.1f ),
normalOffsetBias( 0.00004f ),
constantBiasScale( 1.0f ),
normalOffsetBias( 168.0f ),
autoConstantBiasScale( 100.0f ),
autoNormalOffsetBiasScale( 4.0f ),
shadowMapTechnique( t ),
pssmLambda( 0.95f ),
splitPadding( 1.0f ),
Expand Down
5 changes: 5 additions & 0 deletions OgreMain/include/OgreCamera.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ namespace Ogre {
/// Camera to use for LOD calculation
const Camera* mLodCamera;

bool mNeedsDepthClamp;

/// Whether or not the minimum display size of objects should take effect for this camera
bool mUseMinPixelSize;
/// @see Camera::getPixelDisplayRatio
Expand Down Expand Up @@ -711,6 +713,9 @@ namespace Ogre {
*/
bool getUseMinPixelSize() const { return mUseMinPixelSize; }

void _setNeedsDepthClamp( bool bNeedsDepthClamp );
bool getNeedsDepthClamp( void ) const { return mNeedsDepthClamp; }

/** Returns an estimated ratio between a pixel and the display area it represents.
For orthographic cameras this function returns the amount of meters covered by
a single pixel along the vertical axis. For perspective cameras the value
Expand Down
2 changes: 2 additions & 0 deletions OgreMain/include/OgreHlmsDatablock.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ namespace Ogre
struct _OgreExport HlmsMacroblock : public BasicBlock
{
bool mScissorTestEnabled;
bool mDepthClamp;
bool mDepthCheck;
bool mDepthWrite;
CompareFunction mDepthFunc;
Expand Down Expand Up @@ -125,6 +126,7 @@ namespace Ogre
//Don't include the ID in the comparision
return mAllowGlobalDefaults != _r.mAllowGlobalDefaults ||
mScissorTestEnabled != _r.mScissorTestEnabled ||
mDepthClamp != _r.mDepthClamp ||
mDepthCheck != _r.mDepthCheck ||
mDepthWrite != _r.mDepthWrite ||
mDepthFunc != _r.mDepthFunc ||
Expand Down
1 change: 1 addition & 0 deletions OgreMain/include/OgreHlmsPso.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ namespace Ogre
ForceDisableDepthWrites = 1u << 0u,
InvertVertexWinding = 1u << 1u,
NoDepthBuffer = 1u << 2u,
ForceDepthClamp = 1u << 3u,
};
};

Expand Down
1 change: 1 addition & 0 deletions OgreMain/include/OgreRenderSystemCapabilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ namespace Ogre
RSC_CONST_BUFFER_SLOTS_IN_SHADER = OGRE_CAPS_VALUE(CAPS_CATEGORY_COMMON_3, 10),
RSC_TEXTURE_COMPRESSION_ASTC = OGRE_CAPS_VALUE(CAPS_CATEGORY_COMMON_3, 11),
RSC_STORE_AND_MULTISAMPLE_RESOLVE = OGRE_CAPS_VALUE(CAPS_CATEGORY_COMMON_3, 12),
RSC_DEPTH_CLAMP = OGRE_CAPS_VALUE(CAPS_CATEGORY_COMMON_3, 13),

// ***** DirectX specific caps *****
/// Is DirectX feature "per stage constants" supported
Expand Down
39 changes: 36 additions & 3 deletions OgreMain/src/Compositor/OgreCompositorShadowNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -566,8 +566,6 @@ namespace Ogre
texCamera->setAutoAspectRatio( false );
}

texCamera->_setConstantBiasScale( itor->constantBiasScale );

if( itor->shadowMapTechnique == SHADOWMAP_PSSM )
{
assert( dynamic_cast<PSSMShadowCameraSetup*>
Expand Down Expand Up @@ -595,6 +593,23 @@ namespace Ogre

itShadowCamera->minDistance = itShadowCamera->shadowCameraSetup->getMinDistance();
itShadowCamera->maxDistance = itShadowCamera->shadowCameraSetup->getMaxDistance();

float fAutoConstantBiasScale = 1.0f;
if( itor->autoConstantBiasScale != 0.0f )
{
if( texCamera->getProjectionType() == PT_ORTHOGRAPHIC )
{
const Real orthoSize = std::max( texCamera->getOrthoWindowWidth(),
texCamera->getOrthoWindowHeight() );
float autoFactor = orthoSize / light->getShadowFarDistance();
fAutoConstantBiasScale = 1.0f + autoFactor * itor->autoConstantBiasScale;
}
}
texCamera->_setConstantBiasScale( itor->constantBiasScale * fAutoConstantBiasScale );

const RenderSystemCapabilities *caps = mRenderSystem->getCapabilities();
texCamera->_setNeedsDepthClamp( light->getType() == Light::LT_DIRECTIONAL &&
caps->hasCapability( RSC_DEPTH_CLAMP ) );
}
//Else... this shadow map shouldn't be rendered and when used, return a blank one.
//The Nth closest lights don't cast shadows
Expand Down Expand Up @@ -962,7 +977,25 @@ namespace Ogre
//-----------------------------------------------------------------------------------
float CompositorShadowNode::getNormalOffsetBias( const size_t shadowMapIdx ) const
{
return mDefinition->mShadowMapTexDefinitions[shadowMapIdx].normalOffsetBias;
const ShadowTextureDefinition &shadowMapDef =
mDefinition->mShadowMapTexDefinitions[shadowMapIdx];

float fAutoConstantBiasScale = 1.0f;
if( shadowMapDef.autoNormalOffsetBiasScale != 0.0f )
{
Light const *light = mShadowMapCastingLights[shadowMapDef.light].light;
OGRE_ASSERT_HIGH( light && "Can't call this function if isShadowMapIdxActive is false!" );

const Camera *texCamera = mShadowMapCameras[shadowMapIdx].camera;
if( texCamera->getProjectionType() == PT_ORTHOGRAPHIC )
{
const Real orthoSize =
std::max( texCamera->getOrthoWindowWidth(), texCamera->getOrthoWindowHeight() );
float autoFactor = orthoSize / light->getShadowFarDistance();
fAutoConstantBiasScale = 1.0f + autoFactor * shadowMapDef.autoNormalOffsetBiasScale;
}
}
return shadowMapDef.normalOffsetBias;
}
//-----------------------------------------------------------------------------------
void CompositorShadowNode::setLightFixedToShadowMap( size_t shadowMapIdx, Light *light )
Expand Down
6 changes: 6 additions & 0 deletions OgreMain/src/OgreCamera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ namespace Ogre {
mCullFrustum(0),
mUseRenderingDistance(true),
mLodCamera(0),
mNeedsDepthClamp(false),
mUseMinPixelSize(false),
mPixelDisplayRatio(0),
mConstantBiasScale(1.0f)
Expand Down Expand Up @@ -1131,6 +1132,11 @@ namespace Ogre {

}
//-----------------------------------------------------------------------
void Camera::_setNeedsDepthClamp( bool bNeedsDepthClamp )
{
mNeedsDepthClamp = bNeedsDepthClamp;
}
//-----------------------------------------------------------------------
void Camera::_resetRenderedRqs( size_t numRqs )
{
mRenderedRqs.clear();
Expand Down
11 changes: 11 additions & 0 deletions OgreMain/src/OgreHlms.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2031,6 +2031,11 @@ namespace Ogre
//Without culling there's nothing to invert, we don't need to hold a strong reference.
pso.pass.strongMacroblockBits &= ~HlmsPassPso::InvertVertexWinding;
}
if( pso.macroblock->mDepthClamp )
{
//Macroblock already enabled depth clamp, we don't need to hold a strong reference.
pso.pass.strongMacroblockBits &= ~HlmsPassPso::ForceDepthClamp;
}

if( pso.pass.hasStrongMacroblock() )
{
Expand All @@ -2048,6 +2053,9 @@ namespace Ogre
prepassMacroblock.mCullMode = prepassMacroblock.mCullMode == CULL_CLOCKWISE ?
CULL_ANTICLOCKWISE : CULL_CLOCKWISE;
}
//Force depth clamp. Probably a directional shadow caster pass
if( pso.pass.strongMacroblockBits & HlmsPassPso::ForceDepthClamp )
prepassMacroblock.mDepthClamp = true;

pso.macroblock = mHlmsManager->getMacroblock( prepassMacroblock );
}
Expand Down Expand Up @@ -3075,6 +3083,9 @@ namespace Ogre
if( sceneManager->getCurrentPrePassMode() == PrePassUse )
passPso.strongMacroblockBits |= HlmsPassPso::ForceDisableDepthWrites;

if( sceneManager->getCamerasInProgress().renderingCamera->getNeedsDepthClamp() )
passPso.strongMacroblockBits |= HlmsPassPso::ForceDepthClamp;

const bool invertVertexWinding = mRenderSystem->getInvertVertexWinding();

if( (renderPassDesc->requiresTextureFlipping() && !invertVertexWinding) ||
Expand Down
1 change: 1 addition & 0 deletions OgreMain/src/OgreHlmsDatablock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ namespace Ogre
HlmsMacroblock::HlmsMacroblock() :
BasicBlock( BLOCK_MACRO ),
mScissorTestEnabled( false ),
mDepthClamp( false ),
mDepthCheck( true ),
mDepthWrite( true ),
mDepthFunc( CMPF_LESS_EQUAL ),
Expand Down
7 changes: 7 additions & 0 deletions OgreMain/src/OgreShadowCameraSetupFocused.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,13 @@ namespace Ogre

vMin.z = Ogre::min( vMin.z, vMinCamFrustumLS.z );

const RenderSystemCapabilities *caps = Root::getSingleton().getRenderSystem()->getCapabilities();
if( caps->hasCapability( RSC_DEPTH_CLAMP ) )
{
// We can only do shadow pancaking (increasing precision) if depth clamp is supported
vMax.z = Ogre::max( vMax.z, vMaxCamFrustumLS.z );
}

//Some padding
vMax += 1.5f;
vMin -= 1.5f;
Expand Down
4 changes: 3 additions & 1 deletion RenderSystems/Direct3D11/src/OgreD3D11RenderSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,8 @@ namespace Ogre
rsc->setCapability(RSC_UAV);
}

rsc->setCapability(RSC_DEPTH_CLAMP);

rsc->setCapability(RSC_HWRENDER_TO_TEXTURE);
rsc->setCapability(RSC_TEXTURE_FLOAT);

Expand Down Expand Up @@ -2301,7 +2303,7 @@ namespace Ogre
rasterDesc.SlopeScaledDepthBias = newBlock->mDepthBiasSlopeScale * biasSign;
rasterDesc.DepthBiasClamp = 0;

rasterDesc.DepthClipEnable = true;
rasterDesc.DepthClipEnable = !newBlock->mDepthClamp;
rasterDesc.ScissorEnable = newBlock->mScissorTestEnabled;

rasterDesc.MultisampleEnable = true;
Expand Down
14 changes: 14 additions & 0 deletions RenderSystems/GL3Plus/src/OgreGL3PlusRenderSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,12 @@ namespace Ogre {
rsc->setCapability(RSC_TYPED_UAV_LOADS);
}

if( mHasGL43 || mGLSupport->checkExtension( "GL_ARB_depth_clamp" ) ||

This comment has been minimized.

Copy link
@paroj

paroj Sep 27, 2020

Member

I think this is in 3.0 core

This comment has been minimized.

Copy link
@darksylinc

darksylinc Sep 27, 2020

Author Member

Thanks. I couldn't find official confirmation of when it was added to core.

To find out we'd have to go through the PDF specs and check the wording to see if it contains GL_ARB_depth_clamp's new text or not.

This comment has been minimized.

Copy link
@paroj
mGLSupport->checkExtension( "GL_NV_depth_clamp" ) )
{
rsc->setCapability( RSC_DEPTH_CLAMP );
}

if( mGLSupport->checkExtension( "GL_ARB_shader_viewport_layer_array" ) )
rsc->setCapability( RSC_VP_AND_RT_ARRAY_INDEX_FROM_ANY_SHADER );

Expand Down Expand Up @@ -2054,6 +2060,14 @@ namespace Ogre {

_setDepthBias( macroblock->mDepthBiasConstant, macroblock->mDepthBiasSlopeScale );

if( macroblock->mDepthClamp )
{
OCGE( glEnable( GL_DEPTH_CLAMP ) );
}
else
{
OCGE( glDisable( GL_DEPTH_CLAMP ) );
}

//Cull mode
if( pso->cullMode == 0 )
Expand Down
8 changes: 8 additions & 0 deletions RenderSystems/Metal/src/OgreMetalRenderSystem.mm
Original file line number Diff line number Diff line change
Expand Up @@ -378,9 +378,12 @@ of this software and associated documentation files (the "Software"), to deal
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS
if( [mActiveDevice->mDevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v2] )
rsc->setCapability(RSC_STORE_AND_MULTISAMPLE_RESOLVE);
if( [mActiveDevice->mDevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily4_v1] )
rsc->setCapability(RSC_DEPTH_CLAMP);
#else
if( [mActiveDevice->mDevice supportsFeatureSet:MTLFeatureSet_OSX_GPUFamily1_v2] )
rsc->setCapability(RSC_STORE_AND_MULTISAMPLE_RESOLVE);
rsc->setCapability(RSC_DEPTH_CLAMP);
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS
Expand Down Expand Up @@ -2041,6 +2044,11 @@ of this software and associated documentation files (the "Software"), to deal
slopeScale:pso->macroblock->mDepthBiasSlopeScale * biasSign
clamp:0.0f];
[mActiveRenderEncoder setCullMode:metalPso->cullMode];
if( @available( iOS 11.0, * ) )
{
[mActiveRenderEncoder setDepthClipMode:pso->macroblock->mDepthClamp ? MTLDepthClipModeClamp
: MTLDepthClipModeClip];
}

if( mPso != metalPso )
{
Expand Down
4 changes: 2 additions & 2 deletions Samples/Media/Hlms/Common/Any/ShadowCaster_piece_vs.any
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
@property( hlms_shadowcaster )
@piece( DoShadowCasterVS )
@property( hlms_no_reverse_depth || hlms_shadowcaster_point )
float shadowConstantBias = uintBitsToFloat( worldMaterialIdx[inVs_drawId].y );
float shadowConstantBias = uintBitsToFloat( worldMaterialIdx[inVs_drawId].y ) * passBuf.depthRange.y;
@else
float shadowConstantBias = -uintBitsToFloat( worldMaterialIdx[inVs_drawId].y );
float shadowConstantBias = -uintBitsToFloat( worldMaterialIdx[inVs_drawId].y ) * passBuf.depthRange.y;
@end

@property( !hlms_shadow_uses_depth_texture && !hlms_shadowcaster_point && !exponential_shadow_maps )
Expand Down
19 changes: 10 additions & 9 deletions Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@
@piece( DeclShadowSamplingFuncs )
@foreach( 2, m )
// Perform normal offset bias. See https://github.com/OGRECave/ogre-next/issues/100
INLINE float3 getNormalOffsetBias( float3 geomNormal, float3 lightDir,
INLINE float3 getNormalOffsetBias( float3 geomNormal, float3 lightDir, float normalOffsetBias,
float shadowMapTexSize, float depthRange
@property( @m == 0 )
)
Expand All @@ -147,7 +147,7 @@
shadowMapTexSize /= maxUV.x - minUV.x;
@end

return ( ( 1.0f - tmpNdotL ) * (0.00004f) * geomNormal.xyz * shadowMapTexSize );
return ( ( 1.0f - tmpNdotL ) * normalOffsetBias * geomNormal.xyz * shadowMapTexSize );
}
@end
@foreach( 4, m )
Expand All @@ -159,12 +159,12 @@
float4 psPosLN, float4 invShadowMapSize, float2 minUV, float2 maxUV )
@end @property( @m == 2 )
INLINE float getShadowPoint( @insertpiece( TEXTURE2DSHADOW ) shadowMap, @insertpiece( SamplerShadow )
float3 geomNormal,
float3 posVS, float3 lightPos, float4 invShadowMapSize, float2 invDepthRange
float3 geomNormal, float normalOffsetBias,
float3 posVS, float3 lightPos,float4 invShadowMapSize, float2 invDepthRange
PASSBUF_ARG_DECL )
@end @property( @m == 3 )
INLINE float getShadowPoint( @insertpiece( TEXTURE2DSHADOW ) shadowMap, @insertpiece( SamplerShadow )
float3 geomNormal,
float3 geomNormal, float normalOffsetBias,
float3 posVS, float3 lightPos, float4 invShadowMapSize, float2 invDepthRange,
float2 minUV, float2 maxUV, float2 lengthUV
PASSBUF_ARG_DECL )
Expand All @@ -185,11 +185,11 @@
@else
//Point lights
float3 cubemapDir = posVS.xyz - lightPos.xyz;
cubemapDir += getNormalOffsetBias( geomNormal, cubemapDir,
cubemapDir += getNormalOffsetBias( geomNormal, cubemapDir, normalOffsetBias,
@property( @m == 2 )
invShadowMapSize.z, invDepthRange.y );
invShadowMapSize.x, invDepthRange.y );
@else
invShadowMapSize.z, invDepthRange.y, minUV, maxUV );
invShadowMapSize.x, invDepthRange.y, minUV, maxUV );
@end

float fDepth = length( cubemapDir );
Expand Down Expand Up @@ -438,7 +438,8 @@
@piece( DarkenWithShadowPoint )
* getShadowPoint( hlms_shadowmap@value(CurrentShadowMap), @insertpiece( UseSamplerShadow )
pixelData.geomNormal,
inPs.pos.xyz, light0Buf.lights[@counter(CurrentPointLight)].position.xyz,
passBuf.shadowRcv[@value(CurrentShadowMap)].normalOffsetBias,
inPs.pos.xyz, light0Buf.lights[@value(CurrentPointLight)].position.xyz,
passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize,
passBuf.shadowRcv[@value(CurrentShadowMap)].shadowDepthRange.xy
hlms_shadowmap@counter(CurrentShadowMap)_uv_param PASSBUF_ARG )
Expand Down
2 changes: 1 addition & 1 deletion Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_vs.any
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
@property( !hlms_shadowmap@n_is_point_light )
@property( !skip_normal_offset_bias_vs )
normalOffsetBias = getNormalOffsetBias( worldNorm, outVs.normal, shadowMap@nLightDir,
passBuf.shadowRcv[@n].invShadowMapSize.z,
passBuf.shadowRcv[@n].invShadowMapSize.x,
passBuf.shadowRcv[@n].shadowDepthRange.y,
passBuf.shadowRcv[@n].normalOffsetBias
hlms_shadowmap@n_uv_param );
Expand Down

0 comments on commit 652acb3

Please sign in to comment.