Added drum sounds and voxel collision detection

This commit is contained in:
Philip Rosedale 2013-12-03 16:25:23 -08:00
parent a84e97c54a
commit 8fdd78dc26
8 changed files with 154 additions and 86 deletions

View file

@ -289,7 +289,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o
// add output (@speakers) data just written to the scope
_scope->addSamples(1, outputLeft, BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
_scope->addSamples(2, outputRight, BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
gettimeofday(&_lastCallbackTime, NULL);
}

View file

@ -1567,6 +1567,38 @@ void VoxelSystem::falseColorizeInView() {
setupNewVoxelsForDrawing();
}
class NodeAndPoint {
public:
VoxelNode* node;
glm::vec3 point;
};
// Find the smallest colored voxel enclosing a point (if there is one)
bool VoxelSystem::getVoxelEnclosingOperation(VoxelNode* node, void* extraData) {
NodeAndPoint* nodeAndPoint = (NodeAndPoint*) extraData;
AABox voxelBox = node->getAABox();
if (voxelBox.contains(nodeAndPoint->point)) {
if (node->isColored() && node->isLeaf()) {
// we've reached a solid leaf containing the point, return the node.
nodeAndPoint->node = node;
return false;
}
} else {
// The point is not inside this voxel, so stop recursing.
return false;
}
return true; // keep looking
}
VoxelNode* VoxelSystem::getVoxelEnclosing(const glm::vec3& point) {
NodeAndPoint nodeAndPoint;
nodeAndPoint.point = point;
nodeAndPoint.node = NULL;
_tree->recurseTreeWithOperation(getVoxelEnclosingOperation, (void*) &nodeAndPoint);
return nodeAndPoint.node;
}
// helper classes and args for falseColorizeBySource
class groupColor {
public:

View file

@ -121,6 +121,8 @@ public:
virtual void domainChanged(QString domain);
bool treeIsBusy() const { return _treeIsBusy; }
VoxelNode* getVoxelEnclosing(const glm::vec3& point);
signals:
void importSize(float x, float y, float z);
@ -200,6 +202,7 @@ private:
static bool hideAllSubTreeOperation(VoxelNode* node, void* extraData);
static bool showAllSubTreeOperation(VoxelNode* node, void* extraData);
static bool showAllLocalVoxelsOperation(VoxelNode* node, void* extraData);
static bool getVoxelEnclosingOperation(VoxelNode* node, void* extraData);
int updateNodeInArrays(VoxelNode* node, bool reuseIndex, bool forceDraw);
int forceRemoveNodeFromArrays(VoxelNode* node);

View file

@ -24,7 +24,10 @@ Hand::Hand(Avatar* owningAvatar) :
_raveGloveInitialized(false),
_owningAvatar(owningAvatar),
_renderAlpha(1.0),
_ballColor(0.0, 0.0, 0.4)
_ballColor(0.0, 0.0, 0.4),
_collisionCenter(0,0,0),
_collisionAge(0),
_collisionDuration(0)
{
// initialize all finger particle emitters with an invalid id as default
for (int f = 0; f< NUM_FINGERS; f ++ ) {
@ -51,6 +54,10 @@ void Hand::reset() {
void Hand::simulate(float deltaTime, bool isMine) {
if (_collisionAge > 0.f) {
_collisionAge += deltaTime;
}
calculateGeometry();
if (_isRaveGloveActive) {
@ -67,8 +74,7 @@ void Hand::simulate(float deltaTime, bool isMine) {
for (size_t i = 0; i < getNumPalms(); ++i) {
PalmData& palm = getPalms()[i];
if (palm.isActive()) {
glm::vec3 palmPosition = palm.getPosition();
FingerData& finger = palm.getFingers()[0];
FingerData& finger = palm.getFingers()[0]; // Sixense has only one finger
glm::vec3 fingerTipPosition = finger.getTipPosition();
if (palm.getControllerButtons() & BUTTON_1) {
if (glm::length(fingerTipPosition - _lastFingerAddVoxel) > (FINGERTIP_VOXEL_SIZE / 2.f)) {
@ -88,55 +94,43 @@ void Hand::simulate(float deltaTime, bool isMine) {
}
}
// Check if the finger is intersecting with a voxel in the client voxel tree
VoxelNode* fingerNode = Application::getInstance()->getVoxels()->getVoxelAt(fingerTipPosition.x / TREE_SCALE,
fingerTipPosition.y / TREE_SCALE,
fingerTipPosition.z / TREE_SCALE,
FINGERTIP_VOXEL_SIZE / TREE_SCALE);
VoxelNode* fingerNode = Application::getInstance()->getVoxels()->getVoxelEnclosing(glm::vec3(fingerTipPosition / (float)TREE_SCALE));
if (fingerNode) {
finger.setIsTouchingVoxel(true);
glm::vec3 corner = fingerNode->getCorner();
glm::vec3 storedCorner = finger.getFingerVoxelPosition();
printf("corner: %.3f, %.3f, %.3f ", corner.x, corner.y, corner.z);
printf("stored corner: %.3f, %.3f, %.3f\n", storedCorner.x, storedCorner.y, storedCorner.z);
if (finger.getIsTouchingVoxel()) printf("Touching! %f.3", randFloat());
if (glm::length(fingerNode->getCorner() - finger.getFingerVoxelPosition()) > EPSILON) {
printf("diff = %.9f\n", glm::length(fingerNode->getCorner() - finger.getFingerVoxelPosition()));
finger.setFingerVoxelPosition(fingerNode->getCorner());
finger.setFingerVoxelScale(fingerNode->getScale());
printf("touching voxel scale, %0.4f\n", fingerNode->getScale() * TREE_SCALE);
printVector(glm::vec3(fingerNode->getCorner() * (float)TREE_SCALE));
if (!palm.getIsCollidingWithVoxel()) {
// Collision has just started
palm.setIsCollidingWithVoxel(true);
handleVoxelCollision(&palm, fingerTipPosition, fingerNode, deltaTime);
}
} else {
if (palm.getIsCollidingWithVoxel()) {
// Collision has just ended
palm.setIsCollidingWithVoxel(false);
}
/*
if ((currentFingerVoxel.x != _fingerVoxel.x) ||
(currentFingerVoxel.y != _fingerVoxel.y) ||
(currentFingerVoxel.z != _fingerVoxel.z) ||
(currentFingerVoxel.s != _fingerVoxel.s) ||
(currentFingerVoxel.red != _fingerVoxel.red) ||
(currentFingerVoxel.green != _fingerVoxel.green) ||
(currentFingerVoxel.blue != _fingerVoxel.blue)) {
memcpy(&_fingerVoxel, &currentFingerVoxel, sizeof(VoxelDetail));
_fingerIsOnVoxel = true;
Application::getInstance()->setHighlightVoxel(currentFingerVoxel);
Application::getInstance()->setIsHighlightVoxel(true);
printf("Moved onto a voxel %.2f, %.2f, %.2f s %.2f\n",
currentFingerVoxel.x * TREE_SCALE,
currentFingerVoxel.y * TREE_SCALE,
currentFingerVoxel.z * TREE_SCALE,
currentFingerVoxel.s * TREE_SCALE);
// If desired, make a sound
Application::getInstance()->getAudio()->startCollisionSound(1.0, 7040 * currentFingerVoxel.s * TREE_SCALE, 0.0, 0.999f, false);
}
*/
} else if (finger.getIsTouchingVoxel()) {
// Just moved off a voxel, change back it's color
printf("Moved out of voxel!\n");
finger.setIsTouchingVoxel(false);
Application::getInstance()->setIsHighlightVoxel(false);
}
}
}
}
void Hand::handleVoxelCollision(PalmData* palm, const glm::vec3& fingerTipPosition, VoxelNode* voxel, float deltaTime) {
//
// Collision between finger and a voxel plays sound
//
float volume = glm::length(palm->getVelocity());
float duration = volume;
_collisionCenter = fingerTipPosition;
_collisionAge = deltaTime;
_collisionDuration = duration;
int voxelBrightness = voxel->getColor()[0] + voxel->getColor()[1] + voxel->getColor()[2];
float frequency = 100.f + (voxelBrightness * 2.f); // Hz
// Play a sound
Application::getInstance()->getAudio()->startCollisionSound(volume,
frequency,
0.25,
0.995f,
false);
}
void Hand::calculateGeometry() {
const glm::vec3 leapHandsOffsetFromFace(0.0, -0.2, -0.3); // place the hand in front of the face where we can see it
@ -233,6 +227,21 @@ void Hand::render() {
}
}
// If hand/voxel collision has happened, render a little expanding sphere
if (_collisionAge > 0.f) {
float opacity = glm::clamp(1.f - (_collisionAge / _collisionDuration), 0.f, 1.f);
glColor4f(1, 0, 0, 0.5 * opacity);
glPushMatrix();
glTranslatef(_collisionCenter.x, _collisionCenter.y, _collisionCenter.z);
glutSolidSphere(_collisionAge * 0.25f, 20, 20);
glPopMatrix();
if (_collisionAge > _collisionDuration) {
_collisionAge = 0.f;
}
}
// If hand controller buttons pressed, render stuff as needed
if (getPalms().size() > 0) {
for (size_t i = 0; i < getPalms().size(); ++i) {
@ -353,7 +362,6 @@ void Hand::renderLeapHands() {
} else {
glColor4f(handColor.r, handColor.g, handColor.b, alpha);
}
glPushMatrix();
glTranslatef(_leapFingerTipBalls[i].position.x, _leapFingerTipBalls[i].position.y, _leapFingerTipBalls[i].position.z);
glutSolidSphere(_leapFingerTipBalls[i].radius, 20.0f, 20.0f);

View file

@ -84,6 +84,12 @@ private:
std::vector<HandBall> _leapFingerRootBalls;
glm::vec3 _lastFingerAddVoxel, _lastFingerDeleteVoxel;
bool _isCollidingWithVoxel;
VoxelDetail _collidingVoxel;
glm::vec3 _collisionCenter;
float _collisionAge;
float _collisionDuration;
// private methods
void setLeapHands(const std::vector<glm::vec3>& handPositions,
@ -94,6 +100,8 @@ private:
void renderLeapHands();
void renderLeapFingerTrails();
void calculateGeometry();
void handleVoxelCollision(PalmData* palm, const glm::vec3& fingerTipPosition, VoxelNode* voxel, float deltaTime);
};
#endif

View file

@ -32,7 +32,6 @@ void SixenseManager::update(float deltaTime) {
}
MyAvatar* avatar = Application::getInstance()->getAvatar();
Hand& hand = avatar->getHand();
hand.getPalms().clear();
int maxControllers = sixenseGetMaxControllers();
for (int i = 0; i < maxControllers; i++) {
@ -42,45 +41,63 @@ void SixenseManager::update(float deltaTime) {
sixenseControllerData data;
sixenseGetNewestData(i, &data);
// Set palm position and normal based on Hydra position/orientation
PalmData palm(&hand);
palm.setActive(true);
glm::vec3 position(data.pos[0], data.pos[1], data.pos[2]);
//printf("si: %i\n", data.controller_index);
// Compute current velocity from position change
palm.setVelocity((position - palm.getPosition()) / deltaTime);
// Set palm position and normal based on Hydra position/orientation
// Either find a palm matching the sixense controller, or make a new one
PalmData* palm;
bool foundHand = false;
for (int j = 0; j < hand.getNumPalms(); j++) {
if (hand.getPalms()[j].getSixenseID() == data.controller_index) {
palm = &hand.getPalms()[j];
foundHand = true;
}
}
if (!foundHand) {
PalmData newPalm(&hand);
hand.getPalms().push_back(newPalm);
palm = &hand.getPalms()[hand.getNumPalms() - 1];
palm->setSixenseID(data.controller_index);
printf("Found new Sixense controller, ID %i\n", data.controller_index);
}
palm->setActive(true);
// Read controller buttons and joystick into the hand
palm.setControllerButtons(data.buttons);
palm.setTrigger(data.trigger);
palm.setJoystick(data.joystick_x, data.joystick_y);
palm->setControllerButtons(data.buttons);
palm->setTrigger(data.trigger);
palm->setJoystick(data.joystick_x, data.joystick_y);
glm::vec3 position(data.pos[0], data.pos[1], data.pos[2]);
// Adjust for distance between acquisition 'orb' and the user's torso
// (distance to the right of body center, distance below torso, distance behind torso)
const glm::vec3 SPHERE_TO_TORSO(-250.f, -300.f, -300.f);
position = SPHERE_TO_TORSO + position;
palm.setRawPosition(position);
glm::quat rotation(data.rot_quat[3], -data.rot_quat[0], data.rot_quat[1], -data.rot_quat[2]);
// Rotate about controller
// Compute current velocity from position change
palm->setVelocity((position - palm->getRawPosition()) / deltaTime / 1000.f); // meters/sec
palm->setRawPosition(position);
// Rotation of Palm
glm::quat rotation(data.rot_quat[3], -data.rot_quat[0], data.rot_quat[1], -data.rot_quat[2]);
rotation = glm::angleAxis(180.0f, 0.f, 1.f, 0.f) * rotation;
const glm::vec3 PALM_VECTOR(0.0f, -1.0f, 0.0f);
palm.setRawNormal(rotation * PALM_VECTOR);
palm->setRawNormal(rotation * PALM_VECTOR);
// initialize the "finger" based on the direction
FingerData finger(&palm, &hand);
FingerData finger(palm, &hand);
finger.setActive(true);
finger.setRawRootPosition(position);
const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, 100.0f);
const float FINGER_LENGTH = 100.0f; // Millimeters
const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, FINGER_LENGTH);
finger.setRawTipPosition(position + rotation * FINGER_VECTOR);
// three fingers indicates to the skeleton that we have enough data to determine direction
palm.getFingers().clear();
palm.getFingers().push_back(finger);
palm.getFingers().push_back(finger);
palm.getFingers().push_back(finger);
hand.getPalms().push_back(palm);
palm->getFingers().clear();
palm->getFingers().push_back(finger);
palm->getFingers().push_back(finger);
palm->getFingers().push_back(finger);
}
#endif
}

View file

@ -41,8 +41,10 @@ _velocity(0, 0, 0),
_controllerButtons(0),
_isActive(false),
_leapID(LEAPID_INVALID),
_sixenseID(SIXENSEID_INVALID),
_numFramesWithoutData(0),
_owningHandData(owningHandData)
_owningHandData(owningHandData),
_isCollidingWithVoxel(false)
{
for (int i = 0; i < NUM_FINGERS_PER_HAND; ++i) {
_fingers.push_back(FingerData(this, owningHandData));
@ -56,10 +58,7 @@ _isActive(false),
_leapID(LEAPID_INVALID),
_numFramesWithoutData(0),
_owningPalmData(owningPalmData),
_owningHandData(owningHandData),
_isTouchingVoxel(false),
_fingerVoxelPosition(),
_fingerVoxelScale(0)
_owningHandData(owningHandData)
{
const int standardTrailLength = 10;
setTrailLength(standardTrailLength);

View file

@ -24,6 +24,7 @@ const int NUM_FINGERS_PER_HAND = 5;
const int NUM_FINGERS = NUM_HANDS * NUM_FINGERS_PER_HAND;
const int LEAPID_INVALID = -1;
const int SIXENSEID_INVALID = -1;
enum RaveGloveEffectsMode
{
@ -120,13 +121,6 @@ public:
void resetFramesWithoutData() { _numFramesWithoutData = 0; }
int getFramesWithoutData() const { return _numFramesWithoutData; }
void setIsTouchingVoxel(bool isTouchingVoxel) { _isTouchingVoxel = isTouchingVoxel; }
bool getIsTouchingVoxel() { return _isTouchingVoxel; }
void setFingerVoxelPosition(const glm::vec3& fingerVoxelPosition) { _fingerVoxelPosition = fingerVoxelPosition; }
const glm::vec3& getFingerVoxelPosition() const { return _fingerVoxelPosition; }
void setFingerVoxelScale(float fingerVoxelScale) { _fingerVoxelScale = fingerVoxelScale; }
float getFingerVoxelScale() { return _fingerVoxelScale; }
private:
glm::vec3 _tipRawPosition;
glm::vec3 _rootRawPosition;
@ -138,10 +132,6 @@ private:
int _tipTrailCurrentValidLength;
PalmData* _owningPalmData;
HandData* _owningHandData;
bool _isTouchingVoxel;
glm::vec3 _fingerVoxelPosition;
float _fingerVoxelScale;
};
class PalmData {
@ -153,12 +143,16 @@ public:
const glm::vec3& getRawNormal() const { return _rawNormal; }
bool isActive() const { return _isActive; }
int getLeapID() const { return _leapID; }
int getSixenseID() const { return _sixenseID; }
std::vector<FingerData>& getFingers() { return _fingers; }
size_t getNumFingers() { return _fingers.size(); }
void setActive(bool active) { _isActive = active; }
void setLeapID(int id) { _leapID = id; }
void setSixenseID(int id) { _sixenseID = id; }
void setRawPosition(const glm::vec3& pos) { _rawPosition = pos; }
void setRawNormal(const glm::vec3& normal) { _rawNormal = normal; }
void setVelocity(const glm::vec3& velocity) { _velocity = velocity; }
@ -177,6 +171,9 @@ public:
void setJoystick(float joystickX, float joystickY) { _joystickX = joystickX; _joystickY = joystickY; }
float getJoystickX() { return _joystickX; }
float getJoystickY() { return _joystickY; }
bool getIsCollidingWithVoxel() { return _isCollidingWithVoxel; }
void setIsCollidingWithVoxel(bool isCollidingWithVoxel) { _isCollidingWithVoxel = isCollidingWithVoxel; }
private:
std::vector<FingerData> _fingers;
@ -189,8 +186,12 @@ private:
bool _isActive; // This has current valid data
int _leapID; // the Leap's serial id for this tracked object
int _sixenseID; // Sixense controller ID for this palm
int _numFramesWithoutData; // after too many frames without data, this tracked object assumed lost.
HandData* _owningHandData;
bool _isCollidingWithVoxel; /// Whether the finger of this palm is inside a leaf voxel
};
#endif /* defined(__hifi__HandData__) */