Simplify passing data from MySkeletonModel to Rig

This commit is contained in:
Anthony J. Thibault 2017-06-19 16:54:39 -07:00
parent 6bbc5bfbea
commit c236afe68c
4 changed files with 407 additions and 390 deletions

View file

@ -47,110 +47,113 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar); MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar);
Rig::HeadParameters headParams; Rig::ControllerParameters params;
AnimPose avatarToRigPose(glm::vec3(1.0f), Quaternions::Y_180, glm::vec3(0.0f));
// input action is the highest priority source for head orientation. // input action is the highest priority source for head orientation.
auto avatarHeadPose = myAvatar->getHeadControllerPoseInAvatarFrame(); auto avatarHeadPose = myAvatar->getHeadControllerPoseInAvatarFrame();
if (avatarHeadPose.isValid()) { if (avatarHeadPose.isValid()) {
glm::mat4 rigHeadMat = Matrices::Y_180 * AnimPose pose(avatarHeadPose.getRotation(), avatarHeadPose.getTranslation());
createMatFromQuatAndPos(avatarHeadPose.getRotation(), avatarHeadPose.getTranslation()); params.controllerPoses[Rig::ControllerType_Head] = avatarToRigPose * pose;
headParams.rigHeadPosition = extractTranslation(rigHeadMat); params.controllerActiveFlags[Rig::ControllerType_Head] = true;
headParams.rigHeadOrientation = glmExtractRotation(rigHeadMat);
headParams.headEnabled = true;
} else { } else {
// even though full head IK is disabled, the rig still needs the head orientation to rotate the head up and // even though full head IK is disabled, the rig still needs the head orientation to rotate the head up and
// down in desktop mode. // down in desktop mode.
// preMult 180 is necessary to convert from avatar to rig coordinates. // preMult 180 is necessary to convert from avatar to rig coordinates.
// postMult 180 is necessary to convert head from -z forward to z forward. // postMult 180 is necessary to convert head from -z forward to z forward.
headParams.rigHeadOrientation = Quaternions::Y_180 * head->getFinalOrientationInLocalFrame() * Quaternions::Y_180; glm::quat headRot = Quaternions::Y_180 * head->getFinalOrientationInLocalFrame() * Quaternions::Y_180;
headParams.headEnabled = false; params.controllerPoses[Rig::ControllerType_Head] = AnimPose(glm::vec3(1.0f), headRot, glm::vec3(0.0f));
params.controllerActiveFlags[Rig::ControllerType_Head] = false;
} }
auto avatarHipsPose = myAvatar->getHipsControllerPoseInAvatarFrame(); auto avatarHipsPose = myAvatar->getHipsControllerPoseInAvatarFrame();
if (avatarHipsPose.isValid()) { if (avatarHipsPose.isValid()) {
glm::mat4 rigHipsMat = Matrices::Y_180 * createMatFromQuatAndPos(avatarHipsPose.getRotation(), avatarHipsPose.getTranslation()); AnimPose pose(avatarHipsPose.getRotation(), avatarHipsPose.getTranslation());
headParams.hipsMatrix = rigHipsMat; params.controllerPoses[Rig::ControllerType_Hips] = avatarToRigPose * pose;
headParams.hipsEnabled = true; params.controllerActiveFlags[Rig::ControllerType_Hips] = true;
} else { } else {
headParams.hipsEnabled = false; params.controllerPoses[Rig::ControllerType_Hips] = AnimPose::identity;
params.controllerActiveFlags[Rig::ControllerType_Hips] = false;
} }
auto avatarSpine2Pose = myAvatar->getSpine2ControllerPoseInAvatarFrame(); auto avatarSpine2Pose = myAvatar->getSpine2ControllerPoseInAvatarFrame();
if (avatarSpine2Pose.isValid()) { if (avatarSpine2Pose.isValid()) {
glm::mat4 rigSpine2Mat = Matrices::Y_180 * createMatFromQuatAndPos(avatarSpine2Pose.getRotation(), avatarSpine2Pose.getTranslation()); AnimPose pose(avatarSpine2Pose.getRotation(), avatarSpine2Pose.getTranslation());
headParams.spine2Matrix = rigSpine2Mat; params.controllerPoses[Rig::ControllerType_Spine2] = avatarToRigPose * pose;
headParams.spine2Enabled = true; params.controllerActiveFlags[Rig::ControllerType_Spine2] = true;
} else { } else {
headParams.spine2Enabled = false; params.controllerPoses[Rig::ControllerType_Spine2] = AnimPose::identity;
params.controllerActiveFlags[Rig::ControllerType_Spine2] = false;
} }
auto avatarRightArmPose = myAvatar->getRightArmControllerPoseInAvatarFrame(); auto avatarRightArmPose = myAvatar->getRightArmControllerPoseInAvatarFrame();
if (avatarRightArmPose.isValid()) { if (avatarRightArmPose.isValid()) {
glm::mat4 rightArmMat = Matrices::Y_180 * createMatFromQuatAndPos(avatarRightArmPose.getRotation(), avatarRightArmPose.getTranslation()); AnimPose pose(avatarRightArmPose.getRotation(), avatarRightArmPose.getTranslation());
headParams.rightArmPosition = extractTranslation(rightArmMat); params.controllerPoses[Rig::ControllerType_RightArm] = avatarToRigPose * pose;
headParams.rightArmRotation = glmExtractRotation(rightArmMat); params.controllerActiveFlags[Rig::ControllerType_RightArm] = true;
headParams.rightArmEnabled = true;
} else { } else {
headParams.rightArmEnabled = false; params.controllerPoses[Rig::ControllerType_RightArm] = AnimPose::identity;
params.controllerActiveFlags[Rig::ControllerType_RightArm] = false;
} }
auto avatarLeftArmPose = myAvatar->getLeftArmControllerPoseInAvatarFrame(); auto avatarLeftArmPose = myAvatar->getLeftArmControllerPoseInAvatarFrame();
if (avatarLeftArmPose.isValid()) { if (avatarLeftArmPose.isValid()) {
glm::mat4 leftArmMat = Matrices::Y_180 * createMatFromQuatAndPos(avatarLeftArmPose.getRotation(), avatarLeftArmPose.getTranslation()); AnimPose pose(avatarLeftArmPose.getRotation(), avatarLeftArmPose.getTranslation());
headParams.leftArmPosition = extractTranslation(leftArmMat); params.controllerPoses[Rig::ControllerType_LeftArm] = avatarToRigPose * pose;
headParams.leftArmRotation = glmExtractRotation(leftArmMat); params.controllerActiveFlags[Rig::ControllerType_LeftArm] = true;
headParams.leftArmEnabled = true;
} else { } else {
headParams.leftArmEnabled = false; params.controllerPoses[Rig::ControllerType_LeftArm] = AnimPose::identity;
params.controllerActiveFlags[Rig::ControllerType_LeftArm] = false;
} }
headParams.isTalking = head->getTimeWithoutTalking() <= 1.5f; auto avatarLeftHandPose = myAvatar->getLeftHandControllerPoseInAvatarFrame();
if (avatarLeftHandPose.isValid()) {
_rig.updateFromHeadParameters(headParams, deltaTime); AnimPose pose(avatarLeftHandPose.getRotation(), avatarLeftHandPose.getTranslation());
params.controllerPoses[Rig::ControllerType_LeftHand] = avatarToRigPose * pose;
Rig::HandAndFeetParameters handAndFeetParams; params.controllerActiveFlags[Rig::ControllerType_LeftHand] = true;
auto leftPose = myAvatar->getLeftHandControllerPoseInAvatarFrame();
if (leftPose.isValid()) {
handAndFeetParams.isLeftEnabled = true;
handAndFeetParams.leftPosition = Quaternions::Y_180 * leftPose.getTranslation();
handAndFeetParams.leftOrientation = Quaternions::Y_180 * leftPose.getRotation();
} else { } else {
handAndFeetParams.isLeftEnabled = false; params.controllerPoses[Rig::ControllerType_LeftHand] = AnimPose::identity;
params.controllerActiveFlags[Rig::ControllerType_LeftHand] = false;
} }
auto rightPose = myAvatar->getRightHandControllerPoseInAvatarFrame(); auto avatarRightHandPose = myAvatar->getRightHandControllerPoseInAvatarFrame();
if (rightPose.isValid()) { if (avatarRightHandPose.isValid()) {
handAndFeetParams.isRightEnabled = true; AnimPose pose(avatarRightHandPose.getRotation(), avatarRightHandPose.getTranslation());
handAndFeetParams.rightPosition = Quaternions::Y_180 * rightPose.getTranslation(); params.controllerPoses[Rig::ControllerType_RightHand] = avatarToRigPose * pose;
handAndFeetParams.rightOrientation = Quaternions::Y_180 * rightPose.getRotation(); params.controllerActiveFlags[Rig::ControllerType_RightHand] = true;
} else { } else {
handAndFeetParams.isRightEnabled = false; params.controllerPoses[Rig::ControllerType_RightHand] = AnimPose::identity;
params.controllerActiveFlags[Rig::ControllerType_RightHand] = false;
} }
auto leftFootPose = myAvatar->getLeftFootControllerPoseInAvatarFrame(); auto avatarLeftFootPose = myAvatar->getLeftFootControllerPoseInAvatarFrame();
if (leftFootPose.isValid()) { if (avatarLeftFootPose.isValid()) {
handAndFeetParams.isLeftFootEnabled = true; AnimPose pose(avatarLeftFootPose.getRotation(), avatarLeftFootPose.getTranslation());
handAndFeetParams.leftFootPosition = Quaternions::Y_180 * leftFootPose.getTranslation(); params.controllerPoses[Rig::ControllerType_LeftFoot] = avatarToRigPose * pose;
handAndFeetParams.leftFootOrientation = Quaternions::Y_180 * leftFootPose.getRotation(); params.controllerActiveFlags[Rig::ControllerType_LeftFoot] = true;
} else { } else {
handAndFeetParams.isLeftFootEnabled = false; params.controllerPoses[Rig::ControllerType_LeftFoot] = AnimPose::identity;
params.controllerActiveFlags[Rig::ControllerType_LeftFoot] = false;
} }
auto rightFootPose = myAvatar->getRightFootControllerPoseInAvatarFrame(); auto avatarRightFootPose = myAvatar->getRightFootControllerPoseInAvatarFrame();
if (rightFootPose.isValid()) { if (avatarRightFootPose.isValid()) {
handAndFeetParams.isRightFootEnabled = true; AnimPose pose(avatarRightFootPose.getRotation(), avatarRightFootPose.getTranslation());
handAndFeetParams.rightFootPosition = Quaternions::Y_180 * rightFootPose.getTranslation(); params.controllerPoses[Rig::ControllerType_RightFoot] = avatarToRigPose * pose;
handAndFeetParams.rightFootOrientation = Quaternions::Y_180 * rightFootPose.getRotation(); params.controllerActiveFlags[Rig::ControllerType_RightFoot] = true;
} else { } else {
handAndFeetParams.isRightFootEnabled = false; params.controllerPoses[Rig::ControllerType_RightFoot] = AnimPose::identity;
params.controllerActiveFlags[Rig::ControllerType_RightFoot] = false;
} }
handAndFeetParams.bodyCapsuleRadius = myAvatar->getCharacterController()->getCapsuleRadius(); params.bodyCapsuleRadius = myAvatar->getCharacterController()->getCapsuleRadius();
handAndFeetParams.bodyCapsuleHalfHeight = myAvatar->getCharacterController()->getCapsuleHalfHeight(); params.bodyCapsuleHalfHeight = myAvatar->getCharacterController()->getCapsuleHalfHeight();
handAndFeetParams.bodyCapsuleLocalOffset = myAvatar->getCharacterController()->getCapsuleLocalOffset(); params.bodyCapsuleLocalOffset = myAvatar->getCharacterController()->getCapsuleLocalOffset();
_rig.updateFromHandAndFeetParameters(handAndFeetParams, deltaTime); params.isTalking = head->getTimeWithoutTalking() <= 1.5f;
_rig.updateFromControllerParameters(params, deltaTime);
Rig::CharacterControllerState ccState = convertCharacterControllerState(myAvatar->getCharacterController()->getState()); Rig::CharacterControllerState ccState = convertCharacterControllerState(myAvatar->getCharacterController()->getState());

