Convert JointData from relative frame to absolute.

This commit is contained in:
Anthony J. Thibault 2016-05-12 14:40:27 -07:00
parent 06d1bd5728
commit 55b0060df9
6 changed files with 63 additions and 48 deletions

View file

@ -165,6 +165,7 @@ void Rig::destroyAnimGraph() {
void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOffset) {
_geometryOffset = AnimPose(geometry.offset);
_invGeometryOffset = _geometryOffset.inverse();
setModelOffset(modelOffset);
_animSkeleton = std::make_shared<AnimSkeleton>(geometry);
@ -193,6 +194,7 @@ void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOff
void Rig::reset(const FBXGeometry& geometry) {
_geometryOffset = AnimPose(geometry.offset);
_invGeometryOffset = _geometryOffset.inverse();
_animSkeleton = std::make_shared<AnimSkeleton>(geometry);
_internalPoseSet._relativePoses.clear();
@ -272,24 +274,6 @@ void Rig::setModelOffset(const glm::mat4& modelOffsetMat) {
}
}
bool Rig::getJointStateRotation(int index, glm::quat& rotation) const {
if (isIndexValid(index)) {
rotation = _internalPoseSet._relativePoses[index].rot;
return !isEqual(rotation, _animSkeleton->getRelativeDefaultPose(index).rot);
} else {
return false;
}
}
bool Rig::getJointStateTranslation(int index, glm::vec3& translation) const {
if (isIndexValid(index)) {
translation = _internalPoseSet._relativePoses[index].trans;
return !isEqual(translation, _animSkeleton->getRelativeDefaultPose(index).trans);
} else {
return false;
}
}
void Rig::clearJointState(int index) {
if (isIndexValid(index)) {
_internalPoseSet._overrideFlags[index] = false;
@ -446,6 +430,23 @@ void Rig::calcAnimAlpha(float speed, const std::vector<float>& referenceSpeeds,
*alphaOut = alpha;
}
bool Rig::getJointData(int index, JointData& jointDataOut) const {
if (isIndexValid(index)) {
jointDataOut.rotation = _internalPoseSet._absolutePoses[index].rot;
jointDataOut.rotationSet = !isEqual(jointDataOut.rotation, _animSkeleton->getAbsoluteDefaultPose(index).rot);
// geometry offset is used here so that translations are in meters, this is what the avatar mixer expects
jointDataOut.translation = _geometryOffset * _internalPoseSet._absolutePoses[index].trans;
jointDataOut.translationSet = !isEqual(jointDataOut.translation, _animSkeleton->getAbsoluteDefaultPose(index).trans);
return true;
} else {
jointDataOut.translationSet = false;
jointDataOut.rotationSet = false;
return false;
}
}
void Rig::setEnableInverseKinematics(bool enable) {
_enableInverseKinematics = enable;
}
@ -1232,21 +1233,44 @@ void Rig::copyJointsIntoJointData(QVector<JointData>& jointDataVec) const {
jointDataVec.resize((int)getJointStateCount());
for (auto i = 0; i < jointDataVec.size(); i++) {
JointData& data = jointDataVec[i];
data.rotationSet |= getJointStateRotation(i, data.rotation);
// geometry offset is used here so that translations are in meters.
// this is what the avatar mixer expects
data.translationSet |= getJointStateTranslation(i, data.translation);
data.translation = _geometryOffset * data.translation;
getJointData(i, data);
}
}
void Rig::copyJointsFromJointData(const QVector<JointData>& jointDataVec) {
AnimPose invGeometryOffset = _geometryOffset.inverse();
for (int i = 0; i < jointDataVec.size(); i++) {
const JointData& data = jointDataVec.at(i);
setJointRotation(i, data.rotationSet, data.rotation, 1.0f);
// geometry offset is used here to undo the fact that avatar mixer translations are in meters.
setJointTranslation(i, data.translationSet, invGeometryOffset * data.translation, 1.0f);
if (_animSkeleton) {
std::vector<bool> overrideFlags(_internalPoseSet._overridePoses.size(), false);
AnimPoseVec overridePoses = _animSkeleton->getAbsoluteDefaultPoses(); // start with the default poses.
ASSERT(overrideFlags.size() == absoluteOverridePoses.size());
for (int i = 0; i < jointDataVec.size(); i++) {
if (isIndexValid(i)) {
const JointData& data = jointDataVec.at(i);
if (data.rotationSet) {
overrideFlags[i] = true;
overridePoses[i].rot = data.rotation;
}
if (data.translationSet) {
overrideFlags[i] = true;
// convert from meters back into geometry units.
overridePoses[i].trans = _invGeometryOffset * data.translation;
}
}
}
ASSERT(_internalPoseSet._overrideFlags.size() == _internalPoseSet._overridePoses.size());
_animSkeleton->convertAbsolutePosesToRelative(overridePoses);
for (int i = 0; i < jointDataVec.size(); i++) {
if (overrideFlags[i]) {
_internalPoseSet._overrideFlags[i] = true;
_internalPoseSet._overridePoses[i] = overridePoses[i];
}
}
}
}

View file

@ -104,12 +104,6 @@ public:
void setModelOffset(const glm::mat4& modelOffsetMat);
// geometry space
bool getJointStateRotation(int index, glm::quat& rotation) const;
// geometry space
bool getJointStateTranslation(int index, glm::vec3& translation) const;
void clearJointState(int index);
void clearJointStates();
void clearJointAnimationPriority(int index);
@ -119,8 +113,6 @@ public:
// geometry space
void setJointTranslation(int index, bool valid, const glm::vec3& translation, float priority);
// geometry space
void setJointRotation(int index, bool valid, const glm::quat& rotation, float priority);
// legacy
@ -237,8 +229,12 @@ protected:
void updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAt, const glm::vec3& saccade);
void calcAnimAlpha(float speed, const std::vector<float>& referenceSpeeds, float* alphaOut) const;
// geometry space
bool getJointData(int index, JointData& jointDataOut) const;
AnimPose _modelOffset; // model to rig space
AnimPose _geometryOffset; // geometry to model space (includes unit offset & fst offsets)
AnimPose _invGeometryOffset;
struct PoseSet {
AnimPoseVec _relativePoses; // geometry space relative to parent.

View file

@ -121,6 +121,8 @@ void AvatarData::setHandPosition(const glm::vec3& handPosition) {
_handPosition = glm::inverse(getOrientation()) * (handPosition - getPosition());
}
#define WANT_DEBUG
QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) {
// TODO: DRY this up to a shared method
// that can pack any type given the number of bytes
@ -329,7 +331,7 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) {
}
#ifdef WANT_DEBUG
if (sendAll) {
//if (sendAll) {
qDebug() << "AvatarData::toByteArray" << cullSmallChanges << sendAll
<< "rotations:" << rotationSentCount << "translations:" << translationSentCount
<< "largest:" << maxTranslationDimension
@ -339,7 +341,7 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) {
<< (beforeTranslations - beforeRotations) << "+"
<< (destinationBuffer - beforeTranslations) << "="
<< (destinationBuffer - startPosition);
}
//}
#endif
return avatarDataByteArray.left(destinationBuffer - startPosition);

View file

@ -174,7 +174,8 @@ const PacketVersion VERSION_LIGHT_HAS_FALLOFF_RADIUS = 57;
enum class AvatarMixerPacketVersion : PacketVersion {
TranslationSupport = 17,
SoftAttachmentSupport
SoftAttachmentSupport,
AbsoluteFortyEightBitRotations
};
#endif // hifi_PacketHeaders_h

View file

@ -726,10 +726,6 @@ glm::vec3 Model::calculateScaledOffsetPoint(const glm::vec3& point) const {
return translatedPoint;
}
bool Model::getJointState(int index, glm::quat& rotation) const {
return _rig->getJointStateRotation(index, rotation);
}
void Model::clearJointState(int index) {
_rig->clearJointState(index);
}

View file

@ -252,10 +252,6 @@ protected:
/// Returns the scaled equivalent of a point in model space.
glm::vec3 calculateScaledOffsetPoint(const glm::vec3& point) const;
/// Fetches the joint state at the specified index.
/// \return whether or not the joint state is "valid" (that is, non-default)
bool getJointState(int index, glm::quat& rotation) const;
/// Clear the joint states
void clearJointState(int index);