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

Revision 5095, 35.9 kB (checked in by robert, 8 years ago)

Standardised the bin number of the particle effects

  • 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
28#define USE_LOCAL_SHADERS 1
29
30float random(float min,float max) { return min + (max-min)*(float)rand()/(float)RAND_MAX; }
31
32struct PrecipatationParameters : public osg::Referenced
33{
34    PrecipatationParameters():
35        particleVelocity(0.0,0.0,-5.0),
36        particleSize(0.02),
37        particleColour(0.6, 0.6, 0.6, 1.0),
38        numberOfParticles(10000000),
39        numberOfCellsX(100),
40        numberOfCellsY(100),
41        numberOfCellsZ(1),
42        nearTransition(25.0),
43        farTransition(100.0),
44        fogExponent(1.0),
45        fogDensity(0.001),
46        fogEnd(1000.0),
47        fogColour(0.5, 0.5, 0.5, 1.0),
48        clearColour(0.5, 0.5, 0.5, 1.0)
49    {
50        rain(0.5);
51    }
52
53    void rain (float intensity)
54    {
55        particleVelocity = osg::Vec3(0.0,0.0,-2.0) + osg::Vec3(0.0,0.0,-10.0)*intensity;
56        particleSize = 0.01 + 0.02*intensity;
57        particleColour = osg::Vec4(0.6, 0.6, 0.6, 1.0) -  osg::Vec4(0.1, 0.1, 0.1, 1.0)* intensity;
58        numberOfParticles = (int)(intensity * 85000000.0f);
59        numberOfCellsX = 100 + (int)(100.0f*intensity);
60        numberOfCellsY = 100 + (int)(100.0f*intensity);
61        farTransition = 140.0f - 100.0f*intensity;
62        fogExponent = 1.0f;
63        fogDensity = 0.005f*intensity;
64        fogEnd = 250/(0.01 + intensity);
65        fogColour.set(0.5, 0.5, 0.5, 1.0);
66        clearColour.set(0.5, 0.5, 0.5, 1.0);
67    }
68
69    void snow(float intensity)
70    {
71        particleVelocity = osg::Vec3(0.0,0.0,-1.0) + osg::Vec3(0.0,0.0,-0.5)*intensity;
72        particleSize = 0.02 + 0.03*intensity;
73        particleColour = osg::Vec4(0.85f, 0.85f, 0.85f, 1.0f) -  osg::Vec4(0.1f, 0.1f, 0.1f, 1.0f)* intensity;
74        numberOfParticles = (int)(intensity * 82000000.0f);
75        numberOfCellsX = 100 + (int)(100.0f*intensity);
76        numberOfCellsY = 100 + (int)(100.0f*intensity);
77        farTransition = 140.0f - 100.0f*intensity;
78        fogExponent = 1.0f;
79        fogDensity = 0.02f*intensity;
80        fogEnd = 150.0f/(0.01f + intensity);
81        fogColour.set(0.6, 0.6, 0.6, 1.0);
82        clearColour.set(0.6, 0.6, 0.6, 1.0);
83    }
84
85    osg::BoundingBox    boundingBox;
86    osg::Vec3           particleVelocity;
87    float               particleSize;
88    osg::Vec4           particleColour;
89    unsigned int        numberOfParticles;
90    unsigned int        numberOfCellsX;
91    unsigned int        numberOfCellsY;
92    unsigned int        numberOfCellsZ;
93    float               nearTransition;
94    float               farTransition;
95    float               fogExponent;
96    float               fogDensity;
97    float               fogEnd;
98    osg::Vec4           fogColour;
99    osg::Vec4           clearColour;
100};
101
102#if 0
103struct PrecipitationCullCallback : public virtual osg::Drawable::CullCallback
104{
105    PrecipitationCullCallback() {}
106
107    PrecipitationCullCallback(const PrecipitationCullCallback&,const osg::CopyOp&) {}
108
109    META_Object(osg,PrecipitationCullCallback);
110
111    /** do customized cull code, return true if drawable should be culled.*/
112    virtual bool cull(osg::NodeVisitor* nodeVisitor, osg::Drawable* drawable, osg::State* state) const
113    {
114        return false;
115    }
116};
117#endif
118
119class PrecipitationGeometry : public osg::Geometry
120{
121public:
122
123        PrecipitationGeometry()
124        {
125            setSupportsDisplayList(false);
126           
127            // setCullCallback(new PrecipitationCullCallback());
128        }
129
130        virtual bool supports(const osg::PrimitiveFunctor&) const { return false; }
131        virtual void accept(osg::PrimitiveFunctor&) const {}
132        virtual bool supports(const osg::PrimitiveIndexFunctor&) const { return false; }
133        virtual void accept(osg::PrimitiveIndexFunctor&) const {}
134
135        void setInternalGeometry(osg::Geometry* geometry) { _internalGeometry = geometry; }
136       
137        osg::Geometry* getInternalGeometry() { return _internalGeometry.get(); }
138       
139        void setPosition(const osg::Vec3& position) { _position = position; }
140        const osg::Vec3& getPosition() const { return _position; }
141       
142        void setStartTime(float time) { _startTime = time; }
143        float getStartTime() const { return _startTime; }
144
145
146        virtual void compileGLObjects(osg::State& state) const
147        {
148            if (!_internalGeometry) return;
149
150            static bool s_interalGeometryCompiled = false;
151            if (!s_interalGeometryCompiled)
152            {
153                _internalGeometry->compileGLObjects(state);
154                s_interalGeometryCompiled = true;
155            }
156        }
157
158        virtual void drawImplementation(osg::State& state) const
159        {
160            if (!_internalGeometry) return;
161           
162            const Extensions* extensions = getExtensions(state.getContextID(),true);
163
164            glNormal3fv(_position.ptr());
165            extensions->glMultiTexCoord1f(GL_TEXTURE0+1, _startTime);
166
167            _internalGeometry->draw(state);
168           
169           
170            static int s_frameNumber = 0xffffffff;
171            static unsigned int s_NumberQuads = 0;
172            static unsigned int s_NumberQuadsVertices = 0;
173            static unsigned int s_NumberLines = 0;
174            static unsigned int s_NumberLinesVertices = 0;
175            static unsigned int s_NumberPoints = 0;
176            static unsigned int s_NumberPointsVertices = 0;
177           
178            if (s_frameNumber != state.getFrameStamp()->getFrameNumber())
179            {
180                // std::cout<<"Frame "<< s_frameNumber<<"\tquads "<<s_NumberQuads<<", "<<s_NumberQuadsVertices<<"  points "<<s_NumberPoints<<", "<<s_NumberPointsVertices<<std::endl;
181           
182                s_NumberQuads = 0;
183                s_NumberLines = 0;
184                s_NumberPoints = 0;
185                s_NumberQuadsVertices = 0;
186                s_NumberLinesVertices = 0;
187                s_NumberPointsVertices = 0;
188
189                s_frameNumber = state.getFrameStamp()->getFrameNumber();
190            }
191           
192           
193            if (_internalGeometry->getName()=="quad")
194            {
195                s_NumberQuads++;
196                s_NumberQuadsVertices+= _internalGeometry->getVertexArray()->getNumElements();
197            }
198            else if (_internalGeometry->getName()=="line")
199            {
200                s_NumberLines++;
201                s_NumberLinesVertices+= _internalGeometry->getVertexArray()->getNumElements();
202            }
203            else if (_internalGeometry->getName()=="point")
204            {
205                s_NumberPoints++;
206                s_NumberPointsVertices+= _internalGeometry->getVertexArray()->getNumElements();
207            }
208        }
209
210        virtual osg::BoundingBox computeBound() const
211        {
212            return osg::BoundingBox();
213        }
214       
215protected:       
216
217        osg::Vec3                   _position;
218        float                       _startTime;
219        osg::ref_ptr<osg::Geometry> _internalGeometry;
220
221};
222
223class CullCallback : public osg::NodeCallback
224{
225public:
226
227    CullCallback(osg::Uniform* uniform):
228        _previousFrame(0),
229        _initialized(false),
230        _uniform(uniform)
231    {
232    }
233
234    virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
235    {
236        osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);
237        if (cv)
238        {
239            if (!_initialized)
240            {
241                _previousModelViewMatrix = cv->getModelViewMatrix();
242                _previousFrame = nv->getFrameStamp()->getFrameNumber();
243                _initialized = true;
244            }
245       
246            _uniform->set(_previousModelViewMatrix);
247           
248            // osg::notify(osg::NOTICE)<<"Updating uniform "<<_previousModelViewMatrix<<std::endl;
249
250            traverse(node, nv);
251           
252            if (_previousFrame != nv->getFrameStamp()->getFrameNumber())
253            {
254                _previousModelViewMatrix = cv->getModelViewMatrix();
255                _previousFrame = nv->getFrameStamp()->getFrameNumber();
256            }
257        }
258        else
259        {
260            traverse(node, nv);
261        }
262    }
263   
264    int _previousFrame;
265    bool _initialized;
266    osg::Matrix _previousModelViewMatrix;
267    osg::ref_ptr<osg::Uniform> _uniform;   
268};
269
270void fillSpotLightImage(unsigned char* ptr, const osg::Vec4& centerColour, const osg::Vec4& backgroudColour, unsigned int size, float power)
271{
272    float mid = (float(size)-1.0f)*0.5f;
273    float div = 2.0f/float(size);
274    for(unsigned int r=0;r<size;++r)
275    {
276        //unsigned char* ptr = image->data(0,r,0);
277        for(unsigned int c=0;c<size;++c)
278        {
279            float dx = (float(c) - mid)*div;
280            float dy = (float(r) - mid)*div;
281            float r = powf(1.0f-sqrtf(dx*dx+dy*dy),power);
282            if (r<0.0f) r=0.0f;
283            osg::Vec4 color = centerColour*r+backgroudColour*(1.0f-r);
284            *ptr++ = (unsigned char)((color[0])*255.0f);
285            *ptr++ = (unsigned char)((color[1])*255.0f);
286            *ptr++ = (unsigned char)((color[2])*255.0f);
287            *ptr++ = (unsigned char)((color[3])*255.0f);
288        }
289    }
290}
291
292
293osg::Image* createSpotLightImage(const osg::Vec4& centerColour, const osg::Vec4& backgroudColour, unsigned int size, float power)
294{
295
296#if 0
297    osg::Image* image = new osg::Image;
298    unsigned char* ptr = image->data(0,0,0);
299    fillSpotLightImage(ptr, centerColour, backgroudColour, size, power);
300
301    return image;
302#else
303    osg::Image* image = new osg::Image;
304    osg::Image::MipmapDataType mipmapData;
305    unsigned int s = size;
306    unsigned int totalSize = 0;
307    unsigned i;
308    for(i=0; s>0; s>>=1, ++i)
309    {
310        if (i>0) mipmapData.push_back(totalSize);
311        totalSize += s*s*4;
312    }
313
314    unsigned char* ptr = new unsigned char[totalSize];
315    image->setImage(size, size, size, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, ptr, osg::Image::USE_NEW_DELETE,1);
316
317    image->setMipmapLevels(mipmapData);
318
319    s = size;
320    for(i=0; s>0; s>>=1, ++i)
321    {
322        fillSpotLightImage(ptr, centerColour, backgroudColour, s, power);
323        ptr += s*s*4;
324    }
325
326    return image;
327#endif   
328}
329
330/** create quad, line and point geometry data all with consistent particle positions.*/
331void createGeometry(unsigned int numParticles,
332                    osg::Geometry* quad_geometry,
333                    osg::Geometry* line_geometry,
334                    osg::Geometry* point_geometry)
335{
336    // particle corner offsets
337    osg::Vec2 offset00(0.0f,0.0f);
338    osg::Vec2 offset10(1.0f,0.0f);
339    osg::Vec2 offset01(0.0f,1.0f);
340    osg::Vec2 offset11(1.0f,1.0f);
341   
342    osg::Vec2 offset0(0.5f,0.0f);
343    osg::Vec2 offset1(0.5f,1.0f);
344
345    osg::Vec2 offset(0.5f,0.5f);
346
347
348    // configure quad_geometry;
349    osg::Vec3Array* quad_vertices = 0;
350    osg::Vec2Array* quad_offsets = 0;
351    if (quad_geometry)
352    {
353        quad_geometry->setName("quad");
354   
355        quad_vertices = new osg::Vec3Array(numParticles*4);
356        quad_offsets = new osg::Vec2Array(numParticles*4);
357
358        quad_geometry->setVertexArray(quad_vertices);
359        quad_geometry->setTexCoordArray(0, quad_offsets);
360        quad_geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, numParticles*4));
361    }
362
363    // configure line_geometry;
364    osg::Vec3Array* line_vertices = 0;
365    osg::Vec2Array* line_offsets = 0;
366    if (line_geometry)
367    {
368        line_geometry->setName("line");
369
370        line_vertices = new osg::Vec3Array(numParticles*2);
371        line_offsets = new osg::Vec2Array(numParticles*2);
372
373        line_geometry->setVertexArray(line_vertices);
374        line_geometry->setTexCoordArray(0, line_offsets);
375        line_geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINES, 0, numParticles*2));
376    }
377
378    // configure point_geometry;
379    osg::Vec3Array* point_vertices = 0;
380    osg::Vec2Array* point_offsets = 0;
381    if (point_geometry)
382    {
383        point_geometry->setName("point");
384
385        point_vertices = new osg::Vec3Array(numParticles);
386        point_offsets = new osg::Vec2Array(numParticles);
387
388        point_geometry->setVertexArray(point_vertices);
389        point_geometry->setTexCoordArray(0, point_offsets);
390        point_geometry->addPrimitiveSet(new osg::DrawArrays(GL_POINTS, 0, numParticles));
391    }
392
393    // set up vertex attribute data.
394    for(unsigned int i=0; i< numParticles; ++i)
395    {
396        osg::Vec3 pos( random(0.0f, 1.0f), random(0.0f, 1.0f), random(0.0f, 1.0f));
397   
398        // quad particles
399        if (quad_vertices)
400        {
401            (*quad_vertices)[i*4] = pos;
402            (*quad_vertices)[i*4+1] = pos;
403            (*quad_vertices)[i*4+2] =  pos;
404            (*quad_vertices)[i*4+3] =  pos;
405            (*quad_offsets)[i*4] = offset00;
406            (*quad_offsets)[i*4+1] = offset01;
407            (*quad_offsets)[i*4+2] = offset11;
408            (*quad_offsets)[i*4+3] = offset10;
409        }
410               
411        // line particles
412        if (line_vertices)
413        {
414            (*line_vertices)[i*2] = pos;
415            (*line_vertices)[i*2+1] = pos;
416            (*line_offsets)[i*2] = offset0;
417            (*line_offsets)[i*2+1] = offset1;
418        }
419       
420        // point particles
421        if (point_vertices)
422        {
423            (*point_vertices)[i] = pos;
424            (*point_offsets)[i] = offset;
425        }
426    }
427}
428
429
430static osg::ref_ptr<osg::Geometry> quad_geometry = 0;
431static osg::ref_ptr<osg::StateSet> quad_stateset = 0;
432
433static osg::ref_ptr<osg::Geometry> line_geometry = 0;
434static osg::ref_ptr<osg::StateSet> line_stateset = 0;
435
436static osg::ref_ptr<osg::Geometry> point_geometry = 0;
437static osg::ref_ptr<osg::StateSet> point_stateset = 0;
438
439void setUpGeometries(unsigned int numParticles)
440{
441    unsigned int renderBin = 11;
442
443    {
444        quad_geometry = new osg::Geometry;
445        quad_geometry->setUseVertexBufferObjects(true);
446
447        quad_stateset = new osg::StateSet;
448        osg::Program* program = new osg::Program;
449        quad_stateset->setAttribute(program);
450        quad_stateset->setRenderBinDetails(renderBin,"DepthSortedBin");
451
452#ifdef USE_LOCAL_SHADERS
453        char vertexShaderSource[] =
454            "uniform vec3 dv_i;\n"
455            "uniform vec3 dv_j;\n"
456            "uniform vec3 dv_k;\n"
457            "\n"
458            "uniform float inversePeriod;\n"
459            "uniform vec4 particleColour;\n"
460            "uniform float particleSize;\n"
461            "\n"
462            "uniform float osg_FrameTime;\n"
463            "uniform float osg_DeltaFrameTime;\n"
464            "uniform mat4 previousModelViewMatrix;\n"
465            "\n"
466            "varying vec4 colour;\n"
467            "varying vec2 texCoord;\n"
468            "\n"
469            "void main(void)\n"
470            "{\n"
471            "    vec3 pos = gl_Normal.xyz + (gl_Vertex.x*dv_i) + (dv_j * gl_Vertex.y);\n"
472            "    \n"
473            "    float offset = gl_Vertex.z;\n"
474            "    texCoord = gl_MultiTexCoord0.xy;\n"
475            "    float startTime = gl_MultiTexCoord1.x;\n"
476            "\n"
477            "    vec3 v_previous = pos + dv_k * fract( (osg_FrameTime - startTime)*inversePeriod - offset);\n"
478            "    vec3 v_current = v_previous + dv_k * (osg_DeltaFrameTime*inversePeriod);\n"
479            "    \n"
480            "    colour = particleColour;\n"
481            "    \n"
482            "    vec4 v1 = gl_ModelViewMatrix * vec4(v_current,1.0);\n"
483            "    vec4 v2 = previousModelViewMatrix * vec4(v_previous,1.0);\n"
484            "    \n"
485            "    vec3 dv = v2.xyz - v1.xyz;\n"
486            "    \n"
487            "    vec2 dv_normalized = normalize(dv.xy);\n"
488            "    dv.xy += dv_normalized * particleSize;\n"
489            "    vec2 dp = vec2( -dv_normalized.y, dv_normalized.x ) * particleSize;\n"
490            "    \n"
491            "    float area = length(dv.xy);\n"
492            "    colour.a = 0.05+(particleSize)/area;\n"
493            "    \n"
494            "\n"
495            "    v1.xyz += dv*texCoord.y;\n"
496            "    v1.xy += dp*texCoord.x;\n"
497            "    \n"
498            "    gl_Position = gl_ProjectionMatrix * v1;\n"
499            "}\n";
500
501        char fragmentShaderSource[] =
502            "uniform sampler2D baseTexture;\n"
503            "varying vec2 texCoord;\n"
504            "varying vec4 colour;\n"
505            "\n"
506            "void main (void)\n"
507            "{\n"
508            "    gl_FragColor = colour * texture2D( baseTexture, texCoord);\n"
509            "}\n";
510
511        program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource));
512        program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource));
513#else
514        // get shaders from source
515        program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("quad_rain.vert")));
516        program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("rain.frag")));
517#endif
518    }
519
520
521    {
522        line_geometry = new osg::Geometry;
523        line_geometry->setUseVertexBufferObjects(true);
524
525        line_stateset = new osg::StateSet;
526
527        osg::Program* program = new osg::Program;
528        line_stateset->setAttribute(program);
529        line_stateset->setRenderBinDetails(renderBin,"DepthSortedBin");
530
531#ifdef USE_LOCAL_SHADERS
532        char vertexShaderSource[] =
533            "uniform vec3 dv_i;\n"
534            "uniform vec3 dv_j;\n"
535            "uniform vec3 dv_k;\n"
536            "\n"
537            "uniform float inversePeriod;\n"
538            "uniform vec4 particleColour;\n"
539            "uniform float particleSize;\n"
540            "\n"
541            "uniform float osg_FrameTime;\n"
542            "uniform float osg_DeltaFrameTime;\n"
543            "uniform mat4 previousModelViewMatrix;\n"
544            "\n"
545            "varying vec4 colour;\n"
546            "varying vec2 texCoord;\n"
547            "\n"
548            "void main(void)\n"
549            "{\n"
550            "    vec3 pos = gl_Normal.xyz + (gl_Vertex.x*dv_i) + (dv_j * gl_Vertex.y);\n"
551            "    \n"
552            "\n"
553            "    float offset = gl_Vertex.z;\n"
554            "    texCoord = gl_MultiTexCoord0.xy;\n"
555            "    float startTime = gl_MultiTexCoord1.x;\n"
556            "\n"
557            "    vec3 v_previous = pos + dv_k * fract( (osg_FrameTime - startTime)*inversePeriod - offset);\n"
558            "    vec3 v_current = v_previous + dv_k * (osg_DeltaFrameTime*inversePeriod);\n"
559            "    \n"
560            "    colour = particleColour;\n"
561            "    \n"
562            "    vec4 v1 = gl_ModelViewMatrix * vec4(v_current,1.0);\n"
563            "    vec4 v2 = previousModelViewMatrix * vec4(v_previous,1.0);\n"
564            "    \n"
565            "    vec3 dv = v2.xyz - v1.xyz;\n"
566            "    \n"
567            "    vec2 dv_normalized = normalize(dv.xy);\n"
568            "    dv.xy += dv_normalized * particleSize;\n"
569            "    \n"
570            "    float area = length(dv.xy);\n"
571            "    colour.a = 0.1+(particleSize)/area;\n"
572            "    \n"
573            "    v1.xyz += dv*texCoord.y;\n"
574            "    \n"
575            "    gl_Position = gl_ProjectionMatrix * v1;\n"
576            "}";
577
578        char fragmentShaderSource[] =
579            "uniform sampler2D baseTexture;\n"
580            "varying vec2 texCoord;\n"
581            "varying vec4 colour;\n"
582            "\n"
583            "void main (void)\n"
584            "{\n"
585            "    gl_FragColor = colour * texture2D( baseTexture, texCoord);\n"
586            "}\n";
587
588        program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource));
589        program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource));
590#else
591        // get shaders from source
592        program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("line_rain.vert")));
593        program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("rain.frag")));
594#endif
595    }
596
597
598    {
599        point_geometry = new osg::Geometry;
600        point_geometry->setUseVertexBufferObjects(true);
601
602        point_stateset = new osg::StateSet;
603
604        osg::Program* program = new osg::Program;
605        point_stateset->setAttribute(program);
606
607#ifdef USE_LOCAL_SHADERS
608        char vertexShaderSource[] =
609            "uniform vec3 dv_i;\n"
610            "uniform vec3 dv_j;\n"
611            "uniform vec3 dv_k;\n"
612            "\n"
613            "uniform float inversePeriod;\n"
614            "uniform vec4 particleColour;\n"
615            "uniform float particleSize;\n"
616            "\n"
617            "uniform float osg_FrameTime;\n"
618            "\n"
619            "varying vec4 colour;\n"
620            "varying vec2 texCoord;\n"
621            "\n"
622            "void main(void)\n"
623            "{\n"
624            "    vec3 pos = gl_Normal.xyz + (gl_Vertex.x*dv_i) + (dv_j * gl_Vertex.y);\n"
625            "    texCoord = gl_MultiTexCoord0.xy;\n"
626            "\n"
627            "    float startTime = gl_MultiTexCoord1.x;\n"
628            "\n"
629            "    vec3 v_current = pos + dv_k * fract( (osg_FrameTime - startTime)*inversePeriod - gl_Vertex.z);\n"
630            "   \n"
631            "    colour = particleColour;\n"
632            "\n"
633            "    gl_Position = gl_ModelViewProjectionMatrix * vec4(v_current,1.0);\n"
634            "\n"
635            "    float pointSize = abs(1280.0*particleSize / gl_Position.w);\n"
636            "    //gl_PointSize = max(ceil(pointSize),2);\n"
637            "    gl_PointSize = ceil(pointSize);\n"
638            "    \n"
639            "    colour.a = 0.05+(pointSize*pointSize)/(gl_PointSize*gl_PointSize);\n"
640            "}\n";
641
642        char fragmentShaderSource[] =
643            "uniform sampler2D baseTexture;\n"
644            "varying vec2 texCoord;\n"
645            "varying vec4 colour;\n"
646            "\n"
647            "void main (void)\n"
648            "{\n"
649            "    gl_FragColor = colour * texture2D( baseTexture, texCoord);\n"
650            "}\n";
651
652        program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource));
653        program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource));
654#else
655        // get shaders from source
656        program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("point_rain.vert")));
657        program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("rain.frag")));
658#endif
659
660        /// Setup the point sprites
661        osg::PointSprite *sprite = new osg::PointSprite();
662        point_stateset->setTextureAttributeAndModes(0, sprite, osg::StateAttribute::ON);
663
664        point_stateset->setMode(GL_VERTEX_PROGRAM_POINT_SIZE, osg::StateAttribute::ON);
665        point_stateset->setRenderBinDetails(renderBin,"DepthSortedBin");
666    }
667
668    createGeometry(numParticles, quad_geometry.get(), line_geometry.get(), point_geometry.get());
669
670}
671
672
673osg::Node* createRainEffect(const osg::BoundingBox& bb, const osg::Vec3& velocity, float nearTransition, float farTransition)
674{
675    osg::LOD* lod = new osg::LOD;
676   
677
678    // distance between start point and end of cyclce
679    osg::Vec3 position(bb.xMin(), bb.yMin(), bb.zMax());
680
681    // time taken to get from start to the end of cycle
682    float period = fabs((bb.zMax()-bb.zMin()) / velocity.z());
683    osg::Vec3 dv_i( bb.xMax()-bb.xMin(), 0.0f, 0.0f );
684    osg::Vec3 dv_j( 0.0f, bb.yMax()-bb.yMin(), 0.0f );
685    osg::Vec3 dv_k( velocity * period );
686
687    float startTime = random(0, period);
688   
689    // high res LOD.
690    {
691        osg::Geode* highres_geode = new osg::Geode;
692
693        PrecipitationGeometry* geometry = new PrecipitationGeometry;
694
695        highres_geode->addDrawable(geometry);
696
697        geometry->setName("highres");
698        geometry->setPosition(position);
699        geometry->setStartTime(startTime);
700        geometry->setInitialBound(bb);
701        geometry->setInternalGeometry(quad_geometry.get());
702        geometry->setStateSet(quad_stateset.get());
703       
704        lod->addChild( highres_geode, 0.0f, nearTransition );
705    }
706   
707    // low res LOD
708    {
709        osg::Geode* lowres_geode = new osg::Geode;
710
711
712        PrecipitationGeometry* geometry = new PrecipitationGeometry;
713
714        lowres_geode->addDrawable(geometry);
715
716        geometry->setName("lowres");
717        geometry->setPosition(position);
718        geometry->setStartTime(startTime);
719        geometry->setInitialBound(bb);
720        geometry->setInternalGeometry(point_geometry.get());
721        geometry->setStateSet(point_stateset.get());
722       
723        lod->addChild( lowres_geode, nearTransition, farTransition );
724    }
725
726
727    return lod;
728}
729
730osg::Node* createCellRainEffect(const PrecipatationParameters& parameters)
731{
732   
733    unsigned int numX = parameters.numberOfCellsX;
734    unsigned int numY = parameters.numberOfCellsY;
735    unsigned int numCells = numX*numY;
736    unsigned int numParticlesPerCell = parameters.numberOfParticles/numCells;
737
738    setUpGeometries(numParticlesPerCell);
739   
740    const osg::BoundingBox& bb = parameters.boundingBox;
741   
742    std::cout<<"Effect total number of particles = "<<parameters.numberOfParticles<<std::endl;
743    std::cout<<"Number of cells = "<<numCells<<std::endl;
744    std::cout<<"Number of particles per cell = "<<numParticlesPerCell<<std::endl;
745    std::cout<<"Cell width = "<<(bb.xMax()-bb.xMin())/(float)(numX)<<std::endl;
746    std::cout<<"Cell length = "<<(bb.yMax()-bb.yMin())/(float)(numY)<<std::endl;
747    std::cout<<"Cell height = "<<(bb.zMax()-bb.zMin())<<std::endl;
748
749    osg::Group* group = new osg::Group;
750    for(unsigned int i=0; i<numX; ++i)
751    {
752        for(unsigned int j=0; j<numX; ++j)
753        {
754            osg::BoundingBox bbLocal(bb.xMin() + ((bb.xMax()-bb.xMin())*(float)i)/(float)(numX),
755                                     bb.yMin() + ((bb.yMax()-bb.yMin())*(float)j)/(float)(numY),
756                                     bb.zMin(),
757                                     bb.xMin() + ((bb.xMax()-bb.xMin())*(float)(i+1))/(float)(numX),
758                                     bb.yMin() + ((bb.yMax()-bb.yMin())*(float)(j+1))/(float)(numY),
759                                     bb.zMax());
760
761            group->addChild(createRainEffect(bbLocal, parameters.particleVelocity, parameters.nearTransition, parameters.farTransition));
762        }       
763    }
764   
765
766    osgUtil::Optimizer::SpatializeGroupsVisitor sgv;
767    group->accept(sgv);
768    sgv.divide();
769
770
771    osg::StateSet* stateset = group->getOrCreateStateSet();
772
773    // time taken to get from start to the end of cycle
774    float period = fabs((bb.zMax()-bb.zMin()) / parameters.particleVelocity.z());
775
776    // distance between start point and end of cyclce
777    osg::Vec3 dv_i( (bb.xMax()-bb.xMin())/(float)(numX), 0.0f, 0.0f );
778    osg::Vec3 dv_j( 0.0f, (bb.yMax()-bb.yMin())/(float)(numY), 0.0f );
779    osg::Vec3 dv_k( parameters.particleVelocity * period );
780
781    // set up uniforms
782    // osg::Uniform* position_Uniform = new osg::Uniform("position",position);
783    osg::Uniform* dv_i_Uniform = new osg::Uniform("dv_i",dv_i);
784    osg::Uniform* dv_j_Uniform = new osg::Uniform("dv_j",dv_j);
785    osg::Uniform* dv_k_Uniform = new osg::Uniform("dv_k",dv_k);
786
787    osg::Uniform* inversePeriodUniform = new osg::Uniform("inversePeriod",1.0f/period);
788    //osg::Uniform* startTime = new osg::Uniform("startTime",0.0f);
789
790    //stateset->addUniform(position_Uniform); // vec3
791    stateset->addUniform(dv_i_Uniform); // vec3 could be float
792    stateset->addUniform(dv_j_Uniform); // vec3 could be float
793    stateset->addUniform(dv_k_Uniform); // vec3
794    stateset->addUniform(inversePeriodUniform); // float
795    //stateset->addUniform(startTime); // float
796
797    stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
798    stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
799
800    osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
801    stateset->addUniform(baseTextureSampler);
802
803    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));
804    stateset->setTextureAttribute(0, texture);
805
806    stateset->addUniform(new osg::Uniform("particleColour", parameters.particleColour));
807    stateset->addUniform(new osg::Uniform("particleSize", parameters.particleSize));
808 
809    osg::Uniform* previousModelViewUniform = new osg::Uniform("previousModelViewMatrix",osg::Matrix());
810    stateset->addUniform(previousModelViewUniform);
811   
812    group->setCullCallback(new CullCallback(previousModelViewUniform));
813
814
815    return group;
816}
817
818osg::Node* createModel(osg::Node* loadedModel, PrecipatationParameters& parameters)
819{
820    osg::Group* group = new osg::Group;
821
822    osg::BoundingBox bb(0.0, 0.0, 0.0, 100.0, 100.0, 100.0);
823   
824    if (loadedModel)
825    {
826        group->addChild(loadedModel);
827       
828        osg::BoundingSphere bs = loadedModel->getBound();
829
830        bb.set( -500, -500, 0, +500, +500, 10);
831       
832        parameters.boundingBox = bb;
833       
834        osg::StateSet* stateset = loadedModel->getOrCreateStateSet();
835       
836        osg::Fog* fog = new osg::Fog;
837       
838        if (parameters.fogExponent<1.0)
839        {
840            fog->setMode(osg::Fog::LINEAR);
841        }
842        else if (parameters.fogExponent<2.0)
843        {
844            fog->setMode(osg::Fog::EXP);
845        }
846        else
847        {
848            fog->setMode(osg::Fog::EXP2);
849        }
850       
851        fog->setDensity(parameters.fogDensity);
852        fog->setStart(0.0f);
853        fog->setEnd(parameters.fogEnd);
854        fog->setColor(parameters.fogColour);
855        stateset->setAttributeAndModes(fog, osg::StateAttribute::ON);
856       
857        osg::LightSource* lightSource = new osg::LightSource;
858        group->addChild(lightSource);
859
860        osg::Light* light = lightSource->getLight();
861        light->setLightNum(0);
862        light->setPosition(osg::Vec4(0.0f,0.0f,1.0f,0.0f)); // directional light from above
863        light->setAmbient(osg::Vec4(0.8f,0.8f,0.8f,1.0f));
864        light->setDiffuse(osg::Vec4(0.2f,0.2f,0.2f,1.0f));
865        light->setSpecular(osg::Vec4(0.2f,0.2f,0.2f,1.0f));
866
867               
868    }
869   
870    group->addChild(createCellRainEffect(parameters));
871
872    return group;   
873}
874
875int main( int argc, char **argv )
876{
877
878    // use an ArgumentParser object to manage the program arguments.
879    osg::ArgumentParser arguments(&argc,argv);
880   
881    // set up the usage document, in case we need to print out how to use this program.
882    arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
883    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" example provides an interactive viewer for visualising point clouds..");
884    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
885    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
886    arguments.getApplicationUsage()->addCommandLineOption("","");
887    arguments.getApplicationUsage()->addCommandLineOption("","");
888    arguments.getApplicationUsage()->addCommandLineOption("","");
889    arguments.getApplicationUsage()->addCommandLineOption("","");
890    arguments.getApplicationUsage()->addCommandLineOption("","");
891    arguments.getApplicationUsage()->addCommandLineOption("","");
892    arguments.getApplicationUsage()->addCommandLineOption("","");
893    arguments.getApplicationUsage()->addCommandLineOption("","");
894    arguments.getApplicationUsage()->addCommandLineOption("","");
895    arguments.getApplicationUsage()->addCommandLineOption("","");
896   
897
898    // construct the viewer.
899    osgProducer::Viewer viewer(arguments);
900
901    // set up the value with sensible default event handlers.
902    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
903
904    // get details on keyboard and mouse bindings used by the viewer.
905    viewer.getUsage(*arguments.getApplicationUsage());
906
907    PrecipatationParameters parameters;
908
909    float intensity;
910    while (arguments.read("--snow", intensity)) parameters.snow(intensity);
911    while (arguments.read("--rain", intensity)) parameters.rain(intensity);
912
913    while (arguments.read("--particleSize", parameters.particleSize)) {}
914    while (arguments.read("--particleColor", parameters.particleColour.r(), parameters.particleColour.g(), parameters.particleColour.b(), parameters.particleColour.a())) {}
915    while (arguments.read("--particleColour", parameters.particleColour.r(), parameters.particleColour.g(), parameters.particleColour.b(), parameters.particleColour.a())) {}
916
917    osg::Vec3 particleVelocity;
918    while (arguments.read("--particleVelocity", particleVelocity.x(), particleVelocity.y(), particleVelocity.z() )) parameters.particleVelocity = particleVelocity;
919
920    while (arguments.read("--nearTransition", parameters.nearTransition )) {}
921    while (arguments.read("--farTransition", parameters.farTransition )) {}
922
923    while (arguments.read("--numberOfParticles", parameters.numberOfParticles )) {}
924
925    while (arguments.read("--numberOfCellsX", parameters.numberOfCellsX )) {}
926    while (arguments.read("--numberOfCellsY", parameters.numberOfCellsY )) {}
927    while (arguments.read("--numberOfCellsZ", parameters.numberOfCellsZ )) {}
928
929    while (arguments.read("--boundingBox", parameters.boundingBox.xMin(),
930                                           parameters.boundingBox.yMin(),
931                                           parameters.boundingBox.zMin(),
932                                           parameters.boundingBox.xMax(),
933                                           parameters.boundingBox.yMax(),
934                                           parameters.boundingBox.zMax())) {}
935
936    while (arguments.read("--fogDensity", parameters.fogDensity )) {}
937    while (arguments.read("--fogExponent", parameters.fogExponent )) {}
938    while (arguments.read("--fogEnd", parameters.fogEnd )) {}
939    while (arguments.read("--fogColor", parameters.fogColour.r(), parameters.fogColour.g(), parameters.fogColour.b(), parameters.fogColour.a())) {}
940    while (arguments.read("--fogColour", parameters.fogColour.r(), parameters.fogColour.g(), parameters.fogColour.b(), parameters.fogColour.a())) {}
941 
942
943    viewer.setClearColor(parameters.clearColour);
944
945    // if user request help write it out to cout.
946    if (arguments.read("-h") || arguments.read("--help"))
947    {
948        arguments.getApplicationUsage()->write(std::cout);
949        return 1;
950    }
951
952    // any option left unread are converted into errors to write out later.
953    arguments.reportRemainingOptionsAsUnrecognized();
954
955    // report any errors if they have occured when parsing the program aguments.
956    if (arguments.errors())
957    {
958        arguments.writeErrorMessages(std::cout);
959        return 1;
960    }
961   
962    osg::Timer timer;
963    osg::Timer_t start_tick = timer.tick();
964
965    // read the scene from the list of file specified commandline args.
966    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
967   
968    loadedModel = createModel(loadedModel.get(), parameters);
969
970    // if no model has been successfully loaded report failure.
971    if (!loadedModel)
972    {
973        std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
974        return 1;
975    }
976
977    osg::Timer_t end_tick = timer.tick();
978
979    std::cout << "Time to load = "<<timer.delta_s(start_tick,end_tick)<<std::endl;
980
981    // optimize the scene graph, remove rendundent nodes and state etc.
982    osgUtil::Optimizer optimizer;
983    // optimizer.optimize(loadedModel.get());
984
985    // set the scene to render
986    viewer.setSceneData(loadedModel.get());
987
988    // create the windows and run the threads.
989    viewer.realize();
990
991    while( !viewer.done() )
992    {
993        // wait for all cull and draw threads to complete.
994        viewer.sync();
995
996        // update the scene by traversing it with the the update visitor which will
997        // call all node update callbacks and animations.
998        viewer.update();
999         
1000        // fire off the cull and draw traversals of the scene.
1001        viewer.frame();
1002       
1003    }
1004   
1005    // wait for all cull and draw threads to complete before exit.
1006    viewer.sync();
1007
1008    return 0;
1009}
Note: See TracBrowser for help on using the browser.