From 3d68c1af09db83cabd276669a407ab99926a76b6 Mon Sep 17 00:00:00 2001 From: "Matias N. Goldberg" Date: Tue, 31 Dec 2024 15:45:39 -0300 Subject: [PATCH] Add accurate_non_uniform_normal_scaling material option Fixes #373 --- Components/Hlms/Pbs/src/OgreHlmsPbs.cpp | 3 ++ Docs/2.0/JSON/PbsAllSettings.json | 1 + Docs/2.0/JSON/PbsExample.material.json | 1 + .../Scripts/HlmsPBSDatablockReference.md | 5 +++ OgreMain/include/OgreHlms.h | 1 + OgreMain/include/OgreHlmsDatablock.h | 44 +++++++++++++++++++ OgreMain/src/OgreHlms.cpp | 2 + OgreMain/src/OgreHlmsDatablock.cpp | 9 ++++ OgreMain/src/OgreHlmsJson.cpp | 7 +++ .../Any/Main/800.VertexShader_piece_vs.any | 2 +- 10 files changed, 74 insertions(+), 1 deletion(-) diff --git a/Components/Hlms/Pbs/src/OgreHlmsPbs.cpp b/Components/Hlms/Pbs/src/OgreHlmsPbs.cpp index 930591bc02f..cb8de7728c3 100644 --- a/Components/Hlms/Pbs/src/OgreHlmsPbs.cpp +++ b/Components/Hlms/Pbs/src/OgreHlmsPbs.cpp @@ -764,6 +764,9 @@ namespace Ogre setProperty( kNoTid, PbsProperty::FresnelWorkflow, fresnelWorkflow ); setProperty( kNoTid, PbsProperty::MetallicWorkflow, metallicWorkflow ); + if( datablock->getAccurateNonUniformNormalScaling() ) + setProperty( kNoTid, HlmsBaseProp::AccurateNonUniformNormalScaling, 1 ); + if( datablock->getTwoSidedLighting() ) setProperty( kNoTid, PbsProperty::TwoSidedLighting, 1 ); diff --git a/Docs/2.0/JSON/PbsAllSettings.json b/Docs/2.0/JSON/PbsAllSettings.json index 0c915903bb1..8d17744755d 100644 --- a/Docs/2.0/JSON/PbsAllSettings.json +++ b/Docs/2.0/JSON/PbsAllSettings.json @@ -61,6 +61,7 @@ including invalid combinations (i.e. having a Metallic texture and a Specular te "blendblock" : "unique_name" ["unique_name", "unique_name_for_shadows"], "alpha_test" : ["less" "less_equal" "equal" "not_equal" "greater_equal" "greater" "never" "always" "disabled", 0.5], "shadow_const_bias" : 0.01, + "accurate_non_uniform_normal_scaling" : false, "two_sided" : false, "receive_shadows" : true, "refraction_strength" : 0.2, diff --git a/Docs/2.0/JSON/PbsExample.material.json b/Docs/2.0/JSON/PbsExample.material.json index b0e5a2542a8..d408d178a09 100644 --- a/Docs/2.0/JSON/PbsExample.material.json +++ b/Docs/2.0/JSON/PbsExample.material.json @@ -58,6 +58,7 @@ "blendblock" : "unique_name", "alpha_test" : ["disabled", 0.5], "shadow_const_bias" : 0.01, + "accurate_non_uniform_normal_scaling" : false, "two_sided" : false, "receive_shadows" : true, diff --git a/Docs/src/manual/Scripts/HlmsPBSDatablockReference.md b/Docs/src/manual/Scripts/HlmsPBSDatablockReference.md index af195f80e8c..1e9213850eb 100644 --- a/Docs/src/manual/Scripts/HlmsPBSDatablockReference.md +++ b/Docs/src/manual/Scripts/HlmsPBSDatablockReference.md @@ -12,6 +12,11 @@ Reference Guide: HLMS PBS Datablock {#hlmspbsdatablockref} # Common Datablock Parameters: {#dbCommonParameters} +## Parameter: accurate_non_uniform_normal_scaling {#dbParamAccurateNonUniformNormalScaling} +- See Ogre::HlmsDatablock::setAccurateNonUniformNormalScaling +- Value of type bool +- **DEFAULT=false** + ## Parameter: alpha_test {#dbParamAlphaTest} - Sets the alpha test to the given compare function - Alpha_test value is type array: diff --git a/OgreMain/include/OgreHlms.h b/OgreMain/include/OgreHlms.h index 4c15ad6b2fe..ab02d5a5379 100644 --- a/OgreMain/include/OgreHlms.h +++ b/OgreMain/include/OgreHlms.h @@ -1252,6 +1252,7 @@ namespace Ogre static const IdString AlphaBlend; static const IdString AlphaToCoverage; static const IdString AlphaHash; + static const IdString AccurateNonUniformNormalScaling; // Per material. Related with SsRefractionsAvailable static const IdString ScreenSpaceRefractions; static const IdString diff --git a/OgreMain/include/OgreHlmsDatablock.h b/OgreMain/include/OgreHlmsDatablock.h index bcb6bacc18c..c4e61038f16 100644 --- a/OgreMain/include/OgreHlmsDatablock.h +++ b/OgreMain/include/OgreHlmsDatablock.h @@ -358,6 +358,7 @@ namespace Ogre protected: bool mIgnoreFlushRenderables; + bool mAccurateNonUniformNormalScaling; bool mAlphaHashing; uint8 mAlphaTestCmp; ///< @see CompareFunction bool mAlphaTestShadowCasterOnly; @@ -492,6 +493,49 @@ namespace Ogre return mBlendblock[casterBlock]; } + /** When objects are scaled by non-uniform values, normals tend to get skewed or deformed + causing wrong lighting. + + This setting enables the use of additional math in the vertex shader to ensure normals + are properly scaled in these situations. + + Calling this function triggers a HlmsDatablock::flushRenderables. + @remark + This setting would make more sense to be per object (or ideally autodetect when scale + factor isn't uniform) but this is expensive to perform. Therefore the setting lives + in the material instead, which is the best next thing. + @par + @remark + Due to the way the math works, the normal isn't exactly the same even if there is no scaling + involved. This is particularly noticeable with normal-offset bias in directional lights + shadow mapping, as the shadow displaces a little bit. + @par + @remark + Non-uniform scaling is when the scale is not the same for all axes. + Examples of non-uniform scaling: + @code + node->setScale( 2.0f, 5.0f, 0.02f ); + node->setScale( 1.0f, 5.0f, 1.0f ); + @endcode + Examples of uniform scaling: + @code + node->setScale( 1.0f, 1.0f, 1.0f ); + node->setScale( 3.0f, 3.0f, 3.0f ); + @endcode + @par + @remark + For more info see: + - https://x.com/iquilezles/status/1866219178409316362 + - https://www.shadertoy.com/view/3s33zj + - https://github.com/graphitemaster/normals_revisited + @param bAccurate + True to enable the additional math for correction. + False otherwise (default value). + */ + void setAccurateNonUniformNormalScaling( bool bAccurate ); + + bool getAccurateNonUniformNormalScaling() const { return mAccurateNonUniformNormalScaling; } + /** Uses a trick to *mimic* true Order Independent Transparency alpha blending. The advantage of this method is that it is compatible with depth buffer writes and is order independent. diff --git a/OgreMain/src/OgreHlms.cpp b/OgreMain/src/OgreHlms.cpp index 8616551ce85..66f7da26565 100644 --- a/OgreMain/src/OgreHlms.cpp +++ b/OgreMain/src/OgreHlms.cpp @@ -204,6 +204,8 @@ namespace Ogre const IdString HlmsBaseProp::AlphaBlend = IdString( "hlms_alphablend" ); const IdString HlmsBaseProp::AlphaToCoverage = IdString( "hlms_alpha_to_coverage" ); const IdString HlmsBaseProp::AlphaHash = IdString( "hlms_alpha_hash" ); + const IdString HlmsBaseProp::AccurateNonUniformNormalScaling = + IdString( "hlms_accurate_non_uniform_normal_scaling" ); const IdString HlmsBaseProp::ScreenSpaceRefractions = IdString( "hlms_screen_space_refractions" ); // We use a different convention because it's a really private property that ideally // shouldn't be exposed to users. diff --git a/OgreMain/src/OgreHlmsDatablock.cpp b/OgreMain/src/OgreHlmsDatablock.cpp index 7092b0554fb..cd557d37b5a 100644 --- a/OgreMain/src/OgreHlmsDatablock.cpp +++ b/OgreMain/src/OgreHlmsDatablock.cpp @@ -455,6 +455,15 @@ namespace Ogre } } //----------------------------------------------------------------------------------- + void HlmsDatablock::setAccurateNonUniformNormalScaling( bool bAccurate ) + { + if( mAccurateNonUniformNormalScaling != bAccurate ) + { + mAccurateNonUniformNormalScaling = bAccurate; + flushRenderables(); + } + } + //----------------------------------------------------------------------------------- void HlmsDatablock::setAlphaHashing( bool bAlphaHashing ) { if( mAlphaHashing != bAlphaHashing ) diff --git a/OgreMain/src/OgreHlmsJson.cpp b/OgreMain/src/OgreHlmsJson.cpp index 1d20e42af19..729b54a0308 100644 --- a/OgreMain/src/OgreHlmsJson.cpp +++ b/OgreMain/src/OgreHlmsJson.cpp @@ -514,6 +514,10 @@ namespace Ogre } } + itor = json.FindMember( "accurate_non_uniform_normal_scaling" ); + if( itor != json.MemberEnd() && itor->value.IsBool() ) + datablock->setAccurateNonUniformNormalScaling( itor->value.GetBool() ); + itor = json.FindMember( "alpha_test" ); if( itor != json.MemberEnd() && itor->value.IsArray() ) { @@ -1054,6 +1058,9 @@ namespace Ogre } } + if( datablock->getAccurateNonUniformNormalScaling() ) + outString += ",\n\t\t\t\"accurate_non_uniform_normal_scaling\" : true"; + if( datablock->getAlphaTest() != CMPF_ALWAYS_PASS ) { outString += ",\n\t\t\t\"alpha_test\" : "; 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 55253a32d17..f5a044ca421 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 @@ -35,7 +35,7 @@ @insertpiece( DeclShadowMapMacros ) @insertpiece( DeclAtmosphereNprSkyFuncs ) - @property( accurate_non_uniform_scaled_normals ) + @property( hlms_accurate_non_uniform_normal_scaling ) // Computes transpose( adjugate( m ) ) // See: // https://x.com/iquilezles/status/1866219178409316362