Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/osg/OcclusionQueryNode
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ protected:

bool _enabled;

// If the box of the query geometry is valid.
bool _validQueryGeometry;

// Tracks the last frame number that we performed a query.
// User can set how many times (See setQueryFrameCount).
typedef std::map< const osg::Camera*, unsigned int > FrameCountMap;
Expand Down
94 changes: 83 additions & 11 deletions src/osg/OcclusionQueryNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,17 @@ struct RetrieveQueriesCallback : public osg::Camera::DrawCallback
OSG_WARN << "osgOQ: RQCB: " <<
"glGetQueryObjectiv returned negative value (" << tr->_numPixels << ")." << std::endl;

OSG_DEBUG << "osgOQ: query result: numPixels=" << tr->_numPixels << std::endl;

// Either retrieve last frame's results, or ignore it because the
// camera is inside the view. In either case, _active is now false.
tr->_active = false;
}
// else: query result not available yet, try again next frame
// query result not available yet, try again next frame
else
{
OSG_DEBUG << "osgOQ: query result not available yet" << std::endl;
}

it++;
count++;
Expand Down Expand Up @@ -263,6 +269,8 @@ QueryGeometry::~QueryGeometry()
void
QueryGeometry::reset()
{
OSG_DEBUG << "osgOQ: QueryGeometry::reset()" << std::endl;

OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _mapMutex );

ResultMap::iterator it = _results.begin();
Expand All @@ -282,6 +290,8 @@ QueryGeometry::reset()
void
QueryGeometry::drawImplementation( osg::RenderInfo& renderInfo ) const
{
OSG_DEBUG << "osgOQ: QueryGeometry::drawImplementation(...)" << std::endl;

unsigned int contextID = renderInfo.getState()->getContextID();
osg::GLExtensions* ext = renderInfo.getState()->get<GLExtensions>();

Expand Down Expand Up @@ -442,6 +452,7 @@ QueryGeometry::discardDeletedQueryObjects( unsigned int contextID )

OcclusionQueryNode::OcclusionQueryNode()
: _enabled( true ),
_validQueryGeometry( false ),
_passed(false),
_visThreshold( 500 ),
_queryFrameCount( 5 ),
Expand All @@ -459,6 +470,7 @@ OcclusionQueryNode::~OcclusionQueryNode()

OcclusionQueryNode::OcclusionQueryNode( const OcclusionQueryNode& oqn, const CopyOp& copyop )
: Group( oqn, copyop ),
_validQueryGeometry( false ),
_passed( false )
{
_enabled = oqn._enabled;
Expand All @@ -477,6 +489,22 @@ bool OcclusionQueryNode::getPassed( const Camera* camera, NodeVisitor& nv )
{
// Queries are not enabled. The caller should be osgUtil::CullVisitor,
// return true to traverse the subgraphs.
OSG_DEBUG << "osgOQ: passed because queries are disabled" << std::endl;
_passed = true;
return _passed;
}

QueryGeometry* qg = static_cast< QueryGeometry* >( _queryGeode->getDrawable( 0 ) );

if ( !_validQueryGeometry )
{
// There're cases that the occlusion test result has been retrieved
// after the query geometry has been changed, it's the result of the
// geometry before the change.
qg->reset();

// The box of the query geometry is invalid, return true to traverse
// the subgraphs.
_passed = true;
return _passed;
}
Expand All @@ -491,6 +519,12 @@ bool OcclusionQueryNode::getPassed( const Camera* camera, NodeVisitor& nv )
if( ( lastQueryFrame == 0 ) ||
( (nv.getTraversalNumber() - lastQueryFrame) > (_queryFrameCount + 1) ) )
{
OSG_DEBUG << "osgOQ: passed because"
<< " lastQueryFrame=" << lastQueryFrame
<< ", traversalNumber=" << nv.getTraversalNumber()
<< ", _queryFrameCount=" << _queryFrameCount
<< std::endl;

_passed = true;
return _passed;
}
Expand All @@ -503,7 +537,6 @@ bool OcclusionQueryNode::getPassed( const Camera* camera, NodeVisitor& nv )
_passed = true;
return _passed;
}
QueryGeometry* qg = static_cast< QueryGeometry* >( _queryGeode->getDrawable( 0 ) );

// Get the near plane for the upcoming distance calculation.
osg::Matrix::value_type nearPlane;
Expand All @@ -528,18 +561,30 @@ bool OcclusionQueryNode::getPassed( const Camera* camera, NodeVisitor& nv )
{
// The query hasn't finished yet and the result still
// isn't available, return true to traverse the subgraphs.
OSG_DEBUG << "osgOQ: passed because query result is still not available" << std::endl;
_passed = true;
return _passed;
}

_passed = ( result.numPixels > _visThreshold );

OSG_DEBUG << "osgOQ: passed=" << _passed << " because"
<< " numPixels=" << result.numPixels
<< ", _visThreshold=" << _visThreshold
<< std::endl;
}
else {
OSG_DEBUG << "osgOQ: passed because distance=" << distance << std::endl;
}

