From 8fdd78dc263850ddf9baaffcfa823aef90a31a13 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 3 Dec 2013 16:25:23 -0800 Subject: [PATCH] Added drum sounds and voxel collision detection --- interface/src/Audio.cpp | 2 +- interface/src/VoxelSystem.cpp | 32 ++++++++ interface/src/VoxelSystem.h | 3 + interface/src/avatar/Hand.cpp | 100 ++++++++++++----------- interface/src/avatar/Hand.h | 8 ++ interface/src/devices/SixenseManager.cpp | 63 ++++++++------ libraries/avatars/src/HandData.cpp | 9 +- libraries/avatars/src/HandData.h | 23 +++--- 8 files changed, 154 insertions(+), 86 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 378d86284a..f65e255495 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -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); } diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 324f293110..5b151152ce 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -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: diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index d9c672fdf3..91fe32d990 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -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); diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index d17c30d749..c95c3c901e 100755 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -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, ¤tFingerVoxel, 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); diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index 5e8acdbaa6..d012efb9bd 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -84,6 +84,12 @@ private: std::vector _leapFingerRootBalls; glm::vec3 _lastFingerAddVoxel, _lastFingerDeleteVoxel; + bool _isCollidingWithVoxel; + VoxelDetail _collidingVoxel; + + glm::vec3 _collisionCenter; + float _collisionAge; + float _collisionDuration; // private methods void setLeapHands(const std::vector& 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 diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 8055e8112d..a55715550b 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -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 } diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index 06a30f9e38..a38e2dee6d 100644 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -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); diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h index c072d9afb2..8b43b64ef0 100755 --- a/libraries/avatars/src/HandData.h +++ b/libraries/avatars/src/HandData.h @@ -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& 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 _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__) */