Merge branch 'master' of https://github.com/worklist/hifi into metavoxels

Conflicts:
	interface/src/Application.cpp
This commit is contained in:
Andrzej Kapolka 2013-12-13 15:00:05 -08:00
commit 41c7b9ce29
14 changed files with 302 additions and 20 deletions

View file

@ -1851,6 +1851,8 @@ void Application::init() {
_metavoxels.init();
_particleCollisionSystem.init(&_particleEditSender, _particles.getTree(), _voxels.getTree(), &_audio);
_palette.init(_glWidget->width(), _glWidget->height());
_palette.addAction(Menu::getInstance()->getActionForOption(MenuOption::VoxelAddMode), 0, 0);
_palette.addAction(Menu::getInstance()->getActionForOption(MenuOption::VoxelDeleteMode), 0, 1);
@ -2529,6 +2531,7 @@ void Application::update(float deltaTime) {
updateCursor(deltaTime); // Handle cursor updates
_particles.update(); // update the particles...
_particleCollisionSystem.update(); // handle collisions for the particles...
}
void Application::updateAvatar(float deltaTime) {
@ -2932,6 +2935,7 @@ void Application::updateShadowMap() {
glTranslatef(translation.x, translation.y, translation.z);
renderAvatars(true);
_particles.render();
glPopMatrix();

View file

@ -22,6 +22,7 @@
#include <NetworkPacket.h>
#include <NodeList.h>
#include <PacketHeaders.h>
#include <ParticleCollisionSystem.h>
#include <ParticleEditPacketSender.h>
#include <VoxelQuery.h>
@ -354,6 +355,7 @@ private:
ViewFrustum _sharedVoxelSystemViewFrustum;
ParticleTreeRenderer _particles;
ParticleCollisionSystem _particleCollisionSystem;
QByteArray _voxelsFilename;
bool _wantToKillLocalVoxels;

View file

@ -16,6 +16,7 @@
#include <QtCore/QObject>
#include <AbstractAudioInterface.h>
#include <AudioRingBuffer.h>
#include <StdDev.h>
@ -34,7 +35,7 @@ class QAudioInput;
class QAudioOutput;
class QIODevice;
class Audio : public QObject {
class Audio : public QObject, public AbstractAudioInterface {
Q_OBJECT
public:
// setup for audio I/O
@ -52,9 +53,9 @@ public:
void lowPassFilter(int16_t* inputBuffer);
void startCollisionSound(float magnitude, float frequency, float noise, float duration, bool flashScreen);
void startDrumSound(float volume, float frequency, float duration, float decay);
virtual void startCollisionSound(float magnitude, float frequency, float noise, float duration, bool flashScreen);
virtual void startDrumSound(float volume, float frequency, float duration, float decay);
float getCollisionSoundMagnitude() { return _collisionSoundMagnitude; }
bool getCollisionFlashesScreen() { return _collisionFlashesScreen; }

View file

@ -377,7 +377,7 @@ void Hand::render( bool isMine) {
}
// Render toy ball
if (isMine) {
if (isMine && _hasToyBall) {
glPushMatrix();
glColor3f(1, 0, 0);
glTranslatef(_toyBallPosition.x, _toyBallPosition.y, _toyBallPosition.z);

View file

@ -0,0 +1,19 @@
//
// AbstractAudioInterface.h
// hifi
//
// Created by Brad Hefta-Gaub on 12/4/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
//
#ifndef __hifi__AbstractAudioInterface__
#define __hifi__AbstractAudioInterface__
class AbstractAudioInterface {
public:
virtual void startCollisionSound(float magnitude, float frequency, float noise, float duration, bool flashScreen) = 0;
virtual void startDrumSound(float volume, float frequency, float duration, float decay) = 0;
};
#endif /* defined(__hifi__AbstractAudioInterface__) */

View file

@ -583,33 +583,40 @@ public:
float radius;
glm::vec3& penetration;
bool found;
OctreeElement* penetratedElement;
};
bool findSpherePenetrationOp(OctreeElement* node, void* extraData) {
bool findSpherePenetrationOp(OctreeElement* element, void* extraData) {
SphereArgs* args = static_cast<SphereArgs*>(extraData);
// coarse check against bounds
const AABox& box = node->getAABox();
const AABox& box = element->getAABox();
if (!box.expandedContains(args->center, args->radius)) {
return false;
}
if (!node->isLeaf()) {
if (!element->isLeaf()) {
return true; // recurse on children
}
if (node->hasContent()) {
glm::vec3 nodePenetration;
if (box.findSpherePenetration(args->center, args->radius, nodePenetration)) {
args->penetration = addPenetrations(args->penetration, nodePenetration * (float)TREE_SCALE);
if (element->hasContent()) {
glm::vec3 elementPenetration;
if (element->findSpherePenetration(args->center, args->radius, elementPenetration)) {
args->penetration = addPenetrations(args->penetration, elementPenetration * (float)TREE_SCALE);
args->found = true;
args->penetratedElement = element;
}
}
return false;
}
bool Octree::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) {
SphereArgs args = { center / (float)TREE_SCALE, radius / TREE_SCALE, penetration };
bool Octree::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration,
OctreeElement** penetratedElement) {
SphereArgs args = { center / (float)TREE_SCALE, radius / TREE_SCALE, penetration, false, NULL };
penetration = glm::vec3(0.0f, 0.0f, 0.0f);
recurseTreeWithOperation(findSpherePenetrationOp, &args);
if (penetratedElement) {
*penetratedElement = args.penetratedElement;
}
return args.found;
}
@ -887,7 +894,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node,
unsigned char childrenExistInTreeBits = 0;
unsigned char childrenExistInPacketBits = 0;
unsigned char childrenColoredBits = 0;
const int BYTES_PER_COLOR = 3;
// Make our local buffer large enough to handle writing at this level in case we need to.
LevelDetails thisLevelKey = packetData->startLevel();

View file

@ -218,7 +218,9 @@ public:
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
OctreeElement*& node, float& distance, BoxFace& face);
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration);
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration,
OctreeElement** penetratedElement = NULL);
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration);
// Note: this assumes the fileFormat is the HIO individual voxels code files

View file

@ -1285,6 +1285,11 @@ void OctreeElement::notifyUpdateHooks() {
}
}
bool OctreeElement::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const {
return _box.findSpherePenetration(center, radius, penetration);
}
OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float z, float s) {
OctreeElement* child = NULL;
// If the requested size is less than or equal to our scale, but greater than half our scale, then

View file

@ -93,6 +93,8 @@ public:
virtual bool deleteApproved() const { return true; }
virtual bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const;
// Base class methods you don't need to implement
const unsigned char* getOctalCode() const { return (_octcodePointer) ? _octalCode.pointer : &_octalCode.buffer[0]; }
OctreeElement* getChildAtIndex(int childIndex) const;

View file

@ -0,0 +1,161 @@
//
// ParticleCollisionSystem.cpp
// hifi
//
// Created by Brad Hefta-Gaub on 12/4/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
//
#include <AbstractAudioInterface.h>
#include <VoxelTree.h>
#include "Particle.h"
#include "ParticleCollisionSystem.h"
#include "ParticleEditHandle.h"
#include "ParticleEditPacketSender.h"
#include "ParticleTree.h"
ParticleCollisionSystem::ParticleCollisionSystem(ParticleEditPacketSender* packetSender,
ParticleTree* particles, VoxelTree* voxels, AbstractAudioInterface* audio) {
init(packetSender, particles, voxels, audio);
}
void ParticleCollisionSystem::init(ParticleEditPacketSender* packetSender,
ParticleTree* particles, VoxelTree* voxels, AbstractAudioInterface* audio) {
_packetSender = packetSender;
_particles = particles;
_voxels = voxels;
_audio = audio;
}
ParticleCollisionSystem::~ParticleCollisionSystem() {
}
bool ParticleCollisionSystem::updateOperation(OctreeElement* element, void* extraData) {
ParticleCollisionSystem* system = static_cast<ParticleCollisionSystem*>(extraData);
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
// iterate the particles...
std::vector<Particle>& particles = particleTreeElement->getParticles();
uint16_t numberOfParticles = particles.size();
for (uint16_t i = 0; i < numberOfParticles; i++) {
Particle* particle = &particles[i];
system->checkParticle(particle);
}
return true;
}
void ParticleCollisionSystem::update() {
// update all particles
_particles->lockForWrite();
_particles->recurseTreeWithOperation(updateOperation, this);
_particles->unlock();
}
void ParticleCollisionSystem::checkParticle(Particle* particle) {
updateCollisionWithVoxels(particle);
updateCollisionWithParticles(particle);
}
void ParticleCollisionSystem::updateCollisionWithVoxels(Particle* particle) {
glm::vec3 center = particle->getPosition() * (float)TREE_SCALE;
float radius = particle->getRadius() * (float)TREE_SCALE;
const float VOXEL_ELASTICITY = 1.4f;
const float VOXEL_DAMPING = 0.0;
const float VOXEL_COLLISION_FREQUENCY = 0.5f;
glm::vec3 penetration;
OctreeElement* penetratedVoxel;
if (_voxels->findSpherePenetration(center, radius, penetration, &penetratedVoxel)) {
penetration /= (float)TREE_SCALE;
updateCollisionSound(particle, penetration, VOXEL_COLLISION_FREQUENCY);
applyHardCollision(particle, penetration, VOXEL_ELASTICITY, VOXEL_DAMPING);
}
}
void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particle) {
glm::vec3 center = particle->getPosition() * (float)TREE_SCALE;
float radius = particle->getRadius() * (float)TREE_SCALE;
const float VOXEL_ELASTICITY = 1.4f;
const float VOXEL_DAMPING = 0.0;
const float VOXEL_COLLISION_FREQUENCY = 0.5f;
glm::vec3 penetration;
OctreeElement* penetratedElement;
if (_particles->findSpherePenetration(center, radius, penetration, &penetratedElement)) {
penetration /= (float)TREE_SCALE;
updateCollisionSound(particle, penetration, VOXEL_COLLISION_FREQUENCY);
applyHardCollision(particle, penetration, VOXEL_ELASTICITY, VOXEL_DAMPING);
}
}
void ParticleCollisionSystem::applyHardCollision(Particle* particle, const glm::vec3& penetration,
float elasticity, float damping) {
//
// Update the avatar in response to a hard collision. Position will be reset exactly
// to outside the colliding surface. Velocity will be modified according to elasticity.
//
// if elasticity = 1.0, collision is inelastic.
// if elasticity > 1.0, collision is elastic.
//
glm::vec3 position = particle->getPosition();
glm::vec3 velocity = particle->getVelocity();
position -= penetration;
static float HALTING_VELOCITY = 0.2f / (float) TREE_SCALE;
// cancel out the velocity component in the direction of penetration
float penetrationLength = glm::length(penetration);
const float EPSILON = 0.0f;
if (penetrationLength > EPSILON) {
glm::vec3 direction = penetration / penetrationLength;
velocity -= glm::dot(velocity, direction) * direction * elasticity;
velocity *= glm::clamp(1.f - damping, 0.0f, 1.0f);
if (glm::length(velocity) < HALTING_VELOCITY) {
// If moving really slowly after a collision, and not applying forces, stop altogether
velocity *= 0.f;
}
}
ParticleEditHandle particleEditHandle(_packetSender, _particles, particle->getID());
particleEditHandle.updateParticle(position, particle->getRadius(), particle->getColor(), velocity,
particle->getGravity(), particle->getDamping(), particle->getUpdateScript());
}
void ParticleCollisionSystem::updateCollisionSound(Particle* particle, const glm::vec3 &penetration, 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 = particle->getVelocity() * (float)TREE_SCALE;
/*
// how do we want to handle this??
//
glm::vec3 gravity = particle->getGravity() * (float)TREE_SCALE;
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
_audio->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, true);
}
}

View file

@ -0,0 +1,57 @@
//
// ParticleCollisionSystem.h
// hifi
//
// Created by Brad Hefta-Gaub on 12/4/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
//
#ifndef __hifi__ParticleCollisionSystem__
#define __hifi__ParticleCollisionSystem__
#include <glm/glm.hpp>
#include <stdint.h>
#include <QtScript/QScriptEngine>
#include <QtCore/QObject>
#include <SharedUtil.h>
#include <OctreePacketData.h>
#include "Particle.h"
class AbstractAudioInterface;
class ParticleEditPacketSender;
class ParticleTree;
class VoxelTree;
class ParticleCollisionSystem {
public:
ParticleCollisionSystem(ParticleEditPacketSender* packetSender = NULL, ParticleTree* particles = NULL,
VoxelTree* voxels = NULL,
AbstractAudioInterface* audio = NULL);
void init(ParticleEditPacketSender* packetSender, ParticleTree* particles, VoxelTree* voxels,
AbstractAudioInterface* audio = NULL);
~ParticleCollisionSystem();
void update();
void checkParticle(Particle* particle);
void updateCollisionWithVoxels(Particle* particle);
void updateCollisionWithParticles(Particle* particle);
void applyHardCollision(Particle* particle, const glm::vec3& penetration, float elasticity, float damping);
void updateCollisionSound(Particle* particle, const glm::vec3 &penetration, float frequency);
private:
static bool updateOperation(OctreeElement* element, void* extraData);
ParticleEditPacketSender* _packetSender;
ParticleTree* _particles;
VoxelTree* _voxels;
AbstractAudioInterface* _audio;
};
#endif /* defined(__hifi__ParticleCollisionSystem__) */

View file

@ -15,7 +15,6 @@
std::map<uint32_t,ParticleEditHandle*> ParticleEditHandle::_allHandles;
uint32_t ParticleEditHandle::_nextCreatorTokenID = 0;
ParticleEditHandle::ParticleEditHandle(ParticleEditPacketSender* packetSender, ParticleTree* localTree, uint32_t id) {
if (id == NEW_PARTICLE) {
_creatorTokenID = _nextCreatorTokenID;
@ -36,7 +35,9 @@ ParticleEditHandle::ParticleEditHandle(ParticleEditPacketSender* packetSender, P
ParticleEditHandle::~ParticleEditHandle() {
// remove us from our _allHandles map
_allHandles.erase(_allHandles.find(_creatorTokenID));
if (_creatorTokenID != UNKNOWN_TOKEN) {
_allHandles.erase(_allHandles.find(_creatorTokenID));
}
}
void ParticleEditHandle::createParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity,
@ -71,7 +72,7 @@ bool ParticleEditHandle::updateParticle(glm::vec3 position, float radius, xColor
ParticleDetail newParticleDetail = { _id, usecTimestampNow(),
position, radius, {color.red, color.green, color.blue },
velocity, gravity, damping, updateScript, _creatorTokenID };
// queue the packet
_packetSender->queueParticleEditMessages(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, 1, &newParticleDetail);

View file

@ -8,6 +8,8 @@
#include <QtCore/QDebug>
#include <GeometryUtil.h>
#include "ParticleTree.h"
#include "ParticleTreeElement.h"
@ -84,6 +86,24 @@ void ParticleTreeElement::update(ParticleTreeUpdateArgs& args) {
}
}
bool ParticleTreeElement::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const {
uint16_t numberOfParticles = _particles.size();
for (uint16_t i = 0; i < numberOfParticles; i++) {
glm::vec3 particleCenter = _particles[i].getPosition();
float particleRadius = _particles[i].getRadius();
// don't penetrate yourself
if (particleCenter == center && particleRadius == radius) {
return false;
}
if (findSphereSpherePenetration(center, radius, particleCenter, particleRadius, penetration)) {
return true;
}
}
return false;
}
bool ParticleTreeElement::containsParticle(const Particle& particle) const {
uint16_t numberOfParticles = _particles.size();
for (uint16_t i = 0; i < numberOfParticles; i++) {

View file

@ -70,10 +70,12 @@ public:
/// where an element is not actually rendering all should render elements. If the isRendered() state doesn't match the
/// shouldRender() state, the tree will remark elements as changed even in cases there the elements have not changed.
virtual bool isRendered() const { return getShouldRender(); }
virtual bool deleteApproved() const { return !hasParticles(); }
virtual bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const;
const std::vector<Particle>& getParticles() const { return _particles; }
std::vector<Particle>& getParticles() { return _particles; }
bool hasParticles() const { return _particles.size() > 0; }
void update(ParticleTreeUpdateArgs& args);