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

Revision 8868, 7.6 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 ...
"

Line 
1/*
2  Steffen Frey
3  Fachpraktikum Graphik-Programmierung 2007
4  Institut fuer Visualisierung und Interaktive Systeme
5  Universitaet Stuttgart
6 */
7
8#include <osg/GLExtensions>
9#include <osg/Node>
10#include <osg/Geometry>
11#include <osg/Notify>
12#include <osg/MatrixTransform>
13#include <osg/AnimationPath>
14
15#include <osgDB/ReadFile>
16#include <osgViewer/Viewer>
17#include <osgGA/TrackballManipulator>
18
19#include <iostream>
20
21#include "DePee.h"   
22
23/*!
24  Handles keyboard events.
25  Maintains a copy of the DePee object and part of its internal state
26  Used for example to set sketchiness, color, add or remove a depth peeling pass
27 */
28class KeyboardEventHandler : public osgGA::GUIEventHandler
29{
30public:
31 
32  KeyboardEventHandler(DePee* dePee)
33  {
34    _apc = 0;
35    _dePee = dePee;
36    _sketchy = false;
37    _sketchiness = 1.0;
38    _colored = false;
39    _edgy = true;
40    _crayon = false;
41    _dePee->setSketchy(_sketchy);
42    _dePee->setColored(_colored);
43  }
44 
45  virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&)
46  {
47    switch(ea.getEventType())
48      {
49       
50      case(osgGA::GUIEventAdapter::KEYDOWN):
51        {
52          if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Space)
53            {
54              if(_apc)
55                _apc->setPause(!_apc->getPause());
56              return true;
57            }
58          else if (ea.getKey() == 'a')
59            {
60              _dePee->addDePeePass();
61              return true;
62            }
63          else if (ea.getKey() == 'r')
64            {
65              _dePee->remDePeePass();
66              return true;
67            }
68          else if (ea.getKey() == 'c')
69            {
70              _colored = !_colored;
71              _dePee->setColored(_colored);
72              return true;
73            }
74          else if (ea.getKey() == 's')
75            {
76              _sketchy = !_sketchy;
77              _dePee->setSketchy(_sketchy);
78              return true;
79            }
80         
81          else if (ea.getKey() == 'e')
82            {
83              _edgy = !_edgy;
84              _dePee->setEdgy(_edgy);
85              return true;
86            }
87          else if (ea.getKey() == 'f')
88            {
89              return true;
90            }
91          else if (ea.getKey() == '+')
92            {
93              _sketchiness += 0.5;
94              _dePee->setSketchiness(_sketchiness);
95            }
96          else if (ea.getKey() == '-')
97            {
98              _sketchiness -= 0.5;
99              if(_sketchiness < 0.0)
100                _sketchiness = 0.0;
101              _dePee->setSketchiness(_sketchiness);
102            }
103
104          else if (ea.getKey() == 'y')
105            {
106              _crayon = !_crayon;
107              _dePee->setCrayon(_crayon);
108            }
109         
110          break;
111        }
112         
113      default:
114        break;
115       
116      }
117    return false;
118  }
119  void registerAnimationPathCallback(osg::AnimationPathCallback* apc)
120  {
121    _apc = apc;
122  }
123private:
124  DePee* _dePee;
125  bool _sketchy;
126  bool _colored;
127  bool _edgy;
128  bool _crayon;
129  double _sketchiness;
130  osg::AnimationPathCallback* _apc;
131};
132
133
134/*!
135  Handles mouse events.
136  Maintains a copy of the DePee object and part of its internal state
137  Used to rotate the object
138 */
139class MouseEventHandler : public osgGA::GUIEventHandler
140{
141public:
142 
143  MouseEventHandler(DePee* dePee)
144  {
145    _dePee = dePee;
146  }
147 
148  virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&)
149  {
150    switch(ea.getEventType())
151      {
152        //mouse
153      case(osgGA::GUIEventAdapter::DRAG):
154        {
155          rotate(ea.getXnormalized(), ea.getYnormalized());
156          break;
157        }
158      case(osgGA::GUIEventAdapter::MOVE):
159        _prevX = ea.getXnormalized();
160        _prevY = ea.getYnormalized();
161        break;
162       
163      default:
164        break;
165       
166      }
167    return false;
168  }
169  void registerModelGroupTransform(osg::MatrixTransform* modelGroupTransform)
170  {
171    _modelGroupTransform = modelGroupTransform;
172    _rotCenter = modelGroupTransform->getBound().center();
173  }
174private:
175  void rotate(float x, float y)
176  {
177    osg::Matrix baseMatrix = _modelGroupTransform->getMatrix();
178   
179    baseMatrix.preMultTranslate(_rotCenter);
180    baseMatrix.preMultRotate(osg::Quat((x - _prevX) * 3, osg::Vec3d(0.0, 0.0, 1.0)));
181    baseMatrix.preMultRotate(osg::Quat(-(y - _prevY) * 3, (baseMatrix * osg::Vec3d(1.0, 0.0, 0.0))));
182    baseMatrix.preMultTranslate(-_rotCenter);
183   
184    _modelGroupTransform->setMatrix(baseMatrix);
185
186    _prevX = x;
187    _prevY = y;
188  };
189 
190  DePee* _dePee;
191 
192  float _prevX;
193  float _prevY;
194 
195  osg::Vec3 _rotCenter;
196  osg::MatrixTransform* _modelGroupTransform;
197};
198
199
200
201int main( int argc, char **argv )
202{
203  // use an ArgumentParser object to manage the program arguments.
204  osg::ArgumentParser arguments(&argc,argv);
205 
206  // set up the usage document, in case we need to print out how to use this program.
207  arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates Depth Peeling");
208  arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" filename");
209 
210 
211  // construct the viewer
212  osgViewer::Viewer viewer(arguments);
213   
214  // any option left unread are converted into errors to write out later.
215  arguments.reportRemainingOptionsAsUnrecognized();
216 
217  // report any errors if they have occurred when parsing the program arguments.
218  if (arguments.errors())
219  {
220      arguments.writeErrorMessages(std::cout);
221      return 1;
222  }
223 
224  if (arguments.argc()<=1 || arguments.argc() > 3)
225  {
226        arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
227        return 1;
228  }
229
230
231  //only displays a textured quad
232  viewer.getCamera()->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
233
234  // read the model to do depth peeling with
235  osg::Node* loadedModel = osgDB::readNodeFile(arguments.argv()[1]);
236 
237  if (!loadedModel)
238    return 1;
239   
240  // create a transform to spin the model.
241  osg::MatrixTransform* modelGroupTransform = new osg::MatrixTransform;
242  osg::Group* modelGroup = new osg::Group;
243  modelGroupTransform->addChild(modelGroup);
244  modelGroup->addChild(loadedModel);
245 
246  osg::Group* rootNode = new osg::Group();
247 
248  // add model to the viewer.
249  viewer.setSceneData(rootNode);
250 
251  // Depth peel example only works on a single graphics context right now
252  // so open up viewer on single screen to prevent problems
253  viewer.setUpViewOnSingleScreen(0);
254 
255  // create the windows and run the threads.
256  viewer.realize();
257 
258  unsigned int width = 1280;
259  unsigned int height = 1280;
260  osgViewer::Viewer::Windows windows;
261  viewer.getWindows(windows);
262  if (!windows.empty())
263  {
264    width = windows.front()->getTraits()->width;
265    height = windows.front()->getTraits()->height;
266  }
267
268
269  osg::ref_ptr<DePee> dePee = new DePee(rootNode,
270                                modelGroupTransform,
271                                width,
272                                height);
273 
274  //create event handlers
275  KeyboardEventHandler* keyboardEventHandler = new KeyboardEventHandler(dePee.get());
276  MouseEventHandler* mouseEventHandler = new MouseEventHandler(dePee.get());
277  viewer.addEventHandler(keyboardEventHandler);
278  viewer.addEventHandler(mouseEventHandler);
279
280  //viewer.setCameraManipulator(new osgGA::TrackballManipulator);
281   
282  osg::StateSet* stateset = modelGroupTransform->getOrCreateStateSet();
283
284  stateset->setMode(GL_BLEND, osg::StateAttribute::OFF);
285
286  //create new animation callback for autmatic object rotation
287  osg::AnimationPathCallback* apc = new osg::AnimationPathCallback(modelGroupTransform->getBound().center(),osg::Vec3(0.0f,0.0f,1.0f),osg::inDegrees(45.0f));
288  apc->setPause(true);
289  modelGroupTransform->setUpdateCallback(apc);
290 
291  keyboardEventHandler->registerAnimationPathCallback(apc);
292  mouseEventHandler->registerModelGroupTransform(modelGroupTransform);
293   
294  //setup stuff that is necessary for measuring fps
295  osg::Timer_t current_tick, previous_tick = 1;
296  double* fps = new double;
297  dePee->setFPS(fps);
298 
299  while(!viewer.done())
300  {
301    current_tick = osg::Timer::instance()->tick();
302
303    *fps = 1.0/osg::Timer::instance()->delta_s(previous_tick,current_tick);
304    dePee->updateHUDText();
305
306    previous_tick = current_tick;
307
308    // fire off the cull and draw traversals of the scene.
309    viewer.frame();
310  }
311
312  return 0;
313}
Note: See TracBrowser for help on using the browser.