From 5a0fcb7f6c2ed9a060c35ab72880b36657e020af Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 17 Jul 2013 13:47:18 -0700 Subject: [PATCH 1/4] adding more behavior to the particle system --- interface/src/Application.cpp | 4 +- interface/src/Hand.cpp | 24 ++-- interface/src/ParticleSystem.cpp | 185 ++++++++++++++++++++----------- interface/src/ParticleSystem.h | 32 +++--- 4 files changed, 148 insertions(+), 97 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 582bc4fcb4..dc57e83a4e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2022,7 +2022,7 @@ void Application::update(float deltaTime) { if (_myAvatar.getMode() == AVATAR_MODE_WALKING) { _handControl.stop(); } - + // Update from Touch if (_isTouchPressed) { float TOUCH_YAW_SCALE = -50.0f; @@ -3562,7 +3562,7 @@ void Application::updateParticleSystem(float deltaTime) { attributes.gravity = 0.0f; } - _particleSystem.setParticleAttributesForEmitter(_coolDemoParticleEmitter, attributes); + _particleSystem.setParticleAttributes(_coolDemoParticleEmitter, attributes); } _particleSystem.setUpDirection(glm::vec3(0.0f, 1.0f, 0.0f)); diff --git a/interface/src/Hand.cpp b/interface/src/Hand.cpp index 13365ca8ec..8981819fe5 100755 --- a/interface/src/Hand.cpp +++ b/interface/src/Hand.cpp @@ -178,7 +178,7 @@ void Hand::updateFingerParticles(float deltaTime) { if (!_particleSystemInitialized) { for ( int f = 0; f< NUM_FINGERS_PER_HAND; f ++ ) { _fingerParticleEmitter[f] = _particleSystem.addEmitter(); - _particleSystem.setShowingEmitter(_fingerParticleEmitter[f], true); + //_particleSystem.setShowingEmitter(_fingerParticleEmitter[f], true); } _particleSystemInitialized = true; } else { @@ -193,23 +193,23 @@ void Hand::updateFingerParticles(float deltaTime) { glm::vec3 particleEmitterPosition = leapPositionToWorldPosition(_fingerTips[f]); - // this aspect is still being designed.... - - glm::vec3 tilt = glm::vec3 - ( - 30.0f * sinf( t * 0.55f ), - 0.0f, - 30.0f * cosf( t * 0.75f ) - ); - - glm::quat particleEmitterRotation = glm::quat(glm::radians(tilt)); + glm::vec3 fingerDirection = particleEmitterPosition - leapPositionToWorldPosition(_fingerRoots[f]); + float fingerLength = glm::length(fingerDirection); + + if (fingerLength > 0.0f) { + fingerDirection /= fingerLength; + } else { + fingerDirection = IDENTITY_UP; + } + + glm::quat particleEmitterRotation = rotationBetween(IDENTITY_UP, fingerDirection); _particleSystem.setEmitterPosition(_fingerParticleEmitter[0], particleEmitterPosition); _particleSystem.setEmitterRotation(_fingerParticleEmitter[0], particleEmitterRotation); float radius = 0.005f; glm::vec4 color(1.0f, 0.6f, 0.0f, 0.5f); - glm::vec3 velocity(0.0f, 0.005f, 0.0f); + glm::vec3 velocity = fingerDirection * 0.005f; float lifespan = 0.3f; _particleSystem.emitParticlesNow(_fingerParticleEmitter[0], 1, radius, color, velocity, lifespan); } diff --git a/interface/src/ParticleSystem.cpp b/interface/src/ParticleSystem.cpp index fcc24a2663..bd364959d3 100644 --- a/interface/src/ParticleSystem.cpp +++ b/interface/src/ParticleSystem.cpp @@ -16,29 +16,31 @@ const float DEFAULT_PARTICLE_AIR_FRICTION = 2.0f; ParticleSystem::ParticleSystem() { - _timer = 0.0f; _numEmitters = 0; _numParticles = 0; _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); - _emitter[e].rotation = glm::quat(); - _emitter[e].right = IDENTITY_RIGHT; - _emitter[e].up = IDENTITY_UP; - _emitter[e].front = IDENTITY_FRONT; - _emitter[e].showingEmitter = false; - _emitter[e].particleAttributes.bounce = DEFAULT_PARTICLE_BOUNCE; - _emitter[e].particleAttributes.airFriction = DEFAULT_PARTICLE_AIR_FRICTION; - _emitter[e].particleAttributes.gravity = 0.0f; - _emitter[e].particleAttributes.jitter = 0.0f; - _emitter[e].particleAttributes.emitterAttraction = 0.0f; - _emitter[e].particleAttributes.tornadoForce = 0.0f; - _emitter[e].particleAttributes.neighborAttraction = 0.0f; - _emitter[e].particleAttributes.neighborRepulsion = 0.0f; - _emitter[e].particleAttributes.collisionSphereRadius = 0.0f; - _emitter[e].particleAttributes.collisionSpherePosition = glm::vec3(0.0f, 0.0f, 0.0f); - _emitter[e].particleAttributes.usingCollisionSphere = false; + _emitter[e].position = glm::vec3(0.0f, 0.0f, 0.0f); + _emitter[e].rotation = glm::quat(); + _emitter[e].right = IDENTITY_RIGHT; + _emitter[e].up = IDENTITY_UP; + _emitter[e].front = IDENTITY_FRONT; + _emitter[e].visible = false; + + for (int s = 0; s _particle[p].lifespan) { + killParticle(p); + } else { + updateParticle(p, deltaTime); + } } } } + void ParticleSystem::updateEmitter(int e, float deltaTime) { _emitter[e].front = _emitter[e].rotation * IDENTITY_FRONT; @@ -146,45 +152,54 @@ void ParticleSystem::setOrangeBlueColorPalette() { } -void ParticleSystem::setParticleAttributesForEmitter(int emitterIndex, ParticleAttributes attributes) { +void ParticleSystem::setParticleAttributes(int emitterIndex, ParticleAttributes attributes) { - _emitter[emitterIndex].particleAttributes.bounce = attributes.bounce; - _emitter[emitterIndex].particleAttributes.gravity = attributes.gravity; - _emitter[emitterIndex].particleAttributes.airFriction = attributes.airFriction; - _emitter[emitterIndex].particleAttributes.jitter = attributes.jitter; - _emitter[emitterIndex].particleAttributes.emitterAttraction = attributes.emitterAttraction; - _emitter[emitterIndex].particleAttributes.tornadoForce = attributes.tornadoForce; - _emitter[emitterIndex].particleAttributes.neighborAttraction = attributes.neighborAttraction; - _emitter[emitterIndex].particleAttributes.neighborRepulsion = attributes.neighborRepulsion; - _emitter[emitterIndex].particleAttributes.usingCollisionSphere = attributes.usingCollisionSphere; - _emitter[emitterIndex].particleAttributes.collisionSpherePosition = attributes.collisionSpherePosition; - _emitter[emitterIndex].particleAttributes.collisionSphereRadius = attributes.collisionSphereRadius; + for (int lifeStage = 0; lifeStage < NUM_PARTICLE_LIFE_STAGES; lifeStage ++ ) { + setParticleAttributes(emitterIndex, lifeStage, attributes); + } } +void ParticleSystem::setParticleAttributes(int emitterIndex, int lifeStage, ParticleAttributes attributes) { + + ParticleAttributes * a = &_emitter[emitterIndex].particleAttributes[lifeStage]; + + a->bounce = attributes.bounce; + a->gravity = attributes.gravity; + a->airFriction = attributes.airFriction; + a->jitter = attributes.jitter; + a->emitterAttraction = attributes.emitterAttraction; + a->tornadoForce = attributes.tornadoForce; + a->neighborAttraction = attributes.neighborAttraction; + a->neighborRepulsion = attributes.neighborRepulsion; + a->usingCollisionSphere = attributes.usingCollisionSphere; + a->collisionSpherePosition = attributes.collisionSpherePosition; + a->collisionSphereRadius = attributes.collisionSphereRadius; +} void ParticleSystem::updateParticle(int p, float deltaTime) { - _particle[p].age += deltaTime; + assert(_particle[p].age <= _particle[p].lifespan); + + float ageFraction = _particle[p].age / _particle[p].lifespan; - if (_particle[p].age > _particle[p].lifespan) { - killParticle(p); - } + int lifeStage = (int)( ageFraction * NUM_PARTICLE_LIFE_STAGES ); Emitter myEmitter = _emitter[_particle[p].emitterIndex]; // apply random jitter + float j = myEmitter.particleAttributes[lifeStage].jitter; _particle[p].velocity += glm::vec3 ( - -myEmitter.particleAttributes.jitter * ONE_HALF + myEmitter.particleAttributes.jitter * randFloat(), - -myEmitter.particleAttributes.jitter * ONE_HALF + myEmitter.particleAttributes.jitter * randFloat(), - -myEmitter.particleAttributes.jitter * ONE_HALF + myEmitter.particleAttributes.jitter * randFloat() + -j * ONE_HALF + j * randFloat(), + -j * ONE_HALF + j * randFloat(), + -j * ONE_HALF + j * randFloat() ) * deltaTime; // apply attraction to home position glm::vec3 vectorToHome = myEmitter.position - _particle[p].position; - _particle[p].velocity += vectorToHome * myEmitter.particleAttributes.emitterAttraction * deltaTime; + _particle[p].velocity += vectorToHome * myEmitter.particleAttributes[lifeStage].emitterAttraction * deltaTime; // apply neighbor attraction int neighbor = p + 1; @@ -195,20 +210,20 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { if ( _particle[neighbor].emitterIndex == _particle[p].emitterIndex) { glm::vec3 vectorToNeighbor = _particle[p].position - _particle[neighbor].position; - _particle[p].velocity -= vectorToNeighbor * myEmitter.particleAttributes.neighborAttraction * deltaTime; + _particle[p].velocity -= vectorToNeighbor * myEmitter.particleAttributes[lifeStage].neighborAttraction * deltaTime; float distanceToNeighbor = glm::length(vectorToNeighbor); if (distanceToNeighbor > 0.0f) { - _particle[neighbor].velocity += (vectorToNeighbor / ( 1.0f + distanceToNeighbor * distanceToNeighbor)) * myEmitter.particleAttributes.neighborRepulsion * deltaTime; + _particle[neighbor].velocity += (vectorToNeighbor / ( 1.0f + distanceToNeighbor * distanceToNeighbor)) * myEmitter.particleAttributes[lifeStage].neighborRepulsion * deltaTime; } } // apply tornado force glm::vec3 tornadoDirection = glm::cross(vectorToHome, myEmitter.up); - _particle[p].velocity += tornadoDirection * myEmitter.particleAttributes.tornadoForce * deltaTime; + _particle[p].velocity += tornadoDirection * myEmitter.particleAttributes[lifeStage].tornadoForce * deltaTime; // apply air friction - float drag = 1.0 - myEmitter.particleAttributes.airFriction * deltaTime; + float drag = 1.0 - myEmitter.particleAttributes[lifeStage].airFriction * deltaTime; if (drag < 0.0f) { _particle[p].velocity = glm::vec3(0.0f, 0.0f, 0.0f); } else { @@ -216,7 +231,7 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { } // apply gravity - _particle[p].velocity -= _upDirection * myEmitter.particleAttributes.gravity * deltaTime; + _particle[p].velocity -= _upDirection * myEmitter.particleAttributes[lifeStage].gravity * deltaTime; // update position by velocity _particle[p].position += _particle[p].velocity; @@ -226,36 +241,42 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { _particle[p].position.y = _particle[p].radius; if (_particle[p].velocity.y < 0.0f) { - _particle[p].velocity.y *= -myEmitter.particleAttributes.bounce; + _particle[p].velocity.y *= -myEmitter.particleAttributes[lifeStage].bounce; } } // collision with sphere - if (myEmitter.particleAttributes.usingCollisionSphere) { - glm::vec3 vectorToSphereCenter = myEmitter.particleAttributes.collisionSpherePosition - _particle[p].position; + if (myEmitter.particleAttributes[lifeStage].usingCollisionSphere) { + glm::vec3 vectorToSphereCenter = myEmitter.particleAttributes[lifeStage].collisionSpherePosition - _particle[p].position; float distanceToSphereCenter = glm::length(vectorToSphereCenter); - float combinedRadius = myEmitter.particleAttributes.collisionSphereRadius + _particle[p].radius; + float combinedRadius = myEmitter.particleAttributes[lifeStage].collisionSphereRadius + _particle[p].radius; if (distanceToSphereCenter < combinedRadius) { if (distanceToSphereCenter > 0.0f){ glm::vec3 directionToSphereCenter = vectorToSphereCenter / distanceToSphereCenter; - _particle[p].position = myEmitter.particleAttributes.collisionSpherePosition - directionToSphereCenter * combinedRadius; + _particle[p].position = myEmitter.particleAttributes[lifeStage].collisionSpherePosition - directionToSphereCenter * combinedRadius; } } } + + // do this at the end... + _particle[p].age += deltaTime; } void ParticleSystem::setCollisionSphere(int e, glm::vec3 position, float radius) { - _emitter[e].particleAttributes.usingCollisionSphere = true; - _emitter[e].particleAttributes.collisionSpherePosition = position; - _emitter[e].particleAttributes.collisionSphereRadius = radius; + + int lifeStage = 0; + + _emitter[e].particleAttributes[lifeStage].usingCollisionSphere = true; + _emitter[e].particleAttributes[lifeStage].collisionSpherePosition = position; + _emitter[e].particleAttributes[lifeStage].collisionSphereRadius = radius; } void ParticleSystem::render() { // render the emitters for (unsigned int e = 0; e < _numEmitters; e++) { - if (_emitter[e].showingEmitter) { + if (_emitter[e].visible) { renderEmitter(e, 0.2f); } }; @@ -271,19 +292,49 @@ void ParticleSystem::render() { void ParticleSystem::renderParticle(int p) { 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); - glPopMatrix(); - // render velocity lines - glColor4f( _particle[p].color.x, _particle[p].color.y, _particle[p].color.z, 0.5f); - glm::vec3 end = _particle[p].position - _particle[p].velocity * 2.0f; - glBegin(GL_LINES); - glVertex3f(_particle[p].position.x, _particle[p].position.y, _particle[p].position.z); - glVertex3f(end.x, end.y, end.z); - - glEnd(); + if (USE_BILLBOARD_RENDERING) { + glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition(); + glm::vec3 viewVector = _particle[p].position - cameraPosition; + float distance = glm::length(viewVector); + + if (distance >= 0.0f) { + viewVector /= distance; + glm::vec3 up = glm::vec3(viewVector.y, viewVector.z, viewVector.x); + glm::vec3 right = glm::vec3(viewVector.z, viewVector.x, viewVector.y); + + glm::vec3 p0 = _particle[p].position - right * _particle[p].radius - up * _particle[p].radius; + glm::vec3 p1 = _particle[p].position + right * _particle[p].radius - up * _particle[p].radius; + glm::vec3 p2 = _particle[p].position + right * _particle[p].radius + up * _particle[p].radius; + glm::vec3 p3 = _particle[p].position - right * _particle[p].radius + up * _particle[p].radius; + + glBegin(GL_TRIANGLES); + glVertex3f(p0.x, p0.y, p0.z); + glVertex3f(p1.x, p1.y, p1.z); + glVertex3f(p2.x, p2.y, p2.z); + glEnd(); + + glBegin(GL_TRIANGLES); + glVertex3f(p0.x, p0.y, p0.z); + glVertex3f(p2.x, p2.y, p2.z); + glVertex3f(p3.x, p3.y, p3.z); + glEnd(); + } + } else { + glPushMatrix(); + glTranslatef(_particle[p].position.x, _particle[p].position.y, _particle[p].position.z); + glutSolidSphere(_particle[p].radius, 6, 6); + glPopMatrix(); + + // render velocity lines + glColor4f( _particle[p].color.x, _particle[p].color.y, _particle[p].color.z, 0.5f); + glm::vec3 end = _particle[p].position - _particle[p].velocity * 2.0f; + glBegin(GL_LINES); + glVertex3f(_particle[p].position.x, _particle[p].position.y, _particle[p].position.z); + glVertex3f(end.x, end.y, end.z); + + glEnd(); + } } @@ -293,7 +344,7 @@ void ParticleSystem::renderEmitter(int e, float size) { glm::vec3 r = _emitter[e].right * size; glm::vec3 u = _emitter[e].up * size; glm::vec3 f = _emitter[e].front * size; - + glLineWidth(2.0f); glColor3f(0.8f, 0.4, 0.4); diff --git a/interface/src/ParticleSystem.h b/interface/src/ParticleSystem.h index c94acd03ba..37fd5fb9db 100644 --- a/interface/src/ParticleSystem.h +++ b/interface/src/ParticleSystem.h @@ -11,8 +11,10 @@ #include -const int MAX_PARTICLES = 5000; -const int MAX_EMITTERS = 20; +const int MAX_PARTICLES = 5000; +const int MAX_EMITTERS = 20; +const int NUM_PARTICLE_LIFE_STAGES = 3; +const bool USE_BILLBOARD_RENDERING = false; class ParticleSystem { public: @@ -34,29 +36,29 @@ public: ParticleSystem(); 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 emitParticlesNow(int emitterIndex, int numParticles, float radius, glm::vec4 color, glm::vec3 velocity, float lifespan); void simulate(float deltaTime); void render(); - void setParticleAttributesForEmitter(int emitterIndex, ParticleAttributes attributes); void setOrangeBlueColorPalette(); // apply a nice preset color palette to the particles void setUpDirection(glm::vec3 upDirection) {_upDirection = upDirection;} // tell particle system which direction is up - - void setCollisionSphere(int emitterIndex, glm::vec3 position, float radius); // specify a sphere for the particles to collide with - void setEmitterPosition(int emitterIndex, glm::vec3 position) { _emitter[emitterIndex].position = position; } // set position of emitter - void setEmitterRotation(int emitterIndex, glm::quat rotation) { _emitter[emitterIndex].rotation = rotation; } // set rotation of emitter - void setShowingEmitter (int emitterIndex, bool showing ) { _emitter[emitterIndex].showingEmitter = showing; } // set its visibiity + void setParticleAttributes(int emitterIndex, ParticleAttributes attributes); + void setParticleAttributes(int emitterIndex, int lifeStage, ParticleAttributes attributes); + void setCollisionSphere (int emitterIndex, glm::vec3 position, float radius); // specify a sphere for the particles to collide with + void setEmitterPosition (int emitterIndex, glm::vec3 position) { _emitter[emitterIndex].position = position; } // set position of emitter + void setEmitterRotation (int emitterIndex, glm::quat rotation) { _emitter[emitterIndex].rotation = rotation; } // set rotation of emitter + void setShowingEmitter (int emitterIndex, bool showing ) { _emitter[emitterIndex].visible = showing; } // set its visibiity private: struct Emitter { glm::vec3 position; glm::quat rotation; - glm::vec3 right; - glm::vec3 up; - glm::vec3 front; - bool showingEmitter; - ParticleAttributes particleAttributes; + glm::vec3 right; // derived from rotation + glm::vec3 up; // derived from rotation + glm::vec3 front; // derived from rotation + bool visible; + ParticleAttributes particleAttributes[NUM_PARTICLE_LIFE_STAGES]; // the attributes of particles emitted from this emitter }; struct Particle { @@ -71,7 +73,6 @@ private: }; glm::vec3 _upDirection; - float _timer; Emitter _emitter[MAX_EMITTERS]; Particle _particle[MAX_PARTICLES]; int _numParticles; @@ -81,7 +82,6 @@ private: void updateEmitter(int e, float deltaTime); void updateParticle(int index, float deltaTime); void createParticle(int e, glm::vec3 position, glm::vec3 velocity, float radius, glm::vec4 color, float lifespan); - //void runSpecialEffectsTest(int e, float deltaTime); // for debugging and artistic exploration void killParticle(int p); void renderEmitter(int emitterIndex, float size); void renderParticle(int p); From 202fb95102dcb11b3418e24879324e61cebb2241 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 17 Jul 2013 13:51:00 -0700 Subject: [PATCH 2/4] turned off setShowingEmitter --- interface/src/Application.cpp | 2 +- interface/src/Hand.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index dc57e83a4e..6ba1134d05 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -73,7 +73,7 @@ using namespace std; static char STAR_FILE[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt"; static char STAR_CACHE_FILE[] = "cachedStars.txt"; -static const bool TESTING_PARTICLE_SYSTEM = false; +static const bool TESTING_PARTICLE_SYSTEM = true; static const int BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH = 6; // farther dragged clicks are ignored diff --git a/interface/src/Hand.cpp b/interface/src/Hand.cpp index 8981819fe5..558b4fa886 100755 --- a/interface/src/Hand.cpp +++ b/interface/src/Hand.cpp @@ -178,7 +178,6 @@ void Hand::updateFingerParticles(float deltaTime) { if (!_particleSystemInitialized) { for ( int f = 0; f< NUM_FINGERS_PER_HAND; f ++ ) { _fingerParticleEmitter[f] = _particleSystem.addEmitter(); - //_particleSystem.setShowingEmitter(_fingerParticleEmitter[f], true); } _particleSystemInitialized = true; } else { From d0dffb464bda481c0da5391041b6ee9b0a35a74c Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 17 Jul 2013 14:51:11 -0700 Subject: [PATCH 3/4] added emitter particle --- interface/src/Application.cpp | 1 + interface/src/Hand.cpp | 32 +++++++++++++++++++- interface/src/ParticleSystem.cpp | 50 ++++++++++++++++++++++++++++++-- interface/src/ParticleSystem.h | 24 ++++++++------- 4 files changed, 93 insertions(+), 14 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6ba1134d05..4e0a815ef8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3546,6 +3546,7 @@ void Application::updateParticleSystem(float deltaTime) { ParticleSystem::ParticleAttributes attributes; + attributes.radius = 0.01f; attributes.gravity = 0.0f + 0.05f * sinf( t * 0.52f ); attributes.airFriction = 2.5 + 2.0f * sinf( t * 0.32f ); attributes.jitter = 0.05f + 0.05f * sinf( t * 0.42f ); diff --git a/interface/src/Hand.cpp b/interface/src/Hand.cpp index 558b4fa886..8e16540d55 100755 --- a/interface/src/Hand.cpp +++ b/interface/src/Hand.cpp @@ -176,9 +176,39 @@ void Hand::setLeapHands(const std::vector& handPositions, void Hand::updateFingerParticles(float deltaTime) { if (!_particleSystemInitialized) { + for ( int f = 0; f< NUM_FINGERS_PER_HAND; f ++ ) { + _fingerParticleEmitter[f] = _particleSystem.addEmitter(); + + glm::vec4 color(1.0f, 0.6f, 0.0f, 0.5f); + + //_particleSystem.setEmitterParticle(f, true, 0.012f, color); + + ParticleSystem::ParticleAttributes attributes; + + // set attributes for each life stage of the particle: + attributes.radius = 0.001f; + attributes.gravity = 0.0f; + attributes.airFriction = 0.0f; + attributes.jitter = 0.0f; + attributes.emitterAttraction = 0.0f; + attributes.tornadoForce = 0.0f; + attributes.neighborAttraction = 0.0f; + attributes.neighborRepulsion = 0.0f; + attributes.bounce = 1.0f; + attributes.usingCollisionSphere = false; + _particleSystem.setParticleAttributes(_fingerParticleEmitter[f], 0, attributes); + + attributes.radius = 0.002f; + attributes.jitter = 0.01f; + _particleSystem.setParticleAttributes(_fingerParticleEmitter[f], 1, attributes); + + attributes.radius = 0.007f; + attributes.gravity = -0.01f; + _particleSystem.setParticleAttributes(_fingerParticleEmitter[f], 2, attributes); } + _particleSystemInitialized = true; } else { // update the particles @@ -208,7 +238,7 @@ void Hand::updateFingerParticles(float deltaTime) { float radius = 0.005f; glm::vec4 color(1.0f, 0.6f, 0.0f, 0.5f); - glm::vec3 velocity = fingerDirection * 0.005f; + glm::vec3 velocity = fingerDirection * 0.002f; float lifespan = 0.3f; _particleSystem.emitParticlesNow(_fingerParticleEmitter[0], 1, radius, color, velocity, lifespan); } diff --git a/interface/src/ParticleSystem.cpp b/interface/src/ParticleSystem.cpp index bd364959d3..e4c0c99181 100644 --- a/interface/src/ParticleSystem.cpp +++ b/interface/src/ParticleSystem.cpp @@ -11,6 +11,7 @@ #include "ParticleSystem.h" #include "Application.h" +const float DEFAULT_PARTICLE_RADIUS = 0.01f; const float DEFAULT_PARTICLE_BOUNCE = 1.0f; const float DEFAULT_PARTICLE_AIR_FRICTION = 2.0f; @@ -19,7 +20,7 @@ ParticleSystem::ParticleSystem() { _numEmitters = 0; _numParticles = 0; _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); _emitter[e].rotation = glm::quat(); @@ -27,8 +28,17 @@ ParticleSystem::ParticleSystem() { _emitter[e].up = IDENTITY_UP; _emitter[e].front = IDENTITY_FRONT; _emitter[e].visible = false; - + _emitter[e].baseParticle.alive = false; + _emitter[e].baseParticle.age = 0.0f; + _emitter[e].baseParticle.lifespan = 0.0f; + _emitter[e].baseParticle.radius = 0.0f; + _emitter[e].baseParticle.emitterIndex = 0; + _emitter[e].baseParticle.position = glm::vec3(0.0f, 0.0f, 0.0f); + _emitter[e].baseParticle.velocity = glm::vec3(0.0f, 0.0f, 0.0f); + + for (int s = 0; sradius = attributes.radius; a->bounce = attributes.bounce; a->gravity = attributes.gravity; a->airFriction = attributes.airFriction; @@ -183,8 +195,16 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { float ageFraction = _particle[p].age / _particle[p].lifespan; + + + int lifeStage = (int)( ageFraction * NUM_PARTICLE_LIFE_STAGES ); + + _particle[p].radius = _emitter[_particle[p].emitterIndex].particleAttributes[lifeStage].radius; + + + Emitter myEmitter = _emitter[_particle[p].emitterIndex]; // apply random jitter @@ -272,10 +292,34 @@ void ParticleSystem::setCollisionSphere(int e, glm::vec3 position, float radius) _emitter[e].particleAttributes[lifeStage].collisionSphereRadius = radius; } +void ParticleSystem::setEmitterParticle(int emitterIndex, bool showing ) { + + _emitter[emitterIndex].baseParticle.alive = true; + _emitter[emitterIndex].baseParticle.emitterIndex = emitterIndex; +} + +void ParticleSystem::setEmitterParticle(int emitterIndex, bool showing, float radius, glm::vec4 color ) { + + _emitter[emitterIndex].baseParticle.alive = true; + _emitter[emitterIndex].baseParticle.emitterIndex = emitterIndex; + _emitter[emitterIndex].baseParticle.radius = radius; + _emitter[emitterIndex].baseParticle.color = color; +} + + void ParticleSystem::render() { // render the emitters for (unsigned int e = 0; e < _numEmitters; e++) { + + if (_emitter[e].baseParticle.alive) { + glColor4f(_emitter[e].baseParticle.color.r, _emitter[e].baseParticle.color.g, _emitter[e].baseParticle.color.b, _emitter[e].baseParticle.color.a ); + glPushMatrix(); + glTranslatef(_emitter[e].position.x, _emitter[e].position.y, _emitter[e].position.z); + glutSolidSphere(_emitter[e].baseParticle.radius, 6, 6); + glPopMatrix(); + } + if (_emitter[e].visible) { renderEmitter(e, 0.2f); } diff --git a/interface/src/ParticleSystem.h b/interface/src/ParticleSystem.h index 37fd5fb9db..deffc9a04d 100644 --- a/interface/src/ParticleSystem.h +++ b/interface/src/ParticleSystem.h @@ -20,6 +20,7 @@ class ParticleSystem { public: struct ParticleAttributes { + float radius; float bounce; float gravity; float airFriction; @@ -39,6 +40,8 @@ public: void emitParticlesNow(int emitterIndex, int numParticles, float radius, glm::vec4 color, glm::vec3 velocity, float lifespan); void simulate(float deltaTime); void render(); + void setEmitterParticle(int emitterIndex, bool showing ); + void setEmitterParticle(int emitterIndex, bool showing, float radius, glm::vec4 color ); void setOrangeBlueColorPalette(); // apply a nice preset color palette to the particles void setUpDirection(glm::vec3 upDirection) {_upDirection = upDirection;} // tell particle system which direction is up @@ -51,16 +54,6 @@ public: private: - struct Emitter { - glm::vec3 position; - glm::quat rotation; - glm::vec3 right; // derived from rotation - glm::vec3 up; // derived from rotation - glm::vec3 front; // derived from rotation - bool visible; - ParticleAttributes particleAttributes[NUM_PARTICLE_LIFE_STAGES]; // the attributes of particles emitted from this emitter - }; - struct Particle { bool alive; // is the particle active? glm::vec3 position; // position @@ -72,6 +65,17 @@ private: int emitterIndex; // which emitter created this particle? }; + struct Emitter { + glm::vec3 position; + glm::quat rotation; + glm::vec3 right; // derived from rotation + glm::vec3 up; // derived from rotation + glm::vec3 front; // derived from rotation + bool visible; + Particle baseParticle; // a non-physical particle at the emitter position + ParticleAttributes particleAttributes[NUM_PARTICLE_LIFE_STAGES]; // the attributes of particles emitted from this emitter + }; + glm::vec3 _upDirection; Emitter _emitter[MAX_EMITTERS]; Particle _particle[MAX_PARTICLES]; From 1f1259cec5883158e947d325b1fe675991668700 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 17 Jul 2013 16:03:10 -0700 Subject: [PATCH 4/4] added particle life stages --- interface/src/Application.cpp | 2 +- interface/src/Hand.cpp | 35 ++++++++++++--------- interface/src/ParticleSystem.cpp | 53 +++++++++++++++++++------------- interface/src/ParticleSystem.h | 8 +++-- 4 files changed, 59 insertions(+), 39 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4e0a815ef8..6057ae26ed 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -73,7 +73,7 @@ using namespace std; static char STAR_FILE[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt"; static char STAR_CACHE_FILE[] = "cachedStars.txt"; -static const bool TESTING_PARTICLE_SYSTEM = true; +static const bool TESTING_PARTICLE_SYSTEM = false; static const int BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH = 6; // farther dragged clicks are ignored diff --git a/interface/src/Hand.cpp b/interface/src/Hand.cpp index 8e16540d55..333ad4f90c 100755 --- a/interface/src/Hand.cpp +++ b/interface/src/Hand.cpp @@ -29,6 +29,9 @@ Hand::Hand(Avatar* owningAvatar) : // initialize all finger particle emitters with an invalid id as default for (int f = 0; f< NUM_FINGERS_PER_HAND; f ++ ) { _fingerParticleEmitter[f] = -1; + + //glm::vec4 color(1.0f, 0.6f, 0.0f, 0.5f); + //_particleSystem.setEmitterBaseParticle(f, true, 0.012f, color); } } @@ -181,17 +184,14 @@ void Hand::updateFingerParticles(float deltaTime) { _fingerParticleEmitter[f] = _particleSystem.addEmitter(); - glm::vec4 color(1.0f, 0.6f, 0.0f, 0.5f); - - //_particleSystem.setEmitterParticle(f, true, 0.012f, color); - ParticleSystem::ParticleAttributes attributes; // set attributes for each life stage of the particle: - attributes.radius = 0.001f; + attributes.radius = 0.0f; + attributes.color = glm::vec4( 1.0f, 1.0f, 0.5f, 0.5f); attributes.gravity = 0.0f; attributes.airFriction = 0.0f; - attributes.jitter = 0.0f; + attributes.jitter = 0.002f; attributes.emitterAttraction = 0.0f; attributes.tornadoForce = 0.0f; attributes.neighborAttraction = 0.0f; @@ -200,13 +200,20 @@ void Hand::updateFingerParticles(float deltaTime) { attributes.usingCollisionSphere = false; _particleSystem.setParticleAttributes(_fingerParticleEmitter[f], 0, attributes); - attributes.radius = 0.002f; - attributes.jitter = 0.01f; + attributes.radius = 0.01f; + attributes.jitter = 0.0f; + attributes.gravity = -0.005f; + attributes.color = glm::vec4( 1.0f, 0.2f, 0.0f, 0.4f); _particleSystem.setParticleAttributes(_fingerParticleEmitter[f], 1, attributes); - attributes.radius = 0.007f; - attributes.gravity = -0.01f; + attributes.radius = 0.01f; + attributes.gravity = 0.0f; + attributes.color = glm::vec4( 0.0f, 0.0f, 0.0f, 0.2f); _particleSystem.setParticleAttributes(_fingerParticleEmitter[f], 2, attributes); + + attributes.radius = 0.02f; + attributes.color = glm::vec4( 0.0f, 0.0f, 0.0f, 0.0f); + _particleSystem.setParticleAttributes(_fingerParticleEmitter[f], 3, attributes); } _particleSystemInitialized = true; @@ -233,14 +240,14 @@ void Hand::updateFingerParticles(float deltaTime) { glm::quat particleEmitterRotation = rotationBetween(IDENTITY_UP, fingerDirection); - _particleSystem.setEmitterPosition(_fingerParticleEmitter[0], particleEmitterPosition); - _particleSystem.setEmitterRotation(_fingerParticleEmitter[0], particleEmitterRotation); + _particleSystem.setEmitterPosition(_fingerParticleEmitter[f], particleEmitterPosition); + _particleSystem.setEmitterRotation(_fingerParticleEmitter[f], particleEmitterRotation); float radius = 0.005f; glm::vec4 color(1.0f, 0.6f, 0.0f, 0.5f); glm::vec3 velocity = fingerDirection * 0.002f; - float lifespan = 0.3f; - _particleSystem.emitParticlesNow(_fingerParticleEmitter[0], 1, radius, color, velocity, lifespan); + float lifespan = 1.0f; + _particleSystem.emitParticlesNow(_fingerParticleEmitter[f], 1, radius, color, velocity, lifespan); } } diff --git a/interface/src/ParticleSystem.cpp b/interface/src/ParticleSystem.cpp index e4c0c99181..15343203e4 100644 --- a/interface/src/ParticleSystem.cpp +++ b/interface/src/ParticleSystem.cpp @@ -39,6 +39,7 @@ ParticleSystem::ParticleSystem() { for (int s = 0; sradius = attributes.radius; + a->color = attributes.color; a->bounce = attributes.bounce; a->gravity = attributes.gravity; a->airFriction = attributes.airFriction; @@ -192,19 +195,27 @@ void ParticleSystem::setParticleAttributes(int emitterIndex, int lifeStage, Part void ParticleSystem::updateParticle(int p, float deltaTime) { assert(_particle[p].age <= _particle[p].lifespan); - + float ageFraction = _particle[p].age / _particle[p].lifespan; + + int lifeStage = (int)( ageFraction * (NUM_PARTICLE_LIFE_STAGES-1) ); + + float lifeStageFraction = ageFraction * ( NUM_PARTICLE_LIFE_STAGES - 1 ) - lifeStage; + /* + if ( p == 0 ) { + printf( "lifespan = %f ageFraction = %f lifeStage = %d lifeStageFraction = %f\n", _particle[p].lifespan, ageFraction, lifeStage, lifeStageFraction ); + } + */ - - - int lifeStage = (int)( ageFraction * NUM_PARTICLE_LIFE_STAGES ); - - - _particle[p].radius = _emitter[_particle[p].emitterIndex].particleAttributes[lifeStage].radius; - - - + _particle[p].radius + = _emitter[_particle[p].emitterIndex].particleAttributes[lifeStage ].radius * (1.0f - lifeStageFraction) + + _emitter[_particle[p].emitterIndex].particleAttributes[lifeStage+1].radius * lifeStageFraction; + + _particle[p].color + = _emitter[_particle[p].emitterIndex].particleAttributes[lifeStage ].color * (1.0f - lifeStageFraction) + + _emitter[_particle[p].emitterIndex].particleAttributes[lifeStage+1].color * lifeStageFraction; + Emitter myEmitter = _emitter[_particle[p].emitterIndex]; // apply random jitter @@ -292,13 +303,13 @@ void ParticleSystem::setCollisionSphere(int e, glm::vec3 position, float radius) _emitter[e].particleAttributes[lifeStage].collisionSphereRadius = radius; } -void ParticleSystem::setEmitterParticle(int emitterIndex, bool showing ) { +void ParticleSystem::setEmitterBaseParticle(int emitterIndex, bool showing ) { _emitter[emitterIndex].baseParticle.alive = true; _emitter[emitterIndex].baseParticle.emitterIndex = emitterIndex; } -void ParticleSystem::setEmitterParticle(int emitterIndex, bool showing, float radius, glm::vec4 color ) { +void ParticleSystem::setEmitterBaseParticle(int emitterIndex, bool showing, float radius, glm::vec4 color ) { _emitter[emitterIndex].baseParticle.alive = true; _emitter[emitterIndex].baseParticle.emitterIndex = emitterIndex; @@ -310,7 +321,7 @@ void ParticleSystem::setEmitterParticle(int emitterIndex, bool showing, float ra void ParticleSystem::render() { // render the emitters - for (unsigned int e = 0; e < _numEmitters; e++) { + for (int e = 0; e < _numEmitters; e++) { if (_emitter[e].baseParticle.alive) { glColor4f(_emitter[e].baseParticle.color.r, _emitter[e].baseParticle.color.g, _emitter[e].baseParticle.color.b, _emitter[e].baseParticle.color.a ); @@ -370,14 +381,14 @@ void ParticleSystem::renderParticle(int p) { glutSolidSphere(_particle[p].radius, 6, 6); glPopMatrix(); - // render velocity lines - glColor4f( _particle[p].color.x, _particle[p].color.y, _particle[p].color.z, 0.5f); - glm::vec3 end = _particle[p].position - _particle[p].velocity * 2.0f; - glBegin(GL_LINES); - glVertex3f(_particle[p].position.x, _particle[p].position.y, _particle[p].position.z); - glVertex3f(end.x, end.y, end.z); - - glEnd(); + if (SHOW_VELOCITY_TAILS) { + glColor4f( _particle[p].color.x, _particle[p].color.y, _particle[p].color.z, 0.5f); + glm::vec3 end = _particle[p].position - _particle[p].velocity * 2.0f; + glBegin(GL_LINES); + glVertex3f(_particle[p].position.x, _particle[p].position.y, _particle[p].position.z); + glVertex3f(end.x, end.y, end.z); + glEnd(); + } } } diff --git a/interface/src/ParticleSystem.h b/interface/src/ParticleSystem.h index deffc9a04d..244b791d39 100644 --- a/interface/src/ParticleSystem.h +++ b/interface/src/ParticleSystem.h @@ -13,14 +13,16 @@ const int MAX_PARTICLES = 5000; const int MAX_EMITTERS = 20; -const int NUM_PARTICLE_LIFE_STAGES = 3; +const int NUM_PARTICLE_LIFE_STAGES = 4; const bool USE_BILLBOARD_RENDERING = false; +const bool SHOW_VELOCITY_TAILS = false; class ParticleSystem { public: struct ParticleAttributes { float radius; + glm::vec4 color; float bounce; float gravity; float airFriction; @@ -40,8 +42,8 @@ public: void emitParticlesNow(int emitterIndex, int numParticles, float radius, glm::vec4 color, glm::vec3 velocity, float lifespan); void simulate(float deltaTime); void render(); - void setEmitterParticle(int emitterIndex, bool showing ); - void setEmitterParticle(int emitterIndex, bool showing, float radius, glm::vec4 color ); + void setEmitterBaseParticle(int emitterIndex, bool showing ); + void setEmitterBaseParticle(int emitterIndex, bool showing, float radius, glm::vec4 color ); void setOrangeBlueColorPalette(); // apply a nice preset color palette to the particles void setUpDirection(glm::vec3 upDirection) {_upDirection = upDirection;} // tell particle system which direction is up