From Paul Martz, "The changes are very similar to Magne's, except they now take the near plane into account. The changes are:

* Change OcclusionQueryNode::getPassed to take a NodeVisitor rather than the distance from BS center to the eye point. Change where CullVisitor calls this method to use the new parameters.
 * getPassed now exits early and returns true to avoid blinking / blink-in of geometry for the first frame or for out-of-range LOD children coming back into view.
 * getPassed now considers the distance from the near plane to the bounding sphere (rather than eye point to bounding sphere) when determining if the viewer is "inside" the bounding sphere or not."
This commit is contained in:
Robert Osfield 2010-02-26 10:13:28 +00:00
parent 75527fd800
commit d50eacd07e
3 changed files with 28 additions and 6 deletions

View File

@ -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 );

View File

@ -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<OpenThreads::Mutex> 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)
{

View File

@ -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.