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

Revision 13488, 10.5 kB (checked in by robert, 4 hours ago)

From Mattias Helsing, "Seems I was only half right given what you asked for. CMP0017 only
says that modules that are found and ran from cmake modules dir should
prefer cmake-provided modules. find_package() and include() still look
in CMAKE_MODULE_PATH first.

After some investigating I've come up with a proposal examplified in
the attached FindGDAL.cmake script. It simply calls the cmake provided
FindGDAL.cmake if it exists and returns if it succeeds in finding GDAL
using that, otherwise continue with our local cmake code.
Pro: Wont clutter our root CMakeLists.txt
Con: If we begin to write more advanced Findxxx modules (using
COMPONENTS, REQUIRED etc.) we may have to revise this scheme.
"

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