Show
Ignore:
Timestamp:
04/21/06 21:39:05 (9 years ago)
Author:
robert
Message:

Added new precipitation nodes.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • OpenSceneGraph/trunk/examples/osgprecipitation/osgprecipitation.cpp

    r5096 r5099  
    2626#include <osg/io_utils> 
    2727 
    28 #define USE_LOCAL_SHADERS 1 
    29  
    30 float random(float min,float max) { return min + (max-min)*(float)rand()/(float)RAND_MAX; } 
    31  
    32 struct 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 }; 
     28#include "PrecipitationEffect.h" 
    10529 
    10630#if 0 
    107 struct 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  
    123 class PrecipitationGeometry : public osg::Geometry 
    124 { 
    125 public: 
    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          
    264 protected:         
    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  
    274 class CullCallback : public osg::NodeCallback 
    275 { 
    276 public: 
    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  
    321 void 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  
    344 osg::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.*/ 
    382 void 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  
    481 static osg::ref_ptr<osg::Geometry> quad_geometry = 0; 
    482 static osg::ref_ptr<osg::StateSet> quad_stateset = 0; 
    483  
    484 static osg::ref_ptr<osg::Geometry> line_geometry = 0; 
    485 static osg::ref_ptr<osg::StateSet> line_stateset = 0; 
    486  
    487 static osg::ref_ptr<osg::Geometry> point_geometry = 0; 
    488 static osg::ref_ptr<osg::StateSet> point_stateset = 0; 
    489  
    490 void 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  
    711 osg::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  
    792 osg::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  
    871 osg::Node* createModel(osg::Node* loadedModel, PrecipatationParameters& parameters) 
     31osg::Node* createModel(osg::Node* loadedModel, osgParticle::PrecipitationParameters& parameters) 
    87232{ 
    87333    osg::Group* group = new osg::Group; 
     
    92585    return group;     
    92686} 
     87#endif 
    92788 
    92889int main( int argc, char **argv ) 
     
    958119    viewer.getUsage(*arguments.getApplicationUsage()); 
    959120 
    960     PrecipatationParameters parameters; 
     121    osg::ref_ptr<osgParticle::PrecipitationEffect> precipitationEffect = new osgParticle::PrecipitationEffect; 
     122    osgParticle::PrecipitationParameters& parameters = *precipitationEffect->getParameters(); 
    961123 
    962124    float intensity; 
     
    974136    while (arguments.read("--farTransition", parameters.farTransition )) {} 
    975137 
    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 )) {} 
     138    while (arguments.read("--particleDensity", parameters.particleDensity )) {} 
     139 
     140    while (arguments.read("--cellSizeX", parameters.cellSizeX )) {} 
     141    while (arguments.read("--cellSizeY", parameters.cellSizeY )) {} 
     142    while (arguments.read("--cellSizeZ", parameters.cellSizeZ )) {} 
    981143 
    982144    while (arguments.read("--boundingBox", parameters.boundingBox.xMin(), 
     
    995157    while (arguments.read("--useFarLineSegments")) { parameters.useFarLineSegments = true; } 
    996158 
     159     
     160 
     161 
    997162    viewer.setClearColor(parameters.clearColour); 
     163 
     164    // now force the effect to update all its internal state. 
     165    precipitationEffect->update(); 
     166 
    998167 
    999168    // if user request help write it out to cout. 
     
    1014183    } 
    1015184     
    1016     osg::Timer timer; 
    1017     osg::Timer_t start_tick = timer.tick(); 
    1018  
    1019185    // read the scene from the list of file specified commandline args. 
    1020186    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. 
    1025187    if (!loadedModel)  
    1026188    { 
     
    1028190        return 1; 
    1029191    } 
    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  
     192     
     193#if 1 
     194     
     195    osg::ref_ptr<osg::Group> group = new osg::Group; 
     196    group->addChild(precipitationEffect.get()); 
     197    group->addChild(loadedModel.get()); 
     198     
    1039199    // set the scene to render 
    1040     viewer.setSceneData(loadedModel.get()); 
     200    viewer.setSceneData(group.get()); 
     201 
     202#else     
     203 
     204        loadedModel = createModel(loadedModel.get(), parameters); 
     205 
     206        // set the scene to render 
     207        viewer.setSceneData(loadedModel.get()); 
     208#endif 
    1041209 
    1042210    // create the windows and run the threads.