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

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

From Mathias Froehlich, "This is a generic optimization that does not depend on any cpu or instruction
set.

The optimization is based on the observation that matrix matrix multiplication
with a dense matrix 4x4 is 43 Operations whereas multiplication with a
transform, or scale matrix is only 4
2 operations. Which is a gain of a
*FACTOR*4* for these special cases.
The change implements these special cases, provides a unit test for these
implementation and converts uses of the expensiver dense matrix matrix
routine with the specialized versions.

Depending on the transform nodes in the scenegraph this change gives a
noticable improovement.
For example the osgforest code using the MatrixTransform? is about 20% slower
than the same codepath using the PositionAttitudeTransform? instead of the
MatrixTransform? with this patch applied.

If I remember right, the sse type optimizations did *not* provide a factor 4
improovement. Also these changes are totally independent of any cpu or
instruction set architecture. So I would prefer to have this current kind of
change instead of some hand coded and cpu dependent assembly stuff. If we
need that hand tuned stuff, these can go on top of this changes which must
provide than hand optimized additional variants for the specialized versions
to give a even better result in the end.

An other change included here is a change to rotation matrix from quaterion
code. There is a sqrt call which couold be optimized away. Since we divide in
effect by sqrt(length)*sqrt(length) which is just length ...
"

  • 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->preMultTranslate(position);
841    mymodelview->preMultScale(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.