From d33be39fb6c00e738a0230a88cbad3a121dcfb3f Mon Sep 17 00:00:00 2001 From: Alexei Dobrohotov Date: Wed, 1 Mar 2023 00:52:37 +0300 Subject: [PATCH 1/2] Attach shaders to geometry that lacks a stateset if necessary (bug #7251) --- CHANGELOG.md | 1 + components/shader/shadervisitor.cpp | 86 +++++++++++------------------ 2 files changed, 32 insertions(+), 55 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a14e21bfc..7bb62bc564 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -157,6 +157,7 @@ Bug #6937: Divided by Nix Hounds quest is broken Bug #7008: Race condition on initializing a vector of reserved node names Bug #7121: Crash on TimeStamp construction with invalid hour value + Bug #7251: Force shaders setting still renders some drawables with FFP Feature #890: OpenMW-CS: Column filtering Feature #1465: "Reset" argument for AI functions Feature #2491: Ability to make OpenMW "portable" diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 7a949aac80..d3dbb1d373 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -820,74 +820,50 @@ namespace Shader void ShaderVisitor::apply(osg::Geometry& geometry) { - bool needPop = (geometry.getStateSet() != nullptr); + pushRequirements(geometry); if (geometry.getStateSet()) // TODO: check if stateset affects shader permutation before pushing it - { - pushRequirements(geometry); applyStateSet(geometry.getStateSet(), geometry); - } - if (!mRequirements.empty()) - { - const ShaderRequirements& reqs = mRequirements.back(); + const ShaderRequirements& reqs = mRequirements.back(); + adjustGeometry(geometry, reqs); + createProgram(reqs); - adjustGeometry(geometry, reqs); - - createProgram(reqs); - } - else - ensureFFP(geometry); - - if (needPop) - popRequirements(); + popRequirements(); } void ShaderVisitor::apply(osg::Drawable& drawable) { - bool needPop = drawable.getStateSet(); + pushRequirements(drawable); - if (needPop) + if (drawable.getStateSet()) + applyStateSet(drawable.getStateSet(), drawable); + + const ShaderRequirements& reqs = mRequirements.back(); + createProgram(reqs); + + if (auto rig = dynamic_cast(&drawable)) { - pushRequirements(drawable); - - if (drawable.getStateSet()) - applyStateSet(drawable.getStateSet(), drawable); + osg::ref_ptr sourceGeometry = rig->getSourceGeometry(); + if (sourceGeometry && adjustGeometry(*sourceGeometry, reqs)) + rig->setSourceGeometry(sourceGeometry); } - - if (!mRequirements.empty()) + else if (auto morph = dynamic_cast(&drawable)) { - const ShaderRequirements& reqs = mRequirements.back(); - createProgram(reqs); - - if (auto rig = dynamic_cast(&drawable)) - { - osg::ref_ptr sourceGeometry = rig->getSourceGeometry(); - if (sourceGeometry && adjustGeometry(*sourceGeometry, reqs)) - rig->setSourceGeometry(sourceGeometry); - } - else if (auto morph = dynamic_cast(&drawable)) - { - osg::ref_ptr sourceGeometry = morph->getSourceGeometry(); - if (sourceGeometry && adjustGeometry(*sourceGeometry, reqs)) - morph->setSourceGeometry(sourceGeometry); - } - else if (auto osgaRig = dynamic_cast(&drawable)) - { - osg::ref_ptr sourceOsgaRigGeometry = osgaRig->getSourceRigGeometry(); - osg::ref_ptr sourceGeometry = sourceOsgaRigGeometry->getSourceGeometry(); - if (sourceGeometry && adjustGeometry(*sourceGeometry, reqs)) - { - sourceOsgaRigGeometry->setSourceGeometry(sourceGeometry); - osgaRig->setSourceRigGeometry(sourceOsgaRigGeometry); - } - } - + osg::ref_ptr sourceGeometry = morph->getSourceGeometry(); + if (sourceGeometry && adjustGeometry(*sourceGeometry, reqs)) + morph->setSourceGeometry(sourceGeometry); } - else - ensureFFP(drawable); - - if (needPop) - popRequirements(); + else if (auto osgaRig = dynamic_cast(&drawable)) + { + osg::ref_ptr sourceOsgaRigGeometry = osgaRig->getSourceRigGeometry(); + osg::ref_ptr sourceGeometry = sourceOsgaRigGeometry->getSourceGeometry(); + if (sourceGeometry && adjustGeometry(*sourceGeometry, reqs)) + { + sourceOsgaRigGeometry->setSourceGeometry(sourceGeometry); + osgaRig->setSourceRigGeometry(sourceOsgaRigGeometry); + } + } + popRequirements(); } void ShaderVisitor::setAllowedToModifyStateSets(bool allowed) From ed44095cdc0d33cadb7e27ffa0695932b535aa55 Mon Sep 17 00:00:00 2001 From: Alexei Dobrohotov Date: Fri, 3 Mar 2023 21:28:00 +0300 Subject: [PATCH 2/2] Use Rig/MorphGeometry state for its child geometry --- components/sceneutil/morphgeometry.cpp | 13 +++++++++++++ components/sceneutil/riggeometry.cpp | 16 +++++++++++++++- .../sceneutil/riggeometryosgaextension.cpp | 11 +++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/morphgeometry.cpp b/components/sceneutil/morphgeometry.cpp index 39102b575a..3efccfd6e6 100644 --- a/components/sceneutil/morphgeometry.cpp +++ b/components/sceneutil/morphgeometry.cpp @@ -1,5 +1,7 @@ #include "morphgeometry.hpp" +#include + #include #include @@ -87,7 +89,18 @@ void MorphGeometry::accept(osg::NodeVisitor &nv) nv.pushOntoNodePath(this); if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR) + { + // The cull visitor won't be applied to the node itself, + // but we want to use its state to render the child geometry. + osg::StateSet* stateset = getStateSet(); + osgUtil::CullVisitor* cv = static_cast(&nv); + if (stateset) + cv->pushStateSet(stateset); + cull(&nv); + if (stateset) + cv->popStateSet(); + } else nv.apply(*this); diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 5fca265877..38a35f2a12 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -1,8 +1,11 @@ #include "riggeometry.hpp" +#include + +#include + #include #include -#include #include "skeleton.hpp" #include "util.hpp" @@ -387,7 +390,18 @@ void RigGeometry::accept(osg::NodeVisitor &nv) nv.pushOntoNodePath(this); if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR) + { + // The cull visitor won't be applied to the node itself, + // but we want to use its state to render the child geometry. + osg::StateSet* stateset = getStateSet(); + osgUtil::CullVisitor* cv = static_cast(&nv); + if (stateset) + cv->pushStateSet(stateset); + cull(&nv); + if (stateset) + cv->popStateSet(); + } else if (nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) updateBounds(&nv); else diff --git a/components/sceneutil/riggeometryosgaextension.cpp b/components/sceneutil/riggeometryosgaextension.cpp index 8768eb403f..3389a6ba5d 100644 --- a/components/sceneutil/riggeometryosgaextension.cpp +++ b/components/sceneutil/riggeometryosgaextension.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include #include @@ -220,6 +222,13 @@ void RigGeometryHolder::accept(osg::NodeVisitor &nv) if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR && mSourceRigGeometry.get()) { + // The cull visitor won't be applied to the node itself, + // but we want to use its state to render the child geometry. + osg::StateSet* stateset = getStateSet(); + osgUtil::CullVisitor* cv = static_cast(&nv); + if (stateset) + cv->pushStateSet(stateset); + unsigned int traversalNumber = nv.getTraversalNumber(); if (mLastFrameNumber == traversalNumber) { @@ -255,6 +264,8 @@ void RigGeometryHolder::accept(osg::NodeVisitor &nv) nv.apply(geom); nv.popFromNodePath(); } + if (stateset) + cv->popStateSet(); } else if (nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) {