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

Revision 13497, 10.7 kB (checked in by robert, 30 minutes ago)

From Mattias Helsing, "CMake have release 3.0 and 3.1 and we have some bad checks for cmake
major version when settings cmake policies in CMakeLists.txt. This fixes it"

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