root/OpenSceneGraph/trunk/examples/osgimpostor/osgimpostor.cpp @ 1697

Revision 1697, 10.4 kB (checked in by robert, 11 years ago)

Ported osgGLUT based src/Demos across to being osgProducer based, and placed
them in the new examples/ directory.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <osg/Geometry>
2#include <osg/Impostor>
3#include <osg/Material>
4#include <osg/MatrixTransform>
5#include <osg/Quat>
6#include <osg/Geode>
7
8#include <osgUtil/InsertImpostorsVisitor>
9
10#include <osgDB/ReadFile>
11
12#include <osgGA/TrackballManipulator>
13#include <osgGA/FlightManipulator>
14#include <osgGA/DriveManipulator>
15
16#include <osgProducer/Viewer>
17
18#include "TestManipulator.h"
19
20
21#include <iostream>
22#include <list>
23
24// container storing all house nodes
25typedef osg::ref_ptr<osg::Node> NodePtr;
26typedef std::list<NodePtr>              NodeContainer;
27typedef NodeContainer::iterator NodeIterator;
28
29NodeContainer                                   nodes;
30
31//
32osg::Group * Root = 0;
33
34const int HOUSES_SIZE = 25000;          // total number of houses
35double XDim = 5000.0f;                          // area dimension +/- XDim
36double ZDim = 5000.0f;                          // area dimension +/- YDim
37
38int GridX = 20;                                         // number of grids in x direction
39int GridY = 20;                                         // number of grids in y direction
40
41bool UseImpostor = true;                        // use impostor (or do not use)
42
43float Threshold = 3000.0f;                      // distance where impostor are shown
44
45// create houses and store nodes in container
46void CreateHouses()
47{
48        int i;
49
50        GLubyte indices[48] = {
51                0, 2, 1,
52                3, 2, 0,
53                0, 4, 7,
54                7, 3, 0,
55                0, 1, 5,
56                5, 4, 0,
57                1, 6, 5,
58                2, 6, 1,
59                2, 3, 7,
60                2, 7, 6,
61                4, 8, 7,
62                5, 6, 9,
63                4, 5, 8,
64                8, 5, 9,
65                6, 7, 8,
66                8, 9, 6
67        };
68
69        // use the same color, normal and indices for all houses.
70        osg::Vec4Array* colors = new osg::Vec4Array(1);
71        (*colors)[0] = osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
72
73        // normals
74        osg::Vec3Array * normals = new osg::Vec3Array(16);
75        (*normals)[0] = osg::Vec3( 0.0f,  -0.0f, -1.0f);
76        (*normals)[1] = osg::Vec3( 0.0f,  -0.0f, -1.0f);
77        (*normals)[2] = osg::Vec3( 0.0f,  -1.0f,  0.0f);
78        (*normals)[3] = osg::Vec3( 0.0f,  -1.0f,  0.0f);
79        (*normals)[4] = osg::Vec3( 1.0f,  -0.0f,  0.0f);
80        (*normals)[5] = osg::Vec3( 1.0f,  -0.0f,  0.0f);
81        (*normals)[6] = osg::Vec3( 0.0f, 1.0f,  0.0f);
82        (*normals)[7] = osg::Vec3( 0.0f, 1.0f,  0.0f);
83        (*normals)[8] = osg::Vec3(-1.0f,  -0.0f,  0.0f);
84        (*normals)[9] = osg::Vec3(-1.0f,  -0.0f,  0.0f);
85        (*normals)[10] = osg::Vec3( 0.0f,  -0.928477f, 0.371391f);
86        (*normals)[11] = osg::Vec3( 0.0f, 0.928477f, 0.371391f);
87        (*normals)[12] = osg::Vec3( 0.707107f,  0.0f, 0.707107f);
88        (*normals)[13] = osg::Vec3( 0.707107f,  0.0f, 0.707107f);
89        (*normals)[14] = osg::Vec3(-0.707107f,  0.0f, 0.707107f);
90        (*normals)[15] = osg::Vec3(-0.707107f,  0.0f, 0.707107f);
91
92        // coordIndices
93        osg::UByteArray* coordIndices = new osg::UByteArray(48,indices);
94
95        // share the primtive set.
96        osg::PrimitiveSet* primitives = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES,0,48);
97
98        for (int q = 0; q < HOUSES_SIZE; q++)
99        {
100                float xPos = ((static_cast<double> (rand()) /
101                                          static_cast<double> (RAND_MAX))
102                                         * 2.0 * XDim) - XDim;
103
104                float yPos = ((static_cast<double> (rand()) /
105                                          static_cast<double> (RAND_MAX))
106                                         * 2 * ZDim) - ZDim;
107
108                float scale = 10.0f;
109               
110                osg::Vec3 offset(xPos,yPos,0.0f);
111
112                // coords
113                osg::Vec3Array* coords = new osg::Vec3Array(10);
114                (*coords)[0] = osg::Vec3( 0.5f, -0.7f, 0.0f);
115                (*coords)[1] = osg::Vec3( 0.5f,  0.7f, 0.0f);
116                (*coords)[2] = osg::Vec3(-0.5f, 0.7f, 0.0f);
117                (*coords)[3] = osg::Vec3(-0.5f, -0.7f, 0.0f);
118                (*coords)[4] = osg::Vec3( 0.5f, -0.7f, 1.0f);
119                (*coords)[5] = osg::Vec3( 0.5f,  0.7f, 1.0f);
120                (*coords)[6] = osg::Vec3(-0.5f,  0.7f, 1.0f);
121                (*coords)[7] = osg::Vec3(-0.5f, -0.7f, 1.0f);
122                (*coords)[8] = osg::Vec3( 0.0f, -0.5f, 1.5f);
123                (*coords)[9] = osg::Vec3( 0.0f,  0.5f, 1.5f);
124
125                for (i = 0; i < 10; i++)
126                {
127                        (*coords)[i] = (*coords)[i] * scale + offset;
128                }
129
130
131                // create geometry
132                osg::Geometry * geometry = new osg::Geometry();
133               
134                geometry->addPrimitiveSet(primitives);
135               
136                geometry->setVertexArray(coords);
137                geometry->setVertexIndices(coordIndices);
138               
139                geometry->setColorArray(colors);
140                geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
141               
142                geometry->setNormalArray(normals);
143                geometry->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE);
144
145                osg::Geode * geode = new osg::Geode();
146                geode->addDrawable(geometry);
147               
148                nodes.push_back(geode);
149        }
150}
151
152void LayoutAsGrid()
153{
154        // calculate bounding box
155        osg::BoundingBox bbox;
156        for (NodeIterator node = nodes.begin(); node != nodes.end(); ++node)
157                bbox.expandBy((*node)->getBound());
158
159        // setup grid information
160        osg::Group ** groups = new osg::Group*[GridX * GridY];
161        int i;
162        for (i = 0; i < GridX * GridY; i++)
163                groups[i] = new osg::Group();
164
165        float xGridStart = bbox.xMin();
166        float xGridSize = (bbox.xMax() - bbox.xMin()) / GridX;
167
168        float yGridStart = bbox.yMin();
169        float yGridSize = (bbox.yMax() - bbox.yMin()) / GridY;
170
171        // arrange buildings into right grid
172        for (NodeIterator nodeIter = nodes.begin(); nodeIter != nodes.end(); ++nodeIter)
173        {
174                osg::Node * node = nodeIter->get();
175                osg::Vec3 center = node->getBound().center();
176               
177                int x = (int)floor((center.x() - xGridStart) / xGridSize);
178                int z = (int)floor((center.y() - yGridStart) / yGridSize);
179
180                groups[z * GridX + x]->addChild(node);
181        }
182 
183        // add nodes to building root   
184        for (i = 0; i < GridX * GridY; i++)
185        {
186                osg::StateSet * stateset = new osg::StateSet();
187
188                osg::Material * material = new osg::Material();
189                osg::Vec4 color = osg::Vec4(
190                        0.5f + (static_cast<double> (rand()) / (2.0*static_cast<double> (RAND_MAX))),
191                        0.5f + (static_cast<double> (rand()) / (2.0*static_cast<double> (RAND_MAX))),
192                        0.5f + (static_cast<double> (rand()) / ( 2.0*static_cast<double>(RAND_MAX))),
193                        1.0f);
194                       
195                material->setAmbient(osg::Material::FRONT_AND_BACK, color);
196                material->setDiffuse(osg::Material::FRONT_AND_BACK, color);
197                stateset->setAttributeAndModes(material, osg::StateAttribute::ON);
198
199                groups[i]->setStateSet(stateset);
200
201                if (UseImpostor)
202                {
203                        osg::Impostor * impostor = new osg::Impostor();
204                        impostor->setImpostorThreshold(static_cast<float> (Threshold));
205                        impostor->addChild(groups[i]);
206                        impostor->setRange(0, 0.0f, 1e7f);
207                        impostor->setCenter(groups[i]->getBound().center());
208                        Root->addChild(impostor);
209                }
210                else
211                {
212                        Root->addChild(groups[i]);
213                }
214        }
215
216        delete[] groups;
217}
218
219
220int main( int argc, char **argv )
221{
222    // use an ArgumentParser object to manage the program arguments.
223    osg::ArgumentParser arguments(&argc,argv);
224
225    // set up the usage document, in case we need to print out how to use this program.
226    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getProgramName()+" [options] filename ...");
227    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
228
229    // construct the viewer.
230    osgProducer::Viewer viewer(arguments);
231
232    // set up the value with sensible default event handlers.
233    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
234   
235    // add local test manipulator more suitable for testing impostors.
236    unsigned int pos = viewer.addCameraManipulator(new TestManipulator);
237    viewer.selectCameraManipulator(pos);
238   
239    // get details on keyboard and mouse bindings used by the viewer.
240    viewer.getUsage(*arguments.getApplicationUsage());
241
242    // if user request help write it out to cout.
243    if (arguments.read("-h") || arguments.read("--help"))
244    {
245        arguments.getApplicationUsage()->write(std::cout);
246        return 1;
247    }
248
249    // any option left unread are converted into errors to write out later.
250    arguments.reportRemainingOptionsAsUnrecognized();
251
252    // report any errors if they have occured when parsing the program aguments.
253    if (arguments.errors())
254    {
255        arguments.writeErrorMessages(std::cout);
256        return 1;
257    }
258
259
260
261    // load the nodes from the commandline arguments.
262    osg::Node* model = osgDB::readNodeFiles(arguments);
263    if (model)
264    {
265        // the osgUtil::InsertImpostorsVisitor used lower down to insert impostors
266        // only operators on subclass of Group's, if the model top node is not
267        // a group then it won't be able to insert an impostor.  We therefore
268        // manually insert an impostor above the model.
269        if (dynamic_cast<osg::Group*>(model)==0)
270        {
271            const osg::BoundingSphere& bs = model->getBound();
272            if (bs.valid())
273            {
274
275                osg::Impostor* impostor = new osg::Impostor;
276
277                // standard LOD settings
278                impostor->addChild(model);
279                impostor->setRange(0,0.0f,1e7f);
280                impostor->setCenter(bs.center());
281
282                // impostor specfic settings.
283                impostor->setImpostorThresholdToBound(5.0f);
284
285                model = impostor;
286
287            }
288        }
289
290        // we insert an impostor node above the model, so we keep a handle
291        // on the rootnode of the model, the is required since the
292        // InsertImpostorsVisitor can add a new root in automatically and
293        // we would know about it, other than by following the parent path
294        // up from model.  This is really what should be done, but I'll pass
295        // on it right now as it requires a getRoots() method to be added to
296        // osg::Node, and we're about to make a release so no new features!
297        osg::Group* rootnode = new osg::Group;
298        rootnode->addChild(model);
299
300
301        // now insert impostors in the model using the InsertImpostorsVisitor.
302        osgUtil::InsertImpostorsVisitor ov;
303
304        // traverse the model and collect all osg::Group's and osg::LOD's.
305        // however, don't traverse the rootnode since we want to keep it as
306        // the start of traversal, otherwise the insertImpostor could insert
307        // and Impostor above the current root, making it nolonger a root!
308        model->accept(ov);
309
310        // insert the Impostors above groups and LOD's
311        ov.insertImpostors();
312    }
313    else
314    {
315        // no user model so we'll create our own world.
316        model = Root = new osg::Group();
317        CreateHouses();
318        LayoutAsGrid();
319    }
320
321    // add model to viewer.
322    viewer.setSceneData(model);
323
324    // register trackball, flight and drive.
325
326    // create the windows and run the threads.
327    viewer.realize(Producer::CameraGroup::ThreadPerCamera);
328
329    while( !viewer.done() )
330    {
331        // wait for all cull and draw threads to complete.
332        viewer.sync();
333
334        // update the scene by traversing it with the the update visitor which will
335        // call all node update callbacks and animations.
336        viewer.update();
337         
338        // fire off the cull and draw traversals of the scene.
339        viewer.frame();
340       
341    }
342
343    return 0;
344}
Note: See TracBrowser for help on using the browser.