root/OpenSceneGraph/trunk/examples/osgreflect/osgreflect.cpp @ 12529

Revision 12529, 13.9 kB (checked in by robert, 3 years ago)

Replaced .osg with .osgt file usage

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
RevLine 
[6941]1/* OpenSceneGraph example, osgreflect.
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.
[1673]17*/
18
19#include <osg/Node>
20#include <osg/Geometry>
21#include <osg/Geode>
22#include <osg/Notify>
23#include <osg/MatrixTransform>
24#include <osg/Texture2D>
25#include <osg/BlendFunc>
26#include <osg/Stencil>
27#include <osg/ColorMask>
28#include <osg/Depth>
29#include <osg/ClipNode>
[4713]30#include <osg/AnimationPath>
[1673]31
32#include <osgDB/ReadFile>
[6163]33#include <osgDB/WriteFile>
34
[1673]35#include <osgUtil/Optimizer>
[5954]36#include <osgViewer/Viewer>
[1673]37
[5954]38#include <iostream>
39
[1673]40//
41// A simple demo demonstrating planar reflections using multiple renderings
42// of a subgraph, overriding of state attribures and use of the stencil buffer.
43//
44// The multipass system implemented here is a variation if Mark Kilgard's
45// paper "Improving Shadows and Reflections via the Stencil Buffer" which
46// can be found on the developer parts of the NVidia web site.
47//
48// The variations comes from the fact that the mirrors stencil values
49// are done on the first pass, rather than the second as in Mark's paper.
50// The second pass is now Mark's first pass - drawing the unreflected scene,
51// but also unsets the stencil buffer.  This variation stops the unreflected
52// world poking through the mirror to be seen in the final rendering and
53// also obscures the world correctly when on the reverse side of the mirror.
54// Although there is still some unresolved issue with the clip plane needing
55// to be flipped when looking at the reverse side of the mirror.  Niether
56// of these issues are mentioned in the Mark's paper, but trip us up when
57// we apply them.
58
59
60osg::StateSet* createMirrorTexturedState(const std::string& filename)
61{
62    osg::StateSet* dstate = new osg::StateSet;
63    dstate->setMode(GL_CULL_FACE,osg::StateAttribute::OFF|osg::StateAttribute::PROTECTED);
64   
65    // set up the texture.
66    osg::Image* image = osgDB::readImageFile(filename.c_str());
67    if (image)
68    {
69        osg::Texture2D* texture = new osg::Texture2D;
70        texture->setImage(image);
71        dstate->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON|osg::StateAttribute::PROTECTED);
72    }
73   
74    return dstate;
75}
76
77
78osg::Drawable* createMirrorSurface(float xMin,float xMax,float yMin,float yMax,float z)
79{
80   
81    // set up the drawstate.
82
83    // set up the Geometry.
84    osg::Geometry* geom = new osg::Geometry;
85
86    osg::Vec3Array* coords = new osg::Vec3Array(4);
87    (*coords)[0].set(xMin,yMax,z);
88    (*coords)[1].set(xMin,yMin,z);
89    (*coords)[2].set(xMax,yMin,z);
90    (*coords)[3].set(xMax,yMax,z);
91    geom->setVertexArray(coords);
92
93    osg::Vec3Array* norms = new osg::Vec3Array(1);
94    (*norms)[0].set(0.0f,0.0f,1.0f);
95    geom->setNormalArray(norms);
96    geom->setNormalBinding(osg::Geometry::BIND_OVERALL);
97
98    osg::Vec2Array* tcoords = new osg::Vec2Array(4);
99    (*tcoords)[0].set(0.0f,1.0f);
100    (*tcoords)[1].set(0.0f,0.0f);
101    (*tcoords)[2].set(1.0f,0.0f);
102    (*tcoords)[3].set(1.0f,1.0f);
103    geom->setTexCoordArray(0,tcoords);
104   
105    osg::Vec4Array* colours = new osg::Vec4Array(1);
106    (*colours)[0].set(1.0f,1.0f,1.0,1.0f);
107    geom->setColorArray(colours);
108    geom->setColorBinding(osg::Geometry::BIND_OVERALL);
109
110    geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));
111
112    return geom;
113}
114
115osg::Node* createMirroredScene(osg::Node* model)
116{
117
118    // calculate where to place the mirror according to the
119    // loaded models bounding sphere.
120    const osg::BoundingSphere& bs = model->getBound();
121
122    float width_factor = 1.5;
123    float height_factor = 0.3;
124   
125    float xMin = bs.center().x()-bs.radius()*width_factor;
126    float xMax = bs.center().x()+bs.radius()*width_factor;
127    float yMin = bs.center().y()-bs.radius()*width_factor;
128    float yMax = bs.center().y()+bs.radius()*width_factor;
129   
130    float z = bs.center().z()-bs.radius()*height_factor;
131   
132   
133    // create a textured, transparent node at the appropriate place.
134    osg::Drawable* mirror = createMirrorSurface(xMin,xMax,yMin,yMax,z);
135   
136
137    osg::MatrixTransform* rootNode = new osg::MatrixTransform;
138    rootNode->setMatrix(osg::Matrix::rotate(osg::inDegrees(45.0f),1.0f,0.0f,0.0f));
139       
140    // make sure that the global color mask exists.
141    osg::ColorMask* rootColorMask = new osg::ColorMask;
142    rootColorMask->setMask(true,true,true,true);       
143   
144    // set up depth to be inherited by the rest of the scene unless
145    // overrideen. this is overridden in bin 3.
146    osg::Depth* rootDepth = new osg::Depth;
147    rootDepth->setFunction(osg::Depth::LESS);
148    rootDepth->setRange(0.0,1.0);
149
150    osg::StateSet* rootStateSet = new osg::StateSet();       
151    rootStateSet->setAttribute(rootColorMask);
152    rootStateSet->setAttribute(rootDepth);
153
154    rootNode->setStateSet(rootStateSet);
155
156
157    // bin1  - set up the stencil values and depth for mirror.
158    {
159   
160        // set up the stencil ops so that the stencil buffer get set at
161        // the mirror plane
162        osg::Stencil* stencil = new osg::Stencil;
[4852]163        stencil->setFunction(osg::Stencil::ALWAYS,1,~0u);
[1673]164        stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::REPLACE);
165       
166        // switch off the writing to the color bit planes.
167        osg::ColorMask* colorMask = new osg::ColorMask;
168        colorMask->setMask(false,false,false,false);
169       
170        osg::StateSet* statesetBin1 = new osg::StateSet();       
171        statesetBin1->setRenderBinDetails(1,"RenderBin");
172        statesetBin1->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
173        statesetBin1->setAttributeAndModes(stencil,osg::StateAttribute::ON);
174        statesetBin1->setAttribute(colorMask);
175       
176        // set up the mirror geode.
177        osg::Geode* geode = new osg::Geode;
178        geode->addDrawable(mirror);
179        geode->setStateSet(statesetBin1);
180       
181        rootNode->addChild(geode);
182       
183    }
184
185    // bin one - draw scene without mirror or reflection, unset
186    // stencil values where scene is infront of mirror and hence
187    // occludes the mirror.
188    {       
189        osg::Stencil* stencil = new osg::Stencil;
[4852]190        stencil->setFunction(osg::Stencil::ALWAYS,0,~0u);
[1673]191        stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::REPLACE);
192
193        osg::StateSet* statesetBin2 = new osg::StateSet();       
194        statesetBin2->setRenderBinDetails(2,"RenderBin");
195        statesetBin2->setAttributeAndModes(stencil,osg::StateAttribute::ON);
196       
197
198        osg::Group* groupBin2 = new osg::Group();
199        groupBin2->setStateSet(statesetBin2);
200        groupBin2->addChild(model);
201       
202        rootNode->addChild(groupBin2);
203    }
204       
205    // bin3  - set up the depth to the furthest depth value
206    {
207   
208        // set up the stencil ops so that only operator on this mirrors stencil value.
209        osg::Stencil* stencil = new osg::Stencil;
[4852]210        stencil->setFunction(osg::Stencil::EQUAL,1,~0u);
[1673]211        stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
212       
213        // switch off the writing to the color bit planes.
214        osg::ColorMask* colorMask = new osg::ColorMask;
215        colorMask->setMask(false,false,false,false);
216
217        // set up depth so all writing to depth goes to maximum depth.
218        osg::Depth* depth = new osg::Depth;
219        depth->setFunction(osg::Depth::ALWAYS);
220        depth->setRange(1.0,1.0);
221
222        osg::StateSet* statesetBin3 = new osg::StateSet();
223        statesetBin3->setRenderBinDetails(3,"RenderBin");
224        statesetBin3->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
225        statesetBin3->setAttributeAndModes(stencil,osg::StateAttribute::ON);
226        statesetBin3->setAttribute(colorMask);
227        statesetBin3->setAttribute(depth);
228       
229        // set up the mirror geode.
230        osg::Geode* geode = new osg::Geode;
231        geode->addDrawable(mirror);
232        geode->setStateSet(statesetBin3);
233       
234        rootNode->addChild(geode);
235       
236    }
237
238    // bin4  - draw the reflection.
239    {
240   
241        // now create the 'reflection' of the loaded model by applying
242        // create a Transform which flips the loaded model about the z axis
243        // relative to the mirror node, the loadedModel is added to the
244        // Transform so now appears twice in the scene, but is shared so there
245        // is negligable memory overhead.  Also use an osg::StateSet
246        // attached to the Transform to override the face culling on the subgraph
247        // to prevert an 'inside' out view of the reflected model.
248        // set up the stencil ops so that only operator on this mirrors stencil value.
249
250
251
252        // this clip plane removes any of the scene which when mirror would
253        // poke through the mirror.  However, this clip plane should really
254        // flip sides once the eye point goes to the back of the mirror...
255        osg::ClipPlane* clipplane = new osg::ClipPlane;
[3755]256        clipplane->setClipPlane(0.0,0.0,-1.0,z);
[1673]257        clipplane->setClipPlaneNum(0);
258
259        osg::ClipNode* clipNode = new osg::ClipNode;
260        clipNode->addClipPlane(clipplane);
261
262
263        osg::StateSet* dstate = clipNode->getOrCreateStateSet();
264        dstate->setRenderBinDetails(4,"RenderBin");
265        dstate->setMode(GL_CULL_FACE,osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF);
266
267        osg::Stencil* stencil = new osg::Stencil;
[4852]268        stencil->setFunction(osg::Stencil::EQUAL,1,~0u);
[1673]269        stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
270        dstate->setAttributeAndModes(stencil,osg::StateAttribute::ON);
271
272        osg::MatrixTransform* reverseMatrix = new osg::MatrixTransform;
273        reverseMatrix->setStateSet(dstate);
274        reverseMatrix->preMult(osg::Matrix::translate(0.0f,0.0f,-z)*
275                     osg::Matrix::scale(1.0f,1.0f,-1.0f)*
276                     osg::Matrix::translate(0.0f,0.0f,z));
277
278        reverseMatrix->addChild(model);
279
280        clipNode->addChild(reverseMatrix);
281
282        rootNode->addChild(clipNode);
283   
284    }
285
286
287    // bin5  - draw the textured mirror and blend it with the reflection.
288    {
289   
290        // set up depth so all writing to depth goes to maximum depth.
291        osg::Depth* depth = new osg::Depth;
292        depth->setFunction(osg::Depth::ALWAYS);
293
294        osg::Stencil* stencil = new osg::Stencil;
[4852]295        stencil->setFunction(osg::Stencil::EQUAL,1,~0u);
[1673]296        stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::ZERO);
297
298        // set up additive blending.
299        osg::BlendFunc* trans = new osg::BlendFunc;
300        trans->setFunction(osg::BlendFunc::ONE,osg::BlendFunc::ONE);
301
302        osg::StateSet* statesetBin5 = createMirrorTexturedState("Images/tank.rgb");
303
304        statesetBin5->setRenderBinDetails(5,"RenderBin");
305        statesetBin5->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
306        statesetBin5->setAttributeAndModes(stencil,osg::StateAttribute::ON);
307        statesetBin5->setAttributeAndModes(trans,osg::StateAttribute::ON);
308        statesetBin5->setAttribute(depth);
309       
310        // set up the mirror geode.
311        osg::Geode* geode = new osg::Geode;
312        geode->addDrawable(mirror);
313        geode->setStateSet(statesetBin5);
314       
315        rootNode->addChild(geode);
316
317    }
318   
319    return rootNode;
320}
321
322
323/////////////////////////////////////////////////////////////////////////////////////////////////////////
324//
325// create the viewer
326// load a model
327// decoate the model so it renders using a multipass stencil buffer technique for planar reflections.
328// release the viewer
329// run main loop.
330//
331int main( int argc, char **argv )
332{
333    // use an ArgumentParser object to manage the program arguments.
334    osg::ArgumentParser arguments(&argc,argv);
335
336    // construct the viewer.
[5954]337    osgViewer::Viewer viewer;
[1673]338
339    // read the scene from the list of file specified commandline args.
340    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
[6916]341   
342    // if not loaded assume no arguments passed in, try use default mode instead.
[12529]343    if (!loadedModel) loadedModel = osgDB::readNodeFile("cessna.osgt");
[1673]344
345    // if no model has been successfully loaded report failure.
346    if (!loadedModel)
347    {
[1815]348        std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
[1673]349        return 1;
350    }
351
352
[7648]353    // optimize the scene graph, remove redundant nodes and state etc.
[1673]354    osgUtil::Optimizer optimizer;
355    optimizer.optimize(loadedModel.get());
356
357    // add a transform with a callback to animate the loaded model.
358    osg::ref_ptr<osg::MatrixTransform> loadedModelTransform = new osg::MatrixTransform;
359    loadedModelTransform->addChild(loadedModel.get());
360
[4713]361    osg::ref_ptr<osg::NodeCallback> nc = new osg::AnimationPathCallback(loadedModelTransform->getBound().center(),osg::Vec3(0.0f,0.0f,1.0f),osg::inDegrees(45.0f));
[1673]362    loadedModelTransform->setUpdateCallback(nc.get());
363
364
365    // finally decorate the loaded model so that it has the required multipass/bin scene graph to do the reflection effect.
366    osg::ref_ptr<osg::Node> rootNode = createMirroredScene(loadedModelTransform.get());
367
368    // set the scene to render
369    viewer.setSceneData(rootNode.get());
370
[5966]371    // hint to tell viewer to request stencil buffer when setting up windows
372    osg::DisplaySettings::instance()->setMinimumNumStencilBits(8);
[1673]373
[12529]374    //osgDB::writeNodeFile(*rootNode, "test.osgt");
[6163]375
[5954]376    return viewer.run();
[1673]377
378}
Note: See TracBrowser for help on using the browser.