root/OpenSceneGraph/trunk/src/osgParticle/PrecipitationEffect.cpp @ 8716

Revision 8716, 32.3 kB (checked in by robert, 6 years ago)

Moved initial drawable setup to within the mutex locked section to avoid multi-threaded crash on startup.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under 
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14
15#include<OpenThreads/ScopedLock>
16
17#include<osg/Texture2D>
18#include<osg/PointSprite>
19#include<osgDB/FileUtils>
20#include<osgUtil/CullVisitor>
21#include<osgUtil/GLObjectsVisitor>
22
23#include <osgParticle/PrecipitationEffect>
24
25#include <osg/Notify>
26#include <osg/io_utils>
27#include <osg/Timer>
28
29using namespace osgParticle;
30
31#define USE_LOCAL_SHADERS
32
33static float random(float min,float max) { return min + (max-min)*(float)rand()/(float)RAND_MAX; }
34
35static void fillSpotLightImage(unsigned char* ptr, const osg::Vec4& centerColour, const osg::Vec4& backgroudColour, unsigned int size, float power)
36{
37    if (size==1)
38    {
39        float r = 0.5f;
40        osg::Vec4 color = centerColour*r+backgroudColour*(1.0f-r);
41        *ptr++ = (unsigned char)((color[0])*255.0f);
42        *ptr++ = (unsigned char)((color[1])*255.0f);
43        *ptr++ = (unsigned char)((color[2])*255.0f);
44        *ptr++ = (unsigned char)((color[3])*255.0f);
45        return;
46    }
47
48    float mid = (float(size)-1.0f)*0.5f;
49    float div = 2.0f/float(size);
50    for(unsigned int r=0;r<size;++r)
51    {
52        //unsigned char* ptr = image->data(0,r,0);
53        for(unsigned int c=0;c<size;++c)
54        {
55            float dx = (float(c) - mid)*div;
56            float dy = (float(r) - mid)*div;
57            float r = powf(1.0f-sqrtf(dx*dx+dy*dy),power);
58            if (r<0.0f) r=0.0f;
59            osg::Vec4 color = centerColour*r+backgroudColour*(1.0f-r);
60            *ptr++ = (unsigned char)((color[0])*255.0f);
61            *ptr++ = (unsigned char)((color[1])*255.0f);
62            *ptr++ = (unsigned char)((color[2])*255.0f);
63            *ptr++ = (unsigned char)((color[3])*255.0f);
64        }
65    }
66}
67
68static osg::Image* createSpotLightImage(const osg::Vec4& centerColour, const osg::Vec4& backgroudColour, unsigned int size, float power)
69{
70
71#if 0
72    osg::Image* image = new osg::Image;
73    unsigned char* ptr = image->data(0,0,0);
74    fillSpotLightImage(ptr, centerColour, backgroudColour, size, power);
75
76    return image;
77#else
78    osg::Image* image = new osg::Image;
79    osg::Image::MipmapDataType mipmapData;
80    unsigned int s = size;
81    unsigned int totalSize = 0;
82    unsigned i;
83    for(i=0; s>0; s>>=1, ++i)
84    {
85        if (i>0) mipmapData.push_back(totalSize);
86        totalSize += s*s*4;
87    }
88
89    unsigned char* ptr = new unsigned char[totalSize];
90    image->setImage(size, size, size, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, ptr, osg::Image::USE_NEW_DELETE,1);
91
92    image->setMipmapLevels(mipmapData);
93
94    s = size;
95    for(i=0; s>0; s>>=1, ++i)
96    {
97        fillSpotLightImage(ptr, centerColour, backgroudColour, s, power);
98        ptr += s*s*4;
99    }
100
101    return image;
102#endif   
103}
104
105
106PrecipitationEffect::PrecipitationEffect()
107{
108    setNumChildrenRequiringUpdateTraversal(1);
109   
110    setUpGeometries(1024);
111
112    rain(0.5);
113}
114
115void PrecipitationEffect::rain(float intensity)
116{
117    _wind.set(0.0f,0.0f,0.0f);
118    _particleSpeed = -2.0f + -5.0f*intensity;
119    _particleSize = 0.01 + 0.02*intensity;
120    _particleColor = osg::Vec4(0.6, 0.6, 0.6, 1.0) -  osg::Vec4(0.1, 0.1, 0.1, 1.0)* intensity;
121    _maximumParticleDensity = intensity * 8.5f;
122    _cellSize.set(5.0f / (0.25f+intensity), 5.0f / (0.25f+intensity), 5.0f);
123    _nearTransition = 25.f;
124    _farTransition = 100.0f - 60.0f*sqrtf(intensity);
125   
126    if (!_fog) _fog = new osg::Fog;
127
128    _fog->setMode(osg::Fog::EXP);
129    _fog->setDensity(0.005f*intensity);
130    _fog->setColor(osg::Vec4(0.5, 0.5, 0.5, 1.0));
131
132    _useFarLineSegments = false;
133   
134    _dirty = true;
135
136    update();
137}
138
139void PrecipitationEffect::snow(float intensity)
140{
141    _wind.set(0.0f,0.0f,0.0f);
142    _particleSpeed = -0.75f - 0.25f*intensity;
143    _particleSize = 0.02f + 0.03f*intensity;
144    _particleColor = osg::Vec4(0.85f, 0.85f, 0.85f, 1.0f) -  osg::Vec4(0.1f, 0.1f, 0.1f, 1.0f)* intensity;
145    _maximumParticleDensity = intensity * 8.2f;
146    _cellSize.set(5.0f / (0.25f+intensity), 5.0f / (0.25f+intensity), 5.0f);
147    _nearTransition = 25.f;
148    _farTransition = 100.0f - 60.0f*sqrtf(intensity);
149   
150    if (!_fog) _fog = new osg::Fog;
151
152    _fog->setMode(osg::Fog::EXP);
153    _fog->setDensity(0.01f*intensity);
154    _fog->setColor(osg::Vec4(0.6, 0.6, 0.6, 1.0));
155
156    _useFarLineSegments = false;
157   
158    _dirty = true;
159
160    update();
161}
162
163PrecipitationEffect::PrecipitationEffect(const PrecipitationEffect& copy, const osg::CopyOp& copyop):
164    osg::Node(copy,copyop)
165{
166    setNumChildrenRequiringUpdateTraversal(getNumChildrenRequiringUpdateTraversal()+1);           
167    _dirty = true;
168    update();
169}
170
171void PrecipitationEffect::compileGLObjects(osg::RenderInfo& renderInfo) const
172{
173    if (_quadGeometry.valid())
174    {
175        _quadGeometry->compileGLObjects(renderInfo);
176        if (_quadGeometry->getStateSet()) _quadGeometry->getStateSet()->compileGLObjects(*renderInfo.getState());
177    }
178
179    if (_lineGeometry.valid())
180    {
181        _lineGeometry->compileGLObjects(renderInfo);
182        if (_lineGeometry->getStateSet()) _lineGeometry->getStateSet()->compileGLObjects(*renderInfo.getState());
183    }
184
185    if (_pointGeometry.valid())
186    {
187        _pointGeometry->compileGLObjects(renderInfo);
188        if (_pointGeometry->getStateSet()) _pointGeometry->getStateSet()->compileGLObjects(*renderInfo.getState());
189    }
190}
191
192
193void PrecipitationEffect::traverse(osg::NodeVisitor& nv)
194{
195    if (nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
196    {
197        if (_dirty) update();
198   
199        if (nv.getFrameStamp())
200        {
201            double currentTime = nv.getFrameStamp()->getSimulationTime();
202            static double previousTime = currentTime;
203            double delta = currentTime - previousTime;
204            _origin += _wind * delta;
205            previousTime = currentTime;
206        }
207
208        return;
209    }
210   
211    if (nv.getVisitorType() == osg::NodeVisitor::NODE_VISITOR)
212    {
213        if (_dirty) update();
214
215        osgUtil::GLObjectsVisitor* globjVisitor = dynamic_cast<osgUtil::GLObjectsVisitor*>(&nv);
216        if (globjVisitor)
217        {
218            if (globjVisitor->getMode() & osgUtil::GLObjectsVisitor::COMPILE_STATE_ATTRIBUTES)
219            {
220                compileGLObjects(globjVisitor->getRenderInfo());
221            }
222        }
223   
224        return;
225    }
226   
227
228    if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR)
229    {
230        return;
231    }
232
233    osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
234    if (!cv)
235    {
236        return;
237    }
238
239    ViewIdentifier viewIndentifier(cv, nv.getNodePath());
240   
241    {
242        PrecipitationDrawableSet* precipitationDrawableSet = 0;
243       
244        {
245            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
246            precipitationDrawableSet = &(_viewDrawableMap[viewIndentifier]);
247               
248            if (!precipitationDrawableSet->_quadPrecipitationDrawable)
249            {
250                precipitationDrawableSet->_quadPrecipitationDrawable = new PrecipitationDrawable;
251                precipitationDrawableSet->_quadPrecipitationDrawable->setRequiresPreviousMatrix(true);
252                precipitationDrawableSet->_quadPrecipitationDrawable->setGeometry(_quadGeometry.get());
253                precipitationDrawableSet->_quadPrecipitationDrawable->setStateSet(_quadStateSet.get());
254                precipitationDrawableSet->_quadPrecipitationDrawable->setDrawType(GL_QUADS);
255
256                precipitationDrawableSet->_linePrecipitationDrawable = new PrecipitationDrawable;
257                precipitationDrawableSet->_linePrecipitationDrawable->setRequiresPreviousMatrix(true);
258                precipitationDrawableSet->_linePrecipitationDrawable->setGeometry(_lineGeometry.get());
259                precipitationDrawableSet->_linePrecipitationDrawable->setStateSet(_lineStateSet.get());
260                precipitationDrawableSet->_linePrecipitationDrawable->setDrawType(GL_LINES);
261
262                precipitationDrawableSet->_pointPrecipitationDrawable = new PrecipitationDrawable;
263                precipitationDrawableSet->_pointPrecipitationDrawable->setRequiresPreviousMatrix(false);
264                precipitationDrawableSet->_pointPrecipitationDrawable->setGeometry(_pointGeometry.get());
265                precipitationDrawableSet->_pointPrecipitationDrawable->setStateSet(_pointStateSet.get());
266                precipitationDrawableSet->_pointPrecipitationDrawable->setDrawType(GL_POINTS);
267            }
268        }
269       
270        cull(*precipitationDrawableSet, cv);
271       
272        cv->pushStateSet(_stateset.get());
273        float depth = 0.0f;
274
275        if (!precipitationDrawableSet->_quadPrecipitationDrawable->getCurrentCellMatrixMap().empty())
276        {
277            cv->pushStateSet(precipitationDrawableSet->_quadPrecipitationDrawable->getStateSet());
278            cv->addDrawableAndDepth(precipitationDrawableSet->_quadPrecipitationDrawable.get(),cv->getModelViewMatrix(),depth);   
279            cv->popStateSet();
280        }
281
282        if (!precipitationDrawableSet->_linePrecipitationDrawable->getCurrentCellMatrixMap().empty())
283        {
284            cv->pushStateSet(precipitationDrawableSet->_linePrecipitationDrawable->getStateSet());
285            cv->addDrawableAndDepth(precipitationDrawableSet->_linePrecipitationDrawable.get(),cv->getModelViewMatrix(),depth);   
286            cv->popStateSet();
287        }
288
289        if (!precipitationDrawableSet->_pointPrecipitationDrawable->getCurrentCellMatrixMap().empty())
290        {
291            cv->pushStateSet(precipitationDrawableSet->_pointPrecipitationDrawable->getStateSet());
292            cv->addDrawableAndDepth(precipitationDrawableSet->_pointPrecipitationDrawable.get(),cv->getModelViewMatrix(),depth);   
293            cv->popStateSet();
294        }
295
296        cv->popStateSet();
297
298    }
299}
300
301void PrecipitationEffect::update()
302{
303    _dirty = false;
304
305    osg::notify(osg::INFO)<<"PrecipitationEffect::update()"<<std::endl;
306
307    float length_u = _cellSize.x();
308    float length_v = _cellSize.y();
309    float length_w = _cellSize.z();
310
311    // time taken to get from start to the end of cycle
312    _period = fabsf(_cellSize.z() / _particleSpeed);
313
314    _du.set(length_u, 0.0f, 0.0f);
315    _dv.set(0.0f, length_v, 0.0f);
316    _dw.set(0.0f, 0.0f, length_w);
317
318    _inverse_du.set(1.0f/length_u, 0.0f, 0.0f);
319    _inverse_dv.set(0.0f, 1.0f/length_v, 0.0f);
320    _inverse_dw.set(0.0f, 0.0f, 1.0f/length_w);
321   
322    osg::notify(osg::INFO)<<"Cell size X="<<length_u<<std::endl;
323    osg::notify(osg::INFO)<<"Cell size Y="<<length_v<<std::endl;
324    osg::notify(osg::INFO)<<"Cell size Z="<<length_w<<std::endl;
325   
326
327    {
328        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
329        _viewDrawableMap.clear();
330    }   
331
332    // set up state/
333    {
334        if (!_stateset)
335        {
336            _stateset = new osg::StateSet;
337            _stateset->addUniform(new osg::Uniform("baseTexture",0));
338
339            _stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
340            _stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
341
342            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));
343            _stateset->setTextureAttribute(0, texture);
344        }
345
346        if (!_inversePeriodUniform)
347        {
348            _inversePeriodUniform = new osg::Uniform("inversePeriod",1.0f/_period);
349            _stateset->addUniform(_inversePeriodUniform.get());
350        }
351        else _inversePeriodUniform->set(1.0f/_period);
352
353        if (!_particleColorUniform)
354        {
355            _particleColorUniform = new osg::Uniform("particleColour", _particleColor);
356            _stateset->addUniform(_particleColorUniform.get());
357        }
358        else _particleColorUniform->set(_particleColor);
359       
360        if (!_particleSizeUniform)
361        {
362            _particleSizeUniform = new osg::Uniform("particleSize", _particleSize);
363            _stateset->addUniform(_particleSizeUniform.get());
364        }
365        else _particleSizeUniform->set(_particleSize);
366
367    }
368       
369}
370
371void PrecipitationEffect::createGeometry(unsigned int numParticles,
372                    osg::Geometry* quad_geometry,
373                    osg::Geometry* line_geometry,
374                    osg::Geometry* point_geometry)
375{
376    // particle corner offsets
377    osg::Vec2 offset00(0.0f,0.0f);
378    osg::Vec2 offset10(1.0f,0.0f);
379    osg::Vec2 offset01(0.0f,1.0f);
380    osg::Vec2 offset11(1.0f,1.0f);
381   
382    osg::Vec2 offset0(0.5f,0.0f);
383    osg::Vec2 offset1(0.5f,1.0f);
384
385    osg::Vec2 offset(0.5f,0.5f);
386
387
388    // configure quad_geometry;
389    osg::Vec3Array* quad_vertices = 0;
390    osg::Vec2Array* quad_offsets = 0;
391    if (quad_geometry)
392    {
393        quad_geometry->setName("quad");
394   
395        quad_vertices = new osg::Vec3Array(numParticles*4);
396        quad_offsets = new osg::Vec2Array(numParticles*4);
397
398        quad_geometry->setVertexArray(quad_vertices);
399        quad_geometry->setTexCoordArray(0, quad_offsets);
400    }
401
402    // configure line_geometry;
403    osg::Vec3Array* line_vertices = 0;
404    osg::Vec2Array* line_offsets = 0;
405    if (line_geometry)
406    {
407        line_geometry->setName("line");
408
409        line_vertices = new osg::Vec3Array(numParticles*2);
410        line_offsets = new osg::Vec2Array(numParticles*2);
411
412        line_geometry->setVertexArray(line_vertices);
413        line_geometry->setTexCoordArray(0, line_offsets);
414    }
415
416    // configure point_geometry;
417    osg::Vec3Array* point_vertices = 0;
418    osg::Vec2Array* point_offsets = 0;
419    if (point_geometry)
420    {
421        point_geometry->setName("point");
422
423        point_vertices = new osg::Vec3Array(numParticles);
424        point_offsets = new osg::Vec2Array(numParticles);
425
426        point_geometry->setVertexArray(point_vertices);
427        point_geometry->setTexCoordArray(0, point_offsets);
428    }
429
430    // set up vertex attribute data.
431    for(unsigned int i=0; i< numParticles; ++i)
432    {
433        osg::Vec3 pos( random(0.0f, 1.0f), random(0.0f, 1.0f), random(0.0f, 1.0f));
434   
435        // quad particles
436        if (quad_vertices)
437        {
438            (*quad_vertices)[i*4] = pos;
439            (*quad_vertices)[i*4+1] = pos;
440            (*quad_vertices)[i*4+2] =  pos;
441            (*quad_vertices)[i*4+3] =  pos;
442            (*quad_offsets)[i*4] = offset00;
443            (*quad_offsets)[i*4+1] = offset01;
444            (*quad_offsets)[i*4+2] = offset11;
445            (*quad_offsets)[i*4+3] = offset10;
446        }
447               
448        // line particles
449        if (line_vertices)
450        {
451            (*line_vertices)[i*2] = pos;
452            (*line_vertices)[i*2+1] = pos;
453            (*line_offsets)[i*2] = offset0;
454            (*line_offsets)[i*2+1] = offset1;
455        }
456       
457        // point particles
458        if (point_vertices)
459        {
460            (*point_vertices)[i] = pos;
461            (*point_offsets)[i] = offset;
462        }
463    }
464}
465
466void PrecipitationEffect::setUpGeometries(unsigned int numParticles)
467{
468    unsigned int quadRenderBin = 13;
469    unsigned int lineRenderBin = 12;
470    unsigned int pointRenderBin = 11;
471   
472   
473    osg::notify(osg::INFO)<<"PrecipitationEffect::setUpGeometries("<<numParticles<<")"<<std::endl;
474
475    bool needGeometryRebuild = false;
476
477    if (!_quadGeometry || _quadGeometry->getVertexArray()->getNumElements() != 4*numParticles)
478    {
479        _quadGeometry = new osg::Geometry;
480        _quadGeometry->setUseVertexBufferObjects(true);
481        needGeometryRebuild = true;
482    }
483
484    if (!_lineGeometry || _lineGeometry->getVertexArray()->getNumElements() != 2*numParticles)
485    {
486        _lineGeometry = new osg::Geometry;
487        _lineGeometry->setUseVertexBufferObjects(true);
488        needGeometryRebuild = true;
489    }
490   
491    if (!_pointGeometry || _pointGeometry->getVertexArray()->getNumElements() != numParticles)
492    {
493        _pointGeometry = new osg::Geometry;
494        _pointGeometry->setUseVertexBufferObjects(true);
495        needGeometryRebuild = true;
496    }
497   
498    if (needGeometryRebuild)
499    {
500        createGeometry(numParticles, _quadGeometry.get(), _lineGeometry.get(), _pointGeometry.get());
501    }
502
503
504    if (!_quadStateSet)
505    {
506        _quadStateSet = new osg::StateSet;
507       
508        osg::Program* program = new osg::Program;
509        _quadStateSet->setAttribute(program);
510        _quadStateSet->setRenderBinDetails(quadRenderBin,"DepthSortedBin");
511
512#ifdef USE_LOCAL_SHADERS
513        char vertexShaderSource[] =
514            "uniform float inversePeriod;\n"
515            "uniform vec4 particleColour;\n"
516            "uniform float particleSize;\n"
517            "\n"
518            "uniform float osg_SimulationTime;\n"
519            "uniform float osg_DeltaSimulationTime;\n"
520            "\n"
521            "varying vec4 colour;\n"
522            "varying vec2 texCoord;\n"
523            "\n"
524            "void main(void)\n"
525            "{\n"
526            "    float offset = gl_Vertex.z;\n"
527            "    float startTime = gl_MultiTexCoord1.x;\n"
528            "    texCoord = gl_MultiTexCoord0.xy;\n"
529            "\n"
530            "    vec4 v_previous = gl_Vertex;\n"
531            "    v_previous.z = fract( (osg_SimulationTime - startTime)*inversePeriod - offset);\n"
532            "    \n"
533            "    vec4 v_current =  v_previous;\n"
534            "    v_current.z += (osg_DeltaSimulationTime*inversePeriod);\n"
535            "    \n"
536            "\n"
537            "    colour = particleColour;\n"
538            "    \n"
539            "    vec4 v1 = gl_ModelViewMatrix * v_current;\n"
540            "    vec4 v2 = gl_TextureMatrix[0] * v_previous;\n"
541            "    \n"
542            "    vec3 dv = v2.xyz - v1.xyz;\n"
543            "    \n"
544            "    vec2 dv_normalized = normalize(dv.xy);\n"
545            "    dv.xy += dv_normalized * particleSize;\n"
546            "    vec2 dp = vec2( -dv_normalized.y, dv_normalized.x ) * particleSize;\n"
547            "    \n"
548            "    float area = length(dv.xy);\n"
549            "    colour.a = 0.05+(particleSize)/area;\n"
550            "    \n"
551            "\n"
552            "    v1.xyz += dv*texCoord.y;\n"
553            "    v1.xy += dp*texCoord.x;\n"
554            "    \n"
555            "    gl_Position = gl_ProjectionMatrix * v1;\n"
556            "}\n";
557
558        char fragmentShaderSource[] =
559            "uniform sampler2D baseTexture;\n"
560            "varying vec2 texCoord;\n"
561            "varying vec4 colour;\n"
562            "\n"
563            "void main (void)\n"
564            "{\n"
565            "    gl_FragColor = colour * texture2D( baseTexture, texCoord);\n"
566            "}\n";
567
568        program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource));
569        program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource));
570#else
571        // get shaders from source
572        program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("quad_rain.vert")));
573        program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("rain.frag")));
574#endif
575    }
576
577
578    if (!_lineStateSet)
579    {
580        _lineStateSet = new osg::StateSet;
581
582        osg::Program* program = new osg::Program;
583        _lineStateSet->setAttribute(program);
584        _lineStateSet->setRenderBinDetails(lineRenderBin,"DepthSortedBin");
585
586#ifdef USE_LOCAL_SHADERS
587        char vertexShaderSource[] =
588            "uniform float inversePeriod;\n"
589            "uniform vec4 particleColour;\n"
590            "uniform float particleSize;\n"
591            "\n"
592            "uniform float osg_SimulationTime;\n"
593            "uniform float osg_DeltaSimulationTime;\n"
594            "uniform mat4 previousModelViewMatrix;\n"
595            "\n"
596            "varying vec4 colour;\n"
597            "varying vec2 texCoord;\n"
598            "\n"
599            "void main(void)\n"
600            "{\n"
601            "    float offset = gl_Vertex.z;\n"
602            "    float startTime = gl_MultiTexCoord1.x;\n"
603            "    texCoord = gl_MultiTexCoord0.xy;\n"
604            "\n"
605            "    vec4 v_previous = gl_Vertex;\n"
606            "    v_previous.z = fract( (osg_SimulationTime - startTime)*inversePeriod - offset);\n"
607            "    \n"
608            "    vec4 v_current =  v_previous;\n"
609            "    v_current.z += (osg_DeltaSimulationTime*inversePeriod);\n"
610            "    \n"
611            "    colour = particleColour;\n"
612            "    \n"
613            "    vec4 v1 = gl_ModelViewMatrix * v_current;\n"
614            "    vec4 v2 = gl_TextureMatrix[0] * v_previous;\n"
615            "    \n"
616            "    vec3 dv = v2.xyz - v1.xyz;\n"
617            "    \n"
618            "    vec2 dv_normalized = normalize(dv.xy);\n"
619            "    dv.xy += dv_normalized * particleSize;\n"
620            "    \n"
621            "    float area = length(dv.xy);\n"
622            "    colour.a = (particleSize)/area;\n"
623            "    \n"
624            "    v1.xyz += dv*texCoord.y;\n"
625            "    \n"
626            "    gl_Position = gl_ProjectionMatrix * v1;\n"
627            "}\n";
628
629        char fragmentShaderSource[] =
630            "uniform sampler2D baseTexture;\n"
631            "varying vec2 texCoord;\n"
632            "varying vec4 colour;\n"
633            "\n"
634            "void main (void)\n"
635            "{\n"
636            "    gl_FragColor = colour * texture2D( baseTexture, texCoord);\n"
637            "}\n";
638
639        program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource));
640        program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource));
641#else
642        // get shaders from source
643        program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("line_rain.vert")));
644        program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("rain.frag")));
645#endif
646    }
647
648
649    if (!_pointStateSet)
650    {
651        _pointStateSet = new osg::StateSet;
652
653        osg::Program* program = new osg::Program;
654        _pointStateSet->setAttribute(program);
655
656#ifdef USE_LOCAL_SHADERS
657        char vertexShaderSource[] =
658            "uniform float inversePeriod;\n"
659            "uniform vec4 particleColour;\n"
660            "uniform float particleSize;\n"
661            "\n"
662            "uniform float osg_SimulationTime;\n"
663            "\n"
664            "varying vec4 colour;\n"
665            "\n"
666            "void main(void)\n"
667            "{\n"
668            "    float offset = gl_Vertex.z;\n"
669            "    float startTime = gl_MultiTexCoord1.x;\n"
670            "\n"
671            "    vec4 v_current = gl_Vertex;\n"
672            "    v_current.z = fract( (osg_SimulationTime - startTime)*inversePeriod - offset);\n"
673            "   \n"
674            "    colour = particleColour;\n"
675            "\n"
676            "    gl_Position = gl_ModelViewProjectionMatrix * v_current;\n"
677            "\n"
678            "    float pointSize = abs(1280.0*particleSize / gl_Position.w);\n"
679            "\n"
680            "    //gl_PointSize = max(ceil(pointSize),2);\n"
681            "    gl_PointSize = ceil(pointSize);\n"
682            "    \n"
683            "    colour.a = 0.05+(pointSize*pointSize)/(gl_PointSize*gl_PointSize);\n"
684            "}\n";
685
686        char fragmentShaderSource[] =
687            "uniform sampler2D baseTexture;\n"
688            "varying vec4 colour;\n"
689            "\n"
690            "void main (void)\n"
691            "{\n"
692            "    gl_FragColor = colour * texture2D( baseTexture, gl_TexCoord[0].xy);\n"
693            "}\n";
694
695        program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource));
696        program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource));
697#else
698        // get shaders from source
699        program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("point_rain.vert")));
700        program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("point_rain.frag")));
701#endif
702
703        /// Setup the point sprites
704        osg::PointSprite *sprite = new osg::PointSprite();
705        _pointStateSet->setTextureAttributeAndModes(0, sprite, osg::StateAttribute::ON);
706
707        _pointStateSet->setMode(GL_VERTEX_PROGRAM_POINT_SIZE, osg::StateAttribute::ON);
708        _pointStateSet->setRenderBinDetails(pointRenderBin,"DepthSortedBin");
709    }
710
711
712}
713
714void PrecipitationEffect::cull(PrecipitationDrawableSet& pds, osgUtil::CullVisitor* cv) const
715{
716#ifdef DO_TIMING
717    osg::Timer_t startTick = osg::Timer::instance()->tick();
718#endif
719
720    float cellVolume = _cellSize.x() * _cellSize.y() * _cellSize.z();
721    int numberOfParticles = (int)(_maximumParticleDensity * cellVolume);
722
723    if (numberOfParticles==0) return;
724
725    pds._quadPrecipitationDrawable->setNumberOfVertices(numberOfParticles*4);
726    pds._linePrecipitationDrawable->setNumberOfVertices(numberOfParticles*2);
727    pds._pointPrecipitationDrawable->setNumberOfVertices(numberOfParticles);
728
729    pds._quadPrecipitationDrawable->newFrame();
730    pds._linePrecipitationDrawable->newFrame();
731    pds._pointPrecipitationDrawable->newFrame();
732
733    osg::Matrix inverse_modelview;
734    inverse_modelview.invert(*(cv->getModelViewMatrix()));
735   
736    osg::Vec3 eyeLocal = osg::Vec3(0.0f,0.0f,0.0f) * inverse_modelview;
737    //osg::notify(osg::NOTICE)<<"  eyeLocal "<<eyeLocal<<std::endl;
738   
739    float eye_k = (eyeLocal-_origin)*_inverse_dw;
740    osg::Vec3 eye_kPlane = eyeLocal-_dw*eye_k-_origin;
741   
742    // osg::notify(osg::NOTICE)<<"  eye_kPlane "<<eye_kPlane<<std::endl;
743   
744    float eye_i = eye_kPlane*_inverse_du;
745    float eye_j = eye_kPlane*_inverse_dv;
746   
747    osg::Polytope frustum;
748    frustum.setToUnitFrustum(false,false);
749    frustum.transformProvidingInverse(*(cv->getProjectionMatrix()));
750    frustum.transformProvidingInverse(*(cv->getModelViewMatrix()));
751
752    float i_delta = _farTransition * _inverse_du.x();
753    float j_delta = _farTransition * _inverse_dv.y();
754    float k_delta = 1;//_nearTransition * _inverse_dw.z();
755   
756    int i_min = (int)floor(eye_i - i_delta);
757    int j_min = (int)floor(eye_j - j_delta);
758    int k_min = (int)floor(eye_k - k_delta);
759
760    int i_max = (int)ceil(eye_i + i_delta);
761    int j_max = (int)ceil(eye_j + j_delta);
762    int k_max = (int)ceil(eye_k + k_delta);
763   
764    //osg::notify(osg::NOTICE)<<"i_delta="<<i_delta<<" j_delta="<<j_delta<<" k_delta="<<k_delta<<std::endl;
765
766    unsigned int numTested=0;
767    unsigned int numInFrustum=0;
768
769    float iCyle = 0.43;
770    float jCyle = 0.64;
771
772    for(int i = i_min; i<=i_max; ++i)
773    {
774        for(int j = j_min; j<=j_max; ++j)
775        {
776            for(int k = k_min; k<=k_max; ++k)
777            {
778                float startTime = (float)(i)*iCyle + (float)(j)*jCyle;
779                startTime = (startTime-floor(startTime))*_period;
780   
781                if (build(eyeLocal, i,j,k, startTime, pds, frustum, cv)) ++numInFrustum;
782                ++numTested;
783            }
784        }
785    }
786
787   
788#ifdef DO_TIMING
789    osg::Timer_t endTick = osg::Timer::instance()->tick();
790
791    osg::notify(osg::NOTICE)<<"time for cull "<<osg::Timer::instance()->delta_m(startTick,endTick)<<"ms  numTested="<<numTested<<" numInFrustum"<<numInFrustum<<std::endl;
792    osg::notify(osg::NOTICE)<<"     quads "<<pds._quadPrecipitationDrawable->getCurrentCellMatrixMap().size()<<"   lines "<<pds._linePrecipitationDrawable->getCurrentCellMatrixMap().size()<<"   points "<<pds._pointPrecipitationDrawable->getCurrentCellMatrixMap().size()<<std::endl;
793#endif
794}
795
796bool PrecipitationEffect::build(const osg::Vec3 eyeLocal, int i, int j, int k, float startTime, PrecipitationDrawableSet& pds, osg::Polytope& frustum, osgUtil::CullVisitor* cv) const
797{
798    osg::Vec3 position = _origin + osg::Vec3(float(i)*_du.x(), float(j)*_dv.y(), float(k+1)*_dw.z());
799    osg::Vec3 scale(_du.x(), _dv.y(), -_dw.z());
800
801    osg::BoundingBox bb(position.x(), position.y(), position.z()+scale.z(),
802                        position.x()+scale.x(), position.y()+scale.y(), position.z());
803                       
804    if (!frustum.contains(bb)) return false;
805
806    osg::Vec3 center = position + scale*0.5f;
807    float distance = (center-eyeLocal).length();
808
809    osg::Matrix* mymodelview = 0;
810    if (distance < _nearTransition)
811    {
812        PrecipitationDrawable::DepthMatrixStartTime& mstp = pds._quadPrecipitationDrawable->getCurrentCellMatrixMap()[PrecipitationDrawable::Cell(i,k,j)];
813        mstp.depth = distance;
814        mstp.startTime = startTime;
815        mymodelview = &mstp.modelview;
816    }
817    else if (distance <= _farTransition)
818    {
819        if (_useFarLineSegments)
820        {
821            PrecipitationDrawable::DepthMatrixStartTime& mstp = pds._linePrecipitationDrawable->getCurrentCellMatrixMap()[PrecipitationDrawable::Cell(i,k,j)];
822            mstp.depth = distance;
823            mstp.startTime = startTime;
824            mymodelview = &mstp.modelview;
825        }
826        else
827        {
828            PrecipitationDrawable::DepthMatrixStartTime& mstp = pds._pointPrecipitationDrawable->getCurrentCellMatrixMap()[PrecipitationDrawable::Cell(i,k,j)];
829            mstp.depth = distance;
830            mstp.startTime = startTime;
831            mymodelview = &mstp.modelview;
832        }
833    }
834    else
835    {
836        return false;
837    }
838
839    *mymodelview = *(cv->getModelViewMatrix());
840    mymodelview->preMult(osg::Matrix::translate(position));
841    mymodelview->preMult(osg::Matrix::scale(scale));
842   
843    cv->updateCalculatedNearFar(*(cv->getModelViewMatrix()),bb);
844
845    return true;
846}
847
848
849/////////////////////////////////////////////////////////////////////////////////////////////////////
850//
851//   Precipitation Drawable
852//
853////////////////////////////////////////////////////////////////////////////////////////////////////
854
855PrecipitationEffect::PrecipitationDrawable::PrecipitationDrawable():
856    _requiresPreviousMatrix(true),
857    _drawType(GL_QUADS),
858    _numberOfVertices(0)
859{
860    setSupportsDisplayList(false);
861}
862
863PrecipitationEffect::PrecipitationDrawable::PrecipitationDrawable(const PrecipitationDrawable& copy, const osg::CopyOp& copyop):
864    osg::Drawable(copy,copyop),
865    _requiresPreviousMatrix(copy._requiresPreviousMatrix),
866    _geometry(copy._geometry),
867    _drawType(copy._drawType),
868    _numberOfVertices(copy._numberOfVertices)
869{
870}
871
872
873
874void PrecipitationEffect::PrecipitationDrawable::drawImplementation(osg::RenderInfo& renderInfo) const
875{
876    if (!_geometry) return;
877
878    const osg::Geometry::Extensions* extensions = osg::Geometry::getExtensions(renderInfo.getContextID(),true);
879   
880    // save OpenGL matrices
881    glPushMatrix();
882   
883    if (_requiresPreviousMatrix)
884    {
885        renderInfo.getState()->setActiveTextureUnit(0);
886        glMatrixMode( GL_TEXTURE );
887        glPushMatrix();
888    }
889   
890    typedef std::vector<const CellMatrixMap::value_type*> DepthMatrixStartTimeVector;
891    DepthMatrixStartTimeVector orderedEntries;
892    orderedEntries.reserve(_currentCellMatrixMap.size());
893
894    for(CellMatrixMap::const_iterator citr = _currentCellMatrixMap.begin();
895        citr != _currentCellMatrixMap.end();
896        ++citr)
897    {
898        orderedEntries.push_back(&(*citr));
899    }
900   
901    std::sort(orderedEntries.begin(),orderedEntries.end(),LessFunctor());
902       
903    for(DepthMatrixStartTimeVector::reverse_iterator itr = orderedEntries.rbegin();
904        itr != orderedEntries.rend();
905        ++itr)
906    {
907        extensions->glMultiTexCoord1f(GL_TEXTURE0+1, (*itr)->second.startTime);
908
909        // load cells current modelview matrix
910        if (_requiresPreviousMatrix)
911        {
912            glMatrixMode( GL_MODELVIEW );
913            glLoadMatrix((*itr)->second.modelview.ptr());
914
915            CellMatrixMap::const_iterator pitr = _previousCellMatrixMap.find((*itr)->first);
916            if (pitr != _previousCellMatrixMap.end())
917            {
918                // load previous frame modelview matrix for motion blurr effect
919                glMatrixMode( GL_TEXTURE );
920                glLoadMatrix(pitr->second.modelview.ptr());   
921            }
922            else
923            {
924                // use current modelview matrix as "previous" frame value, cancelling motion blurr effect
925                glMatrixMode( GL_TEXTURE );
926                glLoadMatrix((*itr)->second.modelview.ptr());   
927            }
928        }
929        else
930        {
931            glLoadMatrix((*itr)->second.modelview.ptr());
932        }
933
934        _geometry->draw(renderInfo);
935       
936        unsigned int numVertices = osg::minimum(_geometry->getVertexArray()->getNumElements(), _numberOfVertices);
937        glDrawArrays(_drawType, 0, numVertices);
938    }
939
940    // restore OpenGL matrices
941    if (_requiresPreviousMatrix)
942    {
943        glPopMatrix();
944        glMatrixMode( GL_MODELVIEW );
945    }
946   
947    glPopMatrix();
948
949   
950}
Note: See TracBrowser for help on using the browser.