root/OpenSceneGraph/trunk/examples/osgsimulation/osgsimulation.cpp @ 8868

Revision 8868, 17.3 kB (checked in by robert, 6 years ago)

From Mathias Froehlich, "This is a generic optimization that does not depend on any cpu or instruction
set.

The optimization is based on the observation that matrix matrix multiplication
with a dense matrix 4x4 is 43 Operations whereas multiplication with a
transform, or scale matrix is only 4
2 operations. Which is a gain of a
*FACTOR*4* for these special cases.
The change implements these special cases, provides a unit test for these
implementation and converts uses of the expensiver dense matrix matrix
routine with the specialized versions.

Depending on the transform nodes in the scenegraph this change gives a
noticable improovement.
For example the osgforest code using the MatrixTransform? is about 20% slower
than the same codepath using the PositionAttitudeTransform? instead of the
MatrixTransform? with this patch applied.

If I remember right, the sse type optimizations did *not* provide a factor 4
improovement. Also these changes are totally independent of any cpu or
instruction set architecture. So I would prefer to have this current kind of
change instead of some hand coded and cpu dependent assembly stuff. If we
need that hand tuned stuff, these can go on top of this changes which must
provide than hand optimized additional variants for the specialized versions
to give a even better result in the end.

An other change included here is a change to rotation matrix from quaterion
code. There is a sqrt call which couold be optimized away. Since we divide in
effect by sqrt(length)*sqrt(length) which is just length ...
"

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* OpenSceneGraph example, osgsimulation.
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#ifdef WIN32
20/////////////////////////////////////////////////////////////////////////////
21// Disable unavoidable warning messages:
22
23//  4103: used #pragma pack to change alignment
24//  4114: same type qualifier used more than once
25//  4201: nonstandard extension used : nameless struct/union
26//  4237: "keyword" reserved for future use
27//  4251: class needs to have dll-interface to export class
28//  4275: non DLL-interface class used as base for DLL-interface class
29//  4290: C++ Exception Specification ignored
30//  4503: decorated name length exceeded, name was truncated
31//  4786: string too long - truncated to 255 characters
32
33#pragma warning(disable : 4103 4114 4201 4237 4251 4275 4290 4503 4335 4786)
34
35#endif // WIN32
36
37#include <osgViewer/Viewer>
38#include <osgViewer/ViewerEventHandlers>
39
40#include <osg/Group>
41#include <osg/Geode>
42#include <osg/ShapeDrawable>
43#include <osg/Texture2D>
44#include <osg/PositionAttitudeTransform>
45#include <osg/MatrixTransform>
46#include <osg/CoordinateSystemNode>
47
48#include <osgDB/FileUtils>
49#include <osgDB/ReadFile>
50
51#include <osgText/Text>
52
53#include <osg/CoordinateSystemNode>
54
55#include <osgSim/OverlayNode>
56#include <osgSim/SphereSegment>
57
58#include <osgGA/NodeTrackerManipulator>
59#include <osgGA/StateSetManipulator>
60#include <osgGA/TrackballManipulator>
61#include <osgGA/FlightManipulator>
62#include <osgGA/DriveManipulator>
63#include <osgGA/KeySwitchMatrixManipulator>
64#include <osgGA/AnimationPathManipulator>
65#include <osgGA/TerrainManipulator>
66
67#include <osgParticle/FireEffect>
68
69#include <iostream>
70
71osg::Node* createEarth()
72{
73    osg::TessellationHints* hints = new osg::TessellationHints;
74    hints->setDetailRatio(5.0f);
75
76   
77    osg::ShapeDrawable* sd = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.0,0.0,0.0), osg::WGS_84_RADIUS_POLAR), hints);
78   
79    osg::Geode* geode = new osg::Geode;
80    geode->addDrawable(sd);
81   
82    std::string filename = osgDB::findDataFile("Images/land_shallow_topo_2048.jpg");
83    geode->getOrCreateStateSet()->setTextureAttributeAndModes(0, new osg::Texture2D(osgDB::readImageFile(filename)));
84   
85    osg::CoordinateSystemNode* csn = new osg::CoordinateSystemNode;
86    csn->setEllipsoidModel(new osg::EllipsoidModel());
87    csn->addChild(geode);
88   
89    return csn;
90   
91}
92
93
94class ModelPositionCallback : public osg::NodeCallback
95{
96public:
97
98    ModelPositionCallback(double speed):
99        _latitude(0.0),
100        _longitude(0.0),
101        _height(100000.0),
102        _speed(speed)
103    {
104        _rotation.makeRotate(osg::DegreesToRadians(90.0),0.0,0.0,1.0);
105    }
106   
107    void updateParameters()
108    {
109        _longitude += _speed * ((2.0*osg::PI)/360.0)/20.0;
110    }
111
112
113    virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
114    {
115        updateParameters();
116       
117        osg::NodePath nodePath = nv->getNodePath();
118
119        osg::MatrixTransform* mt = nodePath.empty() ? 0 : dynamic_cast<osg::MatrixTransform*>(nodePath.back());
120        if (mt)
121        {
122            osg::CoordinateSystemNode* csn = 0;
123
124            // find coordinate system node from our parental chain
125            unsigned int i;
126            for(i=0; i<nodePath.size() && csn==0; ++i)
127            {
128                csn = dynamic_cast<osg::CoordinateSystemNode*>(nodePath[i]);
129            }
130           
131            if (csn)
132            {
133
134
135                osg::EllipsoidModel* ellipsoid = csn->getEllipsoidModel();
136                if (ellipsoid)
137                {
138                    osg::Matrix inheritedMatrix;
139                    for(i+=1; i<nodePath.size()-1; ++i)
140                    {
141                        osg::Transform* transform = nodePath[i]->asTransform();
142                        if (transform) transform->computeLocalToWorldMatrix(inheritedMatrix, nv);
143                    }
144                   
145                    osg::Matrixd matrix(inheritedMatrix);
146
147                    //osg::Matrixd matrix;
148                    ellipsoid->computeLocalToWorldTransformFromLatLongHeight(_latitude,_longitude,_height,matrix);
149                    matrix.preMultRotate(_rotation);
150                   
151                    mt->setMatrix(matrix);
152                }
153
154            }       
155        }
156           
157        traverse(node,nv);
158    }   
159   
160    double                  _latitude;
161    double                  _longitude;
162    double                  _height;
163    osg::Quat               _rotation;
164    double                  _speed;
165};
166
167
168class FindNamedNodeVisitor : public osg::NodeVisitor
169{
170public:
171    FindNamedNodeVisitor(const std::string& name):
172        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
173        _name(name) {}
174   
175    virtual void apply(osg::Node& node)
176    {
177        if (node.getName()==_name)
178        {
179            _foundNodes.push_back(&node);
180        }
181        traverse(node);
182    }
183   
184    typedef std::vector< osg::ref_ptr<osg::Node> > NodeList;
185
186    std::string _name;
187    NodeList _foundNodes;
188};
189
190
191int main(int argc, char **argv)
192{
193    // use an ArgumentParser object to manage the program arguments.
194    osg::ArgumentParser arguments(&argc,argv);
195   
196    // set up the usage document, in case we need to print out how to use this program.
197    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates use of node tracker.");
198    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName());
199    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
200   
201
202    // construct the viewer.
203    osgViewer::Viewer viewer(arguments);
204
205    // add the state manipulator
206    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
207   
208    // add the thread model handler
209    viewer.addEventHandler(new osgViewer::ThreadingHandler);
210
211    // add the window size toggle handler
212    viewer.addEventHandler(new osgViewer::WindowSizeHandler);
213       
214    // add the stats handler
215    viewer.addEventHandler(new osgViewer::StatsHandler);
216       
217    // add the record camera path  handler
218    viewer.addEventHandler(new osgViewer::RecordCameraPathHandler);
219
220    // add the help handler
221    viewer.addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage()));
222
223    // set the near far ration computation up.
224    viewer.getCamera()->setComputeNearFarMode(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES);
225    viewer.getCamera()->setNearFarRatio(0.000003f);
226
227
228    double speed = 1.0;
229    while (arguments.read("-f") || arguments.read("--fixed")) speed = 0.0;
230
231
232    osg::Quat rotation;
233    osg::Vec4 vec4;
234    while (arguments.read("--rotate-model",vec4[0],vec4[1],vec4[2],vec4[3]))
235    {
236        osg::Quat local_rotate;
237        local_rotate.makeRotate(osg::DegreesToRadians(vec4[0]),vec4[1],vec4[2],vec4[3]);
238       
239        rotation = rotation * local_rotate;
240    }
241
242    osg::NodeCallback* nc = 0;
243    std::string flightpath_filename;
244    while (arguments.read("--flight-path",flightpath_filename))
245    {
246        std::ifstream fin(flightpath_filename.c_str());
247        if (fin)
248        {
249            osg::AnimationPath* path = new osg::AnimationPath;
250            path->read(fin);
251            nc = new osg::AnimationPathCallback(path);
252        }
253    }
254   
255    osgGA::NodeTrackerManipulator::TrackerMode trackerMode = osgGA::NodeTrackerManipulator::NODE_CENTER_AND_ROTATION;
256    std::string mode;
257    while (arguments.read("--tracker-mode",mode))
258    {
259        if (mode=="NODE_CENTER_AND_ROTATION") trackerMode = osgGA::NodeTrackerManipulator::NODE_CENTER_AND_ROTATION;
260        else if (mode=="NODE_CENTER_AND_AZIM") trackerMode = osgGA::NodeTrackerManipulator::NODE_CENTER_AND_AZIM;
261        else if (mode=="NODE_CENTER") trackerMode = osgGA::NodeTrackerManipulator::NODE_CENTER;
262        else
263        {
264            std::cout<<"Unrecognized --tracker-mode option "<<mode<<", valid options are:"<<std::endl;
265            std::cout<<"    NODE_CENTER_AND_ROTATION"<<std::endl;
266            std::cout<<"    NODE_CENTER_AND_AZIM"<<std::endl;
267            std::cout<<"    NODE_CENTER"<<std::endl;
268            return 1;
269        }
270    }
271   
272   
273    osgGA::NodeTrackerManipulator::RotationMode rotationMode = osgGA::NodeTrackerManipulator::TRACKBALL;
274    while (arguments.read("--rotation-mode",mode))
275    {
276        if (mode=="TRACKBALL") rotationMode = osgGA::NodeTrackerManipulator::TRACKBALL;
277        else if (mode=="ELEVATION_AZIM") rotationMode = osgGA::NodeTrackerManipulator::ELEVATION_AZIM;
278        else
279        {
280            std::cout<<"Unrecognized --rotation-mode option "<<mode<<", valid options are:"<<std::endl;
281            std::cout<<"    TRACKBALL"<<std::endl;
282            std::cout<<"    ELEVATION_AZIM"<<std::endl;
283            return 1;
284        }
285    }
286
287    bool useOverlay = true;
288    while (arguments.read("--no-overlay") || arguments.read("-n")) useOverlay = false;
289   
290    osgSim::OverlayNode::OverlayTechnique technique = osgSim::OverlayNode::OBJECT_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY;
291    while (arguments.read("--object")) technique = osgSim::OverlayNode::OBJECT_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY;
292    while (arguments.read("--ortho") || arguments.read("--orthographic")) technique = osgSim::OverlayNode::VIEW_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY;
293    while (arguments.read("--persp") || arguments.read("--perspective")) technique = osgSim::OverlayNode::VIEW_DEPENDENT_WITH_PERSPECTIVE_OVERLAY;
294
295    unsigned int overlayTextureUnit = 1;
296    while (arguments.read("--unit", overlayTextureUnit)) {}
297   
298    std::string pathfile;
299    while (arguments.read("-p",pathfile)) {}
300
301    bool addFireEffect = arguments.read("--fire");
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   
311    osg::ref_ptr<osgGA::NodeTrackerManipulator> tm;
312   
313    std::string overlayFilename;
314    while(arguments.read("--overlay", overlayFilename)) {}
315
316    // read the scene from the list of file specified commandline args.
317    osg::ref_ptr<osg::Node> root = osgDB::readNodeFiles(arguments);
318
319    if (!root) root = createEarth();
320
321    if (!root) return 0;
322
323
324    if (!overlayFilename.empty())
325    {
326        //osg::Object *pObj = osgDB::readObjectFile("alaska_clean.shp");
327        //osg::ref_ptr<osg::Geode> shapefile = dynamic_cast<osg::Geode*> (pObj);
328        //
329        //ConvertLatLon2EllipsoidCoordinates latlon2em;
330        //shapefile->accept(latlon2em);
331
332        osg::ref_ptr<osg::Node> shapefile = osgDB::readNodeFile(overlayFilename);
333       
334        if (!shapefile)
335        {
336            osg::notify(osg::NOTICE)<<"File `"<<overlayFilename<<"` not found"<<std::endl;
337            return 1;
338        }
339
340        osg::CoordinateSystemNode* csn = dynamic_cast<osg::CoordinateSystemNode*>(root.get());
341        if (csn)
342        {
343
344            osgSim::OverlayNode* overlayNode = new osgSim::OverlayNode(technique);
345            overlayNode->getOrCreateStateSet()->setTextureAttribute(1, new osg::TexEnv(osg::TexEnv::DECAL));
346            overlayNode->setOverlaySubgraph(shapefile.get());
347            overlayNode->setOverlayTextureSizeHint(1024);
348            overlayNode->setOverlayTextureUnit(overlayTextureUnit);
349
350            // insert the OverlayNode between the coordinate system node and its children.
351            for(unsigned int i=0; i<csn->getNumChildren(); ++i)
352            {
353                overlayNode->addChild( csn->getChild(i) );
354            }
355
356            csn->removeChildren(0, csn->getNumChildren());
357            csn->addChild(overlayNode);
358
359            viewer.setSceneData(csn);
360        }
361        else
362        {
363            osgSim::OverlayNode* overlayNode = new osgSim::OverlayNode(technique);
364            overlayNode->getOrCreateStateSet()->setTextureAttribute(1, new osg::TexEnv(osg::TexEnv::DECAL));
365            overlayNode->setOverlaySubgraph(shapefile.get());
366            overlayNode->setOverlayTextureSizeHint(1024);
367            overlayNode->addChild(root.get());
368
369            viewer.setSceneData(overlayNode);
370        }
371    }
372    else
373    {
374   
375
376        // add a viewport to the viewer and attach the scene graph.
377        viewer.setSceneData(root.get());
378
379        osg::CoordinateSystemNode* csn = dynamic_cast<osg::CoordinateSystemNode*>(root.get());
380        if (csn)
381        {
382
383            osg::ref_ptr<osgSim::OverlayNode> overlayNode;
384            if (useOverlay)
385            {
386                overlayNode = new osgSim::OverlayNode(technique);
387
388                // insert the OverlayNode between the coordinate system node and its children.
389                for(unsigned int i=0; i<csn->getNumChildren(); ++i)
390                {
391                    overlayNode->addChild( csn->getChild(i) );
392                }
393
394                csn->removeChildren(0, csn->getNumChildren());
395                csn->addChild(overlayNode.get());
396
397                // tell the overlay node to continously update its overlay texture
398                // as we know we'll be tracking a moving target.
399                overlayNode->setContinuousUpdate(true);
400            }
401
402
403            osg::Node* cessna = osgDB::readNodeFile("cessna.osg");
404            if (cessna)
405            {
406                double s = 200000.0 / cessna->getBound().radius();
407
408                osg::MatrixTransform* scaler = new osg::MatrixTransform;
409                scaler->addChild(cessna);
410                scaler->setMatrix(osg::Matrixd::scale(s,s,s)*osg::Matrixd::rotate(rotation));
411                scaler->getOrCreateStateSet()->setMode(GL_RESCALE_NORMAL,osg::StateAttribute::ON);
412               
413                if (addFireEffect)
414                {               
415                    osg::Vec3d center = cessna->getBound().center();
416                   
417                    osgParticle::FireEffect* fire = new osgParticle::FireEffect(center, 10.0f);
418                    scaler->addChild(fire);
419                }
420               
421
422                if (false)
423                {
424                    osgSim::SphereSegment* ss = new osgSim::SphereSegment(
425                                        osg::Vec3(0.0f,0.0f,0.0f), // center
426                                        19.9f, // radius
427                                        osg::DegreesToRadians(135.0f),
428                                        osg::DegreesToRadians(240.0f),
429                                        osg::DegreesToRadians(-10.0f),
430                                        osg::DegreesToRadians(30.0f),
431                                        60);
432
433                    scaler->addChild(ss);
434                }
435
436                osg::MatrixTransform* mt = new osg::MatrixTransform;
437                mt->addChild(scaler);
438
439
440                if (!nc) nc = new ModelPositionCallback(speed);
441
442                mt->setUpdateCallback(nc);
443
444                csn->addChild(mt);
445
446                // if we are using an overaly node, use the cessna subgraph as the overlay subgraph
447                if (overlayNode.valid())
448                {
449                    overlayNode->setOverlaySubgraph(mt);
450                }
451
452                tm = new osgGA::NodeTrackerManipulator;
453                tm->setTrackerMode(trackerMode);
454                tm->setRotationMode(rotationMode);
455                tm->setTrackNode(scaler);
456            }
457            else
458            {
459                 std::cout<<"Failed to read cessna.osg"<<std::endl;
460            }
461
462        }   
463    }
464
465    // set up camera manipulators.
466    {
467        osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
468
469        if (tm.valid()) keyswitchManipulator->addMatrixManipulator( '0', "NodeTracker", tm.get() );
470
471        keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() );
472        keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() );
473        keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() );
474        keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() );
475
476        if (!pathfile.empty())
477        {
478            osgGA::AnimationPathManipulator* apm = new osgGA::AnimationPathManipulator(pathfile);
479            if (apm || !apm->valid())
480            {
481                unsigned int num = keyswitchManipulator->getNumMatrixManipulators();
482                keyswitchManipulator->addMatrixManipulator( '5', "Path", apm );
483                keyswitchManipulator->selectMatrixManipulator(num);
484            }
485        }
486
487        viewer.setCameraManipulator( keyswitchManipulator.get() );
488    }
489
490    // viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded);
491
492    return viewer.run();
493}
Note: See TracBrowser for help on using the browser.