root/OpenSceneGraph/trunk/examples/osgoit/osgoit.cpp @ 12292

Revision 12292, 18.0 kB (checked in by robert, 3 years ago)

Ran svn propset -R svn:eol-style native . on the OpenSceneGraph

  • Property svn:eol-style set to native
RevLine 
[11675]1#include <osg/Array>
2#include <osg/AlphaFunc>
3#include <osg/BlendFunc>
4#include <osg/Depth>
5#include <osg/Geode>
6#include <osg/Geometry>
7#include <osg/Vec3>
8#include <osg/MatrixTransform>
9#include <osg/Texture2D>
10#include <osg/TextureRectangle>
11#include <osg/TexGen>
12#include <osg/TexEnv>
13#include <osg/TexMat>
14#include <osg/TexGenNode>
15
16#include <osgDB/ReadFile>
17
18#include <osgViewer/Viewer>
19#include <osgViewer/ViewerEventHandlers>
20
21#include <osg/Math>
22
23#include <limits>
24#include <iostream>
25
26// Some choices for the kind of textures we can use ...
27#define USE_TEXTURE_RECTANGLE
28// #define USE_NON_POWER_OF_TWO_TEXTURE
29#define USE_PACKED_DEPTH_STENCIL
30
31template<typename T>
32inline T
33nextPowerOfTwo(T k)
34{
35    if (k == T(0))
36        return 1;
37    k--;
38    for (int i = 1; i < std::numeric_limits<T>::digits; i <<= 1)
39        k = k | k >> i;
40    return k + 1;
41}
42
43class DepthPeeling : public osg::Referenced {
44public:
45    osg::Node*
46    createQuad(unsigned layerNumber, unsigned numTiles)
47    {
48        float tileSpan = 1;
49        float tileOffsetX = 0;
50        float tileOffsetY = 0;
51        if (_showAllLayers) {
52            tileSpan /= numTiles;
53            tileOffsetX = tileSpan * (layerNumber%numTiles);
54            tileOffsetY = 1 - tileSpan * (1 + layerNumber/numTiles);
55        }
56
57        osg::Vec3Array* vertices = new osg::Vec3Array;
58
59        vertices->push_back(osg::Vec3f(tileOffsetX           , tileOffsetY            , 0));
60        vertices->push_back(osg::Vec3f(tileOffsetX           , tileOffsetY  + tileSpan, 0));
61        vertices->push_back(osg::Vec3f(tileOffsetX + tileSpan, tileOffsetY  + tileSpan, 0));
62        vertices->push_back(osg::Vec3f(tileOffsetX + tileSpan, tileOffsetY            , 0));
63
64        osg::Vec3Array* colors = new osg::Vec3Array;
65        colors->push_back(osg::Vec3(1, 1, 1));
66     
67        osg::Vec2Array* texcoords = new osg::Vec2Array;
68        texcoords->push_back(osg::Vec2f(0, 0));
69        texcoords->push_back(osg::Vec2f(0, 1));
70        texcoords->push_back(osg::Vec2f(1, 1));
71        texcoords->push_back(osg::Vec2f(1, 0));
72     
73        osg::Geometry* geometry = new osg::Geometry;
74        geometry->setVertexArray(vertices);
75        geometry->setTexCoordArray(0, texcoords);
76     
77        geometry->setColorArray(colors);
78        geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
79     
80        geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));
81     
82        osg::Geode* geode = new osg::Geode;
83        geode->addDrawable(geometry);
84     
85        return geode;
86    }
87   
88    class CullCallback : public osg::NodeCallback {
89    public:
90        CullCallback(unsigned texUnit, unsigned texWidth, unsigned texHeight, unsigned offsetValue) :
91            _texUnit(texUnit),
92            _texWidth(texWidth),
93            _texHeight(texHeight),
94            _offsetValue(offsetValue)
95        {
96        }
97     
98        virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
99        {
100            osgUtil::CullVisitor* cullVisitor = static_cast<osgUtil::CullVisitor*>(nv);
101            osgUtil::RenderStage* renderStage = cullVisitor->getCurrentRenderStage();
102            const osg::Viewport* viewport = renderStage->getViewport();
103
104            osg::Matrixd m(*cullVisitor->getProjectionMatrix());
105            m.postMultTranslate(osg::Vec3d(1, 1, 1));
106            m.postMultScale(osg::Vec3d(0.5, 0.5, 0.5));
107
108            // scale the texture coordinates to the viewport
109#ifdef USE_TEXTURE_RECTANGLE
110            m.postMultScale(osg::Vec3d(viewport->width(), viewport->height(), 1));
111#else
112#ifndef USE_NON_POWER_OF_TWO_TEXTURE
113            m.postMultScale(osg::Vec3d(viewport->width()/double(_texWidth), viewport->height()/double(_texHeight), 1));
114#endif
115#endif
116
117            // Kind of polygon offset: note this way, we can also offset lines and points.
118            // Whereas with the polygon offset we could only handle surface primitives.
119            m.postMultTranslate(osg::Vec3d(0, 0, -ldexp(double(_offsetValue), -24)));
120
121            osg::TexMat* texMat = new osg::TexMat(m);
122            osg::StateSet* stateSet = new osg::StateSet;
123            stateSet->setTextureAttribute(_texUnit, texMat);
124            cullVisitor->pushStateSet(stateSet);
125            traverse(node, nv);
126            cullVisitor->popStateSet();
127        }
128
129    private:
130        unsigned _texUnit;
131        unsigned _texWidth;
132        unsigned _texHeight;
133        unsigned _offsetValue;
134    };
135
136    void
137    createPeeling()
138    {
139        int numTiles = ceil(sqrt(double(_numPasses)));
140
141        _root->removeChildren(0, _root->getNumChildren());
142        _colorTextures.clear();
143
144        // If not enabled, just use the top level camera
145        if (!_depthPeelingEnabled) {
146            _root->addChild(_scene.get());
147            return;
148        }
149
150        _compositeCamera = new osg::Camera;
151        _compositeCamera->setDataVariance(osg::Object::DYNAMIC);
152        _compositeCamera->setInheritanceMask(osg::Camera::READ_BUFFER | osg::Camera::DRAW_BUFFER);
153        _compositeCamera->setRenderOrder(osg::Camera::POST_RENDER);
154        _compositeCamera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_PRIMITIVES);
155        _compositeCamera->setClearMask(0);
156
157        _compositeCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
158        _compositeCamera->setViewMatrix(osg::Matrix());
159        _compositeCamera->setProjectionMatrix(osg::Matrix::ortho2D(0, 1, 0, 1));
160
161        _compositeCamera->setCullCallback(new CullCallback(0, _texWidth, _texHeight, 0));
162
163        osg::StateSet* stateSet = _compositeCamera->getOrCreateStateSet();
164        stateSet->setBinName("TraversalOrderBin");
165        stateSet->setRenderBinMode(osg::StateSet::USE_RENDERBIN_DETAILS);
166
167        _root->addChild(_compositeCamera.get());
168
169        for (unsigned i = 0; i < 2; ++i) {
170#ifdef USE_TEXTURE_RECTANGLE
171            _depthTextures[i] = new osg::TextureRectangle;
172#else
173            _depthTextures[i] = new osg::Texture2D;
174#endif
175            _depthTextures[i]->setTextureSize(_texWidth, _texHeight);
176
177            _depthTextures[i]->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
178            _depthTextures[i]->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
179            _depthTextures[i]->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_BORDER);
180            _depthTextures[i]->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_BORDER);
181
182#ifdef USE_PACKED_DEPTH_STENCIL
183            _depthTextures[i]->setInternalFormat(GL_DEPTH24_STENCIL8_EXT);
184            _depthTextures[i]->setSourceFormat(GL_DEPTH_STENCIL_EXT);
185            _depthTextures[i]->setSourceType(GL_UNSIGNED_INT_24_8_EXT);
186#else
187            _depthTextures[i]->setInternalFormat(GL_DEPTH_COMPONENT);
188            _depthTextures[i]->setInternalFormat(GL_DEPTH_COMPONENT24);
189#endif
190
191            _depthTextures[i]->setShadowComparison(true);
192            _depthTextures[i]->setShadowAmbient(0); // The r value if the test fails
193            _depthTextures[i]->setShadowCompareFunc(osg::Texture::GREATER);
194            _depthTextures[i]->setShadowTextureMode(osg::Texture::INTENSITY);
195        }
196
197        // Then, the other ones
198        for (unsigned i = 0; i < _numPasses; ++i) {
199            osg::Camera* camera = new osg::Camera;
200            camera->setDataVariance(osg::Object::DYNAMIC);
201
202            camera->setInheritanceMask(osg::Camera::ALL_VARIABLES);
203            camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
204            camera->setRenderOrder(osg::Camera::PRE_RENDER, i);
205            camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
206            camera->setClearColor(osg::Vec4f(0, 0, 0, 0));
207
208            camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
209
210            osg::ref_ptr<osg::Texture> depthTexture = _depthTextures[i%2];
211            osg::ref_ptr<osg::Texture> prevDepthTexture = _depthTextures[(i+1)%2];
212
213#ifdef USE_PACKED_DEPTH_STENCIL
214            camera->attach(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, depthTexture.get());
215#else
216            camera->attach(osg::Camera::DEPTH_BUFFER, depthTexture.get());
217#endif
218
219#ifdef USE_TEXTURE_RECTANGLE
220            osg::ref_ptr<osg::TextureRectangle> colorTexture = new osg::TextureRectangle;
221#else
222            osg::ref_ptr<osg::Texture2D> colorTexture = new osg::Texture2D;
223#endif
224            _colorTextures.push_back(colorTexture);
225
226            colorTexture->setTextureSize(_texWidth, _texHeight);
227            colorTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
228            colorTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
229            colorTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_BORDER);
230            colorTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_BORDER);
231            colorTexture->setInternalFormat(GL_RGBA);
232            camera->attach(osg::Camera::COLOR_BUFFER, colorTexture.get());
233
234            camera->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
235            if (0 == i) {
236                camera->addChild(_scene.get());
237            } else {
238                osg::StateSet* stateSet = camera->getOrCreateStateSet();
239
240                stateSet->setAttributeAndModes(new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01),
241                                               osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
242
243                stateSet->setTextureAttributeAndModes(_texUnit, prevDepthTexture.get());
244
245                // Is the default ...
246                //         stateSet->setTextureAttributeAndModes(_texUnit, new osg::TexEnv(osg::TexEnv::MODULATE));
247                stateSet->setTextureMode(_texUnit, GL_TEXTURE_GEN_S, osg::StateAttribute::ON);
248                stateSet->setTextureMode(_texUnit, GL_TEXTURE_GEN_T, osg::StateAttribute::ON);
249                stateSet->setTextureMode(_texUnit, GL_TEXTURE_GEN_R, osg::StateAttribute::ON);
250                stateSet->setTextureMode(_texUnit, GL_TEXTURE_GEN_Q, osg::StateAttribute::ON);
251
252                osg::TexGenNode* texGenNode = new osg::TexGenNode;
253                texGenNode->setReferenceFrame(osg::TexGenNode::ABSOLUTE_RF);
254                texGenNode->setTextureUnit(_texUnit);
255                texGenNode->getTexGen()->setMode(osg::TexGen::EYE_LINEAR);
256                camera->addChild(texGenNode);
257                camera->addCullCallback(new CullCallback(_texUnit, _texWidth, _texHeight, _offsetValue));
258
259                texGenNode->addChild(_scene.get());
260            }
261
262            _root->addChild(camera);
263
264            osg::Node* geode = createQuad(i, numTiles);
265            osg::StateSet* stateSet = geode->getOrCreateStateSet();
266            stateSet->setTextureAttributeAndModes(0, colorTexture.get(), osg::StateAttribute::ON);
267            stateSet->setAttribute(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON);
268            stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
269            stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
270            stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
271            _compositeCamera->insertChild(0, geode);
272        }
273    }
274
275    DepthPeeling(unsigned width, unsigned height) :
276        _numPasses(8),
277        _texUnit(1),
278        _texWidth(width),
279        _texHeight(height),
280        _showAllLayers(false),
281        _depthPeelingEnabled(true),
282        _offsetValue(8),
283        _root(new osg::Group),
284        _scene(new osg::Group)
285    {
286        createPeeling();
287    }
288
289    void setScene(osg::Node* scene)
290    {
291        _scene->removeChildren(0, _scene->getNumChildren());
292        _scene->addChild(scene);
293    }
294
295    osg::Node* getRoot()
296    {
297        return _root.get();
298    }
299
300    void resize(int width, int height)
301    {
302#ifdef USE_TEXTURE_RECTANGLE
303        _depthTextures[0]->setTextureSize(width, height);
304        _depthTextures[1]->setTextureSize(width, height);
305        for (unsigned i = 0; i < _colorTextures.size(); ++i)
306            _colorTextures[i]->setTextureSize(width, height);
307        _texWidth = width;
308        _texHeight = height;
309#else
310#ifndef USE_NON_POWER_OF_TWO_TEXTURE
311        width = nextPowerOfTwo(width);
312        height = nextPowerOfTwo(height);
313#endif
314        _depthTextures[0]->setTextureSize(width, height);
315        _depthTextures[1]->setTextureSize(width, height);
316        for (unsigned i = 0; i < _colorTextures.size(); ++i)
317            _colorTextures[i]->setTextureSize(width, height);
318        _texWidth = width;
319        _texHeight = height;
320#endif
321        createPeeling();
322    }
323
324    void setNumPasses(unsigned numPasses)
325    {
326        if (numPasses == _numPasses)
327            return;
328        if (numPasses == unsigned(-1))
329            return;
330        _numPasses = numPasses;
331        createPeeling();
332    }
333    unsigned getNumPasses() const
334    {
335        return _numPasses;
336    }
337
338    void setTexUnit(unsigned texUnit)
339    {
340        if (texUnit == _texUnit)
341            return;
342        _texUnit = texUnit;
343        createPeeling();
344    }
345
346    void setShowAllLayers(bool showAllLayers)
347    {
348        if (showAllLayers == _showAllLayers)
349            return;
350        _showAllLayers = showAllLayers;
351        createPeeling();
352    }
353    bool getShowAllLayers() const
354    {
355        return _showAllLayers;
356    }
357
358    void setDepthPeelingEnabled(bool depthPeelingEnabled)
359    {
360        if (depthPeelingEnabled == _depthPeelingEnabled)
361            return;
362        _depthPeelingEnabled = depthPeelingEnabled;
363        createPeeling();
364    }
365    bool getDepthPeelingEnabled() const
366    {
367        return _depthPeelingEnabled;
368    }
369
370    void setOffsetValue(unsigned offsetValue)
371    {
372        if (offsetValue == _offsetValue)
373            return;
374        _offsetValue = offsetValue;
375        createPeeling();
376    }
377    unsigned getOffsetValue() const
378    {
379        return _offsetValue;
380    }
381
382    unsigned _numPasses;
383    unsigned _texUnit;
384    unsigned _texWidth;
385    unsigned _texHeight;
386    bool _showAllLayers;
387    bool _depthPeelingEnabled;
388    unsigned _offsetValue;
389
390    // The root node that is handed over to the viewer
391    osg::ref_ptr<osg::Group> _root;
392
393    // The scene that is displayed
394    osg::ref_ptr<osg::Group> _scene;
395
396    // The final camera that composites the pre rendered textures to the final picture
397    osg::ref_ptr<osg::Camera> _compositeCamera;
398
399#ifdef USE_TEXTURE_RECTANGLE
400    osg::ref_ptr<osg::TextureRectangle> _depthTextures[2];
401    std::vector<osg::ref_ptr<osg::TextureRectangle> > _colorTextures;
402#else
403    osg::ref_ptr<osg::Texture2D> _depthTextures[2];
404    std::vector<osg::ref_ptr<osg::Texture2D> > _colorTextures;
405#endif
406};
407
408class EventHandler : public osgGA::GUIEventHandler {
409public:
410    EventHandler(DepthPeeling* depthPeeling) :
411        _depthPeeling(depthPeeling)
412    { }
413
414    /** Handle events, return true if handled, false otherwise. */
415    virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter&, osg::Object*, osg::NodeVisitor*)
416    {
417        if (ea.getEventType() == osgGA::GUIEventAdapter::RESIZE) {
418            _depthPeeling->resize(ea.getWindowWidth(), ea.getWindowHeight());
419            return true;
420        }
421
422        if (ea.getEventType() == osgGA::GUIEventAdapter::KEYDOWN) {
423            switch (ea.getKey()) {
424            case 'd':
425                _depthPeeling->setDepthPeelingEnabled(!_depthPeeling->getDepthPeelingEnabled());
426                return true;
427            case 'm':
428                _depthPeeling->setNumPasses(_depthPeeling->getNumPasses() + 1);
429                return true;
430            case 'n':
431                _depthPeeling->setNumPasses(_depthPeeling->getNumPasses() - 1);
432                return true;
433            case 'p':
434                _depthPeeling->setOffsetValue(_depthPeeling->getOffsetValue() + 1);
435                return true;
436            case 'o':
437                _depthPeeling->setOffsetValue(_depthPeeling->getOffsetValue() - 1);
438                return true;
439            case 'l':
440                _depthPeeling->setShowAllLayers(!_depthPeeling->getShowAllLayers());
441                return true;
442            default:
443                return false;
444            };
445        }
446
447        return false;
448    }
449
450    osg::ref_ptr<DepthPeeling> _depthPeeling;
451};
452
453int main(int argc, char** argv)
454{
455    // use an ArgumentParser object to manage the program arguments.
456    osg::ArgumentParser arguments(&argc, argv);
457    arguments.getApplicationUsage()->addKeyboardMouseBinding("d", "Toggle depth peeling enabled");
458    arguments.getApplicationUsage()->addKeyboardMouseBinding("m", "Increase the number of depth peeling layers");
459    arguments.getApplicationUsage()->addKeyboardMouseBinding("n", "Decrease the number of depth peeling layers");
460    arguments.getApplicationUsage()->addKeyboardMouseBinding("l", "Toggle display of the individual or composed layer textures");
461    arguments.getApplicationUsage()->addKeyboardMouseBinding("p", "Increase the layer offset");
462    arguments.getApplicationUsage()->addKeyboardMouseBinding("o", "Decrease the layer offset");
463
464    // Have the usual viewer
465    osgViewer::Viewer viewer(arguments);
466
467    osg::DisplaySettings* displaySettings = new osg::DisplaySettings;
468    viewer.setDisplaySettings(displaySettings);
469   
470    // Add the stats handler
471    viewer.addEventHandler(new osgViewer::StatsHandler);
472   
473    // add the help handler
474    viewer.addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage()));
475
476    // load the data
477    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
478    if (!loadedModel)
479    {
480        std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
481        return 1;
482    }
483   
484    // any option left unread are converted into errors to write out later.
485    arguments.reportRemainingOptionsAsUnrecognized();
486   
487    // report any errors if they have occurred when parsing the program arguments.
488    if (arguments.errors())
489    {
490        arguments.writeErrorMessages(std::cout);
491        return 1;
492    }
493
494    // The initial size sez to 0, 0. We get a resize event for the right size ...
495    DepthPeeling* depthPeeling = new DepthPeeling(0, 0);
496    depthPeeling->setScene(loadedModel.get());
497    viewer.setSceneData(depthPeeling->getRoot());
498
499    // Add the event handler for the depth peeling stuff
500    viewer.addEventHandler(new EventHandler(depthPeeling));
501   
502    return viewer.run();
503}
Note: See TracBrowser for help on using the browser.