diff --git a/Horde3D/Source/Horde3DEngine/egParticle.cpp b/Horde3D/Source/Horde3DEngine/egParticle.cpp index 7d94e8a..e629274 100644 --- a/Horde3D/Source/Horde3DEngine/egParticle.cpp +++ b/Horde3D/Source/Horde3DEngine/egParticle.cpp @@ -75,6 +75,7 @@ void ParticleEffectResource::initDefault() { _lifeMin = 0; _lifeMax = 0; _moveVel.reset(); + _drag.reset(); _rotVel.reset(); _size.reset(); _colR.reset(); @@ -133,6 +134,7 @@ bool ParticleEffectResource::load( const char *data, int size ) if( node1.getAttribute( "channel" ) != 0x0 ) { if( _stricmp( node1.getAttribute( "channel" ), "moveVel" ) == 0 ) _moveVel.parse( node1 ); + else if( _stricmp( node1.getAttribute( "channel" ), "drag" ) == 0 ) _drag.parse( node1 ); else if( _stricmp( node1.getAttribute( "channel" ), "size" ) == 0 ) _size.parse( node1 ); else if( _stricmp( node1.getAttribute( "channel" ), "rotVel" ) == 0 ) _rotVel.parse( node1 ); else if( _stricmp( node1.getAttribute( "channel" ), "colR" ) == 0 ) _colR.parse( node1 ); @@ -156,6 +158,7 @@ int ParticleEffectResource::getElemCount( int elem ) { case ParticleEffectResData::ParticleElem: case ParticleEffectResData::ChanMoveVelElem: + case ParticleEffectResData::ChanDragElem: case ParticleEffectResData::ChanRotVelElem: case ParticleEffectResData::ChanSizeElem: case ParticleEffectResData::ChanColRElem: @@ -187,6 +190,9 @@ float ParticleEffectResource::getElemParamF( int elem, int elemIdx, int param, i case ParticleEffectResData::ChanMoveVelElem: chan = &_moveVel; break; + case ParticleEffectResData::ChanDragElem: + chan = &_drag; + break; case ParticleEffectResData::ChanRotVelElem: chan = &_rotVel; break; @@ -244,6 +250,9 @@ void ParticleEffectResource::setElemParamF( int elem, int elemIdx, int param, in case ParticleEffectResData::ChanMoveVelElem: chan = &_moveVel; break; + case ParticleEffectResData::ChanDragElem: + chan = &_drag; + break; case ParticleEffectResData::ChanRotVelElem: chan = &_rotVel; break; @@ -303,6 +312,7 @@ EmitterNode::EmitterNode( const EmitterNodeTpl &emitterTpl ) : _timeDelta = 0; _emissionAccum = 0; + _lastAbsTrans = _absTrans; _particles = 0x0; _parPositions = 0x0; @@ -557,11 +567,45 @@ void EmitterNode::onPostUpdate() _emissionAccum += _emissionRate * _timeDelta; else _delay -= _timeDelta; + + float couldCreateNumParticles = 0; + for( uint32 i = 0; i < _particleCount; ++i ) + { + ParticleData &p = _particles[i]; + if( p.life <= 0 && ((int)p.respawnCounter < _respawnCount || _respawnCount < 0) ) + { + couldCreateNumParticles += 1.0f; + if( couldCreateNumParticles >= _emissionAccum ) + { + break; + } + } + } + + float relMoveX = _absTrans.c[3][0] - _lastAbsTrans.c[3][0]; + float relMoveY = _absTrans.c[3][1] - _lastAbsTrans.c[3][1]; + float relMoveZ = _absTrans.c[3][2] - _lastAbsTrans.c[3][2]; + float relMoveFactorStep = 0.5f; + float relMoveFactor = 0.0f; + if ( couldCreateNumParticles >= 2.0f ) + { + relMoveFactorStep = 1.0 / floor( couldCreateNumParticles - 1.0f ); + } + + float relVelX = 0.0f; + float relVelY = 0.0f; + float relVelZ = 0.0f; + if ( _timeDelta > 0.0f ) + { + relVelX = relMoveX / _timeDelta; + relVelY = relMoveY / _timeDelta; + relVelZ = relMoveZ / _timeDelta; + } for( uint32 i = 0; i < _particleCount; ++i ) { ParticleData &p = _particles[i]; - + // Create particle if( p.life <= 0 && ((int)p.respawnCounter < _respawnCount || _respawnCount < 0) ) { @@ -578,6 +622,8 @@ void EmitterNode::onPostUpdate() ++p.respawnCounter; // Generate start values + p.dragVel0 = Vec3f(relVelX, relVelY, relVelZ); + p.drag0 = randomF( _effectRes->_drag.startMin, _effectRes->_drag.startMax ); p.moveVel0 = randomF( _effectRes->_moveVel.startMin, _effectRes->_moveVel.startMax ); p.rotVel0 = randomF( _effectRes->_rotVel.startMin, _effectRes->_rotVel.startMax ); p.size0 = randomF( _effectRes->_size.startMin, _effectRes->_size.startMax ); @@ -587,9 +633,10 @@ void EmitterNode::onPostUpdate() p.a0 = randomF( _effectRes->_colA.startMin, _effectRes->_colA.startMax ); // Update arrays - _parPositions[i * 3 + 0] = _absTrans.c[3][0]; - _parPositions[i * 3 + 1] = _absTrans.c[3][1]; - _parPositions[i * 3 + 2] = _absTrans.c[3][2]; + _parPositions[i * 3 + 0] = _lastAbsTrans.c[3][0] + relMoveX * relMoveFactor; + _parPositions[i * 3 + 1] = _lastAbsTrans.c[3][1] + relMoveY * relMoveFactor; + _parPositions[i * 3 + 2] = _lastAbsTrans.c[3][2] + relMoveZ * relMoveFactor; + relMoveFactor += relMoveFactorStep; _parSizesANDRotations[i * 2 + 0] = p.size0; _parSizesANDRotations[i * 2 + 1] = randomF( 0, 360 ); _parColors[i * 4 + 0] = p.r0; @@ -602,15 +649,15 @@ void EmitterNode::onPostUpdate() if( _emissionAccum < 0 ) _emissionAccum = 0; } } - // Update particle - if( p.life > 0 ) + else if ( p.life > 0 ) { // Interpolate data float fac = 1.0f - (p.life / p.maxLife); float moveVel = p.moveVel0 * (1.0f + (_effectRes->_moveVel.endRate - 1.0f) * fac); float rotVel = p.rotVel0 * (1.0f + (_effectRes->_rotVel.endRate - 1.0f) * fac); + float drag = p.drag0 * (1.0f + (_effectRes->_drag.endRate - 1.0f) * fac); _parSizesANDRotations[i * 2 + 0] = p.size0 * (1.0f + (_effectRes->_size.endRate - 1.0f) * fac); _parColors[i * 4 + 0] = p.r0 * (1.0f + (_effectRes->_colR.endRate - 1.0f) * fac); _parColors[i * 4 + 1] = p.g0 * (1.0f + (_effectRes->_colG.endRate - 1.0f) * fac); @@ -618,9 +665,9 @@ void EmitterNode::onPostUpdate() _parColors[i * 4 + 3] = p.a0 * (1.0f + (_effectRes->_colA.endRate - 1.0f) * fac); // Update particle position and rotation - _parPositions[i * 3 + 0] += (p.dir.x * moveVel + _force.x) * _timeDelta; - _parPositions[i * 3 + 1] += (p.dir.y * moveVel + _force.y) * _timeDelta; - _parPositions[i * 3 + 2] += (p.dir.z * moveVel + _force.z) * _timeDelta; + _parPositions[i * 3 + 0] += (p.dir.x * moveVel + _force.x + p.dragVel0.x * drag) * _timeDelta; + _parPositions[i * 3 + 1] += (p.dir.y * moveVel + _force.y + p.dragVel0.y * drag) * _timeDelta; + _parPositions[i * 3 + 2] += (p.dir.z * moveVel + _force.z + p.dragVel0.z * drag) * _timeDelta; _parSizesANDRotations[i * 2+ 1] += rotVel * _timeDelta; // Decrease lifetime @@ -652,4 +699,5 @@ void EmitterNode::onPostUpdate() _bBox.max = bBMax; _timeDelta = 0; + _lastAbsTrans = _absTrans; } diff --git a/Horde3D/Source/Horde3DEngine/egParticle.h b/Horde3D/Source/Horde3DEngine/egParticle.h index ccee78c..6a7a6bb 100644 --- a/Horde3D/Source/Horde3DEngine/egParticle.h +++ b/Horde3D/Source/Horde3DEngine/egParticle.h @@ -41,7 +41,8 @@ struct ParticleEffectResData PartLifeMaxF, ChanStartMinF, ChanStartMaxF, - ChanEndRateF + ChanEndRateF, + ChanDragElem, }; }; @@ -64,7 +65,7 @@ class ParticleEffectResource : public Resource private: float _lifeMin, _lifeMax; - ParticleChannel _moveVel, _rotVel; + ParticleChannel _moveVel, _rotVel, _drag; ParticleChannel _size; ParticleChannel _colR, _colG, _colB, _colA; @@ -142,6 +143,8 @@ struct ParticleData // Start values float moveVel0, rotVel0; + Vec3f dragVel0; + float drag0; float size0; float r0, g0, b0, a0; }; @@ -155,6 +158,7 @@ protected: // Emitter data float _timeDelta; float _emissionAccum; + Matrix4f _lastAbsTrans; // Emitter params PMaterialResource _materialRes;