return _passed;
}

void OcclusionQueryNode::traverseQuery( const Camera* camera, NodeVisitor& nv )
{
if (!_validQueryGeometry)
return;

bool issueQuery;
{
const int curFrame = nv.getTraversalNumber();
Expand All @@ -548,8 +593,17 @@ void OcclusionQueryNode::traverseQuery( const Camera* camera, NodeVisitor& nv )
unsigned int& lastQueryFrame = _frameCountMap[ camera ];
issueQuery = (curFrame - lastQueryFrame >= _queryFrameCount);
if (issueQuery)
{
OSG_DEBUG << "osgOQ: traverse query because:"
<< " curFrame=" << curFrame
<< ", lastQueryFrame=" << lastQueryFrame
<< ", _queryFrameCount=" << _queryFrameCount
<< std::endl;

lastQueryFrame = curFrame;
}
}

if (issueQuery)
_queryGeode->accept( nv );
}
Expand All @@ -573,21 +627,37 @@ BoundingSphere OcclusionQueryNode::computeBound() const
// away constness to compute the bounding box and modify the query geometry.
osg::OcclusionQueryNode* nonConstThis = const_cast<osg::OcclusionQueryNode*>( this );


ComputeBoundsVisitor cbv;
nonConstThis->accept( cbv );
BoundingBox bb = cbv.getBoundingBox();

OSG_DEBUG << "osgOQ: compute query bound:"
<< " min=(" << bb._min.x() << "," << bb._min.y() << "," << bb._min.z() << ")"
<< ", max=(" << bb._max.x() << "," << bb._max.y() << "," << bb._max.z() << ")"
<< std::endl;

nonConstThis->_validQueryGeometry = bb.valid();
OSG_DEBUG << "osgOQ: _validQueryGeometry=" << nonConstThis->_validQueryGeometry << std::endl;

osg::ref_ptr<Vec3Array> v = new Vec3Array;
v->resize( 8 );
(*v)[0] = Vec3( bb._min.x(), bb._min.y(), bb._min.z() );
(*v)[1] = Vec3( bb._max.x(), bb._min.y(), bb._min.z() );
(*v)[2] = Vec3( bb._max.x(), bb._min.y(), bb._max.z() );
(*v)[3] = Vec3( bb._min.x(), bb._min.y(), bb._max.z() );
(*v)[4] = Vec3( bb._max.x(), bb._max.y(), bb._min.z() );
(*v)[5] = Vec3( bb._min.x(), bb._max.y(), bb._min.z() );
(*v)[6] = Vec3( bb._min.x(), bb._max.y(), bb._max.z() );
(*v)[7] = Vec3( bb._max.x(), bb._max.y(), bb._max.z() );

// Having (0,0,0) as vertices for the case of the invalid query geometry
// still isn't quite the right thing. But the query geometry is public
// accessible and therefore a user might expect eight vertices, so
// it seems safer to keep eight vertices in the geometry.

if (nonConstThis->_validQueryGeometry)
{
(*v)[0] = Vec3( bb._min.x(), bb._min.y(), bb._min.z() );
(*v)[1] = Vec3( bb._max.x(), bb._min.y(), bb._min.z() );
(*v)[2] = Vec3( bb._max.x(), bb._min.y(), bb._max.z() );
(*v)[3] = Vec3( bb._min.x(), bb._min.y(), bb._max.z() );
(*v)[4] = Vec3( bb._max.x(), bb._max.y(), bb._min.z() );
(*v)[5] = Vec3( bb._min.x(), bb._max.y(), bb._min.z() );
(*v)[6] = Vec3( bb._min.x(), bb._max.y(), bb._max.z() );
(*v)[7] = Vec3( bb._max.x(), bb._max.y(), bb._max.z() );
}

Geometry* geom = static_cast< Geometry* >( nonConstThis->_queryGeode->getDrawable( 0 ) );
geom->setVertexArray( v.get() );
Expand All @@ -608,6 +678,8 @@ void OcclusionQueryNode::setQueriesEnabled( bool enable )

void OcclusionQueryNode::resetQueries()
{
OSG_DEBUG << "osgOQ: OcclusionQueryNode::resetQueries()" << std::endl;

OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _frameCountMutex );
_frameCountMap.clear();
}
Expand Down