From e6b751e53840b2caad5203b4068146a2866c41a4 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Fri, 12 Jul 2013 14:32:14 -0700 Subject: [PATCH 01/17] more work on particle system --- interface/src/Application.cpp | 4 +- interface/src/ParticleSystem.cpp | 178 +++++++++++++++++++++---------- interface/src/ParticleSystem.h | 17 ++- 3 files changed, 138 insertions(+), 61 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6f70c89f3b..591889a83a 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 @@ -2010,6 +2010,8 @@ void Application::update(float deltaTime) { #endif if (TESTING_PARTICLE_SYSTEM) { + glm::vec3 particleEmitterPosition = glm::vec3(5.0f, 1.0f, 5.0f); + _particleSystem.setEmitterPosition(0, particleEmitterPosition); _particleSystem.simulate(deltaTime); } } diff --git a/interface/src/ParticleSystem.cpp b/interface/src/ParticleSystem.cpp index 3c27f3a8df..383f3eeecb 100644 --- a/interface/src/ParticleSystem.cpp +++ b/interface/src/ParticleSystem.cpp @@ -8,59 +8,91 @@ #include #include "InterfaceConfig.h" #include - #include "ParticleSystem.h" +#include "Application.h" ParticleSystem::ParticleSystem() { - _numberOfParticles = 1500; - assert(_numberOfParticles <= MAX_PARTICLES); - - _bounce = 0.9f; - _timer = 0.0f; - _airFriction = 6.0f; - _jitter = 0.1f; - _homeAttraction = 0.0f; - _tornadoForce = 0.0f; - _neighborAttraction = 0.02f; - _neighborRepulsion = 0.9f; - _tornadoAxis = glm::normalize(glm::vec3(0.1f, 1.0f, 0.1f)); - _home = glm::vec3(5.0f, 1.0f, 5.0f); - - _TEST_bigSphereRadius = 0.5f; + _gravity = 0.005; + _numEmitters = 1; + _bounce = 0.9f; + _timer = 0.0f; + _airFriction = 6.0f; + _jitter = 0.1f; + _homeAttraction = 0.0f; + _tornadoForce = 0.0f; + _neighborAttraction = 0.02f; + _neighborRepulsion = 0.9f; + _TEST_bigSphereRadius = 0.5f; _TEST_bigSpherePosition = glm::vec3( 5.0f, _TEST_bigSphereRadius, 5.0f); - - for (unsigned int p = 0; p < _numberOfParticles; p++) { - _particle[p].position = _home; - _particle[p].velocity = glm::vec3(0.0f, 0.0f, 0.0f); + _numParticles = 1500; + + for (unsigned int e = 0; e < _numEmitters; 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; + }; + + for (unsigned int p = 0; p < _numParticles; p++) { - float radian = ((float)p / (float)_numberOfParticles) * PI_TIMES_TWO; + 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); - _particle[p].age = 0.0f; - _particle[p].radius = 0.01f; + _particle[p].color = glm::vec3(red, green, blue); + _particle[p].age = 0.0f; + _particle[p].radius = 0.01f; + _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); } + + assert(_numParticles <= MAX_PARTICLES); + assert(_numEmitters <= MAX_EMITTERS ); } + void ParticleSystem::simulate(float deltaTime) { - runSpecialEffectsTest(deltaTime); - - for (unsigned int p = 0; p < _numberOfParticles; p++) { + // update emitters + for (unsigned int e = 0; e < _numEmitters; e++) { + updateEmitter(e, deltaTime); + } + + // update particles + for (unsigned int p = 0; p < _numParticles; p++) { updateParticle(p, deltaTime); } + + // apply special effects + runSpecialEffectsTest(deltaTime); } +void ParticleSystem::updateEmitter(int e, float deltaTime) { + _emitter[e].front = _emitter[e].rotation * IDENTITY_FRONT; + _emitter[e].right = _emitter[e].rotation * IDENTITY_RIGHT; + _emitter[e].up = _emitter[e].rotation * IDENTITY_UP; +} void ParticleSystem::runSpecialEffectsTest(float deltaTime) { - + _timer += deltaTime; + + glm::vec3 tilt = glm::vec3 + ( + 30.0f * sinf( _timer * 0.55f ), + 0.0f, + 30.0f * cosf( _timer * 0.75f ) + ); + + _emitter[0].rotation = glm::quat(glm::radians(tilt)); _gravity = 0.01f + 0.01f * sinf( _timer * 0.52f ); _airFriction = 3.0f + 2.0f * sinf( _timer * 0.32f ); @@ -69,13 +101,6 @@ void ParticleSystem::runSpecialEffectsTest(float deltaTime) { _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 ); - - _tornadoAxis = glm::vec3 - ( - 0.0f + 0.5f * sinf( _timer * 0.55f ), - 1.0f, - 0.0f + 0.5f * cosf( _timer * 0.75f ) - ); } @@ -95,12 +120,12 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { // apply attraction to home position - glm::vec3 vectorToHome = _home - _particle[p].position; + glm::vec3 vectorToHome = _emitter[_particle[p].emitterIndex].position - _particle[p].position; _particle[p].velocity += vectorToHome * _homeAttraction * deltaTime; // apply neighbor attraction int neighbor = p + 1; - if (neighbor == _numberOfParticles ) { + if (neighbor == _numParticles ) { neighbor = 0; } glm::vec3 vectorToNeighbor = _particle[p].position - _particle[neighbor].position; @@ -113,8 +138,9 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { } // apply tornado force - glm::vec3 tornadoDirection = glm::cross(vectorToHome, _tornadoAxis); - _particle[p].velocity += tornadoDirection * _tornadoForce * deltaTime; + //glm::vec3 tornadoDirection = glm::cross(vectorToHome, _emitter[_particle[p].emitterIndex].up); + //_particle[p].velocity += tornadoDirection * _tornadoForce * deltaTime; + //_particle[p].velocity += _emitter[_particle[p].emitterIndex].up * _tornadoForce * deltaTime; // apply air friction float drag = 1.0 - _airFriction * deltaTime; @@ -155,29 +181,69 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { void ParticleSystem::render() { - for (unsigned int p = 0; p < _numberOfParticles; p++) { - glColor3f(_particle[p].color.x, _particle[p].color.y, _particle[p].color.z); - 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(); - + // render the emitters + for (unsigned int e = 0; e < _numEmitters; e++) { + renderEmitter(e, 0.2f); + }; + + // render the particles + for (unsigned int p = 0; p < _numParticles; p++) { + renderParticle(p); } } +void ParticleSystem::renderParticle(int p) { + + glColor3f(_particle[p].color.x, _particle[p].color.y, _particle[p].color.z); + 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(); +} + + + +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); + glBegin(GL_LINES); + glVertex3f(_emitter[e].position.x, _emitter[e].position.y, _emitter[e].position.z); + glVertex3f(_emitter[e].position.x + r.x, _emitter[e].position.y + r.y, _emitter[e].position.z + r.z); + glEnd(); + + glColor3f(0.4f, 0.8, 0.4); + glBegin(GL_LINES); + glVertex3f(_emitter[e].position.x, _emitter[e].position.y, _emitter[e].position.z); + glVertex3f(_emitter[e].position.x + u.x, _emitter[e].position.y + u.y, _emitter[e].position.z + u.z); + glEnd(); + + glColor3f(0.4f, 0.4, 0.8); + glBegin(GL_LINES); + glVertex3f(_emitter[e].position.x, _emitter[e].position.y, _emitter[e].position.z); + glVertex3f(_emitter[e].position.x + f.x, _emitter[e].position.y + f.y, _emitter[e].position.z + f.z); + glEnd(); +} + + + - diff --git a/interface/src/ParticleSystem.h b/interface/src/ParticleSystem.h index 38eb0a1777..79dfeb4752 100644 --- a/interface/src/ParticleSystem.h +++ b/interface/src/ParticleSystem.h @@ -9,6 +9,8 @@ #ifndef hifi_ParticleSystem_h #define hifi_ParticleSystem_h +#include + const int MAX_PARTICLES = 5000; const int MAX_EMITTERS = 10; @@ -16,6 +18,7 @@ class ParticleSystem { public: ParticleSystem(); + void setEmitterPosition(int e, glm::vec3 position) { _emitter[e].position = position; } void simulate(float deltaTime); void render(); @@ -27,11 +30,15 @@ private: glm::vec3 color; float age; float radius; + int emitterIndex; }; struct Emitter { glm::vec3 position; - glm::vec3 direction; + glm::quat rotation; + glm::vec3 right; + glm::vec3 up; + glm::vec3 front; }; float _bounce; @@ -39,9 +46,8 @@ private: float _timer; Emitter _emitter[MAX_EMITTERS]; Particle _particle[MAX_PARTICLES]; - int _numberOfParticles; - glm::vec3 _home; - glm::vec3 _tornadoAxis; + int _numParticles; + int _numEmitters; float _airFriction; float _jitter; float _homeAttraction; @@ -52,8 +58,11 @@ private: glm::vec3 _TEST_bigSpherePosition; // private methods + void updateEmitter(int e, float deltaTime); void updateParticle(int index, float deltaTime); void runSpecialEffectsTest(float deltaTime); + void renderEmitter(int emitterIndex, float size); + void renderParticle(int p); }; #endif From 3649c89c1292cae62c66eac3f13ba78f10a5c790 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Fri, 12 Jul 2013 16:19:31 -0700 Subject: [PATCH 02/17] more developing on the API for the particle system --- interface/src/Application.cpp | 28 +++++-- interface/src/Application.h | 1 + interface/src/ParticleSystem.cpp | 137 +++++++++++++++++++++---------- interface/src/ParticleSystem.h | 16 ++-- 4 files changed, 127 insertions(+), 55 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 591889a83a..209282b926 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -172,6 +172,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _frameCount(0), _fps(120.0f), _justStarted(true), + _particleSystemInitialized(false), _wantToKillLocalVoxels(false), _frustumDrawingMode(FRUSTUM_DRAW_MODE_ALL), _viewFrustumOffsetYaw(-135.0), @@ -1749,9 +1750,10 @@ void Application::init() { _palette.addTool(&_swatch); _palette.addAction(_colorVoxelMode, 0, 2); _palette.addAction(_eyedropperMode, 0, 3); - _palette.addAction(_selectVoxelMode, 0, 4); + _palette.addAction(_selectVoxelMode, 0, 4); } + const float MAX_AVATAR_EDIT_VELOCITY = 1.0f; const float MAX_VOXEL_EDIT_DISTANCE = 20.0f; const float HEAD_SPHERE_RADIUS = 0.07; @@ -2010,9 +2012,23 @@ void Application::update(float deltaTime) { #endif if (TESTING_PARTICLE_SYSTEM) { - glm::vec3 particleEmitterPosition = glm::vec3(5.0f, 1.0f, 5.0f); - _particleSystem.setEmitterPosition(0, particleEmitterPosition); - _particleSystem.simulate(deltaTime); + if (_particleSystemInitialized) { + _particleSystem.simulate(deltaTime); + } else { + int coolDemoEmitter = _particleSystem.addEmitter(); + + if (coolDemoEmitter != -1) { + glm::vec3 particleEmitterPosition = glm::vec3(5.0f, 1.3f, 5.0f); + _particleSystem.setEmitterPosition(coolDemoEmitter, particleEmitterPosition); + _particleSystem.emitParticlesNow(coolDemoEmitter, 1500); + } + + glm::vec3 collisionSpherePosition = glm::vec3( 5.0f, 0.5f, 5.0f ); + float collisionSphereRadius = 0.5f; + _particleSystem.setCollisionSphere(collisionSpherePosition, collisionSphereRadius); + _particleSystemInitialized = true; + _particleSystem.useOrangeBlueColorPalette(); + } } } @@ -2459,7 +2475,9 @@ void Application::displaySide(Camera& whichCamera) { } if (TESTING_PARTICLE_SYSTEM) { - _particleSystem.render(); + if (_particleSystemInitialized) { + _particleSystem.render(); + } } // Render the world box diff --git a/interface/src/Application.h b/interface/src/Application.h index c6bbd4eec2..37a8b40964 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -278,6 +278,7 @@ private: timeval _timerStart, _timerEnd; timeval _lastTimeUpdated; bool _justStarted; + bool _particleSystemInitialized; Stars _stars; diff --git a/interface/src/ParticleSystem.cpp b/interface/src/ParticleSystem.cpp index 383f3eeecb..0e762fdb0e 100644 --- a/interface/src/ParticleSystem.cpp +++ b/interface/src/ParticleSystem.cpp @@ -13,22 +13,22 @@ ParticleSystem::ParticleSystem() { - _gravity = 0.005; - _numEmitters = 1; - _bounce = 0.9f; - _timer = 0.0f; - _airFriction = 6.0f; - _jitter = 0.1f; - _homeAttraction = 0.0f; - _tornadoForce = 0.0f; - _neighborAttraction = 0.02f; - _neighborRepulsion = 0.9f; - _TEST_bigSphereRadius = 0.5f; - _TEST_bigSpherePosition = glm::vec3( 5.0f, _TEST_bigSphereRadius, 5.0f); - _numParticles = 1500; - - for (unsigned int e = 0; e < _numEmitters; e++) { + _gravity = 0.005; + _numEmitters = 0; + _bounce = 0.9f; + _timer = 0.0f; + _airFriction = 6.0f; + _jitter = 0.1f; + _homeAttraction = 0.0f; + _tornadoForce = 0.0f; + _neighborAttraction = 0.02f; + _neighborRepulsion = 0.9f; + _collisionSphereRadius = 0.0f; + _collisionSpherePosition = glm::vec3(0.0f, 0.0f, 0.0f); + _numParticles = 0; + _usingCollisionSphere = false; + 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; @@ -36,25 +36,25 @@ ParticleSystem::ParticleSystem() { _emitter[e].front = IDENTITY_FRONT; }; - 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); + 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].emitterIndex = 0; _particle[p].position = glm::vec3(0.0f, 0.0f, 0.0f); _particle[p].velocity = glm::vec3(0.0f, 0.0f, 0.0f); + } +} + + +int ParticleSystem::addEmitter() { + _numEmitters ++; + + if (_numEmitters > MAX_EMITTERS) { + return -1; } - assert(_numParticles <= MAX_PARTICLES); - assert(_numEmitters <= MAX_EMITTERS ); + return _numEmitters - 1; } @@ -67,9 +67,11 @@ void ParticleSystem::simulate(float deltaTime) { // update particles for (unsigned int p = 0; p < _numParticles; p++) { - updateParticle(p, deltaTime); + if (_particle[p].alive) { + updateParticle(p, deltaTime); + } } - + // apply special effects runSpecialEffectsTest(deltaTime); } @@ -81,6 +83,40 @@ void ParticleSystem::updateEmitter(int e, float deltaTime) { _emitter[e].up = _emitter[e].rotation * IDENTITY_UP; } + + +void ParticleSystem::emitParticlesNow(int e, int num) { + + _numParticles = num; + + if (_numParticles > MAX_PARTICLES) { + _numParticles = MAX_PARTICLES; + } + + for (unsigned int p = 0; p < num; p++) { + _particle[p].alive = true; + _particle[p].position = _emitter[e].position; + } +} + +void ParticleSystem::useOrangeBlueColorPalette() { + + 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); + } +} + + + + + + void ParticleSystem::runSpecialEffectsTest(float deltaTime) { _timer += deltaTime; @@ -93,14 +129,18 @@ void ParticleSystem::runSpecialEffectsTest(float deltaTime) { ); _emitter[0].rotation = glm::quat(glm::radians(tilt)); - - _gravity = 0.01f + 0.01f * sinf( _timer * 0.52f ); - _airFriction = 3.0f + 2.0f * sinf( _timer * 0.32f ); + + _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 ); + + if (_gravity < 0.0f) { + _gravity = 0.0f; + } } @@ -118,7 +158,6 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { -_jitter * ONE_HALF + _jitter * randFloat() ) * deltaTime; - // apply attraction to home position glm::vec3 vectorToHome = _emitter[_particle[p].emitterIndex].position - _particle[p].position; _particle[p].velocity += vectorToHome * _homeAttraction * deltaTime; @@ -138,9 +177,8 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { } // apply tornado force - //glm::vec3 tornadoDirection = glm::cross(vectorToHome, _emitter[_particle[p].emitterIndex].up); - //_particle[p].velocity += tornadoDirection * _tornadoForce * deltaTime; - //_particle[p].velocity += _emitter[_particle[p].emitterIndex].up * _tornadoForce * deltaTime; + glm::vec3 tornadoDirection = glm::cross(vectorToHome, _emitter[_particle[p].emitterIndex].up); + _particle[p].velocity += tornadoDirection * _tornadoForce * deltaTime; // apply air friction float drag = 1.0 - _airFriction * deltaTime; @@ -166,18 +204,25 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { } // collision with sphere - glm::vec3 vectorToSphereCenter = _TEST_bigSpherePosition - _particle[p].position; - float distanceToSphereCenter = glm::length(vectorToSphereCenter); - float combinedRadius = _TEST_bigSphereRadius + _particle[p].radius; - if (distanceToSphereCenter < combinedRadius) { - - if (distanceToSphereCenter > 0.0f){ - glm::vec3 directionToSphereCenter = vectorToSphereCenter / distanceToSphereCenter; - _particle[p].position = _TEST_bigSpherePosition - directionToSphereCenter * combinedRadius; + if (_usingCollisionSphere) { + glm::vec3 vectorToSphereCenter = _collisionSpherePosition - _particle[p].position; + float distanceToSphereCenter = glm::length(vectorToSphereCenter); + float combinedRadius = _collisionSphereRadius + _particle[p].radius; + if (distanceToSphereCenter < combinedRadius) { + + if (distanceToSphereCenter > 0.0f){ + glm::vec3 directionToSphereCenter = vectorToSphereCenter / distanceToSphereCenter; + _particle[p].position = _collisionSpherePosition - directionToSphereCenter * combinedRadius; + } } } } +void ParticleSystem::setCollisionSphere(glm::vec3 position, float radius) { + _usingCollisionSphere = true; + _collisionSpherePosition = position; + _collisionSphereRadius = radius; +} void ParticleSystem::render() { @@ -188,7 +233,9 @@ void ParticleSystem::render() { // render the particles for (unsigned int p = 0; p < _numParticles; p++) { - renderParticle(p); + if (_particle[p].alive) { + renderParticle(p); + } } } diff --git a/interface/src/ParticleSystem.h b/interface/src/ParticleSystem.h index 79dfeb4752..701d1c85b7 100644 --- a/interface/src/ParticleSystem.h +++ b/interface/src/ParticleSystem.h @@ -18,13 +18,18 @@ class ParticleSystem { public: ParticleSystem(); - void setEmitterPosition(int e, glm::vec3 position) { _emitter[e].position = position; } - void simulate(float deltaTime); - void render(); + int addEmitter(); // add (create) an emitter and get its unique id + void useOrangeBlueColorPalette(); // 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 private: struct Particle { + bool alive; glm::vec3 position; glm::vec3 velocity; glm::vec3 color; @@ -54,8 +59,9 @@ private: float _tornadoForce; float _neighborAttraction; float _neighborRepulsion; - float _TEST_bigSphereRadius; - glm::vec3 _TEST_bigSpherePosition; + bool _usingCollisionSphere; + glm::vec3 _collisionSpherePosition; + float _collisionSphereRadius; // private methods void updateEmitter(int e, float deltaTime); From ae99ca5ec8846b12ecb496c57945078bcdce944c Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Fri, 12 Jul 2013 18:55:42 -0700 Subject: [PATCH 03/17] added more API for the particle system --- interface/src/Application.cpp | 26 ++++++-- interface/src/ParticleSystem.cpp | 111 +++++++++++++++++++------------ interface/src/ParticleSystem.h | 45 +++++++------ 3 files changed, 116 insertions(+), 66 deletions(-) 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); }; From 3bc6b4c0d4648c7cf190bee683fc44f2fb871672 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Fri, 12 Jul 2013 18:56:54 -0700 Subject: [PATCH 04/17] merge --- interface/src/Avatar.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 interface/src/Avatar.cpp diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp old mode 100755 new mode 100644 From 84b6adf5b05f5a725fa04371002579dc4febd5f0 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 15 Jul 2013 13:57:39 -0700 Subject: [PATCH 05/17] more work on particle emitter API --- interface/src/Application.cpp | 88 ++++++++++++++---- interface/src/Application.h | 2 + interface/src/ParticleSystem.cpp | 154 ++++++++++++++++--------------- interface/src/ParticleSystem.h | 35 +++---- 4 files changed, 171 insertions(+), 108 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6ec2f7a2e2..6f5fffd68c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -172,7 +172,9 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _frameCount(0), _fps(120.0f), _justStarted(true), - _particleSystemInitialized(false), + _particleSystemInitialized(false), + _coolDemoParticleEmitter(-1), + _fingerParticleEmitter(-1), _wantToKillLocalVoxels(false), _frustumDrawingMode(FRUSTUM_DRAW_MODE_ALL), _viewFrustumOffsetYaw(-135.0), @@ -2013,35 +2015,89 @@ void Application::update(float deltaTime) { if (TESTING_PARTICLE_SYSTEM) { - if (_particleSystemInitialized) { + if (!_particleSystemInitialized) { - // 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) { + _coolDemoParticleEmitter = _particleSystem.addEmitter(); + _fingerParticleEmitter = _particleSystem.addEmitter(); + + if (_coolDemoParticleEmitter != -1) { + _particleSystem.setShowingEmitter(_coolDemoParticleEmitter, true); glm::vec3 particleEmitterPosition = glm::vec3(5.0f, 1.0f, 5.0f); - _particleSystem.setEmitterPosition(coolDemoEmitter, particleEmitterPosition); + _particleSystem.setEmitterPosition(_coolDemoParticleEmitter, particleEmitterPosition); 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(_coolDemoParticleEmitter, collisionSpherePosition, collisionSphereRadius); + _particleSystem.emitParticlesNow(_coolDemoParticleEmitter, 1500, radius, color, velocity, lifespan); + } + + if (_fingerParticleEmitter != -1) { + _particleSystem.setShowingEmitter(_fingerParticleEmitter, false); } - // 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; // apply a preset color palette - _particleSystem.setOrangeBlueColorPalette(); + _particleSystem.setOrangeBlueColorPalette(); + } else { + // update the particle system + + + static float t = 0.0f; + t += deltaTime; + + + if (_coolDemoParticleEmitter != -1) { + + glm::vec3 tilt = glm::vec3 + ( + 30.0f * sinf( t * 0.55f ), + 0.0f, + 30.0f * cosf( t * 0.75f ) + ); + + _particleSystem.setEmitterRotation(_coolDemoParticleEmitter, glm::quat(glm::radians(tilt))); + } + + if (_fingerParticleEmitter != -1) { + + glm::vec3 particleEmitterPosition = + glm::vec3 + ( + 3.0f + sinf(t * 8.0f) * 0.02f, + 1.0f + cosf(t * 9.0f) * 0.02f, + 3.0f + sinf(t * 7.0f) * 0.02f + ); + + 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)); + + _particleSystem.setEmitterPosition(_fingerParticleEmitter, particleEmitterPosition); + _particleSystem.setEmitterRotation(_fingerParticleEmitter, particleEmitterRotation); + + float radius = 0.01f; + glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); + glm::vec3 velocity(0.0f, 0.01f, 0.0f); + float lifespan = 0.4f; + _particleSystem.emitParticlesNow(_fingerParticleEmitter, 1, radius, color, velocity, lifespan); + } + + _particleSystem.setUpDirection(glm::vec3(0.0f, 1.0f, 0.0f)); + _particleSystem.simulate(deltaTime); } } } diff --git a/interface/src/Application.h b/interface/src/Application.h index 37a8b40964..879f039f8c 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -279,6 +279,8 @@ private: timeval _lastTimeUpdated; bool _justStarted; bool _particleSystemInitialized; + int _coolDemoParticleEmitter; + int _fingerParticleEmitter; Stars _stars; diff --git a/interface/src/ParticleSystem.cpp b/interface/src/ParticleSystem.cpp index e6a3bfef7b..14aaedbac9 100644 --- a/interface/src/ParticleSystem.cpp +++ b/interface/src/ParticleSystem.cpp @@ -13,33 +13,34 @@ 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() { - _timer = 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.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 - + _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].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].bounce = DEFAULT_PARTICLE_BOUNCE; + _emitter[e].airFriction = DEFAULT_PARTICLE_AIR_FRICTION; + _emitter[e].gravity = DEFAULT_PARTICLE_GRAVITY; + _emitter[e].jitter = 0.0f; + _emitter[e].emitterAttraction = 0.0f; + _emitter[e].tornadoForce = 0.0f; + _emitter[e].neighborAttraction = 0.0f; + _emitter[e].neighborRepulsion = 0.0f; + _emitter[e].collisionSphereRadius = 0.0f; + _emitter[e].collisionSpherePosition = glm::vec3(0.0f, 0.0f, 0.0f); + _emitter[e].usingCollisionSphere = false; + _emitter[e].showingEmitter = false; + }; for (unsigned int p = 0; p < MAX_PARTICLES; p++) { @@ -69,9 +70,11 @@ void ParticleSystem::simulate(float deltaTime) { // update emitters for (unsigned int e = 0; e < _numEmitters; e++) { - updateEmitter(e, deltaTime); + updateEmitter(e, deltaTime); } + runSpecialEffectsTest(0, deltaTime); + // update particles for (unsigned int p = 0; p < _numParticles; p++) { if (_particle[p].alive) { @@ -91,22 +94,23 @@ void ParticleSystem::updateEmitter(int e, float deltaTime) { 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++) { - createParticle(_emitter[e].position, velocity, radius, color, lifespan); + createParticle(e, _emitter[e].position, velocity, radius, color, lifespan); } } -void ParticleSystem::createParticle(glm::vec3 position, glm::vec3 velocity, float radius, glm::vec4 color, float lifespan) { +void ParticleSystem::createParticle(int e, 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; + _particle[p].emitterIndex = e; + _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 ++; @@ -145,29 +149,20 @@ void ParticleSystem::setOrangeBlueColorPalette() { } -void ParticleSystem::runSpecialEffectsTest(float deltaTime) { +void ParticleSystem::runSpecialEffectsTest(int e, float deltaTime) { _timer += deltaTime; - - glm::vec3 tilt = glm::vec3 - ( - 30.0f * sinf( _timer * 0.55f ), - 0.0f, - 30.0f * cosf( _timer * 0.75f ) - ); - - _emitter[0].rotation = glm::quat(glm::radians(tilt)); - - _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 ); + + _emitter[e].gravity = 0.0f + DEFAULT_PARTICLE_GRAVITY * sinf( _timer * 0.52f ); + _emitter[e].airFriction = (DEFAULT_PARTICLE_AIR_FRICTION + 0.5f) + 2.0f * sinf( _timer * 0.32f ); + _emitter[e].jitter = 0.05f + 0.05f * sinf( _timer * 0.42f ); + _emitter[e].emitterAttraction = 0.015f + 0.015f * cosf( _timer * 0.6f ); + _emitter[e].tornadoForce = 0.0f + 0.03f * sinf( _timer * 0.7f ); + _emitter[e].neighborAttraction = 0.1f + 0.1f * cosf( _timer * 0.8f ); + _emitter[e].neighborRepulsion = 0.2f + 0.2f * sinf( _timer * 0.4f ); - if (_gravity < 0.0f) { - _gravity = 0.0f; + if (_emitter[e].gravity < 0.0f) { + _emitter[e].gravity = 0.0f; } } @@ -179,40 +174,45 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { if (_particle[p].age > _particle[p].lifespan) { killParticle(p); } + + Emitter myEmitter = _emitter[_particle[p].emitterIndex]; // apply random jitter _particle[p].velocity += glm::vec3 ( - -_jitter * ONE_HALF + _jitter * randFloat(), - -_jitter * ONE_HALF + _jitter * randFloat(), - -_jitter * ONE_HALF + _jitter * randFloat() + -myEmitter.jitter * ONE_HALF + myEmitter.jitter * randFloat(), + -myEmitter.jitter * ONE_HALF + myEmitter.jitter * randFloat(), + -myEmitter.jitter * ONE_HALF + myEmitter.jitter * randFloat() ) * deltaTime; // apply attraction to home position - glm::vec3 vectorToHome = _emitter[_particle[p].emitterIndex].position - _particle[p].position; - _particle[p].velocity += vectorToHome * _emitterAttraction * deltaTime; + glm::vec3 vectorToHome = myEmitter.position - _particle[p].position; + _particle[p].velocity += vectorToHome * myEmitter.emitterAttraction * deltaTime; // apply neighbor attraction int neighbor = p + 1; if (neighbor == _numParticles ) { neighbor = 0; } - glm::vec3 vectorToNeighbor = _particle[p].position - _particle[neighbor].position; - _particle[p].velocity -= vectorToNeighbor * _neighborAttraction * deltaTime; + if ( _particle[neighbor].emitterIndex == _particle[p].emitterIndex) { + glm::vec3 vectorToNeighbor = _particle[p].position - _particle[neighbor].position; + + _particle[p].velocity -= vectorToNeighbor * myEmitter.neighborAttraction * deltaTime; - float distanceToNeighbor = glm::length(vectorToNeighbor); - if (distanceToNeighbor > 0.0f) { - _particle[neighbor].velocity += (vectorToNeighbor / ( 1.0f + distanceToNeighbor * distanceToNeighbor)) * _neighborRepulsion * deltaTime; + float distanceToNeighbor = glm::length(vectorToNeighbor); + if (distanceToNeighbor > 0.0f) { + _particle[neighbor].velocity += (vectorToNeighbor / ( 1.0f + distanceToNeighbor * distanceToNeighbor)) * myEmitter.neighborRepulsion * deltaTime; + } } // apply tornado force - glm::vec3 tornadoDirection = glm::cross(vectorToHome, _emitter[_particle[p].emitterIndex].up); - _particle[p].velocity += tornadoDirection * _tornadoForce * deltaTime; + glm::vec3 tornadoDirection = glm::cross(vectorToHome, myEmitter.up); + _particle[p].velocity += tornadoDirection * myEmitter.tornadoForce * deltaTime; // apply air friction - float drag = 1.0 - _airFriction * deltaTime; + float drag = 1.0 - myEmitter.airFriction * deltaTime; if (drag < 0.0f) { _particle[p].velocity = glm::vec3(0.0f, 0.0f, 0.0f); } else { @@ -220,7 +220,7 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { } // apply gravity - _particle[p].velocity -= _upDirection * _gravity * deltaTime; + _particle[p].velocity -= _upDirection * myEmitter.gravity * deltaTime; // update position by velocity _particle[p].position += _particle[p].velocity; @@ -230,36 +230,38 @@ 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 *= -_bounce; + _particle[p].velocity.y *= -myEmitter.bounce; } } // collision with sphere - if (_usingCollisionSphere) { - glm::vec3 vectorToSphereCenter = _collisionSpherePosition - _particle[p].position; + if (myEmitter.usingCollisionSphere) { + glm::vec3 vectorToSphereCenter = myEmitter.collisionSpherePosition - _particle[p].position; float distanceToSphereCenter = glm::length(vectorToSphereCenter); - float combinedRadius = _collisionSphereRadius + _particle[p].radius; + float combinedRadius = myEmitter.collisionSphereRadius + _particle[p].radius; if (distanceToSphereCenter < combinedRadius) { if (distanceToSphereCenter > 0.0f){ glm::vec3 directionToSphereCenter = vectorToSphereCenter / distanceToSphereCenter; - _particle[p].position = _collisionSpherePosition - directionToSphereCenter * combinedRadius; + _particle[p].position = myEmitter.collisionSpherePosition - directionToSphereCenter * combinedRadius; } } } } -void ParticleSystem::setCollisionSphere(glm::vec3 position, float radius) { - _usingCollisionSphere = true; - _collisionSpherePosition = position; - _collisionSphereRadius = radius; +void ParticleSystem::setCollisionSphere(int e, glm::vec3 position, float radius) { + _emitter[e].usingCollisionSphere = true; + _emitter[e].collisionSpherePosition = position; + _emitter[e].collisionSphereRadius = radius; } void ParticleSystem::render() { // render the emitters for (unsigned int e = 0; e < _numEmitters; e++) { - renderEmitter(e, 0.2f); + if (_emitter[e].showingEmitter) { + renderEmitter(e, 0.2f); + } }; // render the particles diff --git a/interface/src/ParticleSystem.h b/interface/src/ParticleSystem.h index f7f0063dbc..3b8826d697 100644 --- a/interface/src/ParticleSystem.h +++ b/interface/src/ParticleSystem.h @@ -11,8 +11,8 @@ #include -const int MAX_PARTICLES = 10000; -const int MAX_EMITTERS = 10; +const int MAX_PARTICLES = 5000; +const int MAX_EMITTERS = 20; class ParticleSystem { public: @@ -22,13 +22,14 @@ public: 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 setCollisionSphere(int e, glm::vec3 position, float radius); // specify a sphere for the particles to collide with 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 + void setShowingEmitter(int e, bool showing) { _emitter[e].showingEmitter = showing;} + private: @@ -38,6 +39,18 @@ private: glm::vec3 right; glm::vec3 up; glm::vec3 front; + float bounce; + float gravity; + float airFriction; + float jitter; + float emitterAttraction; + float tornadoForce; + float neighborAttraction; + float neighborRepulsion; + bool usingCollisionSphere; + glm::vec3 collisionSpherePosition; + float collisionSphereRadius; + bool showingEmitter; }; struct Particle { @@ -52,27 +65,17 @@ private: }; glm::vec3 _upDirection; - float _bounce; - float _gravity; float _timer; Emitter _emitter[MAX_EMITTERS]; Particle _particle[MAX_PARTICLES]; int _numParticles; int _numEmitters; - float _airFriction; - float _jitter; - float _emitterAttraction; - float _tornadoForce; - float _neighborAttraction; - float _neighborRepulsion; - bool _usingCollisionSphere; - glm::vec3 _collisionSpherePosition; - float _collisionSphereRadius; // private methods void updateEmitter(int e, float deltaTime); void updateParticle(int index, float deltaTime); - void createParticle(glm::vec3 position, glm::vec3 velocity, float radius, glm::vec4 color, float lifespan); + 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 83c779ad766e32caaea1ef846c2768041d2385bf Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 15 Jul 2013 14:08:04 -0700 Subject: [PATCH 06/17] merge --- libraries/shared/src/PacketHeaders.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index 230ca5bacc..f983b91d0b 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -63,4 +63,4 @@ int numBytesForPacketHeader(unsigned char* packetHeader) { // currently this need not be dynamic - there are 2 bytes for each packet header return 2; -} +} \ No newline at end of file From c0f319f077f4bec5a40a3780521f57a2cc23fd52 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 15 Jul 2013 14:36:11 -0700 Subject: [PATCH 07/17] merge --- interface/src/Application.cpp | 8 +++++++- libraries/avatars/src/HandData.h | 0 2 files changed, 7 insertions(+), 1 deletion(-) mode change 100755 => 100644 libraries/avatars/src/HandData.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 44c2bc5200..d7ff6fe959 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2037,7 +2037,6 @@ void Application::update(float deltaTime) { _audio.eventuallyAnalyzePing(); #endif - if (TESTING_PARTICLE_SYSTEM) { if (!_particleSystemInitialized) { @@ -2100,6 +2099,13 @@ void Application::update(float deltaTime) { 1.0f + cosf(t * 9.0f) * 0.02f, 3.0f + sinf(t * 7.0f) * 0.02f ); + + +//_myAvatar.getHand().setLeapFingers(LeapManager::getFingerTips(), LeapManager::getFingerRoots()); +//_myAvatar.getHand().setLeapHands(LeapManager::getHandPositions(), LeapManager::getHandNormals()); + + + glm::vec3 tilt = glm::vec3 ( diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h old mode 100755 new mode 100644 From 56d0c7d7e4954b7607f33204e1cc52be6bc4dc33 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 15 Jul 2013 15:45:31 -0700 Subject: [PATCH 08/17] added array of finger emitters for particle system --- interface/src/Application.cpp | 79 +++++++++++++++----------------- interface/src/Application.h | 2 +- interface/src/Hand.h | 1 + interface/src/LeapManager.cpp | 0 interface/src/ParticleSystem.cpp | 24 ++++++---- 5 files changed, 56 insertions(+), 50 deletions(-) mode change 100755 => 100644 interface/src/LeapManager.cpp diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d7ff6fe959..1b050bc874 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -174,7 +174,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _justStarted(true), _particleSystemInitialized(false), _coolDemoParticleEmitter(-1), - _fingerParticleEmitter(-1), _wantToKillLocalVoxels(false), _frustumDrawingMode(FRUSTUM_DRAW_MODE_ALL), _viewFrustumOffsetYaw(-135.0), @@ -210,6 +209,12 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _bytesCount(0), _swatch(NULL) { + + // initialize all finger particle emitters with an invalid id as default + for (int f = 0; f< NUM_FINGERS_PER_HAND; f ++ ) { + _fingerParticleEmitter[f] = -1; + } + _applicationStartupTime = startup_time; _window->setWindowTitle("Interface"); printLog("Interface Startup:\n"); @@ -2042,8 +2047,7 @@ void Application::update(float deltaTime) { // create a stable test emitter and spit out a bunch of particles _coolDemoParticleEmitter = _particleSystem.addEmitter(); - _fingerParticleEmitter = _particleSystem.addEmitter(); - + if (_coolDemoParticleEmitter != -1) { _particleSystem.setShowingEmitter(_coolDemoParticleEmitter, true); glm::vec3 particleEmitterPosition = glm::vec3(5.0f, 1.0f, 5.0f); @@ -2060,11 +2064,11 @@ void Application::update(float deltaTime) { _particleSystem.emitParticlesNow(_coolDemoParticleEmitter, 1500, radius, color, velocity, lifespan); } - if (_fingerParticleEmitter != -1) { - _particleSystem.setShowingEmitter(_fingerParticleEmitter, false); + for ( int f = 0; f< NUM_FINGERS_PER_HAND; f ++ ) { + _fingerParticleEmitter[f] = _particleSystem.addEmitter(); + _particleSystem.setShowingEmitter(_fingerParticleEmitter[f], true); } - - + // signal that the particle system has been initialized _particleSystemInitialized = true; @@ -2073,11 +2077,9 @@ void Application::update(float deltaTime) { } else { // update the particle system - static float t = 0.0f; t += deltaTime; - if (_coolDemoParticleEmitter != -1) { glm::vec3 tilt = glm::vec3 @@ -2090,40 +2092,35 @@ void Application::update(float deltaTime) { _particleSystem.setEmitterRotation(_coolDemoParticleEmitter, glm::quat(glm::radians(tilt))); } - if (_fingerParticleEmitter != -1) { - - glm::vec3 particleEmitterPosition = - glm::vec3 - ( - 3.0f + sinf(t * 8.0f) * 0.02f, - 1.0f + cosf(t * 9.0f) * 0.02f, - 3.0f + sinf(t * 7.0f) * 0.02f - ); - - -//_myAvatar.getHand().setLeapFingers(LeapManager::getFingerTips(), LeapManager::getFingerRoots()); -//_myAvatar.getHand().setLeapHands(LeapManager::getHandPositions(), LeapManager::getHandNormals()); - - - - - 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)); + const std::vector& fingerTips = _myAvatar.getHand().getFingerTips(); + const std::vector& fingerRoots = _myAvatar.getHand().getFingerRoots(); + const std::vector& handPositions = _myAvatar.getHand().getHandPositions(); + const std::vector& handNormals = _myAvatar.getHand().getHandNormals(); - _particleSystem.setEmitterPosition(_fingerParticleEmitter, particleEmitterPosition); - _particleSystem.setEmitterRotation(_fingerParticleEmitter, particleEmitterRotation); + for ( int f = 0; f< fingerTips.size(); f ++ ) { - float radius = 0.01f; - glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); - glm::vec3 velocity(0.0f, 0.01f, 0.0f); - float lifespan = 0.4f; - _particleSystem.emitParticlesNow(_fingerParticleEmitter, 1, radius, color, velocity, lifespan); + if (_fingerParticleEmitter[f] != -1) { + + glm::vec3 particleEmitterPosition = _myAvatar.getHand().leapPositionToWorldPosition(fingerTips[f]); + + 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)); + + _particleSystem.setEmitterPosition(_fingerParticleEmitter[0], particleEmitterPosition); + _particleSystem.setEmitterRotation(_fingerParticleEmitter[0], particleEmitterRotation); + + float radius = 0.01f; + glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); + glm::vec3 velocity(0.0f, 0.01f, 0.0f); + float lifespan = 0.4f; + _particleSystem.emitParticlesNow(_fingerParticleEmitter[0], 1, radius, color, velocity, lifespan); + } } _particleSystem.setUpDirection(glm::vec3(0.0f, 1.0f, 0.0f)); diff --git a/interface/src/Application.h b/interface/src/Application.h index 789b18e011..2800904c3f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -285,7 +285,7 @@ private: bool _justStarted; bool _particleSystemInitialized; int _coolDemoParticleEmitter; - int _fingerParticleEmitter; + int _fingerParticleEmitter[NUM_FINGERS_PER_HAND]; Stars _stars; diff --git a/interface/src/Hand.h b/interface/src/Hand.h index 1c25c85fbc..7056911871 100755 --- a/interface/src/Hand.h +++ b/interface/src/Hand.h @@ -18,6 +18,7 @@ #include #include +const int NUM_FINGERS_PER_HAND = 5; class Avatar; class ProgramObject; diff --git a/interface/src/LeapManager.cpp b/interface/src/LeapManager.cpp old mode 100755 new mode 100644 diff --git a/interface/src/ParticleSystem.cpp b/interface/src/ParticleSystem.cpp index 14aaedbac9..7364f215af 100644 --- a/interface/src/ParticleSystem.cpp +++ b/interface/src/ParticleSystem.cpp @@ -13,7 +13,6 @@ const float DEFAULT_PARTICLE_BOUNCE = 1.0f; const float DEFAULT_PARTICLE_AIR_FRICTION = 2.0f; -const float DEFAULT_PARTICLE_GRAVITY = 0.05f; ParticleSystem::ParticleSystem() { @@ -30,7 +29,7 @@ ParticleSystem::ParticleSystem() { _emitter[e].front = IDENTITY_FRONT; _emitter[e].bounce = DEFAULT_PARTICLE_BOUNCE; _emitter[e].airFriction = DEFAULT_PARTICLE_AIR_FRICTION; - _emitter[e].gravity = DEFAULT_PARTICLE_GRAVITY; + _emitter[e].gravity = 0.0f; _emitter[e].jitter = 0.0f; _emitter[e].emitterAttraction = 0.0f; _emitter[e].tornadoForce = 0.0f; @@ -56,11 +55,20 @@ ParticleSystem::ParticleSystem() { int ParticleSystem::addEmitter() { + + printf( "\n" ); + printf( "ParticleSystem::addEmitter\n" ); + _numEmitters ++; if (_numEmitters > MAX_EMITTERS) { + + printf( "Oops! _numEmitters > MAX_EMITTERS... returning -1\n" ); + return -1; } + + printf( "ok, _numEmitters is %d,and the index of this newly added emitter is %d.\n", _numEmitters, _numEmitters-1 ); return _numEmitters - 1; } @@ -153,13 +161,13 @@ void ParticleSystem::runSpecialEffectsTest(int e, float deltaTime) { _timer += deltaTime; - _emitter[e].gravity = 0.0f + DEFAULT_PARTICLE_GRAVITY * sinf( _timer * 0.52f ); + _emitter[e].gravity = 0.0f + 0.05f * sinf( _timer * 0.52f ); _emitter[e].airFriction = (DEFAULT_PARTICLE_AIR_FRICTION + 0.5f) + 2.0f * sinf( _timer * 0.32f ); - _emitter[e].jitter = 0.05f + 0.05f * sinf( _timer * 0.42f ); - _emitter[e].emitterAttraction = 0.015f + 0.015f * cosf( _timer * 0.6f ); - _emitter[e].tornadoForce = 0.0f + 0.03f * sinf( _timer * 0.7f ); - _emitter[e].neighborAttraction = 0.1f + 0.1f * cosf( _timer * 0.8f ); - _emitter[e].neighborRepulsion = 0.2f + 0.2f * sinf( _timer * 0.4f ); + _emitter[e].jitter = 0.05f + 0.05f * sinf( _timer * 0.42f ); + _emitter[e].emitterAttraction = 0.015f + 0.015f * cosf( _timer * 0.6f ); + _emitter[e].tornadoForce = 0.0f + 0.03f * sinf( _timer * 0.7f ); + _emitter[e].neighborAttraction = 0.1f + 0.1f * cosf( _timer * 0.8f ); + _emitter[e].neighborRepulsion = 0.2f + 0.2f * sinf( _timer * 0.4f ); if (_emitter[e].gravity < 0.0f) { _emitter[e].gravity = 0.0f; From 0481a81ca7639127b494267a71e0fbba93f20588 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 15 Jul 2013 17:58:17 -0700 Subject: [PATCH 09/17] moved finger particles over to hand.cpp --- interface/src/Application.cpp | 169 ++++++++++++++----------------- interface/src/Application.h | 3 +- interface/src/Hand.cpp | 61 ++++++++++- interface/src/Hand.h | 10 +- interface/src/ParticleSystem.cpp | 106 +++++++++---------- interface/src/ParticleSystem.h | 52 +++++----- 6 files changed, 225 insertions(+), 176 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1b050bc874..16af90ef12 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 @@ -209,12 +209,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _bytesCount(0), _swatch(NULL) { - - // initialize all finger particle emitters with an invalid id as default - for (int f = 0; f< NUM_FINGERS_PER_HAND; f ++ ) { - _fingerParticleEmitter[f] = -1; - } - _applicationStartupTime = startup_time; _window->setWindowTitle("Interface"); printLog("Interface Startup:\n"); @@ -1995,6 +1989,8 @@ void Application::update(float deltaTime) { _myAvatar.simulate(deltaTime, NULL); } + _myAvatar.getHand().simulate(deltaTime, true); + if (!OculusManager::isConnected()) { if (_lookingInMirror->isChecked()) { if (_myCamera.getMode() != CAMERA_MODE_MIRROR) { @@ -2043,90 +2039,8 @@ void Application::update(float deltaTime) { #endif if (TESTING_PARTICLE_SYSTEM) { - if (!_particleSystemInitialized) { - - // create a stable test emitter and spit out a bunch of particles - _coolDemoParticleEmitter = _particleSystem.addEmitter(); - - if (_coolDemoParticleEmitter != -1) { - _particleSystem.setShowingEmitter(_coolDemoParticleEmitter, true); - glm::vec3 particleEmitterPosition = glm::vec3(5.0f, 1.0f, 5.0f); - _particleSystem.setEmitterPosition(_coolDemoParticleEmitter, particleEmitterPosition); - 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; - - // determine a collision sphere - glm::vec3 collisionSpherePosition = glm::vec3( 5.0f, 0.5f, 5.0f ); - float collisionSphereRadius = 0.5f; - _particleSystem.setCollisionSphere(_coolDemoParticleEmitter, collisionSpherePosition, collisionSphereRadius); - _particleSystem.emitParticlesNow(_coolDemoParticleEmitter, 1500, radius, color, velocity, lifespan); - } - - for ( int f = 0; f< NUM_FINGERS_PER_HAND; f ++ ) { - _fingerParticleEmitter[f] = _particleSystem.addEmitter(); - _particleSystem.setShowingEmitter(_fingerParticleEmitter[f], true); - } - - // signal that the particle system has been initialized - _particleSystemInitialized = true; - - // apply a preset color palette - _particleSystem.setOrangeBlueColorPalette(); - } else { - // update the particle system - - static float t = 0.0f; - t += deltaTime; - - if (_coolDemoParticleEmitter != -1) { - - glm::vec3 tilt = glm::vec3 - ( - 30.0f * sinf( t * 0.55f ), - 0.0f, - 30.0f * cosf( t * 0.75f ) - ); - - _particleSystem.setEmitterRotation(_coolDemoParticleEmitter, glm::quat(glm::radians(tilt))); - } - - const std::vector& fingerTips = _myAvatar.getHand().getFingerTips(); - const std::vector& fingerRoots = _myAvatar.getHand().getFingerRoots(); - const std::vector& handPositions = _myAvatar.getHand().getHandPositions(); - const std::vector& handNormals = _myAvatar.getHand().getHandNormals(); - - for ( int f = 0; f< fingerTips.size(); f ++ ) { - - if (_fingerParticleEmitter[f] != -1) { - - glm::vec3 particleEmitterPosition = _myAvatar.getHand().leapPositionToWorldPosition(fingerTips[f]); - - 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)); - - _particleSystem.setEmitterPosition(_fingerParticleEmitter[0], particleEmitterPosition); - _particleSystem.setEmitterRotation(_fingerParticleEmitter[0], particleEmitterRotation); - - float radius = 0.01f; - glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); - glm::vec3 velocity(0.0f, 0.01f, 0.0f); - float lifespan = 0.4f; - _particleSystem.emitParticlesNow(_fingerParticleEmitter[0], 1, radius, color, velocity, lifespan); - } - } - - _particleSystem.setUpDirection(glm::vec3(0.0f, 1.0f, 0.0f)); - _particleSystem.simulate(deltaTime); - } - } + updateParticleSystem(deltaTime); + } } void Application::updateAvatar(float deltaTime) { @@ -3471,3 +3385,76 @@ void Application::exportSettings() { } + +void Application::updateParticleSystem(float deltaTime) { + + if (!_particleSystemInitialized) { + // create a stable test emitter and spit out a bunch of particles + _coolDemoParticleEmitter = _particleSystem.addEmitter(); + + if (_coolDemoParticleEmitter != -1) { + _particleSystem.setShowingEmitter(_coolDemoParticleEmitter, true); + glm::vec3 particleEmitterPosition = glm::vec3(5.0f, 1.0f, 5.0f); + _particleSystem.setEmitterPosition(_coolDemoParticleEmitter, particleEmitterPosition); + 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; + + // determine a collision sphere + glm::vec3 collisionSpherePosition = glm::vec3( 5.0f, 0.5f, 5.0f ); + float collisionSphereRadius = 0.5f; + _particleSystem.setCollisionSphere(_coolDemoParticleEmitter, collisionSpherePosition, collisionSphereRadius); + _particleSystem.emitParticlesNow(_coolDemoParticleEmitter, 1500, radius, color, velocity, lifespan); + } + + // signal that the particle system has been initialized + _particleSystemInitialized = true; + + // apply a preset color palette + _particleSystem.setOrangeBlueColorPalette(); + } else { + // update the particle system + + static float t = 0.0f; + t += deltaTime; + + if (_coolDemoParticleEmitter != -1) { + + glm::vec3 tilt = glm::vec3 + ( + 30.0f * sinf( t * 0.55f ), + 0.0f, + 30.0f * cosf( t * 0.75f ) + ); + + _particleSystem.setEmitterRotation(_coolDemoParticleEmitter, glm::quat(glm::radians(tilt))); + + ParticleSystem::ParticleAttributes attributes; + + 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 ); + attributes.emitterAttraction = 0.015f + 0.015f * cosf( t * 0.6f ); + attributes.tornadoForce = 0.0f + 0.03f * sinf( t * 0.7f ); + attributes.neighborAttraction = 0.1f + 0.1f * cosf( t * 0.8f ); + attributes.neighborRepulsion = 0.2f + 0.2f * sinf( t * 0.4f ); + attributes.bounce = 1.0f; + attributes.usingCollisionSphere = true; + attributes.collisionSpherePosition = glm::vec3( 5.0f, 0.5f, 5.0f ); + attributes.collisionSphereRadius = 0.5f; + + if (attributes.gravity < 0.0f) { + attributes.gravity = 0.0f; + } + + _particleSystem.setParticleAttributesForEmitter(_coolDemoParticleEmitter, attributes); + } + + _particleSystem.setUpDirection(glm::vec3(0.0f, 1.0f, 0.0f)); + _particleSystem.simulate(deltaTime); + } +} + + + diff --git a/interface/src/Application.h b/interface/src/Application.h index 2800904c3f..7ecee0cbec 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -83,6 +83,8 @@ public: const glm::vec3 getMouseVoxelWorldCoordinates(const VoxelDetail _mouseVoxel); + void updateParticleSystem(float deltaTime); + Avatar* getAvatar() { return &_myAvatar; } Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } @@ -285,7 +287,6 @@ private: bool _justStarted; bool _particleSystemInitialized; int _coolDemoParticleEmitter; - int _fingerParticleEmitter[NUM_FINGERS_PER_HAND]; Stars _stars; diff --git a/interface/src/Hand.cpp b/interface/src/Hand.cpp index 29a2c32bf1..fa08db7f27 100755 --- a/interface/src/Hand.cpp +++ b/interface/src/Hand.cpp @@ -23,8 +23,13 @@ Hand::Hand(Avatar* owningAvatar) : _lookingInMirror(false), _ballColor(0.0, 0.0, 0.4), _position(0.0, 0.4, 0.0), - _orientation(0.0, 0.0, 0.0, 1.0) + _orientation(0.0, 0.0, 0.0, 1.0), + _particleSystemInitialized(false) { + // initialize all finger particle emitters with an invalid id as default + for (int f = 0; f< NUM_FINGERS_PER_HAND; f ++ ) { + _fingerParticleEmitter[f] = -1; + } } void Hand::init() { @@ -40,6 +45,7 @@ void Hand::reset() { } void Hand::simulate(float deltaTime, bool isMine) { + updateFingerParticles(deltaTime); } glm::vec3 Hand::leapPositionToWorldPosition(const glm::vec3& leapPosition) { @@ -69,6 +75,10 @@ void Hand::calculateGeometry() { void Hand::render(bool lookingInMirror) { + if (_particleSystemInitialized) { + _particleSystem.render(); + } + _renderAlpha = 1.0; _lookingInMirror = lookingInMirror; @@ -132,3 +142,52 @@ 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(); + _particleSystem.setShowingEmitter(_fingerParticleEmitter[f], true); + } + _particleSystemInitialized = true; + } else { + // update the particles + + static float t = 0.0f; + t += deltaTime; + + for ( int f = 0; f< _fingerTips.size(); f ++ ) { + + if (_fingerParticleEmitter[f] != -1) { + + 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)); + + _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); + float lifespan = 0.3f; + _particleSystem.emitParticlesNow(_fingerParticleEmitter[0], 1, radius, color, velocity, lifespan); + } + } + + _particleSystem.setUpDirection(glm::vec3(0.0f, 1.0f, 0.0f)); + _particleSystem.simulate(deltaTime); + } +} + + + diff --git a/interface/src/Hand.h b/interface/src/Hand.h index 7056911871..f9c451ff84 100755 --- a/interface/src/Hand.h +++ b/interface/src/Hand.h @@ -15,6 +15,7 @@ #include "world.h" #include "InterfaceConfig.h" #include "SerialInterface.h" +#include "ParticleSystem.h" #include #include @@ -47,7 +48,9 @@ public: const std::vector& fingerRoots); void setLeapHands (const std::vector& handPositions, const std::vector& handNormals); - + + void updateFingerParticles(float deltaTime); + // getters const glm::vec3& getLeapBallPosition (int ball) const { return _leapBalls[ball].position;} @@ -58,6 +61,8 @@ private: // disallow copies of the Hand, copy of owning Avatar is disallowed too Hand(const Hand&); Hand& operator= (const Hand&); + + ParticleSystem _particleSystem; Avatar* _owningAvatar; float _renderAlpha; @@ -67,6 +72,9 @@ private: glm::quat _orientation; std::vector _leapBalls; + bool _particleSystemInitialized; + int _fingerParticleEmitter[NUM_FINGERS_PER_HAND]; + // private methods void renderHandSpheres(); void calculateGeometry(); diff --git a/interface/src/ParticleSystem.cpp b/interface/src/ParticleSystem.cpp index 7364f215af..fcc24a2663 100644 --- a/interface/src/ParticleSystem.cpp +++ b/interface/src/ParticleSystem.cpp @@ -22,24 +22,23 @@ ParticleSystem::ParticleSystem() { _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].bounce = DEFAULT_PARTICLE_BOUNCE; - _emitter[e].airFriction = DEFAULT_PARTICLE_AIR_FRICTION; - _emitter[e].gravity = 0.0f; - _emitter[e].jitter = 0.0f; - _emitter[e].emitterAttraction = 0.0f; - _emitter[e].tornadoForce = 0.0f; - _emitter[e].neighborAttraction = 0.0f; - _emitter[e].neighborRepulsion = 0.0f; - _emitter[e].collisionSphereRadius = 0.0f; - _emitter[e].collisionSpherePosition = glm::vec3(0.0f, 0.0f, 0.0f); - _emitter[e].usingCollisionSphere = false; - _emitter[e].showingEmitter = 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].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; }; for (unsigned int p = 0; p < MAX_PARTICLES; p++) { @@ -56,19 +55,11 @@ ParticleSystem::ParticleSystem() { int ParticleSystem::addEmitter() { - printf( "\n" ); - printf( "ParticleSystem::addEmitter\n" ); - _numEmitters ++; if (_numEmitters > MAX_EMITTERS) { - - printf( "Oops! _numEmitters > MAX_EMITTERS... returning -1\n" ); - return -1; } - - printf( "ok, _numEmitters is %d,and the index of this newly added emitter is %d.\n", _numEmitters, _numEmitters-1 ); return _numEmitters - 1; } @@ -81,8 +72,6 @@ void ParticleSystem::simulate(float deltaTime) { updateEmitter(e, deltaTime); } - runSpecialEffectsTest(0, deltaTime); - // update particles for (unsigned int p = 0; p < _numParticles; p++) { if (_particle[p].alive) { @@ -157,24 +146,23 @@ void ParticleSystem::setOrangeBlueColorPalette() { } -void ParticleSystem::runSpecialEffectsTest(int e, float deltaTime) { +void ParticleSystem::setParticleAttributesForEmitter(int emitterIndex, ParticleAttributes attributes) { - _timer += deltaTime; - - _emitter[e].gravity = 0.0f + 0.05f * sinf( _timer * 0.52f ); - _emitter[e].airFriction = (DEFAULT_PARTICLE_AIR_FRICTION + 0.5f) + 2.0f * sinf( _timer * 0.32f ); - _emitter[e].jitter = 0.05f + 0.05f * sinf( _timer * 0.42f ); - _emitter[e].emitterAttraction = 0.015f + 0.015f * cosf( _timer * 0.6f ); - _emitter[e].tornadoForce = 0.0f + 0.03f * sinf( _timer * 0.7f ); - _emitter[e].neighborAttraction = 0.1f + 0.1f * cosf( _timer * 0.8f ); - _emitter[e].neighborRepulsion = 0.2f + 0.2f * sinf( _timer * 0.4f ); - - if (_emitter[e].gravity < 0.0f) { - _emitter[e].gravity = 0.0f; - } + _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; } + void ParticleSystem::updateParticle(int p, float deltaTime) { _particle[p].age += deltaTime; @@ -189,14 +177,14 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { _particle[p].velocity += glm::vec3 ( - -myEmitter.jitter * ONE_HALF + myEmitter.jitter * randFloat(), - -myEmitter.jitter * ONE_HALF + myEmitter.jitter * randFloat(), - -myEmitter.jitter * ONE_HALF + myEmitter.jitter * randFloat() + -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() ) * deltaTime; // apply attraction to home position glm::vec3 vectorToHome = myEmitter.position - _particle[p].position; - _particle[p].velocity += vectorToHome * myEmitter.emitterAttraction * deltaTime; + _particle[p].velocity += vectorToHome * myEmitter.particleAttributes.emitterAttraction * deltaTime; // apply neighbor attraction int neighbor = p + 1; @@ -207,20 +195,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.neighborAttraction * deltaTime; + _particle[p].velocity -= vectorToNeighbor * myEmitter.particleAttributes.neighborAttraction * deltaTime; float distanceToNeighbor = glm::length(vectorToNeighbor); if (distanceToNeighbor > 0.0f) { - _particle[neighbor].velocity += (vectorToNeighbor / ( 1.0f + distanceToNeighbor * distanceToNeighbor)) * myEmitter.neighborRepulsion * deltaTime; + _particle[neighbor].velocity += (vectorToNeighbor / ( 1.0f + distanceToNeighbor * distanceToNeighbor)) * myEmitter.particleAttributes.neighborRepulsion * deltaTime; } } // apply tornado force glm::vec3 tornadoDirection = glm::cross(vectorToHome, myEmitter.up); - _particle[p].velocity += tornadoDirection * myEmitter.tornadoForce * deltaTime; + _particle[p].velocity += tornadoDirection * myEmitter.particleAttributes.tornadoForce * deltaTime; // apply air friction - float drag = 1.0 - myEmitter.airFriction * deltaTime; + float drag = 1.0 - myEmitter.particleAttributes.airFriction * deltaTime; if (drag < 0.0f) { _particle[p].velocity = glm::vec3(0.0f, 0.0f, 0.0f); } else { @@ -228,7 +216,7 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { } // apply gravity - _particle[p].velocity -= _upDirection * myEmitter.gravity * deltaTime; + _particle[p].velocity -= _upDirection * myEmitter.particleAttributes.gravity * deltaTime; // update position by velocity _particle[p].position += _particle[p].velocity; @@ -238,29 +226,29 @@ 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.bounce; + _particle[p].velocity.y *= -myEmitter.particleAttributes.bounce; } } // collision with sphere - if (myEmitter.usingCollisionSphere) { - glm::vec3 vectorToSphereCenter = myEmitter.collisionSpherePosition - _particle[p].position; + if (myEmitter.particleAttributes.usingCollisionSphere) { + glm::vec3 vectorToSphereCenter = myEmitter.particleAttributes.collisionSpherePosition - _particle[p].position; float distanceToSphereCenter = glm::length(vectorToSphereCenter); - float combinedRadius = myEmitter.collisionSphereRadius + _particle[p].radius; + float combinedRadius = myEmitter.particleAttributes.collisionSphereRadius + _particle[p].radius; if (distanceToSphereCenter < combinedRadius) { if (distanceToSphereCenter > 0.0f){ glm::vec3 directionToSphereCenter = vectorToSphereCenter / distanceToSphereCenter; - _particle[p].position = myEmitter.collisionSpherePosition - directionToSphereCenter * combinedRadius; + _particle[p].position = myEmitter.particleAttributes.collisionSpherePosition - directionToSphereCenter * combinedRadius; } } } } void ParticleSystem::setCollisionSphere(int e, glm::vec3 position, float radius) { - _emitter[e].usingCollisionSphere = true; - _emitter[e].collisionSpherePosition = position; - _emitter[e].collisionSphereRadius = radius; + _emitter[e].particleAttributes.usingCollisionSphere = true; + _emitter[e].particleAttributes.collisionSpherePosition = position; + _emitter[e].particleAttributes.collisionSphereRadius = radius; } void ParticleSystem::render() { diff --git a/interface/src/ParticleSystem.h b/interface/src/ParticleSystem.h index 3b8826d697..c94acd03ba 100644 --- a/interface/src/ParticleSystem.h +++ b/interface/src/ParticleSystem.h @@ -16,29 +16,8 @@ const int MAX_EMITTERS = 20; class ParticleSystem { 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 simulate(float deltaTime); - void render(); - - void setOrangeBlueColorPalette(); // apply a nice preset color palette to the particles - void setCollisionSphere(int e, glm::vec3 position, float radius); // specify a sphere for the particles to collide with - 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 - void setShowingEmitter(int e, bool showing) { _emitter[e].showingEmitter = showing;} - - -private: - struct Emitter { - glm::vec3 position; - glm::quat rotation; - glm::vec3 right; - glm::vec3 up; - glm::vec3 front; + struct ParticleAttributes { float bounce; float gravity; float airFriction; @@ -50,7 +29,34 @@ private: bool usingCollisionSphere; glm::vec3 collisionSpherePosition; float collisionSphereRadius; + }; + + 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 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 + +private: + + struct Emitter { + glm::vec3 position; + glm::quat rotation; + glm::vec3 right; + glm::vec3 up; + glm::vec3 front; bool showingEmitter; + ParticleAttributes particleAttributes; }; struct Particle { @@ -75,7 +81,7 @@ 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 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 39130aef58424cd36e20cf04d2041989df91dc32 Mon Sep 17 00:00:00 2001 From: Eric Johnston Date: Tue, 16 Jul 2013 18:10:54 -0700 Subject: [PATCH 10/17] Rave Glove demo: activation mode and stage (dark backdrop) drawing. --- interface/src/Application.cpp | 1 + interface/src/Hand.cpp | 31 +++++++++++++++++++++++++++++++ interface/src/Hand.h | 4 ++++ 3 files changed, 36 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1bfba999b1..791353abdb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2033,6 +2033,7 @@ void Application::update(float deltaTime) { // Leap finger-sensing device LeapManager::enableFakeFingers(_simulateLeapHand->isChecked() || _testRaveGlove->isChecked()); LeapManager::nextFrame(); + _myAvatar.getHand().setRaveGloveActive(_testRaveGlove->isChecked()); _myAvatar.getHand().setLeapFingers(LeapManager::getFingerTips(), LeapManager::getFingerRoots()); _myAvatar.getHand().setLeapHands(LeapManager::getHandPositions(), LeapManager::getHandNormals()); diff --git a/interface/src/Hand.cpp b/interface/src/Hand.cpp index 29a2c32bf1..d0ff0abd5a 100755 --- a/interface/src/Hand.cpp +++ b/interface/src/Hand.cpp @@ -74,12 +74,43 @@ void Hand::render(bool lookingInMirror) { calculateGeometry(); + if (_isRaveGloveActive) + renderRaveGloveStage(); + glEnable(GL_DEPTH_TEST); glEnable(GL_RESCALE_NORMAL); renderHandSpheres(); } +void Hand::renderRaveGloveStage() { + if (_owningAvatar && _owningAvatar->isMyAvatar()) { + Head& head = _owningAvatar->getHead(); + glm::quat headOrientation = head.getOrientation(); + glm::vec3 headPosition = head.getPosition(); + float scale = 100.0f; + glm::vec3 vc = headOrientation * glm::vec3( 0.0f, 0.0f, -30.0f) + headPosition; + glm::vec3 v0 = headOrientation * (glm::vec3(-1.0f, -1.0f, 0.0f) * scale) + vc; + glm::vec3 v1 = headOrientation * (glm::vec3( 1.0f, -1.0f, 0.0f) * scale) + vc; + glm::vec3 v2 = headOrientation * (glm::vec3( 1.0f, 1.0f, 0.0f) * scale) + vc; + glm::vec3 v3 = headOrientation * (glm::vec3(-1.0f, 1.0f, 0.0f) * scale) + vc; + + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBegin(GL_TRIANGLE_FAN); + glColor4f(0.0f, 0.0f, 0.0f, 1.0f); + glVertex3fv((float*)&vc); + glColor4f(0.0f, 0.0f, 0.0f, 0.5f); + glVertex3fv((float*)&v0); + glVertex3fv((float*)&v1); + glVertex3fv((float*)&v2); + glVertex3fv((float*)&v3); + glVertex3fv((float*)&v0); + glEnd(); + glEnable(GL_DEPTH_TEST); + } +} + void Hand::renderHandSpheres() { glPushMatrix(); // Draw the leap balls diff --git a/interface/src/Hand.h b/interface/src/Hand.h index 1c25c85fbc..e1b0dc9ff0 100755 --- a/interface/src/Hand.h +++ b/interface/src/Hand.h @@ -46,9 +46,11 @@ public: const std::vector& fingerRoots); void setLeapHands (const std::vector& handPositions, const std::vector& handNormals); + void setRaveGloveActive(bool active) { _isRaveGloveActive = active; } // getters const glm::vec3& getLeapBallPosition (int ball) const { return _leapBalls[ball].position;} + bool isRaveGloveActive () const { return _isRaveGloveActive; } // position conversion glm::vec3 leapPositionToWorldPosition(const glm::vec3& leapPosition); @@ -61,12 +63,14 @@ private: Avatar* _owningAvatar; float _renderAlpha; bool _lookingInMirror; + bool _isRaveGloveActive; glm::vec3 _ballColor; glm::vec3 _position; glm::quat _orientation; std::vector _leapBalls; // private methods + void renderRaveGloveStage(); void renderHandSpheres(); void calculateGeometry(); }; From 98dd83dde81b3c53229b662083af7ad3bee2273c Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 17 Jul 2013 10:02:23 -0700 Subject: [PATCH 11/17] ahibfasubhdf --- interface/src/Application.cpp | 6 ++- interface/src/Application.h | 8 +++- interface/src/Audio.cpp | 70 ++++++++++++++++++++++++++++------- interface/src/Audio.h | 16 ++++++-- interface/src/Avatar.cpp | 50 +++++++++++++++++++++++-- interface/src/Avatar.h | 7 +++- interface/src/Head.cpp | 6 ++- interface/src/Util.cpp | 34 ++++++++++++----- interface/src/Util.h | 5 ++- 9 files changed, 165 insertions(+), 37 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0bd1826f6b..582bc4fcb4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -195,6 +195,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _isTouchPressed(false), _yawFromTouch(0.0f), _pitchFromTouch(0.0f), + _groundPlaneImpact(0.0f), _mousePressed(false), _mouseVoxelScale(1.0f / 1024.0f), _justEditedVoxel(false), @@ -2528,7 +2529,7 @@ void Application::displaySide(Camera& whichCamera) { //draw a grid ground plane.... if (_renderGroundPlaneOn->isChecked()) { - drawGroundPlaneGrid(EDGE_SIZE_GROUND_PLANE); + renderGroundPlaneGrid(EDGE_SIZE_GROUND_PLANE, _audio.getCollisionSoundMagnitude()); } // Draw voxels if (_renderVoxels->isChecked()) { @@ -2606,6 +2607,9 @@ void Application::displayOverlay() { glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); + // Display a single screen-size quad to + renderCollisionOverlay(_glWidget->width(), _glWidget->height(), _audio.getCollisionSoundMagnitude()); + #ifndef _WIN32 _audio.render(_glWidget->width(), _glWidget->height()); if (_oscilloscopeOn->isChecked()) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 37411aa9d5..9333808a27 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -87,6 +87,7 @@ public: void updateParticleSystem(float deltaTime); Avatar* getAvatar() { return &_myAvatar; } + Audio* getAudio() { return &_audio; } Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } VoxelSystem* getVoxels() { return &_voxels; } @@ -103,6 +104,9 @@ public: QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; } GeometryCache* getGeometryCache() { return &_geometryCache; } + void setGroundPlaneImpact(float groundPlaneImpact) { _groundPlaneImpact = groundPlaneImpact; } + + private slots: void timer(); @@ -208,7 +212,7 @@ private: void deleteVoxelUnderCursor(); void eyedropperVoxelUnderCursor(); void resetSensors(); - + void setMenuShortcutsEnabled(bool enabled); void updateCursor(); @@ -348,6 +352,8 @@ private: float _yawFromTouch; float _pitchFromTouch; + float _groundPlaneImpact; + VoxelDetail _mouseVoxelDragging; glm::vec3 _voxelThrust; bool _mousePressed; // true if mouse has been pressed (clear when finished) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 4c707de938..41090584f3 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -76,9 +76,12 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o NodeList* nodeList = NodeList::getInstance(); Application* interface = Application::getInstance(); Avatar* interfaceAvatar = interface->getAvatar(); - + + memset(outputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); + memset(outputRight, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); + // Add Procedural effects to input samples - addProceduralSounds(inputLeft, BUFFER_LENGTH_SAMPLES_PER_CHANNEL); + addProceduralSounds(inputLeft, outputLeft, outputRight, BUFFER_LENGTH_SAMPLES_PER_CHANNEL); if (nodeList && inputLeft) { @@ -135,12 +138,8 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o + leadingBytes); } - } - - memset(outputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); - memset(outputRight, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); - + AudioRingBuffer* ringBuffer = &_ringBuffer; // if there is anything in the ring buffer, decide what to do: @@ -251,11 +250,11 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o } } #ifndef TEST_AUDIO_LOOPBACK - outputLeft[s] = leftSample; - outputRight[s] = rightSample; + outputLeft[s] += leftSample; + outputRight[s] += rightSample; #else - outputLeft[s] = inputLeft[s]; - outputRight[s] = inputLeft[s]; + outputLeft[s] += inputLeft[s]; + outputRight[s] += inputLeft[s]; #endif } ringBuffer->setNextOutput(ringBuffer->getNextOutput() + PACKET_LENGTH_SAMPLES); @@ -333,7 +332,13 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) : _lastYawMeasuredMaximum(0), _flangeIntensity(0.0f), _flangeRate(0.0f), - _flangeWeight(0.0f) + _flangeWeight(0.0f), + _collisionSoundMagnitude(0.0f), + _collisionSoundFrequency(0.0f), + _collisionSoundNoise(0.0f), + _collisionSoundDuration(0.0f), + _proceduralEffectSample(0), + _heartbeatMagnitude(0.0f) { outputPortAudioError(Pa_Initialize()); @@ -589,7 +594,10 @@ void Audio::lowPassFilter(int16_t* inputBuffer) { } // Take a pointer to the acquired microphone input samples and add procedural sounds -void Audio::addProceduralSounds(int16_t* inputBuffer, int numSamples) { +void Audio::addProceduralSounds(int16_t* inputBuffer, + int16_t* outputLeft, + int16_t* outputRight, + int numSamples) { const float MAX_AUDIBLE_VELOCITY = 6.0; const float MIN_AUDIBLE_VELOCITY = 0.1; const int VOLUME_BASELINE = 400; @@ -598,14 +606,48 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, int numSamples) { float speed = glm::length(_lastVelocity); float volume = VOLUME_BASELINE * (1.f - speed / MAX_AUDIBLE_VELOCITY); + int sample; + + // + // Travelling noise + // // Add a noise-modulated sinewave with volume that tapers off with speed increasing if ((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { for (int i = 0; i < numSamples; i++) { - inputBuffer[i] += (int16_t)((sinf((float) i / SOUND_PITCH * speed) * randFloat()) * volume * speed); + inputBuffer[i] += (int16_t)(sinf((float) (_proceduralEffectSample + i) / SOUND_PITCH ) * volume * (1.f + randFloat() * 0.25f) * speed); } } + const float COLLISION_SOUND_CUTOFF_LEVEL = 0.01f; + const float COLLISION_SOUND_MAX_VOLUME = 1000.f; + const float UP_MAJOR_FIFTH = powf(1.5f, 4.0f); + const float DOWN_TWO_OCTAVES = 4.f; + const float DOWN_FOUR_OCTAVES = 16.f; + float t; + if (_collisionSoundMagnitude > COLLISION_SOUND_CUTOFF_LEVEL) { + for (int i = 0; i < numSamples; i++) { + t = (float) _proceduralEffectSample + (float) i; + sample = sinf(t * _collisionSoundFrequency) + + sinf(t * _collisionSoundFrequency / DOWN_TWO_OCTAVES) + + sinf(t * _collisionSoundFrequency / DOWN_FOUR_OCTAVES * UP_MAJOR_FIFTH); + sample *= _collisionSoundMagnitude * COLLISION_SOUND_MAX_VOLUME; + inputBuffer[i] += sample; + outputLeft[i] += sample; + outputRight[i] += sample; + _collisionSoundMagnitude *= _collisionSoundDuration; + } + } + _proceduralEffectSample += numSamples; } +// +// Starts a collision sound. magnitude is 0-1, with 1 the loudest possible sound. +// +void Audio::startCollisionSound(float magnitude, float frequency, float noise, float duration) { + _collisionSoundMagnitude = magnitude; + _collisionSoundFrequency = frequency; + _collisionSoundNoise = noise; + _collisionSoundDuration = duration; +} // ----------------------------------------------------------- // Accoustic ping (audio system round trip time determination) // ----------------------------------------------------------- diff --git a/interface/src/Audio.h b/interface/src/Audio.h index d11a14444a..37db447381 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -42,7 +42,11 @@ public: int getJitterBufferSamples() { return _jitterBufferSamples; }; void lowPassFilter(int16_t* inputBuffer); - + + void startCollisionSound(float magnitude, float frequency, float noise, float duration); + float getCollisionSoundMagnitude() { return _collisionSoundMagnitude; }; + + void ping(); // Call periodically to eventually perform round trip time analysis, @@ -80,7 +84,13 @@ private: float _flangeIntensity; float _flangeRate; float _flangeWeight; - + float _collisionSoundMagnitude; + float _collisionSoundFrequency; + float _collisionSoundNoise; + float _collisionSoundDuration; + int _proceduralEffectSample; + float _heartbeatMagnitude; + // Audio callback in class context. inline void performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* outputRight); @@ -92,7 +102,7 @@ private: inline void analyzePing(); // Add sounds that we want the user to not hear themselves, by adding on top of mic input signal - void addProceduralSounds(int16_t* inputBuffer, int numSamples); + void addProceduralSounds(int16_t* inputBuffer, int16_t* outputLeft, int16_t* outputRight, int numSamples); // Audio callback called by portaudio. Calls 'performIO'. diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 15ef875c75..e92394af22 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -546,8 +546,8 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { _position += _scale * _gravity * (GRAVITY_EARTH * deltaTime) * deltaTime; } - updateCollisionWithEnvironment(); - updateCollisionWithVoxels(); + updateCollisionWithEnvironment(deltaTime); + updateCollisionWithVoxels(deltaTime); updateAvatarCollisions(deltaTime); } @@ -874,29 +874,41 @@ void Avatar::updateCollisionWithSphere(glm::vec3 position, float radius, float d } } -void Avatar::updateCollisionWithEnvironment() { +void Avatar::updateCollisionWithEnvironment(float deltaTime) { glm::vec3 up = getBodyUpDirection(); float radius = _height * 0.125f; const float ENVIRONMENT_SURFACE_ELASTICITY = 1.0f; const float ENVIRONMENT_SURFACE_DAMPING = 0.01; + const float ENVIRONMENT_COLLISION_FREQUENCY = 0.05f; + const float VISIBLE_GROUND_COLLISION_VELOCITY = 0.2f; glm::vec3 penetration; if (Application::getInstance()->getEnvironment()->findCapsulePenetration( _position - up * (_pelvisFloatingHeight - radius), _position + up * (_height - _pelvisFloatingHeight - radius), radius, penetration)) { + float velocityTowardCollision = glm::dot(_velocity, glm::normalize(penetration)); + if (velocityTowardCollision > VISIBLE_GROUND_COLLISION_VELOCITY) { + Application::getInstance()->setGroundPlaneImpact(1.0f); + } + updateCollisionSound(penetration, deltaTime, ENVIRONMENT_COLLISION_FREQUENCY); + applyHardCollision(penetration, ENVIRONMENT_SURFACE_ELASTICITY, ENVIRONMENT_SURFACE_DAMPING); + + } } -void Avatar::updateCollisionWithVoxels() { +void Avatar::updateCollisionWithVoxels(float deltaTime) { float radius = _height * 0.125f; const float VOXEL_ELASTICITY = 1.4f; const float VOXEL_DAMPING = 0.0; + const float VOXEL_COLLISION_FREQUENCY = 0.5f; glm::vec3 penetration; if (Application::getInstance()->getVoxels()->findCapsulePenetration( _position - glm::vec3(0.0f, _pelvisFloatingHeight - radius, 0.0f), _position + glm::vec3(0.0f, _height - _pelvisFloatingHeight - radius, 0.0f), radius, penetration)) { + updateCollisionSound(penetration, deltaTime, VOXEL_COLLISION_FREQUENCY); applyHardCollision(penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); } } @@ -925,6 +937,36 @@ void Avatar::applyHardCollision(const glm::vec3& penetration, float elasticity, } } +void Avatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTime, float frequency) { + // consider whether to have the collision make a sound + const float AUDIBLE_COLLISION_THRESHOLD = 0.02f; + const float COLLISION_LOUDNESS = 1.f; + const float DURATION_SCALING = 0.004f; + const float NOISE_SCALING = 0.1f; + glm::vec3 velocity = _velocity; + glm::vec3 gravity = getGravity(); + + if (glm::length(gravity) > EPSILON) { + // If gravity is on, remove the effect of gravity on velocity for this + // frame, so that we are not constantly colliding with the surface + velocity -= _scale * glm::length(gravity) * GRAVITY_EARTH * deltaTime * glm::normalize(gravity); + } + float velocityTowardCollision = glm::dot(velocity, glm::normalize(penetration)); + float velocityTangentToCollision = glm::length(velocity) - velocityTowardCollision; + + if (velocityTowardCollision > AUDIBLE_COLLISION_THRESHOLD) { + // Volume is proportional to collision velocity + // Base frequency is modified upward by the angle of the collision + // Noise is a function of the angle of collision + // Duration of the sound is a function of both base frequency and velocity of impact + Application::getInstance()->getAudio()->startCollisionSound( + fmin(COLLISION_LOUDNESS * velocityTowardCollision, 1.f), + frequency * (1.f + velocityTangentToCollision / velocityTowardCollision), + fmin(velocityTangentToCollision / velocityTowardCollision * NOISE_SCALING, 1.f), + 1.f - DURATION_SCALING * powf(frequency, 0.5f) / velocityTowardCollision); + } +} + void Avatar::updateAvatarCollisions(float deltaTime) { // Reset detector for nearest avatar diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index f41094173c..61207a2d8b 100755 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -162,6 +162,8 @@ public: glm::quat getOrientation () const; glm::quat getWorldAlignedOrientation() const; + glm::vec3 getGravity () const { return _gravity; } + glm::vec3 getUprightHeadPosition() const; AvatarVoxelSystem* getVoxels() { return &_voxels; } @@ -262,9 +264,10 @@ private: void updateAvatarCollisions(float deltaTime); void updateArmIKAndConstraints( float deltaTime ); void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime ); - void updateCollisionWithEnvironment(); - void updateCollisionWithVoxels(); + void updateCollisionWithEnvironment(float deltaTime); + void updateCollisionWithVoxels(float deltaTime); void applyHardCollision(const glm::vec3& penetration, float elasticity, float damping); + void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); void applyCollisionWithOtherAvatar( Avatar * other, float deltaTime ); void checkForMouseRayTouching(); }; diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index 131e0968cc..84ae9fffe9 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -227,7 +227,8 @@ void Head::simulate(float deltaTime, bool isMine) { const float CAMERA_FOLLOW_HEAD_RATE_MAX = 0.5f; const float CAMERA_FOLLOW_HEAD_RATE_RAMP_RATE = 1.05f; const float CAMERA_STOP_TOLERANCE_DEGREES = 0.1f; - const float CAMERA_START_TOLERANCE_DEGREES = 2.0f; + const float CAMERA_PITCH_START_TOLERANCE_DEGREES = 10.0f; + const float CAMERA_YAW_START_TOLERANCE_DEGREES = 3.0f; float cameraHeadAngleDifference = glm::length(glm::vec2(_pitch - _cameraPitch, _yaw - _cameraYaw)); if (_isCameraMoving) { _cameraFollowHeadRate = glm::clamp(_cameraFollowHeadRate * CAMERA_FOLLOW_HEAD_RATE_RAMP_RATE, @@ -240,7 +241,8 @@ void Head::simulate(float deltaTime, bool isMine) { _isCameraMoving = false; } } else { - if (cameraHeadAngleDifference > CAMERA_START_TOLERANCE_DEGREES) { + if ((fabs(_pitch - _cameraPitch) > CAMERA_PITCH_START_TOLERANCE_DEGREES) || + (fabs(_yaw - _cameraYaw) > CAMERA_YAW_START_TOLERANCE_DEGREES)) { _isCameraMoving = true; _cameraFollowHeadRate = CAMERA_FOLLOW_HEAD_RATE_START; } diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 20f33f924a..6aff15240e 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -325,22 +325,38 @@ void drawvec3(int x, int y, float scale, float rotate, float thick, int mono, gl glPopMatrix(); } +void renderCollisionOverlay(int width, int height, float magnitude) { + const float MIN_VISIBLE_COLLISION = 0.01f; + if (magnitude > MIN_VISIBLE_COLLISION) { + glColor4f(0, 0, 0, magnitude); + glBegin(GL_QUADS); + glVertex2f(0, 0); + glVertex2d(width, 0); + glVertex2d(width, height); + glVertex2d(0, height); + glEnd(); + } +} -void drawGroundPlaneGrid(float size) { - glColor3f(0.4f, 0.5f, 0.3f); +void renderGroundPlaneGrid(float size, float impact) { glLineWidth(2.0); - + glm::vec4 impactColor(1, 0, 0, 1); + glm::vec3 lineColor(0.4, 0.5, 0.3); + glm::vec4 surfaceColor(0.5, 0.5, 0.5, 0.4); + + glColor3fv(&lineColor.x); for (float x = 0; x <= size; x++) { glBegin(GL_LINES); - glVertex3f(x, 0.0f, 0); - glVertex3f(x, 0.0f, size); - glVertex3f(0, 0.0f, x); - glVertex3f(size, 0.0f, x); + glVertex3f(x, 0, 0); + glVertex3f(x, 0, size); + glVertex3f(0, 0, x); + glVertex3f(size, 0, x); glEnd(); } - // Draw a translucent quad just underneath the grid. - glColor4f(0.5, 0.5, 0.5, 0.4); + // Draw the floor, colored for recent impact + glm::vec4 floorColor = impact * impactColor + (1.f - impact) * surfaceColor; + glColor4fv(&floorColor.x); glBegin(GL_QUADS); glVertex3f(0, 0, 0); glVertex3f(size, 0, 0); diff --git a/interface/src/Util.h b/interface/src/Util.h index 37bd0595ec..8bc77a98ea 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -57,7 +57,10 @@ glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha); double diffclock(timeval *clock1,timeval *clock2); -void drawGroundPlaneGrid(float size); +void renderGroundPlaneGrid(float size, float impact); + +void renderCollisionOverlay(int width, int height, float magnitude); + void renderDiskShadow(glm::vec3 position, glm::vec3 upDirection, float radius, float darkness); From c33e4fe6f7860d70033c8e25587bbf931571dee5 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 17 Jul 2013 10:15:42 -0700 Subject: [PATCH 12/17] file mode reverts --- interface/src/Avatar.cpp | 0 interface/src/LeapManager.cpp | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 interface/src/Avatar.cpp mode change 100644 => 100755 interface/src/LeapManager.cpp diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp old mode 100644 new mode 100755 diff --git a/interface/src/LeapManager.cpp b/interface/src/LeapManager.cpp old mode 100644 new mode 100755 From a501659083610b29673c30172a09c229571566a2 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 17 Jul 2013 10:16:30 -0700 Subject: [PATCH 13/17] change mode of HandData to 644 --- libraries/avatars/src/HandData.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 libraries/avatars/src/HandData.cpp diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp old mode 100755 new mode 100644 From 2147a823986c8f7c89271a99b07ae667bc748da3 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 17 Jul 2013 10:16:45 -0700 Subject: [PATCH 14/17] change mode of HandData.cpp to 755 --- libraries/avatars/src/HandData.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 libraries/avatars/src/HandData.cpp diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp old mode 100644 new mode 100755 From 1aa06116c244f30e9f318bb4798f8ed43ede6ed5 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 17 Jul 2013 10:17:12 -0700 Subject: [PATCH 15/17] change mode of HandData.h to 755 --- libraries/avatars/src/HandData.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 libraries/avatars/src/HandData.h diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h old mode 100644 new mode 100755 From 9e9b379d66c357cfdd58d77c8a0ddaefb733ae8c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 17 Jul 2013 11:49:42 -0700 Subject: [PATCH 16/17] Fix crashing bug in voxel-server related to animation - added VoxelNodeDeleteHook mechanism that allows users of VoxelNode to register for delete notification call backs - added call back to VoxelNodeBag to remove and nodes from bags when the nodes get deleted. --- libraries/voxels/src/VoxelNode.cpp | 43 +++++++++++++++++++++ libraries/voxels/src/VoxelNode.h | 55 +++++++++++++++++---------- libraries/voxels/src/VoxelNodeBag.cpp | 14 +++++++ libraries/voxels/src/VoxelNodeBag.h | 9 ++--- voxel-server/src/main.cpp | 1 - 5 files changed, 95 insertions(+), 27 deletions(-) diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 76fae500dd..1268449ac6 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -54,6 +54,8 @@ void VoxelNode::init(unsigned char * octalCode) { } VoxelNode::~VoxelNode() { + notifyDeleteHooks(); + delete[] _octalCode; // delete all of this node's children @@ -387,3 +389,44 @@ float VoxelNode::distanceToPoint(const glm::vec3& point) const { float distance = sqrtf(glm::dot(temp, temp)); return distance; } + +VoxelNodeDeleteHook VoxelNode::_hooks[VOXEL_NODE_MAX_DELETE_HOOKS]; +void* VoxelNode::_hooksExtraData[VOXEL_NODE_MAX_DELETE_HOOKS]; +int VoxelNode::_hooksInUse = 0; + +int VoxelNode::addDeleteHook(VoxelNodeDeleteHook hook, void* extraData) { + // If first use, initialize the _hooks array + if (_hooksInUse == 0) { + memset(_hooks, 0, sizeof(_hooks)); + memset(_hooksExtraData, 0, sizeof(_hooksExtraData)); + } + // find first available slot + for (int i = 0; i < VOXEL_NODE_MAX_DELETE_HOOKS; i++) { + if (!_hooks[i]) { + _hooks[i] = hook; + _hooksExtraData[i] = extraData; + _hooksInUse++; + return i; + } + } + // if we got here, then we're out of room in our hooks, return error + return VOXEL_NODE_NO_MORE_HOOKS_AVAILABLE; +} + +void VoxelNode::removeDeleteHook(int hookID) { + if (_hooks[hookID]) { + _hooks[hookID] = NULL; + _hooksExtraData[hookID] = NULL; + _hooksInUse--; + } +} + +void VoxelNode::notifyDeleteHooks() { + if (_hooksInUse > 0) { + for (int i = 0; i < VOXEL_NODE_MAX_DELETE_HOOKS; i++) { + if (_hooks[i]) { + _hooks[i](this, _hooksExtraData[i]); + } + } + } +} diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 8e3b9cb5db..431592c2f9 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -15,33 +15,19 @@ #include "VoxelConstants.h" class VoxelTree; // forward delclaration +class VoxelNode; // forward delclaration typedef unsigned char colorPart; typedef unsigned char nodeColor[4]; typedef unsigned char rgbColor[3]; +// Callback function, for delete hook +typedef void (*VoxelNodeDeleteHook)(VoxelNode* node, void* extraData); +const int VOXEL_NODE_MAX_DELETE_HOOKS = 100; +const int VOXEL_NODE_NO_MORE_HOOKS_AVAILABLE = -1; + + class VoxelNode { -private: - nodeColor _trueColor; -#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color - nodeColor _currentColor; - bool _falseColored; -#endif - glBufferIndex _glBufferIndex; - bool _isDirty; - uint64_t _lastChanged; - bool _shouldRender; - bool _isStagedForDeletion; - AABox _box; - unsigned char* _octalCode; - VoxelNode* _children[8]; - int _childCount; - float _density; // If leaf: density = 1, if internal node: 0-1 density of voxels inside - - void calculateAABox(); - - void init(unsigned char * octalCode); - public: VoxelNode(); // root node constructor VoxelNode(unsigned char * octalCode); // regular constructor @@ -118,6 +104,33 @@ public: const nodeColor& getTrueColor() const { return _trueColor; }; const nodeColor& getColor() const { return _trueColor; }; #endif + + static int addDeleteHook(VoxelNodeDeleteHook hook, void* extraData = NULL); + static void removeDeleteHook(int hookID); +private: + void calculateAABox(); + void init(unsigned char * octalCode); + void notifyDeleteHooks(); + + nodeColor _trueColor; +#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color + nodeColor _currentColor; + bool _falseColored; +#endif + glBufferIndex _glBufferIndex; + bool _isDirty; + uint64_t _lastChanged; + bool _shouldRender; + bool _isStagedForDeletion; + AABox _box; + unsigned char* _octalCode; + VoxelNode* _children[8]; + int _childCount; + float _density; // If leaf: density = 1, if internal node: 0-1 density of voxels inside + + static VoxelNodeDeleteHook _hooks[VOXEL_NODE_MAX_DELETE_HOOKS]; + static void* _hooksExtraData[VOXEL_NODE_MAX_DELETE_HOOKS]; + static int _hooksInUse; }; #endif /* defined(__hifi__VoxelNode__) */ diff --git a/libraries/voxels/src/VoxelNodeBag.cpp b/libraries/voxels/src/VoxelNodeBag.cpp index 20a469dec8..4f355116e4 100644 --- a/libraries/voxels/src/VoxelNodeBag.cpp +++ b/libraries/voxels/src/VoxelNodeBag.cpp @@ -9,7 +9,15 @@ #include "VoxelNodeBag.h" #include +VoxelNodeBag::VoxelNodeBag() : + _bagElements(NULL), + _elementsInUse(0), + _sizeOfElementsArray(0) { + _hookID = VoxelNode::addDeleteHook(voxelNodeDeleteHook, (void*)this); +}; + VoxelNodeBag::~VoxelNodeBag() { + VoxelNode::removeDeleteHook(_hookID); deleteAll(); } @@ -118,3 +126,9 @@ void VoxelNodeBag::remove(VoxelNode* node) { } } +void VoxelNodeBag::voxelNodeDeleteHook(VoxelNode* node, void* extraData) { + VoxelNodeBag* theBag = (VoxelNodeBag*)extraData; + theBag->remove(node); // note: remove can safely handle nodes that aren't in it, so we don't need to check contains() +} + + diff --git a/libraries/voxels/src/VoxelNodeBag.h b/libraries/voxels/src/VoxelNodeBag.h index ee6e5045d0..27bd4e5b60 100644 --- a/libraries/voxels/src/VoxelNodeBag.h +++ b/libraries/voxels/src/VoxelNodeBag.h @@ -19,11 +19,7 @@ class VoxelNodeBag { public: - VoxelNodeBag() : - _bagElements(NULL), - _elementsInUse(0), - _sizeOfElementsArray(0) {}; - + VoxelNodeBag(); ~VoxelNodeBag(); void insert(VoxelNode* node); // put a node into the bag @@ -36,11 +32,14 @@ public: void deleteAll(); + static void voxelNodeDeleteHook(VoxelNode* node, void* extraData); + private: VoxelNode** _bagElements; int _elementsInUse; int _sizeOfElementsArray; + int _hookID; }; #endif /* defined(__hifi__VoxelNodeBag__) */ diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 5f5befafa6..f171d9b168 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -384,7 +384,6 @@ void attachVoxelNodeDataToNode(Node* newNode) { } int main(int argc, const char * argv[]) { - pthread_mutex_init(&::treeLock, NULL); qInstallMsgHandler(sharedMessageHandler); From 74eaf72d5301036714d1831ad13e5e6d64dc9d98 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 17 Jul 2013 11:52:50 -0700 Subject: [PATCH 17/17] removed bogus code that related to server crash --- libraries/voxels/src/VoxelTree.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 6ef9f293ee..91a31a6cd1 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1011,12 +1011,6 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, unsigned char* outputBuffer, // How many bytes have we written so far at this level; int bytesWritten = 0; - // These two cases should not ever happen... but if they do, we don't want to crash. - if (!node || !node->getOctalCode()) { - qDebug("VoxelTree::encodeTreeBitstream() BAD VoxelNode! Bailing!"); - return bytesWritten; - } - // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! if (params.viewFrustum && !node->isInView(*params.viewFrustum)) { return bytesWritten;