diff --git a/include/osg/OcclusionQueryNode b/include/osg/OcclusionQueryNode index 9a398189c..57aa3c7b1 100644 --- a/include/osg/OcclusionQueryNode +++ b/include/osg/OcclusionQueryNode @@ -88,7 +88,7 @@ public: // These methods are public so that osgUtil::CullVisitor can access them. // Not intended for application use. - bool getPassed( const osg::Camera* camera, float distanceToEyePoint ); + bool getPassed( const osg::Camera* camera, osg::NodeVisitor& nv ); void traverseQuery( const osg::Camera* camera, osg::NodeVisitor& nv ); void traverseDebug( osg::NodeVisitor& nv ); diff --git a/src/osg/OcclusionQueryNode.cpp b/src/osg/OcclusionQueryNode.cpp index 94acf72fd..7b39e9972 100644 --- a/src/osg/OcclusionQueryNode.cpp +++ b/src/osg/OcclusionQueryNode.cpp @@ -552,13 +552,25 @@ OcclusionQueryNode::OcclusionQueryNode( const OcclusionQueryNode& oqn, const osg bool -OcclusionQueryNode::getPassed( const osg::Camera* camera, float distanceToEyePoint ) +OcclusionQueryNode::getPassed( const osg::Camera* camera, osg::NodeVisitor& nv ) { if ( !_enabled ) // Queries are not enabled. The caller should be osgUtil::CullVisitor, // return true to traverse the subgraphs. return true; + { + // Two situations where we want to simply do a regular traversal: + // 1) it's the first frame for this camers + // 2) we haven't rendered for an abnormally long time (probably because we're an out-of-range LOD child) + // In these cases, assume we're visible to avoid blinking. + OpenThreads::ScopedLock lock( _frameCountMutex ); + const int& lastQueryFrame( _frameCountMap[ camera ] ); + if( ( lastQueryFrame == 0 ) || + ( (nv.getTraversalNumber() - lastQueryFrame) > (_queryFrameCount + 1) ) ) + return true; + } + if (_queryGeode->getDrawable( 0 ) == NULL) { osg::notify( osg::FATAL ) << @@ -568,11 +580,21 @@ OcclusionQueryNode::getPassed( const osg::Camera* camera, float distanceToEyePoi } QueryGeometry* qg = static_cast< QueryGeometry* >( _queryGeode->getDrawable( 0 ) ); - // If the distance to the bounding sphere shell is positive, retrieve - // the results. Others (we're inside the BS shell) we are considered + // Get the near plane for the upcoming distance calculation. + float nearPlane; + const osg::Matrix& proj( camera->getProjectionMatrix() ); + if( ( proj(3,3) != 1. ) || ( proj(2,3) != 0. ) || ( proj(1,3) != 0. ) || ( proj(0,3) != 0.) ) + nearPlane = proj(3,2) / (proj(2,2)-1.); // frustum / perspective + else + nearPlane = (proj(3,2)+1.) / proj(2,2); // ortho + + // If the distance from the near plane to the bounding sphere shell is positive, retrieve + // the results. Otherwise (near plane inside the BS shell) we are considered // to have passed and don't need to retrieve the query. const osg::BoundingSphere& bs = getBound(); - float distance = distanceToEyePoint - bs._radius; + float distanceToEyePoint = nv.getDistanceToEyePoint( bs._center, false ); + + float distance = distanceToEyePoint - nearPlane - bs._radius; _passed = ( distance <= 0.f ); if (!_passed) { diff --git a/src/osgUtil/CullVisitor.cpp b/src/osgUtil/CullVisitor.cpp index 525961759..53650c630 100644 --- a/src/osgUtil/CullVisitor.cpp +++ b/src/osgUtil/CullVisitor.cpp @@ -1446,7 +1446,7 @@ void CullVisitor::apply(osg::OcclusionQueryNode& node) osg::Camera* camera = getCurrentCamera(); // If previous query indicates visible, then traverse as usual. - if (node.getPassed( camera, getDistanceToEyePoint( node.getBound()._center, false ) )) + if (node.getPassed( camera, *this )) handle_cull_callbacks_and_traverse(node); // Traverse the query subtree if OcclusionQueryNode needs to issue another query.