View file

@ -21,6 +21,8 @@ class AnimPose {
public: public:
AnimPose() {} AnimPose() {}
explicit AnimPose(const glm::mat4& mat); explicit AnimPose(const glm::mat4& mat);
explicit AnimPose(const glm::quat& rotIn) : _scale(1.0f), _rot(rotIn), _trans(0.0f) {}
AnimPose(const glm::quat& rotIn, const glm::vec3& transIn) : _scale(1.0f), _rot(rotIn), _trans(transIn) {}
AnimPose(const glm::vec3& scaleIn, const glm::quat& rotIn, const glm::vec3& transIn) : _scale(scaleIn), _rot(rotIn), _trans(transIn) {} AnimPose(const glm::vec3& scaleIn, const glm::quat& rotIn, const glm::vec3& transIn) : _scale(scaleIn), _rot(rotIn), _trans(transIn) {}
static const AnimPose identity; static const AnimPose identity;

View file

@ -1010,46 +1010,6 @@ glm::quat Rig::getJointDefaultRotationInParentFrame(int jointIndex) {
return glm::quat(); return glm::quat();
} }
void Rig::updateFromHeadParameters(const HeadParameters& params, float dt) {
updateHeadAnimVars(params);
_animVars.set("isTalking", params.isTalking);
_animVars.set("notIsTalking", !params.isTalking);
if (params.hipsEnabled) {
_animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToLimitCenterPoses);
_animVars.set("hipsType", (int)IKTarget::Type::RotationAndPosition);
_animVars.set("hipsPosition", extractTranslation(params.hipsMatrix));
_animVars.set("hipsRotation", glmExtractRotation(params.hipsMatrix));
} else {
_animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToUnderPoses);
_animVars.set("hipsType", (int)IKTarget::Type::Unknown);
}
if (params.hipsEnabled && params.spine2Enabled) {
_animVars.set("spine2Type", (int)IKTarget::Type::Spline);
_animVars.set("spine2Position", extractTranslation(params.spine2Matrix));
_animVars.set("spine2Rotation", glmExtractRotation(params.spine2Matrix));
} else {
_animVars.set("spine2Type", (int)IKTarget::Type::Unknown);
}
if (params.leftArmEnabled) {
_animVars.set("leftArmType", (int)IKTarget::Type::RotationAndPosition);
_animVars.set("leftArmPosition", params.leftArmPosition);
_animVars.set("leftArmRotation", params.leftArmRotation);
} else {
_animVars.set("leftArmType", (int)IKTarget::Type::Unknown);
}
if (params.rightArmEnabled) {
_animVars.set("rightArmType", (int)IKTarget::Type::RotationAndPosition);
_animVars.set("rightArmPosition", params.rightArmPosition);
_animVars.set("rightArmRotation", params.rightArmRotation);
} else {
_animVars.set("rightArmType", (int)IKTarget::Type::Unknown);
}
}
void Rig::updateFromEyeParameters(const EyeParameters& params) { void Rig::updateFromEyeParameters(const EyeParameters& params) {
updateEyeJoint(params.leftEyeJointIndex, params.modelTranslation, params.modelRotation, params.eyeLookAt, params.eyeSaccade); updateEyeJoint(params.leftEyeJointIndex, params.modelTranslation, params.modelRotation, params.eyeLookAt, params.eyeSaccade);
@ -1081,12 +1041,12 @@ void Rig::computeHeadFromHMD(const AnimPose& hmdPose, glm::vec3& headPositionOut
headOrientationOut = hmdOrientation; headOrientationOut = hmdOrientation;
} }
void Rig::updateHeadAnimVars(const HeadParameters& params) { void Rig::updateHead(bool headEnabled, bool hipsEnabled, const AnimPose& headPose) {
if (_animSkeleton) { if (_animSkeleton) {
if (params.headEnabled) { if (headEnabled) {
_animVars.set("headPosition", params.rigHeadPosition); _animVars.set("headPosition", headPose.trans());
_animVars.set("headRotation", params.rigHeadOrientation); _animVars.set("headRotation", headPose.rot());
if (params.hipsEnabled) { if (hipsEnabled) {
// Since there is an explicit hips ik target, switch the head to use the more flexible Spline IK chain type. // Since there is an explicit hips ik target, switch the head to use the more flexible Spline IK chain type.
// this will allow the spine to compress/expand and bend more natrually, ensuring that it can reach the head target position. // this will allow the spine to compress/expand and bend more natrually, ensuring that it can reach the head target position.
_animVars.set("headType", (int)IKTarget::Type::Spline); _animVars.set("headType", (int)IKTarget::Type::Spline);
@ -1099,12 +1059,271 @@ void Rig::updateHeadAnimVars(const HeadParameters& params) {
} }
} else { } else {
_animVars.unset("headPosition"); _animVars.unset("headPosition");
_animVars.set("headRotation", params.rigHeadOrientation); _animVars.set("headRotation", headPose.rot());
_animVars.set("headType", (int)IKTarget::Type::RotationOnly); _animVars.set("headType", (int)IKTarget::Type::RotationOnly);
} }
} }
} }
void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnabled, float dt,
const AnimPose& leftHandPose, const AnimPose& rightHandPose,
float bodyCapsuleRadius, float bodyCapsuleHalfHeight, const glm::vec3& bodyCapsuleLocalOffset) {
// Use this capsule to represent the avatar body.
int hipsIndex = indexOfJoint("Hips");
glm::vec3 hipsTrans;
if (hipsIndex >= 0) {
hipsTrans = _internalPoseSet._absolutePoses[hipsIndex].trans();
}
const glm::vec3 bodyCapsuleCenter = hipsTrans - bodyCapsuleLocalOffset;
const glm::vec3 bodyCapsuleStart = bodyCapsuleCenter - glm::vec3(0, bodyCapsuleHalfHeight, 0);
const glm::vec3 bodyCapsuleEnd = bodyCapsuleCenter + glm::vec3(0, bodyCapsuleHalfHeight, 0);
const float HAND_RADIUS = 0.05f;
const float RELAX_DURATION = 0.6f;
const float CONTROL_DURATION = 0.4f;
const bool TO_CONTROLLED = true;
const bool FROM_CONTROLLED = false;
const bool LEFT_HAND = true;
const bool RIGHT_HAND = false;
const float ELBOW_POLE_VECTOR_BLEND_FACTOR = 0.9f;
if (leftHandEnabled) {
if (!_isLeftHandControlled) {
_leftHandControlTimeRemaining = CONTROL_DURATION;
_isLeftHandControlled = true;
}
glm::vec3 handPosition = leftHandPose.trans();
glm::quat handRotation = leftHandPose.rot();
if (_leftHandControlTimeRemaining > 0.0f) {
// Move hand from non-controlled position to controlled position.
_leftHandControlTimeRemaining = std::max(_leftHandControlTimeRemaining - dt, 0.0f);
AnimPose handPose(Vectors::ONE, handRotation, handPosition);
if (transitionHandPose(_leftHandControlTimeRemaining, CONTROL_DURATION, handPose,
LEFT_HAND, TO_CONTROLLED, handPose)) {
handPosition = handPose.trans();
handRotation = handPose.rot();
}
}
if (!hipsEnabled) {
// prevent the hand IK targets from intersecting the body capsule
glm::vec3 displacement;
if (findSphereCapsulePenetration(handPosition, HAND_RADIUS, bodyCapsuleStart, bodyCapsuleEnd, bodyCapsuleRadius, displacement)) {
handPosition -= displacement;
}
}
_animVars.set("leftHandPosition", handPosition);
_animVars.set("leftHandRotation", handRotation);
_animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition);
_lastLeftHandControlledPose = AnimPose(Vectors::ONE, handRotation, handPosition);
_isLeftHandControlled = true;
// compute pole vector
int handJointIndex = _animSkeleton->nameToJointIndex("LeftHand");
int armJointIndex = _animSkeleton->nameToJointIndex("LeftArm");
int elbowJointIndex = _animSkeleton->nameToJointIndex("LeftForeArm");
if (elbowJointIndex >= 0 && armJointIndex >= 0 && elbowJointIndex >= 0) {
glm::vec3 poleVector = calculateElbowPoleVector(handJointIndex, elbowJointIndex, armJointIndex, hipsIndex, true);
// smooth toward desired pole vector from previous pole vector... to reduce jitter
if (!_prevLeftHandPoleVectorValid) {
_prevLeftHandPoleVectorValid = true;
_prevLeftHandPoleVector = poleVector;
}
glm::quat deltaRot = rotationBetween(_prevLeftHandPoleVector, poleVector);
glm::quat smoothDeltaRot = safeMix(deltaRot, Quaternions::IDENTITY, ELBOW_POLE_VECTOR_BLEND_FACTOR);
_prevLeftHandPoleVector = smoothDeltaRot * _prevLeftHandPoleVector;
_animVars.set("leftHandPoleVectorEnabled", true);
_animVars.set("leftHandPoleReferenceVector", Vectors::UNIT_X);
_animVars.set("leftHandPoleVector", _prevLeftHandPoleVector);
} else {
_prevLeftHandPoleVectorValid = false;
_animVars.set("leftHandPoleVectorEnabled", false);
}
} else {
_prevLeftHandPoleVectorValid = false;
_animVars.set("leftHandPoleVectorEnabled", false);
if (_isLeftHandControlled) {
_leftHandRelaxTimeRemaining = RELAX_DURATION;
_isLeftHandControlled = false;
}
if (_leftHandRelaxTimeRemaining > 0.0f) {
// Move hand from controlled position to non-controlled position.
_leftHandRelaxTimeRemaining = std::max(_leftHandRelaxTimeRemaining - dt, 0.0f);
AnimPose handPose;
if (transitionHandPose(_leftHandRelaxTimeRemaining, RELAX_DURATION, _lastLeftHandControlledPose,
LEFT_HAND, FROM_CONTROLLED, handPose)) {
_animVars.set("leftHandPosition", handPose.trans());
_animVars.set("leftHandRotation", handPose.rot());
_animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition);
}
} else {
_animVars.unset("leftHandPosition");
_animVars.unset("leftHandRotation");
_animVars.set("leftHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition);
}
}
if (rightHandEnabled) {
if (!_isRightHandControlled) {
_rightHandControlTimeRemaining = CONTROL_DURATION;
_isRightHandControlled = true;
}
glm::vec3 handPosition = rightHandPose.trans();
glm::quat handRotation = rightHandPose.rot();
if (_rightHandControlTimeRemaining > 0.0f) {
// Move hand from non-controlled position to controlled position.
_rightHandControlTimeRemaining = std::max(_rightHandControlTimeRemaining - dt, 0.0f);
AnimPose handPose(Vectors::ONE, handRotation, handPosition);
if (transitionHandPose(_rightHandControlTimeRemaining, CONTROL_DURATION, handPose, RIGHT_HAND, TO_CONTROLLED, handPose)) {
handPosition = handPose.trans();
handRotation = handPose.rot();
}
}
if (!hipsEnabled) {
// prevent the hand IK targets from intersecting the body capsule
glm::vec3 displacement;
if (findSphereCapsulePenetration(handPosition, HAND_RADIUS, bodyCapsuleStart, bodyCapsuleEnd, bodyCapsuleRadius, displacement)) {
handPosition -= displacement;
}
}
_animVars.set("rightHandPosition", handPosition);
_animVars.set("rightHandRotation", handRotation);
_animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition);
_lastRightHandControlledPose = AnimPose(Vectors::ONE, handRotation, handPosition);
_isRightHandControlled = true;
// compute pole vector
int handJointIndex = _animSkeleton->nameToJointIndex("RightHand");
int armJointIndex = _animSkeleton->nameToJointIndex("RightArm");
int elbowJointIndex = _animSkeleton->nameToJointIndex("RightForeArm");
if (elbowJointIndex >= 0 && armJointIndex >= 0 && elbowJointIndex >= 0) {
glm::vec3 poleVector = calculateElbowPoleVector(handJointIndex, elbowJointIndex, armJointIndex, hipsIndex, false);
// smooth toward desired pole vector from previous pole vector... to reduce jitter
if (!_prevRightHandPoleVectorValid) {
_prevRightHandPoleVectorValid = true;
_prevRightHandPoleVector = poleVector;
}
glm::quat deltaRot = rotationBetween(_prevRightHandPoleVector, poleVector);
glm::quat smoothDeltaRot = safeMix(deltaRot, Quaternions::IDENTITY, ELBOW_POLE_VECTOR_BLEND_FACTOR);
_prevRightHandPoleVector = smoothDeltaRot * _prevRightHandPoleVector;
_animVars.set("rightHandPoleVectorEnabled", true);
_animVars.set("rightHandPoleReferenceVector", -Vectors::UNIT_X);
_animVars.set("rightHandPoleVector", _prevRightHandPoleVector);
} else {
_prevRightHandPoleVectorValid = false;
_animVars.set("rightHandPoleVectorEnabled", false);
}
} else {
_prevRightHandPoleVectorValid = false;
_animVars.set("rightHandPoleVectorEnabled", false);
if (_isRightHandControlled) {
_rightHandRelaxTimeRemaining = RELAX_DURATION;
_isRightHandControlled = false;
}
if (_rightHandRelaxTimeRemaining > 0.0f) {
// Move hand from controlled position to non-controlled position.
_rightHandRelaxTimeRemaining = std::max(_rightHandRelaxTimeRemaining - dt, 0.0f);
AnimPose handPose;
if (transitionHandPose(_rightHandRelaxTimeRemaining, RELAX_DURATION, _lastRightHandControlledPose, RIGHT_HAND, FROM_CONTROLLED, handPose)) {
_animVars.set("rightHandPosition", handPose.trans());
_animVars.set("rightHandRotation", handPose.rot());
_animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition);
}
} else {
_animVars.unset("rightHandPosition");
_animVars.unset("rightHandRotation");
_animVars.set("rightHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition);
}
}
}
void Rig::updateFeet(bool leftFootEnabled, bool rightFootEnabled, const AnimPose& leftFootPose, const AnimPose& rightFootPose) {
const float KNEE_POLE_VECTOR_BLEND_FACTOR = 0.9f;
int hipsIndex = indexOfJoint("Hips");
if (leftFootEnabled) {
glm::vec3 footPosition = leftFootPose.trans();
glm::quat footRotation = leftFootPose.rot();
_animVars.set("leftFootPosition", footPosition);
_animVars.set("leftFootRotation", footRotation);
_animVars.set("leftFootType", (int)IKTarget::Type::RotationAndPosition);
int footJointIndex = _animSkeleton->nameToJointIndex("LeftFoot");
glm::vec3 poleVector = calculateKneePoleVector(footJointIndex, footRotation, hipsIndex);
// smooth toward desired pole vector from previous pole vector... to reduce jitter
if (!_prevLeftFootPoleVectorValid) {
_prevLeftFootPoleVectorValid = true;
_prevLeftFootPoleVector = poleVector;
}
glm::quat deltaRot = rotationBetween(_prevLeftFootPoleVector, poleVector);
glm::quat smoothDeltaRot = safeMix(deltaRot, Quaternions::IDENTITY, KNEE_POLE_VECTOR_BLEND_FACTOR);
_prevLeftFootPoleVector = smoothDeltaRot * _prevLeftFootPoleVector;
_animVars.set("leftFootPoleVectorEnabled", true);
_animVars.set("leftFootPoleReferenceVector", Vectors::UNIT_Z);
_animVars.set("leftFootPoleVector", _prevLeftFootPoleVector);
} else {
_animVars.unset("leftFootPosition");
_animVars.unset("leftFootRotation");
_animVars.set("leftFootType", (int)IKTarget::Type::RotationAndPosition);
_animVars.set("leftFootPoleVectorEnabled", false);
_prevLeftFootPoleVectorValid = false;
}
if (rightFootEnabled) {
glm::vec3 footPosition = rightFootPose.trans();
glm::quat footRotation = rightFootPose.rot();
_animVars.set("rightFootPosition", footPosition);
_animVars.set("rightFootRotation", footRotation);
_animVars.set("rightFootType", (int)IKTarget::Type::RotationAndPosition);
int footJointIndex = _animSkeleton->nameToJointIndex("RightFoot");
glm::vec3 poleVector = calculateKneePoleVector(footJointIndex, footRotation, hipsIndex);
// smooth toward desired pole vector from previous pole vector... to reduce jitter
if (!_prevRightFootPoleVectorValid) {
_prevRightFootPoleVectorValid = true;
_prevRightFootPoleVector = poleVector;
}
glm::quat deltaRot = rotationBetween(_prevRightFootPoleVector, poleVector);
glm::quat smoothDeltaRot = safeMix(deltaRot, Quaternions::IDENTITY, KNEE_POLE_VECTOR_BLEND_FACTOR);
_prevRightFootPoleVector = smoothDeltaRot * _prevRightFootPoleVector;
_animVars.set("rightFootPoleVectorEnabled", true);
_animVars.set("rightFootPoleReferenceVector", Vectors::UNIT_Z);
_animVars.set("rightFootPoleVector", _prevRightFootPoleVector);
} else {
_animVars.unset("rightFootPosition");
_animVars.unset("rightFootRotation");
_animVars.set("rightFootPoleVectorEnabled", false);
_animVars.set("rightFootType", (int)IKTarget::Type::RotationAndPosition);
}
}
void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::vec3& lookAtSpot, const glm::vec3& saccade) { void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::vec3& lookAtSpot, const glm::vec3& saccade) {
// TODO: does not properly handle avatar scale. // TODO: does not properly handle avatar scale.
@ -1196,261 +1415,65 @@ glm::vec3 Rig::calculateKneePoleVector(int footJointIndex, const glm::quat& foot
return glm::normalize(lerp(footForward, hipsForward, FOOT_TO_HIPS_BLEND_FACTOR)); return glm::normalize(lerp(footForward, hipsForward, FOOT_TO_HIPS_BLEND_FACTOR));
} }
void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, float dt) { void Rig::updateFromControllerParameters(const ControllerParameters& params, float dt) {
if (_animSkeleton && _animNode) { if (!_animSkeleton || !_animNode) {
const float HAND_RADIUS = 0.05f; return;
int hipsIndex = indexOfJoint("Hips"); }
glm::vec3 hipsTrans;
if (hipsIndex >= 0) {
hipsTrans = _internalPoseSet._absolutePoses[hipsIndex].trans();
}
// Use this capsule to represent the avatar body. _animVars.set("isTalking", params.isTalking);
const float bodyCapsuleRadius = params.bodyCapsuleRadius; _animVars.set("notIsTalking", !params.isTalking);
const glm::vec3 bodyCapsuleCenter = hipsTrans - params.bodyCapsuleLocalOffset;
const glm::vec3 bodyCapsuleStart = bodyCapsuleCenter - glm::vec3(0, params.bodyCapsuleHalfHeight, 0);
const glm::vec3 bodyCapsuleEnd = bodyCapsuleCenter + glm::vec3(0, params.bodyCapsuleHalfHeight, 0);
// TODO: add isHipsEnabled bool headEnabled = params.controllerActiveFlags[ControllerType_Head];
bool bodySensorTrackingEnabled = params.isLeftFootEnabled || params.isRightFootEnabled; bool leftHandEnabled = params.controllerActiveFlags[ControllerType_LeftHand];
bool rightHandEnabled = params.controllerActiveFlags[ControllerType_RightHand];
bool hipsEnabled = params.controllerActiveFlags[ControllerType_Hips];
bool leftFootEnabled = params.controllerActiveFlags[ControllerType_LeftFoot];
bool rightFootEnabled = params.controllerActiveFlags[ControllerType_RightFoot];
bool leftArmEnabled = params.controllerActiveFlags[ControllerType_LeftArm];
bool rightArmEnabled = params.controllerActiveFlags[ControllerType_RightArm];
bool spine2Enabled = params.controllerActiveFlags[ControllerType_Spine2];
const float RELAX_DURATION = 0.6f; updateHead(headEnabled, hipsEnabled, params.controllerPoses[ControllerType_Head]);
const float CONTROL_DURATION = 0.4f;
const bool TO_CONTROLLED = true;
const bool FROM_CONTROLLED = false;
const bool LEFT_HAND = true;
const bool RIGHT_HAND = false;
const float KNEE_POLE_VECTOR_BLEND_FACTOR = 0.9f; updateHands(leftHandEnabled, rightHandEnabled, hipsEnabled, dt,
const float ELBOW_POLE_VECTOR_BLEND_FACTOR = 0.9f; params.controllerPoses[ControllerType_LeftHand], params.controllerPoses[ControllerType_RightHand],
params.bodyCapsuleRadius, params.bodyCapsuleHalfHeight, params.bodyCapsuleLocalOffset);
if (params.isLeftEnabled) { updateFeet(leftFootEnabled, rightFootEnabled,
if (!_isLeftHandControlled) { params.controllerPoses[ControllerType_LeftFoot], params.controllerPoses[ControllerType_RightFoot]);
_leftHandControlTimeRemaining = CONTROL_DURATION;
_isLeftHandControlled = true;
}
glm::vec3 handPosition = params.leftPosition; if (hipsEnabled) {
glm::quat handRotation = params.leftOrientation; _animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToLimitCenterPoses);
_animVars.set("hipsType", (int)IKTarget::Type::RotationAndPosition);
_animVars.set("hipsPosition", params.controllerPoses[ControllerType_Hips].trans());
_animVars.set("hipsRotation", params.controllerPoses[ControllerType_Hips].rot());
} else {
_animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToUnderPoses);
_animVars.set("hipsType", (int)IKTarget::Type::Unknown);
}
if (_leftHandControlTimeRemaining > 0.0f) { if (hipsEnabled && spine2Enabled) {
// Move hand from non-controlled position to controlled position. _animVars.set("spine2Type", (int)IKTarget::Type::Spline);
_leftHandControlTimeRemaining = std::max(_leftHandControlTimeRemaining - dt, 0.0f); _animVars.set("spine2Position", params.controllerPoses[ControllerType_Spine2].trans());
AnimPose handPose(Vectors::ONE, handRotation, handPosition); _animVars.set("spine2Rotation", params.controllerPoses[ControllerType_Spine2].rot());
if (transitionHandPose(_leftHandControlTimeRemaining, CONTROL_DURATION, handPose, } else {
LEFT_HAND, TO_CONTROLLED, handPose)) { _animVars.set("spine2Type", (int)IKTarget::Type::Unknown);
handPosition = handPose.trans(); }
handRotation = handPose.rot();
}
}
if (!bodySensorTrackingEnabled) { if (leftArmEnabled) {
// prevent the hand IK targets from intersecting the body capsule _animVars.set("leftArmType", (int)IKTarget::Type::RotationAndPosition);
glm::vec3 displacement; _animVars.set("leftArmPosition", params.controllerPoses[ControllerType_LeftArm].trans());
if (findSphereCapsulePenetration(handPosition, HAND_RADIUS, bodyCapsuleStart, bodyCapsuleEnd, bodyCapsuleRadius, displacement)) { _animVars.set("leftArmRotation", params.controllerPoses[ControllerType_LeftArm].rot());
handPosition -= displacement; } else {
} _animVars.set("leftArmType", (int)IKTarget::Type::Unknown);
} }
_animVars.set("leftHandPosition", handPosition); if (rightArmEnabled) {
_animVars.set("leftHandRotation", handRotation); _animVars.set("rightArmType", (int)IKTarget::Type::RotationAndPosition);
_animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition); _animVars.set("rightArmPosition", params.controllerPoses[ControllerType_RightArm].trans());
_animVars.set("rightArmRotation", params.controllerPoses[ControllerType_RightArm].rot());
_lastLeftHandControlledPose = AnimPose(Vectors::ONE, handRotation, handPosition); } else {
_animVars.set("rightArmType", (int)IKTarget::Type::Unknown);
_isLeftHandControlled = true;
_lastLeftHandControlledPose = AnimPose(glm::vec3(1.0f), params.leftOrientation, handPosition);
// compute pole vector
int handJointIndex = _animSkeleton->nameToJointIndex("LeftHand");
int armJointIndex = _animSkeleton->nameToJointIndex("LeftArm");
int elbowJointIndex = _animSkeleton->nameToJointIndex("LeftForeArm");
if (elbowJointIndex >= 0 && armJointIndex >= 0 && elbowJointIndex >= 0) {
glm::vec3 poleVector = calculateElbowPoleVector(handJointIndex, elbowJointIndex, armJointIndex, hipsIndex, true);
// smooth toward desired pole vector from previous pole vector... to reduce jitter
if (!_prevLeftHandPoleVectorValid) {
_prevLeftHandPoleVectorValid = true;
_prevLeftHandPoleVector = poleVector;
}
glm::quat deltaRot = rotationBetween(_prevLeftHandPoleVector, poleVector);
glm::quat smoothDeltaRot = safeMix(deltaRot, Quaternions::IDENTITY, ELBOW_POLE_VECTOR_BLEND_FACTOR);
_prevLeftHandPoleVector = smoothDeltaRot * _prevLeftHandPoleVector;
_animVars.set("leftHandPoleVectorEnabled", true);
_animVars.set("leftHandPoleReferenceVector", Vectors::UNIT_X);
_animVars.set("leftHandPoleVector", _prevLeftHandPoleVector);
} else {
_prevLeftHandPoleVectorValid = false;
_animVars.set("leftHandPoleVectorEnabled", false);
}
} else {
_prevLeftHandPoleVectorValid = false;
_animVars.set("leftHandPoleVectorEnabled", false);
if (_isLeftHandControlled) {
_leftHandRelaxTimeRemaining = RELAX_DURATION;
_isLeftHandControlled = false;
}
if (_leftHandRelaxTimeRemaining > 0.0f) {
// Move hand from controlled position to non-controlled position.
_leftHandRelaxTimeRemaining = std::max(_leftHandRelaxTimeRemaining - dt, 0.0f);
AnimPose handPose;
if (transitionHandPose(_leftHandRelaxTimeRemaining, RELAX_DURATION, _lastLeftHandControlledPose,
LEFT_HAND, FROM_CONTROLLED, handPose)) {
_animVars.set("leftHandPosition", handPose.trans());
_animVars.set("leftHandRotation", handPose.rot());
_animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition);
}
} else {
_animVars.unset("leftHandPosition");
_animVars.unset("leftHandRotation");
_animVars.set("leftHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition);
}
}
if (params.isRightEnabled) {
if (!_isRightHandControlled) {
_rightHandControlTimeRemaining = CONTROL_DURATION;
_isRightHandControlled = true;
}
glm::vec3 handPosition = params.rightPosition;
glm::quat handRotation = params.rightOrientation;
if (_rightHandControlTimeRemaining > 0.0f) {
// Move hand from non-controlled position to controlled position.
_rightHandControlTimeRemaining = std::max(_rightHandControlTimeRemaining - dt, 0.0f);
AnimPose handPose(Vectors::ONE, handRotation, handPosition);
if (transitionHandPose(_rightHandControlTimeRemaining, CONTROL_DURATION, handPose, RIGHT_HAND, TO_CONTROLLED,
handPose)) {
handPosition = handPose.trans();
handRotation = handPose.rot();
}
}
if (!bodySensorTrackingEnabled) {
// prevent the hand IK targets from intersecting the body capsule
glm::vec3 displacement;
if (findSphereCapsulePenetration(handPosition, HAND_RADIUS, bodyCapsuleStart, bodyCapsuleEnd, bodyCapsuleRadius, displacement)) {
handPosition -= displacement;
}
}
_animVars.set("rightHandPosition", handPosition);
_animVars.set("rightHandRotation", handRotation);
_animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition);
_lastRightHandControlledPose = AnimPose(Vectors::ONE, handRotation, handPosition);
_isRightHandControlled = true;
_lastRightHandControlledPose = AnimPose(glm::vec3(1.0f), params.rightOrientation, handPosition);
// compute pole vector
int handJointIndex = _animSkeleton->nameToJointIndex("RightHand");
int armJointIndex = _animSkeleton->nameToJointIndex("RightArm");
int elbowJointIndex = _animSkeleton->nameToJointIndex("RightForeArm");
if (elbowJointIndex >= 0 && armJointIndex >= 0 && elbowJointIndex >= 0) {
glm::vec3 poleVector = calculateElbowPoleVector(handJointIndex, elbowJointIndex, armJointIndex, hipsIndex, false);
// smooth toward desired pole vector from previous pole vector... to reduce jitter
if (!_prevRightHandPoleVectorValid) {
_prevRightHandPoleVectorValid = true;
_prevRightHandPoleVector = poleVector;
}
glm::quat deltaRot = rotationBetween(_prevRightHandPoleVector, poleVector);
glm::quat smoothDeltaRot = safeMix(deltaRot, Quaternions::IDENTITY, ELBOW_POLE_VECTOR_BLEND_FACTOR);
_prevRightHandPoleVector = smoothDeltaRot * _prevRightHandPoleVector;
_animVars.set("rightHandPoleVectorEnabled", true);
_animVars.set("rightHandPoleReferenceVector", -Vectors::UNIT_X);
_animVars.set("rightHandPoleVector", _prevRightHandPoleVector);
} else {
_prevRightHandPoleVectorValid = false;
_animVars.set("rightHandPoleVectorEnabled", false);
}
} else {
_prevRightHandPoleVectorValid = false;
_animVars.set("rightHandPoleVectorEnabled", false);
if (_isRightHandControlled) {
_rightHandRelaxTimeRemaining = RELAX_DURATION;
_isRightHandControlled = false;
}
if (_rightHandRelaxTimeRemaining > 0.0f) {
// Move hand from controlled position to non-controlled position.
_rightHandRelaxTimeRemaining = std::max(_rightHandRelaxTimeRemaining - dt, 0.0f);
AnimPose handPose;
if (transitionHandPose(_rightHandRelaxTimeRemaining, RELAX_DURATION, _lastRightHandControlledPose, RIGHT_HAND,
FROM_CONTROLLED, handPose)) {
_animVars.set("rightHandPosition", handPose.trans());
_animVars.set("rightHandRotation", handPose.rot());
_animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition);
}
} else {
_animVars.unset("rightHandPosition");
_animVars.unset("rightHandRotation");
_animVars.set("rightHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition);
}
}
if (params.isLeftFootEnabled) {
_animVars.set("leftFootPosition", params.leftFootPosition);
_animVars.set("leftFootRotation", params.leftFootOrientation);
_animVars.set("leftFootType", (int)IKTarget::Type::RotationAndPosition);
int footJointIndex = _animSkeleton->nameToJointIndex("LeftFoot");
glm::vec3 poleVector = calculateKneePoleVector(footJointIndex, params.leftFootOrientation, hipsIndex);
// smooth toward desired pole vector from previous pole vector... to reduce jitter
if (!_prevLeftFootPoleVectorValid) {
_prevLeftFootPoleVectorValid = true;
_prevLeftFootPoleVector = poleVector;
}
glm::quat deltaRot = rotationBetween(_prevLeftFootPoleVector, poleVector);
glm::quat smoothDeltaRot = safeMix(deltaRot, Quaternions::IDENTITY, KNEE_POLE_VECTOR_BLEND_FACTOR);
_prevLeftFootPoleVector = smoothDeltaRot * _prevLeftFootPoleVector;
_animVars.set("leftFootPoleVectorEnabled", true);
_animVars.set("leftFootPoleReferenceVector", Vectors::UNIT_Z);
_animVars.set("leftFootPoleVector", _prevLeftFootPoleVector);
} else {
_animVars.unset("leftFootPosition");
_animVars.unset("leftFootRotation");
_animVars.set("leftFootType", (int)IKTarget::Type::RotationAndPosition);
_animVars.set("leftFootPoleVectorEnabled", false);
_prevLeftFootPoleVectorValid = false;
}
if (params.isRightFootEnabled) {
_animVars.set("rightFootPosition", params.rightFootPosition);
_animVars.set("rightFootRotation", params.rightFootOrientation);
_animVars.set("rightFootType", (int)IKTarget::Type::RotationAndPosition);
int footJointIndex = _animSkeleton->nameToJointIndex("RightFoot");
glm::vec3 poleVector = calculateKneePoleVector(footJointIndex, params.rightFootOrientation, hipsIndex);
// smooth toward desired pole vector from previous pole vector... to reduce jitter
if (!_prevRightFootPoleVectorValid) {
_prevRightFootPoleVectorValid = true;
_prevRightFootPoleVector = poleVector;
}
glm::quat deltaRot = rotationBetween(_prevRightFootPoleVector, poleVector);
glm::quat smoothDeltaRot = safeMix(deltaRot, Quaternions::IDENTITY, KNEE_POLE_VECTOR_BLEND_FACTOR);
_prevRightFootPoleVector = smoothDeltaRot * _prevRightFootPoleVector;
_animVars.set("rightFootPoleVectorEnabled", true);
_animVars.set("rightFootPoleReferenceVector", Vectors::UNIT_Z);
_animVars.set("rightFootPoleVector", _prevRightFootPoleVector);
} else {
_animVars.unset("rightFootPosition");
_animVars.unset("rightFootRotation");
_animVars.set("rightFootPoleVectorEnabled", false);
_animVars.set("rightFootType", (int)IKTarget::Type::RotationAndPosition);
}
} }
} }

View file

@ -41,21 +41,26 @@ public:
bool useNames; bool useNames;
}; };
struct HeadParameters { enum ControllerType {
glm::mat4 hipsMatrix = glm::mat4(); // rig space ControllerType_Head = 0,
glm::mat4 spine2Matrix = glm::mat4(); // rig space ControllerType_LeftHand,
glm::quat rigHeadOrientation = glm::quat(); // rig space (-z forward) ControllerType_RightHand,
glm::vec3 rigHeadPosition = glm::vec3(); // rig space ControllerType_Hips,
glm::vec3 rightArmPosition = glm::vec3(); // rig space ControllerType_LeftFoot,
glm::quat rightArmRotation = glm::quat(); // rig space ControllerType_RightFoot,
glm::vec3 leftArmPosition = glm::vec3(); // rig space ControllerType_LeftArm,
glm::quat leftArmRotation = glm::quat(); // rig space ControllerType_RightArm,
bool hipsEnabled = false; ControllerType_Spine2,
bool headEnabled = false; NumControllerTypes
bool spine2Enabled = false; };
bool leftArmEnabled = false;
bool rightArmEnabled = false; struct ControllerParameters {
bool isTalking = false; AnimPose controllerPoses[NumControllerTypes]; // rig space
bool controllerActiveFlags[NumControllerTypes];
bool isTalking;
float bodyCapsuleRadius;
float bodyCapsuleHalfHeight;
glm::vec3 bodyCapsuleLocalOffset;
}; };
struct EyeParameters { struct EyeParameters {
@ -67,25 +72,6 @@ public:
int rightEyeJointIndex = -1; int rightEyeJointIndex = -1;
}; };
struct HandAndFeetParameters {
bool isLeftEnabled;
bool isRightEnabled;
float bodyCapsuleRadius;
float bodyCapsuleHalfHeight;
glm::vec3 bodyCapsuleLocalOffset;
glm::vec3 leftPosition = glm::vec3(); // rig space
glm::quat leftOrientation = glm::quat(); // rig space (z forward)
glm::vec3 rightPosition = glm::vec3(); // rig space
glm::quat rightOrientation = glm::quat(); // rig space (z forward)
bool isLeftFootEnabled;
bool isRightFootEnabled;
glm::vec3 leftFootPosition = glm::vec3(); // rig space
glm::quat leftFootOrientation = glm::quat(); // rig space (z forward)
glm::vec3 rightFootPosition = glm::vec3(); // rig space
glm::quat rightFootOrientation = glm::quat(); // rig space (z forward)
};
enum class CharacterControllerState { enum class CharacterControllerState {
Ground = 0, Ground = 0,
Takeoff, Takeoff,
@ -192,9 +178,8 @@ public:
// legacy // legacy
void clearJointStatePriorities(); void clearJointStatePriorities();
void updateFromHeadParameters(const HeadParameters& params, float dt); void updateFromControllerParameters(const ControllerParameters& params, float dt);
void updateFromEyeParameters(const EyeParameters& params); void updateFromEyeParameters(const EyeParameters& params);
void updateFromHandAndFeetParameters(const HandAndFeetParameters& params, float dt);
void initAnimGraph(const QUrl& url); void initAnimGraph(const QUrl& url);
@ -244,7 +229,11 @@ protected:
void applyOverridePoses(); void applyOverridePoses();
void buildAbsoluteRigPoses(const AnimPoseVec& relativePoses, AnimPoseVec& absolutePosesOut); void buildAbsoluteRigPoses(const AnimPoseVec& relativePoses, AnimPoseVec& absolutePosesOut);
void updateHeadAnimVars(const HeadParameters& params); void updateHead(bool headEnabled, bool hipsEnabled, const AnimPose& headMatrix);
void updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnabled, float dt,
const AnimPose& leftHandPose, const AnimPose& rightHandPose,
float bodyCapsuleRadius, float bodyCapsuleHalfHeight, const glm::vec3& bodyCapsuleLocalOffset);
void updateFeet(bool leftFootEnabled, bool rightFootEnabled, const AnimPose& leftFootPose, const AnimPose& rightFootPose);
void updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::vec3& lookAt, const glm::vec3& saccade); void updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::vec3& lookAt, const glm::vec3& saccade);
void calcAnimAlpha(float speed, const std::vector<float>& referenceSpeeds, float* alphaOut) const; void calcAnimAlpha(float speed, const std::vector<float>& referenceSpeeds, float* alphaOut) const;