root/OpenSceneGraph/trunk/examples/osgtexture3D/osgtexture3D.cpp @ 5763

Revision 5763, 10.8 kB (checked in by robert, 7 years ago)

Added support for float or double osg::Plane, and the default osg::Plane to double.
Performance tests on big models did not indicate any performance penalty in using doubles over floats,
so the move to doubles should mainly impact precision improvements for whole earth databases.

Also made improvements to osgUtil::PlaneIntersector? and osgSim::ElevationSlice? classes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <osg/Node>
2#include <osg/Geometry>
3#include <osg/Notify>
4#include <osg/Texture3D>
5#include <osg/TexGen>
6#include <osg/Geode>
7
8#include <osgDB/Registry>
9#include <osgDB/ReadFile>
10
11#include <osgProducer/Viewer>
12
13
14//
15// A simple demo demonstrating different texturing modes,
16// including using of texture extensions.
17//
18
19
20typedef std::vector< osg::ref_ptr<osg::Image> > ImageList;
21
22
23class ConstructStateCallback : public osgProducer::OsgCameraGroup::RealizeCallback
24{
25    public:
26        ConstructStateCallback(osg::Node* node):_node(node),_initialized(false) {}
27       
28        osg::StateSet* constructState()
29        {
30       
31            // read 4 2d images
32            osg::ref_ptr<osg::Image> image_0 = osgDB::readImageFile("Images/lz.rgb");
33            osg::ref_ptr<osg::Image> image_1 = osgDB::readImageFile("Images/reflect.rgb");
34            osg::ref_ptr<osg::Image> image_2 = osgDB::readImageFile("Images/tank.rgb");
35            osg::ref_ptr<osg::Image> image_3 = osgDB::readImageFile("Images/skymap.jpg");
36
37            if (!image_0 || !image_1 || !image_2 || !image_3)
38            {
39                std::cout << "Warning: could not open files."<<std::endl;
40                return new osg::StateSet;
41            }
42
43            if (image_0->getPixelFormat()!=image_1->getPixelFormat() || image_0->getPixelFormat()!=image_2->getPixelFormat() || image_0->getPixelFormat()!=image_3->getPixelFormat())
44            {
45                std::cout << "Warning: image pixel formats not compatible."<<std::endl;
46                return new osg::StateSet;
47            }
48
49            // get max 3D texture size
50            GLint textureSize = osg::Texture3D::getExtensions(0,true)->maxTexture3DSize();
51            if (textureSize > 256)
52                textureSize = 256;
53
54            // scale them all to the same size.
55            image_0->scaleImage(textureSize,textureSize,1);
56            image_1->scaleImage(textureSize,textureSize,1);
57            image_2->scaleImage(textureSize,textureSize,1);
58            image_3->scaleImage(textureSize,textureSize,1);
59
60
61            // then allocated a 3d image to use for texturing.
62            osg::Image* image_3d = new osg::Image;
63            image_3d->allocateImage(textureSize,textureSize,4,
64                                    image_0->getPixelFormat(),image_0->getDataType());
65
66            // copy the 2d images into the 3d image.
67            image_3d->copySubImage(0,0,0,image_0.get());
68            image_3d->copySubImage(0,0,1,image_1.get());
69            image_3d->copySubImage(0,0,2,image_2.get());
70            image_3d->copySubImage(0,0,3,image_3.get());
71
72            image_3d->setInternalTextureFormat(image_0->getInternalTextureFormat());       
73
74            // set up the 3d texture itself,
75            // note, well set the filtering up so that mip mapping is disabled,
76            // gluBuild3DMipsmaps doesn't do a very good job of handled the
77            // inbalanced dimensions of the 256x256x4 texture.
78            osg::Texture3D* texture3D = new osg::Texture3D;
79            texture3D->setFilter(osg::Texture3D::MIN_FILTER,osg::Texture3D::LINEAR);
80            texture3D->setFilter(osg::Texture3D::MAG_FILTER,osg::Texture3D::LINEAR);
81            texture3D->setWrap(osg::Texture3D::WRAP_R,osg::Texture3D::REPEAT);
82            texture3D->setImage(image_3d);
83
84
85            // create a texgen to generate a R texture coordinate, the geometry
86            // itself will supply the S & T texture coordinates.
87            // in the animateStateSet callback well alter this R value to
88            // move the texture through the 3d texture, 3d texture filtering
89            // will do the blending for us.
90            osg::TexGen* texgen = new osg::TexGen;
91            texgen->setMode(osg::TexGen::OBJECT_LINEAR);
92            texgen->setPlane(osg::TexGen::R, osg::Plane(0.0f,0.0f,0.0f,0.2f));
93
94            // create the StateSet to store the texture data
95            osg::StateSet* stateset = new osg::StateSet;
96            stateset->setTextureMode(0,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
97            stateset->setTextureAttribute(0,texgen);
98            stateset->setTextureAttributeAndModes(0,texture3D,osg::StateAttribute::ON);
99
100            return stateset;
101        }
102
103        virtual void operator()( osgProducer::OsgCameraGroup&, osgProducer::OsgSceneHandler& sh, const Producer::RenderSurface& )
104        {
105            {
106                OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
107
108                if (!_initialized)
109                {
110
111                    // only initialize state once, only need for cases where multiple graphics contexts are
112                    // if which case this callback can get called multiple times.
113                    _initialized = true;
114
115                    if (_node) _node->setStateSet(constructState());
116                }           
117
118            }
119           
120            // now safe to con
121            sh.init();
122           
123        }
124       
125       
126        OpenThreads::Mutex  _mutex;
127        osg::Node*          _node;
128        bool                _initialized;
129       
130};
131
132class UpdateStateCallback : public osg::NodeCallback
133{
134    public:
135        UpdateStateCallback() {}
136       
137        void animateState(osg::StateSet* stateset)
138        {
139            // here we simply get any existing texgen, and then increment its
140            // plane, pushing the R coordinate through the texture.
141            osg::StateAttribute* attribute = stateset->getTextureAttribute(0,osg::StateAttribute::TEXGEN);
142            osg::TexGen* texgen = dynamic_cast<osg::TexGen*>(attribute);
143            if (texgen)
144            {
145                texgen->getPlane(osg::TexGen::R)[3] += 0.001f;
146            }
147
148        }
149
150        virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
151        {
152
153            osg::StateSet* stateset = node->getStateSet();
154            if (stateset)
155            {
156                // we have an exisitng stateset, so lets animate it.
157                animateState(stateset);
158            }
159
160            // note, callback is repsonsible for scenegraph traversal so
161            // should always include call the traverse(node,nv) to ensure
162            // that the rest of cullbacks and the scene graph are traversed.
163            traverse(node,nv);
164        }     
165};
166
167/** create 2,2 square with center at 0,0,0 and aligned along the XZ plan */
168osg::Drawable* createSquare(float textureCoordMax=1.0f)
169{
170    // set up the Geometry.
171    osg::Geometry* geom = new osg::Geometry;
172
173    osg::Vec3Array* coords = new osg::Vec3Array(4);
174    (*coords)[0].set(-1.0f,0.0f,1.0f);
175    (*coords)[1].set(-1.0f,0.0f,-1.0f);
176    (*coords)[2].set(1.0f,0.0f,-1.0f);
177    (*coords)[3].set(1.0f,0.0f,1.0f);
178    geom->setVertexArray(coords);
179
180    osg::Vec3Array* norms = new osg::Vec3Array(1);
181    (*norms)[0].set(0.0f,-1.0f,0.0f);
182    geom->setNormalArray(norms);
183    geom->setNormalBinding(osg::Geometry::BIND_OVERALL);
184
185    osg::Vec2Array* tcoords = new osg::Vec2Array(4);
186    (*tcoords)[0].set(0.0f,textureCoordMax);
187    (*tcoords)[1].set(0.0f,0.0f);
188    (*tcoords)[2].set(textureCoordMax,0.0f);
189    (*tcoords)[3].set(textureCoordMax,textureCoordMax);
190    geom->setTexCoordArray(0,tcoords);
191   
192    geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));
193
194    return geom;
195}
196
197osg::Node* createModel()
198{
199
200    // create the geometry of the model, just a simple 2d quad right now.   
201    osg::Geode* geode = new osg::Geode;
202    geode->addDrawable(createSquare());
203
204    // normally we'd create the stateset's to contain all the textures
205    // etc here, but, the above technique uses osg::Image::scaleImage and
206    // osg::Image::copySubImage() which are implemented with OpenGL utility
207    // library, which unfortunately can't be used until we have a valid
208    // OpenGL context, and at this point in initilialization we don't have
209    // a valid OpenGL context, so we have to delay creation of state until
210    // there is a valid OpenGL context.  I'll manage this by using an
211    // app callback which will create the state during the first traversal.
212    // A bit hacky, and my plan is to reimplement the osg::scaleImage and
213    // osg::Image::copySubImage() without using GLU which will get round
214    // this current limitation.
215    geode->setUpdateCallback(new UpdateStateCallback());
216   
217    return geode;
218
219}
220
221
222int main( int argc, char **argv )
223{
224
225    // use an ArgumentParser object to manage the program arguments.
226    osg::ArgumentParser arguments(&argc,argv);
227   
228    // set up the usage document, in case we need to print out how to use this program.
229    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates use of 3D textures.");
230    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
231    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
232   
233
234    // construct the viewer.
235    osgProducer::Viewer viewer(arguments);
236
237    // set up the value with sensible default event handlers.
238    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
239
240    // get details on keyboard and mouse bindings used by the viewer.
241    viewer.getUsage(*arguments.getApplicationUsage());
242
243    // if user request help write it out to cout.
244    if (arguments.read("-h") || arguments.read("--help"))
245    {
246        arguments.getApplicationUsage()->write(std::cout);
247        return 1;
248    }
249
250    // any option left unread are converted into errors to write out later.
251    arguments.reportRemainingOptionsAsUnrecognized();
252
253    // report any errors if they have occured when parsing the program aguments.
254    if (arguments.errors())
255    {
256        arguments.writeErrorMessages(std::cout);
257        return 1;
258    }
259   
260    // create a model from the images.
261    osg::Node* rootNode = createModel();
262
263    if (rootNode)
264    {
265
266        // set the scene to render
267        viewer.setSceneData(rootNode);
268       
269        // the construct state uses gl commands to resize images so we are forced
270        // to only call it once a valid graphics context has been established,
271        // for that we use a realize callback.
272        viewer.setRealizeCallback(new ConstructStateCallback(rootNode));
273
274        // create the windows and run the threads.
275        viewer.realize();
276
277        while( !viewer.done() )
278        {
279            // wait for all cull and draw threads to complete.
280            viewer.sync();
281
282            // update the scene by traversing it with the the update visitor which will
283            // call all node update callbacks and animations.
284            viewer.update();
285
286            // fire off the cull and draw traversals of the scene.
287            viewer.frame();
288
289        }
290       
291        // wait for all cull and draw threads to complete.
292        viewer.sync();
293
294        // run a clean up frame to delete all OpenGL objects.
295        viewer.cleanup_frame();
296
297        // wait for all the clean up frame to complete.
298        viewer.sync();
299    }   
300   
301    return 0;
302}
Note: See TracBrowser for help on using the browser.