From e6b751e53840b2caad5203b4068146a2866c41a4 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Fri, 12 Jul 2013 14:32:14 -0700 Subject: [PATCH 01/20] 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/20] 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/20] 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/20] 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 8b9e0426b24e6ec01ca53b9ec75683aadbb8fbcc Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 12 Jul 2013 21:34:48 -0700 Subject: [PATCH 05/20] Simple glassy collision sound --- interface/src/Application.h | 1 + interface/src/Audio.cpp | 25 ++++++++++++++++++++++--- interface/src/Audio.h | 6 +++++- interface/src/Avatar.cpp | 8 ++++++++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.h b/interface/src/Application.h index c6bbd4eec2..9e8e359479 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -84,6 +84,7 @@ public: const glm::vec3 getMouseVoxelWorldCoordinates(const VoxelDetail _mouseVoxel); Avatar* getAvatar() { return &_myAvatar; } + Audio* getAudio() { return &_audio; } Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } VoxelSystem* getVoxels() { return &_voxels; } diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 7af42478d5..540e7b1e1e 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -326,7 +326,9 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) : _lastYawMeasuredMaximum(0), _flangeIntensity(0.0f), _flangeRate(0.0f), - _flangeWeight(0.0f) + _flangeWeight(0.0f), + _collisionSoundMagnitude(0.0f), + _proceduralEffectSample(0) { outputPortAudioError(Pa_Initialize()); @@ -591,12 +593,29 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, int numSamples) { float speed = glm::length(_lastVelocity); float volume = VOLUME_BASELINE * (1.f - speed / MAX_AUDIBLE_VELOCITY); + // Test tone (should be continuous!) + /* + for (int i = 0; i < numSamples; i++) { + inputBuffer[i] += (int16_t) (_proceduralEffectSample + i)%16 * 10; + }*/ + // Add a noise-modulated sinewave with volume that tapers off with speed increasing - if ((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { + if (0) { //((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 * speed) * (1.f + randFloat() * 0.0f)) * volume * speed); } } + const float COLLISION_SOUND_CUTOFF_LEVEL = 5.0f; + const float COLLISION_SOUND_PITCH_1 = 2.0f; + const float COLLISION_SOUND_DECAY = 1.f/1024.f; + const float COLLISION_VOLUME_BASELINE = 10.f; + if (_collisionSoundMagnitude > COLLISION_SOUND_CUTOFF_LEVEL) { + for (int i = 0; i < numSamples; i++) { + inputBuffer[i] += (int16_t) ((sinf((float) (_proceduralEffectSample + i) / COLLISION_SOUND_PITCH_1) * COLLISION_VOLUME_BASELINE * _collisionSoundMagnitude)); + _collisionSoundMagnitude *= (1.f - COLLISION_SOUND_DECAY); + } + } + _proceduralEffectSample += numSamples; } // ----------------------------------------------------------- diff --git a/interface/src/Audio.h b/interface/src/Audio.h index a3c8cf1046..78b298644b 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -44,6 +44,8 @@ public: void lowPassFilter(int16_t* inputBuffer); + void setCollisionSoundMagnitude(float collisionSoundMagnitude) { _collisionSoundMagnitude = collisionSoundMagnitude; } + void ping(); // Call periodically to eventually perform round trip time analysis, @@ -81,7 +83,9 @@ private: float _flangeIntensity; float _flangeRate; float _flangeWeight; - + float _collisionSoundMagnitude; + int _proceduralEffectSample; + // Audio callback in class context. inline void performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* outputRight); diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 881b436bf2..7d306b307a 100755 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -873,6 +873,7 @@ void Avatar::updateCollisionWithEnvironment() { _position - up * (_pelvisFloatingHeight - radius), _position + up * (_height - _pelvisFloatingHeight - radius), radius, penetration)) { applyHardCollision(penetration, ENVIRONMENT_SURFACE_ELASTICITY, ENVIRONMENT_SURFACE_DAMPING); + } } @@ -910,6 +911,13 @@ void Avatar::applyHardCollision(const glm::vec3& penetration, float elasticity, // If moving really slowly after a collision, and not applying forces, stop altogether _velocity *= 0.f; } + // Push the collision into the audio system for procedural effects + const float AUDIBLE_COLLISION_THRESHOLD = 200.f; + const float COLLISION_VOLUME = 10000.f; + float collisionSoundLevel = penetrationLength * COLLISION_VOLUME; + if (collisionSoundLevel > AUDIBLE_COLLISION_THRESHOLD) { + Application::getInstance()->getAudio()->setCollisionSoundMagnitude(collisionSoundLevel); + } } } From 84b6adf5b05f5a725fa04371002579dc4febd5f0 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 15 Jul 2013 13:57:39 -0700 Subject: [PATCH 06/20] 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 07/20] 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 f8f6b295597bc0a747b6c0cc62d22932ed3e0d7b Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 15 Jul 2013 14:24:21 -0700 Subject: [PATCH 08/20] Audio collision sounds are played locally as well as injected --- interface/src/Audio.cpp | 39 ++++++++++++++++++++++++--------------- interface/src/Audio.h | 2 +- interface/src/Head.cpp | 6 ++++-- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 540e7b1e1e..a724f7b288 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -75,9 +75,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) { @@ -129,12 +132,8 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o interface->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO) .updateValue(BUFFER_LENGTH_BYTES_PER_CHANNEL + 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: @@ -245,11 +244,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); @@ -584,7 +583,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; @@ -600,18 +602,25 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, int numSamples) { }*/ // Add a noise-modulated sinewave with volume that tapers off with speed increasing - if (0) { //((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { + if ((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { for (int i = 0; i < numSamples; i++) { - inputBuffer[i] += (int16_t)((sinf((float) (_proceduralEffectSample + i) / SOUND_PITCH * speed) * (1.f + randFloat() * 0.0f)) * volume * speed); + //inputBuffer[i] += (int16_t)((sinf((float) (_proceduralEffectSample + i) / SOUND_PITCH * speed) * (1.f + randFloat() * 0.0f)) * 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 = 5.0f; const float COLLISION_SOUND_PITCH_1 = 2.0f; const float COLLISION_SOUND_DECAY = 1.f/1024.f; const float COLLISION_VOLUME_BASELINE = 10.f; + int sample; if (_collisionSoundMagnitude > COLLISION_SOUND_CUTOFF_LEVEL) { for (int i = 0; i < numSamples; i++) { - inputBuffer[i] += (int16_t) ((sinf((float) (_proceduralEffectSample + i) / COLLISION_SOUND_PITCH_1) * COLLISION_VOLUME_BASELINE * _collisionSoundMagnitude)); + sample = (int16_t) ((sinf((float) (_proceduralEffectSample + i) / COLLISION_SOUND_PITCH_1) * COLLISION_VOLUME_BASELINE * _collisionSoundMagnitude)); + inputBuffer[i] += sample; + outputLeft[i] += sample; + outputRight[i] += sample; _collisionSoundMagnitude *= (1.f - COLLISION_SOUND_DECAY); } } diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 78b298644b..715cfeafc8 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -97,7 +97,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/Head.cpp b/interface/src/Head.cpp index 44d62e695d..18141bc2b4 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; } From c0f319f077f4bec5a40a3780521f57a2cc23fd52 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 15 Jul 2013 14:36:11 -0700 Subject: [PATCH 09/20] 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 10/20] 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 26c0eb2dea0556bf0bd011d08a0c576d429b3c3e Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 15 Jul 2013 16:27:46 -0700 Subject: [PATCH 11/20] Start to add heartbeat --- interface/src/Audio.cpp | 10 +++++++++- interface/src/Audio.h | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index a724f7b288..a2b3f08535 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -327,7 +327,8 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) : _flangeRate(0.0f), _flangeWeight(0.0f), _collisionSoundMagnitude(0.0f), - _proceduralEffectSample(0) + _proceduralEffectSample(0), + _heartbeatMagnitude(0.0f) { outputPortAudioError(Pa_Initialize()); @@ -601,6 +602,9 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, inputBuffer[i] += (int16_t) (_proceduralEffectSample + i)%16 * 10; }*/ + // + // 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++) { @@ -624,6 +628,10 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, _collisionSoundMagnitude *= (1.f - COLLISION_SOUND_DECAY); } } + + //if (_heartbeatMagnitude > 0.0f) { + // + //} _proceduralEffectSample += numSamples; } diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 715cfeafc8..1ab671a30b 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -85,6 +85,7 @@ private: float _flangeWeight; float _collisionSoundMagnitude; int _proceduralEffectSample; + float _heartbeatMagnitude; // Audio callback in class context. inline void performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* outputRight); From 0481a81ca7639127b494267a71e0fbba93f20588 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 15 Jul 2013 17:58:17 -0700 Subject: [PATCH 12/20] 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 edf031b98566e73efe3dee0499e26bce90193c81 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 15 Jul 2013 22:42:55 -0700 Subject: [PATCH 13/20] improve collision sounds, difference between ground and voxels --- interface/src/Audio.cpp | 18 +++++++++++++----- interface/src/Audio.h | 5 +++++ interface/src/Avatar.cpp | 34 +++++++++++++++++++++++++++------- interface/src/Avatar.h | 1 + 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 1e04e563a2..8b2856a7c9 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -333,6 +333,9 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) : _flangeRate(0.0f), _flangeWeight(0.0f), _collisionSoundMagnitude(0.0f), + _collisionSoundFrequency(0.0f), + _collisionSoundNoise(0.0f), + _collisionSoundDuration(0.0f), _proceduralEffectSample(0), _heartbeatMagnitude(0.0f) { @@ -621,17 +624,16 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, } } const float COLLISION_SOUND_CUTOFF_LEVEL = 5.0f; - const float COLLISION_SOUND_PITCH_1 = 2.0f; - const float COLLISION_SOUND_DECAY = 1.f/1024.f; - const float COLLISION_VOLUME_BASELINE = 10.f; int sample; if (_collisionSoundMagnitude > COLLISION_SOUND_CUTOFF_LEVEL) { for (int i = 0; i < numSamples; i++) { - sample = (int16_t) ((sinf((float) (_proceduralEffectSample + i) / COLLISION_SOUND_PITCH_1) * COLLISION_VOLUME_BASELINE * _collisionSoundMagnitude)); + sample = (int16_t) (((sinf(((float)_proceduralEffectSample + (float)i) * _collisionSoundFrequency) * (1.f - _collisionSoundNoise) + + ((randFloat() * 2.f - 1.0f) * _collisionSoundNoise)) + * _collisionSoundMagnitude)); inputBuffer[i] += sample; outputLeft[i] += sample; outputRight[i] += sample; - _collisionSoundMagnitude *= (1.f - COLLISION_SOUND_DECAY); + _collisionSoundMagnitude *= _collisionSoundDuration; } } @@ -641,6 +643,12 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, _proceduralEffectSample += numSamples; } +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 1ab671a30b..a43e05e3ec 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -46,6 +46,8 @@ public: void setCollisionSoundMagnitude(float collisionSoundMagnitude) { _collisionSoundMagnitude = collisionSoundMagnitude; } + void startCollisionSound(float magnitude, float frequency, float noise, float duration); + void ping(); // Call periodically to eventually perform round trip time analysis, @@ -84,6 +86,9 @@ private: float _flangeRate; float _flangeWeight; float _collisionSoundMagnitude; + float _collisionSoundFrequency; + float _collisionSoundNoise; + float _collisionSoundDuration; int _proceduralEffectSample; float _heartbeatMagnitude; diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 289d5548c4..b3868f6ea7 100755 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -873,12 +873,15 @@ void Avatar::updateCollisionWithEnvironment() { 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; glm::vec3 penetration; if (Application::getInstance()->getEnvironment()->findCapsulePenetration( _position - up * (_pelvisFloatingHeight - radius), _position + up * (_height - _pelvisFloatingHeight - radius), radius, penetration)) { + createCollisionSound(penetration, ENVIRONMENT_COLLISION_FREQUENCY); applyHardCollision(penetration, ENVIRONMENT_SURFACE_ELASTICITY, ENVIRONMENT_SURFACE_DAMPING); + } } @@ -887,10 +890,12 @@ void Avatar::updateCollisionWithVoxels() { 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)) { + createCollisionSound(penetration, VOXEL_COLLISION_FREQUENCY); applyHardCollision(penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); } } @@ -916,16 +921,31 @@ void Avatar::applyHardCollision(const glm::vec3& penetration, float elasticity, // If moving really slowly after a collision, and not applying forces, stop altogether _velocity *= 0.f; } - // Push the collision into the audio system for procedural effects - const float AUDIBLE_COLLISION_THRESHOLD = 200.f; - const float COLLISION_VOLUME = 10000.f; - float collisionSoundLevel = penetrationLength * COLLISION_VOLUME; - if (collisionSoundLevel > AUDIBLE_COLLISION_THRESHOLD) { - Application::getInstance()->getAudio()->setCollisionSoundMagnitude(collisionSoundLevel); - } } } +void Avatar::createCollisionSound(const glm::vec3 &penetration, float frequency) { + // Push the collision into the audio system for procedural effects + const float AUDIBLE_COLLISION_THRESHOLD = 0.2f; + const float COLLISION_VOLUME = 1000.f; + const float MAX_COLLISION_VOLUME = 15000.f; + const float DURATION_SCALING = 0.004f; + float velocityTowardCollision = glm::dot(_velocity, glm::normalize(penetration)); + float velocityTangentToCollision = glm::length(_velocity) - velocityTowardCollision; + if (velocityTowardCollision > AUDIBLE_COLLISION_THRESHOLD) { + Application::getInstance()->getAudio()->startCollisionSound( + fmax(COLLISION_VOLUME * velocityTowardCollision, MAX_COLLISION_VOLUME), + frequency, + fmin(velocityTangentToCollision / velocityTowardCollision, 1.f), + 1.f - DURATION_SCALING * powf(frequency, 0.5f) / velocityTowardCollision); + + } + //float collisionSoundLevel = penetrationLength * COLLISION_VOLUME; + //if (collisionSoundLevel > AUDIBLE_COLLISION_THRESHOLD) { + // Application::getInstance()->getAudio()->setCollisionSoundMagnitude(collisionSoundLevel); + //} +} + void Avatar::updateAvatarCollisions(float deltaTime) { // Reset detector for nearest avatar diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 643a187a67..31c9b573b8 100755 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -262,6 +262,7 @@ private: void updateCollisionWithEnvironment(); void updateCollisionWithVoxels(); void applyHardCollision(const glm::vec3& penetration, float elasticity, float damping); + void createCollisionSound(const glm::vec3& penetration, float frequency); void applyCollisionWithOtherAvatar( Avatar * other, float deltaTime ); void checkForMouseRayTouching(); }; From 192ae637893c3b22a16cbf3a3504595490cae64d Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 16 Jul 2013 16:40:50 -0700 Subject: [PATCH 14/20] Colliding with ground, voxels makes interesting sounds and flashes your display --- interface/src/Application.cpp | 6 +++- interface/src/Application.h | 7 +++- interface/src/Audio.cpp | 30 ++++++++--------- interface/src/Audio.h | 4 +-- interface/src/Avatar.cpp | 61 +++++++++++++++++++++-------------- interface/src/Avatar.h | 8 +++-- interface/src/Util.cpp | 34 +++++++++++++------ interface/src/Util.h | 5 ++- 8 files changed, 97 insertions(+), 58 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 644d5524f0..a2fe2072c6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -188,6 +188,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), @@ -2516,7 +2517,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()) { @@ -2592,6 +2593,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 b46ee20111..cb1896c4de 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -101,6 +101,9 @@ public: QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; } GeometryCache* getGeometryCache() { return &_geometryCache; } + void setGroundPlaneImpact(float groundPlaneImpact) { _groundPlaneImpact = groundPlaneImpact; } + + private slots: void timer(); @@ -206,7 +209,7 @@ private: void deleteVoxelUnderCursor(); void eyedropperVoxelUnderCursor(); void resetSensors(); - + void setMenuShortcutsEnabled(bool enabled); void updateCursor(); @@ -344,6 +347,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 8b2856a7c9..dc36968c3b 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -605,11 +605,7 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, float speed = glm::length(_lastVelocity); float volume = VOLUME_BASELINE * (1.f - speed / MAX_AUDIBLE_VELOCITY); - // Test tone (should be continuous!) - /* - for (int i = 0; i < numSamples; i++) { - inputBuffer[i] += (int16_t) (_proceduralEffectSample + i)%16 * 10; - }*/ + int sample; // // Travelling noise @@ -617,32 +613,32 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, // 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) (_proceduralEffectSample + i) / SOUND_PITCH * speed) * (1.f + randFloat() * 0.0f)) * 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 = 5.0f; - int sample; + 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); + float t; if (_collisionSoundMagnitude > COLLISION_SOUND_CUTOFF_LEVEL) { for (int i = 0; i < numSamples; i++) { - sample = (int16_t) (((sinf(((float)_proceduralEffectSample + (float)i) * _collisionSoundFrequency) * (1.f - _collisionSoundNoise) - + ((randFloat() * 2.f - 1.0f) * _collisionSoundNoise)) - * _collisionSoundMagnitude)); + t = (float) _proceduralEffectSample + (float) i; + sample = sinf(t * _collisionSoundFrequency) + + sinf(t * _collisionSoundFrequency / 4.f) + + sinf(t * _collisionSoundFrequency / 16.f * UP_MAJOR_FIFTH); + sample *= _collisionSoundMagnitude * COLLISION_SOUND_MAX_VOLUME; inputBuffer[i] += sample; outputLeft[i] += sample; outputRight[i] += sample; _collisionSoundMagnitude *= _collisionSoundDuration; } } - - //if (_heartbeatMagnitude > 0.0f) { - // - //} _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; diff --git a/interface/src/Audio.h b/interface/src/Audio.h index a43e05e3ec..5954361444 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -43,10 +43,10 @@ public: int getJitterBufferSamples() { return _jitterBufferSamples; }; void lowPassFilter(int16_t* inputBuffer); - - void setCollisionSoundMagnitude(float collisionSoundMagnitude) { _collisionSoundMagnitude = collisionSoundMagnitude; } void startCollisionSound(float magnitude, float frequency, float noise, float duration); + float getCollisionSoundMagnitude() { return _collisionSoundMagnitude; }; + void ping(); diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index b3868f6ea7..e34a4ff194 100755 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -545,8 +545,8 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { _position += _scale * _gravity * (GRAVITY_EARTH * deltaTime) * deltaTime; } - updateCollisionWithEnvironment(); - updateCollisionWithVoxels(); + updateCollisionWithEnvironment(deltaTime); + updateCollisionWithVoxels(deltaTime); updateAvatarCollisions(deltaTime); } @@ -867,7 +867,7 @@ 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; @@ -878,7 +878,12 @@ void Avatar::updateCollisionWithEnvironment() { if (Application::getInstance()->getEnvironment()->findCapsulePenetration( _position - up * (_pelvisFloatingHeight - radius), _position + up * (_height - _pelvisFloatingHeight - radius), radius, penetration)) { - createCollisionSound(penetration, ENVIRONMENT_COLLISION_FREQUENCY); + float velocityTowardCollision = glm::dot(_velocity, glm::normalize(penetration)); + if (velocityTowardCollision > 0.2) { + Application::getInstance()->setGroundPlaneImpact(1.0f); + } + updateCollisionSound(penetration, deltaTime, ENVIRONMENT_COLLISION_FREQUENCY); + applyHardCollision(penetration, ENVIRONMENT_SURFACE_ELASTICITY, ENVIRONMENT_SURFACE_DAMPING); @@ -886,7 +891,7 @@ void Avatar::updateCollisionWithEnvironment() { } -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; @@ -895,7 +900,7 @@ void Avatar::updateCollisionWithVoxels() { 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)) { - createCollisionSound(penetration, VOXEL_COLLISION_FREQUENCY); + updateCollisionSound(penetration, deltaTime, VOXEL_COLLISION_FREQUENCY); applyHardCollision(penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); } } @@ -924,26 +929,34 @@ void Avatar::applyHardCollision(const glm::vec3& penetration, float elasticity, } } -void Avatar::createCollisionSound(const glm::vec3 &penetration, float frequency) { - // Push the collision into the audio system for procedural effects - const float AUDIBLE_COLLISION_THRESHOLD = 0.2f; - const float COLLISION_VOLUME = 1000.f; - const float MAX_COLLISION_VOLUME = 15000.f; +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; - float velocityTowardCollision = glm::dot(_velocity, glm::normalize(penetration)); - float velocityTangentToCollision = glm::length(_velocity) - velocityTowardCollision; - if (velocityTowardCollision > AUDIBLE_COLLISION_THRESHOLD) { - Application::getInstance()->getAudio()->startCollisionSound( - fmax(COLLISION_VOLUME * velocityTowardCollision, MAX_COLLISION_VOLUME), - frequency, - fmin(velocityTangentToCollision / velocityTowardCollision, 1.f), - 1.f - DURATION_SCALING * powf(frequency, 0.5f) / velocityTowardCollision); - + 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); } - //float collisionSoundLevel = penetrationLength * COLLISION_VOLUME; - //if (collisionSoundLevel > AUDIBLE_COLLISION_THRESHOLD) { - // Application::getInstance()->getAudio()->setCollisionSoundMagnitude(collisionSoundLevel); - //} } void Avatar::updateAvatarCollisions(float deltaTime) { diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 31c9b573b8..fa605fa425 100755 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -159,6 +159,8 @@ public: glm::quat getOrientation () const; glm::quat getWorldAlignedOrientation() const; + glm::vec3 getGravity () const { return _gravity; } + glm::vec3 getUprightHeadPosition() const; AvatarVoxelSystem* getVoxels() { return &_voxels; } @@ -259,10 +261,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 createCollisionSound(const glm::vec3& penetration, float frequency); + void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); void applyCollisionWithOtherAvatar( Avatar * other, float deltaTime ); void checkForMouseRayTouching(); }; diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 65a277b623..ddce092896 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -326,22 +326,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 984332e63804da9c0329c96fcfc301abb0ad6935 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 17 Jul 2013 09:51:04 -0700 Subject: [PATCH 15/20] fixes per review --- interface/src/Audio.cpp | 8 +++++--- interface/src/Avatar.cpp | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 9f82559512..41090584f3 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -620,13 +620,15 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, 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 / 4.f) + - sinf(t * _collisionSoundFrequency / 16.f * UP_MAJOR_FIFTH); + 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; @@ -638,7 +640,7 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, } // -// Starts a collision sound. magnitude is 0-1, with 1 the loudest possible sound. +// 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; diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index ee613f5758..e92394af22 100755 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -881,12 +881,13 @@ void Avatar::updateCollisionWithEnvironment(float deltaTime) { 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 > 0.2) { + if (velocityTowardCollision > VISIBLE_GROUND_COLLISION_VELOCITY) { Application::getInstance()->setGroundPlaneImpact(1.0f); } updateCollisionSound(penetration, deltaTime, ENVIRONMENT_COLLISION_FREQUENCY); From 98dd83dde81b3c53229b662083af7ad3bee2273c Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 17 Jul 2013 10:02:23 -0700 Subject: [PATCH 16/20] 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 17/20] 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 18/20] 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 19/20] 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 20/20] 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