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

Revision 5084, 20.0 kB (checked in by robert, 8 years ago)

Added support for LOD's with transistion between quads and point rendering.

  • 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/Point>
25#include <osg/PointSprite>
26#include <osg/io_utils>
27
28float random(float min,float max) { return min + (max-min)*(float)rand()/(float)RAND_MAX; }
29
30class PrecipitationGeometry : public osg::Geometry
31{
32public:
33
34        PrecipitationGeometry()
35        {
36            setSupportsDisplayList(false);
37        }
38
39        virtual bool supports(const osg::PrimitiveFunctor&) const { return false; }
40        virtual void accept(osg::PrimitiveFunctor&) const {}
41        virtual bool supports(const osg::PrimitiveIndexFunctor&) const { return false; }
42        virtual void accept(osg::PrimitiveIndexFunctor&) const {}
43
44        void setInternalGeometry(osg::Geometry* geometry) { _internalGeometry = geometry; }
45       
46        osg::Geometry* getInternalGeometry() { return _internalGeometry.get(); }
47
48       
49        virtual void compileGLObjects(osg::State& state) const
50        {
51            if (!_internalGeometry) return;
52
53            static bool s_interalGeometryCompiled = false;
54            if (!s_interalGeometryCompiled)
55            {
56                _internalGeometry->compileGLObjects(state);
57                s_interalGeometryCompiled = true;
58            }
59        }
60
61        virtual void drawImplementation(osg::State& state) const
62        {
63            if (!_internalGeometry) return;
64           
65            _internalGeometry->draw(state);
66        }
67
68        virtual osg::BoundingBox computeBound() const
69        {
70            return osg::BoundingBox();
71        }
72       
73protected:       
74
75        osg::ref_ptr<osg::Geometry> _internalGeometry;
76
77};
78
79class CullCallback : public osg::NodeCallback
80{
81public:
82
83    CullCallback(osg::Uniform* uniform):
84        _previousFrame(0),
85        _initialized(false),
86        _uniform(uniform)
87    {
88    }
89
90    virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
91    {
92        osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);
93        if (cv)
94        {
95            if (!_initialized)
96            {
97                _previousModelViewMatrix = cv->getModelViewMatrix();
98                _previousFrame = nv->getFrameStamp()->getFrameNumber();
99                _initialized = true;
100            }
101       
102            _uniform->set(_previousModelViewMatrix);
103           
104            // osg::notify(osg::NOTICE)<<"Updating uniform "<<_previousModelViewMatrix<<std::endl;
105
106            traverse(node, nv);
107           
108            if (_previousFrame != nv->getFrameStamp()->getFrameNumber())
109            {
110                _previousModelViewMatrix = cv->getModelViewMatrix();
111                _previousFrame = nv->getFrameStamp()->getFrameNumber();
112            }
113        }
114        else
115        {
116            traverse(node, nv);
117        }
118    }
119   
120    int _previousFrame;
121    bool _initialized;
122    osg::Matrix _previousModelViewMatrix;
123    osg::ref_ptr<osg::Uniform> _uniform;   
124};
125
126void fillSpotLightImage(unsigned char* ptr, const osg::Vec4& centerColour, const osg::Vec4& backgroudColour, unsigned int size, float power)
127{
128    float mid = (float(size)-1.0f)*0.5f;
129    float div = 2.0f/float(size);
130    for(unsigned int r=0;r<size;++r)
131    {
132        //unsigned char* ptr = image->data(0,r,0);
133        for(unsigned int c=0;c<size;++c)
134        {
135            float dx = (float(c) - mid)*div;
136            float dy = (float(r) - mid)*div;
137            float r = powf(1.0f-sqrtf(dx*dx+dy*dy),power);
138            if (r<0.0f) r=0.0f;
139            osg::Vec4 color = centerColour*r+backgroudColour*(1.0f-r);
140            *ptr++ = (unsigned char)((color[0])*255.0f);
141            *ptr++ = (unsigned char)((color[1])*255.0f);
142            *ptr++ = (unsigned char)((color[2])*255.0f);
143            *ptr++ = (unsigned char)((color[3])*255.0f);
144        }
145    }
146}
147
148
149osg::Image* createSpotLightImage(const osg::Vec4& centerColour, const osg::Vec4& backgroudColour, unsigned int size, float power)
150{
151
152#if 0
153    osg::Image* image = new osg::Image;
154    unsigned char* ptr = image->data(0,0,0);
155    fillSpotLightImage(ptr, centerColour, backgroudColour, size, power);
156
157    return image;
158#else
159    osg::Image* image = new osg::Image;
160    osg::Image::MipmapDataType mipmapData;
161    unsigned int s = size;
162    unsigned int totalSize = 0;
163    unsigned i;
164    for(i=0; s>0; s>>=1, ++i)
165    {
166        if (i>0) mipmapData.push_back(totalSize);
167        totalSize += s*s*4;
168    }
169
170    unsigned char* ptr = new unsigned char[totalSize];
171    image->setImage(size, size, size, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, ptr, osg::Image::USE_NEW_DELETE,1);
172
173    image->setMipmapLevels(mipmapData);
174
175    s = size;
176    for(i=0; s>0; s>>=1, ++i)
177    {
178        fillSpotLightImage(ptr, centerColour, backgroudColour, s, power);
179        ptr += s*s*4;
180    }
181
182    return image;
183#endif   
184}
185
186/** create quad, line and point geometry data all with consistent particle positions.*/
187void createGeometry(unsigned int numParticles,
188                    osg::Geometry* quad_geometry,
189                    osg::Geometry* line_geometry,
190                    osg::Geometry* point_geometry)
191{
192    // particle corner offsets
193    osg::Vec2 offset00(0.0f,0.0f);
194    osg::Vec2 offset10(1.0f,0.0f);
195    osg::Vec2 offset01(0.0f,1.0f);
196    osg::Vec2 offset11(1.0f,1.0f);
197   
198    osg::Vec2 offset0(0.5f,0.0f);
199    osg::Vec2 offset1(0.5f,1.0f);
200
201    osg::Vec2 offset(0.5f,0.5f);
202
203
204    // configure quad_geometry;
205    osg::Vec3Array* quad_vertices = 0;
206    osg::Vec2Array* quad_offsets = 0;
207    if (quad_geometry)
208    {
209        quad_vertices = new osg::Vec3Array(numParticles*4);
210        quad_offsets = new osg::Vec2Array(numParticles*4);
211
212        quad_geometry->setVertexArray(quad_vertices);
213        quad_geometry->setTexCoordArray(0, quad_offsets);
214        quad_geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, numParticles*4));
215    }
216
217    // configure line_geometry;
218    osg::Vec3Array* line_vertices = 0;
219    osg::Vec2Array* line_offsets = 0;
220    if (line_geometry)
221    {
222        line_vertices = new osg::Vec3Array(numParticles*2);
223        line_offsets = new osg::Vec2Array(numParticles*2);
224
225        line_geometry->setVertexArray(line_vertices);
226        line_geometry->setTexCoordArray(0, line_offsets);
227        line_geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINES, 0, numParticles*2));
228    }
229
230    // configure point_geometry;
231    osg::Vec3Array* point_vertices = 0;
232    osg::Vec2Array* point_offsets = 0;
233    if (point_geometry)
234    {
235        point_vertices = new osg::Vec3Array(numParticles);
236        point_offsets = new osg::Vec2Array(numParticles);
237
238        point_geometry->setVertexArray(point_vertices);
239        point_geometry->setTexCoordArray(0, point_offsets);
240        point_geometry->addPrimitiveSet(new osg::DrawArrays(GL_POINTS, 0, numParticles));
241    }
242
243    // set up vertex attribute data.
244    for(unsigned int i=0; i< numParticles; ++i)
245    {
246        osg::Vec3 pos( random(0.0f, 1.0f), random(0.0f, 1.0f), random(0.0f, 1.0f));
247   
248        // quad particles
249        if (quad_vertices)
250        {
251            (*quad_vertices)[i*4] = pos;
252            (*quad_vertices)[i*4+1] = pos;
253            (*quad_vertices)[i*4+2] =  pos;
254            (*quad_vertices)[i*4+3] =  pos;
255            (*quad_offsets)[i*4] = offset00;
256            (*quad_offsets)[i*4+1] = offset01;
257            (*quad_offsets)[i*4+2] = offset11;
258            (*quad_offsets)[i*4+3] = offset10;
259        }
260               
261        // line particles
262        if (line_vertices)
263        {
264            (*line_vertices)[i*2] = pos;
265            (*line_vertices)[i*2+1] = pos;
266            (*line_offsets)[i*2] = offset0;
267            (*line_offsets)[i*2+1] = offset1;
268        }
269       
270        // point particles
271        if (point_vertices)
272        {
273            (*point_vertices)[i] = pos;
274            (*point_offsets)[i] = offset;
275        }
276    }
277}
278
279
280static osg::ref_ptr<osg::Geometry> quad_geometry = 0;
281static osg::ref_ptr<osg::StateSet> quad_stateset = 0;
282
283static osg::ref_ptr<osg::Geometry> line_geometry = 0;
284static osg::ref_ptr<osg::StateSet> line_stateset = 0;
285
286static osg::ref_ptr<osg::Geometry> point_geometry = 0;
287static osg::ref_ptr<osg::StateSet> point_stateset = 0;
288
289void setUpGeometries(unsigned int numParticles)
290{
291    {
292        quad_geometry = new osg::Geometry;
293        quad_geometry->setUseVertexBufferObjects(true);
294
295        quad_stateset = new osg::StateSet;
296        osg::Program* program = new osg::Program;
297        quad_stateset->setAttribute(program);
298
299        // get shaders from source
300        program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("quad_rain.vert")));
301        program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("rain.frag")));
302    }
303
304
305    {
306        line_geometry = new osg::Geometry;
307        line_geometry->setUseVertexBufferObjects(true);
308
309        line_stateset = new osg::StateSet;
310
311        osg::Program* program = new osg::Program;
312        line_stateset->setAttribute(program);
313
314        // get shaders from source
315        program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("line_rain.vert")));
316        program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("rain.frag")));
317    }
318
319
320    {
321        point_geometry = new osg::Geometry;
322        point_geometry->setUseVertexBufferObjects(true);
323
324        point_stateset = new osg::StateSet;
325
326        osg::Program* program = new osg::Program;
327        point_stateset->setAttribute(program);
328
329        // get shaders from source
330        program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("point_rain.vert")));
331        program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("rain.frag")));
332
333        /// Setup the point sprites
334        osg::PointSprite *sprite = new osg::PointSprite();
335        point_stateset->setTextureAttributeAndModes(0, sprite, osg::StateAttribute::ON);
336
337        point_stateset->setMode(GL_VERTEX_PROGRAM_POINT_SIZE, osg::StateAttribute::ON);
338
339    }
340
341    createGeometry(numParticles, quad_geometry.get(), line_geometry.get(), point_geometry.get());
342
343}
344
345
346osg::Node* createRainEffect(const osg::BoundingBox& bb, const osg::Vec3& velocity)
347{
348    osg::LOD* lod = new osg::LOD;
349   
350    float nearDistance = 100.0;
351    float farDistance = 200.0;
352   
353    // high res LOD.
354    {
355        osg::Geode* highres_geode = new osg::Geode;
356
357        PrecipitationGeometry* geometry = new PrecipitationGeometry;
358
359        highres_geode->addDrawable(geometry);
360
361        geometry->setInitialBound(bb);
362        geometry->setInternalGeometry(quad_geometry.get());
363        geometry->setStateSet(quad_stateset.get());
364       
365        lod->addChild( highres_geode, 0.0f, nearDistance );
366    }
367   
368    // low res LOD
369    {
370        osg::Geode* lowres_geode = new osg::Geode;
371
372        PrecipitationGeometry* geometry = new PrecipitationGeometry;
373
374        lowres_geode->addDrawable(geometry);
375
376        geometry->setInitialBound(bb);
377        geometry->setInternalGeometry(point_geometry.get());
378        geometry->setStateSet(point_stateset.get());
379       
380        lod->addChild( lowres_geode, nearDistance, farDistance );
381    }
382
383
384    // set up state.
385    osg::StateSet* stateset = lod->getOrCreateStateSet();
386    {
387        // time taken to get from start to the end of cycle
388        float period = fabs((bb.zMax()-bb.zMin()) / velocity.z());
389
390        // distance between start point and end of cyclce
391        osg::Vec3 position(bb.xMin(), bb.yMin(), bb.zMax());
392        osg::Vec3 dv_i( bb.xMax()-bb.xMin(), 0.0f, 0.0f );
393        osg::Vec3 dv_j( 0.0f, bb.yMax()-bb.yMin(), 0.0f );
394        osg::Vec3 dv_k( velocity * period );
395
396        // set up uniforms
397        osg::Uniform* position_Uniform = new osg::Uniform("position",position);
398        static osg::Uniform* dv_i_Uniform = new osg::Uniform("dv_i",dv_i);
399        static osg::Uniform* dv_j_Uniform = new osg::Uniform("dv_j",dv_j);
400        static osg::Uniform* dv_k_Uniform = new osg::Uniform("dv_k",dv_k);
401       
402        static osg::Uniform* inversePeriodUniform = new osg::Uniform("inversePeriod",1.0f/period);
403        static osg::Uniform* startTime = new osg::Uniform("startTime",0.0f);
404
405
406        stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
407        stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
408       
409        stateset->addUniform(position_Uniform);
410        stateset->addUniform(dv_i_Uniform);
411        stateset->addUniform(dv_j_Uniform);
412        stateset->addUniform(dv_k_Uniform);
413        stateset->addUniform(inversePeriodUniform);
414        stateset->addUniform(startTime);
415        stateset->addUniform(new osg::Uniform("particleColour", osg::Vec4(0.6,0.6,0.6,1.0)));
416       
417        static osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
418        stateset->addUniform(baseTextureSampler);
419       
420        static 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));
421        stateset->setTextureAttribute(0, texture);
422
423        // make it render after the normal transparent bin
424        stateset->setRenderBinDetails(11,"DepthSortedBin");
425
426        osg::Uniform* previousModelViewUniform = new osg::Uniform("previousModelViewMatrix",osg::Matrix());
427        stateset->addUniform(previousModelViewUniform);
428        lod->setCullCallback(new CullCallback(previousModelViewUniform));
429
430    }
431
432
433    return lod;
434}
435
436osg::Node* createCellRainEffect(const osg::BoundingBox& bb, const osg::Vec3& velocity, unsigned int numParticles)
437{
438   
439    unsigned int numX = 50;
440    unsigned int numY = 50;
441    unsigned int numCells = numX*numY;
442    unsigned int numParticlesPerCell = numParticles/numCells;
443
444    setUpGeometries(numParticlesPerCell);
445   
446    std::cout<<"Effect total number of particles = "<<numParticles<<std::endl;
447    std::cout<<"Number of cells = "<<numCells<<std::endl;
448    std::cout<<"Number of particles per cell = "<<numParticlesPerCell<<std::endl;
449    std::cout<<"Cell width = "<<(bb.xMax()-bb.xMin())/(float)(numX)<<std::endl;
450    std::cout<<"Cell length = "<<(bb.yMax()-bb.yMin())/(float)(numY)<<std::endl;
451    std::cout<<"Cell height = "<<(bb.zMax()-bb.zMin())<<std::endl;
452
453    osg::Group* group = new osg::Group;
454    for(unsigned int i=0; i<numX; ++i)
455    {
456        for(unsigned int j=0; j<numX; ++j)
457        {
458            osg::BoundingBox bbLocal(bb.xMin() + ((bb.xMax()-bb.xMin())*(float)i)/(float)(numX),
459                                     bb.yMin() + ((bb.yMax()-bb.yMin())*(float)j)/(float)(numY),
460                                     bb.zMin(),
461                                     bb.xMin() + ((bb.xMax()-bb.xMin())*(float)(i+1))/(float)(numX),
462                                     bb.yMin() + ((bb.yMax()-bb.yMin())*(float)(j+1))/(float)(numY),
463                                     bb.zMax());
464
465            group->addChild(createRainEffect(bbLocal, velocity));
466        }       
467    }
468    return group;
469}
470
471osg::Node* createModel(osg::Node* loadedModel, bool /*useShaders*/)
472{
473    osg::Group* group = new osg::Group;
474
475    osg::BoundingBox bb(0.0, 0.0, 0.0, 100.0, 100.0, 100.0);
476    osg::Vec3 velocity(0.0,2.0,-5.0);
477    unsigned int numParticles = 10000000;
478   
479    if (loadedModel)
480    {
481        group->addChild(loadedModel);
482       
483        osg::BoundingSphere bs = loadedModel->getBound();
484
485        bb.set( -500, -500, 0, +500, +500, 10);
486       
487        osg::StateSet* stateset = loadedModel->getOrCreateStateSet();
488       
489        osg::Fog* fog = new osg::Fog;
490        fog->setMode(osg::Fog::LINEAR);
491        fog->setDensity(0.1f);
492        fog->setStart(0.0f);
493        fog->setEnd(1000.0f);
494        fog->setColor(osg::Vec4(0.5f,0.5f,0.5f,1.0f));
495        stateset->setAttributeAndModes(fog, osg::StateAttribute::ON);
496       
497        osg::LightSource* lightSource = new osg::LightSource;
498        group->addChild(lightSource);
499
500        osg::Light* light = lightSource->getLight();
501        light->setLightNum(0);
502        light->setPosition(osg::Vec4(0.0f,0.0f,1.0f,0.0f)); // directional light from above
503        light->setAmbient(osg::Vec4(0.8f,0.8f,0.8f,1.0f));
504        light->setDiffuse(osg::Vec4(0.2f,0.2f,0.2f,1.0f));
505        light->setSpecular(osg::Vec4(0.2f,0.2f,0.2f,1.0f));
506
507               
508    }
509   
510#if 0
511    setUpGeometries(numParticles);
512    group->addChild(createRainEffect(bb, velocity));
513#else
514    group->addChild(createCellRainEffect(bb, velocity, numParticles));
515#endif
516    return group;   
517}
518
519int main( int argc, char **argv )
520{
521
522    // use an ArgumentParser object to manage the program arguments.
523    osg::ArgumentParser arguments(&argc,argv);
524   
525    // set up the usage document, in case we need to print out how to use this program.
526    arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
527    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" example provides an interactive viewer for visualising point clouds..");
528    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
529    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
530    arguments.getApplicationUsage()->addCommandLineOption("--shader","Use GLSL shaders.");
531    arguments.getApplicationUsage()->addCommandLineOption("--fixed","Use fixed function pipeline.");
532   
533
534    // construct the viewer.
535    osgProducer::Viewer viewer(arguments);
536
537    // set up the value with sensible default event handlers.
538    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
539
540    // get details on keyboard and mouse bindings used by the viewer.
541    viewer.getUsage(*arguments.getApplicationUsage());
542
543    bool shader = true;
544    while (arguments.read("--shader")) shader = true;
545    while (arguments.read("--fixed")) shader = false;
546
547    // if user request help write it out to cout.
548    if (arguments.read("-h") || arguments.read("--help"))
549    {
550        arguments.getApplicationUsage()->write(std::cout);
551        return 1;
552    }
553
554    // any option left unread are converted into errors to write out later.
555    arguments.reportRemainingOptionsAsUnrecognized();
556
557    // report any errors if they have occured when parsing the program aguments.
558    if (arguments.errors())
559    {
560        arguments.writeErrorMessages(std::cout);
561        return 1;
562    }
563   
564    osg::Timer timer;
565    osg::Timer_t start_tick = timer.tick();
566
567    // read the scene from the list of file specified commandline args.
568    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
569   
570    loadedModel = createModel(loadedModel.get(), shader);
571
572    // if no model has been successfully loaded report failure.
573    if (!loadedModel)
574    {
575        std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
576        return 1;
577    }
578
579    osg::Timer_t end_tick = timer.tick();
580
581    std::cout << "Time to load = "<<timer.delta_s(start_tick,end_tick)<<std::endl;
582
583    // optimize the scene graph, remove rendundent nodes and state etc.
584    osgUtil::Optimizer optimizer;
585    // optimizer.optimize(loadedModel.get());
586
587    // set the scene to render
588    viewer.setSceneData(loadedModel.get());
589
590    // create the windows and run the threads.
591    viewer.realize();
592
593    while( !viewer.done() )
594    {
595        // wait for all cull and draw threads to complete.
596        viewer.sync();
597
598        // update the scene by traversing it with the the update visitor which will
599        // call all node update callbacks and animations.
600        viewer.update();
601         
602        // fire off the cull and draw traversals of the scene.
603        viewer.frame();
604       
605    }
606   
607    // wait for all cull and draw threads to complete before exit.
608    viewer.sync();
609
610    return 0;
611}
Note: See TracBrowser for help on using the browser.