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

Revision 6941, 11.1 kB (checked in by robert, 7 years ago)

From Martin Lavery and Robert Osfield, Updated examples to use a variation of the MIT License

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* OpenSceneGraph example, osgoccluder.
2*
3*  Permission is hereby granted, free of charge, to any person obtaining a copy
4*  of this software and associated documentation files (the "Software"), to deal
5*  in the Software without restriction, including without limitation the rights
6*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7*  copies of the Software, and to permit persons to whom the Software is
8*  furnished to do so, subject to the following conditions:
9*
10*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16*  THE SOFTWARE.
17*/
18
19#include <osgViewer/Viewer>
20
21#include <osg/MatrixTransform>
22#include <osg/Billboard>
23#include <osg/Geode>
24#include <osg/Group>
25#include <osg/Notify>
26#include <osg/LineSegment>
27#include <osg/io_utils>
28
29#include <osgDB/Registry>
30#include <osgDB/ReadFile>
31#include <osgDB/WriteFile>
32
33#include <osgGA/TrackballManipulator>
34#include <osgGA/FlightManipulator>
35#include <osgGA/DriveManipulator>
36
37#include <osgUtil/Optimizer>
38#include <osgUtil/IntersectVisitor>
39
40#include <osg/OccluderNode>
41#include <osg/Geometry>
42#include <osg/ShapeDrawable>
43
44#include <iostream>
45
46class OccluderEventHandler : public osgGA::GUIEventHandler
47{
48    public:
49   
50        OccluderEventHandler(osgViewer::Viewer* viewer):_viewer(viewer) {}
51   
52        virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&);
53
54        void addPoint(const osg::Vec3& pos);
55               
56        void endOccluder();
57       
58        osg::Group* rootNode() { return dynamic_cast<osg::Group*>(_viewer->getSceneData()); }
59       
60       
61        osgViewer::Viewer*                    _viewer;
62        osg::ref_ptr<osg::Group>                _occluders;
63        osg::ref_ptr<osg::ConvexPlanarOccluder> _convexPlanarOccluder;
64};
65
66bool OccluderEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa)
67{
68    switch(ea.getEventType())
69    {
70        case(osgGA::GUIEventAdapter::KEYDOWN):
71        {
72            if (ea.getKey()=='a')
73
74            {
75                osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
76                osgUtil::LineSegmentIntersector::Intersections intersections;
77                if (view && view->computeIntersections(ea.getX(), ea.getY(), intersections))
78                {
79                    const osgUtil::LineSegmentIntersector::Intersection& hit = *(intersections.begin());
80                    if (hit.matrix.valid()) addPoint(hit.localIntersectionPoint * (*hit.matrix));
81                    else addPoint(hit.localIntersectionPoint);
82                }
83
84                return true;
85            }
86            else if (ea.getKey()=='e')
87            {
88                endOccluder();
89                return true;
90            }
91            else if (ea.getKey()=='O')
92            {
93                if (_occluders.valid())
94                {
95                   
96                    if (osgDB::writeNodeFile(*_occluders,"saved_occluders.osg"))
97                        std::cout<<"saved occluders to 'saved_occluders.osg'"<<std::endl;
98                }
99                else
100                {
101                    std::cout<<"no occluders to save"<<std::endl;
102                }
103                return true;
104            }
105            return false;
106        }
107
108        default:
109            return false;
110    }
111}
112
113void OccluderEventHandler::addPoint(const osg::Vec3& pos)
114{
115    std::cout<<"add point "<<pos<<std::endl;
116   
117    if (!_convexPlanarOccluder.valid()) _convexPlanarOccluder = new osg::ConvexPlanarOccluder;
118   
119    osg::ConvexPlanarPolygon& occluder = _convexPlanarOccluder->getOccluder();
120    occluder.add(pos);
121
122//     
123//     osg::BoundingSphere bs = rootNode()->getBound();
124//
125//     osg::ShapeDrawable* sd = new osg::ShapeDrawable(new osg::Sphere(pos,bs.radius()*0.001f));
126//     osg::Geode* geode = new osg::Geode;
127//     geode->addDrawable(sd);
128//
129//     rootNode()->addChild(geode);
130//
131   
132}
133               
134void OccluderEventHandler::endOccluder()
135{
136    if (_convexPlanarOccluder.valid())
137    {
138        if (_convexPlanarOccluder->getOccluder().getVertexList().size()>=3)
139        {
140            osg::OccluderNode* occluderNode = new osg::OccluderNode;
141            occluderNode->setOccluder(_convexPlanarOccluder.get());
142
143            if (!_occluders.valid())
144            {
145                _occluders = new osg::Group;
146                if (rootNode()) rootNode()->addChild(_occluders.get());
147            }
148            _occluders->addChild(occluderNode);
149
150            std::cout<<"created occluder"<<std::endl;
151        }
152        else
153        {
154            std::cout<<"Occluder requires at least 3 points to create occluder."<<std::endl;
155        }
156    }
157    else
158    {
159        std::cout<<"No occluder points to create occluder with."<<std::endl;
160    }
161   
162    // reset current occluder.
163    _convexPlanarOccluder = NULL;
164}
165
166
167osg::Node* createOccluder(const osg::Vec3& v1,const osg::Vec3& v2,const osg::Vec3& v3,const osg::Vec3& v4,float holeRatio=-1.0f)
168{
169   // create and occluder which will site along side the loadmodel model.
170    osg::OccluderNode* occluderNode = new osg::OccluderNode;
171
172    // create the convex planer occluder
173    osg::ConvexPlanarOccluder* cpo = new osg::ConvexPlanarOccluder;
174
175    // attach it to the occluder node.
176    occluderNode->setOccluder(cpo);
177    occluderNode->setName("occluder");
178   
179    // set the occluder up for the front face of the bounding box.
180    osg::ConvexPlanarPolygon& occluder = cpo->getOccluder();
181    occluder.add(v1);
182    occluder.add(v2);
183    occluder.add(v3);
184    occluder.add(v4);
185
186    // create a whole at the center of the occluder if needed.
187    if (holeRatio>0.0f)
188    {
189        // create hole.
190        float ratio = holeRatio;
191        float one_minus_ratio = 1-ratio;
192        osg::Vec3 center = (v1+v2+v3+v4)*0.25f;
193        osg::Vec3 v1dash = v1*ratio + center*one_minus_ratio;
194        osg::Vec3 v2dash = v2*ratio + center*one_minus_ratio;
195        osg::Vec3 v3dash = v3*ratio + center*one_minus_ratio;
196        osg::Vec3 v4dash = v4*ratio + center*one_minus_ratio;
197
198        osg::ConvexPlanarPolygon hole;
199        hole.add(v1dash);
200        hole.add(v2dash);
201        hole.add(v3dash);
202        hole.add(v4dash);
203
204        cpo->addHole(hole);
205    }   
206   
207
208   // create a drawable for occluder.
209    osg::Geometry* geom = new osg::Geometry;
210   
211    osg::Vec3Array* coords = new osg::Vec3Array(occluder.getVertexList().begin(),occluder.getVertexList().end());
212    geom->setVertexArray(coords);
213   
214    osg::Vec4Array* colors = new osg::Vec4Array(1);
215    (*colors)[0].set(1.0f,1.0f,1.0f,0.5f);
216    geom->setColorArray(colors);
217    geom->setColorBinding(osg::Geometry::BIND_OVERALL);
218   
219    geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));
220   
221    osg::Geode* geode = new osg::Geode;
222    geode->addDrawable(geom);
223   
224    osg::StateSet* stateset = new osg::StateSet;
225    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
226    stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
227    stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
228   
229    geom->setStateSet(stateset);
230   
231    // add the occluder geode as a child of the occluder,
232    // as the occluder can't self occlude its subgraph the
233    // geode will never be occluder by this occluder.
234    occluderNode->addChild(geode);   
235   
236    return occluderNode;
237 
238 }
239
240osg::Group* createOccludersAroundModel(osg::Node* model)
241{
242    osg::Group* scene = new osg::Group;
243    scene->setName("rootgroup");
244
245
246    // add the loaded model into a the scene group.
247    scene->addChild(model);
248    model->setName("model");
249
250    // get the bounding volume of the model.
251    const osg::BoundingSphere bs = model->getBound();
252   
253    // create a bounding box around the sphere.
254    osg::BoundingBox bb;
255    bb.expandBy(bs);
256
257   // front
258   scene->addChild(createOccluder(bb.corner(0),
259                                  bb.corner(1),
260                                  bb.corner(5),
261                                  bb.corner(4)));
262
263   // right side
264   scene->addChild(createOccluder(bb.corner(1),
265                                  bb.corner(3),
266                                  bb.corner(7),
267                                  bb.corner(5)));
268
269   // left side
270   scene->addChild(createOccluder(bb.corner(2),
271                                  bb.corner(0),
272                                  bb.corner(4),
273                                  bb.corner(6)));
274
275   // back side
276   scene->addChild(createOccluder(bb.corner(3),
277                                  bb.corner(2),
278                                  bb.corner(6),
279                                  bb.corner(7),
280                                  0.5f)); // create a hole half the size of the occluder.
281
282    return scene;
283}
284
285
286int main( int argc, char **argv )
287{
288
289    // use an ArgumentParser object to manage the program arguments.
290    osg::ArgumentParser arguments(&argc,argv);
291
292    // set up the usage document, in case we need to print out how to use this program.
293    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates use of convex planer occluders.");
294    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
295    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
296    arguments.getApplicationUsage()->addCommandLineOption("-m","Mannually create occluders");
297   
298    // initialize the viewer.
299    osgViewer::Viewer viewer;
300
301    bool manuallyCreateOccluders = false;
302    while (arguments.read("-m")) { manuallyCreateOccluders = true; }
303
304    if (manuallyCreateOccluders)
305    {
306        viewer.addEventHandler(new OccluderEventHandler(&viewer));
307    }
308
309    // if user request help write it out to cout.
310    if (arguments.read("-h") || arguments.read("--help"))
311    {
312        arguments.getApplicationUsage()->write(std::cout);
313        return 1;
314    }
315
316    // load the nodes from the commandline arguments.
317    osg::Node* loadedmodel = osgDB::readNodeFiles(arguments);
318   
319    // if not loaded assume no arguments passed in, try use default mode instead.
320    if (!loadedmodel) loadedmodel = osgDB::readNodeFile("glider.osg");
321   
322    if (!loadedmodel)
323    {
324        osg::notify(osg::NOTICE)<<"Please sepecify and model filename on the command line."<<std::endl;
325        return 1;
326    }
327   
328    // run optimization over the scene graph
329    osgUtil::Optimizer optimzer;
330    optimzer.optimize(loadedmodel);
331
332    // add the occluders to the loaded model.
333    osg::ref_ptr<osg::Group> rootnode;
334   
335    if (manuallyCreateOccluders)
336    {
337        rootnode = new osg::Group;
338        rootnode->addChild(loadedmodel);
339    }
340    else   
341    {
342        rootnode = createOccludersAroundModel(loadedmodel);
343    }
344   
345     
346    // add a viewport to the viewer and attach the scene graph.
347    viewer.setSceneData( rootnode.get() );
348
349    return viewer.run();
350}
Note: See TracBrowser for help on using the browser.