diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 209282b926..6ec2f7a2e2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2011,23 +2011,37 @@ void Application::update(float deltaTime) { _audio.eventuallyAnalyzePing(); #endif + if (TESTING_PARTICLE_SYSTEM) { if (_particleSystemInitialized) { - _particleSystem.simulate(deltaTime); - } else { - int coolDemoEmitter = _particleSystem.addEmitter(); + // update the particle system + _particleSystem.setUpDirection(glm::vec3(0.0f, 1.0f, 0.0f)); + _particleSystem.simulate(deltaTime); + _particleSystem.runSpecialEffectsTest(deltaTime); + } else { + // create a stable test emitter and spit out a bunch of particles + int coolDemoEmitter = _particleSystem.addEmitter(); if (coolDemoEmitter != -1) { - glm::vec3 particleEmitterPosition = glm::vec3(5.0f, 1.3f, 5.0f); + glm::vec3 particleEmitterPosition = glm::vec3(5.0f, 1.0f, 5.0f); _particleSystem.setEmitterPosition(coolDemoEmitter, particleEmitterPosition); - _particleSystem.emitParticlesNow(coolDemoEmitter, 1500); + float radius = 0.01f; + glm::vec4 color(0.0f, 0.0f, 0.0f, 1.0f); + glm::vec3 velocity(0.0f, 0.1f, 0.0f); + float lifespan = 100000.0f; + _particleSystem.emitParticlesNow(coolDemoEmitter, 1500, radius, color, velocity, lifespan); } + // determine a collision sphere glm::vec3 collisionSpherePosition = glm::vec3( 5.0f, 0.5f, 5.0f ); float collisionSphereRadius = 0.5f; _particleSystem.setCollisionSphere(collisionSpherePosition, collisionSphereRadius); + + // signal that the particle system has been initialized _particleSystemInitialized = true; - _particleSystem.useOrangeBlueColorPalette(); + + // apply a preset color palette + _particleSystem.setOrangeBlueColorPalette(); } } } diff --git a/interface/src/ParticleSystem.cpp b/interface/src/ParticleSystem.cpp index 0e762fdb0e..e6a3bfef7b 100644 --- a/interface/src/ParticleSystem.cpp +++ b/interface/src/ParticleSystem.cpp @@ -11,22 +11,28 @@ #include "ParticleSystem.h" #include "Application.h" +const float DEFAULT_PARTICLE_BOUNCE = 1.0f; +const float DEFAULT_PARTICLE_AIR_FRICTION = 2.0f; +const float DEFAULT_PARTICLE_JITTER = 0.05f; +const float DEFAULT_PARTICLE_GRAVITY = 0.05f; + ParticleSystem::ParticleSystem() { - _gravity = 0.005; - _numEmitters = 0; - _bounce = 0.9f; _timer = 0.0f; - _airFriction = 6.0f; - _jitter = 0.1f; - _homeAttraction = 0.0f; + _numEmitters = 0; + _gravity = DEFAULT_PARTICLE_GRAVITY; + _bounce = DEFAULT_PARTICLE_BOUNCE; + _airFriction = DEFAULT_PARTICLE_AIR_FRICTION; + _jitter = DEFAULT_PARTICLE_JITTER; + _emitterAttraction = 0.0f; _tornadoForce = 0.0f; - _neighborAttraction = 0.02f; - _neighborRepulsion = 0.9f; + _neighborAttraction = 0.0f; + _neighborRepulsion = 0.0f; _collisionSphereRadius = 0.0f; _collisionSpherePosition = glm::vec3(0.0f, 0.0f, 0.0f); _numParticles = 0; _usingCollisionSphere = false; + _upDirection = glm::vec3(0.0f, 1.0f, 0.0f); // default for (unsigned int e = 0; e < MAX_EMITTERS; e++) { _emitter[e].position = glm::vec3(0.0f, 0.0f, 0.0f); @@ -39,7 +45,8 @@ ParticleSystem::ParticleSystem() { for (unsigned int p = 0; p < MAX_PARTICLES; p++) { _particle[p].alive = false; _particle[p].age = 0.0f; - _particle[p].radius = 0.01f; + _particle[p].lifespan = 0.0f; + _particle[p].radius = 0.0f; _particle[p].emitterIndex = 0; _particle[p].position = glm::vec3(0.0f, 0.0f, 0.0f); _particle[p].velocity = glm::vec3(0.0f, 0.0f, 0.0f); @@ -71,9 +78,6 @@ void ParticleSystem::simulate(float deltaTime) { updateParticle(p, deltaTime); } } - - // apply special effects - runSpecialEffectsTest(deltaTime); } void ParticleSystem::updateEmitter(int e, float deltaTime) { @@ -84,39 +88,63 @@ void ParticleSystem::updateEmitter(int e, float deltaTime) { } - -void ParticleSystem::emitParticlesNow(int e, int num) { - - _numParticles = num; - - if (_numParticles > MAX_PARTICLES) { - _numParticles = MAX_PARTICLES; - } +void ParticleSystem::emitParticlesNow(int e, int num, float radius, glm::vec4 color, glm::vec3 velocity, float lifespan) { for (unsigned int p = 0; p < num; p++) { - _particle[p].alive = true; - _particle[p].position = _emitter[e].position; + createParticle(_emitter[e].position, velocity, radius, color, lifespan); } } -void ParticleSystem::useOrangeBlueColorPalette() { +void ParticleSystem::createParticle(glm::vec3 position, glm::vec3 velocity, float radius, glm::vec4 color, float lifespan) { + + for (unsigned int p = 0; p < MAX_PARTICLES; p++) { + if (!_particle[p].alive) { + + _particle[p].lifespan = lifespan; + _particle[p].alive = true; + _particle[p].age = 0.0f; + _particle[p].position = position; + _particle[p].velocity = velocity; + _particle[p].radius = radius; + _particle[p].color = color; + + _numParticles ++; + + assert(_numParticles <= MAX_PARTICLES); + + return; + } + } +} + +void ParticleSystem::killParticle(int p) { + + assert( p >= 0); + assert( p < MAX_PARTICLES); + assert( _numParticles > 0); + + _particle[p].alive = false; + _numParticles --; +} + + +void ParticleSystem::setOrangeBlueColorPalette() { for (unsigned int p = 0; p < _numParticles; p++) { float radian = ((float)p / (float)_numParticles) * PI_TIMES_TWO; float wave = sinf(radian); + float red = 0.5f + 0.5f * wave; float green = 0.3f + 0.3f * wave; float blue = 0.2f - 0.2f * wave; - _particle[p].color = glm::vec3(red, green, blue); + float alpha = 1.0f; + + _particle[p].color = glm::vec4(red, green, blue, alpha); } } - - - - void ParticleSystem::runSpecialEffectsTest(float deltaTime) { _timer += deltaTime; @@ -130,13 +158,13 @@ void ParticleSystem::runSpecialEffectsTest(float deltaTime) { _emitter[0].rotation = glm::quat(glm::radians(tilt)); - _gravity = 0.0f + 0.02f * sinf( _timer * 0.52f ); - _airFriction = 3.0f + 1.0f * sinf( _timer * 0.32f ); - _jitter = 0.05f + 0.05f * sinf( _timer * 0.42f ); - _homeAttraction = 0.01f + 0.01f * cosf( _timer * 0.6f ); - _tornadoForce = 0.0f + 0.03f * sinf( _timer * 0.7f ); - _neighborAttraction = 0.1f + 0.1f * cosf( _timer * 0.8f ); - _neighborRepulsion = 0.4f + 0.3f * sinf( _timer * 0.4f ); + _gravity = 0.0f + DEFAULT_PARTICLE_GRAVITY * sinf( _timer * 0.52f ); + _airFriction = (DEFAULT_PARTICLE_AIR_FRICTION + 0.5f) + 2.0f * sinf( _timer * 0.32f ); + _jitter = DEFAULT_PARTICLE_JITTER + DEFAULT_PARTICLE_JITTER * sinf( _timer * 0.42f ); + _emitterAttraction = 0.015f + 0.015f * cosf( _timer * 0.6f ); + _tornadoForce = 0.0f + 0.03f * sinf( _timer * 0.7f ); + _neighborAttraction = 0.1f + 0.1f * cosf( _timer * 0.8f ); + _neighborRepulsion = 0.2f + 0.2f * sinf( _timer * 0.4f ); if (_gravity < 0.0f) { _gravity = 0.0f; @@ -144,10 +172,13 @@ void ParticleSystem::runSpecialEffectsTest(float deltaTime) { } - void ParticleSystem::updateParticle(int p, float deltaTime) { _particle[p].age += deltaTime; + + if (_particle[p].age > _particle[p].lifespan) { + killParticle(p); + } // apply random jitter _particle[p].velocity += @@ -160,7 +191,7 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { // apply attraction to home position glm::vec3 vectorToHome = _emitter[_particle[p].emitterIndex].position - _particle[p].position; - _particle[p].velocity += vectorToHome * _homeAttraction * deltaTime; + _particle[p].velocity += vectorToHome * _emitterAttraction * deltaTime; // apply neighbor attraction int neighbor = p + 1; @@ -189,7 +220,7 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { } // apply gravity - _particle[p].velocity.y -= _gravity * deltaTime; + _particle[p].velocity -= _upDirection * _gravity * deltaTime; // update position by velocity _particle[p].position += _particle[p].velocity; @@ -239,11 +270,9 @@ void ParticleSystem::render() { } } - - void ParticleSystem::renderParticle(int p) { - glColor3f(_particle[p].color.x, _particle[p].color.y, _particle[p].color.z); + glColor4f(_particle[p].color.r, _particle[p].color.g, _particle[p].color.b, _particle[p].color.a ); glPushMatrix(); glTranslatef(_particle[p].position.x, _particle[p].position.y, _particle[p].position.z); glutSolidSphere(_particle[p].radius, 6, 6); diff --git a/interface/src/ParticleSystem.h b/interface/src/ParticleSystem.h index 701d1c85b7..f7f0063dbc 100644 --- a/interface/src/ParticleSystem.h +++ b/interface/src/ParticleSystem.h @@ -11,33 +11,27 @@ #include -const int MAX_PARTICLES = 5000; +const int MAX_PARTICLES = 10000; const int MAX_EMITTERS = 10; class ParticleSystem { public: ParticleSystem(); - int addEmitter(); // add (create) an emitter and get its unique id - void useOrangeBlueColorPalette(); // apply a nice preset color palette to the particles + int addEmitter(); // add (create) an emitter and get its unique id + void emitParticlesNow(int e, int numParticles, float radius, glm::vec4 color, glm::vec3 velocity, float lifespan); + void simulate(float deltaTime); + void render(); + void runSpecialEffectsTest(float deltaTime); // for debugging and artistic exploration + + void setOrangeBlueColorPalette(); // apply a nice preset color palette to the particles void setCollisionSphere(glm::vec3 position, float radius); // specify a sphere for the particles to collide with - void emitParticlesNow(int e, int numParticles); // tell this emitter to generate this many particles right now - void simulate(float deltaTime); // run it - void render(); // show it void setEmitterPosition(int e, glm::vec3 position) { _emitter[e].position = position; } // set the position of this emitter + void setEmitterRotation(int e, glm::quat rotation) { _emitter[e].rotation = rotation; } // set the rotation of this emitter + void setUpDirection(glm::vec3 upDirection) {_upDirection = upDirection;} // tell particle system which direction is up private: - struct Particle { - bool alive; - glm::vec3 position; - glm::vec3 velocity; - glm::vec3 color; - float age; - float radius; - int emitterIndex; - }; - struct Emitter { glm::vec3 position; glm::quat rotation; @@ -45,7 +39,19 @@ private: glm::vec3 up; glm::vec3 front; }; - + + struct Particle { + bool alive; // is the particle active? + glm::vec3 position; // position + glm::vec3 velocity; // velocity + glm::vec4 color; // color (rgba) + float age; // age in seconds + float radius; // radius + float lifespan; // how long this particle stays alive (in seconds) + int emitterIndex; // which emitter created this particle? + }; + + glm::vec3 _upDirection; float _bounce; float _gravity; float _timer; @@ -55,7 +61,7 @@ private: int _numEmitters; float _airFriction; float _jitter; - float _homeAttraction; + float _emitterAttraction; float _tornadoForce; float _neighborAttraction; float _neighborRepulsion; @@ -66,7 +72,8 @@ private: // private methods void updateEmitter(int e, float deltaTime); void updateParticle(int index, float deltaTime); - void runSpecialEffectsTest(float deltaTime); + void createParticle(glm::vec3 position, glm::vec3 velocity, float radius, glm::vec4 color, float lifespan); + void killParticle(int p); void renderEmitter(int emitterIndex, float size); void renderParticle(int p); };