From a36f9d52afc49e4ec6466cd9742d0f3c43a1136a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 12 Nov 2013 15:43:11 -0800 Subject: [PATCH 1/8] Constraint fix, apply constraints to wrists. --- interface/src/avatar/SkeletonModel.cpp | 7 +++--- interface/src/renderer/FBXReader.cpp | 31 ++++++++++++++++++++++---- interface/src/renderer/Model.cpp | 30 ++++++++++++------------- interface/src/renderer/Model.h | 3 ++- 4 files changed, 48 insertions(+), 23 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index f3603e011c..c42554becd 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -141,7 +141,8 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; glm::quat palmRotation; getJointRotation(jointIndex, palmRotation, true); - palmRotation = rotationBetween(palmRotation * geometry.palmDirection, palm.getNormal()) * palmRotation; + applyRotationDelta(jointIndex, rotationBetween(palmRotation * geometry.palmDirection, palm.getNormal())); + getJointRotation(jointIndex, palmRotation, true); // sort the finger indices by raw x, get the average direction QVector fingerIndices; @@ -161,9 +162,9 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin // rotate palm according to average finger direction float directionLength = glm::length(direction); if (directionLength > EPSILON) { - palmRotation = rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction) * palmRotation; + applyRotationDelta(jointIndex, rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction)); + getJointRotation(jointIndex, palmRotation, true); } - setJointRotation(jointIndex, palmRotation, true); // no point in continuing if there are no fingers if (palm.getNumFingers() == 0 || fingerJointIndices.isEmpty()) { diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 042692c3e1..46a677c516 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -875,9 +875,10 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) glm::vec3 preRotation, rotation, postRotation; glm::vec3 scale = glm::vec3(1.0f, 1.0f, 1.0f); glm::vec3 scalePivot, rotationPivot; + bool rotationMinX = false, rotationMinY = false, rotationMinZ = false; + bool rotationMaxX = false, rotationMaxY = false, rotationMaxZ = false; + glm::vec3 rotationMin, rotationMax; FBXModel model = { name, -1 }; - model.rotationMin = glm::vec3(-180.0f, -180.0f, -180.0f); - model.rotationMax = glm::vec3(180.0f, 180.0f, 180.0f); foreach (const FBXNode& subobject, object.children) { bool properties = false; QByteArray propertyName; @@ -920,10 +921,28 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) scale = getVec3(property.properties, index); } else if (property.properties.at(0) == "RotationMin") { - model.rotationMin = getVec3(property.properties, index); + rotationMin = getVec3(property.properties, index); } else if (property.properties.at(0) == "RotationMax") { - model.rotationMax = getVec3(property.properties, index); + rotationMax = getVec3(property.properties, index); + + } else if (property.properties.at(0) == "RotationMinX") { + rotationMinX = property.properties.at(index).toBool(); + + } else if (property.properties.at(0) == "RotationMinY") { + rotationMinY = property.properties.at(index).toBool(); + + } else if (property.properties.at(0) == "RotationMinZ") { + rotationMinZ = property.properties.at(index).toBool(); + + } else if (property.properties.at(0) == "RotationMaxX") { + rotationMaxX = property.properties.at(index).toBool(); + + } else if (property.properties.at(0) == "RotationMaxY") { + rotationMaxY = property.properties.at(index).toBool(); + + } else if (property.properties.at(0) == "RotationMaxZ") { + rotationMaxZ = property.properties.at(index).toBool(); } } } @@ -940,6 +959,10 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) model.postRotation = glm::quat(glm::radians(postRotation)); model.postTransform = glm::translate(-rotationPivot) * glm::translate(scalePivot) * glm::scale(scale) * glm::translate(-scalePivot); + model.rotationMin = glm::vec3(rotationMinX ? rotationMin.x : -180.0f, + rotationMinY ? rotationMin.y : -180.0f, rotationMinZ ? rotationMin.z : -180.0f); + model.rotationMax = glm::vec3(rotationMaxX ? rotationMax.x : 180.0f, + rotationMaxY ? rotationMax.y : 180.0f, rotationMaxZ ? rotationMax.z : 180.0f); models.insert(getID(object.properties), model); } else if (object.name == "Texture") { diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index cadffe448d..a5c4a1e9c5 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -686,6 +686,21 @@ float Model::getLimbLength(int jointIndex) const { return length; } +void Model::applyRotationDelta(int jointIndex, const glm::quat& delta) { + JointState& state = _jointStates[jointIndex]; + const FBXJoint& joint = _geometry->getFBXGeometry().joints[jointIndex]; + if (joint.rotationMin == glm::vec3(-180.0f, -180.0f, -180.0f) && joint.rotationMax == glm::vec3(180.0f, 180.0f, 180.0f)) { + // no constraints + state.rotation = state.rotation * glm::inverse(state.combinedRotation) * delta * state.combinedRotation; + state.combinedRotation = delta * state.combinedRotation; + return; + } + glm::quat newRotation = glm::quat(glm::radians(glm::clamp(safeEulerAngles(state.rotation * + glm::inverse(state.combinedRotation) * delta * state.combinedRotation), joint.rotationMin, joint.rotationMax))); + state.combinedRotation = state.combinedRotation * glm::inverse(state.rotation) * newRotation; + state.rotation = newRotation; +} + void Model::setJointTranslation(int jointIndex, int parentIndex, int childIndex, const glm::vec3& translation) { const FBXGeometry& geometry = _geometry->getFBXGeometry(); JointState& state = _jointStates[jointIndex]; @@ -705,21 +720,6 @@ void Model::setJointTranslation(int jointIndex, int parentIndex, int childIndex, ::setTranslation(state.transform, translation); } -void Model::applyRotationDelta(int jointIndex, const glm::quat& delta) { - JointState& state = _jointStates[jointIndex]; - const FBXJoint& joint = _geometry->getFBXGeometry().joints[jointIndex]; - if (joint.rotationMin == glm::vec3(-180.0f, -180.0f, -180.0f) && joint.rotationMax == glm::vec3(180.0f, 180.0f, 180.0f)) { - // no constraints - state.rotation = state.rotation * glm::inverse(state.combinedRotation) * delta * state.combinedRotation; - state.combinedRotation = delta * state.combinedRotation; - return; - } - glm::quat newRotation = glm::quat(glm::radians(glm::clamp(safeEulerAngles(state.rotation * - glm::inverse(state.combinedRotation) * delta * state.combinedRotation), joint.rotationMin, joint.rotationMax))); - state.combinedRotation = state.combinedRotation * glm::inverse(state.rotation) * newRotation; - state.rotation = newRotation; -} - void Model::deleteGeometry() { foreach (Model* attachment, _attachments) { delete attachment; diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index c99788b03f..327baa6b6b 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -156,10 +156,11 @@ protected: /// first free ancestor. float getLimbLength(int jointIndex) const; + void applyRotationDelta(int jointIndex, const glm::quat& delta); + private: void setJointTranslation(int jointIndex, int parentIndex, int childIndex, const glm::vec3& translation); - void applyRotationDelta(int jointIndex, const glm::quat& delta); void deleteGeometry(); From c2e4a70685c154b1dbf0cf7ffb2105fa8edb0e09 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 13 Nov 2013 10:35:20 -0800 Subject: [PATCH 2/8] Back to the cyclic coordinate descent algorithm (easier to apply joint constraints); Leap hands relative to eyes. --- interface/src/avatar/Avatar.cpp | 9 ++-- interface/src/avatar/Hand.cpp | 2 +- interface/src/renderer/Model.cpp | 81 ++++++++++++-------------------- 3 files changed, 36 insertions(+), 56 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 929b5b600b..0f07e3a0ff 100755 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -665,14 +665,15 @@ void Avatar::updateArmIKAndConstraints(float deltaTime, AvatarJointID fingerTipJ float distance = glm::length(armVector); // don't let right hand get dragged beyond maximum arm length... + float armLength = _skeletonModel.isActive() ? _skeletonModel.getRightArmLength() : _skeleton.getArmLength(); const float ARM_RETRACTION = 0.75f; - float armLength = _maxArmLength * ARM_RETRACTION; - if (distance > armLength) { + float retractedArmLength = armLength * ARM_RETRACTION; + if (distance > retractedArmLength) { // reset right hand to be constrained to maximum arm length fingerJoint.position = shoulderJoint.position; glm::vec3 armNormal = armVector / distance; - armVector = armNormal * armLength; - distance = armLength; + armVector = armNormal * retractedArmLength; + distance = retractedArmLength; glm::vec3 constrainedPosition = shoulderJoint.position; constrainedPosition += armVector; fingerJoint.position = constrainedPosition; diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index a9397913bb..d1d952e0c8 100755 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -66,7 +66,7 @@ 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 Head& head = _owningAvatar->getHead(); - _basePosition = head.getPosition() + head.getOrientation() * leapHandsOffsetFromFace; + _basePosition = head.calculateAverageEyePosition() + head.getOrientation() * leapHandsOffsetFromFace * head.getScale(); _baseOrientation = head.getOrientation(); // generate finger tip balls.... diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index a5c4a1e9c5..ca555adaba 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -594,58 +594,36 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int last if (lastFreeIndex == -1) { lastFreeIndex = freeLineage.last(); } - - // this is a constraint relaxation algorithm: see - // http://www.ryanjuckett.com/programming/animation/22-constraint-relaxation-ik-in-2d - - // the influence of gravity; lowers the potential energy of our configurations - glm::vec3 gravity = _rotation * IDENTITY_UP * -0.01f; - - // over one or more iterations, apply the length constraints and update the rotations accordingly - float uniformScale = (_scale.x + _scale.y + _scale.z) / 3.0f; - const int ITERATION_COUNT = 3; - for (int i = 0; i < ITERATION_COUNT; i++) { - // start by optimistically setting the position of the end joint to our target - setJointTranslation(jointIndex, freeLineage.at(1), -1, relativePosition); - - for (int j = 1; freeLineage.at(j - 1) != lastFreeIndex; j++) { - int sourceIndex = freeLineage.at(j); - int destIndex = freeLineage.at(j - 1); - JointState& sourceState = _jointStates[sourceIndex]; - JointState& destState = _jointStates[destIndex]; - glm::vec3 sourceTranslation = extractTranslation(sourceState.transform); - glm::vec3 destTranslation = extractTranslation(destState.transform); - glm::vec3 boneVector = destTranslation - sourceTranslation; - float boneLength = glm::length(boneVector); - if (boneLength < EPSILON) { - continue; - } - float extension = geometry.joints.at(destIndex).distanceToParent * uniformScale / boneLength - 1.0f; - if (fabs(extension) < EPSILON) { - continue; - } - if (j == 1) { - setJointTranslation(sourceIndex, freeLineage.at(j + 1), -1, - sourceTranslation - boneVector * extension + gravity); - - } else if (sourceIndex == lastFreeIndex) { - setJointTranslation(destIndex, -1, freeLineage.at(j - 2), - destTranslation + boneVector * extension + gravity); - } else { - setJointTranslation(sourceIndex, freeLineage.at(j + 1), -1, - sourceTranslation - boneVector * extension * 0.5f + gravity); - setJointTranslation(destIndex, -1, freeLineage.at(j - 2), - destTranslation + boneVector * extension * 0.5f + gravity); + // this is a cyclic coordinate descent algorithm: see + // http://www.ryanjuckett.com/programming/animation/21-cyclic-coordinate-descent-in-2d + const int ITERATION_COUNT = 1; + for (int i = 0; i < ITERATION_COUNT; i++) { + // first, we go from the joint upwards, rotating the end as close as possible to the target + glm::vec3 endPosition = extractTranslation(_jointStates[jointIndex].transform); + for (int j = 1; freeLineage.at(j - 1) != lastFreeIndex; j++) { + int index = freeLineage.at(j); + if (glm::distance(endPosition, relativePosition) < EPSILON) { + return true; // close enough to target position } - } - - // now update the joint states from the top - for (int j = freeLineage.size() - 1; j >= 0; j--) { - updateJointState(freeLineage.at(j)); - } + const FBXJoint& joint = geometry.joints.at(index); + if (!joint.isFree) { + continue; + } + JointState& state = _jointStates[index]; + glm::vec3 jointPosition = extractTranslation(state.transform); + glm::vec3 jointVector = endPosition - jointPosition; + glm::quat oldCombinedRotation = state.combinedRotation; + applyRotationDelta(index, rotationBetween(jointVector, relativePosition - jointPosition)); + endPosition = state.combinedRotation * glm::inverse(oldCombinedRotation) * jointVector + jointPosition; + } } - + + // now update the joint states from the top + for (int j = freeLineage.size() - 1; j >= 0; j--) { + updateJointState(freeLineage.at(j)); + } + return true; } @@ -679,9 +657,10 @@ float Model::getLimbLength(int jointIndex) const { } const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& freeLineage = geometry.joints.at(jointIndex).freeLineage; - int length = 0.0f; + float length = 0.0f; + float lengthScale = (_scale.x + _scale.y + _scale.z) / 3.0f; for (int i = freeLineage.size() - 2; i >= 0; i--) { - length += geometry.joints.at(freeLineage.at(i)).distanceToParent; + length += geometry.joints.at(freeLineage.at(i)).distanceToParent * lengthScale; } return length; } From d87dccd614996af6adf936514e2f4ec817fdfe93 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 13 Nov 2013 12:06:08 -0800 Subject: [PATCH 3/8] Alignment to pull elbows towards ground. --- interface/src/renderer/Model.cpp | 21 +++++++++++++++++---- interface/src/renderer/Model.h | 3 ++- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index ca555adaba..ac60f98af7 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -584,7 +584,7 @@ bool Model::getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind) return true; } -bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int lastFreeIndex) { +bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int lastFreeIndex, const glm::vec3& alignment) { if (jointIndex == -1 || _jointStates.isEmpty()) { return false; } @@ -598,14 +598,12 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int last // this is a cyclic coordinate descent algorithm: see // http://www.ryanjuckett.com/programming/animation/21-cyclic-coordinate-descent-in-2d const int ITERATION_COUNT = 1; + glm::vec3 worldAlignment = _rotation * alignment; for (int i = 0; i < ITERATION_COUNT; i++) { // first, we go from the joint upwards, rotating the end as close as possible to the target glm::vec3 endPosition = extractTranslation(_jointStates[jointIndex].transform); for (int j = 1; freeLineage.at(j - 1) != lastFreeIndex; j++) { int index = freeLineage.at(j); - if (glm::distance(endPosition, relativePosition) < EPSILON) { - return true; // close enough to target position - } const FBXJoint& joint = geometry.joints.at(index); if (!joint.isFree) { continue; @@ -616,6 +614,21 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int last glm::quat oldCombinedRotation = state.combinedRotation; applyRotationDelta(index, rotationBetween(jointVector, relativePosition - jointPosition)); endPosition = state.combinedRotation * glm::inverse(oldCombinedRotation) * jointVector + jointPosition; + if (alignment != glm::vec3() && j > 1) { + jointVector = endPosition - jointPosition; + glm::vec3 positionSum; + for (int k = j - 1; k > 0; k--) { + int index = freeLineage.at(k); + updateJointState(index); + positionSum += extractTranslation(_jointStates.at(index).transform); + } + glm::vec3 projectedCenterOfMass = glm::cross(jointVector, + glm::cross(positionSum / (j - 1.0f) - jointPosition, jointVector)); + glm::vec3 projectedAlignment = glm::cross(jointVector, glm::cross(worldAlignment, jointVector)); + if (glm::length(projectedCenterOfMass) > EPSILON && glm::length(projectedAlignment) > EPSILON) { + applyRotationDelta(index, rotationBetween(projectedCenterOfMass, projectedAlignment)); + } + } } } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 327baa6b6b..d1068bf0d6 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -143,7 +143,8 @@ protected: bool getJointPosition(int jointIndex, glm::vec3& position) const; bool getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind = false) const; - bool setJointPosition(int jointIndex, const glm::vec3& position, int lastFreeIndex = -1); + bool setJointPosition(int jointIndex, const glm::vec3& position, int lastFreeIndex = -1, + const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f)); bool setJointRotation(int jointIndex, const glm::quat& rotation, bool fromBind = false); /// Restores the indexed joint to its default position. From 332de0646d7ef431113251091a710ba338c87722 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 13 Nov 2013 12:22:54 -0800 Subject: [PATCH 4/8] Orient the Leap hands relative to the body, not the head. --- interface/src/avatar/Hand.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index d1d952e0c8..5f2abd45a3 100755 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -66,9 +66,9 @@ 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 Head& head = _owningAvatar->getHead(); - _basePosition = head.calculateAverageEyePosition() + head.getOrientation() * leapHandsOffsetFromFace * head.getScale(); - _baseOrientation = head.getOrientation(); - + _baseOrientation = _owningAvatar->getOrientation(); + _basePosition = head.calculateAverageEyePosition() + _baseOrientation * leapHandsOffsetFromFace * head.getScale(); + // generate finger tip balls.... _leapFingerTipBalls.clear(); for (size_t i = 0; i < getNumPalms(); ++i) { From 52a3071cb3e0fd7049458e7d5f2233c3f7bb4404 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 13 Nov 2013 12:29:43 -0800 Subject: [PATCH 5/8] Order of update fix. --- interface/src/avatar/Avatar.cpp | 2 +- interface/src/avatar/Hand.cpp | 4 ++-- interface/src/avatar/MyAvatar.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 0f07e3a0ff..8e8225200d 100755 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -390,6 +390,7 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { } } + _hand.simulate(deltaTime, false); _skeletonModel.simulate(deltaTime); _head.setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll)); glm::vec3 headPosition; @@ -399,7 +400,6 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { _head.setPosition(headPosition); _head.setSkinColor(glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2])); _head.simulate(deltaTime, false); - _hand.simulate(deltaTime, false); // use speed and angular velocity to determine walking vs. standing if (_speed + fabs(_bodyYawDelta) > 0.2) { diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 5f2abd45a3..2ee8aad4ae 100755 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -51,6 +51,8 @@ void Hand::reset() { void Hand::simulate(float deltaTime, bool isMine) { + + calculateGeometry(); if (_isRaveGloveActive) { if (_raveGloveEffectsModeChanged && _raveGloveInitialized) { @@ -136,8 +138,6 @@ void Hand::render(bool lookingInMirror) { _renderAlpha = 1.0; _lookingInMirror = lookingInMirror; - calculateGeometry(); - if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayLeapHands)) { if (!isRaveGloveActive()) { renderLeapFingerTrails(); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 82bbb281af..3ce54d7032 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -320,6 +320,7 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) { } } + _hand.simulate(deltaTime, true); _skeletonModel.simulate(deltaTime); _head.setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll)); glm::vec3 headPosition; @@ -330,7 +331,6 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) { _head.setScale(_scale); _head.setSkinColor(glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2])); _head.simulate(deltaTime, true); - _hand.simulate(deltaTime, true); const float WALKING_SPEED_THRESHOLD = 0.2f; // use speed and angular velocity to determine walking vs. standing From 3e4c5f84ed16b5b8c6f59dc45fc5796df1dc3fb3 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 13 Nov 2013 13:26:36 -0800 Subject: [PATCH 6/8] Only rotate if we have at least three active fingers. --- interface/src/avatar/SkeletonModel.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index c42554becd..64288effc4 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -161,7 +161,8 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin // rotate palm according to average finger direction float directionLength = glm::length(direction); - if (directionLength > EPSILON) { + const int MIN_ROTATION_FINGERS = 3; + if (directionLength > EPSILON && palm.getNumFingers() >= MIN_ROTATION_FINGERS) { applyRotationDelta(jointIndex, rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction)); getJointRotation(jointIndex, palmRotation, true); } From 76d8bd0a9cc54453f9c0c82956977e29a08fb522 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 13 Nov 2013 13:53:41 -0800 Subject: [PATCH 7/8] Finger IK, take two. --- interface/src/avatar/SkeletonModel.cpp | 9 ++------- interface/src/renderer/Model.cpp | 8 +++++--- interface/src/renderer/Model.h | 2 +- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 64288effc4..bf4e2bb65b 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -176,15 +176,10 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin float proportion = fingerIndices.size() / (float)fingerJointIndices.size(); for (int i = 0; i < fingerJointIndices.size(); i++) { int fingerIndex = fingerIndices.at(roundf(i * proportion)).index; - glm::vec3 fingerVector = palm.getFingers()[fingerIndex].getTipPosition() - - palm.getFingers()[fingerIndex].getRootPosition(); - int fingerJointIndex = fingerJointIndices.at(i); int fingertipJointIndex = fingertipJointIndices.at(i); - glm::vec3 jointVector = extractTranslation(geometry.joints.at(fingertipJointIndex).bindTransform) - - extractTranslation(geometry.joints.at(fingerJointIndex).bindTransform); - - setJointRotation(fingerJointIndex, rotationBetween(palmRotation * jointVector, fingerVector) * palmRotation, true); + setJointPosition(fingertipJointIndex, palm.getFingers()[fingerIndex].getTipPosition(), + fingerJointIndex, true, -palm.getNormal()); } } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index ac60f98af7..ac6f2c4c47 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -584,7 +584,8 @@ bool Model::getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind) return true; } -bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int lastFreeIndex, const glm::vec3& alignment) { +bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int lastFreeIndex, + bool allIntermediatesFree, const glm::vec3& alignment) { if (jointIndex == -1 || _jointStates.isEmpty()) { return false; } @@ -605,7 +606,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int last for (int j = 1; freeLineage.at(j - 1) != lastFreeIndex; j++) { int index = freeLineage.at(j); const FBXJoint& joint = geometry.joints.at(index); - if (!joint.isFree) { + if (!(joint.isFree || allIntermediatesFree)) { continue; } JointState& state = _jointStates[index]; @@ -625,7 +626,8 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int last glm::vec3 projectedCenterOfMass = glm::cross(jointVector, glm::cross(positionSum / (j - 1.0f) - jointPosition, jointVector)); glm::vec3 projectedAlignment = glm::cross(jointVector, glm::cross(worldAlignment, jointVector)); - if (glm::length(projectedCenterOfMass) > EPSILON && glm::length(projectedAlignment) > EPSILON) { + const float LENGTH_EPSILON = 0.001f; + if (glm::length(projectedCenterOfMass) > LENGTH_EPSILON && glm::length(projectedAlignment) > LENGTH_EPSILON) { applyRotationDelta(index, rotationBetween(projectedCenterOfMass, projectedAlignment)); } } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index d1068bf0d6..44ac7971a5 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -144,7 +144,7 @@ protected: bool getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind = false) const; bool setJointPosition(int jointIndex, const glm::vec3& position, int lastFreeIndex = -1, - const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f)); + bool allIntermediatesFree = false, const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f)); bool setJointRotation(int jointIndex, const glm::quat& rotation, bool fromBind = false); /// Restores the indexed joint to its default position. From c76af1ca12fa40c7863f12ea40580dfcb1728537 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 13 Nov 2013 13:58:14 -0800 Subject: [PATCH 8/8] Scratch that; didn't work. --- interface/src/avatar/SkeletonModel.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index bf4e2bb65b..64288effc4 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -176,10 +176,15 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin float proportion = fingerIndices.size() / (float)fingerJointIndices.size(); for (int i = 0; i < fingerJointIndices.size(); i++) { int fingerIndex = fingerIndices.at(roundf(i * proportion)).index; + glm::vec3 fingerVector = palm.getFingers()[fingerIndex].getTipPosition() - + palm.getFingers()[fingerIndex].getRootPosition(); + int fingerJointIndex = fingerJointIndices.at(i); int fingertipJointIndex = fingertipJointIndices.at(i); - setJointPosition(fingertipJointIndex, palm.getFingers()[fingerIndex].getTipPosition(), - fingerJointIndex, true, -palm.getNormal()); + glm::vec3 jointVector = extractTranslation(geometry.joints.at(fingertipJointIndex).bindTransform) - + extractTranslation(geometry.joints.at(fingerJointIndex).bindTransform); + + setJointRotation(fingerJointIndex, rotationBetween(palmRotation * jointVector, fingerVector) * palmRotation, true); } }