From 6c4ecb024654aadf9764a8cf427d9f5c3b00c675 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 11 Feb 2014 14:38:31 -0800 Subject: [PATCH 01/15] Splitting hand collisions between other avatars and ourself. --- interface/src/avatar/Hand.cpp | 149 ++++++++++++++++-------------- interface/src/avatar/Hand.h | 3 + interface/src/avatar/MyAvatar.cpp | 3 + 3 files changed, 88 insertions(+), 67 deletions(-) diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 4dac42a02e..b62e88289f 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -167,91 +167,106 @@ void Hand::simulate(float deltaTime, bool isMine) { } void Hand::updateCollisions() { - // use position to obtain the left and right palm indices - int leftPalmIndex, rightPalmIndex; - getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex); - + collideAgainstOtherAvatars(); + collideAgainstOurself(); +} + +void Hand::collideAgainstOtherAvatars() { + if (!Menu::getInstance()->isOptionChecked(MenuOption::CollideWithAvatars)) { + return; + } ModelCollisionList collisions; - // check for collisions + float scaledPalmRadius = PALM_COLLISION_RADIUS * _owningAvatar->getScale(); for (size_t i = 0; i < getNumPalms(); i++) { PalmData& palm = getPalms()[i]; if (!palm.isActive()) { continue; } - float scaledPalmRadius = PALM_COLLISION_RADIUS * _owningAvatar->getScale(); glm::vec3 totalPenetration; - - if (Menu::getInstance()->isOptionChecked(MenuOption::CollideWithAvatars)) { - // check other avatars - foreach (const AvatarSharedPointer& avatarPointer, Application::getInstance()->getAvatarManager().getAvatarHash()) { - Avatar* avatar = static_cast(avatarPointer.data()); - if (avatar == _owningAvatar) { - // don't collid with our own hands - continue; - } - if (Menu::getInstance()->isOptionChecked(MenuOption::PlaySlaps)) { - // Check for palm collisions - glm::vec3 myPalmPosition = palm.getPosition(); - float palmCollisionDistance = 0.1f; - bool wasColliding = palm.getIsCollidingWithPalm(); - palm.setIsCollidingWithPalm(false); - // If 'Play Slaps' is enabled, look for palm-to-palm collisions and make sound - for (size_t j = 0; j < avatar->getHand().getNumPalms(); j++) { - PalmData& otherPalm = avatar->getHand().getPalms()[j]; - if (!otherPalm.isActive()) { - continue; - } - glm::vec3 otherPalmPosition = otherPalm.getPosition(); - if (glm::length(otherPalmPosition - myPalmPosition) < palmCollisionDistance) { - palm.setIsCollidingWithPalm(true); - if (!wasColliding) { - const float PALM_COLLIDE_VOLUME = 1.f; - const float PALM_COLLIDE_FREQUENCY = 1000.f; - const float PALM_COLLIDE_DURATION_MAX = 0.75f; - const float PALM_COLLIDE_DECAY_PER_SAMPLE = 0.01f; - Application::getInstance()->getAudio()->startDrumSound(PALM_COLLIDE_VOLUME, - PALM_COLLIDE_FREQUENCY, - PALM_COLLIDE_DURATION_MAX, - PALM_COLLIDE_DECAY_PER_SAMPLE); - // If the other person's palm is in motion, move mine downward to show I was hit - const float MIN_VELOCITY_FOR_SLAP = 0.05f; - if (glm::length(otherPalm.getVelocity()) > MIN_VELOCITY_FOR_SLAP) { - // add slapback here - } + // check other avatars + foreach (const AvatarSharedPointer& avatarPointer, Application::getInstance()->getAvatarManager().getAvatarHash()) { + Avatar* avatar = static_cast(avatarPointer.data()); + if (avatar == _owningAvatar) { + // don't collid with our own hands + continue; + } + collisions.clear(); + if (Menu::getInstance()->isOptionChecked(MenuOption::PlaySlaps)) { + // Check for palm collisions + glm::vec3 myPalmPosition = palm.getPosition(); + float palmCollisionDistance = 0.1f; + bool wasColliding = palm.getIsCollidingWithPalm(); + palm.setIsCollidingWithPalm(false); + // If 'Play Slaps' is enabled, look for palm-to-palm collisions and make sound + for (size_t j = 0; j < avatar->getHand().getNumPalms(); j++) { + PalmData& otherPalm = avatar->getHand().getPalms()[j]; + if (!otherPalm.isActive()) { + continue; + } + glm::vec3 otherPalmPosition = otherPalm.getPosition(); + if (glm::length(otherPalmPosition - myPalmPosition) < palmCollisionDistance) { + palm.setIsCollidingWithPalm(true); + if (!wasColliding) { + const float PALM_COLLIDE_VOLUME = 1.f; + const float PALM_COLLIDE_FREQUENCY = 1000.f; + const float PALM_COLLIDE_DURATION_MAX = 0.75f; + const float PALM_COLLIDE_DECAY_PER_SAMPLE = 0.01f; + Application::getInstance()->getAudio()->startDrumSound(PALM_COLLIDE_VOLUME, + PALM_COLLIDE_FREQUENCY, + PALM_COLLIDE_DURATION_MAX, + PALM_COLLIDE_DECAY_PER_SAMPLE); + // If the other person's palm is in motion, move mine downward to show I was hit + const float MIN_VELOCITY_FOR_SLAP = 0.05f; + if (glm::length(otherPalm.getVelocity()) > MIN_VELOCITY_FOR_SLAP) { + // add slapback here } } } } - if (avatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, collisions)) { - for (int j = 0; j < collisions.size(); ++j) { - // we don't resolve penetrations that would poke the other avatar - if (!avatar->isPokeable(collisions[j])) { - totalPenetration = addPenetrations(totalPenetration, collisions[j]._penetration); - } + } + if (avatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, collisions)) { + for (int j = 0; j < collisions.size(); ++j) { + // we don't resolve penetrations that would poke the other avatar + if (!avatar->isPokeable(collisions[j])) { + totalPenetration = addPenetrations(totalPenetration, collisions[j]._penetration); } } } } - - if (Menu::getInstance()->isOptionChecked(MenuOption::HandsCollideWithSelf)) { - // and the current avatar (ignoring everything below the parent of the parent of the last free joint) - collisions.clear(); - const Model& skeletonModel = _owningAvatar->getSkeletonModel(); - int skipIndex = skeletonModel.getParentJointIndex(skeletonModel.getParentJointIndex( - skeletonModel.getLastFreeJointIndex((i == leftPalmIndex) ? skeletonModel.getLeftHandJointIndex() : - (i == rightPalmIndex) ? skeletonModel.getRightHandJointIndex() : -1))); - if (_owningAvatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, collisions, skipIndex)) { - for (int j = 0; j < collisions.size(); ++j) { - totalPenetration = addPenetrations(totalPenetration, collisions[j]._penetration); - } + // resolve penetration + palm.addToPosition(-totalPenetration); + } +} + +void Hand::collideAgainstOurself() { + if (!Menu::getInstance()->isOptionChecked(MenuOption::HandsCollideWithSelf)) { + return; + } + + ModelCollisionList collisions; + int leftPalmIndex, rightPalmIndex; + getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex); + float scaledPalmRadius = PALM_COLLISION_RADIUS * _owningAvatar->getScale(); + + for (size_t i = 0; i < getNumPalms(); i++) { + PalmData& palm = getPalms()[i]; + if (!palm.isActive()) { + continue; + } + glm::vec3 totalPenetration; + // and the current avatar (ignoring everything below the parent of the parent of the last free joint) + collisions.clear(); + const Model& skeletonModel = _owningAvatar->getSkeletonModel(); + int skipIndex = skeletonModel.getParentJointIndex(skeletonModel.getParentJointIndex( + skeletonModel.getLastFreeJointIndex((i == leftPalmIndex) ? skeletonModel.getLeftHandJointIndex() : + (i == rightPalmIndex) ? skeletonModel.getRightHandJointIndex() : -1))); + if (_owningAvatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, collisions, skipIndex)) { + for (int j = 0; j < collisions.size(); ++j) { + totalPenetration = addPenetrations(totalPenetration, collisions[j]._penetration); } } - - // un-penetrate + // resolve penetration palm.addToPosition(-totalPenetration); - - // we recycle the collisions container, so we clear it for the next loop - collisions.clear(); } } diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index 3c8ec2d562..5a8e3d0e6f 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -97,6 +97,9 @@ private: void renderLeapFingerTrails(); void updateCollisions(); + void collideAgainstOtherAvatars(); + void collideAgainstOurself(); + void calculateGeometry(); void handleVoxelCollision(PalmData* palm, const glm::vec3& fingerTipPosition, VoxelTreeElement* voxel, float deltaTime); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5a4512419d..31437182bc 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1052,6 +1052,9 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) { setPosition(_position - 0.5f * penetration); glm::vec3 pushOut = 0.5f * penetration; } + + // collide their hands against our movable limbs + } } } From 04bc05cfe65a989994c987dbefcf27246ad97e44 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 12 Feb 2014 08:29:22 -0800 Subject: [PATCH 02/15] Moving hand-avatar collision trigger calls into MyAvatar Also renaming some methods in Model to be more descriptive. --- interface/src/avatar/Avatar.cpp | 9 ++- interface/src/avatar/Avatar.h | 5 +- interface/src/avatar/Hand.cpp | 101 +++++++++++++++--------------- interface/src/avatar/Hand.h | 7 +-- interface/src/avatar/MyAvatar.cpp | 9 ++- interface/src/renderer/Model.cpp | 7 +-- interface/src/renderer/Model.h | 8 +-- 7 files changed, 71 insertions(+), 75 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 5b2a142ac2..487f72a1e5 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -445,20 +445,19 @@ float Avatar::getHeight() const { return extents.maximum.y - extents.minimum.y; } -bool Avatar::isPokeable(ModelCollisionInfo& collision) const { +bool Avatar::collisionWouldMoveAvatar(ModelCollisionInfo& collision) const { // ATM only the Skeleton is pokeable // TODO: make poke affect head if (collision._model == &_skeletonModel && collision._jointIndex != -1) { - return _skeletonModel.isPokeable(collision); + return _skeletonModel.collisionHitsMoveableJoint(collision); } return false; } -bool Avatar::poke(ModelCollisionInfo& collision) { +void Avatar::applyCollision(ModelCollisionInfo& collision) { if (collision._model == &_skeletonModel && collision._jointIndex != -1) { - return _skeletonModel.poke(collision); + _skeletonModel.applyCollision(collision); } - return false; } float Avatar::getPelvisFloatingHeight() const { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 7e8a1d8f64..2fc26a36b5 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -129,11 +129,10 @@ public: float getHeight() const; /// \return true if we expect the avatar would move as a result of the collision - bool isPokeable(ModelCollisionInfo& collision) const; + bool collisionWouldMoveAvatar(ModelCollisionInfo& collision) const; /// \param collision a data structure for storing info about collisions against Models - /// \return true if the collision affects the Avatar models - bool poke(ModelCollisionInfo& collision); + void applyCollision(ModelCollisionInfo& collision); public slots: void updateCollisionFlags(); diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index b62e88289f..7e47b0a0d5 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -84,7 +84,6 @@ void Hand::simulate(float deltaTime, bool isMine) { if (isMine) { _buckyBalls.simulate(deltaTime); - updateCollisions(); } calculateGeometry(); @@ -166,16 +165,11 @@ void Hand::simulate(float deltaTime, bool isMine) { } } -void Hand::updateCollisions() { - collideAgainstOtherAvatars(); - collideAgainstOurself(); -} - -void Hand::collideAgainstOtherAvatars() { - if (!Menu::getInstance()->isOptionChecked(MenuOption::CollideWithAvatars)) { +void Hand::collideAgainstAvatar(Avatar* avatar, bool isMyHand) { + if (!avatar || avatar == _owningAvatar) { + // don't collide with our own hands (that is done elsewhere) return; } - ModelCollisionList collisions; float scaledPalmRadius = PALM_COLLISION_RADIUS * _owningAvatar->getScale(); for (size_t i = 0; i < getNumPalms(); i++) { PalmData& palm = getPalms()[i]; @@ -183,58 +177,61 @@ void Hand::collideAgainstOtherAvatars() { continue; } glm::vec3 totalPenetration; - // check other avatars - foreach (const AvatarSharedPointer& avatarPointer, Application::getInstance()->getAvatarManager().getAvatarHash()) { - Avatar* avatar = static_cast(avatarPointer.data()); - if (avatar == _owningAvatar) { - // don't collid with our own hands - continue; - } - collisions.clear(); - if (Menu::getInstance()->isOptionChecked(MenuOption::PlaySlaps)) { - // Check for palm collisions - glm::vec3 myPalmPosition = palm.getPosition(); - float palmCollisionDistance = 0.1f; - bool wasColliding = palm.getIsCollidingWithPalm(); - palm.setIsCollidingWithPalm(false); - // If 'Play Slaps' is enabled, look for palm-to-palm collisions and make sound - for (size_t j = 0; j < avatar->getHand().getNumPalms(); j++) { - PalmData& otherPalm = avatar->getHand().getPalms()[j]; - if (!otherPalm.isActive()) { - continue; - } - glm::vec3 otherPalmPosition = otherPalm.getPosition(); - if (glm::length(otherPalmPosition - myPalmPosition) < palmCollisionDistance) { - palm.setIsCollidingWithPalm(true); - if (!wasColliding) { - const float PALM_COLLIDE_VOLUME = 1.f; - const float PALM_COLLIDE_FREQUENCY = 1000.f; - const float PALM_COLLIDE_DURATION_MAX = 0.75f; - const float PALM_COLLIDE_DECAY_PER_SAMPLE = 0.01f; - Application::getInstance()->getAudio()->startDrumSound(PALM_COLLIDE_VOLUME, - PALM_COLLIDE_FREQUENCY, - PALM_COLLIDE_DURATION_MAX, - PALM_COLLIDE_DECAY_PER_SAMPLE); - // If the other person's palm is in motion, move mine downward to show I was hit - const float MIN_VELOCITY_FOR_SLAP = 0.05f; - if (glm::length(otherPalm.getVelocity()) > MIN_VELOCITY_FOR_SLAP) { - // add slapback here - } + ModelCollisionList collisions; + if (Menu::getInstance()->isOptionChecked(MenuOption::PlaySlaps)) { + // Check for palm collisions + glm::vec3 myPalmPosition = palm.getPosition(); + float palmCollisionDistance = 0.1f; + bool wasColliding = palm.getIsCollidingWithPalm(); + palm.setIsCollidingWithPalm(false); + // If 'Play Slaps' is enabled, look for palm-to-palm collisions and make sound + for (size_t j = 0; j < avatar->getHand().getNumPalms(); j++) { + PalmData& otherPalm = avatar->getHand().getPalms()[j]; + if (!otherPalm.isActive()) { + continue; + } + glm::vec3 otherPalmPosition = otherPalm.getPosition(); + if (glm::length(otherPalmPosition - myPalmPosition) < palmCollisionDistance) { + palm.setIsCollidingWithPalm(true); + if (!wasColliding) { + const float PALM_COLLIDE_VOLUME = 1.f; + const float PALM_COLLIDE_FREQUENCY = 1000.f; + const float PALM_COLLIDE_DURATION_MAX = 0.75f; + const float PALM_COLLIDE_DECAY_PER_SAMPLE = 0.01f; + Application::getInstance()->getAudio()->startDrumSound(PALM_COLLIDE_VOLUME, + PALM_COLLIDE_FREQUENCY, + PALM_COLLIDE_DURATION_MAX, + PALM_COLLIDE_DECAY_PER_SAMPLE); + // If the other person's palm is in motion, move mine downward to show I was hit + const float MIN_VELOCITY_FOR_SLAP = 0.05f; + if (glm::length(otherPalm.getVelocity()) > MIN_VELOCITY_FOR_SLAP) { + // add slapback here } } } } - if (avatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, collisions)) { - for (int j = 0; j < collisions.size(); ++j) { - // we don't resolve penetrations that would poke the other avatar - if (!avatar->isPokeable(collisions[j])) { + } + if (avatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, collisions)) { + for (int j = 0; j < collisions.size(); ++j) { + if (isMyHand) { + if (!avatar->collisionWouldMoveAvatar(collisions[j])) { + // we resolve the hand from collision when it belongs to MyAvatar AND the other Avatar is + // not expected to respond to the collision (hand hit unmovable part of their Avatar) totalPenetration = addPenetrations(totalPenetration, collisions[j]._penetration); } + } else { + // when this !isMyHand then avatar is MyAvatar and we apply the collision + // which might not do anything (hand hit unmovable part of MyAvatar) however + // we don't resolve the hand's penetration (we expect their simulation + // to do the right thing). + avatar->applyCollision(collisions[j]); } } } - // resolve penetration - palm.addToPosition(-totalPenetration); + if (isMyHand) { + // resolve penetration + palm.addToPosition(-totalPenetration); + } } } diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index 5a8e3d0e6f..9413d024c3 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -67,6 +67,9 @@ public: glm::vec3 getAndResetGrabDeltaVelocity(); glm::quat getAndResetGrabRotation(); + void collideAgainstAvatar(Avatar* avatar, bool isMyHand); + void collideAgainstOurself(); + private: // disallow copies of the Hand, copy of owning Avatar is disallowed too Hand(const Hand&); @@ -96,10 +99,6 @@ private: void renderLeapHands(bool isMine); void renderLeapFingerTrails(); - void updateCollisions(); - void collideAgainstOtherAvatars(); - void collideAgainstOurself(); - void calculateGeometry(); void handleVoxelCollision(PalmData* palm, const glm::vec3& fingerTipPosition, VoxelTreeElement* voxel, float deltaTime); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 31437182bc..e0d9db43aa 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -344,6 +344,7 @@ void MyAvatar::simulate(float deltaTime) { _position += _velocity * deltaTime; // update avatar skeleton and simulate hand and head + _hand.collideAgainstOurself(); _hand.simulate(deltaTime, true); _skeletonModel.simulate(deltaTime); _head.setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll)); @@ -1050,11 +1051,13 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) { avatar->getPosition(), theirCapsuleRadius, theirCapsuleHeight, penetration)) { // move the avatar out by half the penetration setPosition(_position - 0.5f * penetration); - glm::vec3 pushOut = 0.5f * penetration; } - // collide their hands against our movable limbs - + // collide our hands against them + _hand.collideAgainstAvatar(avatar, true); + + // collide their hands against us + avatar->getHand().collideAgainstAvatar(this, false); } } } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index de48be8694..f899e76ef4 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -722,7 +722,7 @@ void Model::renderCollisionProxies(float alpha) { glPopMatrix(); } -bool Model::isPokeable(ModelCollisionInfo& collision) const { +bool Model::collisionHitsMoveableJoint(ModelCollisionInfo& collision) const { // the joint is pokable by a collision if it exists and is free to move const FBXJoint& joint = _geometry->getFBXGeometry().joints[collision._jointIndex]; if (joint.parentIndex == -1 || @@ -736,7 +736,7 @@ bool Model::isPokeable(ModelCollisionInfo& collision) const { return !freeLineage.isEmpty(); } -bool Model::poke(ModelCollisionInfo& collision) { +void Model::applyCollision(ModelCollisionInfo& collision) { // This needs work. At the moment it can wiggle joints that are free to move (such as arms) // but unmovable joints (such as torso) cannot be influenced at all. glm::vec3 jointPosition(0.f); @@ -760,11 +760,10 @@ bool Model::poke(ModelCollisionInfo& collision) { getJointPosition(jointIndex, end); glm::vec3 newEnd = start + glm::angleAxis(glm::degrees(angle), axis) * (end - start); // try to move it - return setJointPosition(jointIndex, newEnd, -1, true); + setJointPosition(jointIndex, newEnd, -1, true); } } } - return false; } void Model::deleteGeometry() { diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 003cdfe3e5..bab25bed7a 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -167,12 +167,12 @@ public: void renderCollisionProxies(float alpha); - /// \return true if the collision would move the model - bool isPokeable(ModelCollisionInfo& collision) const; + /// \return true if the collision is against a moveable joint + bool collisionHitsMoveableJoint(ModelCollisionInfo& collision) const; /// \param collisionInfo info about the collision - /// \return true if collision affects the Model - bool poke(ModelCollisionInfo& collisionInfo); + /// Use the collisionInfo to affect the model + void applyCollision(ModelCollisionInfo& collisionInfo); protected: From 3a8aa0c47e4f9556d9401be67cf551b41b8e147f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Feb 2014 10:02:16 -0800 Subject: [PATCH 03/15] Removing HeadData::findSpherePenetration() as unused cruft. --- libraries/avatars/src/HeadData.cpp | 7 ------- libraries/avatars/src/HeadData.h | 7 ------- 2 files changed, 14 deletions(-) diff --git a/libraries/avatars/src/HeadData.cpp b/libraries/avatars/src/HeadData.cpp index f863d6b592..62e8276bd3 100644 --- a/libraries/avatars/src/HeadData.cpp +++ b/libraries/avatars/src/HeadData.cpp @@ -45,10 +45,3 @@ void HeadData::addLean(float sideways, float forwards) { _leanForward += forwards; } -bool HeadData::findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, glm::vec3& penetration) const { - // we would like to update this to determine collisions/penetrations with the Avatar's head sphere... - // but right now it does not appear as if the HeadData has a position and radius. - // this is a placeholder for now. - return false; -} - diff --git a/libraries/avatars/src/HeadData.h b/libraries/avatars/src/HeadData.h index fde684bbf1..0f096059c0 100644 --- a/libraries/avatars/src/HeadData.h +++ b/libraries/avatars/src/HeadData.h @@ -58,13 +58,6 @@ public: void setLookAtPosition(const glm::vec3& lookAtPosition) { _lookAtPosition = lookAtPosition; } friend class AvatarData; - - /// Checks for penetration between the described sphere and the hand. - /// \param penetratorCenter the center of the penetration test sphere - /// \param penetratorRadius the radius of the penetration test sphere - /// \param penetration[out] the vector in which to store the penetration - /// \return whether or not the sphere penetrated - bool findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, glm::vec3& penetration) const; protected: float _yaw; From e793c207f9fd15f2ad70266a154b51e7d9348ab1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Feb 2014 10:03:14 -0800 Subject: [PATCH 04/15] Minor whitespace removal. --- interface/src/avatar/MyAvatar.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e0d9db43aa..560f1a6fd4 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -837,7 +837,6 @@ void MyAvatar::updateThrust(float deltaTime) { } } } - } // Update speed brake status @@ -903,7 +902,6 @@ void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) { } } - void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) { const float VOXEL_ELASTICITY = 0.4f; const float VOXEL_DAMPING = 0.0f; From 9523ea7d03a3b402a860b294b0b2883251f9818f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Feb 2014 10:03:39 -0800 Subject: [PATCH 05/15] Only do slaps for MyAvatar. --- interface/src/avatar/Hand.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 7e47b0a0d5..5749da5f14 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -178,7 +178,7 @@ void Hand::collideAgainstAvatar(Avatar* avatar, bool isMyHand) { } glm::vec3 totalPenetration; ModelCollisionList collisions; - if (Menu::getInstance()->isOptionChecked(MenuOption::PlaySlaps)) { + if (isMyHand && Menu::getInstance()->isOptionChecked(MenuOption::PlaySlaps)) { // Check for palm collisions glm::vec3 myPalmPosition = palm.getPosition(); float palmCollisionDistance = 0.1f; @@ -220,10 +220,10 @@ void Hand::collideAgainstAvatar(Avatar* avatar, bool isMyHand) { totalPenetration = addPenetrations(totalPenetration, collisions[j]._penetration); } } else { - // when this !isMyHand then avatar is MyAvatar and we apply the collision + // when !isMyHand then avatar is MyAvatar and we apply the collision // which might not do anything (hand hit unmovable part of MyAvatar) however - // we don't resolve the hand's penetration (we expect their simulation - // to do the right thing). + // we don't resolve the hand's penetration because we expect the remote + // simulation to do the right thing. avatar->applyCollision(collisions[j]); } } From 312bc7521f5d13a698773c99351b0a2aebbc234a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Feb 2014 10:04:58 -0800 Subject: [PATCH 06/15] Making arm restoration rate independent of FPS and easier to tune. --- interface/src/avatar/SkeletonModel.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index ac08c52b49..ff4de8c41e 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -36,23 +36,24 @@ void SkeletonModel::simulate(float deltaTime) { HandData& hand = _owningAvatar->getHand(); hand.getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex); - const float HAND_RESTORATION_RATE = 0.25f; + const float HAND_RESTORATION_PERIOD = 1.f; // seconds + float handRestorePercent = glm::clamp(deltaTime / HAND_RESTORATION_PERIOD, 0.f, 1.f); const FBXGeometry& geometry = _geometry->getFBXGeometry(); if (leftPalmIndex == -1) { // no Leap data; set hands from mouse if (_owningAvatar->getHandState() == HAND_STATE_NULL) { - restoreRightHandPosition(HAND_RESTORATION_RATE); + restoreRightHandPosition(handRestorePercent); } else { applyHandPosition(geometry.rightHandJointIndex, _owningAvatar->getHandPosition()); } - restoreLeftHandPosition(HAND_RESTORATION_RATE); + restoreLeftHandPosition(handRestorePercent); } else if (leftPalmIndex == rightPalmIndex) { // right hand only applyPalmData(geometry.rightHandJointIndex, geometry.rightFingerJointIndices, geometry.rightFingertipJointIndices, hand.getPalms()[leftPalmIndex]); - restoreLeftHandPosition(HAND_RESTORATION_RATE); + restoreLeftHandPosition(handRestorePercent); } else { applyPalmData(geometry.leftHandJointIndex, geometry.leftFingerJointIndices, geometry.leftFingertipJointIndices, From 6d75efd2b01d56fe8d236de1985fc9de824927d6 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Feb 2014 10:46:28 -0800 Subject: [PATCH 07/15] tweaks to default menus for alpha, make Gravity false so we don't fall into abyss --- interface/src/Menu.cpp | 8 ++++---- interface/src/Menu.h | 2 +- interface/src/avatar/Hand.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 7eb5807c6f..2e026f216f 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -161,7 +161,7 @@ Menu::Menu() : #endif addDisabledActionAndSeparator(editMenu, "Physics"); - addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::Gravity, Qt::SHIFT | Qt::Key_G, true); + addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::Gravity, Qt::SHIFT | Qt::Key_G, false); addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::ClickToFly); @@ -339,14 +339,14 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Avatars, 0, true); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::CollisionProxies); - addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::LookAtVectors, 0, true); + addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::LookAtVectors, 0, false); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::FaceshiftTCP, 0, false, appInstance->getFaceshift(), SLOT(setTCPEnabled(bool))); - addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, true); + addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, false); QMenu* handOptionsMenu = developerMenu->addMenu("Hand Options"); @@ -356,7 +356,7 @@ Menu::Menu() : true, appInstance->getSixenseManager(), SLOT(setFilter(bool))); - addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayLeapHands, 0, true); + addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHands, 0, true); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::VoxelDrumming, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::PlaySlaps, 0, false); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 742b9fc66f..2f0c65413c 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -183,7 +183,7 @@ namespace MenuOption { const QString DisableDeltaSending = "Disable Delta Sending"; const QString DisableLowRes = "Disable Lower Resolution While Moving"; const QString DisplayFrustum = "Display Frustum"; - const QString DisplayLeapHands = "Display Leap Hands"; + const QString DisplayHands = "Display Hands"; const QString DisplayHandTargets = "Display Hand Targets"; const QString FilterSixense = "Smooth Sixense Movement"; const QString DontRenderVoxels = "Don't call _voxels.render()"; diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 8edb455a75..1239e38818 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -304,7 +304,7 @@ void Hand::render(bool isMine) { } } - if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayLeapHands)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayHands)) { renderLeapHands(isMine); } From 156fa6dc5aaa57465c585b6b6cda7dfc0a98c9a3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Feb 2014 11:03:35 -0800 Subject: [PATCH 08/15] more tweaks, removed old clouds --- interface/src/Application.cpp | 14 ------ interface/src/Application.h | 4 -- interface/src/Cloud.cpp | 85 ----------------------------------- interface/src/Cloud.h | 32 ------------- interface/src/Menu.cpp | 17 +++---- interface/src/Menu.h | 1 - 6 files changed, 5 insertions(+), 148 deletions(-) delete mode 100644 interface/src/Cloud.cpp delete mode 100644 interface/src/Cloud.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 004b71074b..f51360cca1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2146,15 +2146,6 @@ void Application::updateThreads(float deltaTime) { } } -void Application::updateParticles(float deltaTime) { - bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarnings, "Application::updateParticles()"); - - if (Menu::getInstance()->isOptionChecked(MenuOption::ParticleCloud)) { - _cloud.simulate(deltaTime); - } -} - void Application::updateMetavoxels(float deltaTime) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateMetavoxels()"); @@ -2276,7 +2267,6 @@ void Application::update(float deltaTime) { updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... _avatarManager.updateOtherAvatars(deltaTime); //loop through all the other avatars and simulate them... - updateParticles(deltaTime); // Simulate particle cloud movements updateMetavoxels(deltaTime); // update metavoxels updateCamera(deltaTime); // handle various camera tweaks like off axis projection updateDialogs(deltaTime); // update various stats dialogs if present @@ -2711,10 +2701,6 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // disable specular lighting for ground and voxels glMaterialfv(GL_FRONT, GL_SPECULAR, NO_SPECULAR_COLOR); - // Draw Cloud Particles - if (Menu::getInstance()->isOptionChecked(MenuOption::ParticleCloud)) { - _cloud.render(); - } // Draw voxels if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), diff --git a/interface/src/Application.h b/interface/src/Application.h index ff6e08758b..c5aafc4e9d 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -32,7 +32,6 @@ #include "BandwidthMeter.h" #include "Camera.h" -#include "Cloud.h" #include "DatagramProcessor.h" #include "Environment.h" #include "GLCanvas.h" @@ -284,7 +283,6 @@ private: void updateSixense(float deltaTime); void updateSerialDevices(float deltaTime); void updateThreads(float deltaTime); - void updateParticles(float deltaTime); void updateMetavoxels(float deltaTime); void updateCamera(float deltaTime); void updateDialogs(float deltaTime); @@ -351,8 +349,6 @@ private: Stars _stars; - Cloud _cloud; - VoxelSystem _voxels; VoxelTree _clipboard; // if I copy/paste VoxelImporter* _voxelImporter; diff --git a/interface/src/Cloud.cpp b/interface/src/Cloud.cpp deleted file mode 100644 index a89ee04810..0000000000 --- a/interface/src/Cloud.cpp +++ /dev/null @@ -1,85 +0,0 @@ -// -// Cloud.cpp -// interface -// -// Created by Philip Rosedale on 11/17/12. -// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. -// - -#include -#include -#include "Cloud.h" -#include "Util.h" -#include "Field.h" - -const int NUM_PARTICLES = 100000; -const float FIELD_COUPLE = 0.001f; -const bool RENDER_FIELD = false; - -Cloud::Cloud() { - glm::vec3 box = glm::vec3(PARTICLE_WORLD_SIZE); - _bounds = box; - _count = NUM_PARTICLES; - _particles = new Particle[_count]; - _field = new Field(PARTICLE_WORLD_SIZE, FIELD_COUPLE); - - for (unsigned int i = 0; i < _count; i++) { - _particles[i].position = randVector() * box; - const float INIT_VEL_SCALE = 0.03f; - _particles[i].velocity = randVector() * ((float)PARTICLE_WORLD_SIZE * INIT_VEL_SCALE); - _particles[i].color = randVector(); - } -} - -void Cloud::render() { - if (RENDER_FIELD) { - _field->render(); - } - - glPointSize(3.0f); - glDisable(GL_TEXTURE_2D); - glEnable(GL_POINT_SMOOTH); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glVertexPointer(3, GL_FLOAT, 3 * sizeof(glm::vec3), &_particles[0].position); - glColorPointer(3, GL_FLOAT, 3 * sizeof(glm::vec3), &_particles[0].color); - glDrawArrays(GL_POINTS, 0, NUM_PARTICLES); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - -} - -void Cloud::simulate (float deltaTime) { - unsigned int i; - _field->simulate(deltaTime); - for (i = 0; i < _count; ++i) { - - // Update position - _particles[i].position += _particles[i].velocity * deltaTime; - - // Decay Velocity (Drag) - const float CONSTANT_DAMPING = 0.15f; - _particles[i].velocity *= (1.f - CONSTANT_DAMPING * deltaTime); - - // Interact with Field - _field->interact(deltaTime, _particles[i].position, _particles[i].velocity); - - // Update color to velocity - _particles[i].color = (glm::normalize(_particles[i].velocity) * 0.5f) + 0.5f; - - // Bounce at bounds - if ((_particles[i].position.x > _bounds.x) || (_particles[i].position.x < 0.f)) { - _particles[i].position.x = glm::clamp(_particles[i].position.x, 0.f, _bounds.x); - _particles[i].velocity.x *= -1.f; - } - if ((_particles[i].position.y > _bounds.y) || (_particles[i].position.y < 0.f)) { - _particles[i].position.y = glm::clamp(_particles[i].position.y, 0.f, _bounds.y); - _particles[i].velocity.y *= -1.f; - } - if ((_particles[i].position.z > _bounds.z) || (_particles[i].position.z < 0.f)) { - _particles[i].position.z = glm::clamp(_particles[i].position.z, 0.f, _bounds.z); - _particles[i].velocity.z *= -1.f; - } - } - } diff --git a/interface/src/Cloud.h b/interface/src/Cloud.h deleted file mode 100644 index fcf414b62e..0000000000 --- a/interface/src/Cloud.h +++ /dev/null @@ -1,32 +0,0 @@ -// -// Cloud.h -// interface -// -// Created by Philip Rosedale on 11/17/12. -// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. -// - -#ifndef __interface__Cloud__ -#define __interface__Cloud__ - -#include "Field.h" - -#define PARTICLE_WORLD_SIZE 256.0 - -class Cloud { -public: - Cloud(); - void simulate(float deltaTime); - void render(); - -private: - struct Particle { - glm::vec3 position, velocity, color; - }* _particles; - - unsigned int _count; - glm::vec3 _bounds; - Field* _field; -}; - -#endif diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 2e026f216f..4a3733f760 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -238,9 +238,9 @@ Menu::Menu() : SLOT(setFullscreen(bool))); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, Qt::Key_P, true, appInstance,SLOT(cameraMenuChanged())); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H,false, - appInstance,SLOT(cameraMenuChanged())); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H, true); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false, + appInstance, SLOT(cameraMenuChanged())); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Enable3DTVMode, 0, false, @@ -266,14 +266,8 @@ Menu::Menu() : appInstance->getAvatar(), SLOT(resetSize())); - addCheckableActionToQMenuAndActionHash(viewMenu, - MenuOption::OffAxisProjection, - 0, - true); - addCheckableActionToQMenuAndActionHash(viewMenu, - MenuOption::TurnWithHead, - 0, - true); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::OffAxisProjection, 0, false); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::MoveWithLean, 0, false); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HeadMouse, 0, false); @@ -298,7 +292,6 @@ Menu::Menu() : appInstance->getGlowEffect(), SLOT(cycleRenderMode())); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ParticleCloud, 0, false); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Shadows, 0, false); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, false); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 2f0c65413c..19e9fbf49f 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -223,7 +223,6 @@ namespace MenuOption { const QString KillLocalVoxels = "Kill Local Voxels"; const QString GoHome = "Go Home"; const QString Gravity = "Use Gravity"; - const QString ParticleCloud = "Particle Cloud"; const QString LodTools = "LOD Tools"; const QString Log = "Log"; const QString Login = "Login"; From d9b50359a6818434ea7a6c22a3bb1642efb6a7f3 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Feb 2014 12:21:28 -0800 Subject: [PATCH 09/15] Hand-face collisions now work (sorta). --- interface/src/avatar/Avatar.cpp | 25 ++++++++++++++++++++++--- interface/src/avatar/Head.cpp | 28 ++++++++++++++++++++++++++++ interface/src/avatar/Head.h | 2 ++ 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 487f72a1e5..f36c03cba6 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -162,6 +162,7 @@ void Avatar::render(bool forceRenderHead) { // render body if (Menu::getInstance()->isOptionChecked(MenuOption::CollisionProxies)) { _skeletonModel.renderCollisionProxies(1.f); + //_head.getFaceModel().renderCollisionProxies(0.5f); } if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) { @@ -276,11 +277,14 @@ bool Avatar::findSphereCollisions(const glm::vec3& penetratorCenter, float penet bool didPenetrate = false; glm::vec3 skeletonPenetration; ModelCollisionInfo collisionInfo; + /* Temporarily disabling collisions against the skeleton because the collision proxies up + * near the neck are bad and prevent the hand from hitting the face. if (_skeletonModel.findSphereCollision(penetratorCenter, penetratorRadius, collisionInfo, 1.0f, skeletonSkipIndex)) { collisionInfo._model = &_skeletonModel; collisions.push_back(collisionInfo); didPenetrate = true; } + */ if (_head.getFaceModel().findSphereCollision(penetratorCenter, penetratorRadius, collisionInfo)) { collisionInfo._model = &(_head.getFaceModel()); collisions.push_back(collisionInfo); @@ -448,16 +452,31 @@ float Avatar::getHeight() const { bool Avatar::collisionWouldMoveAvatar(ModelCollisionInfo& collision) const { // ATM only the Skeleton is pokeable // TODO: make poke affect head + if (!collision._model) { + return false; + } if (collision._model == &_skeletonModel && collision._jointIndex != -1) { - return _skeletonModel.collisionHitsMoveableJoint(collision); + // collision response of skeleton is temporarily disabled + return false; + //return _skeletonModel.collisionHitsMoveableJoint(collision); + } + if (collision._model == &(_head.getFaceModel())) { + return true; } return false; } void Avatar::applyCollision(ModelCollisionInfo& collision) { - if (collision._model == &_skeletonModel && collision._jointIndex != -1) { - _skeletonModel.applyCollision(collision); + if (!collision._model) { + return; } + if (collision._model == &(_head.getFaceModel())) { + _head.applyCollision(collision); + } + // TODO: make skeleton respond to collisions + //if (collision._model == &_skeletonModel && collision._jointIndex != -1) { + // _skeletonModel.applyCollision(collision); + //} } float Avatar::getPelvisFloatingHeight() const { diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index e5d4724bb5..bb88530aa7 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -219,6 +219,34 @@ float Head::getTweakedRoll() const { return glm::clamp(_roll + _tweakedRoll, MIN_HEAD_ROLL, MAX_HEAD_ROLL); } +void Head::applyCollision(ModelCollisionInfo& collisionInfo) { + // HACK: the collision proxies for the FaceModel are bad. As a temporary workaround + // we collide against a hard coded collision proxy. + // TODO: get a better collision proxy here. + const float HEAD_RADIUS = 0.15f; + const glm::vec3 HEAD_CENTER = _position; + + // collide the contactPoint against the collision proxy to obtain a new penetration + // NOTE: that penetration is in opposite direction (points the way out for the point, not the sphere) + glm::vec3 penetration; + if (findPointSpherePenetration(collisionInfo._contactPoint, HEAD_CENTER, HEAD_RADIUS, penetration)) { + // compute lean angles + Avatar* owningAvatar = static_cast(_owningAvatar); + glm::quat bodyRotation = owningAvatar->getOrientation(); + glm::vec3 neckPosition; + if (owningAvatar->getSkeletonModel().getNeckPosition(neckPosition)) { + glm::vec3 xAxis = bodyRotation * glm::vec3(1.f, 0.f, 0.f); + glm::vec3 zAxis = bodyRotation * glm::vec3(0.f, 0.f, 1.f); + float neckLength = glm::length(_position - neckPosition); + if (neckLength > 0.f) { + float forward = glm::dot(collisionInfo._penetration, zAxis) / neckLength; + float sideways = - glm::dot(collisionInfo._penetration, xAxis) / neckLength; + addLean(sideways, forward); + } + } + } +} + void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) { Application::getInstance()->getGlowEffect()->begin(); diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 19f9efd8e6..eae8223903 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -79,6 +79,8 @@ public: float getTweakedPitch() const; float getTweakedYaw() const; float getTweakedRoll() const; + + void applyCollision(ModelCollisionInfo& collisionInfo); private: // disallow copies of the Head, copy of owning Avatar is disallowed too From b75de42802ca858c9e9ce7c398fc2aba3ec2b931 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Feb 2014 12:22:40 -0800 Subject: [PATCH 10/15] Making the lean recovery use more tuneable parameters. --- interface/src/avatar/MyAvatar.cpp | 33 +++++++++---------------------- interface/src/avatar/MyAvatar.h | 2 +- 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 560f1a6fd4..8a4d734072 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -112,23 +112,7 @@ void MyAvatar::updateTransmitter(float deltaTime) { void MyAvatar::update(float deltaTime) { updateTransmitter(deltaTime); - // TODO: resurrect touch interactions between avatars - //// rotate body yaw for yaw received from multitouch - //setOrientation(getOrientation() * glm::quat(glm::vec3(0, _yawFromTouch, 0))); - //_yawFromTouch = 0.f; - // - //// apply pitch from touch - //_head.setPitch(_head.getPitch() + _pitchFromTouch); - //_pitchFromTouch = 0.0f; - // - //float TOUCH_YAW_SCALE = -0.25f; - //float TOUCH_PITCH_SCALE = -12.5f; - //float FIXED_TOUCH_TIMESTEP = 0.016f; - //_yawFromTouch += ((_touchAvgX - _lastTouchAvgX) * TOUCH_YAW_SCALE * FIXED_TOUCH_TIMESTEP); - //_pitchFromTouch += ((_touchAvgY - _lastTouchAvgY) * TOUCH_PITCH_SCALE * FIXED_TOUCH_TIMESTEP); - - // Update my avatar's state from gyros - updateFromGyros(Menu::getInstance()->isOptionChecked(MenuOption::TurnWithHead)); + updateFromGyros(deltaTime); // Update head mouse from faceshift if active Faceshift* faceshift = Application::getInstance()->getFaceshift(); @@ -364,7 +348,7 @@ void MyAvatar::simulate(float deltaTime) { const float MAX_PITCH = 90.0f; // Update avatar head rotation with sensor data -void MyAvatar::updateFromGyros(bool turnWithHead) { +void MyAvatar::updateFromGyros(float deltaTime) { Faceshift* faceshift = Application::getInstance()->getFaceshift(); glm::vec3 estimatedPosition, estimatedRotation; @@ -372,7 +356,7 @@ void MyAvatar::updateFromGyros(bool turnWithHead) { estimatedPosition = faceshift->getHeadTranslation(); estimatedRotation = safeEulerAngles(faceshift->getHeadRotation()); // Rotate the body if the head is turned beyond the screen - if (turnWithHead) { + if (Menu::getInstance()->isOptionChecked(MenuOption::TurnWithHead)) { const float FACESHIFT_YAW_TURN_SENSITIVITY = 0.5f; const float FACESHIFT_MIN_YAW_TURN = 15.f; const float FACESHIFT_MAX_YAW_TURN = 50.f; @@ -387,11 +371,12 @@ void MyAvatar::updateFromGyros(bool turnWithHead) { } } else { // restore rotation, lean to neutral positions - const float RESTORE_RATE = 0.05f; - _head.setYaw(glm::mix(_head.getYaw(), 0.0f, RESTORE_RATE)); - _head.setRoll(glm::mix(_head.getRoll(), 0.0f, RESTORE_RATE)); - _head.setLeanSideways(glm::mix(_head.getLeanSideways(), 0.0f, RESTORE_RATE)); - _head.setLeanForward(glm::mix(_head.getLeanForward(), 0.0f, RESTORE_RATE)); + const float RESTORE_PERIOD = 1.f; // seconds + float restorePercentage = glm::clamp(deltaTime/RESTORE_PERIOD, 0.f, 1.f); + _head.setYaw(glm::mix(_head.getYaw(), 0.0f, restorePercentage)); + _head.setRoll(glm::mix(_head.getRoll(), 0.0f, restorePercentage)); + _head.setLeanSideways(glm::mix(_head.getLeanSideways(), 0.0f, restorePercentage)); + _head.setLeanForward(glm::mix(_head.getLeanForward(), 0.0f, restorePercentage)); return; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index b912f6b0a7..0130cc9ca2 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -34,7 +34,7 @@ public: void reset(); void update(float deltaTime); void simulate(float deltaTime); - void updateFromGyros(bool turnWithHead); + void updateFromGyros(float deltaTime); void updateTransmitter(float deltaTime); void render(bool forceRenderHead); From ee4733d0bd8ce8801e5ea7622b62ea0a198f4b95 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Feb 2014 12:41:23 -0800 Subject: [PATCH 11/15] Fixing a comment. --- libraries/avatars/src/AvatarHashMap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 72ada7d421..82485691c5 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -2,7 +2,7 @@ // AvatarHashMap.cpp // hifi // -// Created by Stephen AndrewMeadows on 1/28/2014. +// Created by AndrewMeadows on 1/28/2014. // Copyright (c) 2014 HighFidelity, Inc. All rights reserved. // From 50d864901e742ba3cb7e0b338855474dbf13af10 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Feb 2014 14:02:25 -0800 Subject: [PATCH 12/15] Improved comment about limitation of collision check. --- interface/src/renderer/Model.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index ce11ee3d71..7686b1ac7f 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -477,7 +477,10 @@ bool Model::findSphereCollision(const glm::vec3& penetratorCenter, float penetra if (findSphereCapsuleConePenetration(relativeCenter, penetratorRadius, start, end, startRadius, endRadius, bonePenetration)) { totalPenetration = addPenetrations(totalPenetration, bonePenetration); - // TODO: Andrew to try to keep the joint furthest toward the root + // BUG: we currently overwrite the jointIndex with the last one found + // which can cause incorrect collisions when colliding against more than + // one joint. + // TODO: fix this. jointIndex = i; } outerContinue: ; From 9d841ce918f505a82a2f83f68d471f5ec78df268 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Feb 2014 18:19:20 -0800 Subject: [PATCH 13/15] add Stop All Scripts and Reload All Scripts --- interface/src/Application.cpp | 24 ++++++++++++++++++++++++ interface/src/Application.h | 2 ++ interface/src/Menu.cpp | 2 ++ interface/src/Menu.h | 6 ++++-- 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f51360cca1..80c2dc7feb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3984,6 +3984,30 @@ void Application::saveScripts() { settings->endArray(); } +void Application::stopAllScripts() { + // stops all current running scripts + QList scriptActions = Menu::getInstance()->getActiveScriptsMenu()->actions(); + foreach (QAction* scriptAction, scriptActions) { + scriptAction->activate(QAction::Trigger); + qDebug() << "stopping script..." << scriptAction->text(); + } +} + +void Application::reloadAllScripts() { + // reloads all current running scripts + QList scriptActions = Menu::getInstance()->getActiveScriptsMenu()->actions(); + foreach (QAction* scriptAction, scriptActions) { + scriptAction->activate(QAction::Trigger); + qDebug() << "stopping script..." << scriptAction->text(); + } + QStringList reloadList = _activeScripts; + _activeScripts.clear(); + foreach (QString scriptName, reloadList){ + qDebug() << "reloading script..." << scriptName; + loadScript(scriptName); + } +} + void Application::removeScriptName(const QString& fileNameString) { _activeScripts.removeOne(fileNameString); } diff --git a/interface/src/Application.h b/interface/src/Application.h index c5aafc4e9d..3153150457 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -231,6 +231,8 @@ public slots: void loadDialog(); void toggleLogDialog(); void initAvatarAndViewFrustum(); + void stopAllScripts(); + void reloadAllScripts(); private slots: void timer(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 4a3733f760..f16a276653 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -93,6 +93,8 @@ Menu::Menu() : addDisabledActionAndSeparator(fileMenu, "Scripts"); addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, appInstance, SLOT(loadDialog())); + addActionToQMenuAndActionHash(fileMenu, MenuOption::StopAllScripts, 0, appInstance, SLOT(stopAllScripts())); + addActionToQMenuAndActionHash(fileMenu, MenuOption::ReloadAllScripts, 0, appInstance, SLOT(reloadAllScripts())); _activeScriptsMenu = fileMenu->addMenu("Running Scripts"); addDisabledActionAndSeparator(fileMenu, "Voxels"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 19e9fbf49f..31b19a64c6 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -243,8 +243,10 @@ namespace MenuOption { const QString PasteVoxels = "Paste"; const QString PasteToVoxel = "Paste to Voxel..."; const QString PipelineWarnings = "Show Render Pipeline Warnings"; + const QString PlaySlaps = "Play Slaps"; const QString Preferences = "Preferences..."; const QString RandomizeVoxelColors = "Randomize Voxel TRUE Colors"; + const QString ReloadAllScripts = "Reload All Scripts"; const QString ResetAvatarSize = "Reset Avatar Size"; const QString ResetSwatchColors = "Reset Swatch Colors"; const QString RunTimingTests = "Run Timing Tests"; @@ -253,11 +255,10 @@ namespace MenuOption { const QString SettingsExport = "Export Settings"; const QString ShowAllLocalVoxels = "Show All Local Voxels"; const QString ShowTrueColors = "Show TRUE Colors"; - const QString VoxelDrumming = "Voxel Drumming"; - const QString PlaySlaps = "Play Slaps"; const QString SuppressShortTimings = "Suppress Timings Less than 10ms"; const QString Stars = "Stars"; const QString Stats = "Stats"; + const QString StopAllScripts = "Stop All Scripts"; const QString TestPing = "Test Ping"; const QString TreeStats = "Calculate Tree Stats"; const QString TransmitterDrive = "Transmitter Drive"; @@ -268,6 +269,7 @@ namespace MenuOption { const QString VoxelAddMode = "Add Voxel Mode"; const QString VoxelColorMode = "Color Voxel Mode"; const QString VoxelDeleteMode = "Delete Voxel Mode"; + const QString VoxelDrumming = "Voxel Drumming"; const QString VoxelGetColorMode = "Get Color Mode"; const QString VoxelMode = "Cycle Voxel Mode"; const QString VoxelPaintColor = "Voxel Paint Color"; From dbd6cb71c9aadc491fa667becf566be2a6fc3d06 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Feb 2014 20:55:16 -0800 Subject: [PATCH 14/15] fixed crash on shutdown with multiple scripts --- libraries/octree/src/OctreeScriptingInterface.cpp | 13 +++++++++++-- libraries/octree/src/OctreeScriptingInterface.h | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/libraries/octree/src/OctreeScriptingInterface.cpp b/libraries/octree/src/OctreeScriptingInterface.cpp index 553ab961df..89bf5ceb62 100644 --- a/libraries/octree/src/OctreeScriptingInterface.cpp +++ b/libraries/octree/src/OctreeScriptingInterface.cpp @@ -11,13 +11,19 @@ #include "OctreeScriptingInterface.h" OctreeScriptingInterface::OctreeScriptingInterface(OctreeEditPacketSender* packetSender, - JurisdictionListener* jurisdictionListener) + JurisdictionListener* jurisdictionListener) : + _packetSender(NULL), + _jurisdictionListener(NULL), + _managedPacketSender(false), + _managedJurisdictionListener(false), + _initialized(false) { setPacketSender(packetSender); setJurisdictionListener(jurisdictionListener); } OctreeScriptingInterface::~OctreeScriptingInterface() { +qDebug() << "OctreeScriptingInterface::~OctreeScriptingInterface() this=" << this; cleanupManagedObjects(); } @@ -45,6 +51,9 @@ void OctreeScriptingInterface::setJurisdictionListener(JurisdictionListener* jur } void OctreeScriptingInterface::init() { + if (_initialized) { + return; + } if (_jurisdictionListener) { _managedJurisdictionListener = false; } else { @@ -64,5 +73,5 @@ void OctreeScriptingInterface::init() { if (QCoreApplication::instance()) { connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(cleanupManagedObjects())); } - + _initialized = true; } diff --git a/libraries/octree/src/OctreeScriptingInterface.h b/libraries/octree/src/OctreeScriptingInterface.h index 34eddd8bed..3c832cbae8 100644 --- a/libraries/octree/src/OctreeScriptingInterface.h +++ b/libraries/octree/src/OctreeScriptingInterface.h @@ -93,6 +93,7 @@ protected: JurisdictionListener* _jurisdictionListener; bool _managedPacketSender; bool _managedJurisdictionListener; + bool _initialized; }; #endif /* defined(__hifi__OctreeScriptingInterface__) */ From cd137b2b12bca1c450fb9eb23db4326e670cfdcf Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Feb 2014 21:00:20 -0800 Subject: [PATCH 15/15] tweak to reload scripts --- interface/src/Application.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 80c2dc7feb..96ace9076a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3991,16 +3991,18 @@ void Application::stopAllScripts() { scriptAction->activate(QAction::Trigger); qDebug() << "stopping script..." << scriptAction->text(); } + _activeScripts.clear(); } void Application::reloadAllScripts() { + // remember all the current scripts so we can reload them + QStringList reloadList = _activeScripts; // reloads all current running scripts QList scriptActions = Menu::getInstance()->getActiveScriptsMenu()->actions(); foreach (QAction* scriptAction, scriptActions) { scriptAction->activate(QAction::Trigger); qDebug() << "stopping script..." << scriptAction->text(); } - QStringList reloadList = _activeScripts; _activeScripts.clear(); foreach (QString scriptName, reloadList){ qDebug() << "reloading script..." << scriptName;