root/OpenSceneGraph/trunk/examples/osgprecipitation/osgprecipitation.cpp @ 5078

Revision 5078, 13.2 kB (checked in by robert, 8 years ago)

Added quad based rain effect

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
2 *
3 * This application is open source and may be redistributed and/or modified   
4 * freely and without restriction, both in commericial and non commericial applications,
5 * as long as this copyright notice is maintained.
6 *
7 * This application is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10*/
11
12#include <osgDB/ReadFile>
13#include <osgDB/FileUtils>
14#include <osgUtil/Optimizer>
15#include <osgUtil/CullVisitor>
16#include <osgProducer/Viewer>
17
18#include <osg/Point>
19#include <osg/BlendFunc>
20#include <osg/Texture2D>
21#include <osg/PointSprite>
22#include <osg/Program>
23#include <osg/Fog>
24#include <osg/io_utils>
25
26float random(float min,float max) { return min + (max-min)*(float)rand()/(float)RAND_MAX; }
27
28class PrecipitationGeometry : public osg::Geometry
29{
30public:
31        virtual bool supports(const osg::PrimitiveFunctor&) const { return false; }
32        virtual void accept(osg::PrimitiveFunctor&) const {}
33        virtual bool supports(const osg::PrimitiveIndexFunctor&) const { return false; }
34        virtual void accept(osg::PrimitiveIndexFunctor&) const {}
35
36};
37
38class CullCallback : public osg::NodeCallback
39{
40public:
41
42    CullCallback(osg::Uniform* uniform):
43        _previousFrame(0),
44        _initialized(false),
45        _uniform(uniform)
46    {
47    }
48
49    virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
50    {
51        osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);
52        if (cv)
53        {
54            if (!_initialized)
55            {
56                _previousModelViewMatrix = cv->getModelViewMatrix();
57                _previousFrame = nv->getFrameStamp()->getFrameNumber();
58                _initialized = true;
59            }
60       
61            _uniform->set(_previousModelViewMatrix);
62           
63            // osg::notify(osg::NOTICE)<<"Updating uniform "<<_previousModelViewMatrix<<std::endl;
64
65            traverse(node, nv);
66           
67            if (_previousFrame != nv->getFrameStamp()->getFrameNumber())
68            {
69                _previousModelViewMatrix = cv->getModelViewMatrix();
70                _previousFrame = nv->getFrameStamp()->getFrameNumber();
71            }
72        }
73        else
74        {
75            traverse(node, nv);
76        }
77    }
78   
79    int _previousFrame;
80    bool _initialized;
81    osg::Matrix _previousModelViewMatrix;
82    osg::ref_ptr<osg::Uniform> _uniform;   
83};
84
85osg::Node* createRainEffect(const osg::BoundingBox& bb, const osg::Vec3& velocity, unsigned int numParticles, bool useShaders)
86{
87    osg::Geode* geode = new osg::Geode;
88
89    osg::Geometry* geometry = new PrecipitationGeometry;
90    geode->addDrawable(geometry);
91
92    osg::StateSet* stateset = geometry->getOrCreateStateSet();
93
94    // set up geometry.
95    {
96   
97        // per vertex properties
98        osg::Vec3Array* vertices = new osg::Vec3Array(numParticles*4);
99        osg::Vec3Array* offsets = new osg::Vec3Array(numParticles*4);
100       
101        osg::Vec3 frameDelta = velocity*(2.0f/60.0f);
102        float size = 1.0;
103       
104        for(unsigned int i=0; i< numParticles; ++i)
105        {
106            (*vertices)[i*4].set(random(bb.xMin(), bb.xMax()), random(bb.yMin(),bb.yMax()), bb.zMax());
107            (*vertices)[i*4+1] = (*vertices)[i*4];
108            (*vertices)[i*4+2] = (*vertices)[i*4];
109            (*vertices)[i*4+3] = (*vertices)[i*4];
110            (*offsets)[i*4].z() = random(0.0, 1.0);
111            (*offsets)[i*4+1].z() = (*offsets)[i*4].z();
112            (*offsets)[i*4+2].z() = (*offsets)[i*4].z();
113            (*offsets)[i*4+3].z() = (*offsets)[i*4].z();
114            (*offsets)[i*4].x() = 0.0;
115            (*offsets)[i*4].y() = 0.0;
116            (*offsets)[i*4+1].x() = 0.0;
117            (*offsets)[i*4+1].y() = 1.0;
118            (*offsets)[i*4+2].x() = 1.0;
119            (*offsets)[i*4+2].y() = 1.0;
120            (*offsets)[i*4+3].x() = 1.0;
121            (*offsets)[i*4+3].y() = 0.0;
122        }
123
124        geometry->setVertexArray(vertices);
125        geometry->setTexCoordArray(0, offsets);
126
127        // overall attributes
128        osg::Vec4Array* colours = new osg::Vec4Array(1);
129        (*colours)[0].set(0.5f,0.5f,0.5f,1.0f);
130        geometry->setColorArray(colours);
131        geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
132       
133        geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, numParticles*4));
134    }
135
136    // set up state.
137    {
138        // time taken to get from start to the end of cycle
139        float period = fabs((bb.zMax()-bb.zMin()) / velocity.z());
140
141        // distance between start point and end of cyclce
142        osg::Vec3 delta = velocity * period;
143
144        // set up uniforms
145        osg::Uniform* deltaUniform = new osg::Uniform("delta",delta);
146        osg::Uniform* inversePeriodUniform = new osg::Uniform("inversePeriod",1.0f/period);
147        osg::Uniform* startTime = new osg::Uniform("startTime",0.0f);
148
149        osg::Program* program = new osg::Program;
150        stateset->setAttribute(program);
151
152        // get shaders from source
153        program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("rain.vert")));
154        program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("rain.frag")));
155
156        stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
157        stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
158       
159        stateset->addUniform(deltaUniform);
160        stateset->addUniform(inversePeriodUniform);
161        stateset->addUniform(startTime);
162       
163        osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
164        stateset->addUniform(baseTextureSampler);
165       
166        osg::Texture2D* texture = new osg::Texture2D(osgDB::readImageFile("Images/particle.rgb"));
167        stateset->setTextureAttribute(0, texture);
168
169        // make it render after the normal transparent bin
170        stateset->setRenderBinDetails(11,"DepthSortedBin");
171
172        osg::Uniform* previousModelViewUniform = new osg::Uniform("previousModelViewMatrix",osg::Matrix());
173        stateset->addUniform(previousModelViewUniform);
174        geode->setCullCallback(new CullCallback(previousModelViewUniform));
175
176    }
177   
178    geometry->setUseVertexBufferObjects(true);
179    geometry->setInitialBound(bb);
180
181    return geode;
182}
183/*
184osg::Node* createSnowEffect(const osg::BoundingBox& bb, const osg::Vec3& velocity, unsigned int numParticles, bool useShaders)
185{
186    osg::Geometry* geometry = new osg::Geometry;
187
188    osg::StateSet* stateset = geometry->getOrCreateStateSet();
189
190    // set up geometry.
191    {
192   
193        // per vertex properties
194        osg::Vec3Array* vertices = new osg::Vec3Array(numParticles);
195        osg::FloatArray* offsets = new osg::FloatArray(numParticles);
196       
197        for(unsigned int i=0; i< numParticles; ++i)
198        {
199            (*vertices)[i].set(random(bb.xMin(), bb.xMax()), random(bb.yMin(),bb.yMax()), bb.zMax());
200            (*offsets)[i] = random(0.0, 1.0);
201        }
202
203        geometry->setVertexArray(vertices);
204        geometry->setTexCoordArray(0, offsets);
205
206        // overall attributes
207        osg::Vec4Array* colours = new osg::Vec4Array(1);
208        (*colours)[0].set(1.0f,1.0f,1.0f,1.0f);
209        geometry->setColorArray(colours);
210        geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
211       
212        geometry->addPrimitiveSet(new osg::DrawArrays(GL_POINTS, 0, numParticles));
213    }
214
215    // set up state.
216    {
217        // time taken to get from start to the end of cycle
218        float period = fabs((bb.zMax()-bb.zMin()) / velocity.z());
219
220        // distance between start point and end of cyclce
221        osg::Vec3 delta = velocity * period;
222
223        // set up uniforms
224        osg::Uniform* deltaUniform = new osg::Uniform("delta",delta);
225        osg::Uniform* inversePeriodUniform = new osg::Uniform("inversePeriod",1.0f/period);
226        osg::Uniform* startTime = new osg::Uniform("startTime",0.0f);
227
228        osg::Program* program = new osg::Program;
229        stateset->setAttribute(program);
230
231        // get shaders from source
232        program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("snow.vert")));
233        program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("snow.frag")));
234
235        stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
236       
237        stateset->addUniform(deltaUniform);
238        stateset->addUniform(inversePeriodUniform);
239        stateset->addUniform(startTime);
240    }
241   
242    geometry->setInitialBound(bb);
243
244
245    osg::Geode* geode = new osg::Geode;
246    geode->addDrawable(geometry);
247
248    return geode;
249}
250*/
251osg::Node* createModel(osg::Node* loadedModel, bool useShaders)
252{
253    osg::Group* group = new osg::Group;
254
255    osg::BoundingBox bb(0.0, 0.0, 0.0, 100.0, 100.0, 100.0);
256    osg::Vec3 velocity(0.0,0.0,-2.0);
257    unsigned int numParticles = 150000;
258   
259    if (loadedModel)
260    {
261        group->addChild(loadedModel);
262       
263        osg::BoundingSphere bs = loadedModel->getBound();
264
265        bb.set( -100, -100, 0, +100, +100, 10);
266       
267        osg::StateSet* stateset = loadedModel->getOrCreateStateSet();
268       
269        osg::Fog* fog = new osg::Fog;
270        fog->setMode(osg::Fog::LINEAR);
271        fog->setDensity(0.1f);
272        fog->setStart(0.0f);
273        fog->setEnd(1000.0f);
274        fog->setColor(osg::Vec4(0.5f,0.5f,0.5f,1.0f));
275        stateset->setAttributeAndModes(fog, osg::StateAttribute::ON);
276       
277        osg::LightSource* lightSource = new osg::LightSource;
278        group->addChild(lightSource);
279
280        osg::Light* light = lightSource->getLight();
281        light->setLightNum(0);
282        light->setPosition(osg::Vec4(0.0f,0.0f,1.0f,0.0f)); // directional light from above
283        light->setAmbient(osg::Vec4(0.8f,0.8f,0.8f,1.0f));
284        light->setDiffuse(osg::Vec4(0.2f,0.2f,0.2f,1.0f));
285        light->setSpecular(osg::Vec4(0.2f,0.2f,0.2f,1.0f));
286
287               
288    }
289
290    group->addChild(createRainEffect(bb, velocity, numParticles, useShaders));
291
292    return group;   
293}
294
295int main( int argc, char **argv )
296{
297
298    // use an ArgumentParser object to manage the program arguments.
299    osg::ArgumentParser arguments(&argc,argv);
300   
301    // set up the usage document, in case we need to print out how to use this program.
302    arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
303    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" example provides an interactive viewer for visualising point clouds..");
304    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
305    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
306    arguments.getApplicationUsage()->addCommandLineOption("--shader","Use GLSL shaders.");
307    arguments.getApplicationUsage()->addCommandLineOption("--fixed","Use fixed function pipeline.");
308   
309
310    // construct the viewer.
311    osgProducer::Viewer viewer(arguments);
312
313    // set up the value with sensible default event handlers.
314    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
315
316    // get details on keyboard and mouse bindings used by the viewer.
317    viewer.getUsage(*arguments.getApplicationUsage());
318
319    bool shader = true;
320    while (arguments.read("--shader")) shader = true;
321    while (arguments.read("--fixed")) shader = false;
322
323    // if user request help write it out to cout.
324    if (arguments.read("-h") || arguments.read("--help"))
325    {
326        arguments.getApplicationUsage()->write(std::cout);
327        return 1;
328    }
329
330    // any option left unread are converted into errors to write out later.
331    arguments.reportRemainingOptionsAsUnrecognized();
332
333    // report any errors if they have occured when parsing the program aguments.
334    if (arguments.errors())
335    {
336        arguments.writeErrorMessages(std::cout);
337        return 1;
338    }
339   
340    osg::Timer timer;
341    osg::Timer_t start_tick = timer.tick();
342
343    // read the scene from the list of file specified commandline args.
344    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
345   
346    loadedModel = createModel(loadedModel.get(), shader);
347
348    // if no model has been successfully loaded report failure.
349    if (!loadedModel)
350    {
351        std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
352        return 1;
353    }
354
355    osg::Timer_t end_tick = timer.tick();
356
357    std::cout << "Time to load = "<<timer.delta_s(start_tick,end_tick)<<std::endl;
358
359    // optimize the scene graph, remove rendundent nodes and state etc.
360    osgUtil::Optimizer optimizer;
361    optimizer.optimize(loadedModel.get());
362
363    // set the scene to render
364    viewer.setSceneData(loadedModel.get());
365
366    // create the windows and run the threads.
367    viewer.realize();
368
369    while( !viewer.done() )
370    {
371        // wait for all cull and draw threads to complete.
372        viewer.sync();
373
374        // update the scene by traversing it with the the update visitor which will
375        // call all node update callbacks and animations.
376        viewer.update();
377         
378        // fire off the cull and draw traversals of the scene.
379        viewer.frame();
380       
381    }
382   
383    // wait for all cull and draw threads to complete before exit.
384    viewer.sync();
385
386    return 0;
387}
Note: See TracBrowser for help on using the browser.