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

Revision 5096, 37.1 kB (checked in by robert, 9 years ago)

Convertered shaders across to using modelview matrix instead of uniforms.

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