#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class OccluderEventHandler : public osgGA::GUIEventHandler { public: OccluderEventHandler(osgProducer::Viewer* viewer):_viewer(viewer) {} virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&); virtual void accept(osgGA::GUIEventHandlerVisitor& v) { v.visit(*this); } void addPoint(const osg::Vec3& pos); void endOccluder(); osg::Group* rootNode() { return dynamic_cast(_viewer->getSceneData()); } osgProducer::Viewer* _viewer; osg::ref_ptr _occluders; osg::ref_ptr _convexPlanarOccluder; }; bool OccluderEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&) { switch(ea.getEventType()) { case(osgGA::GUIEventAdapter::KEYDOWN): { if (ea.getKey()=='a') { float x = ea.getXnormalized(); float y = ea.getYnormalized(); osgUtil::IntersectVisitor::HitList hitList; if (!_viewer->computeIntersections(x,y,hitList)) { return true; } if (!hitList.empty()) { osgUtil::Hit& hit = hitList.front(); addPoint(hit.getWorldIntersectPoint()); } return true; } else if (ea.getKey()=='e') { endOccluder(); return true; } else if (ea.getKey()=='O') { if (_occluders.valid()) { if (osgDB::writeNodeFile(*_occluders,"saved_occluders.osg")) std::cout<<"saved occluders to 'saved_occluders.osg'"<getOccluder(); occluder.add(pos); // // osg::BoundingSphere bs = rootNode()->getBound(); // // osg::ShapeDrawable* sd = new osg::ShapeDrawable(new osg::Sphere(pos,bs.radius()*0.001f)); // osg::Geode* geode = new osg::Geode; // geode->addDrawable(sd); // // rootNode()->addChild(geode); // } void OccluderEventHandler::endOccluder() { if (_convexPlanarOccluder.valid()) { if (_convexPlanarOccluder->getOccluder().getVertexList().size()>=3) { osg::OccluderNode* occluderNode = new osg::OccluderNode; occluderNode->setOccluder(_convexPlanarOccluder.get()); if (!_occluders.valid()) { _occluders = new osg::Group; if (rootNode()) rootNode()->addChild(_occluders.get()); } _occluders->addChild(occluderNode); std::cout<<"created occluder"<setOccluder(cpo); occluderNode->setName("occluder"); // set the occluder up for the front face of the bounding box. osg::ConvexPlanarPolygon& occluder = cpo->getOccluder(); occluder.add(v1); occluder.add(v2); occluder.add(v3); occluder.add(v4); // create a whole at the center of the occluder if needed. if (holeRatio>0.0f) { // create hole. float ratio = holeRatio; float one_minus_ratio = 1-ratio; osg::Vec3 center = (v1+v2+v3+v4)*0.25f; osg::Vec3 v1dash = v1*ratio + center*one_minus_ratio; osg::Vec3 v2dash = v2*ratio + center*one_minus_ratio; osg::Vec3 v3dash = v3*ratio + center*one_minus_ratio; osg::Vec3 v4dash = v4*ratio + center*one_minus_ratio; osg::ConvexPlanarPolygon hole; hole.add(v1dash); hole.add(v2dash); hole.add(v3dash); hole.add(v4dash); cpo->addHole(hole); } // create a drawable for occluder. osg::Geometry* geom = new osg::Geometry; osg::Vec3Array* coords = new osg::Vec3Array(occluder.getVertexList().begin(),occluder.getVertexList().end()); geom->setVertexArray(coords); osg::Vec4Array* colors = new osg::Vec4Array(1); (*colors)[0].set(1.0f,1.0f,1.0f,0.5f); geom->setColorArray(colors); geom->setColorBinding(osg::Geometry::BIND_OVERALL); geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4)); osg::Geode* geode = new osg::Geode; geode->addDrawable(geom); osg::StateSet* stateset = new osg::StateSet; stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF); stateset->setMode(GL_BLEND,osg::StateAttribute::ON); stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); geom->setStateSet(stateset); // add the occluder geode as a child of the occluder, // as the occluder can't self occlude its subgraph the // geode will never be occluder by this occluder. occluderNode->addChild(geode); return occluderNode; } osg::Group* createOccludersAroundModel(osg::Node* model) { osg::Group* scene = new osg::Group; scene->setName("rootgroup"); // add the loaded model into a the scene group. scene->addChild(model); model->setName("model"); // get the bounding volume of the model. const osg::BoundingSphere bs = model->getBound(); // create a bounding box around the sphere. osg::BoundingBox bb; bb.expandBy(bs); // front scene->addChild(createOccluder(bb.corner(0), bb.corner(1), bb.corner(5), bb.corner(4))); // right side scene->addChild(createOccluder(bb.corner(1), bb.corner(3), bb.corner(7), bb.corner(5))); // left side scene->addChild(createOccluder(bb.corner(2), bb.corner(0), bb.corner(4), bb.corner(6))); // back side scene->addChild(createOccluder(bb.corner(3), bb.corner(2), bb.corner(6), bb.corner(7), 0.5f)); // create a hole half the size of the occluder. return scene; } int main( int argc, char **argv ) { // use an ArgumentParser object to manage the program arguments. osg::ArgumentParser arguments(&argc,argv); // set up the usage document, in case we need to print out how to use this program. arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates use of convex planer occluders."); arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ..."); arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information"); arguments.getApplicationUsage()->addCommandLineOption("-m","Mannually create occluders"); // initialize the viewer. osgProducer::Viewer viewer(arguments); // set up the value with sensible default event handlers. viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS); bool manuallyCreateOccluders = false; while (arguments.read("-m")) { manuallyCreateOccluders = true; } if (manuallyCreateOccluders) { viewer.getEventHandlerList().push_front(new OccluderEventHandler(&viewer)); } // get details on keyboard and mouse bindings used by the viewer. viewer.getUsage(*arguments.getApplicationUsage()); // if user request help write it out to cout. if (arguments.read("-h") || arguments.read("--help")) { arguments.getApplicationUsage()->write(std::cout); return 1; } // any option left unread are converted into errors to write out later. arguments.reportRemainingOptionsAsUnrecognized(); // report any errors if they have occured when parsing the program aguments. if (arguments.errors()) { arguments.writeErrorMessages(std::cout); return 1; } // load the nodes from the commandline arguments. osg::Node* loadedmodel = osgDB::readNodeFiles(arguments); if (!loadedmodel) { return 1; } // run optimization over the scene graph osgUtil::Optimizer optimzer; optimzer.optimize(loadedmodel); // add the occluders to the loaded model. osg::ref_ptr rootnode; if (manuallyCreateOccluders) { rootnode = new osg::Group; rootnode->addChild(loadedmodel); } else { rootnode = createOccludersAroundModel(loadedmodel); } // add a viewport to the viewer and attach the scene graph. viewer.setSceneData( rootnode.get() ); // create the windows and run the threads. viewer.realize(); while( !viewer.done() ) { // wait for all cull and draw threads to complete. viewer.sync(); // update the scene by traversing it with the the update visitor which will // call all node update callbacks and animations. viewer.update(); // fire off the cull and draw traversals of the scene. viewer.frame(); } viewer.sync(); return 0; }