From 19cf8b46c317af49c5195efb49c0d144b321a7f3 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sat, 26 Jan 2019 16:33:23 +0000 Subject: [PATCH 1/7] Introduced a QueryGeometry::getQueryResult(const osg::Camera*) method as a more informative replacedment for QueryGeometry::getNumPixels(). --- src/osg/OcclusionQueryNode.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/osg/OcclusionQueryNode.cpp b/src/osg/OcclusionQueryNode.cpp index b6222acb7..e0f736ef8 100644 --- a/src/osg/OcclusionQueryNode.cpp +++ b/src/osg/OcclusionQueryNode.cpp @@ -544,8 +544,7 @@ 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. - _passed = true; - return _passed; + return true; } _passed = ( result.numPixels > _visThreshold ); From c64b94da2ee341f5e52a614eb46075d3e41067a7 Mon Sep 17 00:00:00 2001 From: Daniel Trstenjak Date: Fri, 25 Jan 2019 15:02:45 +0100 Subject: [PATCH 2/7] OcclusionQueryNode: ensure a consistent value for '_passed' --- src/osg/OcclusionQueryNode.cpp | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/osg/OcclusionQueryNode.cpp b/src/osg/OcclusionQueryNode.cpp index e0f736ef8..915dcdb82 100644 --- a/src/osg/OcclusionQueryNode.cpp +++ b/src/osg/OcclusionQueryNode.cpp @@ -483,21 +483,6 @@ bool OcclusionQueryNode::getPassed( const Camera* camera, NodeVisitor& nv ) 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 false to not traverse - // the subgraphs. - _passed = false; - return _passed; - } - { // Two situations where we want to simply do a regular traversal: // 1) it's the first frame for this camera @@ -520,6 +505,7 @@ 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; @@ -544,7 +530,8 @@ 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. - return true; + _passed = true; + return _passed; } _passed = ( result.numPixels > _visThreshold ); From 3ef5d2b3313fd9f8cb60a3f6230bf38687a6ccc5 Mon Sep 17 00:00:00 2001 From: Daniel Trstenjak Date: Tue, 29 Jan 2019 11:37:28 +0100 Subject: [PATCH 3/7] OcclusionQueryNode: ensure a valid query geometry If the query geometry is invalid then don't do any occlusion queries and never traverse the subgraphs. --- src/osg/OcclusionQueryNode.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/osg/OcclusionQueryNode.cpp b/src/osg/OcclusionQueryNode.cpp index 915dcdb82..8acf40084 100644 --- a/src/osg/OcclusionQueryNode.cpp +++ b/src/osg/OcclusionQueryNode.cpp @@ -483,6 +483,14 @@ bool OcclusionQueryNode::getPassed( const Camera* camera, NodeVisitor& nv ) return _passed; } + if ( !_validQueryGeometry ) + { + // The box of the query geometry is invalid, return false to not traverse + // the subgraphs. + _passed = false; + return _passed; + } + { // Two situations where we want to simply do a regular traversal: // 1) it's the first frame for this camera From 8fb5ba4a3f2a33fd0a133c7b3c6e181b2b1f058a Mon Sep 17 00:00:00 2001 From: Daniel Trstenjak Date: Tue, 29 Jan 2019 14:40:16 +0100 Subject: [PATCH 4/7] OcclusionQueryNode: reset the test result of the invalid geometry 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. --- src/osg/OcclusionQueryNode.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/osg/OcclusionQueryNode.cpp b/src/osg/OcclusionQueryNode.cpp index 8acf40084..b6222acb7 100644 --- a/src/osg/OcclusionQueryNode.cpp +++ b/src/osg/OcclusionQueryNode.cpp @@ -483,8 +483,15 @@ bool OcclusionQueryNode::getPassed( const Camera* camera, NodeVisitor& nv ) 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 false to not traverse // the subgraphs. _passed = false; @@ -513,7 +520,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; From 817d92b70347337e1f3eca5b094bba510e1210a4 Mon Sep 17 00:00:00 2001 From: Daniel Trstenjak Date: Wed, 14 Aug 2019 11:27:40 +0200 Subject: [PATCH 5/7] 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. --- include/osg/OcclusionQueryNode | 26 +++-- src/osg/OcclusionQueryNode.cpp | 172 ++++++++++++++++++++------------- 2 files changed, 126 insertions(+), 72 deletions(-) diff --git a/include/osg/OcclusionQueryNode b/include/osg/OcclusionQueryNode index f2fb2c229..1bb87ff53 100644 --- a/include/osg/OcclusionQueryNode +++ b/include/osg/OcclusionQueryNode @@ -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.*/ - 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; @@ -158,8 +158,11 @@ public: osg::StateSet* getQueryStateSet(); const osg::StateSet* getQueryStateSet() const; - // Get the QueryGeometry object used for occlusion query. Returns 0 if no QueryGeometry is created. - osg::QueryGeometry* getQueryGeometry(); + // Set and get the QueryGeometry object used for the occlusion query. + // 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; // Set and get the StateSet used by the OcclusionQueryNode @@ -189,17 +192,28 @@ public: static void discardDeletedQueryObjects( unsigned int contextID ); protected: + enum QueryGeometryState { + INVALID, + VALID, + USER_DEFINED + }; + virtual ~OcclusionQueryNode(); 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 > _debugGeode; bool _enabled; - // If the box of the query geometry is valid. - mutable bool _validQueryGeometry; + mutable QueryGeometryState _queryGeometryState; // Tracks the last frame number that we performed a query. // User can set how many times (See setQueryFrameCount). diff --git a/src/osg/OcclusionQueryNode.cpp b/src/osg/OcclusionQueryNode.cpp index b6222acb7..b3cdee6ba 100644 --- a/src/osg/OcclusionQueryNode.cpp +++ b/src/osg/OcclusionQueryNode.cpp @@ -48,6 +48,36 @@ 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 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 ca = new Vec4Array; + ca->push_back( Vec4( 1.f, 1.f, 1.f, 1.f ) ); + + ref_ptr 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 // query test (disable lighting, texture mapping, etc). Probably some // 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 tr; { @@ -380,7 +410,7 @@ QueryGeometry::QueryResult QueryGeometry::getQueryResult( const osg::Camera* cam } unsigned int -QueryGeometry::getNumPixels( const osg::Camera* cam ) +QueryGeometry::getNumPixels( const osg::Camera* cam ) const { return getQueryResult(cam).numPixels; } @@ -442,7 +472,7 @@ QueryGeometry::discardDeletedQueryObjects( unsigned int contextID ) OcclusionQueryNode::OcclusionQueryNode() : _enabled( true ), - _validQueryGeometry( false ), + _queryGeometryState( INVALID ), _passed(false), _visThreshold( 500 ), _queryFrameCount( 5 ), @@ -460,7 +490,7 @@ OcclusionQueryNode::~OcclusionQueryNode() OcclusionQueryNode::OcclusionQueryNode( const OcclusionQueryNode& oqn, const CopyOp& copyop ) : Group( oqn, copyop ), - _validQueryGeometry( false ), + _queryGeometryState( INVALID ), _passed( false ) { _enabled = oqn._enabled; @@ -485,7 +515,7 @@ bool OcclusionQueryNode::getPassed( const Camera* camera, NodeVisitor& nv ) QueryGeometry* qg = static_cast< QueryGeometry* >( _queryGeode->getDrawable( 0 ) ); - if ( !_validQueryGeometry ) + if ( !isQueryGeometryValid() ) { // There're cases that the occlusion test result has been retrieved // 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 ) { - if (!_validQueryGeometry || ! _enabled) + if (!isQueryGeometryValid() || ! _enabled) return; bool issueQuery; @@ -590,42 +620,45 @@ BoundingSphere OcclusionQueryNode::computeBound() const // an application thread or by a non-osgViewer application. OpenThreads::ScopedLock lock( _computeBoundMutex ) ; - // 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. - osg::OcclusionQueryNode* nonConstThis = const_cast( this ); - - - ComputeBoundsVisitor cbv; - nonConstThis->accept( cbv ); - BoundingBox bb = cbv.getBoundingBox(); - const bool bbValid = bb.valid(); - _validQueryGeometry = bbValid; - - osg::ref_ptr v = new Vec3Array; - v->resize( 8 ); - - // 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 (bbValid) + if (_queryGeometryState != USER_DEFINED) { - (*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() ); + // 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. + osg::OcclusionQueryNode* nonConstThis = const_cast( this ); + + + ComputeBoundsVisitor cbv; + nonConstThis->accept( cbv ); + BoundingBox bb = cbv.getBoundingBox(); + const bool bbValid = bb.valid(); + _queryGeometryState = bbValid ? VALID : INVALID; + + osg::ref_ptr v = new Vec3Array; + v->resize( 8 ); + + // 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 (bbValid) + { + (*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() ); + + geom = static_cast< osg::Geometry* >( nonConstThis->_debugGeode->getDrawable( 0 ) ); + geom->setVertexArray( v.get() ); } - - Geometry* geom = static_cast< Geometry* >( nonConstThis->_queryGeode->getDrawable( 0 ) ); - geom->setVertexArray( v.get() ); - - geom = static_cast< osg::Geometry* >( nonConstThis->_debugGeode->getDrawable( 0 ) ); - geom->setVertexArray( v.get() ); } return Group::computeBound(); @@ -723,21 +756,12 @@ bool OcclusionQueryNode::getPassed() const 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 _queryGeode = new Geode; _queryGeode->setName( "OQTest" ); _queryGeode->setDataVariance( Object::DYNAMIC ); - - ref_ptr< QueryGeometry > geom = new QueryGeometry( getName() ); - geom->setDataVariance( Object::DYNAMIC ); - geom->addPrimitiveSet( new DrawElementsUShort( PrimitiveSet::QUADS, 24, indices ) ); - - _queryGeode->addDrawable( geom.get() ); + _queryGeode->addDrawable( createDefaultQueryGeometry( getName() ) ); } { @@ -746,17 +770,7 @@ void OcclusionQueryNode::createSupportNodes() _debugGeode = new Geode; _debugGeode->setName( "Debug" ); _debugGeode->setDataVariance( Object::DYNAMIC ); - - ref_ptr geom = new Geometry; - geom->setDataVariance( Object::DYNAMIC ); - - ref_ptr 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() ); + _debugGeode->addDrawable( createDefaultDebugQueryGeometry() ); } // 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 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 { if (_queryGeode.valid()) _queryGeode->releaseGLObjects(state); @@ -787,14 +823,18 @@ void OcclusionQueryNode::discardDeletedQueryObjects( unsigned int 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 ) ); - return qg; + setQueryGeometryInternal( geom, geom, USER_DEFINED ); + } + else + { + setQueryGeometryInternal( createDefaultQueryGeometry( getName() ), + createDefaultDebugQueryGeometry(), + INVALID); } - return 0; } const osg::QueryGeometry* OcclusionQueryNode::getQueryGeometry() const From ddb72691bcc60ba34137369e61f93c56976c763b Mon Sep 17 00:00:00 2001 From: Daniel Trstenjak Date: Fri, 23 Aug 2019 09:46:02 +0200 Subject: [PATCH 6/7] OcclusionQueryNode: fix resetting to default query geometry When the query geometry gets reset to its default then its vertices have to be updated by the bounding box dimensions of the current children of the OcclusionQueryNode. --- include/osg/OcclusionQueryNode | 2 + src/osg/OcclusionQueryNode.cpp | 79 ++++++++++++++++++++-------------- 2 files changed, 48 insertions(+), 33 deletions(-) diff --git a/include/osg/OcclusionQueryNode b/include/osg/OcclusionQueryNode index 1bb87ff53..9d8ebabc3 100644 --- a/include/osg/OcclusionQueryNode +++ b/include/osg/OcclusionQueryNode @@ -208,6 +208,8 @@ protected: osg::Geometry* debugQueryGeom, QueryGeometryState state ); + void updateDefaultQueryGeometry(); + osg::ref_ptr< osg::Geode > _queryGeode; osg::ref_ptr< osg::Geode > _debugGeode; diff --git a/src/osg/OcclusionQueryNode.cpp b/src/osg/OcclusionQueryNode.cpp index b3cdee6ba..6fd2a3123 100644 --- a/src/osg/OcclusionQueryNode.cpp +++ b/src/osg/OcclusionQueryNode.cpp @@ -625,39 +625,7 @@ BoundingSphere OcclusionQueryNode::computeBound() const // 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. osg::OcclusionQueryNode* nonConstThis = const_cast( this ); - - - ComputeBoundsVisitor cbv; - nonConstThis->accept( cbv ); - BoundingBox bb = cbv.getBoundingBox(); - const bool bbValid = bb.valid(); - _queryGeometryState = bbValid ? VALID : INVALID; - - osg::ref_ptr v = new Vec3Array; - v->resize( 8 ); - - // 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 (bbValid) - { - (*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() ); - - geom = static_cast< osg::Geometry* >( nonConstThis->_debugGeode->getDrawable( 0 ) ); - geom->setVertexArray( v.get() ); + nonConstThis->updateDefaultQueryGeometry(); } } @@ -803,6 +771,49 @@ void OcclusionQueryNode::setQueryGeometryInternal( QueryGeometry* queryGeom, } +void OcclusionQueryNode::updateDefaultQueryGeometry() +{ + if (_queryGeometryState == USER_DEFINED) + { + OSG_FATAL << "osgOQ: OcclusionQueryNode: Unexpected QueryGeometryState=USER_DEFINED." << std::endl; + return; + } + + ComputeBoundsVisitor cbv; + accept( cbv ); + + BoundingBox bb = cbv.getBoundingBox(); + const bool bbValid = bb.valid(); + _queryGeometryState = bbValid ? VALID : INVALID; + + osg::ref_ptr v = new Vec3Array; + v->resize( 8 ); + + // 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 (bbValid) + { + (*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* >( _queryGeode->getDrawable( 0 ) ); + geom->setVertexArray( v.get() ); + + geom = static_cast< osg::Geometry* >( _debugGeode->getDrawable( 0 ) ); + geom->setVertexArray( v.get() ); +} + + void OcclusionQueryNode::releaseGLObjects( State* state ) const { if (_queryGeode.valid()) _queryGeode->releaseGLObjects(state); @@ -834,6 +845,8 @@ void OcclusionQueryNode::setQueryGeometry( QueryGeometry* geom ) setQueryGeometryInternal( createDefaultQueryGeometry( getName() ), createDefaultDebugQueryGeometry(), INVALID); + + updateDefaultQueryGeometry(); } } From 995e849e8afdf99c5274d5e7f7dad0351eb1c9bd Mon Sep 17 00:00:00 2001 From: Daniel Trstenjak Date: Fri, 23 Aug 2019 09:59:54 +0200 Subject: [PATCH 7/7] OcclusionQueryNode: make all usages of 'updateDefaultQueryGeometry' thread safe --- src/osg/OcclusionQueryNode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/osg/OcclusionQueryNode.cpp b/src/osg/OcclusionQueryNode.cpp index 6fd2a3123..6be23a5f5 100644 --- a/src/osg/OcclusionQueryNode.cpp +++ b/src/osg/OcclusionQueryNode.cpp @@ -759,8 +759,6 @@ void OcclusionQueryNode::setQueryGeometryInternal( QueryGeometry* queryGeom, return; } - OpenThreads::ScopedLock lock( _computeBoundMutex ) ; - _queryGeometryState = state; _queryGeode->removeDrawables(0, _queryGeode->getNumDrawables()); @@ -836,6 +834,8 @@ void OcclusionQueryNode::discardDeletedQueryObjects( unsigned int contextID ) void OcclusionQueryNode::setQueryGeometry( QueryGeometry* geom ) { + OpenThreads::ScopedLock lock( _computeBoundMutex ) ; + if (geom) { setQueryGeometryInternal( geom, geom, USER_DEFINED );