OcclusionQueryNode: fix use case of user defined query geometry
The user defined query geometry handling has been broken in several ways. The previous way of defining a query geometry was using the non const `getQueryGeometry` method and overriding its members. But then `OcclusionQueryNode` wasn't aware of the geometry change and couldn't internally handle it correctly. The `computeBound` method never considered a user defined query geometry and always just overrode the vertices of the geometry. The member `_validQueryGeometry` wasn't correctly set. This change should fix all this issues by introducing a small backward compatibility break. The non const `getQueryGeometry` method is removed forcing the user to use the `setQueryGeometry` method. But then `OcclusionQueryNode` is aware of the user defined query geometry and can handle it correctly.
This commit is contained in:
parent
8fb5ba4a3f
commit
817d92b703
@ -82,9 +82,9 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** return a QueryResult for specified Camera, where the QueryResult.valid is true when query results are available, and in which case the QueryResult.numPixels provides the num of pixels in the query result.*/
|
/** return a QueryResult for specified Camera, where the QueryResult.valid is true when query results are available, and in which case the QueryResult.numPixels provides the num of pixels in the query result.*/
|
||||||
QueryResult getQueryResult( const osg::Camera* cam );
|
QueryResult getQueryResult( const osg::Camera* cam ) const;
|
||||||
|
|
||||||
unsigned int getNumPixels( const osg::Camera* cam );
|
unsigned int getNumPixels( const osg::Camera* cam ) const;
|
||||||
|
|
||||||
virtual void releaseGLObjects( osg::State* state = 0 ) const;
|
virtual void releaseGLObjects( osg::State* state = 0 ) const;
|
||||||
|
|
||||||
@ -158,8 +158,11 @@ public:
|
|||||||
osg::StateSet* getQueryStateSet();
|
osg::StateSet* getQueryStateSet();
|
||||||
const osg::StateSet* getQueryStateSet() const;
|
const osg::StateSet* getQueryStateSet() const;
|
||||||
|
|
||||||
// Get the QueryGeometry object used for occlusion query. Returns 0 if no QueryGeometry is created.
|
// Set and get the QueryGeometry object used for the occlusion query.
|
||||||
osg::QueryGeometry* getQueryGeometry();
|
// By default an axis aligned box is used as the query geometry.
|
||||||
|
// Resetting to the default query geometry is done by setting it to 0.
|
||||||
|
// Returns 0 if no QueryGeometry is created.
|
||||||
|
void setQueryGeometry( osg::QueryGeometry* geom );
|
||||||
const osg::QueryGeometry* getQueryGeometry() const;
|
const osg::QueryGeometry* getQueryGeometry() const;
|
||||||
|
|
||||||
// Set and get the StateSet used by the OcclusionQueryNode
|
// Set and get the StateSet used by the OcclusionQueryNode
|
||||||
@ -189,17 +192,28 @@ public:
|
|||||||
static void discardDeletedQueryObjects( unsigned int contextID );
|
static void discardDeletedQueryObjects( unsigned int contextID );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
enum QueryGeometryState {
|
||||||
|
INVALID,
|
||||||
|
VALID,
|
||||||
|
USER_DEFINED
|
||||||
|
};
|
||||||
|
|
||||||
virtual ~OcclusionQueryNode();
|
virtual ~OcclusionQueryNode();
|
||||||
|
|
||||||
virtual void createSupportNodes();
|
virtual void createSupportNodes();
|
||||||
|
|
||||||
|
bool isQueryGeometryValid() const { return _queryGeometryState != INVALID; }
|
||||||
|
|
||||||
|
void setQueryGeometryInternal( osg::QueryGeometry* queryGeom,
|
||||||
|
osg::Geometry* debugQueryGeom,
|
||||||
|
QueryGeometryState state );
|
||||||
|
|
||||||
osg::ref_ptr< osg::Geode > _queryGeode;
|
osg::ref_ptr< osg::Geode > _queryGeode;
|
||||||
osg::ref_ptr< osg::Geode > _debugGeode;
|
osg::ref_ptr< osg::Geode > _debugGeode;
|
||||||
|
|
||||||
bool _enabled;
|
bool _enabled;
|
||||||
|
|
||||||
// If the box of the query geometry is valid.
|
mutable QueryGeometryState _queryGeometryState;
|
||||||
mutable bool _validQueryGeometry;
|
|
||||||
|
|
||||||
// Tracks the last frame number that we performed a query.
|
// Tracks the last frame number that we performed a query.
|
||||||
// User can set how many times (See setQueryFrameCount).
|
// User can set how many times (See setQueryFrameCount).
|
||||||
|
@ -48,6 +48,36 @@
|
|||||||
namespace osg
|
namespace osg
|
||||||
{
|
{
|
||||||
|
|
||||||
|
QueryGeometry* createDefaultQueryGeometry( const std::string& name )
|
||||||
|
{
|
||||||
|
GLushort indices[] = { 0, 1, 2, 3, 4, 5, 6, 7,
|
||||||
|
0, 3, 6, 5, 2, 1, 4, 7,
|
||||||
|
5, 4, 1, 0, 2, 7, 6, 3 };
|
||||||
|
|
||||||
|
ref_ptr<QueryGeometry> geom = new QueryGeometry( name );
|
||||||
|
geom->setDataVariance( Object::DYNAMIC );
|
||||||
|
geom->addPrimitiveSet( new DrawElementsUShort( PrimitiveSet::QUADS, 24, indices ) );
|
||||||
|
|
||||||
|
return geom.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
Geometry* createDefaultDebugQueryGeometry()
|
||||||
|
{
|
||||||
|
GLushort indices[] = { 0, 1, 2, 3, 4, 5, 6, 7,
|
||||||
|
0, 3, 6, 5, 2, 1, 4, 7,
|
||||||
|
5, 4, 1, 0, 2, 7, 6, 3 };
|
||||||
|
|
||||||
|
ref_ptr<Vec4Array> ca = new Vec4Array;
|
||||||
|
ca->push_back( Vec4( 1.f, 1.f, 1.f, 1.f ) );
|
||||||
|
|
||||||
|
ref_ptr<Geometry> geom = new Geometry;
|
||||||
|
geom->setDataVariance( Object::DYNAMIC );
|
||||||
|
geom->setColorArray( ca.get(), Array::BIND_OVERALL );
|
||||||
|
geom->addPrimitiveSet( new DrawElementsUShort( PrimitiveSet::QUADS, 24, indices ) );
|
||||||
|
|
||||||
|
return geom.release();
|
||||||
|
}
|
||||||
|
|
||||||
// Create and return a StateSet appropriate for performing an occlusion
|
// Create and return a StateSet appropriate for performing an occlusion
|
||||||
// query test (disable lighting, texture mapping, etc). Probably some
|
// query test (disable lighting, texture mapping, etc). Probably some
|
||||||
// room for improvement here. Could disable shaders, for example.
|
// room for improvement here. Could disable shaders, for example.
|
||||||
@ -364,7 +394,7 @@ QueryGeometry::drawImplementation( osg::RenderInfo& renderInfo ) const
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QueryGeometry::QueryResult QueryGeometry::getQueryResult( const osg::Camera* cam )
|
QueryGeometry::QueryResult QueryGeometry::getQueryResult( const osg::Camera* cam ) const
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::TestResult> tr;
|
osg::ref_ptr<osg::TestResult> tr;
|
||||||
{
|
{
|
||||||
@ -380,7 +410,7 @@ QueryGeometry::QueryResult QueryGeometry::getQueryResult( const osg::Camera* cam
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
QueryGeometry::getNumPixels( const osg::Camera* cam )
|
QueryGeometry::getNumPixels( const osg::Camera* cam ) const
|
||||||
{
|
{
|
||||||
return getQueryResult(cam).numPixels;
|
return getQueryResult(cam).numPixels;
|
||||||
}
|
}
|
||||||
@ -442,7 +472,7 @@ QueryGeometry::discardDeletedQueryObjects( unsigned int contextID )
|
|||||||
|
|
||||||
OcclusionQueryNode::OcclusionQueryNode()
|
OcclusionQueryNode::OcclusionQueryNode()
|
||||||
: _enabled( true ),
|
: _enabled( true ),
|
||||||
_validQueryGeometry( false ),
|
_queryGeometryState( INVALID ),
|
||||||
_passed(false),
|
_passed(false),
|
||||||
_visThreshold( 500 ),
|
_visThreshold( 500 ),
|
||||||
_queryFrameCount( 5 ),
|
_queryFrameCount( 5 ),
|
||||||
@ -460,7 +490,7 @@ OcclusionQueryNode::~OcclusionQueryNode()
|
|||||||
|
|
||||||
OcclusionQueryNode::OcclusionQueryNode( const OcclusionQueryNode& oqn, const CopyOp& copyop )
|
OcclusionQueryNode::OcclusionQueryNode( const OcclusionQueryNode& oqn, const CopyOp& copyop )
|
||||||
: Group( oqn, copyop ),
|
: Group( oqn, copyop ),
|
||||||
_validQueryGeometry( false ),
|
_queryGeometryState( INVALID ),
|
||||||
_passed( false )
|
_passed( false )
|
||||||
{
|
{
|
||||||
_enabled = oqn._enabled;
|
_enabled = oqn._enabled;
|
||||||
@ -485,7 +515,7 @@ bool OcclusionQueryNode::getPassed( const Camera* camera, NodeVisitor& nv )
|
|||||||
|
|
||||||
QueryGeometry* qg = static_cast< QueryGeometry* >( _queryGeode->getDrawable( 0 ) );
|
QueryGeometry* qg = static_cast< QueryGeometry* >( _queryGeode->getDrawable( 0 ) );
|
||||||
|
|
||||||
if ( !_validQueryGeometry )
|
if ( !isQueryGeometryValid() )
|
||||||
{
|
{
|
||||||
// There're cases that the occlusion test result has been retrieved
|
// There're cases that the occlusion test result has been retrieved
|
||||||
// after the query geometry has been changed, it's the result of the
|
// after the query geometry has been changed, it's the result of the
|
||||||
@ -556,7 +586,7 @@ bool OcclusionQueryNode::getPassed( const Camera* camera, NodeVisitor& nv )
|
|||||||
|
|
||||||
void OcclusionQueryNode::traverseQuery( const Camera* camera, NodeVisitor& nv )
|
void OcclusionQueryNode::traverseQuery( const Camera* camera, NodeVisitor& nv )
|
||||||
{
|
{
|
||||||
if (!_validQueryGeometry || ! _enabled)
|
if (!isQueryGeometryValid() || ! _enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool issueQuery;
|
bool issueQuery;
|
||||||
@ -590,6 +620,8 @@ BoundingSphere OcclusionQueryNode::computeBound() const
|
|||||||
// an application thread or by a non-osgViewer application.
|
// an application thread or by a non-osgViewer application.
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _computeBoundMutex ) ;
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _computeBoundMutex ) ;
|
||||||
|
|
||||||
|
if (_queryGeometryState != USER_DEFINED)
|
||||||
|
{
|
||||||
// This is the logical place to put this code, but the method is const. Cast
|
// This is the logical place to put this code, but the method is const. Cast
|
||||||
// away constness to compute the bounding box and modify the query geometry.
|
// away constness to compute the bounding box and modify the query geometry.
|
||||||
osg::OcclusionQueryNode* nonConstThis = const_cast<osg::OcclusionQueryNode*>( this );
|
osg::OcclusionQueryNode* nonConstThis = const_cast<osg::OcclusionQueryNode*>( this );
|
||||||
@ -599,7 +631,7 @@ BoundingSphere OcclusionQueryNode::computeBound() const
|
|||||||
nonConstThis->accept( cbv );
|
nonConstThis->accept( cbv );
|
||||||
BoundingBox bb = cbv.getBoundingBox();
|
BoundingBox bb = cbv.getBoundingBox();
|
||||||
const bool bbValid = bb.valid();
|
const bool bbValid = bb.valid();
|
||||||
_validQueryGeometry = bbValid;
|
_queryGeometryState = bbValid ? VALID : INVALID;
|
||||||
|
|
||||||
osg::ref_ptr<Vec3Array> v = new Vec3Array;
|
osg::ref_ptr<Vec3Array> v = new Vec3Array;
|
||||||
v->resize( 8 );
|
v->resize( 8 );
|
||||||
@ -627,6 +659,7 @@ BoundingSphere OcclusionQueryNode::computeBound() const
|
|||||||
geom = static_cast< osg::Geometry* >( nonConstThis->_debugGeode->getDrawable( 0 ) );
|
geom = static_cast< osg::Geometry* >( nonConstThis->_debugGeode->getDrawable( 0 ) );
|
||||||
geom->setVertexArray( v.get() );
|
geom->setVertexArray( v.get() );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Group::computeBound();
|
return Group::computeBound();
|
||||||
}
|
}
|
||||||
@ -723,21 +756,12 @@ bool OcclusionQueryNode::getPassed() const
|
|||||||
|
|
||||||
void OcclusionQueryNode::createSupportNodes()
|
void OcclusionQueryNode::createSupportNodes()
|
||||||
{
|
{
|
||||||
GLushort indices[] = { 0, 1, 2, 3, 4, 5, 6, 7,
|
|
||||||
0, 3, 6, 5, 2, 1, 4, 7,
|
|
||||||
5, 4, 1, 0, 2, 7, 6, 3 };
|
|
||||||
|
|
||||||
{
|
{
|
||||||
// Add the test geometry Geode
|
// Add the test geometry Geode
|
||||||
_queryGeode = new Geode;
|
_queryGeode = new Geode;
|
||||||
_queryGeode->setName( "OQTest" );
|
_queryGeode->setName( "OQTest" );
|
||||||
_queryGeode->setDataVariance( Object::DYNAMIC );
|
_queryGeode->setDataVariance( Object::DYNAMIC );
|
||||||
|
_queryGeode->addDrawable( createDefaultQueryGeometry( getName() ) );
|
||||||
ref_ptr< QueryGeometry > geom = new QueryGeometry( getName() );
|
|
||||||
geom->setDataVariance( Object::DYNAMIC );
|
|
||||||
geom->addPrimitiveSet( new DrawElementsUShort( PrimitiveSet::QUADS, 24, indices ) );
|
|
||||||
|
|
||||||
_queryGeode->addDrawable( geom.get() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -746,17 +770,7 @@ void OcclusionQueryNode::createSupportNodes()
|
|||||||
_debugGeode = new Geode;
|
_debugGeode = new Geode;
|
||||||
_debugGeode->setName( "Debug" );
|
_debugGeode->setName( "Debug" );
|
||||||
_debugGeode->setDataVariance( Object::DYNAMIC );
|
_debugGeode->setDataVariance( Object::DYNAMIC );
|
||||||
|
_debugGeode->addDrawable( createDefaultDebugQueryGeometry() );
|
||||||
ref_ptr<Geometry> geom = new Geometry;
|
|
||||||
geom->setDataVariance( Object::DYNAMIC );
|
|
||||||
|
|
||||||
ref_ptr<Vec4Array> ca = new Vec4Array;
|
|
||||||
ca->push_back( Vec4( 1.f, 1.f, 1.f, 1.f ) );
|
|
||||||
geom->setColorArray( ca.get(), Array::BIND_OVERALL );
|
|
||||||
|
|
||||||
geom->addPrimitiveSet( new DrawElementsUShort( PrimitiveSet::QUADS, 24, indices ) );
|
|
||||||
|
|
||||||
_debugGeode->addDrawable( geom.get() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creste state sets. Note that the osgOQ visitors (which place OQNs throughout
|
// Creste state sets. Note that the osgOQ visitors (which place OQNs throughout
|
||||||
@ -767,6 +781,28 @@ void OcclusionQueryNode::createSupportNodes()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void OcclusionQueryNode::setQueryGeometryInternal( QueryGeometry* queryGeom,
|
||||||
|
Geometry* debugQueryGeom,
|
||||||
|
QueryGeometryState state )
|
||||||
|
{
|
||||||
|
if (!queryGeom || !debugQueryGeom)
|
||||||
|
{
|
||||||
|
OSG_FATAL << "osgOQ: OcclusionQueryNode: No QueryGeometry." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _computeBoundMutex ) ;
|
||||||
|
|
||||||
|
_queryGeometryState = state;
|
||||||
|
|
||||||
|
_queryGeode->removeDrawables(0, _queryGeode->getNumDrawables());
|
||||||
|
_queryGeode->addDrawable(queryGeom);
|
||||||
|
|
||||||
|
_debugGeode->removeDrawables(0, _debugGeode->getNumDrawables());
|
||||||
|
_debugGeode->addDrawable(debugQueryGeom);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void OcclusionQueryNode::releaseGLObjects( State* state ) const
|
void OcclusionQueryNode::releaseGLObjects( State* state ) const
|
||||||
{
|
{
|
||||||
if (_queryGeode.valid()) _queryGeode->releaseGLObjects(state);
|
if (_queryGeode.valid()) _queryGeode->releaseGLObjects(state);
|
||||||
@ -787,14 +823,18 @@ void OcclusionQueryNode::discardDeletedQueryObjects( unsigned int contextID )
|
|||||||
QueryGeometry::discardDeletedQueryObjects( contextID );
|
QueryGeometry::discardDeletedQueryObjects( contextID );
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::QueryGeometry* OcclusionQueryNode::getQueryGeometry()
|
void OcclusionQueryNode::setQueryGeometry( QueryGeometry* geom )
|
||||||
{
|
{
|
||||||
if (_queryGeode && _queryGeode->getDrawable( 0 ))
|
if (geom)
|
||||||
{
|
{
|
||||||
QueryGeometry* qg = static_cast< QueryGeometry* >( _queryGeode->getDrawable( 0 ) );
|
setQueryGeometryInternal( geom, geom, USER_DEFINED );
|
||||||
return qg;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setQueryGeometryInternal( createDefaultQueryGeometry( getName() ),
|
||||||
|
createDefaultDebugQueryGeometry(),
|
||||||
|
INVALID);
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const osg::QueryGeometry* OcclusionQueryNode::getQueryGeometry() const
|
const osg::QueryGeometry* OcclusionQueryNode::getQueryGeometry() const
|
||||||
|
Loading…
Reference in New Issue
Block a user