mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 06:44:06 +02:00
Merge pull request #670 from Ventrella/particles
Added more API to the Particle System
This commit is contained in:
commit
1d18252498
6 changed files with 450 additions and 127 deletions
|
@ -178,6 +178,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
_frameCount(0),
|
||||
_fps(120.0f),
|
||||
_justStarted(true),
|
||||
_particleSystemInitialized(false),
|
||||
_coolDemoParticleEmitter(-1),
|
||||
_wantToKillLocalVoxels(false),
|
||||
_frustumDrawingMode(FRUSTUM_DRAW_MODE_ALL),
|
||||
_viewFrustumOffsetYaw(-135.0),
|
||||
|
@ -1867,9 +1869,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;
|
||||
|
@ -2082,6 +2085,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) {
|
||||
|
@ -2130,8 +2135,8 @@ void Application::update(float deltaTime) {
|
|||
#endif
|
||||
|
||||
if (TESTING_PARTICLE_SYSTEM) {
|
||||
_particleSystem.simulate(deltaTime);
|
||||
}
|
||||
updateParticleSystem(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
void Application::updateAvatar(float deltaTime) {
|
||||
|
@ -2580,7 +2585,9 @@ void Application::displaySide(Camera& whichCamera) {
|
|||
}
|
||||
|
||||
if (TESTING_PARTICLE_SYSTEM) {
|
||||
_particleSystem.render();
|
||||
if (_particleSystemInitialized) {
|
||||
_particleSystem.render();
|
||||
}
|
||||
}
|
||||
|
||||
// Render the world box
|
||||
|
@ -3492,3 +3499,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -84,6 +84,8 @@ public:
|
|||
|
||||
const glm::vec3 getMouseVoxelWorldCoordinates(const VoxelDetail _mouseVoxel);
|
||||
|
||||
void updateParticleSystem(float deltaTime);
|
||||
|
||||
Avatar* getAvatar() { return &_myAvatar; }
|
||||
Audio* getAudio() { return &_audio; }
|
||||
Camera* getCamera() { return &_myCamera; }
|
||||
|
@ -290,6 +292,8 @@ private:
|
|||
timeval _timerStart, _timerEnd;
|
||||
timeval _lastTimeUpdated;
|
||||
bool _justStarted;
|
||||
bool _particleSystemInitialized;
|
||||
int _coolDemoParticleEmitter;
|
||||
|
||||
Stars _stars;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -163,3 +173,52 @@ void Hand::setLeapHands(const std::vector<glm::vec3>& 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -15,9 +15,11 @@
|
|||
#include "world.h"
|
||||
#include "InterfaceConfig.h"
|
||||
#include "SerialInterface.h"
|
||||
#include "ParticleSystem.h"
|
||||
#include <SharedUtil.h>
|
||||
#include <vector>
|
||||
|
||||
const int NUM_FINGERS_PER_HAND = 5;
|
||||
|
||||
class Avatar;
|
||||
class ProgramObject;
|
||||
|
@ -46,8 +48,10 @@ public:
|
|||
const std::vector<glm::vec3>& fingerRoots);
|
||||
void setLeapHands (const std::vector<glm::vec3>& handPositions,
|
||||
const std::vector<glm::vec3>& handNormals);
|
||||
void updateFingerParticles(float deltaTime);
|
||||
void setRaveGloveActive(bool active) { _isRaveGloveActive = active; }
|
||||
|
||||
|
||||
// getters
|
||||
const glm::vec3& getLeapBallPosition (int ball) const { return _leapBalls[ball].position;}
|
||||
bool isRaveGloveActive () const { return _isRaveGloveActive; }
|
||||
|
@ -59,6 +63,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;
|
||||
|
@ -69,6 +75,9 @@ private:
|
|||
glm::quat _orientation;
|
||||
std::vector<HandBall> _leapBalls;
|
||||
|
||||
bool _particleSystemInitialized;
|
||||
int _fingerParticleEmitter[NUM_FINGERS_PER_HAND];
|
||||
|
||||
// private methods
|
||||
void renderRaveGloveStage();
|
||||
void renderHandSpheres();
|
||||
|
|
|
@ -8,74 +8,157 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include "InterfaceConfig.h"
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "ParticleSystem.h"
|
||||
#include "Application.h"
|
||||
|
||||
const float DEFAULT_PARTICLE_BOUNCE = 1.0f;
|
||||
const float DEFAULT_PARTICLE_AIR_FRICTION = 2.0f;
|
||||
|
||||
ParticleSystem::ParticleSystem() {
|
||||
|
||||
_numberOfParticles = 1500;
|
||||
assert(_numberOfParticles <= MAX_PARTICLES);
|
||||
_timer = 0.0f;
|
||||
_numEmitters = 0;
|
||||
_numParticles = 0;
|
||||
_upDirection = glm::vec3(0.0f, 1.0f, 0.0f); // default
|
||||
|
||||
for (unsigned int e = 0; e < MAX_EMITTERS; e++) {
|
||||
_emitter[e].position = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
_emitter[e].rotation = glm::quat();
|
||||
_emitter[e].right = IDENTITY_RIGHT;
|
||||
_emitter[e].up = IDENTITY_UP;
|
||||
_emitter[e].front = IDENTITY_FRONT;
|
||||
_emitter[e].showingEmitter = false;
|
||||
_emitter[e].particleAttributes.bounce = DEFAULT_PARTICLE_BOUNCE;
|
||||
_emitter[e].particleAttributes.airFriction = DEFAULT_PARTICLE_AIR_FRICTION;
|
||||
_emitter[e].particleAttributes.gravity = 0.0f;
|
||||
_emitter[e].particleAttributes.jitter = 0.0f;
|
||||
_emitter[e].particleAttributes.emitterAttraction = 0.0f;
|
||||
_emitter[e].particleAttributes.tornadoForce = 0.0f;
|
||||
_emitter[e].particleAttributes.neighborAttraction = 0.0f;
|
||||
_emitter[e].particleAttributes.neighborRepulsion = 0.0f;
|
||||
_emitter[e].particleAttributes.collisionSphereRadius = 0.0f;
|
||||
_emitter[e].particleAttributes.collisionSpherePosition = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
_emitter[e].particleAttributes.usingCollisionSphere = false;
|
||||
};
|
||||
|
||||
_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;
|
||||
_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);
|
||||
|
||||
float radian = ((float)p / (float)_numberOfParticles) * 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;
|
||||
}
|
||||
for (unsigned int p = 0; p < MAX_PARTICLES; p++) {
|
||||
_particle[p].alive = false;
|
||||
_particle[p].age = 0.0f;
|
||||
_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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int ParticleSystem::addEmitter() {
|
||||
|
||||
_numEmitters ++;
|
||||
|
||||
if (_numEmitters > MAX_EMITTERS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _numEmitters - 1;
|
||||
}
|
||||
|
||||
|
||||
void ParticleSystem::simulate(float deltaTime) {
|
||||
|
||||
runSpecialEffectsTest(deltaTime);
|
||||
|
||||
for (unsigned int p = 0; p < _numberOfParticles; p++) {
|
||||
updateParticle(p, deltaTime);
|
||||
// update emitters
|
||||
for (unsigned int e = 0; e < _numEmitters; e++) {
|
||||
updateEmitter(e, deltaTime);
|
||||
}
|
||||
|
||||
// update particles
|
||||
for (unsigned int p = 0; p < _numParticles; p++) {
|
||||
if (_particle[p].alive) {
|
||||
updateParticle(p, 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::emitParticlesNow(int e, int num, float radius, glm::vec4 color, glm::vec3 velocity, float lifespan) {
|
||||
|
||||
for (unsigned int p = 0; p < num; p++) {
|
||||
createParticle(e, _emitter[e].position, velocity, radius, color, 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].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 ++;
|
||||
|
||||
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;
|
||||
float alpha = 1.0f;
|
||||
|
||||
_particle[p].color = glm::vec4(red, green, blue, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ParticleSystem::setParticleAttributesForEmitter(int emitterIndex, ParticleAttributes attributes) {
|
||||
|
||||
void ParticleSystem::runSpecialEffectsTest(float deltaTime) {
|
||||
|
||||
_timer += deltaTime;
|
||||
|
||||
_gravity = 0.01f + 0.01f * sinf( _timer * 0.52f );
|
||||
_airFriction = 3.0f + 2.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 );
|
||||
|
||||
_tornadoAxis = glm::vec3
|
||||
(
|
||||
0.0f + 0.5f * sinf( _timer * 0.55f ),
|
||||
1.0f,
|
||||
0.0f + 0.5f * cosf( _timer * 0.75f )
|
||||
);
|
||||
_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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -83,41 +166,49 @@ 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);
|
||||
}
|
||||
|
||||
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.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 = _home - _particle[p].position;
|
||||
_particle[p].velocity += vectorToHome * _homeAttraction * deltaTime;
|
||||
glm::vec3 vectorToHome = myEmitter.position - _particle[p].position;
|
||||
_particle[p].velocity += vectorToHome * myEmitter.particleAttributes.emitterAttraction * 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;
|
||||
|
||||
_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.particleAttributes.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.particleAttributes.neighborRepulsion * deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
// apply tornado force
|
||||
glm::vec3 tornadoDirection = glm::cross(vectorToHome, _tornadoAxis);
|
||||
_particle[p].velocity += tornadoDirection * _tornadoForce * deltaTime;
|
||||
glm::vec3 tornadoDirection = glm::cross(vectorToHome, myEmitter.up);
|
||||
_particle[p].velocity += tornadoDirection * myEmitter.particleAttributes.tornadoForce * deltaTime;
|
||||
|
||||
// apply air friction
|
||||
float drag = 1.0 - _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 {
|
||||
|
@ -125,7 +216,7 @@ void ParticleSystem::updateParticle(int p, float deltaTime) {
|
|||
}
|
||||
|
||||
// apply gravity
|
||||
_particle[p].velocity.y -= _gravity * deltaTime;
|
||||
_particle[p].velocity -= _upDirection * myEmitter.particleAttributes.gravity * deltaTime;
|
||||
|
||||
// update position by velocity
|
||||
_particle[p].position += _particle[p].velocity;
|
||||
|
@ -135,49 +226,98 @@ 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.particleAttributes.bounce;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 (myEmitter.particleAttributes.usingCollisionSphere) {
|
||||
glm::vec3 vectorToSphereCenter = myEmitter.particleAttributes.collisionSpherePosition - _particle[p].position;
|
||||
float distanceToSphereCenter = glm::length(vectorToSphereCenter);
|
||||
float combinedRadius = myEmitter.particleAttributes.collisionSphereRadius + _particle[p].radius;
|
||||
if (distanceToSphereCenter < combinedRadius) {
|
||||
|
||||
if (distanceToSphereCenter > 0.0f){
|
||||
glm::vec3 directionToSphereCenter = vectorToSphereCenter / distanceToSphereCenter;
|
||||
_particle[p].position = myEmitter.particleAttributes.collisionSpherePosition - directionToSphereCenter * combinedRadius;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleSystem::setCollisionSphere(int e, glm::vec3 position, float radius) {
|
||||
_emitter[e].particleAttributes.usingCollisionSphere = true;
|
||||
_emitter[e].particleAttributes.collisionSpherePosition = position;
|
||||
_emitter[e].particleAttributes.collisionSphereRadius = radius;
|
||||
}
|
||||
|
||||
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++) {
|
||||
if (_emitter[e].showingEmitter) {
|
||||
renderEmitter(e, 0.2f);
|
||||
}
|
||||
};
|
||||
|
||||
// render the particles
|
||||
for (unsigned int p = 0; p < _numParticles; p++) {
|
||||
if (_particle[p].alive) {
|
||||
renderParticle(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleSystem::renderParticle(int p) {
|
||||
|
||||
glColor4f(_particle[p].color.r, _particle[p].color.g, _particle[p].color.b, _particle[p].color.a );
|
||||
glPushMatrix();
|
||||
glTranslatef(_particle[p].position.x, _particle[p].position.y, _particle[p].position.z);
|
||||
glutSolidSphere(_particle[p].radius, 6, 6);
|
||||
glPopMatrix();
|
||||
|
||||
// render velocity lines
|
||||
glColor4f( _particle[p].color.x, _particle[p].color.y, _particle[p].color.z, 0.5f);
|
||||
glm::vec3 end = _particle[p].position - _particle[p].velocity * 2.0f;
|
||||
glBegin(GL_LINES);
|
||||
glVertex3f(_particle[p].position.x, _particle[p].position.y, _particle[p].position.z);
|
||||
glVertex3f(end.x, end.y, end.z);
|
||||
|
||||
glEnd();
|
||||
}
|
||||
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -9,51 +9,82 @@
|
|||
#ifndef hifi_ParticleSystem_h
|
||||
#define hifi_ParticleSystem_h
|
||||
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
const int MAX_PARTICLES = 5000;
|
||||
const int MAX_EMITTERS = 10;
|
||||
const int MAX_EMITTERS = 20;
|
||||
|
||||
class ParticleSystem {
|
||||
public:
|
||||
|
||||
struct ParticleAttributes {
|
||||
float bounce;
|
||||
float gravity;
|
||||
float airFriction;
|
||||
float jitter;
|
||||
float emitterAttraction;
|
||||
float tornadoForce;
|
||||
float neighborAttraction;
|
||||
float neighborRepulsion;
|
||||
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 {
|
||||
glm::vec3 position;
|
||||
glm::vec3 velocity;
|
||||
glm::vec3 color;
|
||||
float age;
|
||||
float radius;
|
||||
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?
|
||||
};
|
||||
|
||||
struct Emitter {
|
||||
glm::vec3 position;
|
||||
glm::vec3 direction;
|
||||
};
|
||||
|
||||
float _bounce;
|
||||
float _gravity;
|
||||
|
||||
glm::vec3 _upDirection;
|
||||
float _timer;
|
||||
Emitter _emitter[MAX_EMITTERS];
|
||||
Particle _particle[MAX_PARTICLES];
|
||||
int _numberOfParticles;
|
||||
glm::vec3 _home;
|
||||
glm::vec3 _tornadoAxis;
|
||||
float _airFriction;
|
||||
float _jitter;
|
||||
float _homeAttraction;
|
||||
float _tornadoForce;
|
||||
float _neighborAttraction;
|
||||
float _neighborRepulsion;
|
||||
float _TEST_bigSphereRadius;
|
||||
glm::vec3 _TEST_bigSpherePosition;
|
||||
int _numParticles;
|
||||
int _numEmitters;
|
||||
|
||||
// private methods
|
||||
void updateEmitter(int e, float deltaTime);
|
||||
void updateParticle(int index, float deltaTime);
|
||||
void runSpecialEffectsTest(float deltaTime);
|
||||
void createParticle(int e, glm::vec3 position, glm::vec3 velocity, float radius, glm::vec4 color, float lifespan);
|
||||
//void runSpecialEffectsTest(int e, float deltaTime); // for debugging and artistic exploration
|
||||
void killParticle(int p);
|
||||
void renderEmitter(int emitterIndex, float size);
|
||||
void renderParticle(int p);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue