root/OpenSceneGraph/trunk/examples/osgprerendercubemap/osgprerendercubemap.cpp @ 2233

Revision 2233, 16.1 kB (checked in by robert, 11 years ago)

Added support for Matrixd and Matrixf implementations, with the default
Matrix typedef's to either Matrixd or Matrixf.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <osg/GLExtensions>
2#include <osg/Group>
3#include <osg/Geode>
4#include <osg/Matrix>
5#include <osg/Quat>
6#include <osg/StateSet>
7#include <osg/TextureCubeMap>
8#include <osg/TexGen>
9#include <osg/TexMat>
10#include <osg/TexEnvCombine>
11#include <osg/ShapeDrawable>
12#include <osg/PositionAttitudeTransform>
13
14#include <osgUtil/RenderToTextureStage>
15#include <osgUtil/Optimizer>
16
17#include <osgDB/ReadFile>
18#include <osgDB/Registry>
19
20#include <osgGA/TrackballManipulator>
21#include <osgGA/FlightManipulator>
22#include <osgGA/DriveManipulator>
23
24#include <osgProducer/Viewer>
25
26#include <iostream>
27#include <string>
28#include <vector>
29
30
31//#define UPDATE_ONE_IMAGE_PER_FRAME 1
32
33
34class PrerenderAppCallback : public osg::NodeCallback
35{
36    public:
37   
38        PrerenderAppCallback(osg::Node* subgraph):
39            _subgraph(subgraph) {}
40
41        virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
42        {
43            // traverse the subgraph to update any nodes.
44            if (_subgraph.valid()) _subgraph->accept(*nv);
45       
46            // must traverse the Node's subgraph           
47            traverse(node,nv);
48        }
49       
50        osg::ref_ptr<osg::Node>     _subgraph;
51};
52
53
54class PrerenderCullCallback : public osg::NodeCallback
55{
56    public:
57   
58        PrerenderCullCallback(osg::Node* subgraph, osg::TextureCubeMap* cubemap, osg::TexMat* texmat):
59            _subgraph(subgraph),
60            _cubemap(cubemap),
61            _texmat(texmat)
62            {
63                _updateCubemapFace = 0;
64                _clearColor = osg::Vec4(1,1,1,1);
65                _localState[0] = new osg::StateSet;
66                _localState[1] = new osg::StateSet;
67                _localState[2] = new osg::StateSet;
68                _localState[3] = new osg::StateSet;
69                _localState[4] = new osg::StateSet;
70                _localState[5] = new osg::StateSet;
71            }
72
73        virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
74        {
75            osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);
76            if (cv && _cubemap.valid() && _subgraph.valid())
77            {
78                const osg::Vec4 clearColArray[] =
79                {
80                    osg::Vec4(0, 0, 1, 1), // +X
81                    osg::Vec4(1, 0.7f, 0, 1), // -X
82                    osg::Vec4(0, 1, 1, 1), // +Y
83                    osg::Vec4(1, 1, 0, 1), // -Y
84                    osg::Vec4(1, 0, 0, 1), // +Z
85                    osg::Vec4(0, 1, 0, 1)  // -Z
86                };
87
88                osg::Quat q;
89                cv->getModelViewMatrix().get(q);
90                const osg::Matrix C = osg::Matrix::rotate( q.inverse() );
91                _texmat->setMatrix(C);
92
93#if UPDATE_ONE_IMAGE_PER_FRAME
94                if ((_updateCubemapFace >= 0) && (_updateCubemapFace <= 5))
95                {
96                    _clearColor = clearColArray[_updateCubemapFace];
97                    doPreRender(*cv, _updateCubemapFace++);
98                }
99#else
100                while (_updateCubemapFace<6)
101                {
102                    _clearColor = clearColArray[_updateCubemapFace];
103                    doPreRender(*cv, _updateCubemapFace++);
104                }
105#endif
106            }
107
108            // must traverse the subgraph           
109            traverse(node,nv);
110        }
111       
112        void doPreRender(osgUtil::CullVisitor& cv, const int nFace);
113       
114        struct ImageData
115        {
116            ImageData(const osg::Vec3& dir, const osg::Vec3& up) : _dir(dir), _up(up) {}
117            osg::Vec3 _dir;
118            osg::Vec3 _up;
119        };
120
121        osg::ref_ptr<osg::Node> _subgraph;
122        osg::ref_ptr<osg::TextureCubeMap> _cubemap;
123        osg::ref_ptr<osg::StateSet> _localState[6];
124        osg::ref_ptr<osg::TexMat> _texmat;
125        osg::Vec4 _clearColor;
126        int _updateCubemapFace;
127};
128
129
130void PrerenderCullCallback::doPreRender(osgUtil::CullVisitor& cv, const int nFace)
131{
132    const ImageData id[] =
133    {
134        ImageData( osg::Vec3( 1,  0,  0), osg::Vec3( 0, -1,  0) ), // +X
135        ImageData( osg::Vec3(-1,  0,  0), osg::Vec3( 0, -1,  0) ), // -X
136        ImageData( osg::Vec3( 0,  1,  0), osg::Vec3( 0,  0,  1) ), // +Y
137        ImageData( osg::Vec3( 0, -1,  0), osg::Vec3( 0,  0, -1) ), // -Y
138        ImageData( osg::Vec3( 0,  0,  1), osg::Vec3( 0, -1,  0) ), // +Z
139        ImageData( osg::Vec3( 0,  0, -1), osg::Vec3( 0, -1,  0) )  // -Z
140    };
141
142    osg::Image* image = _cubemap->getImage((osg::TextureCubeMap::Face)nFace);
143    osg::Vec3 dir = id[nFace]._dir;
144    osg::Vec3 up  = id[nFace]._up;
145
146    const osg::BoundingSphere& bs = _subgraph->getBound();
147    if (!bs.valid())
148    {
149        osg::notify(osg::WARN) << "bb invalid"<<_subgraph.get()<<std::endl;
150        return;
151    }
152
153    // create the render to texture stage.
154    osg::ref_ptr<osgUtil::RenderToTextureStage> rtts = new osgUtil::RenderToTextureStage;
155
156    // set up lighting.
157    // currently ignore lights in the scene graph itself..
158    // will do later.
159    osgUtil::RenderStage* previous_stage = cv.getCurrentRenderBin()->_stage;
160
161    // set up the background color and clear mask.
162    rtts->setClearColor(_clearColor);
163
164    // ABJ: use default (color+depth)
165    rtts->setClearMask(previous_stage->getClearMask());
166
167    // set up to charge the same RenderStageLighting is the parent previous stage.
168    rtts->setRenderStageLighting(previous_stage->getRenderStageLighting());
169
170    // record the render bin, to be restored after creation
171    // of the render to text
172    osgUtil::RenderBin* previousRenderBin = cv.getCurrentRenderBin();
173
174    // set the current renderbin to be the newly created stage.
175    cv.setCurrentRenderBin(rtts.get());
176
177
178    float znear = 1.0f*bs.radius();
179    float zfar  = 3.0f*bs.radius();
180       
181    znear *= 0.9f;
182    zfar *= 1.1f;
183
184    // set up projection.
185    const double fovy = 90.0;
186    const double aspectRatio = 1.0;
187    osg::RefMatrix* projection = new osg::RefMatrix;
188    projection->makePerspective(fovy, aspectRatio, znear, zfar);
189
190    cv.pushProjectionMatrix(projection);
191
192    osg::RefMatrix* matrix = new osg::RefMatrix;
193    osg::Vec3 eye    = bs.center(); eye.z() = 0.0f;
194    osg::Vec3 center = eye + dir;
195    matrix->makeLookAt(eye, center, up);
196
197    cv.pushModelViewMatrix(matrix);
198
199    cv.pushStateSet(_localState[nFace].get());
200
201    {
202        // traverse the subgraph
203        _subgraph->accept(cv);
204    }
205
206    cv.popStateSet();
207
208    // restore the previous model view matrix.
209    cv.popModelViewMatrix();
210
211    // restore the previous model view matrix.
212    cv.popProjectionMatrix();
213
214    // restore the previous renderbin.
215    cv.setCurrentRenderBin(previousRenderBin);
216
217    if (rtts->_renderGraphList.size()==0 && rtts->_bins.size()==0)
218    {
219        // getting to this point means that all the subgraph has been
220        // culled by small feature culling or is beyond LOD ranges.
221        return;
222    }
223
224    int height = 128;
225    int width  = 128;
226
227    const osg::Viewport& viewport = *cv.getViewport();
228
229    // offset the impostor viewport from the center of the main window
230    // viewport as often the edges of the viewport might be obscured by
231    // other windows, which can cause image/reading writing problems.
232    int center_x = viewport.x()+viewport.width()/2;
233    int center_y = viewport.y()+viewport.height()/2;
234
235    osg::Viewport* new_viewport = new osg::Viewport;
236    new_viewport->setViewport(center_x-width/2,center_y-height/2,width,height);
237    rtts->setViewport(new_viewport);
238   
239    _localState[nFace]->setAttribute(new_viewport);
240
241    // and the render to texture stage to the current stages
242    // dependancy list.
243    cv.getCurrentRenderBin()->_stage->addToDependencyList(rtts.get());
244
245    // if one exist attach image to the RenderToTextureStage.
246//  if (_image.valid()) rtts->setImage(_image.get());
247    if (image) rtts->setImage(image);
248}
249
250
251osg::Drawable* makeGeometry()
252{
253    const float radius = 20;
254    return new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.0f,0.0f,0.0f),radius));
255}
256
257
258osg::Node* createPreRenderSubGraph(osg::Node* subgraph)
259{
260    if (!subgraph) return 0;
261 
262    // create the quad to visualize.
263    osg::Drawable* geom = makeGeometry();
264    geom->setSupportsDisplayList(false);
265
266    // new we need to add the texture to the Drawable, we do so by creating a
267    // StateSet to contain the Texture StateAttribute.
268    osg::StateSet* stateset = new osg::StateSet;
269
270    osg::TextureCubeMap* cubemap = new osg::TextureCubeMap;
271
272    // set up the textures
273    osg::Image* imagePosX = new osg::Image;
274    osg::Image* imageNegX = new osg::Image;
275    osg::Image* imagePosY = new osg::Image;
276    osg::Image* imageNegY = new osg::Image;
277    osg::Image* imagePosZ = new osg::Image;
278    osg::Image* imageNegZ = new osg::Image;
279
280    imagePosX->setInternalTextureFormat(GL_RGB);
281    imageNegX->setInternalTextureFormat(GL_RGB);
282    imagePosY->setInternalTextureFormat(GL_RGB);
283    imageNegY->setInternalTextureFormat(GL_RGB);
284    imagePosZ->setInternalTextureFormat(GL_RGB);
285    imageNegZ->setInternalTextureFormat(GL_RGB);
286
287    cubemap->setImage(osg::TextureCubeMap::POSITIVE_X, imagePosX);
288    cubemap->setImage(osg::TextureCubeMap::NEGATIVE_X, imageNegX);
289    cubemap->setImage(osg::TextureCubeMap::POSITIVE_Y, imagePosY);
290    cubemap->setImage(osg::TextureCubeMap::NEGATIVE_Y, imageNegY);
291    cubemap->setImage(osg::TextureCubeMap::POSITIVE_Z, imagePosZ);
292    cubemap->setImage(osg::TextureCubeMap::NEGATIVE_Z, imageNegZ);
293
294    cubemap->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
295    cubemap->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
296    cubemap->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE);
297    cubemap->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
298    cubemap->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
299    stateset->setTextureAttributeAndModes(0, cubemap, osg::StateAttribute::ON);
300
301    osg::TexGen *texgen = new osg::TexGen;
302    texgen->setMode(osg::TexGen::REFLECTION_MAP);
303    stateset->setTextureAttributeAndModes(0, texgen, osg::StateAttribute::ON);
304
305    osg::TexMat* texmat = new osg::TexMat;
306    stateset->setTextureAttribute(0, texmat);
307
308    stateset->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
309
310    geom->setStateSet(stateset);
311
312    osg::Geode* geode = new osg::Geode;
313    geode->addDrawable(geom);
314
315    // Geodes can't have cull callback so create extra Group to attach cullcallback.
316    osg::Group* parent = new osg::Group;
317   
318    parent->setUpdateCallback(new PrerenderAppCallback(subgraph));
319   
320    parent->setCullCallback(new PrerenderCullCallback(subgraph, cubemap, texmat));
321 
322    parent->addChild(geode);
323   
324    return parent;
325}
326
327
328struct DrawableCullCallback : public osg::Drawable::CullCallback
329{
330    DrawableCullCallback(osg::TexMat* texmat) : _texmat(texmat)
331    {}
332
333    virtual bool cull(osg::NodeVisitor* nv, osg::Drawable* /*drawable*/, osg::State* /*state*/) const
334    {
335        osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);
336        if (cv)
337        {
338            osg::Quat q;
339            cv->getModelViewMatrix().get(q);
340            const osg::Matrix C = osg::Matrix::rotate( q.inverse() );
341            _texmat->setMatrix(C);
342        }
343        return false;
344    }
345
346    mutable osg::ref_ptr<osg::TexMat> _texmat;
347};
348
349osg::Node* createReferenceSphere()
350{
351    const float radius = 10;
352    osg::Drawable* sphere = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.0f,0.0f,0.0f),radius));
353
354    osg::StateSet* stateset = new osg::StateSet;
355    sphere->setStateSet(stateset);
356
357    osg::TextureCubeMap* cubemap = new osg::TextureCubeMap;
358    #define CUBEMAP_FILENAME(face) "Cubemap_axis/" #face ".png"
359
360    osg::Image* imagePosX = osgDB::readImageFile(CUBEMAP_FILENAME(posx));
361    osg::Image* imageNegX = osgDB::readImageFile(CUBEMAP_FILENAME(negx));
362    osg::Image* imagePosY = osgDB::readImageFile(CUBEMAP_FILENAME(posy));
363    osg::Image* imageNegY = osgDB::readImageFile(CUBEMAP_FILENAME(negy));
364    osg::Image* imagePosZ = osgDB::readImageFile(CUBEMAP_FILENAME(posz));
365    osg::Image* imageNegZ = osgDB::readImageFile(CUBEMAP_FILENAME(negz));
366
367    if (imagePosX && imageNegX && imagePosY && imageNegY && imagePosZ && imageNegZ)
368    {
369        cubemap->setImage(osg::TextureCubeMap::POSITIVE_X, imagePosX);
370        cubemap->setImage(osg::TextureCubeMap::NEGATIVE_X, imageNegX);
371        cubemap->setImage(osg::TextureCubeMap::POSITIVE_Y, imagePosY);
372        cubemap->setImage(osg::TextureCubeMap::NEGATIVE_Y, imageNegY);
373        cubemap->setImage(osg::TextureCubeMap::POSITIVE_Z, imagePosZ);
374        cubemap->setImage(osg::TextureCubeMap::NEGATIVE_Z, imageNegZ);
375
376        cubemap->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
377        cubemap->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
378        cubemap->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE);
379        cubemap->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
380        cubemap->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
381        stateset->setTextureAttributeAndModes(0, cubemap, osg::StateAttribute::ON);
382    }
383
384    osg::TexGen *texgen = new osg::TexGen;
385    texgen->setMode(osg::TexGen::REFLECTION_MAP);
386    stateset->setTextureAttributeAndModes(0, texgen, osg::StateAttribute::ON);
387
388    osg::TexMat* texmat = new osg::TexMat;
389    stateset->setTextureAttribute(0, texmat);
390
391    stateset->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
392
393
394    sphere->setCullCallback(new DrawableCullCallback(texmat));
395
396    osg::Geode* geode = new osg::Geode();
397    geode->addDrawable(sphere);
398
399    return geode;
400}
401
402int main( int argc, char **argv )
403{
404    // use an ArgumentParser object to manage the program arguments.
405    osg::ArgumentParser arguments(&argc,argv);
406
407    // set up the usage document, in case we need to print out how to use this program.
408    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates pre rendering of scene to a texture, and then apply this texture to geometry.");
409    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
410    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
411   
412    // construct the viewer.
413    osgProducer::Viewer viewer(arguments);
414
415    // set up the value with sensible default event handlers.
416    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
417
418    // get details on keyboard and mouse bindings used by the viewer.
419    viewer.getUsage(*arguments.getApplicationUsage());
420
421    // if user request help write it out to cout.
422    if (arguments.read("-h") || arguments.read("--help"))
423    {
424        arguments.getApplicationUsage()->write(std::cout);
425        return 1;
426    }
427
428    // any option left unread are converted into errors to write out later.
429    arguments.reportRemainingOptionsAsUnrecognized();
430
431    // report any errors if they have occured when parsing the program aguments.
432    if (arguments.errors())
433    {
434        arguments.writeErrorMessages(std::cout);
435        return 1;
436    }
437/*   
438    if (arguments.argc()<=1)
439    {
440        arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
441        return 1;
442    }
443*/
444   
445    osg::Group* rootNode = new osg::Group();
446
447#if 1
448    osg::Node* sky = osgDB::readNodeFile("skydome.osg");
449    if (sky)
450        rootNode->addChild(createPreRenderSubGraph(sky));
451#endif
452
453#if 1
454    osg::PositionAttitudeTransform* pat = new osg::PositionAttitudeTransform;
455    pat->setPosition(osg::Vec3(0,0,50));
456    pat->addChild(createReferenceSphere());
457    rootNode->addChild(pat);
458#endif
459    // load the nodes from the commandline arguments.
460    osg::Node* loadedModel = osgDB::readNodeFiles(arguments);
461    if (loadedModel)
462        rootNode->addChild(loadedModel);
463
464
465    // add model to the viewer.
466    viewer.setSceneData( rootNode );
467
468
469    // create the windows and run the threads.
470    viewer.realize();
471
472    while( !viewer.done() )
473    {
474        // wait for all cull and draw threads to complete.
475        viewer.sync();
476
477        // update the scene by traversing it with the the update visitor which will
478        // call all node update callbacks and animations.
479        viewer.update();
480         
481        // fire off the cull and draw traversals of the scene.
482        viewer.frame();
483       
484    }
485   
486    // wait for all cull and draw threads to complete before exit.
487    viewer.sync();
488
489    return 0;
490}
Note: See TracBrowser for help on using the browser.