I have been postponing the occlusion for now. So far things seem to be working
alright. I have found all the intersections and made a geode to collect them
all, using storeGeode->containsDrawable(draws) to remove any duplicates.
But with the a file (that I'm not sure I can share, for copyright issues) that
I'm using that contains 4 chairs, it only seems to detect three of them.
However, when I draw single bounding boxes around items (by moving the camera
around and drawing a bounding box around the first item intersected with the
polytopeintersector), it will draw a box around each individual chair.
So that I can see what objects are being detected, I was thinking it might be
good to add multiple selection boxes of different colours, around every
drawable that intersected with the polytopevisitor. The selection box is a
matrixtransform on a geode, which gets moved and sized by the handler. But I
don't know how to make multiple selection boxes. Help?
I've added my code, which is a mishmash of example code stuck together. The
relevant code is in the keyhandler (search: KEY_F3).
Thank you,
Sterling
------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=49414#49414
/* OpenSceneGraph example, osganimate.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
// This exampl demonstrates use of OcclusionQueryNode.
//
// In general, you use OcclusionQueryNode by simply attaching a subgraph
// or subgraphs as children, and it performs an OpenGL oclusion query
// to determine whether to draw the subgraphs or not.
//
// You can manually insert OcclusionQueryNodes at strategic locations
// in your scene graph, or you can write a NodeVisitor to insert them
// automatically, as this example shows.
//
// Run this example with no command line arguments, and it creates
// a "stock scene" to show how OcclusionQueryNode can be used.
//
// Or, run this example with a model on the command line, and the
// example uses a NodeVisitor to try to find worthwhile locations
// for OcclusionQueryNodes in your the scene graph.
#include <osg/MatrixTransform>
#include <osg/ShapeDrawable>
#include <osg/NodeVisitor>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/StateSet>
#include <osg/StateAttribute>
#include <osg/PolygonMode>
#include <osg/ColorMask>
#include <osg/PolygonOffset>
#include <osg/Depth>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgUtil/Optimizer>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/StateSetManipulator>
#include <osg/OcclusionQueryNode>
#include <iostream>
#include <sstream>
// NodeVisitors and utility functions for OcclusionQueryNode
// Use this visitor to insert OcclusionQueryNodes (OQNs) in the
// visited subgraph. Only one OQN will test any particular node
// (no nesting). See also OcclusionQueryNonFlatVisitor.
class OcclusionQueryVisitor : public osg::NodeVisitor
{
public:
OcclusionQueryVisitor();
virtual ~OcclusionQueryVisitor();
// Specify the vertex count threshold for performing occlusion
// query tests. Nodes in the scene graph whose total child geometry
// contains fewer vertices than the specified threshold will
// never be tested, just drawn. (In fact, they will br treated as
// potential occluders and rendered first in front-to-back order.)
void setOccluderThreshold( int vertices );
int getOccluderThreshold() const;
virtual void apply( osg::OcclusionQueryNode& oqn );
virtual void apply( osg::Group& group );
virtual void apply( osg::Geode& geode );
protected:
void addOQN( osg::Node& node );
// When an OQR creates all OQNs and each OQN shares the same OQC,
// these methods are used to uniquely name all OQNs. Handy
// for debugging.
std::string getNextOQNName();
int getNameIdx() const { return _nameIdx; }
osg::ref_ptr<osg::StateSet> _state;
osg::ref_ptr<osg::StateSet> _debugState;
unsigned int _nameIdx;
int _occluderThreshold;
};
// Find all OQNs in the visited scene graph and set their visibility threshold.
class VisibilityThresholdVisitor : public osg::NodeVisitor
{
public:
VisibilityThresholdVisitor( unsigned int threshold=50 ) //5000
: osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ),
_visThreshold( threshold ) {}
virtual ~VisibilityThresholdVisitor() {}
virtual void apply( osg::OcclusionQueryNode& oqn );
protected:
unsigned int _visThreshold;
};
class InfoVisitor : public osg::NodeVisitor
{
public:
InfoVisitor() : _level(0)
{
setTraversalMode( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN );
}
std::string spaces()
{ return std::string(_level*2, ' '); }
void apply( osg::Node& node )
{
std::cout << spaces() << node.libraryName() << ":NODE:" <<
node.className() << " " << node.getName() << std::endl;
_level++;
traverse( node );
_level--;
}
void apply( osg::Geode& geode )
{
std::cout << spaces() << geode.libraryName() << ":GEODE:" <<
geode.className() << " " << geode.getName() << std::endl;
_level++;
for ( unsigned int i=0; i<geode.getNumDrawables(); ++i )
{
osg::Drawable* drawable = geode.getDrawable(i);
std::cout << spaces() << drawable->libraryName() << ":DRAWABLE:" <<
drawable->className() << " " << drawable->getName() << std::endl;
}
traverse( geode );
_level--;
}
protected:
unsigned int _level;
};
// Find all OQNs in the visited scene graph and set the number of frames
// between queries.
class QueryFrameCountVisitor : public osg::NodeVisitor
{
public:
QueryFrameCountVisitor( int count=5 )
: osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ),
_count( count ) {}
virtual ~QueryFrameCountVisitor() {}
virtual void apply( osg::OcclusionQueryNode& oqn );
protected:
unsigned int _count;
};
// Find all OQNs in the visited scene graph and enable or disable queries..
class EnableQueryVisitor : public osg::NodeVisitor
{
public:
EnableQueryVisitor( bool enable=true )
: osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ),
_enabled( enable ) {}
virtual ~EnableQueryVisitor() {}
virtual void apply( osg::OcclusionQueryNode& oqn );
protected:
bool _enabled;
};
// Find all OQNs in the visited scene graph and enable or disable the
// debug bounding volume display.
class DebugDisplayVisitor : public osg::NodeVisitor
{
public:
DebugDisplayVisitor( bool debug=true )
: osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ),
_debug( debug ) {}
virtual ~DebugDisplayVisitor() {}
virtual void apply( osg::OcclusionQueryNode& oqn );
protected:
bool _debug;
};
// Remove all OQNs from the visited scene graph.
class RemoveOcclusionQueryVisitor : public osg::NodeVisitor
{
public:
RemoveOcclusionQueryVisitor();
virtual ~RemoveOcclusionQueryVisitor();
virtual void apply( osg::OcclusionQueryNode& oqn );
protected:
};
// Gather statistics about OQN performance in the visited scene graph.
class StatisticsVisitor : public osg::NodeVisitor
{
public:
StatisticsVisitor( osg::NodeVisitor::TraversalMode
mode=osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN );
virtual ~StatisticsVisitor();
virtual void apply( osg::OcclusionQueryNode& oqn );
void reset();
unsigned int getNumOQNs() const;
unsigned int getNumPassed() const;
protected:
unsigned int _numOQNs;
unsigned int _numPassed;
};
unsigned int countGeometryVertices( osg::Geometry* geom )
{
if (!geom->getVertexArray())
return 0;
// TBD This will eventually iterate over the PrimitiveSets and total the
// number of vertices actually used. But for now, it just returns the
// size of the vertex array.
return geom->getVertexArray()->getNumElements();
}
class VertexCounter : public osg::NodeVisitor
{
public:
VertexCounter( int limit )
: osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ),
_limit( limit ),
_total( 0 ) {}
~VertexCounter() {}
int getTotal() { return _total; }
bool exceeded() const { return _total > _limit; }
void reset() { _total = 0; }
virtual void apply( osg::Node& node )
{
std::cout << "Node2" << std::endl;
// Check for early abort. If out total already exceeds the
// max number of vertices, no need to traverse further.
if (exceeded())
return;
traverse( node );
}
virtual void apply( osg::Geode& geode )
{
std::cout << "Geode2" << std::endl;
// Possible early abort.
if (exceeded())
return;
unsigned int i;
for( i = 0; i < geode.getNumDrawables(); i++ )
{
osg::Geometry* geom = dynamic_cast<osg::Geometry
*>(geode.getDrawable(i));
if( !geom )
continue;
_total += countGeometryVertices( geom );
if (_total > _limit)
break;
}
}
protected:
int _limit;
int _total;
};
OcclusionQueryVisitor::OcclusionQueryVisitor()
: osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ),
_nameIdx( 0 ),
_occluderThreshold( 5000 ) //5000
{
// Create a dummy OcclusionQueryNode just so we can get its state.
// We'll then share that state between all OQNs we add to the visited scene
graph.
osg::ref_ptr<osg::OcclusionQueryNode> oqn = new osg::OcclusionQueryNode;
_state = oqn->getQueryStateSet();
_debugState = oqn->getDebugStateSet();
}
OcclusionQueryVisitor::~OcclusionQueryVisitor()
{
osg::notify( osg::INFO ) <<
"osgOQ: OcclusionQueryVisitor: Added " << getNameIdx() <<
" OQNodes." << std::endl;
}
void
OcclusionQueryVisitor::setOccluderThreshold( int vertices )
{
_occluderThreshold = vertices;
}
int
OcclusionQueryVisitor::getOccluderThreshold() const
{
return _occluderThreshold;
}
void
OcclusionQueryVisitor::apply( osg::OcclusionQueryNode& oqn )
{
// A subgraph is already under osgOQ control.
// Don't traverse further.
std::cout << "Done." << std::endl;
return;
}
void
OcclusionQueryVisitor::apply( osg::Group& group )
{
std::cout << "GROUP" << std::endl;
if (group.getNumParents() == 0)
{
// Can't add an OQN above a root node.
traverse( group );
return;
}
int preTraverseOQNCount = getNameIdx();
traverse( group );
if (getNameIdx() > preTraverseOQNCount)
// A least one OQN was added below the current node.
// Don't add one here to avoid hierarchical nesting.
return;
// There are no OQNs below this group. If the vertex
// count exceeds the threshold, add an OQN here.
addOQN( group );
}
void
OcclusionQueryVisitor::apply( osg::Geode& geode )
{
std::cout << "GEODE" << std::endl;
if (geode.getNumParents() == 0)
{
// Can't add an OQN above a root node.
traverse( geode );
return;
}
addOQN( geode );
}
void
OcclusionQueryVisitor::addOQN( osg::Node& node )
{
std::cout << "addOQN" << std::endl;
VertexCounter vc( _occluderThreshold );
node.accept( vc );
if (vc.exceeded())
{
// Insert OQN(s) above this node.
unsigned int np = node.getNumParents();
while (np--)
{
osg::Group* parent = dynamic_cast<osg::Group*>( node.getParent( np
) );
if (parent != NULL)
{
osg::ref_ptr<osg::OcclusionQueryNode> oqn = new
osg::OcclusionQueryNode();
oqn->addChild( &node );
parent->replaceChild( &node, oqn.get() );
oqn->setName( getNextOQNName() );
// Set all OQNs to use the same query StateSets (instead of
multiple copies
// of the same StateSet) for efficiency.
oqn->setQueryStateSet( _state.get() );
oqn->setDebugStateSet( _debugState.get() );
}
}
}
}
std::string
OcclusionQueryVisitor::getNextOQNName()
{
std::ostringstream ostr;
ostr << "OQNode_" << _nameIdx++;
return ostr.str();
}
//
void
VisibilityThresholdVisitor::apply( osg::OcclusionQueryNode& oqn )
{
std::cout << "oqn??" << std::endl;
oqn.setVisibilityThreshold( _visThreshold );
traverse( oqn );
}
void
QueryFrameCountVisitor::apply( osg::OcclusionQueryNode& oqn )
{
std::cout << "oqn Frame" << std::endl;
oqn.setQueryFrameCount( _count );
traverse( oqn );
}
void
EnableQueryVisitor::apply( osg::OcclusionQueryNode& oqn )
{
std::cout << "Enable oqn" << std::endl;
oqn.setQueriesEnabled( _enabled );
traverse( oqn );
}
void
DebugDisplayVisitor::apply( osg::OcclusionQueryNode& oqn )
{
std::cout << "debugDisplay" << std::endl;
oqn.setDebugDisplay( _debug );
traverse( oqn );
}
RemoveOcclusionQueryVisitor::RemoveOcclusionQueryVisitor()
: osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN )
{
}
RemoveOcclusionQueryVisitor::~RemoveOcclusionQueryVisitor()
{
}
void
RemoveOcclusionQueryVisitor::apply( osg::OcclusionQueryNode& oqn )
{
if (oqn.getNumParents() == 0)
{
// Even if this is an OQN, can't delete it because it's the root.
traverse( oqn );
return;
}
osg::ref_ptr<osg::OcclusionQueryNode> oqnPtr = &oqn;
unsigned int np = oqn.getNumParents();
while (np--)
{
osg::Group* parent = dynamic_cast<osg::Group*>( oqn.getParent( np ) );
if (parent != NULL)
{
// Remove OQN from parent.
parent->removeChild( oqnPtr.get() );
// Add OQN's children to parent.
unsigned int nc = oqn.getNumChildren();
while (nc--)
parent->addChild( oqn.getChild( nc ) );
}
}
}
StatisticsVisitor::StatisticsVisitor( osg::NodeVisitor::TraversalMode mode )
: osg::NodeVisitor( mode ),
_numOQNs( 0 ),
_numPassed( 0 )
{
}
StatisticsVisitor::~StatisticsVisitor()
{
}
void
StatisticsVisitor::apply( osg::OcclusionQueryNode& oqn )
{
std::cout << "Statistics oqn" << oqn.getName() << std::endl;
_numOQNs++;
if (oqn.getPassed())
_numPassed++;
traverse( oqn );
}
void
StatisticsVisitor::reset()
{
_numOQNs = _numPassed = 0;
}
unsigned int
StatisticsVisitor::getNumOQNs() const
{
return _numOQNs;
}
unsigned int
StatisticsVisitor::getNumPassed() const
{
return _numPassed;
}
// End NodeVisitors
// KetHandler --
// Allow user to do interesting things with an
// OcclusionQueryNode-enabled scene graph at run time.
class KeyHandler : public osgGA::GUIEventHandler
{
public:
KeyHandler( osg::Node& node, osg::Camera& camera )
: _node( node ),
_camera( camera ),
_enable( true ),
_debug( false )
{}
osg::Node* getOrCreateSelectionBox()
{
if ( !_selectionBox )
{
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
osg::ref_ptr<osg::ShapeDrawable> sd = new
osg::ShapeDrawable(new osg::Box(osg::Vec3(), 1.0f));
geode->addDrawable(sd);
//geode->addDrawable(
// new osg::ShapeDrawable(new osg::Box(osg::Vec3(), 1.0f)) );
sd->setColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); // white
_selectionBox = new osg::MatrixTransform;
_selectionBox->setNodeMask( 0x1 );
_selectionBox->addChild( geode.get() );
osg::StateSet* ss = _selectionBox->getOrCreateStateSet();
ss->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
ss->setAttributeAndModes( new osg::PolygonMode(
osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE) );
}
return _selectionBox.get();
}
bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& )
{
switch( ea.getEventType() )
{
case(osgGA::GUIEventAdapter::KEYUP):
{
if (ea.getKey() ==
osgGA::GUIEventAdapter::KEY_F3)
{
//std::cout << "f3" << std::endl;
std::cout << "F3 pressed" << std::endl;
osg::ref_ptr<osgUtil::PolytopeIntersector> intersector = new
osgUtil::PolytopeIntersector(
osgUtil::PolytopeIntersector::WINDOW, 0, 0, 400, 400);//0,0,400,400
osgUtil::IntersectionVisitor iv(
intersector.get() );
_camera.accept(iv);
if (
intersector->containsIntersections())
{
std::cout << "ok." << std::endl;
osgUtil::PolytopeIntersector::Intersections& intersections =
intersector->getIntersections();
int count = 0;
osg::ref_ptr<osg::Geode>
storeGeode = new osg::Geode;
for(osgUtil::PolytopeIntersector::Intersections::iterator itr =
intersections.begin(); itr != intersections.end(); ++itr)
{
//std::cout <<
itr->distance;
osg::ref_ptr<osg::Drawable> drw = itr->drawable.get();
osg::ref_ptr<osg::Node>
nod = drw->getParent(0);
osg::ref_ptr<osg::Group> grp = nod->getParent(0);
osg::ref_ptr<osg::Geometry> geom = drw->asGeometry();
osg::ref_ptr<osg::Geode> geod = drw->getParent(0)->asGeode();
std::cout << "geode
name:" << geod->getName() << std::endl;
std::cout << "geom
name:" << geom->getName() << std::endl;
std::cout << "grp
name:" << grp->getName() << "grp class:" << grp->className() << std::endl;
std::cout << "drw
name:" << drw->getName() << " drw class:" << drw->className() << std::endl;
std::cout <<
nod->getName() << " libName:" << nod->libraryName() << " class:" <<
nod->className() << " NumDescriptions:"
<<
nod->getParent(0)->className() << std::endl;
std::cout <<
itr->distance << std::endl;
if
(storeGeode->containsDrawable(drw))
{
;//storeGeode->addDrawable(drw);
}
else
{
storeGeode->addDrawable(drw);
//geod->removeDrawable(drw);
//InfoVisitor
infVist;
//grp->accept(infVist);
}
//storeGeode->addDrawable(drw);
/*if
(storeGeode->containsDrawable(drw))
{
std::cout <<
"contains." << std::endl;
}
*/
//std::cout <<
geod->removeDrawable(drw);
//break;
osg::BoundingBox bb =
drw->getBound();// drw->getBound();
osg::Vec3 worldCenter =
bb.center() * osg::computeLocalToWorld(itr->nodePath);
_selectionBox->setMatrix(
osg::Matrix::scale(bb.xMax()-bb.xMin(), bb.yMax()-bb.yMin(),
bb.zMax()-bb.zMin()) *
osg::Matrix::translate(worldCenter) );
count++;
break;
}
std::cout << count << std::endl;
std::cout <<
storeGeode->getNumDrawables() << std::endl;
//InfoVisitor infoV;
//storeGeode->accept(infoV);
osg::Geode::DrawableList
drwList = storeGeode->getDrawableList();
/*for
(osg::Geode::DrawableList::iterator itr=drwList.begin(); itr<drwList.end();
itr++)
{
osg::ref_ptr<osg::Drawable> drw = itr->get();
osg::ref_ptr<osg::Node>
nod = drw->getParent(0);
osg::ref_ptr<osg::Group> grp = nod->getParent(0);
osg::ref_ptr<osg::Geometry> geom = drw->asGeometry();
//osg::ref_ptr<osg::Geode> geod = drw->getParent(0)->asGeode();
//std::cout << "geode
name:" << geod->getName() << std::endl;
std::cout << "geom
name:" << geom->getName() << std::endl;
std::cout << "grp
name:" << grp->getName() << "grp class:" << grp->className() << std::endl;
std::cout << "drw
name:" << drw->getName() << " drw class:" << drw->className() << std::endl;
std::cout <<
nod->getName() << " libName:" << nod->libraryName() << " class:" <<
nod->className() << " NumDescriptions:"
<<
nod->getParent(0)->className() << std::endl << std::endl;
//std::cout <<
itr->distance << std::endl;
}*/
}
}
if (ea.getKey() ==
osgGA::GUIEventAdapter::KEY_F4)
{
std::cout << "F4 pressed" << std::endl;
InfoVisitor infoVisitor;
_node.accept( infoVisitor );
}
if (ea.getKey() ==
osgGA::GUIEventAdapter::KEY_F5)
{
OcclusionQueryVisitor oqv;
_node.accept( oqv );
std::cout << "F5" << std::endl;
return true;
}
if (ea.getKey()==osgGA::GUIEventAdapter::KEY_F6)
{
// F6 -- Toggle osgOQ testing.
std::cout << "F6" << std::endl;
_enable = !_enable;
EnableQueryVisitor eqv( _enable );
_node.accept( eqv );
return true;
}
else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_F7)
{
// F7 -- Toggle display of OQ test bounding volumes
_debug = !_debug;
DebugDisplayVisitor ddv( _debug );
_node.accept( ddv );
return true;
}
else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_F8)
{
// F8 -- Gether stats and display
StatisticsVisitor sv;
_node.accept( sv );
std::cout << "osgOQ: Stats: numOQNs " << sv.getNumOQNs() <<
", numPased " << sv.getNumPassed() << std::endl;
return true;
}
else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_F9)
{
// F9 -- Remove all OcclusionQueryNodes
std::cout << "F9 - remove OQN" <<
std::endl;
RemoveOcclusionQueryVisitor roqv;
_node.accept( roqv );
return true;
}
else if (ea.getKey()=='o')
{
if (osgDB::writeNodeFile( _node, "saved_model.osgt" ))
osg::notify( osg::ALWAYS ) << "osgOQ: Wrote scene graph
to \"saved_model.osgt\"" << std::endl;
else
osg::notify( osg::ALWAYS ) << "osgOQ: Wrote failed for
\"saved_model.osgt\"" << std::endl;
return true;
}
return false;
}
default:
break;
}
return false;
}
osg::Node& _node;
osg::Camera& _camera;
//osg::Viewer& _viewer;
bool _enable, _debug;
protected:
osg::ref_ptr<osg::MatrixTransform> _selectionBox;
};
// Create a cube with one side missing. This makes a great simple occluder.
osg::ref_ptr<osg::Node>
createBox()
{
osg::ref_ptr<osg::Geode> box = new osg::Geode;
osg::StateSet* state = box->getOrCreateStateSet();
osg::PolygonMode* pm = new osg::PolygonMode(
osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL );
state->setAttributeAndModes( pm,
osg::StateAttribute::ON | osg::StateAttribute::PROTECTED );
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;
geom->setVertexArray( v.get() );
{
const float x( 0.f );
const float y( 0.f );
const float z( 0.f );
const float r( 1.1f );
v->push_back( osg::Vec3( x-r, y-r, z-r ) ); //left -X
v->push_back( osg::Vec3( x-r, y-r, z+r ) );
v->push_back( osg::Vec3( x-r, y+r, z+r ) );
v->push_back( osg::Vec3( x-r, y+r, z-r ) );
v->push_back( osg::Vec3( x+r, y-r, z+r ) ); //right +X
v->push_back( osg::Vec3( x+r, y-r, z-r ) );
v->push_back( osg::Vec3( x+r, y+r, z-r ) );
v->push_back( osg::Vec3( x+r, y+r, z+r ) );
v->push_back( osg::Vec3( x-r, y-r, z-r ) ); // bottom -Z
v->push_back( osg::Vec3( x-r, y+r, z-r ) );
v->push_back( osg::Vec3( x+r, y+r, z-r ) );
v->push_back( osg::Vec3( x+r, y-r, z-r ) );
v->push_back( osg::Vec3( x-r, y-r, z+r ) ); // top +Z
v->push_back( osg::Vec3( x+r, y-r, z+r ) );
v->push_back( osg::Vec3( x+r, y+r, z+r ) );
v->push_back( osg::Vec3( x-r, y+r, z+r ) );
v->push_back( osg::Vec3( x-r, y+r, z-r ) ); // back +Y
v->push_back( osg::Vec3( x-r, y+r, z+r ) );
v->push_back( osg::Vec3( x+r, y+r, z+r ) );
v->push_back( osg::Vec3( x+r, y+r, z-r ) );
}
osg::ref_ptr<osg::Vec4Array> c = new osg::Vec4Array;
geom->setColorArray( c.get() );
geom->setColorBinding( osg::Geometry::BIND_OVERALL );
c->push_back( osg::Vec4( 0.f, 1.f, 1.f, 1.f ) );
osg::ref_ptr<osg::Vec3Array> n = new osg::Vec3Array;
geom->setNormalArray( n.get() );
geom->setNormalBinding( osg::Geometry::BIND_PER_PRIMITIVE );
n->push_back( osg::Vec3( -1.f, 0.f, 0.f ) );
n->push_back( osg::Vec3( 1.f, 0.f, 0.f ) );
n->push_back( osg::Vec3( 0.f, 0.f, -1.f ) );
n->push_back( osg::Vec3( 0.f, 0.f, 1.f ) );
n->push_back( osg::Vec3( 0.f, 1.f, 0.f ) );
geom->addPrimitiveSet( new osg::DrawArrays( GL_QUADS, 0, 20 ) );
box->addDrawable( geom.get() );
return box.get();
}
// Make a Geometry that renders slow intentionally.
// To make sure it renders slow, we do the following:
// * Disable display lists
// * Force glBegin/glEnd slow path
// * Lots of vertices and color data per vertex
// * No vertex sharing
// * Draw the triangles as wireframe
osg::ref_ptr<osg::Node>
createRandomTriangles( unsigned int num )
{
osg::ref_ptr<osg::Geode> tris = new osg::Geode;
osg::StateSet* ss = tris->getOrCreateStateSet();
// Force wireframe. Many gfx cards handle this poorly.
osg::PolygonMode* pm = new osg::PolygonMode(
osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE );
ss->setAttributeAndModes( pm, osg::StateAttribute::ON |
osg::StateAttribute::PROTECTED);
ss->setMode( GL_LIGHTING, osg::StateAttribute::OFF |
osg::StateAttribute::PROTECTED);
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
// Disable display lists to decrease performance.
geom->setUseDisplayList( false );
osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;
geom->setVertexArray( v.get() );
v->resize( num*3 );
unsigned int i;
srand( 0 );
#define RAND_NEG1_TO_1 ( ((rand()%20)-10)*.1 )
for (i=0; i<num; i++)
{
osg::Vec3& v0 = (*v)[ i*3+0 ];
osg::Vec3& v1 = (*v)[ i*3+1 ];
osg::Vec3& v2 = (*v)[ i*3+2 ];
v0 = osg::Vec3( RAND_NEG1_TO_1, RAND_NEG1_TO_1, RAND_NEG1_TO_1 );
v1 = osg::Vec3( RAND_NEG1_TO_1, RAND_NEG1_TO_1, RAND_NEG1_TO_1 );
v2 = osg::Vec3( RAND_NEG1_TO_1, RAND_NEG1_TO_1, RAND_NEG1_TO_1 );
}
osg::ref_ptr<osg::Vec4Array> c = new osg::Vec4Array;
geom->setColorArray( c.get() );
// Bind per primitive to force slow glBegin/glEnd path.
geom->setColorBinding( osg::Geometry::BIND_PER_PRIMITIVE );
c->resize( num );
#define RAND_0_TO_1 ( (rand()%10)*.1 )
for (i=0; i<num; i++)
{
osg::Vec4& c0 = (*c)[ i ];
c0 = osg::Vec4( RAND_0_TO_1, RAND_0_TO_1, RAND_0_TO_1, 1. );
}
geom->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLES, 0, num*3 ) );
tris->addDrawable( geom.get() );
return tris.get();
}
// Create the stock scene:
// Top level Group
// Geode (simple occluder
// OcclusionQueryNode
// Geode with complex, slow geometry.
osg::ref_ptr<osg::Node>
createStockScene()
{
// Create a simple box occluder
osg::ref_ptr<osg::Group> root = new osg::Group();
root->addChild( createBox().get() );
// Create a complex mess of triangles as a child below an
// OcclusionQueryNode. The OQN will ensure that the
// subgraph isn't rendered when it's not visible.
osg::ref_ptr<osg::OcclusionQueryNode> oqn = new osg::OcclusionQueryNode;
oqn->addChild( createRandomTriangles( 20000 ).get() );
root->addChild( oqn.get() );
return root.get();
}
int main(int argc, char** argv)
{
// use an ArgumentParser object to manage the program arguments.
osg::ArgumentParser arguments(&argc,argv);
arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+"
demonstrates OpenGL occlusion query in OSG using the OcclusionQueryNode.");
arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+"
[options] [filename(s)]");
arguments.getApplicationUsage()->addCommandLineOption("-h or
--help","Display command line parameters");
// if user request help write it out to cout.
if (arguments.read("-h") || arguments.read("--help"))
{
arguments.getApplicationUsage()->write(std::cout,
osg::ApplicationUsage::COMMAND_LINE_OPTION);
return 1;
}
// report any errors if they have occurred when parsing the program
arguments.
if (arguments.errors())
{
arguments.writeErrorMessages(std::cout);
return 1;
}
osgViewer::Viewer viewer( arguments );
//osgViewer::Viewer viewer;
// add the state manipulator
viewer.addEventHandler( new
osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
// add the stats handler
viewer.addEventHandler(new osgViewer::StatsHandler);
// add the help handler
viewer.addEventHandler(new
osgViewer::HelpHandler(arguments.getApplicationUsage()));
bool optimize = arguments.read( "--opt" );
// load the specified model
/*osg::ref_ptr<osg::Node> model1 = osgDB::readNodeFile( "cessna.osg" );
osg::ref_ptr<osg::Node> model2 = osgDB::readNodeFile( "cow.osg" );
osg::ref_ptr<osg::Group> root = new osg::Group;
root->addChild( model1.get() );
root->addChild( model2.get() );*/
osg::ref_ptr<osg::Group> root = new osg::Group;
//osg::ref_ptr<osg::Node> root = 0;
if (arguments.argc()>1)
{
//root = osgDB::readNodeFiles( arguments );
osg::ref_ptr<osg::Node> ch = osgDB::readNodeFiles(arguments);
root->addChild(ch);
if (root.valid())
{
// Run a NodeVisitor to insert OcclusionQueryNodes in the scene
graph.
OcclusionQueryVisitor oqv;
root->accept( oqv );
}
else
{
std::cout << arguments.getApplicationName() <<": unable to load
specified data." << std::endl;
return 1;
}
}
else
{
//root = createStockScene().get();
if (!root)
{
std::cout << arguments.getApplicationName() <<": Failed to create
stock scene." << std::endl;
return 1;
}
}
// any option left unread are converted into errors to write out later.
arguments.reportRemainingOptionsAsUnrecognized();
// report any errors if they have occurred when parsing the program
arguments.
if (arguments.errors())
{
arguments.writeErrorMessages(std::cout);
return 1;
}
// optimize the scene graph, remove redundant nodes and state etc.
if (optimize)
{
osgUtil::Optimizer optimizer;
optimizer.optimize( root.get() );
}
viewer.setUpViewInWindow(500, 500, 500, 500, 0);
osg::ref_ptr<osg::Camera> camera = viewer.getCamera();
osg::ref_ptr<KeyHandler> keyhandler = new KeyHandler(*root, *camera);
root->addChild( keyhandler->getOrCreateSelectionBox() );
viewer.setSceneData( root.get() );
//keyhandler->getOrCreateSelectionBox();
//KeyHandler* kh = new KeyHandler( *root, *camera );
//kh->getOrCreateSelectionBox();
//viewer.setSceneData( root.get() );
viewer.addEventHandler( keyhandler.get() );
return viewer.run();
}
_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org