From 9976b809d12b0669f811b913b38b08181edbafd8 Mon Sep 17 00:00:00 2001 From: "Matias N. Goldberg" Date: Wed, 10 Jun 2020 21:13:40 -0300 Subject: [PATCH 1/9] Implemented normal offset bias (#100) 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) --- Components/Hlms/Pbs/include/OgreHlmsPbs.h | 2 + Components/Hlms/Pbs/src/OgreHlmsPbs.cpp | 11 ++-- Components/Hlms/Unlit/include/OgreHlmsUnlit.h | 1 + Components/Hlms/Unlit/src/OgreHlmsUnlit.cpp | 7 ++- Docs/src/manual/compositor.md | 16 +++++ .../Compositor/OgreCompositorShadowNode.h | 5 ++ .../Compositor/OgreCompositorShadowNodeDef.h | 9 +++ OgreMain/include/OgreCamera.h | 5 ++ OgreMain/include/OgreScriptCompiler.h | 2 + .../Compositor/OgreCompositorShadowNode.cpp | 15 +++++ OgreMain/src/OgreCamera.cpp | 3 +- OgreMain/src/OgreHlms.cpp | 12 ++++ OgreMain/src/OgreHlmsDatablock.cpp | 2 +- OgreMain/src/OgreHlmsManager.cpp | 2 +- OgreMain/src/OgreScriptCompiler.cpp | 2 + OgreMain/src/OgreScriptTranslator.cpp | 46 ++++++++++++++- .../ShadowMapDebuggingGameState.cpp | 5 -- .../Hlms/Common/Any/ShadowCaster_piece_vs.any | 12 ++-- .../Main/500.Structs_piece_vs_piece_ps.any | 3 +- .../Any/Main/800.VertexShader_piece_vs.any | 29 ++++++---- .../Hlms/Pbs/Any/ShadowMapping_piece_ps.any | 58 ++++++++++++++----- .../Hlms/Pbs/Any/ShadowMapping_piece_vs.any | 56 +++++++++++++++++- 22 files changed, 256 insertions(+), 47 deletions(-) diff --git a/Components/Hlms/Pbs/include/OgreHlmsPbs.h b/Components/Hlms/Pbs/include/OgreHlmsPbs.h index ffe21f4ffe7..e7122c70d3a 100644 --- a/Components/Hlms/Pbs/include/OgreHlmsPbs.h +++ b/Components/Hlms/Pbs/include/OgreHlmsPbs.h @@ -182,6 +182,8 @@ namespace Ogre ConstBufferPool::BufferPool const *mLastBoundPool; + float mConstantBiasScale; + bool mHasSeparateSamplers; DescriptorSetTexture const *mLastDescTexture; DescriptorSetSampler const *mLastDescSampler; diff --git a/Components/Hlms/Pbs/src/OgreHlmsPbs.cpp b/Components/Hlms/Pbs/src/OgreHlmsPbs.cpp index 3b5599ef52f..7a6b93e4362 100644 --- a/Components/Hlms/Pbs/src/OgreHlmsPbs.cpp +++ b/Components/Hlms/Pbs/src/OgreHlmsPbs.cpp @@ -289,6 +289,7 @@ namespace Ogre mDecalsDiffuseMergedEmissive( false ), mDecalsSamplerblock( 0 ), mLastBoundPool( 0 ), + mConstantBiasScale( 1.0f ), mHasSeparateSamplers( 0 ), mLastDescTexture( 0 ), mLastDescSampler( 0 ), @@ -1491,6 +1492,7 @@ namespace Ogre retVal.setProperties = mSetProperties; CamerasInProgress cameras = sceneManager->getCamerasInProgress(); + mConstantBiasScale = cameras.renderingCamera->_getConstantBiasScale(); Matrix4 viewMatrix = cameras.renderingCamera->getVrViewMatrix( 0 ); Matrix4 projectionMatrix = cameras.renderingCamera->getProjectionMatrixWithRSDepth(); @@ -1578,7 +1580,8 @@ namespace Ogre //mat4 view + mat4 shadowRcv[numShadowMapLights].texViewProj + // vec2 shadowRcv[numShadowMapLights].shadowDepthRange + - // vec2 padding + + // float normalOffsetBias + + // float padding + // vec4 shadowRcv[numShadowMapLights].invShadowMapSize + //mat3 invViewMatCubemap (upgraded to three vec4) mapSize += ( 16 + (16 + 2 + 2 + 4) * numShadowMapLights + 4 * 3 ) * 4; @@ -1899,7 +1902,7 @@ namespace Ogre *passBufferPtr++ = fNear; } *passBufferPtr++ = 1.0f / depthRange; - *passBufferPtr++ = 0.0f; + *passBufferPtr++ = shadowNode->getNormalOffsetBias( (size_t)shadowMapTexIdx ); *passBufferPtr++ = 0.0f; //Padding @@ -3210,8 +3213,8 @@ namespace Ogre currentMappedTexBuffer = mStartMappedTexBuffer + currentConstOffset; } - *reinterpret_cast( currentMappedConstBuffer+1 ) = datablock-> - mShadowConstantBias; + *reinterpret_cast( currentMappedConstBuffer + 1 ) = + datablock->mShadowConstantBias * mConstantBiasScale; #if !OGRE_NO_FINE_LIGHT_MASK_GRANULARITY *( currentMappedConstBuffer+2u ) = queuedRenderable.movableObject->getLightMask(); #endif diff --git a/Components/Hlms/Unlit/include/OgreHlmsUnlit.h b/Components/Hlms/Unlit/include/OgreHlmsUnlit.h index 38286c49a13..4ef6b076c38 100644 --- a/Components/Hlms/Unlit/include/OgreHlmsUnlit.h +++ b/Components/Hlms/Unlit/include/OgreHlmsUnlit.h @@ -79,6 +79,7 @@ namespace Ogre DescriptorSetTexture const *mLastDescTexture; DescriptorSetSampler const *mLastDescSampler; + float mConstantBiasScale; bool mUsingInstancedStereo; bool mUsingExponentialShadowMaps; diff --git a/Components/Hlms/Unlit/src/OgreHlmsUnlit.cpp b/Components/Hlms/Unlit/src/OgreHlmsUnlit.cpp index d79c7e7438b..afca5971483 100644 --- a/Components/Hlms/Unlit/src/OgreHlmsUnlit.cpp +++ b/Components/Hlms/Unlit/src/OgreHlmsUnlit.cpp @@ -80,6 +80,7 @@ namespace Ogre mHasSeparateSamplers( 0 ), mLastDescTexture( 0 ), mLastDescSampler( 0 ), + mConstantBiasScale( 1.0f ), mUsingInstancedStereo( false ), mUsingExponentialShadowMaps( false ), mEsmK( 600u ), @@ -104,6 +105,7 @@ namespace Ogre mLastBoundPool( 0 ), mLastDescTexture( 0 ), mLastDescSampler( 0 ), + mConstantBiasScale( 1.0f ), mUsingInstancedStereo( false ), mUsingExponentialShadowMaps( false ), mEsmK( 600u ), @@ -624,6 +626,7 @@ namespace Ogre retVal.pso.pass = passCache.passPso; mUsingInstancedStereo = isInstancedStereo; + mConstantBiasScale = cameras.renderingCamera->_getConstantBiasScale(); Matrix4 viewMatrix = cameras.renderingCamera->getViewMatrix(true); Matrix4 projectionMatrix = cameras.renderingCamera->getProjectionMatrixWithRSDepth(); @@ -958,8 +961,8 @@ namespace Ogre //uint materialIdx[] *currentMappedConstBuffer = datablock->getAssignedSlot(); - *reinterpret_cast( currentMappedConstBuffer+1 ) = datablock-> - mShadowConstantBias; + *reinterpret_cast( currentMappedConstBuffer + 1 ) = + datablock->mShadowConstantBias * mConstantBiasScale; *(currentMappedConstBuffer+2) = useIdentityProjection; currentMappedConstBuffer += 4; diff --git a/Docs/src/manual/compositor.md b/Docs/src/manual/compositor.md index 949ff38a297..c1549fc9092 100644 --- a/Docs/src/manual/compositor.md +++ b/Docs/src/manual/compositor.md @@ -1290,6 +1290,22 @@ thus the recommended values are num\_stable\_splits = 1 or num\_stable\_splits = The default is num\_stable\_splits = 0 which disables the feature +- normal\_offset\_bias + +Normal-offset bias is per cascade / shadow map to fight shadow acne and self shadowing artifacts +Very large values can cause misalignments between the objects and their shadows (if they're touching) + +Default is 0.00004 + +- constant\_bias\_scale + +Constant bias is per material (tweak HlmsDatablock::mShadowConstantBias). +This value lets you multiply it 'mShadowConstantBias * constantBiasScale' per cascade / shadow map + +Large values can cause peter-panning. + +Default is 1.0 + - pssm\_lambda \ Only used by PSSM techniques. Value usually between 0 & 1. The default diff --git a/OgreMain/include/Compositor/OgreCompositorShadowNode.h b/OgreMain/include/Compositor/OgreCompositorShadowNode.h index d1033cb13db..d51c9f43edb 100644 --- a/OgreMain/include/Compositor/OgreCompositorShadowNode.h +++ b/OgreMain/include/Compositor/OgreCompositorShadowNode.h @@ -222,6 +222,9 @@ namespace Ogre /// return a valid pointer. const Light* getLightAssociatedWith( uint32 shadowMapIdx ) const; + /// Returns 0 if shadowMapIdx is out of bounds + size_t getLightIdxAssociatedWith( const size_t shadowMapIdx ) const; + /** Outputs the min & max depth range for the given camera. 0 & 100000 if camera not found @remarks Performs linear search O(N), except the overload that provides a shadowMapIdx @@ -280,6 +283,8 @@ namespace Ogre const TextureGpuVec& getContiguousShadowMapTex(void) const { return mContiguousShadowMapTex; } uint32 getIndexToContiguousShadowMapTex( size_t shadowMapIdx ) const; + float getNormalOffsetBias( const size_t shadowMapIdx ) const; + /** Marks a shadow map as statically updated, and ties the given light to always use that shadow map. @remarks diff --git a/OgreMain/include/Compositor/OgreCompositorShadowNodeDef.h b/OgreMain/include/Compositor/OgreCompositorShadowNodeDef.h index 4dce5a81357..799844c19ac 100644 --- a/OgreMain/include/Compositor/OgreCompositorShadowNodeDef.h +++ b/OgreMain/include/Compositor/OgreCompositorShadowNodeDef.h @@ -63,6 +63,13 @@ namespace Ogre size_t light; //Render Nth closest light size_t split; //Split for that light (only for PSSM/CSM) + /// Constant bias is per material (tweak HlmsDatablock::mShadowConstantBias). + /// This value lets you multiply it 'mShadowConstantBias * constantBiasScale' + /// per cascade / shadow map + float constantBiasScale; + /// Normal offset bias is per cascade / shadow map + float normalOffsetBias; + ShadowMapTechniques shadowMapTechnique; //PSSM params @@ -87,6 +94,8 @@ namespace Ogre arrayIdx( _arrayIdx ), light( _light ), split( _split ), + constantBiasScale( 1.0f ), + normalOffsetBias( 0.00004f ), shadowMapTechnique( t ), pssmLambda( 0.95f ), splitPadding( 1.0f ), diff --git a/OgreMain/include/OgreCamera.h b/OgreMain/include/OgreCamera.h index 5d8be6fe085..ff2fb8d2f06 100644 --- a/OgreMain/include/OgreCamera.h +++ b/OgreMain/include/OgreCamera.h @@ -195,6 +195,8 @@ namespace Ogre { /// @see Camera::getPixelDisplayRatio Real mPixelDisplayRatio; + float mConstantBiasScale; + /// Each frame it is set to all false. After rendering each RQ, it is set to true vector::type mRenderedRqs; @@ -721,6 +723,9 @@ namespace Ogre { */ Real getPixelDisplayRatio() const { return mPixelDisplayRatio; } + void _setConstantBiasScale( const float bias ) { mConstantBiasScale = bias; } + float _getConstantBiasScale( void ) const { return mConstantBiasScale; } + /** Called at the beginning of each frame to know which RenderQueue IDs have been rendered @param numRqs Max number of total possible render queues in this frame diff --git a/OgreMain/include/OgreScriptCompiler.h b/OgreMain/include/OgreScriptCompiler.h index df39155df96..cd00c7457a9 100644 --- a/OgreMain/include/OgreScriptCompiler.h +++ b/OgreMain/include/OgreScriptCompiler.h @@ -1002,6 +1002,8 @@ namespace Ogre ID_SHADOW_NODE, ID_NUM_SPLITS, ID_NUM_STABLE_SPLITS, + ID_NORMAL_OFFSET_BIAS, + ID_CONSTANT_BIAS_SCALE, ID_PSSM_SPLIT_PADDING, ID_PSSM_SPLIT_BLEND, ID_PSSM_SPLIT_FADE, diff --git a/OgreMain/src/Compositor/OgreCompositorShadowNode.cpp b/OgreMain/src/Compositor/OgreCompositorShadowNode.cpp index 69adf8cedfd..49a09bd025a 100644 --- a/OgreMain/src/Compositor/OgreCompositorShadowNode.cpp +++ b/OgreMain/src/Compositor/OgreCompositorShadowNode.cpp @@ -566,6 +566,8 @@ namespace Ogre texCamera->setAutoAspectRatio( false ); } + texCamera->_setConstantBiasScale( itor->constantBiasScale ); + if( itor->shadowMapTechnique == SHADOWMAP_PSSM ) { assert( dynamic_cast @@ -828,6 +830,14 @@ namespace Ogre return retVal; } //----------------------------------------------------------------------------------- + size_t CompositorShadowNode::getLightIdxAssociatedWith( const size_t shadowMapIdx ) const + { + size_t retVal = 0; + if( shadowMapIdx < mDefinition->mShadowMapTexDefinitions.size() ) + retVal = mDefinition->mShadowMapTexDefinitions[shadowMapIdx].light; + return retVal; + } + //----------------------------------------------------------------------------------- void CompositorShadowNode::getMinMaxDepthRange( const Frustum *shadowMapCamera, Real &outMin, Real &outMax ) const { @@ -950,6 +960,11 @@ namespace Ogre return mShadowMapCameras[shadowMapIdx].idxToContiguousTex; } //----------------------------------------------------------------------------------- + float CompositorShadowNode::getNormalOffsetBias( const size_t shadowMapIdx ) const + { + return mDefinition->mShadowMapTexDefinitions[shadowMapIdx].normalOffsetBias; + } + //----------------------------------------------------------------------------------- void CompositorShadowNode::setLightFixedToShadowMap( size_t shadowMapIdx, Light *light ) { assert( shadowMapIdx < mShadowMapCameras.size() ); diff --git a/OgreMain/src/OgreCamera.cpp b/OgreMain/src/OgreCamera.cpp index 2d75de5fa98..5ce8f20daf2 100644 --- a/OgreMain/src/OgreCamera.cpp +++ b/OgreMain/src/OgreCamera.cpp @@ -57,7 +57,8 @@ namespace Ogre { mUseRenderingDistance(true), mLodCamera(0), mUseMinPixelSize(false), - mPixelDisplayRatio(0) + mPixelDisplayRatio(0), + mConstantBiasScale(1.0f) { // Reasonable defaults to camera params diff --git a/OgreMain/src/OgreHlms.cpp b/OgreMain/src/OgreHlms.cpp index c479b47e37e..649cb5c7cbd 100644 --- a/OgreMain/src/OgreHlms.cpp +++ b/OgreMain/src/OgreHlms.cpp @@ -2627,6 +2627,12 @@ namespace Ogre setProperty( propName.c_str(), shadowNode->getIndexToContiguousShadowMapTex( shadowMapTexIdx ) ); + propName.resize( basePropSize ); + propName.a( "_light_idx" ); + setProperty( propName.c_str(), + static_cast( + shadowNode->getLightIdxAssociatedWith( shadowMapTexIdx ) ) ); + if( shadowTexDef->uvOffset != Vector2::ZERO || shadowTexDef->uvLength != Vector2::UNIT_SCALE ) { @@ -2703,6 +2709,12 @@ namespace Ogre propName.a( "_uv_length_y_fract" ); setProperty( propName.c_str(), (int32)(fractPart * 100000.0f) ); } + else if( light->getType() == Light::LT_SPOTLIGHT ) + { + propName.resize( basePropSize ); + propName.a( "_is_spot" ); + setProperty( propName.c_str(), 1 ); + } ++shadowMapTexIdx; } diff --git a/OgreMain/src/OgreHlmsDatablock.cpp b/OgreMain/src/OgreHlmsDatablock.cpp index ae5e73810cc..2eed1adaf94 100644 --- a/OgreMain/src/OgreHlmsDatablock.cpp +++ b/OgreMain/src/OgreHlmsDatablock.cpp @@ -115,7 +115,7 @@ namespace Ogre mAlphaTestCmp( CMPF_ALWAYS_PASS ), mAlphaTestShadowCasterOnly( false ), mAlphaTestThreshold( 0.5f ), - mShadowConstantBias( 0.01f ) + mShadowConstantBias( 0.001f ) { mMacroblockHash[0] = mMacroblockHash[1] = 0; mMacroblock[0] = mMacroblock[1] = 0; diff --git a/OgreMain/src/OgreHlmsManager.cpp b/OgreMain/src/OgreHlmsManager.cpp index 4ceeade062e..25c64fc3438 100644 --- a/OgreMain/src/OgreHlmsManager.cpp +++ b/OgreMain/src/OgreHlmsManager.cpp @@ -44,7 +44,7 @@ namespace Ogre HlmsManager::HlmsManager() : mComputeHlms( 0 ), mRenderSystem( 0 ), - mShadowMappingUseBackFaces( true ), + mShadowMappingUseBackFaces( false ), mDefaultHlmsType( HLMS_PBS ) #if !OGRE_NO_JSON , mJsonListener( 0 ) diff --git a/OgreMain/src/OgreScriptCompiler.cpp b/OgreMain/src/OgreScriptCompiler.cpp index 80a681e779d..b3354433536 100644 --- a/OgreMain/src/OgreScriptCompiler.cpp +++ b/OgreMain/src/OgreScriptCompiler.cpp @@ -1377,6 +1377,8 @@ namespace Ogre mIds["compositor_node_shadow"] = ID_SHADOW_NODE; mIds["num_splits"] = ID_NUM_SPLITS; mIds["num_stable_splits"] = ID_NUM_STABLE_SPLITS; + mIds["normal_offset_bias"] = ID_NORMAL_OFFSET_BIAS; + mIds["constant_bias_scale"] = ID_CONSTANT_BIAS_SCALE; mIds["pssm_split_padding"] = ID_PSSM_SPLIT_PADDING; mIds["pssm_split_blend"] = ID_PSSM_SPLIT_BLEND; mIds["pssm_split_fade"] = ID_PSSM_SPLIT_FADE; diff --git a/OgreMain/src/OgreScriptTranslator.cpp b/OgreMain/src/OgreScriptTranslator.cpp index 97f26bdc484..85d6a298487 100644 --- a/OgreMain/src/OgreScriptTranslator.cpp +++ b/OgreMain/src/OgreScriptTranslator.cpp @@ -7514,7 +7514,51 @@ namespace Ogre{ } } break; - case ID_PSSM_SPLIT_PADDING: + case ID_NORMAL_OFFSET_BIAS: + { + if( prop->values.empty() ) + { + compiler->addError( ScriptCompiler::CE_NUMBEREXPECTED, prop->file, + prop->line ); + } + else if( prop->values.size() != 1 ) + { + compiler->addError( ScriptCompiler::CE_FEWERPARAMETERSEXPECTED, prop->file, + prop->line ); + } + + AbstractNodeList::const_iterator it0 = prop->values.begin(); + if( !getReal( *it0, &defaultParams.normalOffsetBias ) ) + { + compiler->addError( ScriptCompiler::CE_NUMBEREXPECTED, prop->file, + prop->line ); + return; + } + } + break; + case ID_CONSTANT_BIAS_SCALE: + { + if( prop->values.empty() ) + { + compiler->addError( ScriptCompiler::CE_NUMBEREXPECTED, prop->file, + prop->line ); + } + else if( prop->values.size() != 1 ) + { + compiler->addError( ScriptCompiler::CE_FEWERPARAMETERSEXPECTED, prop->file, + prop->line ); + } + + AbstractNodeList::const_iterator it0 = prop->values.begin(); + if( !getReal( *it0, &defaultParams.constantBiasScale ) ) + { + compiler->addError( ScriptCompiler::CE_NUMBEREXPECTED, prop->file, + prop->line ); + return; + } + } + break; + case ID_PSSM_SPLIT_PADDING: { if(prop->values.empty()) { diff --git a/Samples/2.0/ApiUsage/ShadowMapDebugging/ShadowMapDebuggingGameState.cpp b/Samples/2.0/ApiUsage/ShadowMapDebugging/ShadowMapDebuggingGameState.cpp index a61d47716ac..07ae0821d88 100644 --- a/Samples/2.0/ApiUsage/ShadowMapDebugging/ShadowMapDebuggingGameState.cpp +++ b/Samples/2.0/ApiUsage/ShadowMapDebugging/ShadowMapDebuggingGameState.cpp @@ -449,11 +449,6 @@ namespace Demo } #endif - if( nextFilter == Ogre::HlmsPbs::ExponentialShadowMaps ) - pbs->getHlmsManager()->setShadowMappingUseBackFaces( false ); - else - pbs->getHlmsManager()->setShadowMappingUseBackFaces( true ); - pbs->setShadowSettings( nextFilter ); if( nextFilter == Ogre::HlmsPbs::ExponentialShadowMaps ) diff --git a/Samples/Media/Hlms/Common/Any/ShadowCaster_piece_vs.any b/Samples/Media/Hlms/Common/Any/ShadowCaster_piece_vs.any index 75671d04099..48be8522465 100644 --- a/Samples/Media/Hlms/Common/Any/ShadowCaster_piece_vs.any +++ b/Samples/Media/Hlms/Common/Any/ShadowCaster_piece_vs.any @@ -12,9 +12,9 @@ @property( !hlms_shadow_uses_depth_texture && !hlms_shadowcaster_point && !exponential_shadow_maps ) //Linear depth @property( hlms_shadowcaster_directional || !hlms_no_reverse_depth ) - outVs.depth = outVs_Position.z + shadowConstantBias * passBuf.depthRange.y * passBuf.depthRange.y; + outVs.depth = outVs_Position.z + shadowConstantBias; @else - outVs.depth = (outVs_Position.z + shadowConstantBias * passBuf.depthRange.y) * passBuf.depthRange.y; + outVs.depth = outVs_Position.z * passBuf.depthRange.y + shadowConstantBias; @end @property( hlms_no_reverse_depth && (syntax == glsl || syntax == glsles) )outVs.depth = (outVs.depth * 0.5) + 0.5;@end @end @@ -22,7 +22,7 @@ @property( hlms_shadowcaster_point ) outVs.toCameraWS = worldPos.xyz - passBuf.cameraPosWS.xyz; @property( !exponential_shadow_maps ) - outVs.constBias = shadowConstantBias * passBuf.depthRange.y * passBuf.depthRange.y; + outVs.constBias = shadowConstantBias; @end @end @@ -31,16 +31,16 @@ //however we can use a cheap approximation ("pseudo linear depth") //see http://www.yosoygames.com.ar/wp/2014/01/linear-depth-buffer-my-ass/ @property( hlms_shadowcaster_directional || !hlms_no_reverse_depth ) - outVs_Position.z = outVs_Position.z + shadowConstantBias * passBuf.depthRange.y * passBuf.depthRange.y; + outVs_Position.z = outVs_Position.z + shadowConstantBias; @else - outVs_Position.z = (outVs_Position.z + shadowConstantBias * passBuf.depthRange.y) * passBuf.depthRange.y * outVs_Position.w; + outVs_Position.z = (outVs_Position.z * passBuf.depthRange.y + shadowConstantBias) * outVs_Position.w; @end @end @property( exponential_shadow_maps && !hlms_shadowcaster_point ) //It's the same as (float4( worldPos.xyz, 1 ) * viewMatrix).z float linearZ = -(dot( worldPos.xyz, passBuf.viewZRow.xyz ) + passBuf.viewZRow.w); - //linearZ += (shadowConstantBias * passBuf.depthRange.y); + //linearZ += shadowConstantBias; outVs.depth = (linearZ - passBuf.depthRange.x) * passBuf.depthRange.y; @end @end diff --git a/Samples/Media/Hlms/Pbs/Any/Main/500.Structs_piece_vs_piece_ps.any b/Samples/Media/Hlms/Pbs/Any/Main/500.Structs_piece_vs_piece_ps.any index 1ec8b9bb73a..6d9261a42b6 100644 --- a/Samples/Media/Hlms/Pbs/Any/Main/500.Structs_piece_vs_piece_ps.any +++ b/Samples/Media/Hlms/Pbs/Any/Main/500.Structs_piece_vs_piece_ps.any @@ -6,7 +6,8 @@ struct ShadowReceiverData float4 texViewZRow; @end float2 shadowDepthRange; - float2 padding; + float normalOffsetBias; + float padding; float4 invShadowMapSize; }; diff --git a/Samples/Media/Hlms/Pbs/Any/Main/800.VertexShader_piece_vs.any b/Samples/Media/Hlms/Pbs/Any/Main/800.VertexShader_piece_vs.any index 64c144fd03d..7366e1162d5 100644 --- a/Samples/Media/Hlms/Pbs/Any/Main/800.VertexShader_piece_vs.any +++ b/Samples/Media/Hlms/Pbs/Any/Main/800.VertexShader_piece_vs.any @@ -23,6 +23,8 @@ @insertpiece( DeclQuat_yAxis ) @end @end + + @insertpiece( DeclShadowMapMacros ) @end @property( !hlms_skeleton ) @@ -48,8 +50,8 @@ worldPos.y = dot( worldMat[1], inputPos ); worldPos.z = dot( worldMat[2], inputPos ); worldPos.xyz *= inVs_blendWeights[0]; - @property( hlms_normal || hlms_qtangent ) - float3 worldNorm; + @property( hlms_normal || hlms_qtangent ) + float3 worldNorm; worldNorm.x = dot( worldMat[0].xyz, inputNormal ); worldNorm.y = dot( worldMat[1].xyz, inputNormal ); worldNorm.z = dot( worldMat[2].xyz, inputNormal ); @@ -227,6 +229,15 @@ //This newline is required else the Hlms parser will put '#define a #define b' in the same line @property( !hlms_pose_normals )#define inputNormal normal@end + @property( hlms_qtangent ) + //Decode qTangent to TBN with reflection + float3 normal = xAxis( normalize( inVs_qtangent ) ); + @property( normal_map ) + float3 tangent = yAxis( inVs_qtangent ); + outVs.biNormalReflection = sign( inVs_qtangent.w ); //We ensure in C++ qtangent.w is never 0 + @end + @end + @property( !hlms_skeleton && !hlms_pose ) ogre_float4x3 worldMat = UNPACK_MAT4x3( worldMatBuf, inVs_drawId @property( !hlms_shadowcaster )<< 1u@end ); @property( hlms_normal || hlms_qtangent ) @@ -234,14 +245,12 @@ @end float4 worldPos = float4( mul(inVs_vertex, worldMat).xyz, 1.0f ); - @end - - @property( hlms_qtangent ) - //Decode qTangent to TBN with reflection - float3 normal = xAxis( normalize( inVs_qtangent ) ); - @property( normal_map ) - float3 tangent = yAxis( inVs_qtangent ); - outVs.biNormalReflection = sign( inVs_qtangent.w ); //We ensure in C++ qtangent.w is never 0 + @property( hlms_num_shadow_map_lights ) + // We need worldNorm for normal offset bias + float3 worldNorm; + worldNorm.x = dot( worldMat[0].xyz, inputNormal ); + worldNorm.y = dot( worldMat[1].xyz, inputNormal ); + worldNorm.z = dot( worldMat[2].xyz, inputNormal ); @end @end diff --git a/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any b/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any index 58b8b7e0107..0927878266e 100644 --- a/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any +++ b/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any @@ -1,4 +1,4 @@ - + //#include "SyntaxHighlightingMisc.h" @property( hlms_num_shadow_map_lights ) @@ -12,10 +12,10 @@ @property( hlms_shadowmap@n_is_point_light ) #define hlms_shadowmap@n_uv_length float2( @value( hlms_shadowmap@n_uv_length_x_int ).@value( hlms_shadowmap@n_uv_length_x_fract ), @value( hlms_shadowmap@n_uv_length_y_int ).@value( hlms_shadowmap@n_uv_length_y_fract ) ) #define hlms_shadowmap@n_uv_param , hlms_shadowmap@n_uv_min, hlms_shadowmap@n_uv_max, hlms_shadowmap@n_uv_length - @end @property( !hlms_shadowmap@n_is_point_light ) + @else #define hlms_shadowmap@n_uv_param , hlms_shadowmap@n_uv_min, hlms_shadowmap@n_uv_max @end - @end @property( !hlms_shadowmap@n_uvs_fulltex ) + @else #define hlms_shadowmap@n_uv_param @end @end @@ -131,6 +131,25 @@ /// Declare getShadow twice (two overloads). The second one manually /// performs clamp to border to deal with UV atlases. @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, + float shadowMapTexSize, float depthRange + @property( @m == 0 ) + ) + @else + , float2 minUV, float2 maxUV ) + @end + { + float tmpNdotL = saturate( dot( lightDir.xyz, geomNormal.xyz ) ); + + @property( @m == 1 ) + shadowMapTexSize /= maxUV.x - minUV.x; + @end + + return ( ( 1.0f - tmpNdotL ) * (0.00004f) * geomNormal.xyz * shadowMapTexSize ); + } + @end @foreach( 4, m ) @property( @m == 0 ) INLINE float getShadow( @insertpiece( TEXTURE2DSHADOW ) shadowMap, @insertpiece( SamplerShadow ) @@ -140,10 +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 PASSBUF_ARG_DECL ) @end @property( @m == 3 ) INLINE float getShadowPoint( @insertpiece( TEXTURE2DSHADOW ) shadowMap, @insertpiece( SamplerShadow ) + float3 geomNormal, float3 posVS, float3 lightPos, float4 invShadowMapSize, float2 invDepthRange, float2 minUV, float2 maxUV, float2 lengthUV PASSBUF_ARG_DECL ) @@ -164,6 +185,13 @@ @else //Point lights float3 cubemapDir = posVS.xyz - lightPos.xyz; + cubemapDir += getNormalOffsetBias( geomNormal, cubemapDir, + @property( @m == 2 ) + invShadowMapSize.z, invDepthRange.y ); + @else + invShadowMapSize.z, invDepthRange.y, minUV, maxUV ); + @end + float fDepth = length( cubemapDir ); cubemapDir *= 1.0 / fDepth; cubemapDir = mul( cubemapDir.xyz, passBuf.invViewMatCubemap ); @@ -186,12 +214,12 @@ @property( pcf >= 3 ) float2 offsets[@value(pcf_iterations)] = - @property( syntax == glsl || syntax == glsles ) + @property( syntax == glsl || syntax == glsles ) float2[@value(pcf_iterations)]( - @end - @property( syntax != glsl && syntax != glsles ) - { - @end + @end + @property( syntax != glsl && syntax != glsles ) + { + @end @property( pcf == 3 ) float2( 0., 0. ), //0, 0 float2( 1., 0. ), //1, 0 @@ -263,12 +291,12 @@ float2(1, 0), // 1, 2 float2(1, 0) // 2, 2 @end - @property( syntax == glsl || syntax == glsles ) - ); - @end - @property( syntax != glsl && syntax != glsles ) + @property( syntax == glsl || syntax == glsles ) + ); + @end + @property( syntax != glsl && syntax != glsles ) }; - @end + @end @end @insertpiece( regularTexturePcfGlSampling ) @@ -389,7 +417,7 @@ inPs.posL0, passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize hlms_shadowmap@counter(CurrentShadowMap)_uv_param ); - @end @property( !receive_shadows ) + @else float fShadow = 1.0; @end @end @@ -397,6 +425,7 @@ @property( receive_shadows ) @piece( DarkenWithShadowFirstLight )* fShadow@end + @piece( DarkenWithShadow ) * getShadow( hlms_shadowmap@value(CurrentShadowMap), @insertpiece( UseSamplerShadow ) inPs.posL@value(CurrentShadowMap), @@ -408,6 +437,7 @@ @pset( CurrentPointLight, hlms_lights_directional_non_caster ) @piece( DarkenWithShadowPoint ) * getShadowPoint( hlms_shadowmap@value(CurrentShadowMap), @insertpiece( UseSamplerShadow ) + pixelData.geomNormal, inPs.pos.xyz, light0Buf.lights[@counter(CurrentPointLight)].position.xyz, passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize, passBuf.shadowRcv[@value(CurrentShadowMap)].shadowDepthRange.xy diff --git a/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_vs.any b/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_vs.any index ee2df78fe20..97f4df6034a 100644 --- a/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_vs.any +++ b/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_vs.any @@ -2,11 +2,65 @@ //#include "SyntaxHighlightingMisc.h" @property( !hlms_shadowcaster ) + @piece( DeclShadowMapMacros ) + @foreach( hlms_num_shadow_map_lights, n ) + @property( hlms_shadowmap@n_is_directional_light ) + #define shadowMap@nLightDir light0Buf.lights[@value(hlms_shadowmap@n_light_idx)].position.xyz + @end + @property( hlms_shadowmap@n_is_point_light ) + #define shadowMap@nLightDir normalize(light0Buf.lights[@value(hlms_shadowmap@n_light_idx)].position.xyz - outVs.pos) + @end + @property( hlms_shadowmap@n_is_spot ) + #define shadowMap@nLightDir light0Buf.lights[@value(hlms_shadowmap@n_light_idx)].spotDirection.xyz + @end + @end + @foreach( hlms_num_shadow_map_lights, n ) + #define hlms_shadowmap@n_uv_min float2( @value( hlms_shadowmap@n_uv_min_x_int ).@value( hlms_shadowmap@n_uv_min_x_fract ), @value( hlms_shadowmap@n_uv_min_y_int ).@value( hlms_shadowmap@n_uv_min_y_fract ) ) + #define hlms_shadowmap@n_uv_max float2( @value( hlms_shadowmap@n_uv_max_x_int ).@value( hlms_shadowmap@n_uv_max_x_fract ), @value( hlms_shadowmap@n_uv_max_y_int ).@value( hlms_shadowmap@n_uv_max_y_fract ) ) + @property( hlms_shadowmap@n_uvs_fulltex ) + @property( hlms_shadowmap@n_is_point_light ) + #define hlms_shadowmap@n_uv_length float2( @value( hlms_shadowmap@n_uv_length_x_int ).@value( hlms_shadowmap@n_uv_length_x_fract ), @value( hlms_shadowmap@n_uv_length_y_int ).@value( hlms_shadowmap@n_uv_length_y_fract ) ) + #define hlms_shadowmap@n_uv_param , hlms_shadowmap@n_uv_min, hlms_shadowmap@n_uv_max, hlms_shadowmap@n_uv_length + @else + #define hlms_shadowmap@n_uv_param , hlms_shadowmap@n_uv_min, hlms_shadowmap@n_uv_max + @end + @else + #define hlms_shadowmap@n_uv_param + @end + @end + + @foreach( 2, m ) + // Perform normal offset bias. See https://github.com/OGRECave/ogre-next/issues/100 + INLINE float3 getNormalOffsetBias( float3 worldNormal, float3 viewSpaceNormal, float3 lightDir, + float shadowMapTexSize, float depthRange, + float normalOffsetBias + @property( @m == 0 ) + ) + @else + , float2 minUV, float2 maxUV ) + @end + { + float tmpNdotL = saturate( dot( lightDir.xyz, viewSpaceNormal.xyz ) ); + + @property( @m == 1 ) + shadowMapTexSize /= maxUV.x - minUV.x; + @end + + return ( ( 1.0f - tmpNdotL ) * normalOffsetBias * worldNormal.xyz * shadowMapTexSize ); + } + @end + @end + @property( !exponential_shadow_maps ) @piece( DoShadowReceiveVS ) + float3 normalOffsetBias; @foreach( hlms_num_shadow_map_lights, n ) @property( !hlms_shadowmap@n_is_point_light ) - outVs.posL@n = mul( float4(worldPos.xyz, 1.0f), passBuf.shadowRcv[@n].texViewProj );@end @end + normalOffsetBias = getNormalOffsetBias( worldNorm, outVs.normal, shadowMap@nLightDir, + passBuf.shadowRcv[@n].invShadowMapSize.z, passBuf.shadowRcv[@n].shadowDepthRange.y, + passBuf.shadowRcv[@n].normalOffsetBias + hlms_shadowmap@n_uv_param ); + outVs.posL@n = mul( float4(worldPos.xyz + normalOffsetBias, 1.0f), passBuf.shadowRcv[@n].texViewProj );@end @end @foreach( hlms_num_shadow_map_lights, n ) @property( !hlms_shadowmap@n_is_point_light ) From f1b18af1b6e9be811f6947e63a977e0db6c54c09 Mon Sep 17 00:00:00 2001 From: "Matias N. Goldberg" Date: Thu, 11 Jun 2020 20:30:27 -0300 Subject: [PATCH 2/9] Removed setShadowMappingUseBackFaces --- Components/Hlms/Pbs/src/OgreHlmsPbs.cpp | 8 ---- Components/Hlms/Unlit/src/OgreHlmsUnlit.cpp | 8 ---- OgreMain/include/OgreHlms.h | 3 -- OgreMain/include/OgreHlmsManager.h | 15 ------- OgreMain/src/OgreHlms.cpp | 14 ------- OgreMain/src/OgreHlmsDatablock.cpp | 42 ++----------------- OgreMain/src/OgreHlmsManager.cpp | 15 ------- .../ShadowMapFromCodeGameState.cpp | 5 --- 8 files changed, 4 insertions(+), 106 deletions(-) diff --git a/Components/Hlms/Pbs/src/OgreHlmsPbs.cpp b/Components/Hlms/Pbs/src/OgreHlmsPbs.cpp index 7a6b93e4362..949699ed850 100644 --- a/Components/Hlms/Pbs/src/OgreHlmsPbs.cpp +++ b/Components/Hlms/Pbs/src/OgreHlmsPbs.cpp @@ -3499,14 +3499,6 @@ namespace Ogre void HlmsPbs::setShadowSettings( ShadowFilter filter ) { mShadowFilter = filter; - - if( mShadowFilter == ExponentialShadowMaps && mHlmsManager->getShadowMappingUseBackFaces() ) - { - LogManager::getSingleton().logMessage( - "QUALITY WARNING: It is highly recommended that you call " - "mHlmsManager->setShadowMappingUseBackFaces( false ) when using Exponential " - "Shadow Maps (HlmsPbs::setShadowSettings)" ); - } } //----------------------------------------------------------------------------------- void HlmsPbs::setEsmK( uint16 K ) diff --git a/Components/Hlms/Unlit/src/OgreHlmsUnlit.cpp b/Components/Hlms/Unlit/src/OgreHlmsUnlit.cpp index afca5971483..1587ff416af 100644 --- a/Components/Hlms/Unlit/src/OgreHlmsUnlit.cpp +++ b/Components/Hlms/Unlit/src/OgreHlmsUnlit.cpp @@ -1061,14 +1061,6 @@ namespace Ogre void HlmsUnlit::setShadowSettings( bool useExponentialShadowMaps ) { mUsingExponentialShadowMaps = useExponentialShadowMaps; - - if( mUsingExponentialShadowMaps && mHlmsManager->getShadowMappingUseBackFaces() ) - { - LogManager::getSingleton().logMessage( - "QUALITY WARNING: It is highly recommended that you call " - "mHlmsManager->setShadowMappingUseBackFaces( false ) when using Exponential " - "Shadow Maps (HlmsUnlit::setShadowSettings)" ); - } } //----------------------------------------------------------------------------------- void HlmsUnlit::setEsmK( uint16 K ) diff --git a/OgreMain/include/OgreHlms.h b/OgreMain/include/OgreHlms.h index 995e20bc3f5..66bcde54ae6 100644 --- a/OgreMain/include/OgreHlms.h +++ b/OgreMain/include/OgreHlms.h @@ -799,9 +799,6 @@ namespace Ogre static int32 getProperty( const HlmsPropertyVec &properties, IdString key, int32 defaultVal=0 ); - /// Internal use. @see HlmsManager::setShadowMappingUseBackFaces - void _notifyShadowMappingBackFaceSetting(void); - void _clearShaderCache(void); virtual void _changeRenderSystem( RenderSystem *newRs ); diff --git a/OgreMain/include/OgreHlmsManager.h b/OgreMain/include/OgreHlmsManager.h index 3eec86b5ec7..4a06c5ab2ab 100644 --- a/OgreMain/include/OgreHlmsManager.h +++ b/OgreMain/include/OgreHlmsManager.h @@ -113,7 +113,6 @@ namespace Ogre InputLayoutsVec mInputLayouts; RenderSystem *mRenderSystem; - bool mShadowMappingUseBackFaces; public: typedef std::map HlmsDatablockMap; protected: @@ -321,20 +320,6 @@ namespace Ogre void registerComputeHlms( HlmsCompute *provider ); void unregisterComputeHlms(void); - /** Sets whether or not shadow casters should be rendered into shadow - textures using their back faces rather than their front faces. - @remarks - Rendering back faces rather than front faces into a shadow texture - can help minimise depth comparison issues, if you're using depth - shadowmapping. You will probably still need some biasing but you - won't need as much. For solid objects the result is the same anyway, - if you have objects with holes you may want to turn this option off. - The default is to enable this option. - */ - void setShadowMappingUseBackFaces( bool useBackFaces ); - - bool getShadowMappingUseBackFaces(void) { return mShadowMappingUseBackFaces; } - void _changeRenderSystem( RenderSystem *newRs ); RenderSystem* getRenderSystem(void) const { return mRenderSystem; } diff --git a/OgreMain/src/OgreHlms.cpp b/OgreMain/src/OgreHlms.cpp index 649cb5c7cbd..96455431148 100644 --- a/OgreMain/src/OgreHlms.cpp +++ b/OgreMain/src/OgreHlms.cpp @@ -3186,20 +3186,6 @@ namespace Ogre return mListener == &c_defaultListener ? 0 : mListener; } //----------------------------------------------------------------------------------- - void Hlms::_notifyShadowMappingBackFaceSetting(void) - { - HlmsDatablockMap::const_iterator itor = mDatablocks.begin(); - HlmsDatablockMap::const_iterator end = mDatablocks.end(); - - while( itor != end ) - { - HlmsDatablock *datablock = itor->second.datablock; - datablock->setMacroblock( datablock->getMacroblock( false ), false ); - - ++itor; - } - } - //----------------------------------------------------------------------------------- void Hlms::_clearShaderCache(void) { clearShaderCache(); diff --git a/OgreMain/src/OgreHlmsDatablock.cpp b/OgreMain/src/OgreHlmsDatablock.cpp index 2eed1adaf94..eaecd11b410 100644 --- a/OgreMain/src/OgreHlmsDatablock.cpp +++ b/OgreMain/src/OgreHlmsDatablock.cpp @@ -247,19 +247,7 @@ namespace Ogre if( !casterBlock ) { mIgnoreFlushRenderables = true; - bool useBackFaces = mCreator->getHlmsManager()->getShadowMappingUseBackFaces(); - - if( useBackFaces && macroblock.mCullMode != CULL_NONE ) - { - HlmsMacroblock casterblock = macroblock; - casterblock.mCullMode = macroblock.mCullMode == CULL_CLOCKWISE ? CULL_ANTICLOCKWISE : - CULL_CLOCKWISE; - setMacroblock( casterblock, true ); - } - else - { - setMacroblock( mMacroblock[0], true ); - } + setMacroblock( mMacroblock[0], true ); mIgnoreFlushRenderables = false; } @@ -289,19 +277,7 @@ namespace Ogre if( !casterBlock ) { mIgnoreFlushRenderables = true; - bool useBackFaces = mCreator->getHlmsManager()->getShadowMappingUseBackFaces(); - - if( useBackFaces && macroblock->mCullMode != CULL_NONE ) - { - HlmsMacroblock casterblock = *macroblock; - casterblock.mCullMode = macroblock->mCullMode == CULL_CLOCKWISE ? CULL_ANTICLOCKWISE : - CULL_CLOCKWISE; - setMacroblock( casterblock, true ); - } - else - { - setMacroblock( mMacroblock[0], true ); - } + setMacroblock( mMacroblock[0], true ); mIgnoreFlushRenderables = false; } @@ -505,20 +481,10 @@ namespace Ogre bool HlmsDatablock::hasCustomShadowMacroblock(void) const { const HlmsMacroblock *macroblock0 = mMacroblock[0]; - //Hard copy - HlmsMacroblock macroblock1 = *mMacroblock[1]; - - const bool useBackFaces = mCreator->getHlmsManager()->getShadowMappingUseBackFaces(); - - //Revert the flipping - if( useBackFaces && macroblock0->mCullMode != CULL_NONE && macroblock1.mCullMode != CULL_NONE ) - { - macroblock1.mCullMode = macroblock1.mCullMode == CULL_CLOCKWISE ? CULL_ANTICLOCKWISE : - CULL_CLOCKWISE; - } + const HlmsMacroblock *macroblock1 = mMacroblock[1]; //Now compare if they're equal - return *macroblock0 != macroblock1; + return *macroblock0 != *macroblock1; } //----------------------------------------------------------------------------------- ColourValue HlmsDatablock::getDiffuseColour(void) const diff --git a/OgreMain/src/OgreHlmsManager.cpp b/OgreMain/src/OgreHlmsManager.cpp index 25c64fc3438..dcd6edcd6f8 100644 --- a/OgreMain/src/OgreHlmsManager.cpp +++ b/OgreMain/src/OgreHlmsManager.cpp @@ -44,7 +44,6 @@ namespace Ogre HlmsManager::HlmsManager() : mComputeHlms( 0 ), mRenderSystem( 0 ), - mShadowMappingUseBackFaces( false ), mDefaultHlmsType( HLMS_PBS ) #if !OGRE_NO_JSON , mJsonListener( 0 ) @@ -663,20 +662,6 @@ namespace Ogre } } //----------------------------------------------------------------------------------- - void HlmsManager::setShadowMappingUseBackFaces( bool useBackFaces ) - { - if( mShadowMappingUseBackFaces != useBackFaces ) - { - mShadowMappingUseBackFaces = useBackFaces; - - for( int i=0; i_notifyShadowMappingBackFaceSetting(); - } - } - } - //----------------------------------------------------------------------------------- void HlmsManager::renderSystemDestroyAllBlocks(void) { if( mRenderSystem ) diff --git a/Samples/2.0/ApiUsage/ShadowMapFromCode/ShadowMapFromCodeGameState.cpp b/Samples/2.0/ApiUsage/ShadowMapFromCode/ShadowMapFromCodeGameState.cpp index a9bb59afd7f..74fb53b7d81 100644 --- a/Samples/2.0/ApiUsage/ShadowMapFromCode/ShadowMapFromCodeGameState.cpp +++ b/Samples/2.0/ApiUsage/ShadowMapFromCode/ShadowMapFromCodeGameState.cpp @@ -430,11 +430,6 @@ namespace Demo } #endif - if( nextFilter == Ogre::HlmsPbs::ExponentialShadowMaps ) - pbs->getHlmsManager()->setShadowMappingUseBackFaces( false ); - else - pbs->getHlmsManager()->setShadowMappingUseBackFaces( true ); - pbs->setShadowSettings( nextFilter ); if( nextFilter == Ogre::HlmsPbs::ExponentialShadowMaps ) From 4d291e00eb3f533e741b4b5957faeba35519cdb0 Mon Sep 17 00:00:00 2001 From: "Matias N. Goldberg" Date: Fri, 12 Jun 2020 14:45:02 -0300 Subject: [PATCH 3/9] Fix crash in Terrain vertex shader due to Normal Offset Bias --- .../src/Terra/Hlms/OgreHlmsTerra.cpp | 6 ++++++ .../Media/Hlms/Pbs/Any/ShadowMapping_piece_vs.any | 13 ++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Samples/2.0/Tutorials/Tutorial_Terrain/src/Terra/Hlms/OgreHlmsTerra.cpp b/Samples/2.0/Tutorials/Tutorial_Terrain/src/Terra/Hlms/OgreHlmsTerra.cpp index 47106ecb357..beebcefd82f 100644 --- a/Samples/2.0/Tutorials/Tutorial_Terrain/src/Terra/Hlms/OgreHlmsTerra.cpp +++ b/Samples/2.0/Tutorials/Tutorial_Terrain/src/Terra/Hlms/OgreHlmsTerra.cpp @@ -255,6 +255,12 @@ namespace Ogre assert( dynamic_cast(renderable) && "This Hlms can only be used on a Terra object!" ); + // Disable normal offset bias because the world normals are not available in the + // vertex shader. We could fetch the normals, but tessellation is constantly changing in + // Terra, and besides we don't care because Terra doesn't cast shadow maps, thus it + // has no self occlussion artifacts. + setProperty( "skip_normal_offset_bias_vs", 1 ); + TerrainCell *terrainCell = static_cast(renderable); setProperty( TerraProperty::UseSkirts, terrainCell->getUseSkirts() ); diff --git a/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_vs.any b/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_vs.any index 97f4df6034a..672276911ba 100644 --- a/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_vs.any +++ b/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_vs.any @@ -53,13 +53,16 @@ @property( !exponential_shadow_maps ) @piece( DoShadowReceiveVS ) - float3 normalOffsetBias; + float3 normalOffsetBias = float3( 0, 0, 0 ); @foreach( hlms_num_shadow_map_lights, n ) @property( !hlms_shadowmap@n_is_point_light ) - normalOffsetBias = getNormalOffsetBias( worldNorm, outVs.normal, shadowMap@nLightDir, - passBuf.shadowRcv[@n].invShadowMapSize.z, passBuf.shadowRcv[@n].shadowDepthRange.y, - passBuf.shadowRcv[@n].normalOffsetBias - hlms_shadowmap@n_uv_param ); + @property( !skip_normal_offset_bias_vs ) + normalOffsetBias = getNormalOffsetBias( worldNorm, outVs.normal, shadowMap@nLightDir, + passBuf.shadowRcv[@n].invShadowMapSize.z, + passBuf.shadowRcv[@n].shadowDepthRange.y, + passBuf.shadowRcv[@n].normalOffsetBias + hlms_shadowmap@n_uv_param ); + @end outVs.posL@n = mul( float4(worldPos.xyz + normalOffsetBias, 1.0f), passBuf.shadowRcv[@n].texViewProj );@end @end @foreach( hlms_num_shadow_map_lights, n ) From b14fdf8a985ef518c00dcdbe8ce00ea278772d47 Mon Sep 17 00:00:00 2001 From: "Matias N. Goldberg" Date: Fri, 12 Jun 2020 19:07:19 -0300 Subject: [PATCH 4/9] Changed the default values of mShadowConstantBias and constantBiasScale for much better backwards compatibility with older materials --- Components/Hlms/Pbs/src/OgreHlmsPbs.cpp | 2 +- Components/Hlms/Unlit/src/OgreHlmsUnlit.cpp | 4 ++-- Docs/src/manual/compositor.md | 2 +- OgreMain/include/Compositor/OgreCompositorShadowNodeDef.h | 2 +- OgreMain/src/OgreHlmsDatablock.cpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Components/Hlms/Pbs/src/OgreHlmsPbs.cpp b/Components/Hlms/Pbs/src/OgreHlmsPbs.cpp index 949699ed850..04243f2ba1c 100644 --- a/Components/Hlms/Pbs/src/OgreHlmsPbs.cpp +++ b/Components/Hlms/Pbs/src/OgreHlmsPbs.cpp @@ -289,7 +289,7 @@ namespace Ogre mDecalsDiffuseMergedEmissive( false ), mDecalsSamplerblock( 0 ), mLastBoundPool( 0 ), - mConstantBiasScale( 1.0f ), + mConstantBiasScale( 0.1f ), mHasSeparateSamplers( 0 ), mLastDescTexture( 0 ), mLastDescSampler( 0 ), diff --git a/Components/Hlms/Unlit/src/OgreHlmsUnlit.cpp b/Components/Hlms/Unlit/src/OgreHlmsUnlit.cpp index 1587ff416af..4a92cce32cc 100644 --- a/Components/Hlms/Unlit/src/OgreHlmsUnlit.cpp +++ b/Components/Hlms/Unlit/src/OgreHlmsUnlit.cpp @@ -80,7 +80,7 @@ namespace Ogre mHasSeparateSamplers( 0 ), mLastDescTexture( 0 ), mLastDescSampler( 0 ), - mConstantBiasScale( 1.0f ), + mConstantBiasScale( 0.1f ), mUsingInstancedStereo( false ), mUsingExponentialShadowMaps( false ), mEsmK( 600u ), @@ -105,7 +105,7 @@ namespace Ogre mLastBoundPool( 0 ), mLastDescTexture( 0 ), mLastDescSampler( 0 ), - mConstantBiasScale( 1.0f ), + mConstantBiasScale( 0.1f ), mUsingInstancedStereo( false ), mUsingExponentialShadowMaps( false ), mEsmK( 600u ), diff --git a/Docs/src/manual/compositor.md b/Docs/src/manual/compositor.md index c1549fc9092..84bd90e1fa8 100644 --- a/Docs/src/manual/compositor.md +++ b/Docs/src/manual/compositor.md @@ -1304,7 +1304,7 @@ This value lets you multiply it 'mShadowConstantBias * constantBiasScale' per ca Large values can cause peter-panning. -Default is 1.0 +Default is 0.1 for backwards compatibility with older materials created by Ogre 2.2.2 and earlier - pssm\_lambda \ diff --git a/OgreMain/include/Compositor/OgreCompositorShadowNodeDef.h b/OgreMain/include/Compositor/OgreCompositorShadowNodeDef.h index 799844c19ac..db0efca3ba4 100644 --- a/OgreMain/include/Compositor/OgreCompositorShadowNodeDef.h +++ b/OgreMain/include/Compositor/OgreCompositorShadowNodeDef.h @@ -94,7 +94,7 @@ namespace Ogre arrayIdx( _arrayIdx ), light( _light ), split( _split ), - constantBiasScale( 1.0f ), + constantBiasScale( 0.1f ), normalOffsetBias( 0.00004f ), shadowMapTechnique( t ), pssmLambda( 0.95f ), diff --git a/OgreMain/src/OgreHlmsDatablock.cpp b/OgreMain/src/OgreHlmsDatablock.cpp index eaecd11b410..d46d1fbb0bf 100644 --- a/OgreMain/src/OgreHlmsDatablock.cpp +++ b/OgreMain/src/OgreHlmsDatablock.cpp @@ -115,7 +115,7 @@ namespace Ogre mAlphaTestCmp( CMPF_ALWAYS_PASS ), mAlphaTestShadowCasterOnly( false ), mAlphaTestThreshold( 0.5f ), - mShadowConstantBias( 0.001f ) + mShadowConstantBias( 0.01f ) { mMacroblockHash[0] = mMacroblockHash[1] = 0; mMacroblock[0] = mMacroblock[1] = 0; From 50d84a843d5fabcb8ca123a300b392b8df00383c Mon Sep 17 00:00:00 2001 From: "Matias N. Goldberg" Date: Fri, 19 Jun 2020 16:42:12 -0300 Subject: [PATCH 5/9] Fix stable PSSM outputting the wrong min/max range --- OgreMain/src/OgreShadowCameraSetupPSSM.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OgreMain/src/OgreShadowCameraSetupPSSM.cpp b/OgreMain/src/OgreShadowCameraSetupPSSM.cpp index 4b7b200dfbb..6a0486f569a 100644 --- a/OgreMain/src/OgreShadowCameraSetupPSSM.cpp +++ b/OgreMain/src/OgreShadowCameraSetupPSSM.cpp @@ -147,6 +147,8 @@ namespace Ogre { mConcentricShadowCamera.getShadowCamera( sm, cam, light, texCam, iteration, viewportRealSize ); + mMinDistance = mConcentricShadowCamera.getMinDistance(); + mMaxDistance = mConcentricShadowCamera.getMaxDistance(); } else { From 652acb35572df6041410a5c366edd7de5d9bec80 Mon Sep 17 00:00:00 2001 From: "Matias N. Goldberg" Date: Fri, 19 Jun 2020 19:57:43 -0300 Subject: [PATCH 6/9] Multiple shadow mapping improvements (#100). See description 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. --- .../Compositor/OgreCompositorShadowNodeDef.h | 17 +++++++- OgreMain/include/OgreCamera.h | 5 +++ OgreMain/include/OgreHlmsDatablock.h | 2 + OgreMain/include/OgreHlmsPso.h | 1 + .../include/OgreRenderSystemCapabilities.h | 1 + .../Compositor/OgreCompositorShadowNode.cpp | 39 +++++++++++++++++-- OgreMain/src/OgreCamera.cpp | 6 +++ OgreMain/src/OgreHlms.cpp | 11 ++++++ OgreMain/src/OgreHlmsDatablock.cpp | 1 + OgreMain/src/OgreShadowCameraSetupFocused.cpp | 7 ++++ .../Direct3D11/src/OgreD3D11RenderSystem.cpp | 4 +- .../GL3Plus/src/OgreGL3PlusRenderSystem.cpp | 14 +++++++ .../Metal/src/OgreMetalRenderSystem.mm | 8 ++++ .../Hlms/Common/Any/ShadowCaster_piece_vs.any | 4 +- .../Hlms/Pbs/Any/ShadowMapping_piece_ps.any | 19 ++++----- .../Hlms/Pbs/Any/ShadowMapping_piece_vs.any | 2 +- 16 files changed, 123 insertions(+), 18 deletions(-) diff --git a/OgreMain/include/Compositor/OgreCompositorShadowNodeDef.h b/OgreMain/include/Compositor/OgreCompositorShadowNodeDef.h index db0efca3ba4..f2aa1861d90 100644 --- a/OgreMain/include/Compositor/OgreCompositorShadowNodeDef.h +++ b/OgreMain/include/Compositor/OgreCompositorShadowNodeDef.h @@ -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 @@ -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 ), diff --git a/OgreMain/include/OgreCamera.h b/OgreMain/include/OgreCamera.h index ff2fb8d2f06..b901c964c2a 100644 --- a/OgreMain/include/OgreCamera.h +++ b/OgreMain/include/OgreCamera.h @@ -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 @@ -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 diff --git a/OgreMain/include/OgreHlmsDatablock.h b/OgreMain/include/OgreHlmsDatablock.h index e4ca6ff1138..2f1627b22db 100644 --- a/OgreMain/include/OgreHlmsDatablock.h +++ b/OgreMain/include/OgreHlmsDatablock.h @@ -77,6 +77,7 @@ namespace Ogre struct _OgreExport HlmsMacroblock : public BasicBlock { bool mScissorTestEnabled; + bool mDepthClamp; bool mDepthCheck; bool mDepthWrite; CompareFunction mDepthFunc; @@ -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 || diff --git a/OgreMain/include/OgreHlmsPso.h b/OgreMain/include/OgreHlmsPso.h index e0fed274206..e92e22b85c2 100644 --- a/OgreMain/include/OgreHlmsPso.h +++ b/OgreMain/include/OgreHlmsPso.h @@ -141,6 +141,7 @@ namespace Ogre ForceDisableDepthWrites = 1u << 0u, InvertVertexWinding = 1u << 1u, NoDepthBuffer = 1u << 2u, + ForceDepthClamp = 1u << 3u, }; }; diff --git a/OgreMain/include/OgreRenderSystemCapabilities.h b/OgreMain/include/OgreRenderSystemCapabilities.h index bc91b9546c9..fa05228ba69 100644 --- a/OgreMain/include/OgreRenderSystemCapabilities.h +++ b/OgreMain/include/OgreRenderSystemCapabilities.h @@ -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 diff --git a/OgreMain/src/Compositor/OgreCompositorShadowNode.cpp b/OgreMain/src/Compositor/OgreCompositorShadowNode.cpp index 49a09bd025a..dc721d9051b 100644 --- a/OgreMain/src/Compositor/OgreCompositorShadowNode.cpp +++ b/OgreMain/src/Compositor/OgreCompositorShadowNode.cpp @@ -566,8 +566,6 @@ namespace Ogre texCamera->setAutoAspectRatio( false ); } - texCamera->_setConstantBiasScale( itor->constantBiasScale ); - if( itor->shadowMapTechnique == SHADOWMAP_PSSM ) { assert( dynamic_cast @@ -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 @@ -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 ) diff --git a/OgreMain/src/OgreCamera.cpp b/OgreMain/src/OgreCamera.cpp index 5ce8f20daf2..fc11a35df6a 100644 --- a/OgreMain/src/OgreCamera.cpp +++ b/OgreMain/src/OgreCamera.cpp @@ -56,6 +56,7 @@ namespace Ogre { mCullFrustum(0), mUseRenderingDistance(true), mLodCamera(0), + mNeedsDepthClamp(false), mUseMinPixelSize(false), mPixelDisplayRatio(0), mConstantBiasScale(1.0f) @@ -1131,6 +1132,11 @@ namespace Ogre { } //----------------------------------------------------------------------- + void Camera::_setNeedsDepthClamp( bool bNeedsDepthClamp ) + { + mNeedsDepthClamp = bNeedsDepthClamp; + } + //----------------------------------------------------------------------- void Camera::_resetRenderedRqs( size_t numRqs ) { mRenderedRqs.clear(); diff --git a/OgreMain/src/OgreHlms.cpp b/OgreMain/src/OgreHlms.cpp index 96455431148..ce6adfc5d87 100644 --- a/OgreMain/src/OgreHlms.cpp +++ b/OgreMain/src/OgreHlms.cpp @@ -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() ) { @@ -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 ); } @@ -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) || diff --git a/OgreMain/src/OgreHlmsDatablock.cpp b/OgreMain/src/OgreHlmsDatablock.cpp index d46d1fbb0bf..7fc26a7299b 100644 --- a/OgreMain/src/OgreHlmsDatablock.cpp +++ b/OgreMain/src/OgreHlmsDatablock.cpp @@ -54,6 +54,7 @@ namespace Ogre HlmsMacroblock::HlmsMacroblock() : BasicBlock( BLOCK_MACRO ), mScissorTestEnabled( false ), + mDepthClamp( false ), mDepthCheck( true ), mDepthWrite( true ), mDepthFunc( CMPF_LESS_EQUAL ), diff --git a/OgreMain/src/OgreShadowCameraSetupFocused.cpp b/OgreMain/src/OgreShadowCameraSetupFocused.cpp index 50cffdead06..791aa266fbc 100644 --- a/OgreMain/src/OgreShadowCameraSetupFocused.cpp +++ b/OgreMain/src/OgreShadowCameraSetupFocused.cpp @@ -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; diff --git a/RenderSystems/Direct3D11/src/OgreD3D11RenderSystem.cpp b/RenderSystems/Direct3D11/src/OgreD3D11RenderSystem.cpp index 288896a6932..0c6bf344e48 100644 --- a/RenderSystems/Direct3D11/src/OgreD3D11RenderSystem.cpp +++ b/RenderSystems/Direct3D11/src/OgreD3D11RenderSystem.cpp @@ -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); @@ -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; diff --git a/RenderSystems/GL3Plus/src/OgreGL3PlusRenderSystem.cpp b/RenderSystems/GL3Plus/src/OgreGL3PlusRenderSystem.cpp index 8220b74c342..88c911b5d64 100644 --- a/RenderSystems/GL3Plus/src/OgreGL3PlusRenderSystem.cpp +++ b/RenderSystems/GL3Plus/src/OgreGL3PlusRenderSystem.cpp @@ -399,6 +399,12 @@ namespace Ogre { rsc->setCapability(RSC_TYPED_UAV_LOADS); } + if( mHasGL43 || mGLSupport->checkExtension( "GL_ARB_depth_clamp" ) || + 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 ); @@ -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 ) diff --git a/RenderSystems/Metal/src/OgreMetalRenderSystem.mm b/RenderSystems/Metal/src/OgreMetalRenderSystem.mm index df9dd4a0fe1..cef115f499f 100644 --- a/RenderSystems/Metal/src/OgreMetalRenderSystem.mm +++ b/RenderSystems/Metal/src/OgreMetalRenderSystem.mm @@ -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 @@ -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 ) { diff --git a/Samples/Media/Hlms/Common/Any/ShadowCaster_piece_vs.any b/Samples/Media/Hlms/Common/Any/ShadowCaster_piece_vs.any index 48be8522465..3d51cc42251 100644 --- a/Samples/Media/Hlms/Common/Any/ShadowCaster_piece_vs.any +++ b/Samples/Media/Hlms/Common/Any/ShadowCaster_piece_vs.any @@ -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 ) diff --git a/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any b/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any index 0927878266e..2a20e2a3b96 100644 --- a/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any +++ b/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any @@ -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 ) ) @@ -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 ) @@ -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 ) @@ -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 ); @@ -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 ) diff --git a/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_vs.any b/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_vs.any index 672276911ba..151c7c7beac 100644 --- a/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_vs.any +++ b/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_vs.any @@ -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 ); From 739b079964c71dc44271871a25951bfb657e6718 Mon Sep 17 00:00:00 2001 From: "Matias N. Goldberg" Date: Sat, 20 Jun 2020 13:07:17 -0300 Subject: [PATCH 7/9] Regression: point light shadows not working correctly (#100) Thanks SolarPortal for the report --- Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any b/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any index 2a20e2a3b96..6e3b9f5793e 100644 --- a/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any +++ b/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any @@ -439,7 +439,7 @@ * getShadowPoint( hlms_shadowmap@value(CurrentShadowMap), @insertpiece( UseSamplerShadow ) pixelData.geomNormal, passBuf.shadowRcv[@value(CurrentShadowMap)].normalOffsetBias, - inPs.pos.xyz, light0Buf.lights[@value(CurrentPointLight)].position.xyz, + inPs.pos.xyz, light0Buf.lights[@counter(CurrentPointLight)].position.xyz, passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize, passBuf.shadowRcv[@value(CurrentShadowMap)].shadowDepthRange.xy hlms_shadowmap@counter(CurrentShadowMap)_uv_param PASSBUF_ARG ) From 83a76d857a6c2845e48cce5f79d48e5811d4d1b7 Mon Sep 17 00:00:00 2001 From: "Matias N. Goldberg" Date: Sun, 21 Jun 2020 19:24:59 -0300 Subject: [PATCH 8/9] Added depth_clamp to JSON materials --- Docs/2.0/JSON/PbsAllSettings.json | 1 + Docs/2.0/JSON/PbsExample.material.json | 1 + OgreMain/src/OgreHlmsJson.cpp | 7 +++++++ 3 files changed, 9 insertions(+) diff --git a/Docs/2.0/JSON/PbsAllSettings.json b/Docs/2.0/JSON/PbsAllSettings.json index edf78e531f9..3b8c21a35d3 100644 --- a/Docs/2.0/JSON/PbsAllSettings.json +++ b/Docs/2.0/JSON/PbsAllSettings.json @@ -26,6 +26,7 @@ including invalid combinations (i.e. having a Metallic texture and a Specular te "unique_name" : { "scissor_test" : false, + "depth_clamp" : false, "depth_check" : true, "depth_write" : true, "depth_function" : "less" "less_equal" "equal" "not_equal" "greater_equal" "greater" "never" "always", diff --git a/Docs/2.0/JSON/PbsExample.material.json b/Docs/2.0/JSON/PbsExample.material.json index 3e390aa87cc..b0e5a2542a8 100644 --- a/Docs/2.0/JSON/PbsExample.material.json +++ b/Docs/2.0/JSON/PbsExample.material.json @@ -23,6 +23,7 @@ "unique_name" : { "scissor_test" : false, + "depth_clamp" : false, "depth_check" : true, "depth_write" : true, "depth_function" : "less_equal", diff --git a/OgreMain/src/OgreHlmsJson.cpp b/OgreMain/src/OgreHlmsJson.cpp index d020460a630..7922893e426 100644 --- a/OgreMain/src/OgreHlmsJson.cpp +++ b/OgreMain/src/OgreHlmsJson.cpp @@ -310,6 +310,10 @@ namespace Ogre if( itor != macroblocksJson.MemberEnd() && itor->value.IsBool() ) macroblock.mScissorTestEnabled = itor->value.GetBool(); + itor = macroblocksJson.FindMember("depth_clamp"); + if( itor != macroblocksJson.MemberEnd() && itor->value.IsBool() ) + macroblock.mDepthClamp = itor->value.GetBool(); + itor = macroblocksJson.FindMember("depth_check"); if( itor != macroblocksJson.MemberEnd() && itor->value.IsBool() ) macroblock.mDepthCheck = itor->value.GetBool(); @@ -846,6 +850,9 @@ namespace Ogre outString += "\t\t\t\"scissor_test\" : "; outString += macroblock->mScissorTestEnabled ? "true" : "false"; + outString += ",\n\t\t\t\"depth_clamp\" : "; + outString += macroblock->mDepthClamp ? "true" : "false"; + outString += ",\n\t\t\t\"depth_check\" : "; outString += macroblock->mDepthCheck ? "true" : "false"; From 47d81e0044e0a0db8112a2d43d6c2f58a5606997 Mon Sep 17 00:00:00 2001 From: "Matias N. Goldberg" Date: Mon, 22 Jun 2020 20:30:07 -0300 Subject: [PATCH 9/9] Fixed shadow acne in D3D11 (#100) OpenGL was looking fine Metal was possibly affected --- .../Media/Hlms/Pbs/Any/Main/800.VertexShader_piece_vs.any | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Samples/Media/Hlms/Pbs/Any/Main/800.VertexShader_piece_vs.any b/Samples/Media/Hlms/Pbs/Any/Main/800.VertexShader_piece_vs.any index 7366e1162d5..8c6a1dde827 100644 --- a/Samples/Media/Hlms/Pbs/Any/Main/800.VertexShader_piece_vs.any +++ b/Samples/Media/Hlms/Pbs/Any/Main/800.VertexShader_piece_vs.any @@ -247,10 +247,7 @@ float4 worldPos = float4( mul(inVs_vertex, worldMat).xyz, 1.0f ); @property( hlms_num_shadow_map_lights ) // We need worldNorm for normal offset bias - float3 worldNorm; - worldNorm.x = dot( worldMat[0].xyz, inputNormal ); - worldNorm.y = dot( worldMat[1].xyz, inputNormal ); - worldNorm.z = dot( worldMat[2].xyz, inputNormal ); + float3 worldNorm = mul( inputNormal, toFloat3x3( worldMat ) ).xyz; @end @end