diff --git a/examples/osgdepthpartition/DepthPartitionNode.cpp b/examples/osgdepthpartition/DepthPartitionNode.cpp index a0136d56c..663329520 100644 --- a/examples/osgdepthpartition/DepthPartitionNode.cpp +++ b/examples/osgdepthpartition/DepthPartitionNode.cpp @@ -1,6 +1,5 @@ #include "DepthPartitionNode.h" #include -#include #define CURRENT_CLASS DepthPartitionNode CURRENT_CLASS::CURRENT_CLASS() @@ -10,8 +9,7 @@ CURRENT_CLASS::CURRENT_CLASS() } CURRENT_CLASS::CURRENT_CLASS(const CURRENT_CLASS& dpn, const osg::CopyOp& copyop) - : osg::Group(dpn,copyop), - _active(dpn._active), + : _active(dpn._active), _renderOrder(dpn._renderOrder), _clearColorBuffer(dpn._clearColorBuffer) { @@ -116,26 +114,17 @@ void CURRENT_CLASS::traverse(osg::NodeVisitor &nv) osg::CameraNode *currCam; DistanceAccumulator::DistancePair currPair; - for(unsigned int j = 0; j < _numCameras; j++) + for(i = 0; i < _numCameras; i++) { // Create the camera, and clamp it's projection matrix - currPair = camPairs[j]; // (near,far) pair for current camera + currPair = camPairs[i]; // (near,far) pair for current camera currCam = createOrReuseCamera(projection, currPair.first, - currPair.second, j); + currPair.second, i); // Set the modelview matrix and viewport of the camera currCam->setViewMatrix(modelview); currCam->setViewport(viewport); -/* - // Set our children as the camera's children - currCam->removeChild(0, currCam->getNumChildren()); - for(i = 0; i < numChildren; i++) - { - currCam->addChild(_children[i].get()); - } -*/ - // Redirect the CullVisitor to the current camera currCam->accept(nv); } diff --git a/examples/osgdepthpartition/DepthPartitionNode.h b/examples/osgdepthpartition/DepthPartitionNode.h index ab0a78bc5..e002e31ae 100644 --- a/examples/osgdepthpartition/DepthPartitionNode.h +++ b/examples/osgdepthpartition/DepthPartitionNode.h @@ -37,11 +37,19 @@ class CURRENT_CLASS : public osg::Group inline osg::CameraNode::RenderOrder getRenderOrder() const { return _renderOrder; } + /** Set/get the maximum depth that the scene will be traversed to. + Defaults to UINT_MAX. */ + void setMaxTraversalDepth(unsigned int depth) + { _distAccumulator->setMaxDepth(depth); } + + inline unsigned int getMaxTraversalDepth() const + { return _distAccumulator->getMaxDepth(); } + /** Override update and cull traversals */ virtual void traverse(osg::NodeVisitor &nv); /** Catch child management functions so the CameraNodes can be informed - of new/removed children */ + of added or removed children. */ virtual bool addChild(osg::Node *child); virtual bool insertChild(unsigned int index, osg::Node *child); virtual bool removeChild(osg::Node *child); diff --git a/examples/osgdepthpartition/DistanceAccumulator.cpp b/examples/osgdepthpartition/DistanceAccumulator.cpp index ac9387158..4410296f7 100644 --- a/examples/osgdepthpartition/DistanceAccumulator.cpp +++ b/examples/osgdepthpartition/DistanceAccumulator.cpp @@ -24,11 +24,11 @@ double distance(const osg::Vec3 &coord, const osg::Matrix& matrix) #define CURRENT_CLASS DistanceAccumulator CURRENT_CLASS::CURRENT_CLASS() - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN), _nearFarRatio(0.0) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN), + _nearFarRatio(0.0005), _maxDepth(UINT_MAX) { setMatrices(osg::Matrix::identity(), osg::Matrix::identity()); reset(); - setNearFarRatio(0.0005); } CURRENT_CLASS::~CURRENT_CLASS() {} @@ -44,97 +44,155 @@ void CURRENT_CLASS::pushLocalFrustum() _localFrusta.push_back(localFrustum); // Compute new bounding box corners - osg::Vec3d lookVector(-currMatrix(0,2), -currMatrix(1,2), -currMatrix(2,2)); bbCornerPair corner; - corner.second = (lookVector.x()>=0?1:0) | - (lookVector.y()>=0?2:0) | - (lookVector.z()>=0?4:0); + corner.second = (currMatrix(0,2)<=0?1:0) | + (currMatrix(1,2)<=0?2:0) | + (currMatrix(2,2)<=0?4:0); corner.first = (~corner.second)&7; _bbCorners.push_back(corner); } -void CURRENT_CLASS::apply(osg::CameraNode& /*camera*/) +void CURRENT_CLASS::pushDistancePair(double zNear, double zFar) { - // We don't support scenes with CameraNodes in them - return; + if(zFar > 0.0) // Make sure some of drawable is visible + { + // Make sure near plane is in front of viewpoint. + if(zNear <= 0.0) + { + zNear = zFar*_nearFarRatio; + if(zNear >= 1.0) zNear = 1.0; // 1.0 limit chosen arbitrarily! + } + + // Add distance pair for current drawable + _distancePairs.push_back(DistancePair(zNear, zFar)); + + // Override the current nearest/farthest planes if necessary + if(zNear < _limits.first) _limits.first = zNear; + if(zFar > _limits.second) _limits.second = zFar; + } +} + +/** Return true if the node should be traversed, and false if the bounding sphere + of the node is small enough to be rendered by one CameraNode. If the latter + is true, then store the node's near & far plane distances. */ +bool CURRENT_CLASS::shouldContinueTraversal(osg::Node &node) +{ + // Allow traversal to continue if we haven't reached maximum depth. + bool keepTraversing = (_currentDepth < _maxDepth); + + const osg::BoundingSphere &bs = node.getBound(); + double zNear = 0.0, zFar = 0.0; + + // Make sure bounding sphere is valid and within viewing volume + if(bs.valid()) + { + if(!_localFrusta.back().contains(bs)) keepTraversing = false; + else + { + // Compute near and far planes for this node + zNear = distance(bs._center, _viewMatrices.back()); + zFar = zNear + bs._radius; + zNear -= bs._radius; + + // If near/far ratio is big enough, then we don't need to keep + // traversing children of this node. + if(zNear >= zFar*_nearFarRatio) keepTraversing = false; + } + } + + // If traversal should stop, then store this node's (near,far) pair + if(!keepTraversing) pushDistancePair(zNear, zFar); + + return keepTraversing; +} + +void CURRENT_CLASS::apply(osg::Node &node) +{ + if(shouldContinueTraversal(node)) + { + // Traverse this node + _currentDepth++; + traverse(node); + _currentDepth--; + } } void CURRENT_CLASS::apply(osg::Projection &proj) { - // Push the new projection matrix view frustum - _projectionMatrices.push_back(proj.getMatrix()); - pushLocalFrustum(); + if(shouldContinueTraversal(proj)) + { + // Push the new projection matrix view frustum + _projectionMatrices.push_back(proj.getMatrix()); + pushLocalFrustum(); - traverse(proj); // Traverse the rest of the scene graph + // Traverse the group + _currentDepth++; + traverse(proj); + _currentDepth--; - // Reload original matrix and frustum - _localFrusta.pop_back(); - _bbCorners.pop_back(); - _projectionMatrices.pop_back(); + // Reload original matrix and frustum + _localFrusta.pop_back(); + _bbCorners.pop_back(); + _projectionMatrices.pop_back(); + } } void CURRENT_CLASS::apply(osg::Transform &transform) { - // Compute transform for current node - osg::Matrix currMatrix = _viewMatrices.back(); - bool pushMatrix = transform.computeLocalToWorldMatrix(currMatrix, this); - - if(pushMatrix) + if(shouldContinueTraversal(transform)) { - // Store the new modelview matrix and view frustum - _viewMatrices.push_back(currMatrix); - pushLocalFrustum(); - } + // Compute transform for current node + osg::Matrix currMatrix = _viewMatrices.back(); + bool pushMatrix = transform.computeLocalToWorldMatrix(currMatrix, this); - traverse(transform); // Traverse the rest of the scene graph + if(pushMatrix) + { + // Store the new modelview matrix and view frustum + _viewMatrices.push_back(currMatrix); + pushLocalFrustum(); + } - if(pushMatrix) - { - // Restore the old modelview matrix and view frustum - _localFrusta.pop_back(); - _bbCorners.pop_back(); - _viewMatrices.pop_back(); + _currentDepth++; + traverse(transform); + _currentDepth--; + + if(pushMatrix) + { + // Restore the old modelview matrix and view frustum + _localFrusta.pop_back(); + _bbCorners.pop_back(); + _viewMatrices.pop_back(); + } } } void CURRENT_CLASS::apply(osg::Geode &geode) { - osg::Drawable *drawable; - double zNear, zFar; - - // Handle each drawable in this geode - for(unsigned int i = 0; i < geode.getNumDrawables(); i++) + // Contained drawables will only be individually considered if we are + // allowed to continue traversing. + if(shouldContinueTraversal(geode)) { - drawable = geode.getDrawable(i); + osg::Drawable *drawable; + double zNear, zFar; - const osg::BoundingBox &bb = drawable->getBound(); - if(bb.valid()) + // Handle each drawable in this geode + for(unsigned int i = 0; i < geode.getNumDrawables(); i++) { - // Make sure drawable will be visible in the scene - if(!_localFrusta.back().contains(bb)) continue; + drawable = geode.getDrawable(i); - // Compute near/far distances for current drawable - zNear = distance(bb.corner(_bbCorners.back().first), - _viewMatrices.back()); - zFar = distance(bb.corner(_bbCorners.back().second), - _viewMatrices.back()); - if(zNear > zFar) std::swap(zNear, zFar); - - if(zFar > 0.0) // Make sure some of drawable is visible + const osg::BoundingBox &bb = drawable->getBound(); + if(bb.valid()) { - // Make sure near plane is in front of viewpoint. - if(zNear <= 0.0) - { - zNear = zFar*_nearFarRatio; - if(zNear >= 1.0) zNear = 1.0; // 1.0 limit chosen arbitrarily! - } + // Make sure drawable will be visible in the scene + if(!_localFrusta.back().contains(bb)) continue; - // Add distance pair for current drawable and current rendering mode - _distancePairs.push_back(DistancePair(zNear, zFar)); - - // Override the current nearest/farthest planes if necessary - if(zNear < _limits.first) _limits.first = zNear; - if(zFar > _limits.second) _limits.second = zFar; + // Compute near/far distances for current drawable + zNear = distance(bb.corner(_bbCorners.back().first), + _viewMatrices.back()); + zFar = distance(bb.corner(_bbCorners.back().second), + _viewMatrices.back()); + if(zNear > zFar) std::swap(zNear, zFar); + pushDistancePair(zNear, zFar); } } } @@ -154,6 +212,7 @@ void CURRENT_CLASS::reset() _cameraPairs.clear(); _limits.first = DBL_MAX; _limits.second = 0.0; + _currentDepth = 0; // Initial transform matrix is the modelview matrix _viewMatrices.clear(); @@ -276,7 +335,7 @@ void CURRENT_CLASS::computeCameraPairs() void CURRENT_CLASS::setNearFarRatio(double ratio) { - if(_nearFarRatio == ratio || ratio <= 0.0 || ratio >= 1.0) return; + if(ratio <= 0.0 || ratio >= 1.0) return; _nearFarRatio = ratio; } #undef CURRENT_CLASS diff --git a/examples/osgdepthpartition/DistanceAccumulator.h b/examples/osgdepthpartition/DistanceAccumulator.h index b13d0ae7e..f8dfc5f9c 100644 --- a/examples/osgdepthpartition/DistanceAccumulator.h +++ b/examples/osgdepthpartition/DistanceAccumulator.h @@ -22,7 +22,7 @@ class CURRENT_CLASS : public osg::NodeVisitor CURRENT_CLASS(); - virtual void apply(osg::CameraNode &camera); + virtual void apply(osg::Node &node); virtual void apply(osg::Projection &proj); virtual void apply(osg::Transform &transform); virtual void apply(osg::Geode &geode); @@ -51,10 +51,15 @@ class CURRENT_CLASS : public osg::NodeVisitor void setNearFarRatio(double ratio); inline double getNearFarRatio() const { return _nearFarRatio; } + inline void setMaxDepth(unsigned int depth) { _maxDepth = depth; } + inline unsigned int getMaxDepth() const { return _maxDepth; } + protected: virtual ~CURRENT_CLASS(); void pushLocalFrustum(); + void pushDistancePair(double zNear, double zFar); + bool shouldContinueTraversal(osg::Node &node); // Stack of matrices accumulated during traversal osg::fast_back_stack _viewMatrices; @@ -81,6 +86,9 @@ class CURRENT_CLASS : public osg::NodeVisitor // Ratio of nearest/farthest clip plane for each section of the scene double _nearFarRatio; + + // Maximum depth to traverse to + unsigned int _maxDepth, _currentDepth; }; #undef CURRENT_CLASS