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

Revision 13376, 11.0 kB (checked in by robert, 14 hours ago)

Changed the osgUI behaviour so that events are set to be handled by Widgets that have focus even if they don't directly use them.

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