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

Revision 1815, 10.3 kB (checked in by robert, 11 years ago)

Added the usage report to the examples for when no arguments are passed
to the examples.

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