root/OpenSceneGraph/trunk/examples/osgoccluder/osgoccluder.cpp @ 3995

Revision 3995, 10.9 kB (checked in by robert, 9 years ago)

Added #include <osg/io_utils>

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <osgProducer/Viewer>
2
3#include <osg/MatrixTransform>
4#include <osg/Billboard>
5#include <osg/Geode>
6#include <osg/Group>
7#include <osg/Notify>
8#include <osg/LineSegment>
9#include <osg/io_utils>
10
11#include <osgDB/Registry>
12#include <osgDB/ReadFile>
13#include <osgDB/WriteFile>
14
15#include <osgGA/TrackballManipulator>
16#include <osgGA/FlightManipulator>
17#include <osgGA/DriveManipulator>
18
19#include <osgUtil/Optimizer>
20#include <osgUtil/IntersectVisitor>
21
22#include <osg/OccluderNode>
23#include <osg/Geometry>
24#include <osg/ShapeDrawable>
25
26
27class OccluderEventHandler : public osgGA::GUIEventHandler
28{
29    public:
30   
31        OccluderEventHandler(osgProducer::Viewer* viewer):_viewer(viewer) {}
32   
33        virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&);
34
35        virtual void accept(osgGA::GUIEventHandlerVisitor& v)
36        {
37            v.visit(*this);
38        }
39       
40        void addPoint(const osg::Vec3& pos);
41               
42        void endOccluder();
43       
44        osg::Group* rootNode() { return dynamic_cast<osg::Group*>(_viewer->getSceneData()); }
45       
46       
47        osgProducer::Viewer*                    _viewer;
48        osg::ref_ptr<osg::Group>                _occluders;
49        osg::ref_ptr<osg::ConvexPlanarOccluder> _convexPlanarOccluder;
50};
51
52bool OccluderEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&)
53{
54    switch(ea.getEventType())
55    {
56        case(osgGA::GUIEventAdapter::KEYDOWN):
57        {
58            if (ea.getKey()=='a')
59            {
60
61                float x = ea.getXnormalized();
62                float y = ea.getYnormalized();
63 
64                osgUtil::IntersectVisitor::HitList hitList;
65                if (!_viewer->computeIntersections(x,y,hitList))
66                {
67                     return true;
68                }
69
70                if (!hitList.empty())
71                {
72
73                    osgUtil::Hit& hit = hitList.front();
74                    addPoint(hit.getWorldIntersectPoint());
75                }
76
77                return true;
78            }
79            else if (ea.getKey()=='e')
80            {
81                endOccluder();
82                return true;
83            }
84            else if (ea.getKey()=='O')
85            {
86                if (_occluders.valid())
87                {
88                   
89                    if (osgDB::writeNodeFile(*_occluders,"saved_occluders.osg"))
90                        std::cout<<"saved occluders to 'saved_occluders.osg'"<<std::endl;
91                }
92                else
93                {
94                    std::cout<<"no occluders to save"<<std::endl;
95                }
96                return true;
97            }
98            return false;
99        }
100
101        default:
102            return false;
103    }
104}
105
106void OccluderEventHandler::addPoint(const osg::Vec3& pos)
107{
108    std::cout<<"add point "<<pos<<std::endl;
109   
110    if (!_convexPlanarOccluder.valid()) _convexPlanarOccluder = new osg::ConvexPlanarOccluder;
111   
112    osg::ConvexPlanarPolygon& occluder = _convexPlanarOccluder->getOccluder();
113    occluder.add(pos);
114
115//     
116//     osg::BoundingSphere bs = rootNode()->getBound();
117//
118//     osg::ShapeDrawable* sd = new osg::ShapeDrawable(new osg::Sphere(pos,bs.radius()*0.001f));
119//     osg::Geode* geode = new osg::Geode;
120//     geode->addDrawable(sd);
121//
122//     rootNode()->addChild(geode);
123//
124   
125}
126               
127void OccluderEventHandler::endOccluder()
128{
129    if (_convexPlanarOccluder.valid())
130    {
131        if (_convexPlanarOccluder->getOccluder().getVertexList().size()>=3)
132        {
133            osg::OccluderNode* occluderNode = new osg::OccluderNode;
134            occluderNode->setOccluder(_convexPlanarOccluder.get());
135
136            if (!_occluders.valid())
137            {
138                _occluders = new osg::Group;
139                if (rootNode()) rootNode()->addChild(_occluders.get());
140            }
141            _occluders->addChild(occluderNode);
142
143            std::cout<<"created occluder"<<std::endl;
144        }
145        else
146        {
147            std::cout<<"Occluder requires at least 3 points to create occluder."<<std::endl;
148        }
149    }
150    else
151    {
152        std::cout<<"No occluder points to create occluder with."<<std::endl;
153    }
154   
155    // reset current occluder.
156    _convexPlanarOccluder = NULL;
157}
158
159
160osg::Node* createOccluder(const osg::Vec3& v1,const osg::Vec3& v2,const osg::Vec3& v3,const osg::Vec3& v4,float holeRatio=-1.0f)
161{
162   // create and occluder which will site along side the loadmodel model.
163    osg::OccluderNode* occluderNode = new osg::OccluderNode;
164
165    // create the convex planer occluder
166    osg::ConvexPlanarOccluder* cpo = new osg::ConvexPlanarOccluder;
167
168    // attach it to the occluder node.
169    occluderNode->setOccluder(cpo);
170    occluderNode->setName("occluder");
171   
172    // set the occluder up for the front face of the bounding box.
173    osg::ConvexPlanarPolygon& occluder = cpo->getOccluder();
174    occluder.add(v1);
175    occluder.add(v2);
176    occluder.add(v3);
177    occluder.add(v4);
178
179    // create a whole at the center of the occluder if needed.
180    if (holeRatio>0.0f)
181    {
182        // create hole.
183        float ratio = holeRatio;
184        float one_minus_ratio = 1-ratio;
185        osg::Vec3 center = (v1+v2+v3+v4)*0.25f;
186        osg::Vec3 v1dash = v1*ratio + center*one_minus_ratio;
187        osg::Vec3 v2dash = v2*ratio + center*one_minus_ratio;
188        osg::Vec3 v3dash = v3*ratio + center*one_minus_ratio;
189        osg::Vec3 v4dash = v4*ratio + center*one_minus_ratio;
190
191        osg::ConvexPlanarPolygon hole;
192        hole.add(v1dash);
193        hole.add(v2dash);
194        hole.add(v3dash);
195        hole.add(v4dash);
196
197        cpo->addHole(hole);
198    }   
199   
200
201   // create a drawable for occluder.
202    osg::Geometry* geom = new osg::Geometry;
203   
204    osg::Vec3Array* coords = new osg::Vec3Array(occluder.getVertexList().begin(),occluder.getVertexList().end());
205    geom->setVertexArray(coords);
206   
207    osg::Vec4Array* colors = new osg::Vec4Array(1);
208    (*colors)[0].set(1.0f,1.0f,1.0f,0.5f);
209    geom->setColorArray(colors);
210    geom->setColorBinding(osg::Geometry::BIND_OVERALL);
211   
212    geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));
213   
214    osg::Geode* geode = new osg::Geode;
215    geode->addDrawable(geom);
216   
217    osg::StateSet* stateset = new osg::StateSet;
218    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
219    stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
220    stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
221   
222    geom->setStateSet(stateset);
223   
224    // add the occluder geode as a child of the occluder,
225    // as the occluder can't self occlude its subgraph the
226    // geode will never be occluder by this occluder.
227    occluderNode->addChild(geode);   
228   
229    return occluderNode;
230 
231 }
232
233osg::Group* createOccludersAroundModel(osg::Node* model)
234{
235    osg::Group* scene = new osg::Group;
236    scene->setName("rootgroup");
237
238
239    // add the loaded model into a the scene group.
240    scene->addChild(model);
241    model->setName("model");
242
243    // get the bounding volume of the model.
244    const osg::BoundingSphere bs = model->getBound();
245   
246    // create a bounding box around the sphere.
247    osg::BoundingBox bb;
248    bb.expandBy(bs);
249
250   // front
251   scene->addChild(createOccluder(bb.corner(0),
252                                  bb.corner(1),
253                                  bb.corner(5),
254                                  bb.corner(4)));
255
256   // right side
257   scene->addChild(createOccluder(bb.corner(1),
258                                  bb.corner(3),
259                                  bb.corner(7),
260                                  bb.corner(5)));
261
262   // left side
263   scene->addChild(createOccluder(bb.corner(2),
264                                  bb.corner(0),
265                                  bb.corner(4),
266                                  bb.corner(6)));
267
268   // back side
269   scene->addChild(createOccluder(bb.corner(3),
270                                  bb.corner(2),
271                                  bb.corner(6),
272                                  bb.corner(7),
273                                  0.5f)); // create a hole half the size of the occluder.
274
275    return scene;
276}
277
278
279int main( int argc, char **argv )
280{
281
282    // use an ArgumentParser object to manage the program arguments.
283    osg::ArgumentParser arguments(&argc,argv);
284
285    // set up the usage document, in case we need to print out how to use this program.
286    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates use of convex planer occluders.");
287    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
288    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
289    arguments.getApplicationUsage()->addCommandLineOption("-m","Mannually create occluders");
290   
291    // initialize the viewer.
292    osgProducer::Viewer viewer(arguments);
293
294    // set up the value with sensible default event handlers.
295    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
296
297    bool manuallyCreateOccluders = false;
298    while (arguments.read("-m")) { manuallyCreateOccluders = true; }
299
300    if (manuallyCreateOccluders)
301    {
302        viewer.getEventHandlerList().push_front(new OccluderEventHandler(&viewer));
303    }
304
305    // get details on keyboard and mouse bindings used by the viewer.
306    viewer.getUsage(*arguments.getApplicationUsage());
307
308    // if user request help write it out to cout.
309    if (arguments.read("-h") || arguments.read("--help"))
310    {
311        arguments.getApplicationUsage()->write(std::cout);
312        return 1;
313    }
314
315    // any option left unread are converted into errors to write out later.
316    arguments.reportRemainingOptionsAsUnrecognized();
317
318    // report any errors if they have occured when parsing the program aguments.
319    if (arguments.errors())
320    {
321        arguments.writeErrorMessages(std::cout);
322        return 1;
323    }
324
325    // load the nodes from the commandline arguments.
326    osg::Node* loadedmodel = osgDB::readNodeFiles(arguments);
327    if (!loadedmodel)
328    {
329        return 1;
330    }
331   
332    // run optimization over the scene graph
333    osgUtil::Optimizer optimzer;
334    optimzer.optimize(loadedmodel);
335
336    // add the occluders to the loaded model.
337    osg::ref_ptr<osg::Group> rootnode;
338   
339    if (manuallyCreateOccluders)
340    {
341        rootnode = new osg::Group;
342        rootnode->addChild(loadedmodel);
343    }
344    else   
345    {
346        rootnode = createOccludersAroundModel(loadedmodel);
347    }
348   
349     
350    // add a viewport to the viewer and attach the scene graph.
351    viewer.setSceneData( rootnode.get() );
352
353
354    // create the windows and run the threads.
355    viewer.realize();
356
357
358    while( !viewer.done() )
359    {
360        // wait for all cull and draw threads to complete.
361        viewer.sync();
362
363        // update the scene by traversing it with the the update visitor which will
364        // call all node update callbacks and animations.
365        viewer.update();
366         
367        // fire off the cull and draw traversals of the scene.
368        viewer.frame();
369       
370    }
371
372    viewer.sync();
373
374    return 0;
375}
Note: See TracBrowser for help on using the browser.