diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 7ee4fb9511..9fd206aad4 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -25,9 +25,16 @@ #include #include #include +#include +#include +#include +#include +#include #include #include +#include +#include #include "glextensions.hpp" #include "shadowsbin.hpp" @@ -242,7 +249,7 @@ class VDSMCameraCullCallback : public osg::NodeCallback { public: - VDSMCameraCullCallback(MWShadowTechnique* vdsm, osg::Polytope& polytope); + VDSMCameraCullCallback(MWShadowTechnique* vdsm, const osg::Polytope& polytope); void operator()(osg::Node*, osg::NodeVisitor* nv) override; @@ -257,47 +264,61 @@ class VDSMCameraCullCallback : public osg::NodeCallback osg::Polytope _polytope; }; -VDSMCameraCullCallback::VDSMCameraCullCallback(MWShadowTechnique* vdsm, osg::Polytope& polytope): +VDSMCameraCullCallback::VDSMCameraCullCallback(MWShadowTechnique* vdsm, const osg::Polytope& polytope): _vdsm(vdsm), _polytope(polytope) -{ -} +{} void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) { osgUtil::CullVisitor* cv = static_cast(nv); osg::Camera* camera = node->asCamera(); OSG_INFO<<"VDSMCameraCullCallback::operator()(osg::Node* "<getCurrentRenderStage()) + cv->setCurrentRenderBin(stage); -#if 1 if (!_polytope.empty()) { - OSG_INFO<<"Pushing custom Polytope"<getProjectionCullingStack().back(); - - cs.setFrustum(_polytope); - - cv->pushCullingSet(); + auto& stack = cv->getProjectionCullingStack(); + if (!stack.empty()) + { + osg::CullingSet& cs = stack.back(); + cs.setFrustum(_polytope); + cv->pushCullingSet(); + } + else + { + // No projection stack available; skip polytope for safety in parallel paths + } + } + // Push casting state and shadows bin while traversing the RTT camera + if (auto* cast = _vdsm->getCastingStateSet()) + { + cv->pushStateSet(cast); } -#endif // bin has to go inside camera cull or the rendertexture stage will override it cv->pushStateSet(_vdsm->getOrCreateShadowsBinStateSet()); if (_vdsm->getShadowedScene()) { _vdsm->getShadowedScene()->osg::Group::traverse(*nv); } - cv->popStateSet(); -#if 1 + cv->popStateSet(); // pop shadows bin stateset + if (_vdsm->getCastingStateSet()){ + cv->popStateSet(); + } if (!_polytope.empty()) { - OSG_INFO<<"Popping custom Polytope"<popCullingSet(); + auto& stack = cv->getProjectionCullingStack(); + if (!stack.empty()) + { + cv->popCullingSet(); + } } -#endif - - _renderStage = cv->getCurrentRenderBin()->getStage(); + // Capture the RTT render stage after traversal for PSM adjustments later. + _renderStage = cv->getCurrentRenderStage(); OSG_INFO<<"VDSM second : _renderStage = "<<_renderStage<getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) @@ -305,10 +326,11 @@ void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) // make sure that the near plane is computed correctly. cv->computeNearPlane(); - osg::Matrixd projection = *(cv->getProjectionMatrix()); - + osg::RefMatrix* projRef = cv->getProjectionMatrix(); + if (!projRef) + return; // cannot proceed safely without a projection matrix + osg::Matrixd projection = *projRef; OSG_INFO<<"RTT Projection matrix "<osg::Group::traverse(cv); return; } - + OSG_INFO<_uniforms[cv.getTraversalNumber() % 2]; ShadowSettings* settings = getShadowedScene()->getShadowSettings(); + const bool debugDraw = settings->getDebugDraw(); + const bool isCascaded = settings->getMultipleShadowMapHint() == ShadowSettings::CASCADED; + const bool isParallelSplit = settings->getMultipleShadowMapHint() == ShadowSettings::PARALLEL_SPLIT; OSG_INFO<<"cv->getProjectionMatrix()="<<*cv.getProjectionMatrix()<getMaximumShadowMapDistance(),maxZFar); if (minZNear>maxZFar) minZNear = maxZFar*settings->getMinimumShadowMapNearFarRatio(); - //OSG_NOTICE<<"maxZFar "<second); // return compute near far mode back to it's original settings @@ -1184,8 +1199,6 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) // return compute near far mode back to it's original settings cv.setComputeNearFarMode(cachedNearFarMode); - OSG_INFO<<"frustum.eye="<getMultipleShadowMapHint() == ShadowSettings::PARALLEL_SPLIT && sm_i+1getMultipleShadowMapHint() == ShadowSettings::PARALLEL_SPLIT) - { - // OSG_NOTICE<<"Need to adjust RTT camera projection and view matrix here, r_start="< #include #include +#include #include #include @@ -90,6 +91,11 @@ namespace SceneUtil { virtual void setupCastingShader(Shader::ShaderManager &shaderManager); + // Experimental: enable parallel shadow preparation/culling + void setParallelShadowCullingEnabled(bool enabled) { mParallelShadowCullingEnabled = enabled; } + // Experimental: enable parallel per-cascade RTT traversal + void setParallelShadowTraversalEnabled(bool enabled) { mParallelShadowTraversalEnabled = enabled; } + class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack { public: @@ -272,6 +278,7 @@ namespace SceneUtil { void setWorldMask(unsigned int worldMask) { _worldMask = worldMask; } osg::ref_ptr getOrCreateShadowsBinStateSet(); + osg::StateSet* getCastingStateSet() const { return _shadowCastingStateSet.get(); } protected: virtual ~MWShadowTechnique(); @@ -309,6 +316,9 @@ namespace SceneUtil { unsigned int _worldMask = ~0u; + bool mParallelShadowCullingEnabled = false; + bool mParallelShadowTraversalEnabled = false; + class DebugHUD final : public osg::Referenced { public: diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index a03700578d..7475a9a061 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -80,6 +80,9 @@ namespace SceneUtil mShadowTechnique->enableDebugHUD(); else mShadowTechnique->disableDebugHUD(); + + mShadowTechnique->setParallelShadowCullingEnabled(settings.mParallelShadowCulling); + mShadowTechnique->setParallelShadowTraversalEnabled(settings.mParallelShadowTraversal); } void ShadowManager::disableShadowsForStateSet(osg::StateSet& stateset) const diff --git a/components/settings/categories/shadows.hpp b/components/settings/categories/shadows.hpp index b6349dfd44..feb9091363 100644 --- a/components/settings/categories/shadows.hpp +++ b/components/settings/categories/shadows.hpp @@ -42,6 +42,8 @@ namespace Settings SettingValue mTerrainShadows{ mIndex, "Shadows", "terrain shadows" }; SettingValue mObjectShadows{ mIndex, "Shadows", "object shadows" }; SettingValue mEnableIndoorShadows{ mIndex, "Shadows", "enable indoor shadows" }; + SettingValue mParallelShadowCulling{ mIndex, "Shadows", "parallel shadow culling" }; + SettingValue mParallelShadowTraversal{ mIndex, "Shadows", "parallel shadow traversal" }; }; } diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 2c4bbab953..a6bd09d43b 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -1021,6 +1021,12 @@ wait for all jobs on exit = false # Enable or disable shadows. Bear in mind that this will force OpenMW to use shaders as if "[Shaders]/force shaders" was set to true. enable shadows = false +# compute per-cascade prep and cull RTT cameras in parallel +parallel shadow culling = false + +# compute per-cascade RTT traversal in parallel +parallel shadow traversal = false + # How many shadow maps to use - more of these means each shadow map texel covers less area, producing better looking shadows, but may decrease performance. number of shadow maps = 3