first stab at secondary target pose support

This commit is contained in:
Anthony J. Thibault 2017-07-13 18:12:33 -07:00
parent 2e0bc36cfd
commit c85e187c61
7 changed files with 190 additions and 123 deletions

View file

@ -4749,7 +4749,7 @@ void Application::update(float deltaTime) {
myAvatar->setDriveKey(MyAvatar::ZOOM, userInputMapper->getActionState(controller::Action::TRANSLATE_CAMERA_Z));
}
static std::vector<controller::Action> avatarControllerActions = {
static const std::vector<controller::Action> avatarControllerActions = {
controller::Action::LEFT_HAND,
controller::Action::RIGHT_HAND,
controller::Action::LEFT_FOOT,
@ -4796,7 +4796,19 @@ void Application::update(float deltaTime) {
controller::Action::RIGHT_HAND_PINKY1,
controller::Action::RIGHT_HAND_PINKY2,
controller::Action::RIGHT_HAND_PINKY3,
controller::Action::RIGHT_HAND_PINKY4
controller::Action::RIGHT_HAND_PINKY4,
controller::Action::LEFT_ARM,
controller::Action::RIGHT_ARM,
controller::Action::LEFT_SHOULDER,
controller::Action::RIGHT_SHOULDER,
controller::Action::LEFT_FORE_ARM,
controller::Action::RIGHT_FORE_ARM,
controller::Action::LEFT_LEG,
controller::Action::RIGHT_LEG,
controller::Action::LEFT_UP_LEG,
controller::Action::RIGHT_UP_LEG,
controller::Action::LEFT_TOE_BASE,
controller::Action::RIGHT_TOE_BASE
};
glm::mat4 myAvatarMatrix = createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition());

View file

@ -56,96 +56,72 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
auto avatarHeadPose = myAvatar->getControllerPoseInAvatarFrame(controller::Action::HEAD);
if (avatarHeadPose.isValid()) {
AnimPose pose(avatarHeadPose.getRotation(), avatarHeadPose.getTranslation());
params.controllerPoses[Rig::ControllerType_Head] = avatarToRigPose * pose;
params.controllerActiveFlags[Rig::ControllerType_Head] = true;
params.primaryControllerPoses[Rig::PrimaryControllerType_Head] = avatarToRigPose * pose;
params.primaryControllerActiveFlags[Rig::PrimaryControllerType_Head] = true;
} else {
// even though full head IK is disabled, the rig still needs the head orientation to rotate the head up and
// down in desktop mode.
// preMult 180 is necessary to convert from avatar to rig coordinates.
// postMult 180 is necessary to convert head from -z forward to z forward.
glm::quat headRot = Quaternions::Y_180 * head->getFinalOrientationInLocalFrame() * Quaternions::Y_180;
params.controllerPoses[Rig::ControllerType_Head] = AnimPose(glm::vec3(1.0f), headRot, glm::vec3(0.0f));
params.controllerActiveFlags[Rig::ControllerType_Head] = false;
params.primaryControllerPoses[Rig::PrimaryControllerType_Head] = AnimPose(glm::vec3(1.0f), headRot, glm::vec3(0.0f));
params.primaryControllerActiveFlags[Rig::PrimaryControllerType_Head] = false;
}
auto avatarHipsPose = myAvatar->getControllerPoseInAvatarFrame(controller::Action::HIPS);
if (avatarHipsPose.isValid()) {
AnimPose pose(avatarHipsPose.getRotation(), avatarHipsPose.getTranslation());
params.controllerPoses[Rig::ControllerType_Hips] = avatarToRigPose * pose;
params.controllerActiveFlags[Rig::ControllerType_Hips] = true;
} else {
params.controllerPoses[Rig::ControllerType_Hips] = AnimPose::identity;
params.controllerActiveFlags[Rig::ControllerType_Hips] = false;
//
// primary controller poses, control IK targets directly.
//
static const std::vector<std::pair<controller::Action, Rig::PrimaryControllerType>> primaryControllers = {
{ controller::Action::LEFT_HAND, Rig::PrimaryControllerType_LeftHand },
{ controller::Action::RIGHT_HAND, Rig::PrimaryControllerType_RightHand },
{ controller::Action::HIPS, Rig::PrimaryControllerType_Hips },
{ controller::Action::LEFT_FOOT, Rig::PrimaryControllerType_LeftFoot },
{ controller::Action::RIGHT_FOOT, Rig::PrimaryControllerType_RightFoot },
{ controller::Action::SPINE2, Rig::PrimaryControllerType_Spine2 }
};
for (auto pair : primaryControllers) {
auto pose = myAvatar->getControllerPoseInAvatarFrame(pair.first);
if (pose.isValid()) {
AnimPose pose(pose.getRotation(), pose.getTranslation());
params.primaryControllerPoses[pair.second] = avatarToRigPose * pose;
params.primaryControllerActiveFlags[pair.second] = true;
} else {
params.primaryControllerPoses[pair.second] = AnimPose::identity;
params.primaryControllerActiveFlags[pair.second] = false;
}
}
auto avatarSpine2Pose = myAvatar->getControllerPoseInAvatarFrame(controller::Action::SPINE2);
if (avatarSpine2Pose.isValid()) {
AnimPose pose(avatarSpine2Pose.getRotation(), avatarSpine2Pose.getTranslation());
params.controllerPoses[Rig::ControllerType_Spine2] = avatarToRigPose * pose;
params.controllerActiveFlags[Rig::ControllerType_Spine2] = true;
} else {
params.controllerPoses[Rig::ControllerType_Spine2] = AnimPose::identity;
params.controllerActiveFlags[Rig::ControllerType_Spine2] = false;
}
//
// secondary controller poses, influence the pose of the skeleton indirectly.
//
auto avatarRightArmPose = myAvatar->getControllerPoseInAvatarFrame(controller::Action::RIGHT_ARM);
if (avatarRightArmPose.isValid()) {
AnimPose pose(avatarRightArmPose.getRotation(), avatarRightArmPose.getTranslation());
params.controllerPoses[Rig::ControllerType_RightArm] = avatarToRigPose * pose;
params.controllerActiveFlags[Rig::ControllerType_RightArm] = true;
} else {
params.controllerPoses[Rig::ControllerType_RightArm] = AnimPose::identity;
params.controllerActiveFlags[Rig::ControllerType_RightArm] = false;
}
static const std::vector<std::pair<controller::Action, Rig::SecondaryControllerType>> secondaryControllers = {
{ controller::Action::LEFT_SHOULDER, Rig::SecondaryControllerType_LeftShoulder },
{ controller::Action::RIGHT_SHOULDER, Rig::SecondaryControllerType_RightShoulder },
{ controller::Action::LEFT_ARM, Rig::SecondaryControllerType_LeftArm },
{ controller::Action::RIGHT_ARM, Rig::SecondaryControllerType_RightArm },
{ controller::Action::LEFT_FORE_ARM, Rig::SecondaryControllerType_LeftForeArm },
{ controller::Action::RIGHT_FORE_ARM, Rig::SecondaryControllerType_RightForeArm },
{ controller::Action::LEFT_UP_LEG, Rig::SecondaryControllerType_LeftUpLeg },
{ controller::Action::RIGHT_UP_LEG, Rig::SecondaryControllerType_RightUpLeg },
{ controller::Action::LEFT_LEG, Rig::SecondaryControllerType_LeftLeg },
{ controller::Action::RIGHT_LEG, Rig::SecondaryControllerType_RightLeg },
{ controller::Action::LEFT_TOE_BASE, Rig::SecondaryControllerType_LeftToeBase },
{ controller::Action::RIGHT_TOE_BASE, Rig::SecondaryControllerType_RightToeBase }
};
auto avatarLeftArmPose = myAvatar->getControllerPoseInAvatarFrame(controller::Action::LEFT_ARM);
if (avatarLeftArmPose.isValid()) {
AnimPose pose(avatarLeftArmPose.getRotation(), avatarLeftArmPose.getTranslation());
params.controllerPoses[Rig::ControllerType_LeftArm] = avatarToRigPose * pose;
params.controllerActiveFlags[Rig::ControllerType_LeftArm] = true;
} else {
params.controllerPoses[Rig::ControllerType_LeftArm] = AnimPose::identity;
params.controllerActiveFlags[Rig::ControllerType_LeftArm] = false;
}
auto avatarLeftHandPose = myAvatar->getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND);
if (avatarLeftHandPose.isValid()) {
AnimPose pose(avatarLeftHandPose.getRotation(), avatarLeftHandPose.getTranslation());
params.controllerPoses[Rig::ControllerType_LeftHand] = avatarToRigPose * pose;
params.controllerActiveFlags[Rig::ControllerType_LeftHand] = true;
} else {
params.controllerPoses[Rig::ControllerType_LeftHand] = AnimPose::identity;
params.controllerActiveFlags[Rig::ControllerType_LeftHand] = false;
}
auto avatarRightHandPose = myAvatar->getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND);
if (avatarRightHandPose.isValid()) {
AnimPose pose(avatarRightHandPose.getRotation(), avatarRightHandPose.getTranslation());
params.controllerPoses[Rig::ControllerType_RightHand] = avatarToRigPose * pose;
params.controllerActiveFlags[Rig::ControllerType_RightHand] = true;
} else {
params.controllerPoses[Rig::ControllerType_RightHand] = AnimPose::identity;
params.controllerActiveFlags[Rig::ControllerType_RightHand] = false;
}
auto avatarLeftFootPose = myAvatar->getControllerPoseInAvatarFrame(controller::Action::LEFT_FOOT);
if (avatarLeftFootPose.isValid()) {
AnimPose pose(avatarLeftFootPose.getRotation(), avatarLeftFootPose.getTranslation());
params.controllerPoses[Rig::ControllerType_LeftFoot] = avatarToRigPose * pose;
params.controllerActiveFlags[Rig::ControllerType_LeftFoot] = true;
} else {
params.controllerPoses[Rig::ControllerType_LeftFoot] = AnimPose::identity;
params.controllerActiveFlags[Rig::ControllerType_LeftFoot] = false;
}
auto avatarRightFootPose = myAvatar->getControllerPoseInAvatarFrame(controller::Action::RIGHT_FOOT);
if (avatarRightFootPose.isValid()) {
AnimPose pose(avatarRightFootPose.getRotation(), avatarRightFootPose.getTranslation());
params.controllerPoses[Rig::ControllerType_RightFoot] = avatarToRigPose * pose;
params.controllerActiveFlags[Rig::ControllerType_RightFoot] = true;
} else {
params.controllerPoses[Rig::ControllerType_RightFoot] = AnimPose::identity;
params.controllerActiveFlags[Rig::ControllerType_RightFoot] = false;
for (auto pair : secondaryControllers) {
auto pose = myAvatar->getControllerPoseInAvatarFrame(pair.first);
if (pose.isValid()) {
AnimPose pose(pose.getRotation(), pose.getTranslation());
params.secondaryControllerPoses[pair.second] = avatarToRigPose * pose;
params.secondaryControllerActiveFlags[pair.second] = true;
} else {
params.secondaryControllerPoses[pair.second] = AnimPose::identity;
params.secondaryControllerActiveFlags[pair.second] = false;
}
}
params.bodyCapsuleRadius = myAvatar->getCharacterController()->getCapsuleRadius();

View file

@ -921,6 +921,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
{
PROFILE_RANGE_EX(simulation_animation, "ik/ccd", 0xffff00ff, 0);
preconditionRelativePosesToAvoidLimbLock(context, targets);
setSecondaryTargets(context);
solve(context, targets);
}
@ -1015,6 +1016,22 @@ void AnimInverseKinematics::clearIKJointLimitHistory() {
}
}
void AnimInverseKinematics::setSecondaryTargetInRigFrame(int jointIndex, const AnimPose& pose) {
auto iter = _secondaryTargetsInRigFrame.find(jointIndex);
if (iter != _secondaryTargetsInRigFrame.end()) {
iter->second = pose;
} else {
_secondaryTargetsInRigFrame.insert({ jointIndex, pose });
}
}
void AnimInverseKinematics::clearSecondaryTarget(int jointIndex) {
auto iter = _secondaryTargetsInRigFrame.find(jointIndex);
if (iter != _secondaryTargetsInRigFrame.end()) {
_secondaryTargetsInRigFrame.erase(iter);
}
}
RotationConstraint* AnimInverseKinematics::getConstraint(int index) const {
RotationConstraint* constraint = nullptr;
std::map<int, RotationConstraint*>::const_iterator constraintItr = _constraints.find(index);
@ -1722,6 +1739,20 @@ void AnimInverseKinematics::preconditionRelativePosesToAvoidLimbLock(const AnimC
}
}
// overwrites _relativePoses with secondary poses.
void AnimInverseKinematics::setSecondaryTargets(const AnimContext& context) {
AnimPose rigToGeometryPose = AnimPose(glm::inverse(context.getGeometryToRigMatrix()));
for (auto& iter : _secondaryTargetsInRigFrame) {
AnimPose absPose = rigToGeometryPose * iter.second;
AnimPose parentAbsPose;
int parentIndex = _skeleton->getParentIndex(iter.first);
if (parentIndex >= 0) {
parentAbsPose = _skeleton->getAbsolutePose(parentIndex, _relativePoses);
}
_relativePoses[iter.first] = parentAbsPose.inverse() * absPose;
}
}
void AnimInverseKinematics::initRelativePosesFromSolutionSource(SolutionSource solutionSource, const AnimPoseVec& underPoses) {
const float RELAX_BLEND_FACTOR = (1.0f / 16.0f);
const float COPY_BLEND_FACTOR = 1.0f;

View file

@ -63,6 +63,9 @@ public:
NumSolutionSources,
};
void setSecondaryTargetInRigFrame(int jointIndex, const AnimPose& pose);
void clearSecondaryTarget(int jointIndex);
void setSolutionSource(SolutionSource solutionSource) { _solutionSource = solutionSource; }
void setSolutionSourceVar(const QString& solutionSourceVar) { _solutionSourceVar = solutionSourceVar; }
@ -83,6 +86,7 @@ protected:
void initRelativePosesFromSolutionSource(SolutionSource solutionSource, const AnimPoseVec& underPose);
void blendToPoses(const AnimPoseVec& targetPoses, const AnimPoseVec& underPose, float blendFactor);
void preconditionRelativePosesToAvoidLimbLock(const AnimContext& context, const std::vector<IKTarget>& targets);
void setSecondaryTargets(const AnimContext& context);
// used to pre-compute information about each joint influeced by a spline IK target.
struct SplineJointInfo {
@ -136,6 +140,8 @@ protected:
AnimPoseVec _relativePoses; // current relative poses
AnimPoseVec _limitCenterPoses; // relative
std::map<int, AnimPose> _secondaryTargetsInRigFrame;
std::map<int, std::vector<SplineJointInfo>> _splineJointInfoMap;
// experimental data for moving hips during IK

View file

@ -1474,24 +1474,25 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo
_animVars.set("isTalking", params.isTalking);
_animVars.set("notIsTalking", !params.isTalking);
bool headEnabled = params.controllerActiveFlags[ControllerType_Head];
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];
bool headEnabled = params.primaryControllerActiveFlags[PrimaryControllerType_Head];
bool leftHandEnabled = params.primaryControllerActiveFlags[PrimaryControllerType_LeftHand];
bool rightHandEnabled = params.primaryControllerActiveFlags[PrimaryControllerType_RightHand];
bool hipsEnabled = params.primaryControllerActiveFlags[PrimaryControllerType_Hips];
bool leftFootEnabled = params.primaryControllerActiveFlags[PrimaryControllerType_LeftFoot];
bool rightFootEnabled = params.primaryControllerActiveFlags[PrimaryControllerType_RightFoot];
bool spine2Enabled = params.primaryControllerActiveFlags[PrimaryControllerType_Spine2];
updateHead(headEnabled, hipsEnabled, params.controllerPoses[ControllerType_Head]);
bool leftArmEnabled = params.secondaryControllerActiveFlags[SecondaryControllerType_LeftArm];
bool rightArmEnabled = params.secondaryControllerActiveFlags[SecondaryControllerType_RightArm];
updateHead(headEnabled, hipsEnabled, params.primaryControllerPoses[PrimaryControllerType_Head]);
updateHands(leftHandEnabled, rightHandEnabled, hipsEnabled, leftArmEnabled, rightArmEnabled, dt,
params.controllerPoses[ControllerType_LeftHand], params.controllerPoses[ControllerType_RightHand],
params.primaryControllerPoses[PrimaryControllerType_LeftHand], params.primaryControllerPoses[PrimaryControllerType_RightHand],
params.bodyCapsuleRadius, params.bodyCapsuleHalfHeight, params.bodyCapsuleLocalOffset);
updateFeet(leftFootEnabled, rightFootEnabled,
params.controllerPoses[ControllerType_LeftFoot], params.controllerPoses[ControllerType_RightFoot]);
params.primaryControllerPoses[PrimaryControllerType_LeftFoot], params.primaryControllerPoses[PrimaryControllerType_RightFoot]);
// if the hips or the feet are being controlled.
if (hipsEnabled || rightFootEnabled || leftFootEnabled) {
@ -1512,34 +1513,46 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo
if (hipsEnabled) {
_animVars.set("hipsType", (int)IKTarget::Type::RotationAndPosition);
_animVars.set("hipsPosition", params.controllerPoses[ControllerType_Hips].trans());
_animVars.set("hipsRotation", params.controllerPoses[ControllerType_Hips].rot());
_animVars.set("hipsPosition", params.primaryControllerPoses[PrimaryControllerType_Hips].trans());
_animVars.set("hipsRotation", params.primaryControllerPoses[PrimaryControllerType_Hips].rot());
} else {
_animVars.set("hipsType", (int)IKTarget::Type::Unknown);
}
if (hipsEnabled && spine2Enabled) {
_animVars.set("spine2Type", (int)IKTarget::Type::Spline);
_animVars.set("spine2Position", params.controllerPoses[ControllerType_Spine2].trans());
_animVars.set("spine2Rotation", params.controllerPoses[ControllerType_Spine2].rot());
_animVars.set("spine2Position", params.primaryControllerPoses[PrimaryControllerType_Spine2].trans());
_animVars.set("spine2Rotation", params.primaryControllerPoses[PrimaryControllerType_Spine2].rot());
} else {
_animVars.set("spine2Type", (int)IKTarget::Type::Unknown);
}
if (leftArmEnabled) {
_animVars.set("leftArmType", (int)IKTarget::Type::RotationAndPosition);
_animVars.set("leftArmPosition", params.controllerPoses[ControllerType_LeftArm].trans());
_animVars.set("leftArmRotation", params.controllerPoses[ControllerType_LeftArm].rot());
} else {
_animVars.set("leftArmType", (int)IKTarget::Type::Unknown);
}
// set secondary targets
static const std::vector<QString> secondaryControllerJointNames = {
"LeftShoulder",
"RightShoulder",
"LeftArm",
"RightArm",
"LeftForeArm",
"RightForeArm",
"LeftUpLeg",
"RightUpLeg",
"LeftLeg",
"RightLeg",
"LeftToeBase",
"RightToeBase"
};
if (rightArmEnabled) {
_animVars.set("rightArmType", (int)IKTarget::Type::RotationAndPosition);
_animVars.set("rightArmPosition", params.controllerPoses[ControllerType_RightArm].trans());
_animVars.set("rightArmRotation", params.controllerPoses[ControllerType_RightArm].rot());
} else {
_animVars.set("rightArmType", (int)IKTarget::Type::Unknown);
std::shared_ptr<AnimInverseKinematics> ikNode = getAnimInverseKinematicsNode();
for (int i = 0; i < (int)NumSecondaryControllerTypes; i++) {
int index = indexOfJoint(secondaryControllerJointNames[i]);
if (index >= 0) {
if (params.secondaryControllerActiveFlags[i]) {
ikNode->setSecondaryTargetInRigFrame(index, params.secondaryControllerPoses[i]);
} else {
ikNode->clearSecondaryTarget(index);
}
}
}
}

View file

@ -41,22 +41,39 @@ public:
bool useNames;
};
enum ControllerType {
ControllerType_Head = 0,
ControllerType_LeftHand,
ControllerType_RightHand,
ControllerType_Hips,
ControllerType_LeftFoot,
ControllerType_RightFoot,
ControllerType_LeftArm,
ControllerType_RightArm,
ControllerType_Spine2,
NumControllerTypes
enum PrimaryControllerType {
PrimaryControllerType_Head = 0,
PrimaryControllerType_LeftHand,
PrimaryControllerType_RightHand,
PrimaryControllerType_Hips,
PrimaryControllerType_LeftFoot,
PrimaryControllerType_RightFoot,
PrimaryControllerType_Spine2,
NumPrimaryControllerTypes
};
// NOTE: These should ordered such that joint parents appear before their children.
enum SecondaryControllerType {
SecondaryControllerType_LeftShoulder = 0,
SecondaryControllerType_RightShoulder,
SecondaryControllerType_LeftArm,
SecondaryControllerType_RightArm,
SecondaryControllerType_LeftForeArm,
SecondaryControllerType_RightForeArm,
SecondaryControllerType_LeftUpLeg,
SecondaryControllerType_RightUpLeg,
SecondaryControllerType_LeftLeg,
SecondaryControllerType_RightLeg,
SecondaryControllerType_LeftToeBase,
SecondaryControllerType_RightToeBase,
NumSecondaryControllerTypes
};
struct ControllerParameters {
AnimPose controllerPoses[NumControllerTypes]; // rig space
bool controllerActiveFlags[NumControllerTypes];
AnimPose primaryControllerPoses[NumPrimaryControllerTypes]; // rig space
bool primaryControllerActiveFlags[NumPrimaryControllerTypes];
AnimPose secondaryControllerPoses[NumSecondaryControllerTypes]; // rig space
bool secondaryControllerActiveFlags[NumSecondaryControllerTypes];
bool isTalking;
float bodyCapsuleRadius;
float bodyCapsuleHalfHeight;

View file

@ -101,6 +101,7 @@ enum class Action {
// Bisected aliases for TRANSLATE_CAMERA_Z
BOOM_IN,
BOOM_OUT,
LEFT_ARM,
RIGHT_ARM,
@ -146,7 +147,18 @@ enum class Action {
RIGHT_HAND_PINKY3,
RIGHT_HAND_PINKY4,
NUM_ACTIONS,
LEFT_SHOULDER,
RIGHT_SHOULDER,
LEFT_FORE_ARM,
RIGHT_FORE_ARM,
LEFT_LEG,
RIGHT_LEG,
LEFT_UP_LEG,
RIGHT_UP_LEG,
LEFT_TOE_BASE,
RIGHT_TOE_BASE,
NUM_ACTIONS
};
template <typename T>