From 54d490e24b75ceccfc138f48edcd751756aeef84 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 19 Oct 2001 12:56:37 +0000 Subject: [PATCH] Added support for specifying whether view frustum and small feature culling should be applied to a node or its child with the new osg::Node::setCullingActive() flag. A mechanism has been implemented so that if child has its culling disabled then their parents, all the way up to the root are also have their culling implicitly disabled. The osg::CullVisitor has updated to take account of both the explicit control via setCullingActive and the implicit culling disabling through children being disabled. This feature is useful for nodes which don't have a bounding volume to cull against, earth sky implementations and light sources. The default osg::Node::_cullingActive is true, i.e. culling is enabled by default. --- include/osg/Node | 23 +++++++++-- src/osg/Group.cpp | 62 +++++++++++++++++++++++++++++ src/osg/Node.cpp | 79 +++++++++++++++++++++++++++++++++++++ src/osgPlugins/osg/Node.cpp | 20 ++++++++++ src/osgUtil/CullVisitor.cpp | 35 ++++++++++++---- 5 files changed, 209 insertions(+), 10 deletions(-) diff --git a/include/osg/Node b/include/osg/Node index 5aec15c7b..fa1fd282d 100644 --- a/include/osg/Node +++ b/include/osg/Node @@ -105,6 +105,20 @@ class SG_EXPORT Node : public Object * since they have an AppCallback attached to them or their children.*/ inline const int getNumChildrenRequiringAppTraversal() const { return _numChildrenRequiringAppTraversal; } + + /** Set the view frustum/small feature culling of this node to be active or inactive. + * The default value to true for _cullingActive. Used a guide + * to the cull traversal.*/ + void setCullingActive(const bool active); + + /** Get the view frustum/small feature _cullingActive flag. Used a guide + * to the cull traversal.*/ + inline const bool getCullingActive() const { return _cullingActive; } + + /** Get the number of Children of this node which have culling disabled.*/ + inline const int getNumChildrenWithCullingDisabled() const { return _numChildrenWithCullingDisabled; } + + /** * Set user data. See MemoryAdapter documentation for details * of how to specify memory management of _userData. @@ -201,11 +215,14 @@ class SG_EXPORT Node : public Object ParentList _parents; friend Group; - ref_ptr _appCallback; - int _numChildrenRequiringAppTraversal; - + ref_ptr _appCallback; + int _numChildrenRequiringAppTraversal; void setNumChildrenRequiringAppTraversal(const int num); + bool _cullingActive; + int _numChildrenWithCullingDisabled; + void setNumChildrenWithCullingDisabled(const int num); + void* _userData; ref_ptr _memoryAdapter; diff --git a/src/osg/Group.cpp b/src/osg/Group.cpp index 85f1169c9..7a7f57120 100644 --- a/src/osg/Group.cpp +++ b/src/osg/Group.cpp @@ -62,6 +62,16 @@ bool Group::addChild( Node *child ) ); } + // could now require disabling of culling thanks to the new subgraph, + // so need to check and update if required. + if (child->getNumChildrenWithCullingDisabled()>0 || + !child->getCullingActive()) + { + setNumChildrenWithCullingDisabled( + getNumChildrenWithCullingDisabled()+1 + ); + } + return true; } else return false; @@ -89,6 +99,14 @@ bool Group::removeChild( Node *child ) ); } + if (child->getNumChildrenWithCullingDisabled()>0 || + !child->getCullingActive()) + { + setNumChildrenWithCullingDisabled( + getNumChildrenWithCullingDisabled()-1 + ); + } + // note ref_ptr<> automatically handles decrementing child's reference count. _children.erase(itr); dirtyBound(); @@ -118,6 +136,50 @@ bool Group::replaceChild( Node *origNode, Node *newNode ) newNode->_parents.push_back(this); dirtyBound(); + + + // could now require app traversal thanks to the new subgraph, + // so need to check and update if required. + int delta_numChildrenRequiringAppTraversal = 0; + if (origNode->getNumChildrenRequiringAppTraversal()>0 || + origNode->getAppCallback()) + { + --delta_numChildrenRequiringAppTraversal; + } + if (newNode->getNumChildrenRequiringAppTraversal()>0 || + newNode->getAppCallback()) + { + ++delta_numChildrenRequiringAppTraversal; + } + + if (delta_numChildrenRequiringAppTraversal!=0) + { + setNumChildrenRequiringAppTraversal( + getNumChildrenRequiringAppTraversal()+delta_numChildrenRequiringAppTraversal + ); + } + + // could now require disabling of culling thanks to the new subgraph, + // so need to check and update if required. + int delta_numChildrenWithCullingDisabled = 0; + if (origNode->getNumChildrenWithCullingDisabled()>0 || + !origNode->getCullingActive()) + { + --delta_numChildrenWithCullingDisabled; + } + if (newNode->getNumChildrenWithCullingDisabled()>0 || + !newNode->getCullingActive()) + { + ++delta_numChildrenWithCullingDisabled; + } + + if (delta_numChildrenWithCullingDisabled!=0) + { + setNumChildrenWithCullingDisabled( + getNumChildrenWithCullingDisabled()-1 + ); + } + return true; } else return false; diff --git a/src/osg/Node.cpp b/src/osg/Node.cpp index c65470c13..36258db1f 100644 --- a/src/osg/Node.cpp +++ b/src/osg/Node.cpp @@ -15,6 +15,10 @@ Node::Node() _nodeMask = 0xffffffff; _numChildrenRequiringAppTraversal = 0; + + _cullingActive = true; + _numChildrenWithCullingDisabled = 0; + } @@ -112,6 +116,81 @@ void Node::setNumChildrenRequiringAppTraversal(const int num) } +void Node::setCullingActive(const bool active) +{ + // if no changes just return. + if (_cullingActive == active) return; + + // culling active has been changed, will need to update + // both _cullActive and possibly the parents numChildrenWithCullingDisabled + // if culling disabled changes. + + // update the parents _numChildrenWithCullingDisabled + // note, if _numChildrenWithCullingDisabled!=0 then the + // parents won't be affected by any app callback change, + // so no need to inform them. + if (_numChildrenWithCullingDisabled==0 && !_parents.empty()) + { + int delta = 0; + if (!_cullingActive) --delta; + if (!active) ++delta; + if (delta!=0) + { + // the number of callbacks has changed, need to pass this + // on to parents so they know whether app traversal is + // reqired on this subgraph. + for(ParentList::iterator itr =_parents.begin(); + itr != _parents.end(); + ++itr) + { + (*itr)->setNumChildrenWithCullingDisabled( + (*itr)->getNumChildrenWithCullingDisabled()+delta ); + } + + } + } + + // set the cullingActive itself. + _cullingActive = active; +} + +void Node::setNumChildrenWithCullingDisabled(const int num) +{ + // if no changes just return. + if (_numChildrenWithCullingDisabled==num) return; + + // note, if _cullingActive is false then the + // parents won't be affected by any changes to + // _numChildrenWithCullingDisabled so no need to inform them. + if (_cullingActive && !_parents.empty()) + { + + // need to pass on changes to parents. + int delta = 0; + if (_numChildrenWithCullingDisabled>0) --delta; + if (num>0) ++delta; + if (delta!=0) + { + // the number of callbacks has changed, need to pass this + // on to parents so they know whether app traversal is + // reqired on this subgraph. + for(ParentList::iterator itr =_parents.begin(); + itr != _parents.end(); + ++itr) + { + (*itr)->setNumChildrenWithCullingDisabled( + (*itr)->getNumChildrenWithCullingDisabled()+delta + ); + } + + } + } + + // finally update this objects value. + _numChildrenWithCullingDisabled=num; +} + + const bool Node::computeBound() const { _bsphere.init(); diff --git a/src/osgPlugins/osg/Node.cpp b/src/osgPlugins/osg/Node.cpp index e8e832e8c..91491302e 100644 --- a/src/osgPlugins/osg/Node.cpp +++ b/src/osgPlugins/osg/Node.cpp @@ -34,6 +34,22 @@ bool Node_readLocalData(Object& obj, Input& fr) iteratorAdvanced = true; } + if (fr[0].matchWord("cullingActive")) + { + if (fr[1].matchWord("FALSE")) + { + node.setCullingActive(false); + iteratorAdvanced = true; + fr+=2; + } + else if (fr[1].matchWord("TRUE")) + { + node.setCullingActive(true); + iteratorAdvanced = true; + fr+=2; + } + } + // if (fr.matchSequence("user_data {")) // { // notify(DEBUG) << "Matched user_data {"<(_userData); diff --git a/src/osgUtil/CullVisitor.cpp b/src/osgUtil/CullVisitor.cpp index c99a7e75c..80138fada 100644 --- a/src/osgUtil/CullVisitor.cpp +++ b/src/osgUtil/CullVisitor.cpp @@ -367,7 +367,10 @@ CullViewState::CullingMode CullVisitor::getCullingMode() const void CullVisitor::apply(Node& node) { CullViewState::CullingMode mode = _cullingModeStack.back(); - if (isCulled(node.getBound(),mode)) return; + + if (!node.getCullingActive()) mode = 0; + else if (node.getNumChildrenWithCullingDisabled()==0 && + isCulled(node.getBound(),mode)) return; // push the culling mode. _cullingModeStack.push_back(mode); @@ -391,7 +394,10 @@ void CullVisitor::apply(Geode& node) // return if object's bounding sphere is culled. CullViewState::CullingMode mode = _cullingModeStack.back(); - if (isCulled(node.getBound(),mode)) return; + + if (!node.getCullingActive()) mode = 0; + else if (node.getNumChildrenWithCullingDisabled()==0 && + isCulled(node.getBound(),mode)) return; // push the node's state. StateSet* node_state = node.getStateSet(); @@ -465,7 +471,10 @@ void CullVisitor::apply(Billboard& node) { // return if object's bounding sphere is culled. CullViewState::CullingMode mode = _cullingModeStack.back(); - if (isCulled(node.getBound(),mode)) return; + + if (!node.getCullingActive()) mode = 0; + else if (node.getNumChildrenWithCullingDisabled()==0 && + isCulled(node.getBound(),mode)) return; // push the node's state. StateSet* node_state = node.getStateSet(); @@ -566,7 +575,10 @@ void CullVisitor::apply(Group& node) { // return if object's bounding sphere is culled. CullViewState::CullingMode mode = _cullingModeStack.back(); - if (isCulled(node.getBound(),mode)) return; + + if (!node.getCullingActive()) mode = 0; + else if (node.getNumChildrenWithCullingDisabled()==0 && + isCulled(node.getBound(),mode)) return; // push the culling mode. _cullingModeStack.push_back(mode); @@ -589,7 +601,10 @@ void CullVisitor::apply(Transform& node) { // return if object's bounding sphere is culled. CullViewState::CullingMode mode = _cullingModeStack.back(); - if (isCulled(node.getBound(),mode)) return; + + if (!node.getCullingActive()) mode = 0; + else if (node.getNumChildrenWithCullingDisabled()==0 && + isCulled(node.getBound(),mode)) return; // push the culling mode. _cullingModeStack.push_back(mode); @@ -622,7 +637,10 @@ void CullVisitor::apply(LOD& node) { // return if object's bounding sphere is culled. CullViewState::CullingMode mode = _cullingModeStack.back(); - if (isCulled(node.getBound(),mode)) return; + + if (!node.getCullingActive()) mode = 0; + else if (node.getNumChildrenWithCullingDisabled()==0 && + isCulled(node.getBound(),mode)) return; int eval = node.evaluate(getEyeLocal(),_LODBias); if (eval<0) return; @@ -667,7 +685,10 @@ void CullVisitor::apply(Impostor& node) // return if object's bounding sphere is culled. CullViewState::CullingMode mode = _cullingModeStack.back(); - if (isCulled(bs,mode)) return; + + if (!node.getCullingActive()) mode = 0; + else if (node.getNumChildrenWithCullingDisabled()==0 && + isCulled(node.getBound(),mode)) return; osg::Vec3 eyeLocal = getEyeLocal();