From d340224c95862be8bf49ca31b0db7d5651d96411 Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 1/7] shadowsbin for gl state reduction --- components/CMakeLists.txt | 2 +- components/sceneutil/mwshadowtechnique.cpp | 17 ++- components/sceneutil/shadowsbin.cpp | 133 +++++++++++++++++++++ components/sceneutil/shadowsbin.hpp | 58 +++++++++ components/shader/shadervisitor.cpp | 7 -- 5 files changed, 204 insertions(+), 13 deletions(-) create mode 100644 components/sceneutil/shadowsbin.cpp create mode 100644 components/sceneutil/shadowsbin.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 412717aaa..eaf9a6dda 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -51,7 +51,7 @@ add_component_dir (shader add_component_dir (sceneutil clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer - actorutil detourdebugdraw navmesh agentpath shadow mwshadowtechnique + actorutil detourdebugdraw navmesh agentpath shadow mwshadowtechnique shadowsbin ) add_component_dir (nif diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index f31d2faef..bc0bcdf33 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -24,6 +24,7 @@ #include #include +#include "shadowsbin.hpp" namespace { @@ -272,10 +273,20 @@ void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) cv->pushCullingSet(); } #endif + // bin has to go inside camera cull or the rendertexture stage will override it + static osg::ref_ptr ss; + if (!ss) + { + ShadowsBinAdder adder("ShadowsBin"); + ss = new osg::StateSet; + ss->setRenderBinDetails(osg::StateSet::OPAQUE_BIN, "ShadowsBin", osg::StateSet::OVERRIDE_PROTECTED_RENDERBIN_DETAILS); + } + cv->pushStateSet(ss); if (_vdsm->getShadowedScene()) { _vdsm->getShadowedScene()->osg::Group::traverse(*nv); } + cv->popStateSet(); #if 1 if (!_polytope.empty()) { @@ -1569,14 +1580,10 @@ void MWShadowTechnique::createShaders() _shadowCastingStateSet->setAttributeAndModes(_castingProgram, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); // The casting program uses a sampler, so to avoid undefined behaviour, we must bind a dummy texture in case no other is supplied _shadowCastingStateSet->setTextureAttributeAndModes(0, _fallbackBaseTexture.get(), osg::StateAttribute::ON); - _shadowCastingStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", false)); - + _shadowCastingStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", true)); _shadowCastingStateSet->setMode(GL_DEPTH_CLAMP, osg::StateAttribute::ON); - _shadowCastingStateSet->setRenderBinDetails(osg::StateSet::OPAQUE_BIN, "RenderBin", osg::StateSet::OVERRIDE_PROTECTED_RENDERBIN_DETAILS); - // TODO: compare performance when alpha testing is handled here versus using a discard in the fragment shader - // TODO: compare performance when we set a bunch of GL state to the default here with OVERRIDE set so that there are fewer pointless state switches } osg::Polytope MWShadowTechnique::computeLightViewFrustumPolytope(Frustum& frustum, LightData& positionedLight) diff --git a/components/sceneutil/shadowsbin.cpp b/components/sceneutil/shadowsbin.cpp new file mode 100644 index 000000000..2bf2f06f6 --- /dev/null +++ b/components/sceneutil/shadowsbin.cpp @@ -0,0 +1,133 @@ +#include "shadowsbin.hpp" +#include +#include +#include +#include + +using namespace osgUtil; + +namespace +{ + template + inline void accumulateState(T& currentValue, T newValue, bool& isOverride, unsigned int overrideFlags) + { + if (isOverride && !(overrideFlags & osg::StateAttribute::PROTECTED)) return; + + if (overrideFlags & osg::StateAttribute::OVERRIDE) + isOverride = true; + + currentValue = newValue; + } + + inline void accumulateModeState(const osg::StateSet* ss, bool& currentValue, bool& isOverride, int mode) + { + const osg::StateSet::ModeList& l = ss->getModeList(); + osg::StateSet::ModeList::const_iterator mf = l.find(mode); + if (mf == l.end()) + return; + int flags = mf->second; + bool newValue = flags & osg::StateAttribute::ON; + accumulateState(currentValue, newValue, isOverride, ss->getMode(mode)); + } + + inline bool materialNeedShadows(osg::Material* m) + { + return m->getDiffuse(osg::Material::FRONT).a() > 0.5; + } +} + +namespace SceneUtil +{ + +ShadowsBin::ShadowsBin() +{ + mStateSet = new osg::StateSet; + mStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", false)); +} + +bool ShadowsBin::cullStateGraph(StateGraph* sg, StateGraph* root, std::unordered_set& uninteresting) +{ + std::vector return_path; + State state; + StateGraph* sg_new = sg; + do + { + if (uninteresting.find(sg_new) != uninteresting.end()) + break; + return_path.push_back(sg_new); + sg_new = sg_new->_parent; + } while (sg_new && sg_new != root); + for(std::vector::reverse_iterator itr=return_path.rbegin(); itr!=return_path.rend(); ++itr) + { + const osg::StateSet* ss = (*itr)->getStateSet(); + if (!ss) continue; + accumulateModeState(ss, state.mAlphaBlend, state.mAlphaBlendOverride, GL_BLEND); + accumulateModeState(ss, state.mAlphaTest, state.mAlphaTestOverride, GL_ALPHA_TEST); + const osg::StateSet::AttributeList& l = ss->getAttributeList(); + osg::StateSet::AttributeList::const_iterator f = l.find(std::make_pair(osg::StateAttribute::MATERIAL, 0)); + if (f != l.end()) + { + const osg::StateSet::RefAttributePair* rap = &f->second; + accumulateState(state.mMaterial, static_cast(rap->first.get()), state.mMaterialOverride, rap->second); + if (state.mMaterial && !materialNeedShadows(state.mMaterial)) + state.mMaterial = nullptr; + } + f = l.find(std::make_pair(osg::StateAttribute::FRONTFACE, 0)); + if (f != l.end()) + state.mImportantState = true; + if ((*itr) != sg && !state.interesting()) + uninteresting.insert(*itr); + } + + if (!state.needShadows()) + return true; + + if (!state.needTexture() && !state.mImportantState) + { + for (RenderLeaf* leaf : sg->_leaves) + { + leaf->_parent = root; + root->_leaves.push_back(leaf); + } + return true; + } + return false; +} + +bool ShadowsBin::State::needShadows() const +{ + if (!mMaterial) + return true; + return materialNeedShadows(mMaterial); +} + +void ShadowsBin::sortImplementation() +{ + if (!_stateGraphList.size()) + return; + StateGraph* root = _stateGraphList[0]; + while (root->_parent) + { + root = root->_parent; + const osg::StateSet* ss = root->getStateSet(); + if (ss->getMode(GL_NORMALIZE) & osg::StateAttribute::ON // that is root stategraph of renderingmanager cpp + || ss->getAttribute(osg::StateAttribute::VIEWPORT)) // fallback to rendertargets sg just in case + break; + if (!root->_parent) + return; + } + root = root->find_or_insert(mStateSet.get()); + root->_leaves.reserve(_stateGraphList.size()); + StateGraphList newList; + std::unordered_set uninteresting; + for (StateGraph* graph : _stateGraphList) + { + if (!cullStateGraph(graph, root, uninteresting)) + newList.push_back(graph); + } + if (!root->_leaves.empty()) + newList.push_back(root); + _stateGraphList = newList; +} + +} diff --git a/components/sceneutil/shadowsbin.hpp b/components/sceneutil/shadowsbin.hpp new file mode 100644 index 000000000..05926bace --- /dev/null +++ b/components/sceneutil/shadowsbin.hpp @@ -0,0 +1,58 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_SHADOWBIN_H +#define OPENMW_COMPONENTS_SCENEUTIL_SHADOWBIN_H +#include +#include + +namespace osg +{ + class Material; +} + +namespace SceneUtil +{ + + /// renderbin which culls redundent state for shadows rendering + class ShadowsBin : public osgUtil::RenderBin + { + private: + osg::ref_ptr mStateSet; + public: + META_Object(SceneUtil, ShadowsBin) + ShadowsBin(); + ShadowsBin(const ShadowsBin& rhs, const osg::CopyOp& copyop) : osgUtil::RenderBin(rhs, copyop), mStateSet(rhs.mStateSet) {} + + virtual void sortImplementation(); + + struct State + { + State():mAlphaBlend(false),mAlphaBlendOverride(false),mAlphaTest(false),mAlphaTestOverride(false),mMaterial(nullptr),mMaterialOverride(false),mImportantState(false){} + bool mAlphaBlend; + bool mAlphaBlendOverride; + bool mAlphaTest; + bool mAlphaTestOverride; + osg::Material* mMaterial; + bool mMaterialOverride; + bool mImportantState; + bool needTexture() const { return mAlphaBlend || mAlphaTest; } + bool needShadows() const; + bool interesting() const { return !needShadows() || needTexture() || mAlphaBlendOverride || mAlphaTestOverride || mMaterialOverride || mImportantState; } + }; + + bool cullStateGraph(osgUtil::StateGraph* sg, osgUtil::StateGraph* root, std::unordered_set& uninteresting); + + static void addPrototype(const std::string& name) + { + osg::ref_ptr bin (new ShadowsBin); + osgUtil::RenderBin::addRenderBinPrototype(name, bin); + } + }; + + class ShadowsBinAdder + { + public: + ShadowsBinAdder(const std::string& name){ ShadowsBin::addPrototype(name); } + }; + +} + +#endif diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index e40cc255b..365cc5b66 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -205,13 +205,6 @@ namespace Shader mRequirements.back().mShaderRequired = true; } } - - if (diffuseMap) - { - if (!writableStateSet) - writableStateSet = getWritableStateSet(node); - writableStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", true)); - } } const osg::StateSet::AttributeList& attributes = stateset->getAttributeList(); From 449506fef155f1d0d4bcaa833604409babfe7bf8 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 31 Oct 2020 19:06:20 +0000 Subject: [PATCH 2/7] Attempt to explain what shadowsbin is doing --- components/sceneutil/shadowsbin.cpp | 44 ++++++++++++++++++++--------- components/sceneutil/shadowsbin.hpp | 19 +++++++------ 2 files changed, 40 insertions(+), 23 deletions(-) diff --git a/components/sceneutil/shadowsbin.cpp b/components/sceneutil/shadowsbin.cpp index 2bf2f06f6..e0a141ffb 100644 --- a/components/sceneutil/shadowsbin.cpp +++ b/components/sceneutil/shadowsbin.cpp @@ -32,6 +32,7 @@ namespace inline bool materialNeedShadows(osg::Material* m) { + // I'm pretty sure this needs to check the colour mode - vertex colours might override this value. return m->getDiffuse(osg::Material::FRONT).a() > 0.5; } } @@ -45,38 +46,45 @@ ShadowsBin::ShadowsBin() mStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", false)); } -bool ShadowsBin::cullStateGraph(StateGraph* sg, StateGraph* root, std::unordered_set& uninteresting) +bool ShadowsBin::cullStateGraph(StateGraph* sg, StateGraph* root, std::unordered_set& uninterestingCache) { std::vector return_path; State state; StateGraph* sg_new = sg; do { - if (uninteresting.find(sg_new) != uninteresting.end()) + if (uninterestingCache.find(sg_new) != uninterestingCache.end()) break; return_path.push_back(sg_new); sg_new = sg_new->_parent; } while (sg_new && sg_new != root); - for(std::vector::reverse_iterator itr=return_path.rbegin(); itr!=return_path.rend(); ++itr) + + for(auto itr=return_path.rbegin(); itr!=return_path.rend(); ++itr) { const osg::StateSet* ss = (*itr)->getStateSet(); - if (!ss) continue; + if (!ss) + continue; + accumulateModeState(ss, state.mAlphaBlend, state.mAlphaBlendOverride, GL_BLEND); accumulateModeState(ss, state.mAlphaTest, state.mAlphaTestOverride, GL_ALPHA_TEST); - const osg::StateSet::AttributeList& l = ss->getAttributeList(); - osg::StateSet::AttributeList::const_iterator f = l.find(std::make_pair(osg::StateAttribute::MATERIAL, 0)); - if (f != l.end()) + + const osg::StateSet::AttributeList& attributes = ss->getAttributeList(); + osg::StateSet::AttributeList::const_iterator found = attributes.find(std::make_pair(osg::StateAttribute::MATERIAL, 0)); + if (found != attributes.end()) { - const osg::StateSet::RefAttributePair* rap = &f->second; - accumulateState(state.mMaterial, static_cast(rap->first.get()), state.mMaterialOverride, rap->second); + const osg::StateSet::RefAttributePair& rap = found->second; + accumulateState(state.mMaterial, static_cast(rap.first.get()), state.mMaterialOverride, rap.second); if (state.mMaterial && !materialNeedShadows(state.mMaterial)) state.mMaterial = nullptr; } - f = l.find(std::make_pair(osg::StateAttribute::FRONTFACE, 0)); - if (f != l.end()) + + // osg::FrontFace specifies triangle winding, not front-face culling. We can't safely reparent anything under it. + found = attributes.find(std::make_pair(osg::StateAttribute::FRONTFACE, 0)); + if (found != attributes.end()) state.mImportantState = true; + if ((*itr) != sg && !state.interesting()) - uninteresting.insert(*itr); + uninterestingCache.insert(*itr); } if (!state.needShadows()) @@ -103,6 +111,10 @@ bool ShadowsBin::State::needShadows() const void ShadowsBin::sortImplementation() { + // The cull visitor contains a stategraph. + // When a stateset is pushed, it's added/found as a child of the current stategraph node, then that node becomes the new current stategraph node. + // When a drawable is added, the current stategraph node is added to the current renderbin (if it's not there already) and the drawable is added as a renderleaf to the stategraph + // This means our list only contains stategraph nodes with directly-attached renderleaves, but they might have parents with more state set that needs to be considered. if (!_stateGraphList.size()) return; StateGraph* root = _stateGraphList[0]; @@ -117,12 +129,16 @@ void ShadowsBin::sortImplementation() return; } root = root->find_or_insert(mStateSet.get()); + // root is now a stategraph with useDiffuseMapForShadowAlpha disabled but minimal other state root->_leaves.reserve(_stateGraphList.size()); StateGraphList newList; - std::unordered_set uninteresting; + std::unordered_set uninterestingCache; for (StateGraph* graph : _stateGraphList) { - if (!cullStateGraph(graph, root, uninteresting)) + // Render leaves which shouldn't use the diffuse map for shadow alpha but do cast shadows become children of root, so graph is now empty. Don't add to newList. + // Graphs containing just render leaves which don't cast shadows are discarded. Don't add to newList. + // Graphs containing other leaves need to be in newList. + if (!cullStateGraph(graph, root, uninterestingCache)) newList.push_back(graph); } if (!root->_leaves.empty()) diff --git a/components/sceneutil/shadowsbin.hpp b/components/sceneutil/shadowsbin.hpp index 05926bace..6302d5974 100644 --- a/components/sceneutil/shadowsbin.hpp +++ b/components/sceneutil/shadowsbin.hpp @@ -17,11 +17,11 @@ namespace SceneUtil private: osg::ref_ptr mStateSet; public: - META_Object(SceneUtil, ShadowsBin) - ShadowsBin(); - ShadowsBin(const ShadowsBin& rhs, const osg::CopyOp& copyop) : osgUtil::RenderBin(rhs, copyop), mStateSet(rhs.mStateSet) {} + META_Object(SceneUtil, ShadowsBin) + ShadowsBin(); + ShadowsBin(const ShadowsBin& rhs, const osg::CopyOp& copyop) : osgUtil::RenderBin(rhs, copyop), mStateSet(rhs.mStateSet) {} - virtual void sortImplementation(); + virtual void sortImplementation(); struct State { @@ -35,16 +35,17 @@ namespace SceneUtil bool mImportantState; bool needTexture() const { return mAlphaBlend || mAlphaTest; } bool needShadows() const; + // A state is interesting if there's anything about it that might affect whether we can optimise child state bool interesting() const { return !needShadows() || needTexture() || mAlphaBlendOverride || mAlphaTestOverride || mMaterialOverride || mImportantState; } }; bool cullStateGraph(osgUtil::StateGraph* sg, osgUtil::StateGraph* root, std::unordered_set& uninteresting); - static void addPrototype(const std::string& name) - { - osg::ref_ptr bin (new ShadowsBin); - osgUtil::RenderBin::addRenderBinPrototype(name, bin); - } + static void addPrototype(const std::string& name) + { + osg::ref_ptr bin (new ShadowsBin); + osgUtil::RenderBin::addRenderBinPrototype(name, bin); + } }; class ShadowsBinAdder From 5d046bc95dfc9e848b03772f4e53521fd2a1c343 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 11 Nov 2020 14:58:06 +0000 Subject: [PATCH 3/7] Mark override --- components/sceneutil/shadowsbin.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/shadowsbin.hpp b/components/sceneutil/shadowsbin.hpp index 6302d5974..6c35e1779 100644 --- a/components/sceneutil/shadowsbin.hpp +++ b/components/sceneutil/shadowsbin.hpp @@ -21,7 +21,7 @@ namespace SceneUtil ShadowsBin(); ShadowsBin(const ShadowsBin& rhs, const osg::CopyOp& copyop) : osgUtil::RenderBin(rhs, copyop), mStateSet(rhs.mStateSet) {} - virtual void sortImplementation(); + void sortImplementation() override; struct State { From 72f7e6a702cef495159869e3bde2de1d4627c7b8 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 12 Nov 2020 00:26:30 +0000 Subject: [PATCH 4/7] Handle all shadow alpha uniforms in shadowsbin --- apps/openmw/mwrender/animation.cpp | 12 ++------ components/sceneutil/mwshadowtechnique.cpp | 11 +------- components/sceneutil/mwshadowtechnique.hpp | 1 - components/sceneutil/shadowsbin.cpp | 33 ++++++++++++++-------- components/sceneutil/shadowsbin.hpp | 7 +++-- components/shader/shadermanager.cpp | 10 ------- components/shader/shadermanager.hpp | 6 ---- components/shader/shadervisitor.cpp | 28 +----------------- components/shader/shadervisitor.hpp | 1 - 9 files changed, 29 insertions(+), 80 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 29645a7c1..94a521960 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -16,7 +16,6 @@ #include #include -#include #include #include @@ -37,8 +36,6 @@ #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwworld/esmstore.hpp" @@ -493,9 +490,8 @@ namespace MWRender class TransparencyUpdater : public SceneUtil::StateSetUpdater { public: - TransparencyUpdater(const float alpha, osg::ref_ptr shadowUniform) + TransparencyUpdater(const float alpha) : mAlpha(alpha) - , mShadowUniform(shadowUniform) { } @@ -509,9 +505,6 @@ namespace MWRender { osg::BlendFunc* blendfunc (new osg::BlendFunc); stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - // TODO: don't do this anymore once custom shadow renderbin is handling it - if (mShadowUniform) - stateset->addUniform(mShadowUniform); stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); stateset->setRenderBinMode(osg::StateSet::OVERRIDE_RENDERBIN_DETAILS); @@ -533,7 +526,6 @@ namespace MWRender private: float mAlpha; - osg::ref_ptr mShadowUniform; }; struct Animation::AnimSource @@ -1773,7 +1765,7 @@ namespace MWRender { if (mTransparencyUpdater == nullptr) { - mTransparencyUpdater = new TransparencyUpdater(alpha, mResourceSystem->getSceneManager()->getShaderManager().getShadowMapAlphaTestEnableUniform()); + mTransparencyUpdater = new TransparencyUpdater(alpha); mObjectRoot->addCullCallback(mTransparencyUpdater); } else diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index c8a241c36..06a1efd2a 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -885,15 +885,6 @@ void SceneUtil::MWShadowTechnique::setupCastingShader(Shader::ShaderManager & sh _castingProgram->addShader(shaderManager.getShader("shadowcasting_vertex.glsl", Shader::ShaderManager::DefineMap(), osg::Shader::VERTEX)); _castingProgram->addShader(shaderManager.getShader("shadowcasting_fragment.glsl", Shader::ShaderManager::DefineMap(), osg::Shader::FRAGMENT)); - - _shadowMapAlphaTestDisableUniform = shaderManager.getShadowMapAlphaTestDisableUniform(); - _shadowMapAlphaTestDisableUniform->setName("alphaTestShadows"); - _shadowMapAlphaTestDisableUniform->setType(osg::Uniform::BOOL); - _shadowMapAlphaTestDisableUniform->set(false); - - shaderManager.getShadowMapAlphaTestEnableUniform()->setName("alphaTestShadows"); - shaderManager.getShadowMapAlphaTestEnableUniform()->setType(osg::Uniform::BOOL); - shaderManager.getShadowMapAlphaTestEnableUniform()->set(true); } MWShadowTechnique::ViewDependentData* MWShadowTechnique::createViewDependentData(osgUtil::CullVisitor* /*cv*/) @@ -1595,7 +1586,7 @@ void MWShadowTechnique::createShaders() // The casting program uses a sampler, so to avoid undefined behaviour, we must bind a dummy texture in case no other is supplied _shadowCastingStateSet->setTextureAttributeAndModes(0, _fallbackBaseTexture.get(), osg::StateAttribute::ON); _shadowCastingStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", true)); - _shadowCastingStateSet->addUniform(_shadowMapAlphaTestDisableUniform); + _shadowCastingStateSet->addUniform(new osg::Uniform("alphaTestShadows", false)); osg::ref_ptr depth = new osg::Depth; depth->setWriteMask(true); _shadowCastingStateSet->setAttribute(depth, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 23a8e009a..a7208cfa6 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -288,7 +288,6 @@ namespace SceneUtil { osg::ref_ptr _debugHud; osg::ref_ptr _castingProgram; - osg::ref_ptr _shadowMapAlphaTestDisableUniform; }; } diff --git a/components/sceneutil/shadowsbin.cpp b/components/sceneutil/shadowsbin.cpp index e0a141ffb..4c0c78cab 100644 --- a/components/sceneutil/shadowsbin.cpp +++ b/components/sceneutil/shadowsbin.cpp @@ -42,11 +42,16 @@ namespace SceneUtil ShadowsBin::ShadowsBin() { - mStateSet = new osg::StateSet; - mStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", false)); + mNoTestStateSet = new osg::StateSet; + mNoTestStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", false)); + mNoTestStateSet->addUniform(new osg::Uniform("alphaTestShadows", false)); + + mShaderAlphaTestStateSet = new osg::StateSet; + mShaderAlphaTestStateSet->addUniform(new osg::Uniform("alphaTestShadows", true)); + mShaderAlphaTestStateSet->setMode(GL_BLEND, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); } -bool ShadowsBin::cullStateGraph(StateGraph* sg, StateGraph* root, std::unordered_set& uninterestingCache) +StateGraph* ShadowsBin::cullStateGraph(StateGraph* sg, StateGraph* root, std::unordered_set& uninterestingCache) { std::vector return_path; State state; @@ -88,7 +93,7 @@ bool ShadowsBin::cullStateGraph(StateGraph* sg, StateGraph* root, std::unordered } if (!state.needShadows()) - return true; + return nullptr; if (!state.needTexture() && !state.mImportantState) { @@ -97,9 +102,12 @@ bool ShadowsBin::cullStateGraph(StateGraph* sg, StateGraph* root, std::unordered leaf->_parent = root; root->_leaves.push_back(leaf); } - return true; + return nullptr; } - return false; + + if (state.mAlphaBlend) + return sg->find_or_insert(mShaderAlphaTestStateSet); + return sg; } bool ShadowsBin::State::needShadows() const @@ -128,9 +136,9 @@ void ShadowsBin::sortImplementation() if (!root->_parent) return; } - root = root->find_or_insert(mStateSet.get()); + StateGraph* noTestRoot = root->find_or_insert(mNoTestStateSet.get()); // root is now a stategraph with useDiffuseMapForShadowAlpha disabled but minimal other state - root->_leaves.reserve(_stateGraphList.size()); + noTestRoot->_leaves.reserve(_stateGraphList.size()); StateGraphList newList; std::unordered_set uninterestingCache; for (StateGraph* graph : _stateGraphList) @@ -138,11 +146,12 @@ void ShadowsBin::sortImplementation() // Render leaves which shouldn't use the diffuse map for shadow alpha but do cast shadows become children of root, so graph is now empty. Don't add to newList. // Graphs containing just render leaves which don't cast shadows are discarded. Don't add to newList. // Graphs containing other leaves need to be in newList. - if (!cullStateGraph(graph, root, uninterestingCache)) - newList.push_back(graph); + StateGraph* graphToAdd = cullStateGraph(graph, noTestRoot, uninterestingCache); + if (graphToAdd) + newList.push_back(graphToAdd); } - if (!root->_leaves.empty()) - newList.push_back(root); + if (!noTestRoot->_leaves.empty()) + newList.push_back(noTestRoot); _stateGraphList = newList; } diff --git a/components/sceneutil/shadowsbin.hpp b/components/sceneutil/shadowsbin.hpp index 6c35e1779..13f68ec90 100644 --- a/components/sceneutil/shadowsbin.hpp +++ b/components/sceneutil/shadowsbin.hpp @@ -15,11 +15,12 @@ namespace SceneUtil class ShadowsBin : public osgUtil::RenderBin { private: - osg::ref_ptr mStateSet; + osg::ref_ptr mNoTestStateSet; + osg::ref_ptr mShaderAlphaTestStateSet; public: META_Object(SceneUtil, ShadowsBin) ShadowsBin(); - ShadowsBin(const ShadowsBin& rhs, const osg::CopyOp& copyop) : osgUtil::RenderBin(rhs, copyop), mStateSet(rhs.mStateSet) {} + ShadowsBin(const ShadowsBin& rhs, const osg::CopyOp& copyop) : osgUtil::RenderBin(rhs, copyop), mNoTestStateSet(rhs.mNoTestStateSet), mShaderAlphaTestStateSet(rhs.mShaderAlphaTestStateSet) {} void sortImplementation() override; @@ -39,7 +40,7 @@ namespace SceneUtil bool interesting() const { return !needShadows() || needTexture() || mAlphaBlendOverride || mAlphaTestOverride || mMaterialOverride || mImportantState; } }; - bool cullStateGraph(osgUtil::StateGraph* sg, osgUtil::StateGraph* root, std::unordered_set& uninteresting); + osgUtil::StateGraph* cullStateGraph(osgUtil::StateGraph* sg, osgUtil::StateGraph* root, std::unordered_set& uninteresting); static void addPrototype(const std::string& name) { diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index bfaa11282..788a8720b 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -384,14 +384,4 @@ namespace Shader program.second->releaseGLObjects(state); } - const osg::ref_ptr ShaderManager::getShadowMapAlphaTestEnableUniform() - { - return mShadowMapAlphaTestEnableUniform; - } - - const osg::ref_ptr ShaderManager::getShadowMapAlphaTestDisableUniform() - { - return mShadowMapAlphaTestDisableUniform; - } - } diff --git a/components/shader/shadermanager.hpp b/components/shader/shadermanager.hpp index ed5bbc907..13db30b01 100644 --- a/components/shader/shadermanager.hpp +++ b/components/shader/shadermanager.hpp @@ -43,9 +43,6 @@ namespace Shader void releaseGLObjects(osg::State* state); - const osg::ref_ptr getShadowMapAlphaTestEnableUniform(); - const osg::ref_ptr getShadowMapAlphaTestDisableUniform(); - private: std::string mPath; @@ -63,9 +60,6 @@ namespace Shader ProgramMap mPrograms; std::mutex mMutex; - - const osg::ref_ptr mShadowMapAlphaTestEnableUniform = new osg::Uniform(); - const osg::ref_ptr mShadowMapAlphaTestDisableUniform = new osg::Uniform(); }; bool parseFors(std::string& source, const std::string& templateName); diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index c30307f29..f17c4a80c 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -1,7 +1,5 @@ #include "shadervisitor.hpp" -#include -#include #include #include #include @@ -25,7 +23,6 @@ namespace Shader : mShaderRequired(false) , mColorMode(0) , mMaterialOverridden(false) - , mBlendFuncOverridden(false) , mNormalHeight(false) , mTexStageRequiringTangents(-1) , mNode(nullptr) @@ -233,14 +230,11 @@ namespace Shader if (!writableStateSet) writableStateSet = getWritableStateSet(node); // We probably shouldn't construct a new version of this each time as Uniforms use pointer comparison for early-out. - // Also it should probably belong to the shader manager + // Also it should probably belong to the shader manager or be applied by the shadows bin writableStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", true)); } } - bool alphaSettingsChanged = false; - bool alphaTestShadows = false; - const osg::StateSet::AttributeList& attributes = stateset->getAttributeList(); for (osg::StateSet::AttributeList::const_iterator it = attributes.begin(); it != attributes.end(); ++it) { @@ -284,28 +278,8 @@ namespace Shader mRequirements.back().mColorMode = colorMode; } } - else if (it->first.first == osg::StateAttribute::BLENDFUNC) - { - if (!mRequirements.back().mBlendFuncOverridden || it->second.second & osg::StateAttribute::PROTECTED) - { - if (it->second.second & osg::StateAttribute::OVERRIDE) - mRequirements.back().mBlendFuncOverridden = true; - - const osg::BlendFunc* blend = static_cast(it->second.first.get()); - if (blend->getSource() == osg::BlendFunc::SRC_ALPHA || blend->getSource() == osg::BlendFunc::SRC_COLOR) - alphaTestShadows = true; - alphaSettingsChanged = true; - } - } // Eventually, move alpha testing to discard in shader adn remove deprecated state here } - // we don't need to check for glEnable/glDisable of blending as we always set it at the same time - if (alphaSettingsChanged) - { - if (!writableStateSet) - writableStateSet = getWritableStateSet(node); - writableStateSet->addUniform(alphaTestShadows ? mShaderManager.getShadowMapAlphaTestEnableUniform() : mShaderManager.getShadowMapAlphaTestDisableUniform()); - } } void ShaderVisitor::pushRequirements(osg::Node& node) diff --git a/components/shader/shadervisitor.hpp b/components/shader/shadervisitor.hpp index bf1022180..ae157b976 100644 --- a/components/shader/shadervisitor.hpp +++ b/components/shader/shadervisitor.hpp @@ -75,7 +75,6 @@ namespace Shader int mColorMode; bool mMaterialOverridden; - bool mBlendFuncOverridden; bool mNormalHeight; // true if normal map has height info in alpha channel From 296dce470a6b2fe26894daaf5d9b3b3e6923a787 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 12 Nov 2020 16:58:29 +0000 Subject: [PATCH 5/7] Spelling fix --- components/sceneutil/shadowsbin.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/shadowsbin.hpp b/components/sceneutil/shadowsbin.hpp index 13f68ec90..86fd47cc0 100644 --- a/components/sceneutil/shadowsbin.hpp +++ b/components/sceneutil/shadowsbin.hpp @@ -11,7 +11,7 @@ namespace osg namespace SceneUtil { - /// renderbin which culls redundent state for shadows rendering + /// renderbin which culls redundant state for shadow map rendering class ShadowsBin : public osgUtil::RenderBin { private: From cdbf19a5086e33ee790be9854a366b4ef65e928d Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 12 Nov 2020 17:04:23 +0000 Subject: [PATCH 6/7] Tidy up run-on lines --- components/sceneutil/shadowsbin.hpp | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/components/sceneutil/shadowsbin.hpp b/components/sceneutil/shadowsbin.hpp index 86fd47cc0..cc6fd3525 100644 --- a/components/sceneutil/shadowsbin.hpp +++ b/components/sceneutil/shadowsbin.hpp @@ -20,13 +20,26 @@ namespace SceneUtil public: META_Object(SceneUtil, ShadowsBin) ShadowsBin(); - ShadowsBin(const ShadowsBin& rhs, const osg::CopyOp& copyop) : osgUtil::RenderBin(rhs, copyop), mNoTestStateSet(rhs.mNoTestStateSet), mShaderAlphaTestStateSet(rhs.mShaderAlphaTestStateSet) {} + ShadowsBin(const ShadowsBin& rhs, const osg::CopyOp& copyop) + : osgUtil::RenderBin(rhs, copyop) + , mNoTestStateSet(rhs.mNoTestStateSet) + , mShaderAlphaTestStateSet(rhs.mShaderAlphaTestStateSet) + {} void sortImplementation() override; struct State { - State():mAlphaBlend(false),mAlphaBlendOverride(false),mAlphaTest(false),mAlphaTestOverride(false),mMaterial(nullptr),mMaterialOverride(false),mImportantState(false){} + State() + : mAlphaBlend(false) + , mAlphaBlendOverride(false) + , mAlphaTest(false) + , mAlphaTestOverride(false) + , mMaterial(nullptr) + , mMaterialOverride(false) + , mImportantState(false) + {} + bool mAlphaBlend; bool mAlphaBlendOverride; bool mAlphaTest; @@ -37,7 +50,10 @@ namespace SceneUtil bool needTexture() const { return mAlphaBlend || mAlphaTest; } bool needShadows() const; // A state is interesting if there's anything about it that might affect whether we can optimise child state - bool interesting() const { return !needShadows() || needTexture() || mAlphaBlendOverride || mAlphaTestOverride || mMaterialOverride || mImportantState; } + bool interesting() const + { + return !needShadows() || needTexture() || mAlphaBlendOverride || mAlphaTestOverride || mMaterialOverride || mImportantState; + } }; osgUtil::StateGraph* cullStateGraph(osgUtil::StateGraph* sg, osgUtil::StateGraph* root, std::unordered_set& uninteresting); From fcfd340c697afdaee2fd989e7d782283c929eade Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 12 Nov 2020 23:23:40 +0000 Subject: [PATCH 7/7] Actually copy alpha blended drawables to the new stategraph --- components/sceneutil/shadowsbin.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/shadowsbin.cpp b/components/sceneutil/shadowsbin.cpp index 4c0c78cab..520ad0362 100644 --- a/components/sceneutil/shadowsbin.cpp +++ b/components/sceneutil/shadowsbin.cpp @@ -106,7 +106,15 @@ StateGraph* ShadowsBin::cullStateGraph(StateGraph* sg, StateGraph* root, std::un } if (state.mAlphaBlend) - return sg->find_or_insert(mShaderAlphaTestStateSet); + { + sg_new = sg->find_or_insert(mShaderAlphaTestStateSet); + for (RenderLeaf* leaf : sg->_leaves) + { + leaf->_parent = sg_new; + sg_new->_leaves.push_back(leaf); + } + return sg_new; + } return sg; }