Hey guys,
I want to setup multiple choices of shadow quality in my game, and at least my initial idea was to setup multiple shadownodes and then change the working one on the fly.
How do I do that, I couldn't find where to set the shadow node in a CompositorPass or CompositorPassDef, and more importantly, is that the best idea to have multiple shadow quality choices in my game?
Cheers.
How to change shadow nodes on the fly
-
- Greenskin
- Posts: 145
- Joined: Fri Jun 12, 2015 6:53 pm
- Location: Florianopolis, Brazil
- x 17
-
- OGRE Team Member
- Posts: 5478
- Joined: Sat Jul 21, 2007 4:55 pm
- Location: Buenos Aires, Argentina
- x 1359
Re: How to change shadow nodes on the fly
Except for PCF filtering, you'll need to destroy the workspace and either:
We personally went for the first method, for reference this is what we do (note that it does some assumptions; you may have to suit it for your needs):
Note that you should destroy all workspaces using that shadow node before calling setShadowMapping, then create them again. If you forgot to destroy one of those workspaces; you'll have a workspace with a dangling pointer as Shadow Node and will crash.
If you go for the 2nd option (predefined quality nodes); then you'll only need the last part where "passSceneDef->mShadowNode" is set (and set it to the predefined node you want). Though you will still have to recreate the instances.
- Programmatically destroy the shadow node, and it again, suiting the new setting
- Predefine a number of shadow nodes for each quality, and programatically change the nodes using these shadow nodes so they reference the other shadow node (e.g. if they referenced "ShadowNodeHigh" they now reference "ShadowNodeLow")
We personally went for the first method, for reference this is what we do (note that it does some assumptions; you may have to suit it for your needs):
Code: Select all
void setShadowMapping( bool shadowsEnabled, uint32 numShadowCastingLights,
uint32 resolution = 2048,
bool usePssm = true, uint32 numPssmSplits = 3,
HlmsPbs::ShadowFilter shadowFilter = HlmsPbs::PCF_3x3 )
{
size_t numShadowMaps = numShadowCastingLights + (usePssm ? (numPssmSplits - 1) : 0);
size_t split = 0;
size_t lightIdx = 0;
CompositorManager2 *compositorManager = Root::getSingleton().getCompositorManager2();
compositorManager->removeAllShadowNodeDefinitions();
CompositorShadowNodeDef *shadowNodeDef = compositorManager->addShadowNodeDefinition( "myShadowNode" );
shadowNodeDef->setNumLocalTextureDefinitions( numShadowMaps );
shadowNodeDef->setDefaultTechnique( SHADOWMAP_PSSM );
for( size_t i=0; i<numShadowMaps; ++i )
{
ShadowTextureDefinition *shadowTexDef =
shadowNodeDef->addShadowTextureDefinition( lightIdx, split,
StringConverter::toString(i),
false );
shadowTexDef->width = resolution;
shadowTexDef->height = resolution;
shadowTexDef->formatList.push_back( PF_D32_FLOAT );
shadowTexDef->depthBufferId = DepthBuffer::POOL_NON_SHAREABLE;
if( usePssm && i < numPssmSplits )
{
shadowTexDef->shadowMapTechnique = SHADOWMAP_PSSM;
shadowTexDef->pssmLambda = 0.95f;
shadowTexDef->numSplits = 3;
++split;
if( split >= numPssmSplits )
{
split = 0;
++lightIdx;
}
}
else
{
shadowNodeDef->setDefaultTechnique( SHADOWMAP_FOCUSED );
shadowTexDef->shadowMapTechnique = SHADOWMAP_FOCUSED;
split = 0;
++lightIdx;
}
}
shadowNodeDef->setNumTargetPass( numShadowMaps );
for( size_t i=0; i<numShadowMaps; ++i )
{
CompositorTargetDef *targetPassDef = shadowNodeDef->addTargetPass( StringConverter::toString(i) );
targetPassDef->setNumPasses( 2 );
{
CompositorPassClearDef *pass = static_cast<CompositorPassClearDef*>(
targetPassDef->addPass( PASS_CLEAR ) );
pass->mClearBufferFlags = FBT_DEPTH|FBT_STENCIL;
pass->mShadowMapIdx = i;
pass->mIncludeOverlays = false;
}
{
CompositorPassSceneDef *pass = static_cast<CompositorPassSceneDef*>(
targetPassDef->addPass( PASS_SCENE ) );
pass->mVisibilityMask = 0x00000001;
pass->mShadowMapIdx = i;
pass->mIncludeOverlays = false;
}
}
CompositorNodeDef *nodeDef = compositorManager->getNodeDefinitionNonConst( "DefaultNode" );
for( size_t i=0; i<nodeDef->getNumTargetPasses(); ++i )
{
CompositorTargetDef *targetDef = nodeDef->getTargetPass( i );
const CompositorPassDefVec &passDefs = targetDef->getCompositorPasses();
CompositorPassDefVec::const_iterator itor = passDefs.begin();
CompositorPassDefVec::const_iterator end = passDefs.end();
while( itor != end )
{
CompositorPassDef *passDef = *itor;
if( passDef->mIdentifier == 1000 ) //We actually flag which passes use a shadow node with an identifier
{
assert( passDef->getType() == PASS_SCENE );
CompositorPassSceneDef *passSceneDef = static_cast<CompositorPassSceneDef*>(passDef);
passSceneDef->mShadowNode = shadowsEnabled ? IdString( "myShadowNode" ) : IdString();
}
else
{
assert( passDef->getType() != PASS_SCENE );
}
++itor;
}
}
Ogre::Root *root = Root::getSingletonPtr();
Ogre::HlmsManager *hlmsManager = root->getHlmsManager();
Ogre::Hlms *hlms = hlmsManager->getHlms( Ogre::HLMS_PBS );
Ogre::HlmsPbs *hlmsPbs = static_cast<Ogre::HlmsPbs*>(hlms);
hlmsPbs->setShadowSettings( shadowFilter );
}
If you go for the 2nd option (predefined quality nodes); then you'll only need the last part where "passSceneDef->mShadowNode" is set (and set it to the predefined node you want). Though you will still have to recreate the instances.
-
- Greenskin
- Posts: 145
- Joined: Fri Jun 12, 2015 6:53 pm
- Location: Florianopolis, Brazil
- x 17
Re: How to change shadow nodes on the fly
Great, it worked!
I did the second method, and setup a few pre defined shadow nodes, then the code I used to swap between them was the following:
I did the second method, and setup a few pre defined shadow nodes, then the code I used to swap between them was the following:
Thanks.Ogre::CompositorManager2* compositorManager = Ogre::Root::getSingleton().getCompositorManager2();
Ogre::CompositorNodeDef* nodeDef = compositorManager->getNodeDefinitionNonConst("ClientNode");
for (int i = 0; i < nodeDef->getNumTargetPasses(); ++i) {
Ogre::CompositorTargetDef *targetDef = nodeDef->getTargetPass(i);
const Ogre::CompositorPassDefVec &passDefs = targetDef->getCompositorPasses();
Ogre::CompositorPassDefVec::const_iterator itor = passDefs.begin();
Ogre::CompositorPassDefVec::const_iterator end = passDefs.end();
while (itor != end) {
Ogre::CompositorPassDef *passDef = *itor;
if (passDef->getType() == Ogre::PASS_SCENE) {
Ogre::CompositorPassSceneDef* passSceneDef = static_cast<Ogre::CompositorPassSceneDef*>(passDef);
if (passSceneDef->mShadowNode.mHash != 0) {
passSceneDef->mShadowNode = Ogre::IdString(shadowNode);
}
}
++itor;
}
}
Ogre::CompositorWorkspace* workspace = Core::getInstance()->getGraphicsSystem()->getWorkspace("ClientWorkspace");
workspace->recreateAllNodes();
workspace->reconnectAllNodes();