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

Revision 5079, 15.3 kB (checked in by robert, 9 years ago)

Added mipmap generation.

  • 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
85void fillSpotLightImage(unsigned char* ptr, const osg::Vec4& centerColour, const osg::Vec4& backgroudColour, unsigned int size, float power)
86{
87    float mid = (float(size)-1.0f)*0.5f;
88    float div = 2.0f/float(size);
89    for(unsigned int r=0;r<size;++r)
90    {
91        //unsigned char* ptr = image->data(0,r,0);
92        for(unsigned int c=0;c<size;++c)
93        {
94            float dx = (float(c) - mid)*div;
95            float dy = (float(r) - mid)*div;
96            float r = powf(1.0f-sqrtf(dx*dx+dy*dy),power);
97            if (r<0.0f) r=0.0f;
98            osg::Vec4 color = centerColour*r+backgroudColour*(1.0f-r);
99            *ptr++ = (unsigned char)((color[0])*255.0f);
100            *ptr++ = (unsigned char)((color[1])*255.0f);
101            *ptr++ = (unsigned char)((color[2])*255.0f);
102            *ptr++ = (unsigned char)((color[3])*255.0f);
103        }
104    }
105}
106
107
108osg::Image* createSpotLightImage(const osg::Vec4& centerColour, const osg::Vec4& backgroudColour, unsigned int size, float power)
109{
110    osg::Image* image = new osg::Image;
111
112#if 0
113     
114     
115    unsigned char* ptr = image->data(0,0,0);
116    fillSpotLightImage(ptr, centerColour, backgroudColour, size, power);
117#else
118    osg::Image::MipmapDataType mipmapData;
119    unsigned int s = size;
120    unsigned int totalSize = 0;
121    unsigned i;
122    for(i=0; s>0; s>>=1, ++i)
123    {
124        if (i>0) mipmapData.push_back(totalSize);
125        totalSize += s*s*4;
126        std::cout<<" i= "<<i<<" s="<<s<<" p="<<totalSize<<std::endl;
127    }
128
129    std::cout<<"Total size ="<<totalSize<<std::endl;
130
131    unsigned char* ptr = new unsigned char[totalSize];
132    image->setImage(size, size, size, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, ptr, osg::Image::USE_NEW_DELETE,1);
133
134    image->setMipmapLevels(mipmapData);
135
136    s = size;
137    for(i=0; s>0; s>>=1, ++i)
138    {
139        fillSpotLightImage(ptr, centerColour, backgroudColour, s, power);
140        ptr += s*s*4;
141    }
142
143#endif   
144
145
146    return image;
147}
148
149
150osg::Node* createRainEffect(const osg::BoundingBox& bb, const osg::Vec3& velocity, unsigned int numParticles, bool useShaders)
151{
152    osg::Geode* geode = new osg::Geode;
153
154    osg::Geometry* geometry = new PrecipitationGeometry;
155    geode->addDrawable(geometry);
156
157    osg::StateSet* stateset = geometry->getOrCreateStateSet();
158
159    // set up geometry.
160    {
161   
162        // per vertex properties
163        osg::Vec3Array* vertices = new osg::Vec3Array(numParticles*4);
164        osg::Vec3Array* offsets = new osg::Vec3Array(numParticles*4);
165       
166        osg::Vec3 frameDelta = velocity*(2.0f/60.0f);
167        float size = 1.0;
168       
169        for(unsigned int i=0; i< numParticles; ++i)
170        {
171            (*vertices)[i*4].set(random(bb.xMin(), bb.xMax()), random(bb.yMin(),bb.yMax()), bb.zMax());
172            (*vertices)[i*4+1] = (*vertices)[i*4];
173            (*vertices)[i*4+2] = (*vertices)[i*4];
174            (*vertices)[i*4+3] = (*vertices)[i*4];
175            (*offsets)[i*4].z() = random(0.0, 1.0);
176            (*offsets)[i*4+1].z() = (*offsets)[i*4].z();
177            (*offsets)[i*4+2].z() = (*offsets)[i*4].z();
178            (*offsets)[i*4+3].z() = (*offsets)[i*4].z();
179            (*offsets)[i*4].x() = 0.0;
180            (*offsets)[i*4].y() = 0.0;
181            (*offsets)[i*4+1].x() = 0.0;
182            (*offsets)[i*4+1].y() = 1.0;
183            (*offsets)[i*4+2].x() = 1.0;
184            (*offsets)[i*4+2].y() = 1.0;
185            (*offsets)[i*4+3].x() = 1.0;
186            (*offsets)[i*4+3].y() = 0.0;
187        }
188
189        geometry->setVertexArray(vertices);
190        geometry->setTexCoordArray(0, offsets);
191
192        // overall attributes
193        osg::Vec4Array* colours = new osg::Vec4Array(1);
194        (*colours)[0].set(0.5f,0.5f,0.5f,1.0f);
195        geometry->setColorArray(colours);
196        geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
197       
198        geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, numParticles*4));
199    }
200
201    // set up state.
202    {
203        // time taken to get from start to the end of cycle
204        float period = fabs((bb.zMax()-bb.zMin()) / velocity.z());
205
206        // distance between start point and end of cyclce
207        osg::Vec3 delta = velocity * period;
208
209        // set up uniforms
210        osg::Uniform* deltaUniform = new osg::Uniform("delta",delta);
211        osg::Uniform* inversePeriodUniform = new osg::Uniform("inversePeriod",1.0f/period);
212        osg::Uniform* startTime = new osg::Uniform("startTime",0.0f);
213
214        osg::Program* program = new osg::Program;
215        stateset->setAttribute(program);
216
217        // get shaders from source
218        program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("rain.vert")));
219        program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("rain.frag")));
220
221        stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
222        stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
223       
224        stateset->addUniform(deltaUniform);
225        stateset->addUniform(inversePeriodUniform);
226        stateset->addUniform(startTime);
227       
228        osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
229        stateset->addUniform(baseTextureSampler);
230       
231//        osg::Texture2D* texture = new osg::Texture2D(osgDB::readImageFile("Images/particle.rgb"));
232        osg::Texture2D* texture = new osg::Texture2D(createSpotLightImage(osg::Vec4(1.0f,1.0f,1.0f,1.0f),osg::Vec4(1.0f,1.0f,1.0f,0.0f),32,1.0));
233//        texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
234        stateset->setTextureAttribute(0, texture);
235
236        // make it render after the normal transparent bin
237        stateset->setRenderBinDetails(11,"DepthSortedBin");
238
239        osg::Uniform* previousModelViewUniform = new osg::Uniform("previousModelViewMatrix",osg::Matrix());
240        stateset->addUniform(previousModelViewUniform);
241        geode->setCullCallback(new CullCallback(previousModelViewUniform));
242
243    }
244   
245    geometry->setUseVertexBufferObjects(true);
246    geometry->setInitialBound(bb);
247
248    return geode;
249}
250/*
251osg::Node* createSnowEffect(const osg::BoundingBox& bb, const osg::Vec3& velocity, unsigned int numParticles, bool useShaders)
252{
253    osg::Geometry* geometry = new osg::Geometry;
254
255    osg::StateSet* stateset = geometry->getOrCreateStateSet();
256
257    // set up geometry.
258    {
259   
260        // per vertex properties
261        osg::Vec3Array* vertices = new osg::Vec3Array(numParticles);
262        osg::FloatArray* offsets = new osg::FloatArray(numParticles);
263       
264        for(unsigned int i=0; i< numParticles; ++i)
265        {
266            (*vertices)[i].set(random(bb.xMin(), bb.xMax()), random(bb.yMin(),bb.yMax()), bb.zMax());
267            (*offsets)[i] = random(0.0, 1.0);
268        }
269
270        geometry->setVertexArray(vertices);
271        geometry->setTexCoordArray(0, offsets);
272
273        // overall attributes
274        osg::Vec4Array* colours = new osg::Vec4Array(1);
275        (*colours)[0].set(1.0f,1.0f,1.0f,1.0f);
276        geometry->setColorArray(colours);
277        geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
278       
279        geometry->addPrimitiveSet(new osg::DrawArrays(GL_POINTS, 0, numParticles));
280    }
281
282    // set up state.
283    {
284        // time taken to get from start to the end of cycle
285        float period = fabs((bb.zMax()-bb.zMin()) / velocity.z());
286
287        // distance between start point and end of cyclce
288        osg::Vec3 delta = velocity * period;
289
290        // set up uniforms
291        osg::Uniform* deltaUniform = new osg::Uniform("delta",delta);
292        osg::Uniform* inversePeriodUniform = new osg::Uniform("inversePeriod",1.0f/period);
293        osg::Uniform* startTime = new osg::Uniform("startTime",0.0f);
294
295        osg::Program* program = new osg::Program;
296        stateset->setAttribute(program);
297
298        // get shaders from source
299        program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("snow.vert")));
300        program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("snow.frag")));
301
302        stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
303       
304        stateset->addUniform(deltaUniform);
305        stateset->addUniform(inversePeriodUniform);
306        stateset->addUniform(startTime);
307    }
308   
309    geometry->setInitialBound(bb);
310
311
312    osg::Geode* geode = new osg::Geode;
313    geode->addDrawable(geometry);
314
315    return geode;
316}
317*/
318osg::Node* createModel(osg::Node* loadedModel, bool useShaders)
319{
320    osg::Group* group = new osg::Group;
321
322    osg::BoundingBox bb(0.0, 0.0, 0.0, 100.0, 100.0, 100.0);
323    osg::Vec3 velocity(0.0,2.0,-5.0);
324    unsigned int numParticles = 150000;
325   
326    if (loadedModel)
327    {
328        group->addChild(loadedModel);
329       
330        osg::BoundingSphere bs = loadedModel->getBound();
331
332        bb.set( -100, -100, 0, +100, +100, 10);
333       
334        osg::StateSet* stateset = loadedModel->getOrCreateStateSet();
335       
336        osg::Fog* fog = new osg::Fog;
337        fog->setMode(osg::Fog::LINEAR);
338        fog->setDensity(0.1f);
339        fog->setStart(0.0f);
340        fog->setEnd(1000.0f);
341        fog->setColor(osg::Vec4(0.5f,0.5f,0.5f,1.0f));
342        stateset->setAttributeAndModes(fog, osg::StateAttribute::ON);
343       
344        osg::LightSource* lightSource = new osg::LightSource;
345        group->addChild(lightSource);
346
347        osg::Light* light = lightSource->getLight();
348        light->setLightNum(0);
349        light->setPosition(osg::Vec4(0.0f,0.0f,1.0f,0.0f)); // directional light from above
350        light->setAmbient(osg::Vec4(0.8f,0.8f,0.8f,1.0f));
351        light->setDiffuse(osg::Vec4(0.2f,0.2f,0.2f,1.0f));
352        light->setSpecular(osg::Vec4(0.2f,0.2f,0.2f,1.0f));
353
354               
355    }
356
357    group->addChild(createRainEffect(bb, velocity, numParticles, useShaders));
358
359    return group;   
360}
361
362int main( int argc, char **argv )
363{
364
365    // use an ArgumentParser object to manage the program arguments.
366    osg::ArgumentParser arguments(&argc,argv);
367   
368    // set up the usage document, in case we need to print out how to use this program.
369    arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
370    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" example provides an interactive viewer for visualising point clouds..");
371    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
372    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
373    arguments.getApplicationUsage()->addCommandLineOption("--shader","Use GLSL shaders.");
374    arguments.getApplicationUsage()->addCommandLineOption("--fixed","Use fixed function pipeline.");
375   
376
377    // construct the viewer.
378    osgProducer::Viewer viewer(arguments);
379
380    // set up the value with sensible default event handlers.
381    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
382
383    // get details on keyboard and mouse bindings used by the viewer.
384    viewer.getUsage(*arguments.getApplicationUsage());
385
386    bool shader = true;
387    while (arguments.read("--shader")) shader = true;
388    while (arguments.read("--fixed")) shader = false;
389
390    // if user request help write it out to cout.
391    if (arguments.read("-h") || arguments.read("--help"))
392    {
393        arguments.getApplicationUsage()->write(std::cout);
394        return 1;
395    }
396
397    // any option left unread are converted into errors to write out later.
398    arguments.reportRemainingOptionsAsUnrecognized();
399
400    // report any errors if they have occured when parsing the program aguments.
401    if (arguments.errors())
402    {
403        arguments.writeErrorMessages(std::cout);
404        return 1;
405    }
406   
407    osg::Timer timer;
408    osg::Timer_t start_tick = timer.tick();
409
410    // read the scene from the list of file specified commandline args.
411    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
412   
413    loadedModel = createModel(loadedModel.get(), shader);
414
415    // if no model has been successfully loaded report failure.
416    if (!loadedModel)
417    {
418        std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
419        return 1;
420    }
421
422    osg::Timer_t end_tick = timer.tick();
423
424    std::cout << "Time to load = "<<timer.delta_s(start_tick,end_tick)<<std::endl;
425
426    // optimize the scene graph, remove rendundent nodes and state etc.
427    osgUtil::Optimizer optimizer;
428    optimizer.optimize(loadedModel.get());
429
430    // set the scene to render
431    viewer.setSceneData(loadedModel.get());
432
433    // create the windows and run the threads.
434    viewer.realize();
435
436    while( !viewer.done() )
437    {
438        // wait for all cull and draw threads to complete.
439        viewer.sync();
440
441        // update the scene by traversing it with the the update visitor which will
442        // call all node update callbacks and animations.
443        viewer.update();
444         
445        // fire off the cull and draw traversals of the scene.
446        viewer.frame();
447       
448    }
449   
450    // wait for all cull and draw threads to complete before exit.
451    viewer.sync();
452
453    return 0;
454}
Note: See TracBrowser for help on using the browser.