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

Revision 5093, 35.8 kB (checked in by robert, 9 years ago)

Added inline shaders so that the tha example can be run from any directory.

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