void SkeletonModel::applyPalmData(int jointIndex, const QVector<int>& fingerJointIndices, const QVector<int>& fingertipJointIndices, PalmData& palm) { if (jointIndex == -1) { return; } const FBXGeometry& geometry = _geometry->getFBXGeometry(); float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; glm::quat palmRotation; getJointRotation(jointIndex, palmRotation, true); applyRotationDelta(jointIndex, rotationBetween(palmRotation * geometry.palmDirection, palm.getNormal()), false); getJointRotation(jointIndex, palmRotation, true); // sort the finger indices by raw x, get the average direction QVector<IndexValue> fingerIndices; glm::vec3 direction; for (size_t i = 0; i < palm.getNumFingers(); i++) { glm::vec3 fingerVector = palm.getFingers()[i].getTipPosition() - palm.getPosition(); float length = glm::length(fingerVector); if (length > EPSILON) { direction += fingerVector / length; } fingerVector = glm::inverse(palmRotation) * fingerVector * -sign; IndexValue indexValue = { i, atan2f(fingerVector.z, fingerVector.x) }; fingerIndices.append(indexValue); } qSort(fingerIndices.begin(), fingerIndices.end()); // rotate palm according to average finger direction float directionLength = glm::length(direction); 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), false); getJointRotation(jointIndex, palmRotation, true); } // no point in continuing if there are no fingers if (palm.getNumFingers() == 0 || fingerJointIndices.isEmpty()) { stretchArm(jointIndex, palm.getPosition()); return; } // match them up as best we can 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); } stretchArm(jointIndex, palm.getPosition()); }
void SkeletonModel::applyPalmData(int jointIndex, const QVector<int>& fingerJointIndices, const QVector<int>& fingertipJointIndices, PalmData& palm) { if (jointIndex == -1) { return; } const FBXGeometry& geometry = _geometry->getFBXGeometry(); float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; int parentJointIndex = geometry.joints.at(jointIndex).parentIndex; if (parentJointIndex == -1) { return; } // rotate forearm to align with palm direction glm::quat palmRotation; getJointRotation(parentJointIndex, palmRotation, true); applyRotationDelta(parentJointIndex, rotationBetween(palmRotation * geometry.palmDirection, palm.getNormal()), false); getJointRotation(parentJointIndex, palmRotation, true); // sort the finger indices by raw x, get the average direction QVector<IndexValue> fingerIndices; glm::vec3 direction; for (size_t i = 0; i < palm.getNumFingers(); i++) { glm::vec3 fingerVector = palm.getFingers()[i].getTipPosition() - palm.getPosition(); float length = glm::length(fingerVector); if (length > EPSILON) { direction += fingerVector / length; } fingerVector = glm::inverse(palmRotation) * fingerVector * -sign; IndexValue indexValue = { (int)i, atan2f(fingerVector.z, fingerVector.x) }; fingerIndices.append(indexValue); } qSort(fingerIndices.begin(), fingerIndices.end()); // rotate forearm according to average finger direction float directionLength = glm::length(direction); const unsigned int MIN_ROTATION_FINGERS = 3; if (directionLength > EPSILON && palm.getNumFingers() >= MIN_ROTATION_FINGERS) { applyRotationDelta(parentJointIndex, rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction), false); getJointRotation(parentJointIndex, palmRotation, true); } // let wrist inherit forearm rotation _jointStates[jointIndex].rotation = glm::quat(); // set elbow position from wrist position glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f); setJointPosition(parentJointIndex, palm.getPosition() + forearmVector * geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale)); }
void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return; } const FBXGeometry& geometry = _geometry->getFBXGeometry(); float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; int parentJointIndex = geometry.joints.at(jointIndex).parentIndex; if (parentJointIndex == -1) { return; } // rotate palm to align with its normal (normal points out of hand's palm) glm::quat inverseRotation = glm::inverse(_rotation); glm::vec3 palmPosition = inverseRotation * (palm.getPosition() - _translation); glm::vec3 palmNormal = inverseRotation * palm.getNormal(); glm::vec3 fingerDirection = inverseRotation * palm.getFingerDirection(); glm::quat palmRotation = rotationBetween(geometry.palmDirection, palmNormal); palmRotation = rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), fingerDirection) * palmRotation; if (Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK)) { setHandPosition(jointIndex, palmPosition, palmRotation); } else if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { float forearmLength = geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale); glm::vec3 forearm = palmRotation * glm::vec3(sign * forearmLength, 0.0f, 0.0f); setJointPosition(parentJointIndex, palmPosition + forearm, glm::quat(), false, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); JointState& parentState = _jointStates[parentJointIndex]; parentState.setRotationInBindFrame(palmRotation, PALM_PRIORITY); // lock hand to forearm by slamming its rotation (in parent-frame) to identity _jointStates[jointIndex].setRotationInConstrainedFrame(glm::quat(), PALM_PRIORITY); } else { inverseKinematics(jointIndex, palmPosition, palmRotation, PALM_PRIORITY); } }
void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { if (jointIndex == -1) { return; } const FBXGeometry& geometry = _geometry->getFBXGeometry(); float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; int parentJointIndex = geometry.joints.at(jointIndex).parentIndex; if (parentJointIndex == -1) { return; } // rotate palm to align with its normal (normal points out of hand's palm) glm::quat palmRotation; if (!Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK) && Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { getJointRotation(parentJointIndex, palmRotation, true); } else { getJointRotation(jointIndex, palmRotation, true); } palmRotation = rotationBetween(palmRotation * geometry.palmDirection, palm.getNormal()) * palmRotation; // rotate palm to align with finger direction glm::vec3 direction = palm.getFingerDirection(); palmRotation = rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction) * palmRotation; // set hand position, rotation if (Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK)) { setHandPosition(jointIndex, palm.getPosition(), palmRotation); } else if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f); setJointPosition(parentJointIndex, palm.getPosition() + forearmVector * geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale)); setJointRotation(parentJointIndex, palmRotation, true); _jointStates[jointIndex].rotation = glm::quat(); } else { setJointPosition(jointIndex, palm.getPosition(), palmRotation, true); } }