mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 13:49:12 +02:00
First pass at having an explicit Hips IK target.
Also, AnimManipulator nodes support setting position and rotation on a single joint.
This commit is contained in:
parent
6a6800b8c3
commit
a10b157aff
13 changed files with 205 additions and 148 deletions
|
@ -50,6 +50,12 @@
|
||||||
"type": "inverseKinematics",
|
"type": "inverseKinematics",
|
||||||
"data": {
|
"data": {
|
||||||
"targets": [
|
"targets": [
|
||||||
|
{
|
||||||
|
"jointName": "Hips",
|
||||||
|
"positionVar": "hipsPosition",
|
||||||
|
"rotationVar": "hipsRotation",
|
||||||
|
"typeVar": "hipsType"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"jointName": "RightHand",
|
"jointName": "RightHand",
|
||||||
"positionVar": "rightHandPosition",
|
"positionVar": "rightHandPosition",
|
||||||
|
@ -91,20 +97,27 @@
|
||||||
"children": []
|
"children": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "manipulatorOverlay",
|
"id": "hipsManipulatorOverlay",
|
||||||
"type": "overlay",
|
"type": "overlay",
|
||||||
"data": {
|
"data": {
|
||||||
"alpha": 1.0,
|
"alpha": 0.0,
|
||||||
"boneSet": "spineOnly"
|
"boneSet": "hipsOnly"
|
||||||
},
|
},
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"id": "spineLean",
|
"id": "hipsManipulator",
|
||||||
"type": "manipulator",
|
"type": "manipulator",
|
||||||
"data": {
|
"data": {
|
||||||
"alpha": 0.0,
|
"alpha": 0.0,
|
||||||
|
"alphaVar": "hipsManipulatorAlpha",
|
||||||
"joints": [
|
"joints": [
|
||||||
{ "type": "absoluteRotation", "jointName": "Spine", "var": "lean" }
|
{
|
||||||
|
"jointName": "Hips",
|
||||||
|
"rotationType": "absolute",
|
||||||
|
"translationType": "absolute",
|
||||||
|
"rotationVar": "hipsManipulatorRotation",
|
||||||
|
"translationVar": "hipsManipulatorPosition"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"children": []
|
"children": []
|
||||||
|
|
|
@ -553,9 +553,12 @@ private:
|
||||||
|
|
||||||
void setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visiblity);
|
void setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visiblity);
|
||||||
|
|
||||||
|
// AJT: FIX ME... reorder this
|
||||||
|
public:
|
||||||
// derive avatar body position and orientation from the current HMD Sensor location.
|
// derive avatar body position and orientation from the current HMD Sensor location.
|
||||||
// results are in HMD frame
|
// results are in HMD frame
|
||||||
glm::mat4 deriveBodyFromHMDSensor() const;
|
glm::mat4 deriveBodyFromHMDSensor() const;
|
||||||
|
private:
|
||||||
|
|
||||||
virtual void updatePalms() override {}
|
virtual void updatePalms() override {}
|
||||||
void lateUpdatePalms();
|
void lateUpdatePalms();
|
||||||
|
|
|
@ -119,7 +119,11 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
||||||
headParams.rigHeadPosition = extractTranslation(rigHMDMat);
|
headParams.rigHeadPosition = extractTranslation(rigHMDMat);
|
||||||
headParams.rigHeadOrientation = extractRotation(rigHMDMat);
|
headParams.rigHeadOrientation = extractRotation(rigHMDMat);
|
||||||
headParams.worldHeadOrientation = extractRotation(worldHMDMat);
|
headParams.worldHeadOrientation = extractRotation(worldHMDMat);
|
||||||
|
|
||||||
|
headParams.hipsMatrix = worldToRig * myAvatar->getSensorToWorldMatrix() * myAvatar->deriveBodyFromHMDSensor();
|
||||||
|
headParams.hipsEnabled = true;
|
||||||
} else {
|
} else {
|
||||||
|
headParams.hipsEnabled = false;
|
||||||
headParams.isInHMD = false;
|
headParams.isInHMD = false;
|
||||||
|
|
||||||
// We don't have a valid localHeadPosition.
|
// We don't have a valid localHeadPosition.
|
||||||
|
|
|
@ -87,6 +87,7 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::
|
||||||
// build a list of valid targets from _targetVarVec and animVars
|
// build a list of valid targets from _targetVarVec and animVars
|
||||||
_maxTargetIndex = -1;
|
_maxTargetIndex = -1;
|
||||||
bool removeUnfoundJoints = false;
|
bool removeUnfoundJoints = false;
|
||||||
|
|
||||||
for (auto& targetVar : _targetVarVec) {
|
for (auto& targetVar : _targetVarVec) {
|
||||||
if (targetVar.jointIndex == -1) {
|
if (targetVar.jointIndex == -1) {
|
||||||
// this targetVar hasn't been validated yet...
|
// this targetVar hasn't been validated yet...
|
||||||
|
@ -105,9 +106,8 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::
|
||||||
AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses);
|
AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses);
|
||||||
glm::quat rotation = animVars.lookupRigToGeometry(targetVar.rotationVar, defaultPose.rot());
|
glm::quat rotation = animVars.lookupRigToGeometry(targetVar.rotationVar, defaultPose.rot());
|
||||||
glm::vec3 translation = animVars.lookupRigToGeometry(targetVar.positionVar, defaultPose.trans());
|
glm::vec3 translation = animVars.lookupRigToGeometry(targetVar.positionVar, defaultPose.trans());
|
||||||
if (target.getType() == IKTarget::Type::HipsRelativeRotationAndPosition) {
|
AnimPose absPose(glm::vec3(1.0f), rotation, translation);
|
||||||
translation += _hipsOffset;
|
|
||||||
}
|
|
||||||
target.setPose(rotation, translation);
|
target.setPose(rotation, translation);
|
||||||
target.setIndex(targetVar.jointIndex);
|
target.setIndex(targetVar.jointIndex);
|
||||||
targets.push_back(target);
|
targets.push_back(target);
|
||||||
|
@ -441,26 +441,6 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
||||||
computeTargets(animVars, targets, underPoses);
|
computeTargets(animVars, targets, underPoses);
|
||||||
}
|
}
|
||||||
|
|
||||||
// debug render ik targets
|
|
||||||
if (context.getEnableDebugDrawIKTargets()) {
|
|
||||||
const vec4 WHITE(1.0f);
|
|
||||||
glm::mat4 rigToAvatarMat = createMatFromQuatAndPos(Quaternions::Y_180, glm::vec3());
|
|
||||||
|
|
||||||
for (auto& target : targets) {
|
|
||||||
glm::mat4 geomTargetMat = createMatFromQuatAndPos(target.getRotation(), target.getTranslation());
|
|
||||||
glm::mat4 avatarTargetMat = rigToAvatarMat * context.getGeometryToRigMatrix() * geomTargetMat;
|
|
||||||
|
|
||||||
QString name = QString("ikTarget%1").arg(target.getIndex());
|
|
||||||
DebugDraw::getInstance().addMyAvatarMarker(name, glmExtractRotation(avatarTargetMat), extractTranslation(avatarTargetMat), WHITE);
|
|
||||||
}
|
|
||||||
} else if (context.getEnableDebugDrawIKTargets() != _previousEnableDebugIKTargets) {
|
|
||||||
// remove markers if they were added last frame.
|
|
||||||
for (auto& target : targets) {
|
|
||||||
QString name = QString("ikTarget%1").arg(target.getIndex());
|
|
||||||
DebugDraw::getInstance().removeMyAvatarMarker(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_previousEnableDebugIKTargets = context.getEnableDebugDrawIKTargets();
|
_previousEnableDebugIKTargets = context.getEnableDebugDrawIKTargets();
|
||||||
|
|
||||||
if (targets.empty()) {
|
if (targets.empty()) {
|
||||||
|
@ -478,25 +458,52 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
||||||
{
|
{
|
||||||
PROFILE_RANGE_EX(simulation_animation, "ik/shiftHips", 0xffff00ff, 0);
|
PROFILE_RANGE_EX(simulation_animation, "ik/shiftHips", 0xffff00ff, 0);
|
||||||
|
|
||||||
// shift hips according to the _hipsOffset from the previous frame
|
// AJT: TODO only need abs poses below hips.
|
||||||
float offsetLength = glm::length(_hipsOffset);
|
AnimPoseVec absolutePoses;
|
||||||
const float MIN_HIPS_OFFSET_LENGTH = 0.03f;
|
absolutePoses.resize(_relativePoses.size());
|
||||||
if (offsetLength > MIN_HIPS_OFFSET_LENGTH && _hipsIndex >= 0) {
|
computeAbsolutePoses(absolutePoses);
|
||||||
// but only if offset is long enough
|
|
||||||
float scaleFactor = ((offsetLength - MIN_HIPS_OFFSET_LENGTH) / offsetLength);
|
for (auto& target: targets) {
|
||||||
if (_hipsParentIndex == -1) {
|
if (target.getType() == IKTarget::Type::RotationAndPosition && target.getIndex() == _hipsIndex) {
|
||||||
// the hips are the root so _hipsOffset is in the correct frame
|
AnimPose absPose = target.getPose();
|
||||||
_relativePoses[_hipsIndex].trans() = underPoses[_hipsIndex].trans() + scaleFactor * _hipsOffset;
|
int parentIndex = _skeleton->getParentIndex(target.getIndex());
|
||||||
} else {
|
if (parentIndex != -1) {
|
||||||
// the hips are NOT the root so we need to transform _hipsOffset into hips local-frame
|
_relativePoses[_hipsIndex] = absolutePoses[parentIndex].inverse() * absPose;
|
||||||
glm::quat hipsFrameRotation = _relativePoses[_hipsParentIndex].rot();
|
} else {
|
||||||
int index = _skeleton->getParentIndex(_hipsParentIndex);
|
_relativePoses[_hipsIndex] = absPose;
|
||||||
while (index != -1) {
|
|
||||||
hipsFrameRotation *= _relativePoses[index].rot();
|
|
||||||
index = _skeleton->getParentIndex(index);
|
|
||||||
}
|
}
|
||||||
_relativePoses[_hipsIndex].trans() = underPoses[_hipsIndex].trans()
|
}
|
||||||
+ glm::inverse(glm::normalize(hipsFrameRotation)) * (scaleFactor * _hipsOffset);
|
}
|
||||||
|
|
||||||
|
for (auto& target: targets) {
|
||||||
|
if (target.getType() == IKTarget::Type::HipsRelativeRotationAndPosition) {
|
||||||
|
AnimPose pose = target.getPose();
|
||||||
|
pose.trans() = pose.trans() + (_relativePoses[_hipsIndex].trans() - underPoses[_hipsIndex].trans());
|
||||||
|
target.setPose(pose.rot(), pose.trans());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
PROFILE_RANGE_EX(simulation_animation, "ik/debugDraw", 0xffff00ff, 0);
|
||||||
|
|
||||||
|
// debug render ik targets
|
||||||
|
if (context.getEnableDebugDrawIKTargets()) {
|
||||||
|
const vec4 WHITE(1.0f);
|
||||||
|
glm::mat4 rigToAvatarMat = createMatFromQuatAndPos(Quaternions::Y_180, glm::vec3());
|
||||||
|
|
||||||
|
for (auto& target : targets) {
|
||||||
|
glm::mat4 geomTargetMat = createMatFromQuatAndPos(target.getRotation(), target.getTranslation());
|
||||||
|
glm::mat4 avatarTargetMat = rigToAvatarMat * context.getGeometryToRigMatrix() * geomTargetMat;
|
||||||
|
|
||||||
|
QString name = QString("ikTarget%1").arg(target.getIndex());
|
||||||
|
DebugDraw::getInstance().addMyAvatarMarker(name, glmExtractRotation(avatarTargetMat), extractTranslation(avatarTargetMat), WHITE);
|
||||||
|
}
|
||||||
|
} else if (context.getEnableDebugDrawIKTargets() != _previousEnableDebugIKTargets) {
|
||||||
|
// remove markers if they were added last frame.
|
||||||
|
for (auto& target : targets) {
|
||||||
|
QString name = QString("ikTarget%1").arg(target.getIndex());
|
||||||
|
DebugDraw::getInstance().removeMyAvatarMarker(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -505,60 +512,6 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
||||||
PROFILE_RANGE_EX(simulation_animation, "ik/ccd", 0xffff00ff, 0);
|
PROFILE_RANGE_EX(simulation_animation, "ik/ccd", 0xffff00ff, 0);
|
||||||
solveWithCyclicCoordinateDescent(targets);
|
solveWithCyclicCoordinateDescent(targets);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
PROFILE_RANGE_EX(simulation_animation, "ik/measureHipsOffset", 0xffff00ff, 0);
|
|
||||||
|
|
||||||
// measure new _hipsOffset for next frame
|
|
||||||
// by looking for discrepancies between where a targeted endEffector is
|
|
||||||
// and where it wants to be (after IK solutions are done)
|
|
||||||
glm::vec3 newHipsOffset = Vectors::ZERO;
|
|
||||||
for (auto& target: targets) {
|
|
||||||
int targetIndex = target.getIndex();
|
|
||||||
if (targetIndex == _headIndex && _headIndex != -1) {
|
|
||||||
// special handling for headTarget
|
|
||||||
if (target.getType() == IKTarget::Type::RotationOnly) {
|
|
||||||
// we want to shift the hips to bring the underPose closer
|
|
||||||
// to where the head happens to be (overpose)
|
|
||||||
glm::vec3 under = _skeleton->getAbsolutePose(_headIndex, underPoses).trans();
|
|
||||||
glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans();
|
|
||||||
const float HEAD_OFFSET_SLAVE_FACTOR = 0.65f;
|
|
||||||
newHipsOffset += HEAD_OFFSET_SLAVE_FACTOR * (actual - under);
|
|
||||||
} else if (target.getType() == IKTarget::Type::HmdHead) {
|
|
||||||
// we want to shift the hips to bring the head to its designated position
|
|
||||||
glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans();
|
|
||||||
_hipsOffset += target.getTranslation() - actual;
|
|
||||||
// and ignore all other targets
|
|
||||||
newHipsOffset = _hipsOffset;
|
|
||||||
break;
|
|
||||||
} else if (target.getType() == IKTarget::Type::RotationAndPosition) {
|
|
||||||
glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans();
|
|
||||||
glm::vec3 targetPosition = target.getTranslation();
|
|
||||||
newHipsOffset += targetPosition - actualPosition;
|
|
||||||
|
|
||||||
// Add downward pressure on the hips
|
|
||||||
newHipsOffset *= 0.95f;
|
|
||||||
newHipsOffset -= 1.0f;
|
|
||||||
}
|
|
||||||
} else if (target.getType() == IKTarget::Type::RotationAndPosition) {
|
|
||||||
glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans();
|
|
||||||
glm::vec3 targetPosition = target.getTranslation();
|
|
||||||
newHipsOffset += targetPosition - actualPosition;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// smooth transitions by relaxing _hipsOffset toward the new value
|
|
||||||
const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.10f;
|
|
||||||
float tau = dt < HIPS_OFFSET_SLAVE_TIMESCALE ? dt / HIPS_OFFSET_SLAVE_TIMESCALE : 1.0f;
|
|
||||||
_hipsOffset += (newHipsOffset - _hipsOffset) * tau;
|
|
||||||
|
|
||||||
// clamp the hips offset
|
|
||||||
float hipsOffsetLength = glm::length(_hipsOffset);
|
|
||||||
if (hipsOffsetLength > _maxHipsOffsetLength) {
|
|
||||||
_hipsOffset *= _maxHipsOffsetLength / hipsOffsetLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _relativePoses;
|
return _relativePoses;
|
||||||
|
|
|
@ -12,6 +12,16 @@
|
||||||
#include "AnimUtil.h"
|
#include "AnimUtil.h"
|
||||||
#include "AnimationLogging.h"
|
#include "AnimationLogging.h"
|
||||||
|
|
||||||
|
AnimManipulator::JointVar::JointVar(const QString& jointNameIn, Type rotationTypeIn, Type translationTypeIn,
|
||||||
|
const QString& rotationVarIn, const QString& translationVarIn) :
|
||||||
|
jointName(jointNameIn),
|
||||||
|
rotationType(rotationTypeIn),
|
||||||
|
translationType(translationTypeIn),
|
||||||
|
rotationVar(rotationVarIn),
|
||||||
|
translationVar(translationVarIn),
|
||||||
|
jointIndex(-1),
|
||||||
|
hasPerformedJointLookup(false) {}
|
||||||
|
|
||||||
AnimManipulator::AnimManipulator(const QString& id, float alpha) :
|
AnimManipulator::AnimManipulator(const QString& id, float alpha) :
|
||||||
AnimNode(AnimNode::Type::Manipulator, id),
|
AnimNode(AnimNode::Type::Manipulator, id),
|
||||||
_alpha(alpha) {
|
_alpha(alpha) {
|
||||||
|
@ -36,7 +46,10 @@ const AnimPoseVec& AnimManipulator::overlay(const AnimVariantMap& animVars, cons
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& jointVar : _jointVars) {
|
for (auto& jointVar : _jointVars) {
|
||||||
|
|
||||||
if (!jointVar.hasPerformedJointLookup) {
|
if (!jointVar.hasPerformedJointLookup) {
|
||||||
|
|
||||||
|
// map from joint name to joint index and cache the result.
|
||||||
jointVar.jointIndex = _skeleton->nameToJointIndex(jointVar.jointName);
|
jointVar.jointIndex = _skeleton->nameToJointIndex(jointVar.jointName);
|
||||||
if (jointVar.jointIndex < 0) {
|
if (jointVar.jointIndex < 0) {
|
||||||
qCWarning(animation) << "AnimManipulator could not find jointName" << jointVar.jointName << "in skeleton";
|
qCWarning(animation) << "AnimManipulator could not find jointName" << jointVar.jointName << "in skeleton";
|
||||||
|
@ -100,34 +113,62 @@ AnimPose AnimManipulator::computeRelativePoseFromJointVar(const AnimVariantMap&
|
||||||
|
|
||||||
AnimPose defaultAbsPose = _skeleton->getAbsolutePose(jointVar.jointIndex, underPoses);
|
AnimPose defaultAbsPose = _skeleton->getAbsolutePose(jointVar.jointIndex, underPoses);
|
||||||
|
|
||||||
if (jointVar.type == JointVar::Type::AbsoluteRotation || jointVar.type == JointVar::Type::AbsolutePosition) {
|
// compute relative translation
|
||||||
|
glm::vec3 relTrans;
|
||||||
|
switch (jointVar.translationType) {
|
||||||
|
case JointVar::Type::Absolute: {
|
||||||
|
glm::vec3 absTrans = animVars.lookupRigToGeometry(jointVar.translationVar, defaultAbsPose.trans());
|
||||||
|
|
||||||
if (jointVar.type == JointVar::Type::AbsoluteRotation) {
|
// convert to from absolute to relative.
|
||||||
defaultAbsPose.rot() = animVars.lookupRigToGeometry(jointVar.var, defaultAbsPose.rot());
|
AnimPose parentAbsPose;
|
||||||
} else if (jointVar.type == JointVar::Type::AbsolutePosition) {
|
int parentIndex = _skeleton->getParentIndex(jointVar.jointIndex);
|
||||||
defaultAbsPose.trans() = animVars.lookupRigToGeometry(jointVar.var, defaultAbsPose.trans());
|
if (parentIndex >= 0) {
|
||||||
|
parentAbsPose = _skeleton->getAbsolutePose(parentIndex, underPoses);
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert from absolute to relative
|
||||||
|
relTrans = transformPoint(parentAbsPose.inverse(), absTrans);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
case JointVar::Type::Relative:
|
||||||
// because jointVar is absolute, we must use an absolute parent frame to convert into a relative pose.
|
relTrans = animVars.lookupRigToGeometryVector(jointVar.translationVar, defaultRelPose.trans());
|
||||||
AnimPose parentAbsPose = AnimPose::identity;
|
break;
|
||||||
int parentIndex = _skeleton->getParentIndex(jointVar.jointIndex);
|
case JointVar::Type::UnderPose:
|
||||||
if (parentIndex >= 0) {
|
relTrans = underPoses[jointVar.jointIndex].trans();
|
||||||
parentAbsPose = _skeleton->getAbsolutePose(parentIndex, underPoses);
|
break;
|
||||||
}
|
case JointVar::Type::Default:
|
||||||
|
default:
|
||||||
// convert from absolute to relative
|
relTrans = defaultRelPose.trans();
|
||||||
return parentAbsPose.inverse() * defaultAbsPose;
|
break;
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// override the default rel pose
|
|
||||||
AnimPose relPose = defaultRelPose;
|
|
||||||
if (jointVar.type == JointVar::Type::RelativeRotation) {
|
|
||||||
relPose.rot() = animVars.lookupRigToGeometry(jointVar.var, defaultRelPose.rot());
|
|
||||||
} else if (jointVar.type == JointVar::Type::RelativePosition) {
|
|
||||||
relPose.trans() = animVars.lookupRigToGeometry(jointVar.var, defaultRelPose.trans());
|
|
||||||
}
|
|
||||||
|
|
||||||
return relPose;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::quat relRot;
|
||||||
|
switch (jointVar.rotationType) {
|
||||||
|
case JointVar::Type::Absolute: {
|
||||||
|
glm::quat absRot = animVars.lookupRigToGeometry(jointVar.translationVar, defaultAbsPose.rot());
|
||||||
|
|
||||||
|
// convert to from absolute to relative.
|
||||||
|
AnimPose parentAbsPose;
|
||||||
|
int parentIndex = _skeleton->getParentIndex(jointVar.jointIndex);
|
||||||
|
if (parentIndex >= 0) {
|
||||||
|
parentAbsPose = _skeleton->getAbsolutePose(parentIndex, underPoses);
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert from absolute to relative
|
||||||
|
relRot = glm::inverse(parentAbsPose.rot()) * absRot;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case JointVar::Type::Relative:
|
||||||
|
relRot = animVars.lookupRigToGeometry(jointVar.translationVar, defaultRelPose.rot());
|
||||||
|
break;
|
||||||
|
case JointVar::Type::UnderPose:
|
||||||
|
relRot = underPoses[jointVar.jointIndex].rot();
|
||||||
|
break;
|
||||||
|
case JointVar::Type::Default:
|
||||||
|
default:
|
||||||
|
relRot = defaultRelPose.rot();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AnimPose(glm::vec3(1), relRot, relTrans);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,17 +31,20 @@ public:
|
||||||
|
|
||||||
struct JointVar {
|
struct JointVar {
|
||||||
enum class Type {
|
enum class Type {
|
||||||
AbsoluteRotation = 0,
|
Absolute,
|
||||||
AbsolutePosition,
|
Relative,
|
||||||
RelativeRotation,
|
UnderPose,
|
||||||
RelativePosition,
|
Default,
|
||||||
NumTypes
|
NumTypes
|
||||||
};
|
};
|
||||||
|
|
||||||
JointVar(const QString& varIn, const QString& jointNameIn, Type typeIn) : var(varIn), jointName(jointNameIn), type(typeIn), jointIndex(-1), hasPerformedJointLookup(false) {}
|
JointVar(const QString& jointNameIn, Type rotationType, Type translationType, const QString& rotationVarIn, const QString& translationVarIn);
|
||||||
QString var = "";
|
|
||||||
QString jointName = "";
|
QString jointName = "";
|
||||||
Type type = Type::AbsoluteRotation;
|
Type rotationType = Type::Absolute;
|
||||||
|
Type translationType = Type::Absolute;
|
||||||
|
QString rotationVar = "";
|
||||||
|
QString translationVar = "";
|
||||||
|
|
||||||
int jointIndex = -1;
|
int jointIndex = -1;
|
||||||
bool hasPerformedJointLookup = false;
|
bool hasPerformedJointLookup = false;
|
||||||
bool isRelative = false;
|
bool isRelative = false;
|
||||||
|
|
|
@ -79,10 +79,10 @@ static AnimStateMachine::InterpType stringToInterpType(const QString& str) {
|
||||||
|
|
||||||
static const char* animManipulatorJointVarTypeToString(AnimManipulator::JointVar::Type type) {
|
static const char* animManipulatorJointVarTypeToString(AnimManipulator::JointVar::Type type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case AnimManipulator::JointVar::Type::AbsoluteRotation: return "absoluteRotation";
|
case AnimManipulator::JointVar::Type::Absolute: return "absolute";
|
||||||
case AnimManipulator::JointVar::Type::AbsolutePosition: return "absolutePosition";
|
case AnimManipulator::JointVar::Type::Relative: return "relative";
|
||||||
case AnimManipulator::JointVar::Type::RelativeRotation: return "relativeRotation";
|
case AnimManipulator::JointVar::Type::UnderPose: return "underPose";
|
||||||
case AnimManipulator::JointVar::Type::RelativePosition: return "relativePosition";
|
case AnimManipulator::JointVar::Type::Default: return "default";
|
||||||
case AnimManipulator::JointVar::Type::NumTypes: return nullptr;
|
case AnimManipulator::JointVar::Type::NumTypes: return nullptr;
|
||||||
};
|
};
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -339,7 +339,8 @@ static const char* boneSetStrings[AnimOverlay::NumBoneSets] = {
|
||||||
"spineOnly",
|
"spineOnly",
|
||||||
"empty",
|
"empty",
|
||||||
"leftHand",
|
"leftHand",
|
||||||
"rightHand"
|
"rightHand",
|
||||||
|
"hipsOnly"
|
||||||
};
|
};
|
||||||
|
|
||||||
static AnimOverlay::BoneSet stringToBoneSetEnum(const QString& str) {
|
static AnimOverlay::BoneSet stringToBoneSetEnum(const QString& str) {
|
||||||
|
@ -406,17 +407,25 @@ static AnimNode::Pointer loadManipulatorNode(const QJsonObject& jsonObj, const Q
|
||||||
}
|
}
|
||||||
auto jointObj = jointValue.toObject();
|
auto jointObj = jointValue.toObject();
|
||||||
|
|
||||||
READ_STRING(type, jointObj, id, jsonUrl, nullptr);
|
|
||||||
READ_STRING(jointName, jointObj, id, jsonUrl, nullptr);
|
READ_STRING(jointName, jointObj, id, jsonUrl, nullptr);
|
||||||
READ_STRING(var, jointObj, id, jsonUrl, nullptr);
|
READ_STRING(rotationType, jointObj, id, jsonUrl, nullptr);
|
||||||
|
READ_STRING(translationType, jointObj, id, jsonUrl, nullptr);
|
||||||
|
READ_STRING(rotationVar, jointObj, id, jsonUrl, nullptr);
|
||||||
|
READ_STRING(translationVar, jointObj, id, jsonUrl, nullptr);
|
||||||
|
|
||||||
AnimManipulator::JointVar::Type jointVarType = stringToAnimManipulatorJointVarType(type);
|
AnimManipulator::JointVar::Type jointVarRotationType = stringToAnimManipulatorJointVarType(rotationType);
|
||||||
if (jointVarType == AnimManipulator::JointVar::Type::NumTypes) {
|
if (jointVarRotationType == AnimManipulator::JointVar::Type::NumTypes) {
|
||||||
qCCritical(animation) << "AnimNodeLoader, bad type in \"joints\", id =" << id << ", url =" << jsonUrl.toDisplayString();
|
qCWarning(animation) << "AnimNodeLoader, bad rotationType in \"joints\", id =" << id << ", url =" << jsonUrl.toDisplayString();
|
||||||
return nullptr;
|
jointVarRotationType = AnimManipulator::JointVar::Type::Default;
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimManipulator::JointVar jointVar(var, jointName, jointVarType);
|
AnimManipulator::JointVar::Type jointVarTranslationType = stringToAnimManipulatorJointVarType(translationType);
|
||||||
|
if (jointVarTranslationType == AnimManipulator::JointVar::Type::NumTypes) {
|
||||||
|
qCWarning(animation) << "AnimNodeLoader, bad translationType in \"joints\", id =" << id << ", url =" << jsonUrl.toDisplayString();
|
||||||
|
jointVarTranslationType = AnimManipulator::JointVar::Type::Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimManipulator::JointVar jointVar(jointName, jointVarRotationType, jointVarTranslationType, rotationVar, translationVar);
|
||||||
node->addJointVar(jointVar);
|
node->addJointVar(jointVar);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ void AnimOverlay::buildBoneSet(BoneSet boneSet) {
|
||||||
case SpineOnlyBoneSet: buildSpineOnlyBoneSet(); break;
|
case SpineOnlyBoneSet: buildSpineOnlyBoneSet(); break;
|
||||||
case LeftHandBoneSet: buildLeftHandBoneSet(); break;
|
case LeftHandBoneSet: buildLeftHandBoneSet(); break;
|
||||||
case RightHandBoneSet: buildRightHandBoneSet(); break;
|
case RightHandBoneSet: buildRightHandBoneSet(); break;
|
||||||
|
case HipsOnlyBoneSet: buildHipsOnlyBoneSet(); break;
|
||||||
default:
|
default:
|
||||||
case EmptyBoneSet: buildEmptyBoneSet(); break;
|
case EmptyBoneSet: buildEmptyBoneSet(); break;
|
||||||
}
|
}
|
||||||
|
@ -188,6 +189,13 @@ void AnimOverlay::buildRightHandBoneSet() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AnimOverlay::buildHipsOnlyBoneSet() {
|
||||||
|
assert(_skeleton);
|
||||||
|
buildEmptyBoneSet();
|
||||||
|
int hipsJoint = _skeleton->nameToJointIndex("Hips");
|
||||||
|
_boneSetVec[hipsJoint] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
// for AnimDebugDraw rendering
|
// for AnimDebugDraw rendering
|
||||||
const AnimPoseVec& AnimOverlay::getPosesInternal() const {
|
const AnimPoseVec& AnimOverlay::getPosesInternal() const {
|
||||||
return _poses;
|
return _poses;
|
||||||
|
|
|
@ -37,6 +37,7 @@ public:
|
||||||
EmptyBoneSet,
|
EmptyBoneSet,
|
||||||
LeftHandBoneSet,
|
LeftHandBoneSet,
|
||||||
RightHandBoneSet,
|
RightHandBoneSet,
|
||||||
|
HipsOnlyBoneSet,
|
||||||
NumBoneSets
|
NumBoneSets
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -75,6 +76,7 @@ public:
|
||||||
void buildEmptyBoneSet();
|
void buildEmptyBoneSet();
|
||||||
void buildLeftHandBoneSet();
|
void buildLeftHandBoneSet();
|
||||||
void buildRightHandBoneSet();
|
void buildRightHandBoneSet();
|
||||||
|
void buildHipsOnlyBoneSet();
|
||||||
|
|
||||||
// no copies
|
// no copies
|
||||||
AnimOverlay(const AnimOverlay&) = delete;
|
AnimOverlay(const AnimOverlay&) = delete;
|
||||||
|
|
|
@ -165,6 +165,15 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec3 lookupRigToGeometryVector(const QString& key, const glm::vec3& defaultValue) const {
|
||||||
|
if (key.isEmpty()) {
|
||||||
|
return defaultValue;
|
||||||
|
} else {
|
||||||
|
auto iter = _map.find(key);
|
||||||
|
return iter != _map.end() ? transformVectorFast(_rigToGeometryMat, iter->second.getVec3()) : defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const glm::quat& lookupRaw(const QString& key, const glm::quat& defaultValue) const {
|
const glm::quat& lookupRaw(const QString& key, const glm::quat& defaultValue) const {
|
||||||
if (key.isEmpty()) {
|
if (key.isEmpty()) {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
|
|
|
@ -21,13 +21,14 @@ public:
|
||||||
RotationOnly,
|
RotationOnly,
|
||||||
HmdHead,
|
HmdHead,
|
||||||
HipsRelativeRotationAndPosition,
|
HipsRelativeRotationAndPosition,
|
||||||
Unknown,
|
Unknown
|
||||||
};
|
};
|
||||||
|
|
||||||
IKTarget() {}
|
IKTarget() {}
|
||||||
|
|
||||||
const glm::vec3& getTranslation() const { return _pose.trans(); }
|
const glm::vec3& getTranslation() const { return _pose.trans(); }
|
||||||
const glm::quat& getRotation() const { return _pose.rot(); }
|
const glm::quat& getRotation() const { return _pose.rot(); }
|
||||||
|
const AnimPose& getPose() const { return _pose; }
|
||||||
int getIndex() const { return _index; }
|
int getIndex() const { return _index; }
|
||||||
Type getType() const { return _type; }
|
Type getType() const { return _type; }
|
||||||
|
|
||||||
|
|
|
@ -1024,6 +1024,15 @@ void Rig::updateFromHeadParameters(const HeadParameters& params, float dt) {
|
||||||
|
|
||||||
_animVars.set("isTalking", params.isTalking);
|
_animVars.set("isTalking", params.isTalking);
|
||||||
_animVars.set("notIsTalking", !params.isTalking);
|
_animVars.set("notIsTalking", !params.isTalking);
|
||||||
|
|
||||||
|
// AJT:
|
||||||
|
if (params.hipsEnabled) {
|
||||||
|
_animVars.set("hipsType", (int)IKTarget::Type::RotationAndPosition);
|
||||||
|
_animVars.set("hipsPosition", extractTranslation(params.hipsMatrix));
|
||||||
|
_animVars.set("hipsRotation", glmExtractRotation(params.hipsMatrix) * Quaternions::Y_180);
|
||||||
|
} else {
|
||||||
|
_animVars.set("hipsType", (int)IKTarget::Type::Unknown);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rig::updateFromEyeParameters(const EyeParameters& params) {
|
void Rig::updateFromEyeParameters(const EyeParameters& params) {
|
||||||
|
@ -1094,7 +1103,7 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) {
|
||||||
|
|
||||||
_animVars.set("headPosition", headPos);
|
_animVars.set("headPosition", headPos);
|
||||||
_animVars.set("headRotation", headRot);
|
_animVars.set("headRotation", headRot);
|
||||||
_animVars.set("headType", (int)IKTarget::Type::HmdHead);
|
_animVars.set("headType", (int)IKTarget::Type::RotationAndPosition);
|
||||||
_animVars.set("neckPosition", neckPos);
|
_animVars.set("neckPosition", neckPos);
|
||||||
_animVars.set("neckRotation", neckRot);
|
_animVars.set("neckRotation", neckRot);
|
||||||
_animVars.set("neckType", (int)IKTarget::Type::Unknown); // 'Unknown' disables the target
|
_animVars.set("neckType", (int)IKTarget::Type::Unknown); // 'Unknown' disables the target
|
||||||
|
|
|
@ -45,6 +45,8 @@ public:
|
||||||
glm::quat worldHeadOrientation = glm::quat(); // world space (-z forward)
|
glm::quat worldHeadOrientation = glm::quat(); // world space (-z forward)
|
||||||
glm::quat rigHeadOrientation = glm::quat(); // rig space (-z forward)
|
glm::quat rigHeadOrientation = glm::quat(); // rig space (-z forward)
|
||||||
glm::vec3 rigHeadPosition = glm::vec3(); // rig space
|
glm::vec3 rigHeadPosition = glm::vec3(); // rig space
|
||||||
|
glm::mat4 hipsMatrix = glm::mat4(); // rig space
|
||||||
|
bool hipsEnabled = false;
|
||||||
bool isInHMD = false;
|
bool isInHMD = false;
|
||||||
int neckJointIndex = -1;
|
int neckJointIndex = -1;
|
||||||
bool isTalking = false;
|
bool isTalking = false;
|
||||||
|
|
Loading…
Reference in a new issue