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

Revision 5082, 19.0 kB (checked in by robert, 9 years ago)

Added point and line paths.

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