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

Revision 13041, 30.8 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

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