root/OpenSceneGraph/trunk/src/osgParticle/Particle.cpp @ 10827

Revision 10827, 7.5 kB (checked in by robert, 4 years ago)

From Martin Scheffler, "osgParticle: method to set start and end tile for particle texture (for animated particles). I also updated examples/osgParticle to show the feature.
The texture in data/Images should be copied to osg-data. I created the texture myself with the help of an explosion generator, so no license issues there.
"

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <osgParticle/Particle>
2#include <osgParticle/LinearInterpolator>
3#include <osgParticle/ParticleSystem>
4
5#include <osg/Vec3>
6#include <osg/Vec4>
7#include <osg/Matrix>
8#include <osg/GL>
9#include <osg/Notify>
10
11namespace
12{
13
14    const float cosPI3 = cosf(osg::PI / 3.0f);
15    const float sinPI3 = sinf(osg::PI / 3.0f);
16    const float hex_texcoord_x1 = 0.5f + 0.5f * cosPI3;
17    const float hex_texcoord_x2 = 0.5f - 0.5f * cosPI3;
18    const float hex_texcoord_y1 = 0.5f + 0.5f * sinPI3;
19    const float hex_texcoord_y2 = 0.5f - 0.5f * sinPI3;
20
21}
22
23osgParticle::Particle::Particle()
24:   _shape(QUAD),
25    _sr(0.2f, 0.2f),
26    _ar(1, 0),
27    _cr(osg::Vec4(1, 1, 1, 1), osg::Vec4(1, 1, 1, 1)),
28    _si(new LinearInterpolator),
29    _ai(new LinearInterpolator),
30    _ci(new LinearInterpolator),
31    _alive(true),
32    _mustdie(false),
33    _lifeTime(2),
34    _radius(0.2f),
35    _mass(0.1f),
36    _massinv(10.0f),
37    _prev_pos(0, 0, 0),
38    _position(0, 0, 0),
39    _velocity(0, 0, 0),
40    _prev_angle(0, 0, 0),
41    _angle(0, 0, 0),
42    _angul_arvel(0, 0, 0),
43    _t0(0),
44    _current_size(0),
45    _current_alpha(0),
46    _s_tile(1.0f),
47    _t_tile(1.0f),
48    _start_tile(0),
49    _end_tile(0),
50    _cur_tile(-1),
51    _s_coord(0.0f),
52    _t_coord(0.0f),
53    _previousParticle(INVALID_INDEX),
54    _nextParticle(INVALID_INDEX)
55{
56}
57
58bool osgParticle::Particle::update(double dt)
59{
60    // this method should return false when the particle dies;
61    // so, if we were instructed to die, do it now and return.
62    if (_mustdie) {
63        _alive = false;
64        return false;
65    }
66
67    double x = 0;   
68
69    // if we don't live forever, compute our normalized age.
70    if (_lifeTime > 0) {
71        x = _t0 / _lifeTime;
72    }
73
74    _t0 += dt;
75
76    // if our age is over the lifetime limit, then die and return.
77    if (x > 1) {
78        _alive = false;
79        return false;
80    }
81
82    //Compute the current texture tile based on our normalized age
83    int currentTile = _start_tile + static_cast<int>(x * getNumTiles());
84   
85    //If the current texture tile is different from previous, then compute new texture coords
86    if(currentTile != _cur_tile)
87    {
88   
89        _cur_tile = currentTile;
90        _s_coord = _s_tile * fmod(_cur_tile , 1.0 / _s_tile);
91        _t_coord = 1.0 - _t_tile * (static_cast<int>(_cur_tile * _t_tile) + 1);
92
93        // osg::notify(osg::NOTICE)<<this<<" setting tex coords "<<_s_coord<<" "<<_t_coord<<std::endl;
94    }
95   
96    // compute the current values for size, alpha and color.
97    if (_lifeTime <= 0) {
98       if (dt == _t0) {
99          _current_size = _sr.get_random();
100          _current_alpha = _ar.get_random();
101          _current_color = _cr.get_random();
102       }
103    } else {
104       _current_size = _si.get()->interpolate(x, _sr);
105       _current_alpha = _ai.get()->interpolate(x, _ar);
106       _current_color = _ci.get()->interpolate(x, _cr);
107    }
108
109    // update position
110    _prev_pos = _position;
111    _position += _velocity * dt;
112
113    // update angle
114    _prev_angle = _angle;
115    _angle += _angul_arvel * dt;
116
117    if (_angle.x() > osg::PI*2) _angle.x() -= osg::PI*2;
118    if (_angle.x() < -osg::PI*2) _angle.x() += osg::PI*2;
119    if (_angle.y() > osg::PI*2) _angle.y() -= osg::PI*2;
120    if (_angle.y() < -osg::PI*2) _angle.y() += osg::PI*2;
121    if (_angle.z() > osg::PI*2) _angle.z() -= osg::PI*2;
122    if (_angle.z() < -osg::PI*2) _angle.z() += osg::PI*2;
123
124    return true;
125}
126
127void osgParticle::Particle::render(osg::GLBeginEndAdapter* gl, const osg::Vec3& xpos, const osg::Vec3& px, const osg::Vec3& py, float scale) const
128{
129    gl->Color4f( _current_color.x(),
130                _current_color.y(),
131                _current_color.z(),
132                _current_color.w() * _current_alpha);
133
134    osg::Vec3 p1(px * _current_size * scale);
135    osg::Vec3 p2(py * _current_size * scale);
136
137    switch (_shape)
138    {
139    case POINT:
140        gl->Vertex3f(xpos.x(), xpos.y(), xpos.z());
141        break;
142
143    case QUAD:
144        gl->TexCoord2f(_s_coord, _t_coord);
145        gl->Vertex3fv((xpos-(p1+p2)).ptr());
146        gl->TexCoord2f(_s_coord+_s_tile, _t_coord);
147        gl->Vertex3fv((xpos+(p1-p2)).ptr());
148        gl->TexCoord2f(_s_coord+_s_tile, _t_coord+_t_tile);
149        gl->Vertex3fv((xpos+(p1+p2)).ptr());
150        gl->TexCoord2f(_s_coord, _t_coord+_t_tile);
151        gl->Vertex3fv((xpos-(p1-p2)).ptr());
152        break;
153
154    case QUAD_TRIANGLESTRIP:
155        gl->PushMatrix();
156        gl->Translatef(xpos.x(), xpos.y(), xpos.z());
157        // we must gl.Begin() and gl.End() here, because each particle is a single strip
158        gl->Begin(GL_TRIANGLE_STRIP);
159        gl->TexCoord2f(_s_coord+_s_tile, _t_coord+_t_tile);
160        gl->Vertex3fv((p1+p2).ptr());
161        gl->TexCoord2f(_s_coord, _t_coord+_t_tile);
162        gl->Vertex3fv((-p1+p2).ptr());
163        gl->TexCoord2f(_s_coord+_s_tile, _t_coord);
164        gl->Vertex3fv((p1-p2).ptr());
165        gl->TexCoord2f(_s_coord, _t_coord);
166        gl->Vertex3fv((-p1-p2).ptr());
167        gl->End();
168        gl->PopMatrix();
169        break;
170
171    case HEXAGON:
172        gl->PushMatrix();
173        gl->Translatef(xpos.x(), xpos.y(), xpos.z());
174        // we must gl.Begin() and gl.End() here, because each particle is a single fan
175        gl->Begin(GL_TRIANGLE_FAN);
176        gl->TexCoord2f(_s_coord + _s_tile * 0.5f, _t_coord + _t_tile * 0.5f);
177        gl->Vertex3f(0,0,0);
178        gl->TexCoord2f(_s_coord + _s_tile * hex_texcoord_x1, _t_coord + _t_tile * hex_texcoord_y1);
179        gl->Vertex3fv((p1*cosPI3+p2*sinPI3).ptr());
180        gl->TexCoord2f(_s_coord + _s_tile * hex_texcoord_x2, _t_coord + _t_tile * hex_texcoord_y1);
181        gl->Vertex3fv((-p1*cosPI3+p2*sinPI3).ptr());
182        gl->TexCoord2f(_s_coord, _t_coord + _t_tile * 0.5f);
183        gl->Vertex3fv((-p1).ptr());
184        gl->TexCoord2f(_s_coord + _s_tile * hex_texcoord_x2, _t_coord + _t_tile * hex_texcoord_y2);
185        gl->Vertex3fv((-p1*cosPI3-p2*sinPI3).ptr());
186        gl->TexCoord2f(_s_coord + _s_tile * hex_texcoord_x1, _t_coord + _t_tile * hex_texcoord_y2);
187        gl->Vertex3fv((p1*cosPI3-p2*sinPI3).ptr());
188        gl->TexCoord2f(_s_coord + _s_tile, _t_coord + _t_tile * 0.5f);
189        gl->Vertex3fv((p1).ptr());
190        gl->TexCoord2f(_s_coord + _s_tile * hex_texcoord_x1, _t_coord + _t_tile * hex_texcoord_y1);
191        gl->Vertex3fv((p1*cosPI3+p2*sinPI3).ptr());
192        gl->End();
193        break;
194
195    case LINE:
196        {
197            // Get the normalized direction of the particle, to be used in the
198            // calculation of one of the linesegment endpoints.
199            float vl = _velocity.length();
200            if (vl != 0) {
201                osg::Vec3 v = _velocity * _current_size * scale / vl;
202
203                gl->TexCoord1f(0);
204                gl->Vertex3f(xpos.x(), xpos.y(), xpos.z());
205                gl->TexCoord1f(1);
206                gl->Vertex3f(xpos.x() + v.x(), xpos.y() + v.y(), xpos.z() + v.z());
207            }
208        }
209        break;
210
211    default:
212        osg::notify(osg::WARN) << "Invalid shape for particles\n";
213    }
214}
215
216void osgParticle::Particle::setUpTexCoordsAsPartOfConnectedParticleSystem(ParticleSystem* ps)
217{
218    if (getPreviousParticle()!=Particle::INVALID_INDEX)
219    {
220        update(0.0);
221
222        Particle* previousParticle = ps->getParticle(getPreviousParticle());
223        const osg::Vec3& previousPosition = previousParticle->getPosition();
224        const osg::Vec3& newPosition = getPosition();
225        float distance = (newPosition-previousPosition).length();
226        float s_coord_delta = 0.5f*distance/getCurrentSize();
227        float s_coord = previousParticle->_s_coord + s_coord_delta;
228
229        setTextureTile(1,1,0);
230        _cur_tile = 0;
231        _s_coord = s_coord;
232        _t_coord = 0.0f;
233    }
234}
Note: See TracBrowser for help on using the browser.