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

Revision 1851, 11.2 kB (checked in by robert, 12 years ago)

Changed the '-c' commandline option to '-m' to avoid overlapp with -c
used for config files.

  • 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
10#include <osgDB/Registry>
11#include <osgDB/ReadFile>
12#include <osgDB/WriteFile>
13
14#include <osgGA/TrackballManipulator>
15#include <osgGA/FlightManipulator>
16#include <osgGA/DriveManipulator>
17
18#include <osgUtil/Optimizer>
19#include <osgUtil/IntersectVisitor>
20
21#include <osg/OccluderNode>
22#include <osg/Geometry>
23
24
25class OccluderEventHandler : public osgGA::GUIEventHandler
26{
27    public:
28   
29        OccluderEventHandler(osgUtil::SceneView* sceneview,osg::Group* rootnode):_sceneview(sceneview),_rootnode(rootnode) {}
30   
31        virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&);
32
33        virtual void accept(osgGA::GUIEventHandlerVisitor& v)
34        {
35            v.visit(*this);
36        }
37       
38        void addPoint(const osg::Vec3& pos);
39               
40        void endOccluder();
41       
42       
43        osg::ref_ptr<osgUtil::SceneView>        _sceneview;
44        osg::ref_ptr<osg::Group>                _rootnode;
45        osg::ref_ptr<osg::Group>                _occluders;
46        osg::ref_ptr<osg::ConvexPlanarOccluder> _convexPlanarOccluder;
47};
48
49bool OccluderEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&)
50{
51    switch(ea.getEventType())
52    {
53        case(osgGA::GUIEventAdapter::KEYDOWN):
54        {
55            if (ea.getKey()=='a')
56            {
57
58                float x = ea.getX();
59                float y = ea.getY();
60 
61                osg::Vec3 near_point,far_point;
62                if (!_sceneview->projectWindowXYIntoObject(x,ea.getYmax()-y,near_point,far_point))
63                {
64                     return true;
65                }
66
67                osg::ref_ptr<osg::LineSegment> lineSegment = new osg::LineSegment;
68                lineSegment->set(near_point,far_point);
69
70                osgUtil::IntersectVisitor iv;
71                iv.addLineSegment(lineSegment.get());
72
73                _rootnode->accept(iv);
74
75                if (iv.hits())
76                {
77               
78                    osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(lineSegment.get());
79                    if (!hitList.empty())
80                    {
81                   
82                        osgUtil::Hit& hit = hitList.front();
83                        addPoint(hit.getWorldIntersectPoint());
84                    }
85
86                }
87
88                return true;
89            }
90            else if (ea.getKey()=='e')
91            {
92                endOccluder();
93                return true;
94            }
95            else if (ea.getKey()=='O')
96            {
97                if (_occluders.valid())
98                {
99                    std::cout<<"saving occluders to 'saved_occluders.osg'"<<std::endl;
100                    osgDB::writeNodeFile(*_occluders,"saved_occluders.osg");
101                }
102                else
103                {
104                    std::cout<<"no occluders to save"<<std::endl;
105                }
106                return true;
107            }
108            return false;
109        }
110
111        default:
112            return false;
113    }
114}
115
116void OccluderEventHandler::addPoint(const osg::Vec3& pos)
117{
118    std::cout<<"add point "<<pos<<std::endl;
119   
120    if (!_convexPlanarOccluder.valid()) _convexPlanarOccluder = new osg::ConvexPlanarOccluder;
121   
122    osg::ConvexPlanarPolygon& occluder = _convexPlanarOccluder->getOccluder();
123    occluder.add(pos);
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                _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    // get details on keyboard and mouse bindings used by the viewer.
301    viewer.getUsage(*arguments.getApplicationUsage());
302
303    // if user request help write it out to cout.
304    if (arguments.read("-h") || arguments.read("--help"))
305    {
306        arguments.getApplicationUsage()->write(std::cout);
307        return 1;
308    }
309
310    // any option left unread are converted into errors to write out later.
311    arguments.reportRemainingOptionsAsUnrecognized();
312
313    // report any errors if they have occured when parsing the program aguments.
314    if (arguments.errors())
315    {
316        arguments.writeErrorMessages(std::cout);
317        return 1;
318    }
319
320    // load the nodes from the commandline arguments.
321    osg::Node* loadedmodel = osgDB::readNodeFiles(arguments);
322    if (!loadedmodel)
323    {
324        return 1;
325    }
326   
327    // run optimization over the scene graph
328    osgUtil::Optimizer optimzer;
329    optimzer.optimize(loadedmodel);
330
331    // add the occluders to the loaded model.
332    osg::ref_ptr<osg::Group> rootnode;
333   
334    if (manuallyCreateOccluders)
335    {
336        rootnode = new osg::Group;
337        rootnode->addChild(loadedmodel);
338    }
339    else   
340    {
341        rootnode = createOccludersAroundModel(loadedmodel);
342    }
343   
344     
345    // add a viewport to the viewer and attach the scene graph.
346    viewer.setSceneData( rootnode.get() );
347
348
349    // create the windows and run the threads.
350    viewer.realize();
351
352    if (manuallyCreateOccluders)
353    {
354        osgUtil::SceneView* sceneview = viewer.getSceneHandlerList()[0].get();
355   
356        viewer.getEventHandlerList().push_front(new OccluderEventHandler(sceneview,rootnode.get()));
357    }
358
359    while( !viewer.done() )
360    {
361        // wait for all cull and draw threads to complete.
362        viewer.sync();
363
364        // update the scene by traversing it with the the update visitor which will
365        // call all node update callbacks and animations.
366        viewer.update();
367         
368        // fire off the cull and draw traversals of the scene.
369        viewer.frame();
370       
371    }
372
373    viewer.sync();
374
375    return 0;
376}
Note: See TracBrowser for help on using the browser.