mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 11:48:09 +02:00
Relay joint translations across network. Apply animation's root-joint translation to avatar.
This commit is contained in:
parent
a820682816
commit
50dd8eba45
33 changed files with 585 additions and 84 deletions
|
@ -77,7 +77,19 @@ void ScriptableAvatar::update(float deltatime) {
|
||||||
int mapping = animationJoints.indexOf(modelJoints[i]);
|
int mapping = animationJoints.indexOf(modelJoints[i]);
|
||||||
if (mapping != -1 && !_maskedJoints.contains(modelJoints[i])) {
|
if (mapping != -1 && !_maskedJoints.contains(modelJoints[i])) {
|
||||||
JointData& data = _jointData[i];
|
JointData& data = _jointData[i];
|
||||||
data.rotation = safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction);
|
|
||||||
|
auto newRotation = safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction);
|
||||||
|
auto newTranslation = floorFrame.translations.at(i) * (1.0f - frameFraction) +
|
||||||
|
ceilFrame.translations.at(i) * frameFraction;
|
||||||
|
|
||||||
|
if (data.rotation != newRotation) {
|
||||||
|
data.rotation = newRotation;
|
||||||
|
data.rotationSet = true;
|
||||||
|
}
|
||||||
|
if (data.translation != newTranslation) {
|
||||||
|
data.translation = newTranslation;
|
||||||
|
data.translationSet = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -202,11 +202,14 @@ void Avatar::simulate(float deltaTime) {
|
||||||
PerformanceTimer perfTimer("skeleton");
|
PerformanceTimer perfTimer("skeleton");
|
||||||
for (int i = 0; i < _jointData.size(); i++) {
|
for (int i = 0; i < _jointData.size(); i++) {
|
||||||
const JointData& data = _jointData.at(i);
|
const JointData& data = _jointData.at(i);
|
||||||
_skeletonModel.setJointState(i, true, data.rotation);
|
_skeletonModel.setJointRotation(i, data.rotationSet, data.rotation, 1.0f);
|
||||||
|
_skeletonModel.setJointTranslation(i, data.translationSet, data.translation, 1.0f);
|
||||||
}
|
}
|
||||||
_skeletonModel.simulate(deltaTime, _hasNewJointRotations);
|
|
||||||
|
_skeletonModel.simulate(deltaTime, _hasNewJointRotations || _hasNewJointTranslations);
|
||||||
simulateAttachments(deltaTime);
|
simulateAttachments(deltaTime);
|
||||||
_hasNewJointRotations = false;
|
_hasNewJointRotations = false;
|
||||||
|
_hasNewJointTranslations = false;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("head");
|
PerformanceTimer perfTimer("head");
|
||||||
|
@ -879,6 +882,16 @@ glm::quat Avatar::getJointRotation(int index) const {
|
||||||
return rotation;
|
return rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec3 Avatar::getJointTranslation(int index) const {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
return AvatarData::getJointTranslation(index);
|
||||||
|
}
|
||||||
|
glm::vec3 translation;
|
||||||
|
_skeletonModel.getJointTranslation(index, translation);
|
||||||
|
return translation;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int Avatar::getJointIndex(const QString& name) const {
|
int Avatar::getJointIndex(const QString& name) const {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
int result;
|
int result;
|
||||||
|
|
|
@ -115,6 +115,7 @@ public:
|
||||||
|
|
||||||
virtual QVector<glm::quat> getJointRotations() const;
|
virtual QVector<glm::quat> getJointRotations() const;
|
||||||
virtual glm::quat getJointRotation(int index) const;
|
virtual glm::quat getJointRotation(int index) const;
|
||||||
|
virtual glm::vec3 getJointTranslation(int index) const;
|
||||||
virtual int getJointIndex(const QString& name) const;
|
virtual int getJointIndex(const QString& name) const;
|
||||||
virtual QStringList getJointNames() const;
|
virtual QStringList getJointNames() const;
|
||||||
|
|
||||||
|
|
|
@ -239,9 +239,11 @@ void MyAvatar::simulate(float deltaTime) {
|
||||||
PerformanceTimer perfTimer("joints");
|
PerformanceTimer perfTimer("joints");
|
||||||
// copy out the skeleton joints from the model
|
// copy out the skeleton joints from the model
|
||||||
_jointData.resize(_rig->getJointStateCount());
|
_jointData.resize(_rig->getJointStateCount());
|
||||||
|
|
||||||
for (int i = 0; i < _jointData.size(); i++) {
|
for (int i = 0; i < _jointData.size(); i++) {
|
||||||
JointData& data = _jointData[i];
|
JointData& data = _jointData[i];
|
||||||
_rig->getJointStateRotation(i, data.rotation);
|
data.rotationSet |= _rig->getJointStateRotation(i, data.rotation);
|
||||||
|
data.translationSet |= _rig->getJointStateTranslation(i, data.translation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1083,21 +1085,43 @@ void MyAvatar::setJointRotations(QVector<glm::quat> jointRotations) {
|
||||||
int numStates = glm::min(_skeletonModel.getJointStateCount(), jointRotations.size());
|
int numStates = glm::min(_skeletonModel.getJointStateCount(), jointRotations.size());
|
||||||
for (int i = 0; i < numStates; ++i) {
|
for (int i = 0; i < numStates; ++i) {
|
||||||
// HACK: ATM only Recorder calls setJointRotations() so we hardcode its priority here
|
// HACK: ATM only Recorder calls setJointRotations() so we hardcode its priority here
|
||||||
_skeletonModel.setJointState(i, true, jointRotations[i], RECORDER_PRIORITY);
|
_skeletonModel.setJointRotation(i, true, jointRotations[i], RECORDER_PRIORITY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::setJointData(int index, const glm::quat& rotation) {
|
void MyAvatar::setJointTranslations(QVector<glm::vec3> jointTranslations) {
|
||||||
|
int numStates = glm::min(_skeletonModel.getJointStateCount(), jointTranslations.size());
|
||||||
|
for (int i = 0; i < numStates; ++i) {
|
||||||
|
// HACK: ATM only Recorder calls setJointTranslations() so we hardcode its priority here
|
||||||
|
_skeletonModel.setJointTranslation(i, true, jointTranslations[i], RECORDER_PRIORITY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyAvatar::setJointData(int index, const glm::quat& rotation, const glm::vec3& translation) {
|
||||||
if (QThread::currentThread() == thread()) {
|
if (QThread::currentThread() == thread()) {
|
||||||
// HACK: ATM only JS scripts call setJointData() on MyAvatar so we hardcode the priority
|
// HACK: ATM only JS scripts call setJointData() on MyAvatar so we hardcode the priority
|
||||||
_rig->setJointState(index, true, rotation, SCRIPT_PRIORITY);
|
_rig->setJointState(index, true, rotation, translation, SCRIPT_PRIORITY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyAvatar::setJointRotation(int index, const glm::quat& rotation) {
|
||||||
|
if (QThread::currentThread() == thread()) {
|
||||||
|
// HACK: ATM only JS scripts call setJointData() on MyAvatar so we hardcode the priority
|
||||||
|
_rig->setJointRotation(index, true, rotation, SCRIPT_PRIORITY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyAvatar::setJointTranslation(int index, const glm::vec3& translation) {
|
||||||
|
if (QThread::currentThread() == thread()) {
|
||||||
|
// HACK: ATM only JS scripts call setJointData() on MyAvatar so we hardcode the priority
|
||||||
|
_rig->setJointTranslation(index, true, translation, SCRIPT_PRIORITY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::clearJointData(int index) {
|
void MyAvatar::clearJointData(int index) {
|
||||||
if (QThread::currentThread() == thread()) {
|
if (QThread::currentThread() == thread()) {
|
||||||
// HACK: ATM only JS scripts call clearJointData() on MyAvatar so we hardcode the priority
|
// HACK: ATM only JS scripts call clearJointData() on MyAvatar so we hardcode the priority
|
||||||
_rig->setJointState(index, false, glm::quat(), 0.0f);
|
_rig->setJointState(index, false, glm::quat(), glm::vec3(), 0.0f);
|
||||||
_rig->clearJointAnimationPriority(index);
|
_rig->clearJointAnimationPriority(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1396,7 +1420,10 @@ void MyAvatar::preRender(RenderArgs* renderArgs) {
|
||||||
AnimPose pose = _debugDrawSkeleton->getRelativeBindPose(i);
|
AnimPose pose = _debugDrawSkeleton->getRelativeBindPose(i);
|
||||||
glm::quat jointRot;
|
glm::quat jointRot;
|
||||||
_rig->getJointRotationInConstrainedFrame(i, jointRot);
|
_rig->getJointRotationInConstrainedFrame(i, jointRot);
|
||||||
|
glm::vec3 jointTrans;
|
||||||
|
_rig->getJointTranslation(i, jointTrans);
|
||||||
pose.rot = pose.rot * jointRot;
|
pose.rot = pose.rot * jointRot;
|
||||||
|
pose.trans = jointTrans;
|
||||||
poses.push_back(pose);
|
poses.push_back(pose);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -139,7 +139,10 @@ public:
|
||||||
void clearLookAtTargetAvatar();
|
void clearLookAtTargetAvatar();
|
||||||
|
|
||||||
virtual void setJointRotations(QVector<glm::quat> jointRotations);
|
virtual void setJointRotations(QVector<glm::quat> jointRotations);
|
||||||
virtual void setJointData(int index, const glm::quat& rotation);
|
virtual void setJointTranslations(QVector<glm::vec3> jointTranslations);
|
||||||
|
virtual void setJointData(int index, const glm::quat& rotation, const glm::vec3& translation);
|
||||||
|
virtual void setJointRotation(int index, const glm::quat& rotation);
|
||||||
|
virtual void setJointTranslation(int index, const glm::vec3& translation);
|
||||||
virtual void clearJointData(int index);
|
virtual void clearJointData(int index);
|
||||||
virtual void clearJointsData();
|
virtual void clearJointsData();
|
||||||
|
|
||||||
|
|
|
@ -648,6 +648,7 @@ void SkeletonModel::computeBoundingShape() {
|
||||||
// RECOVER FROM BOUNINDG SHAPE HACK: now that we're all done, restore the default pose
|
// RECOVER FROM BOUNINDG SHAPE HACK: now that we're all done, restore the default pose
|
||||||
for (int i = 0; i < numStates; i++) {
|
for (int i = 0; i < numStates; i++) {
|
||||||
_rig->restoreJointRotation(i, 1.0f, 1.0f);
|
_rig->restoreJointRotation(i, 1.0f, 1.0f);
|
||||||
|
_rig->restoreJointTranslation(i, 1.0f, 1.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -147,8 +147,14 @@ void AnimClip::copyFromNetworkAnim() {
|
||||||
for (int j = 0; j < animJointCount; j++) {
|
for (int j = 0; j < animJointCount; j++) {
|
||||||
int k = jointMap[j];
|
int k = jointMap[j];
|
||||||
if (k >= 0 && k < skeletonJointCount) {
|
if (k >= 0 && k < skeletonJointCount) {
|
||||||
// currently FBX animations only have rotation.
|
|
||||||
_anim[i][k].rot = _skeleton->getRelativeBindPose(k).rot * geom.animationFrames[i].rotations[j];
|
_anim[i][k].rot = _skeleton->getRelativeBindPose(k).rot * geom.animationFrames[i].rotations[j];
|
||||||
|
|
||||||
|
// TODO -- why does applying all the joint translations make a mutant?
|
||||||
|
if (animJoints[j].parentIndex == -1) {
|
||||||
|
_anim[i][k].trans = geom.animationFrames[i].translations[j] * extractScale(geom.offset);
|
||||||
|
} else {
|
||||||
|
_anim[i][k].trans = _skeleton->getRelativeBindPose(k).trans;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -322,9 +322,11 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar
|
||||||
std::map<int, RotationConstraint*>::iterator constraintItr = _constraints.begin();
|
std::map<int, RotationConstraint*>::iterator constraintItr = _constraints.begin();
|
||||||
while (constraintItr != _constraints.end()) {
|
while (constraintItr != _constraints.end()) {
|
||||||
int index = constraintItr->first;
|
int index = constraintItr->first;
|
||||||
|
|
||||||
glm::quat rotation = _relativePoses[index].rot;
|
glm::quat rotation = _relativePoses[index].rot;
|
||||||
constraintItr->second->apply(rotation);
|
constraintItr->second->apply(rotation);
|
||||||
_relativePoses[index].rot = rotation;
|
_relativePoses[index].rot = rotation;
|
||||||
|
|
||||||
++constraintItr;
|
++constraintItr;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -354,6 +356,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
||||||
} else {
|
} else {
|
||||||
_relativePoses[i].rot = underPoses[i].rot;
|
_relativePoses[i].rot = underPoses[i].rot;
|
||||||
}
|
}
|
||||||
|
_relativePoses[i].trans = underPoses[i].trans;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return evaluate(animVars, dt, triggersOut);
|
return evaluate(animVars, dt, triggersOut);
|
||||||
|
|
|
@ -55,6 +55,7 @@ const AnimPoseVec& AnimManipulator::overlay(const AnimVariantMap& animVars, floa
|
||||||
defaultRelPose = underPoses[jointVar.jointIndex];
|
defaultRelPose = underPoses[jointVar.jointIndex];
|
||||||
defaultAbsPose = _skeleton->getAbsolutePose(jointVar.jointIndex, underPoses);
|
defaultAbsPose = _skeleton->getAbsolutePose(jointVar.jointIndex, underPoses);
|
||||||
defaultAbsPose.rot = animVars.lookup(jointVar.var, defaultAbsPose.rot);
|
defaultAbsPose.rot = animVars.lookup(jointVar.var, defaultAbsPose.rot);
|
||||||
|
defaultAbsPose.trans = animVars.lookup(jointVar.var, defaultAbsPose.trans);
|
||||||
|
|
||||||
// because jointVar is absolute, we must use an absolute parent frame to convert into a relative pose.
|
// because jointVar is absolute, we must use an absolute parent frame to convert into a relative pose.
|
||||||
int parentIndex = _skeleton->getParentIndex(jointVar.jointIndex);
|
int parentIndex = _skeleton->getParentIndex(jointVar.jointIndex);
|
||||||
|
@ -68,6 +69,7 @@ const AnimPoseVec& AnimManipulator::overlay(const AnimVariantMap& animVars, floa
|
||||||
defaultRelPose = AnimPose::identity;
|
defaultRelPose = AnimPose::identity;
|
||||||
defaultAbsPose = _skeleton->getAbsoluteBindPose(jointVar.jointIndex);
|
defaultAbsPose = _skeleton->getAbsoluteBindPose(jointVar.jointIndex);
|
||||||
defaultAbsPose.rot = animVars.lookup(jointVar.var, defaultAbsPose.rot);
|
defaultAbsPose.rot = animVars.lookup(jointVar.var, defaultAbsPose.rot);
|
||||||
|
defaultAbsPose.trans = animVars.lookup(jointVar.var, defaultAbsPose.trans);
|
||||||
|
|
||||||
// because jointVar is absolute, we must use an absolute parent frame to convert into a relative pose
|
// because jointVar is absolute, we must use an absolute parent frame to convert into a relative pose
|
||||||
// here we use the bind pose
|
// here we use the bind pose
|
||||||
|
|
|
@ -173,6 +173,7 @@ void AnimationHandle::applyFrame(float frameIndex) {
|
||||||
const FBXAnimationFrame& floorFrame = animationGeometry.animationFrames.at((int)glm::floor(frameIndex) % frameCount);
|
const FBXAnimationFrame& floorFrame = animationGeometry.animationFrames.at((int)glm::floor(frameIndex) % frameCount);
|
||||||
const FBXAnimationFrame& ceilFrame = animationGeometry.animationFrames.at((int)glm::ceil(frameIndex) % frameCount);
|
const FBXAnimationFrame& ceilFrame = animationGeometry.animationFrames.at((int)glm::ceil(frameIndex) % frameCount);
|
||||||
float frameFraction = glm::fract(frameIndex);
|
float frameFraction = glm::fract(frameIndex);
|
||||||
|
|
||||||
for (int i = 0; i < _jointMappings.size(); i++) {
|
for (int i = 0; i < _jointMappings.size(); i++) {
|
||||||
int mapping = _jointMappings.at(i);
|
int mapping = _jointMappings.at(i);
|
||||||
if (mapping != -1) { // allow missing bones
|
if (mapping != -1) { // allow missing bones
|
||||||
|
@ -183,6 +184,15 @@ void AnimationHandle::applyFrame(float frameIndex) {
|
||||||
_priority,
|
_priority,
|
||||||
false,
|
false,
|
||||||
_mix);
|
_mix);
|
||||||
|
|
||||||
|
// This isn't working.
|
||||||
|
// glm::vec3 floorTranslationPart = floorFrame.translations.at(i) * (1.0f - frameFraction);
|
||||||
|
// glm::vec3 ceilTranslationPart = ceilFrame.translations.at(i) * frameFraction;
|
||||||
|
// glm::vec3 floorCeilFraction = floorTranslationPart + ceilTranslationPart;
|
||||||
|
// glm::vec3 defaultTrans = _rig->getJointDefaultTranslationInConstrainedFrame(i);
|
||||||
|
// glm::vec3 mixedTranslation = floorCeilFraction * (1.0f - _mix) + defaultTrans * _mix;
|
||||||
|
// _rig->setJointTranslation(mapping, true, mixedTranslation, _priority);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,6 +213,7 @@ void AnimationHandle::restoreJoints() {
|
||||||
int mapping = _jointMappings.at(i);
|
int mapping = _jointMappings.at(i);
|
||||||
if (mapping != -1) {
|
if (mapping != -1) {
|
||||||
_rig->restoreJointRotation(mapping, 1.0f, _rig->getJointAnimatinoPriority(mapping));
|
_rig->restoreJointRotation(mapping, 1.0f, _rig->getJointAnimatinoPriority(mapping));
|
||||||
|
_rig->restoreJointTranslation(mapping, 1.0f, _rig->getJointAnimatinoPriority(mapping));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,7 @@ void AvatarRig::updateJointState(int index, glm::mat4 rootTransform) {
|
||||||
|
|
||||||
// compute model transforms
|
// compute model transforms
|
||||||
if (index == _rootJointIndex) {
|
if (index == _rootJointIndex) {
|
||||||
// we always zero-out the translation part of an avatar's root join-transform.
|
|
||||||
state.computeTransform(rootTransform);
|
state.computeTransform(rootTransform);
|
||||||
clearJointTransformTranslation(index);
|
|
||||||
} else {
|
} else {
|
||||||
// guard against out-of-bounds access to _jointStates
|
// guard against out-of-bounds access to _jointStates
|
||||||
int parentIndex = state.getParentIndex();
|
int parentIndex = state.getParentIndex();
|
||||||
|
@ -97,3 +95,28 @@ void AvatarRig::setHandPosition(int jointIndex,
|
||||||
shoulderRotation, priority);
|
shoulderRotation, priority);
|
||||||
setJointRotationInBindFrame(jointIndex, rotation, priority);
|
setJointRotationInBindFrame(jointIndex, rotation, priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AvatarRig::setJointTranslation(int index, bool valid, const glm::vec3& translation, float priority) {
|
||||||
|
if (index != -1 && index < _jointStates.size()) {
|
||||||
|
JointState& state = _jointStates[index];
|
||||||
|
if (valid) {
|
||||||
|
state.setTranslation(translation, priority);
|
||||||
|
} else {
|
||||||
|
state.restoreTranslation(1.0f, priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AvatarRig::setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation, float priority) {
|
||||||
|
if (index != -1 && index < _jointStates.size()) {
|
||||||
|
JointState& state = _jointStates[index];
|
||||||
|
if (valid) {
|
||||||
|
state.setRotationInConstrainedFrame(rotation, priority);
|
||||||
|
state.setTranslation(translation, priority);
|
||||||
|
} else {
|
||||||
|
state.restoreRotation(1.0f, priority);
|
||||||
|
state.restoreTranslation(1.0f, priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -24,6 +24,10 @@ class AvatarRig : public Rig {
|
||||||
virtual void updateJointState(int index, glm::mat4 rootTransform);
|
virtual void updateJointState(int index, glm::mat4 rootTransform);
|
||||||
virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation,
|
virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation,
|
||||||
float scale, float priority);
|
float scale, float priority);
|
||||||
|
virtual void setJointTranslation(int index, bool valid, const glm::vec3& translation, float priority);
|
||||||
|
virtual void setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation, float priority);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // hifi_AvatarRig_h
|
#endif // hifi_AvatarRig_h
|
||||||
|
|
|
@ -27,3 +27,17 @@ void EntityRig::updateJointState(int index, glm::mat4 rootTransform) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EntityRig::setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation, float priority) {
|
||||||
|
if (index != -1 && index < _jointStates.size()) {
|
||||||
|
JointState& state = _jointStates[index];
|
||||||
|
if (valid) {
|
||||||
|
state.setRotationInConstrainedFrame(rotation, priority);
|
||||||
|
// state.setTranslation(translation, priority);
|
||||||
|
} else {
|
||||||
|
state.restoreRotation(1.0f, priority);
|
||||||
|
// state.restoreTranslation(1.0f, priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ class EntityRig : public Rig {
|
||||||
virtual void updateJointState(int index, glm::mat4 rootTransform);
|
virtual void updateJointState(int index, glm::mat4 rootTransform);
|
||||||
virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation,
|
virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation,
|
||||||
float scale, float priority) {}
|
float scale, float priority) {}
|
||||||
|
virtual void setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation, float priority);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_EntityRig_h
|
#endif // hifi_EntityRig_h
|
||||||
|
|
|
@ -43,6 +43,7 @@ void JointState::copyState(const JointState& other) {
|
||||||
_isFree = other._isFree;
|
_isFree = other._isFree;
|
||||||
_parentIndex = other._parentIndex;
|
_parentIndex = other._parentIndex;
|
||||||
_defaultRotation = other._defaultRotation;
|
_defaultRotation = other._defaultRotation;
|
||||||
|
_defaultTranslation = other._defaultTranslation;
|
||||||
_inverseDefaultRotation = other._inverseDefaultRotation;
|
_inverseDefaultRotation = other._inverseDefaultRotation;
|
||||||
_translation = other._translation;
|
_translation = other._translation;
|
||||||
_rotationMin = other._rotationMin;
|
_rotationMin = other._rotationMin;
|
||||||
|
@ -60,6 +61,7 @@ JointState::JointState(const FBXJoint& joint) {
|
||||||
_parentIndex = joint.parentIndex;
|
_parentIndex = joint.parentIndex;
|
||||||
_translation = joint.translation;
|
_translation = joint.translation;
|
||||||
_defaultRotation = joint.rotation;
|
_defaultRotation = joint.rotation;
|
||||||
|
_defaultTranslation = _translation;
|
||||||
_inverseDefaultRotation = joint.inverseDefaultRotation;
|
_inverseDefaultRotation = joint.inverseDefaultRotation;
|
||||||
_rotationMin = joint.rotationMin;
|
_rotationMin = joint.rotationMin;
|
||||||
_rotationMax = joint.rotationMax;
|
_rotationMax = joint.rotationMax;
|
||||||
|
@ -92,6 +94,9 @@ glm::quat JointState::getRotation() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void JointState::initTransform(const glm::mat4& parentTransform) {
|
void JointState::initTransform(const glm::mat4& parentTransform) {
|
||||||
|
|
||||||
|
_unitsScale = extractScale(parentTransform);
|
||||||
|
|
||||||
computeTransform(parentTransform);
|
computeTransform(parentTransform);
|
||||||
_positionInParentFrame = glm::inverse(extractRotation(parentTransform)) * (extractTranslation(_transform) - extractTranslation(parentTransform));
|
_positionInParentFrame = glm::inverse(extractRotation(parentTransform)) * (extractTranslation(_transform) - extractTranslation(parentTransform));
|
||||||
_distanceToParent = glm::length(_positionInParentFrame);
|
_distanceToParent = glm::length(_positionInParentFrame);
|
||||||
|
@ -139,6 +144,13 @@ void JointState::restoreRotation(float fraction, float priority) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JointState::restoreTranslation(float fraction, float priority) {
|
||||||
|
if (priority == _animationPriority || _animationPriority == 0.0f) {
|
||||||
|
_translation = _translation * (1.0f - fraction) + _defaultTranslation * fraction;
|
||||||
|
_animationPriority = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void JointState::setRotationInBindFrame(const glm::quat& rotation, float priority, bool constrain) {
|
void JointState::setRotationInBindFrame(const glm::quat& rotation, float priority, bool constrain) {
|
||||||
// rotation is from bind- to model-frame
|
// rotation is from bind- to model-frame
|
||||||
if (priority >= _animationPriority) {
|
if (priority >= _animationPriority) {
|
||||||
|
@ -245,6 +257,14 @@ void JointState::setRotationInConstrainedFrame(glm::quat targetRotation, float p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JointState::setTranslation(const glm::vec3& translation, float priority) {
|
||||||
|
if (priority >= _animationPriority || _animationPriority == 0.0f) {
|
||||||
|
_translation = translation / _unitsScale;
|
||||||
|
_transformChanged = true;
|
||||||
|
_animationPriority = priority;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void JointState::setRotationInConstrainedFrameInternal(const glm::quat& targetRotation) {
|
void JointState::setRotationInConstrainedFrameInternal(const glm::quat& targetRotation) {
|
||||||
if (_rotationInConstrainedFrame != targetRotation) {
|
if (_rotationInConstrainedFrame != targetRotation) {
|
||||||
glm::quat parentRotation = computeParentRotation();
|
glm::quat parentRotation = computeParentRotation();
|
||||||
|
@ -269,13 +289,17 @@ bool JointState::rotationIsDefault(const glm::quat& rotation, float tolerance) c
|
||||||
glm::abs(rotation.w - defaultRotation.w) < tolerance;
|
glm::abs(rotation.w - defaultRotation.w) < tolerance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool JointState::translationIsDefault(const glm::vec3& translation, float tolerance) const {
|
||||||
|
return glm::distance(_defaultTranslation, translation * _unitsScale) < tolerance;
|
||||||
|
}
|
||||||
|
|
||||||
glm::quat JointState::getDefaultRotationInParentFrame() const {
|
glm::quat JointState::getDefaultRotationInParentFrame() const {
|
||||||
// NOTE: the result is constant and could be cached
|
// NOTE: the result is constant and could be cached
|
||||||
return _preRotation * _defaultRotation * _postRotation;
|
return _preRotation * _defaultRotation * _postRotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
const glm::vec3& JointState::getDefaultTranslationInConstrainedFrame() const {
|
glm::vec3 JointState::getDefaultTranslationInConstrainedFrame() const {
|
||||||
return _translation;
|
return _defaultTranslation * _unitsScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JointState::slaveVisibleTransform() {
|
void JointState::slaveVisibleTransform() {
|
||||||
|
|
|
@ -77,6 +77,8 @@ public:
|
||||||
/// \param priority priority level of this animation blend
|
/// \param priority priority level of this animation blend
|
||||||
void restoreRotation(float fraction, float priority);
|
void restoreRotation(float fraction, float priority);
|
||||||
|
|
||||||
|
void restoreTranslation(float fraction, float priority);
|
||||||
|
|
||||||
/// \param rotation is from bind- to model-frame
|
/// \param rotation is from bind- to model-frame
|
||||||
/// computes and sets new _rotationInConstrainedFrame
|
/// computes and sets new _rotationInConstrainedFrame
|
||||||
/// NOTE: the JointState's model-frame transform/rotation are NOT updated!
|
/// NOTE: the JointState's model-frame transform/rotation are NOT updated!
|
||||||
|
@ -88,14 +90,18 @@ public:
|
||||||
void setRotationInModelFrame(const glm::quat& rotationInModelFrame, float priority, bool constrain);
|
void setRotationInModelFrame(const glm::quat& rotationInModelFrame, float priority, bool constrain);
|
||||||
|
|
||||||
void setRotationInConstrainedFrame(glm::quat targetRotation, float priority, bool constrain = false, float mix = 1.0f);
|
void setRotationInConstrainedFrame(glm::quat targetRotation, float priority, bool constrain = false, float mix = 1.0f);
|
||||||
|
|
||||||
|
void setTranslation(const glm::vec3& translation, float priority);
|
||||||
|
|
||||||
void setVisibleRotationInConstrainedFrame(const glm::quat& targetRotation);
|
void setVisibleRotationInConstrainedFrame(const glm::quat& targetRotation);
|
||||||
const glm::quat& getRotationInConstrainedFrame() const { return _rotationInConstrainedFrame; }
|
const glm::quat& getRotationInConstrainedFrame() const { return _rotationInConstrainedFrame; }
|
||||||
const glm::quat& getVisibleRotationInConstrainedFrame() const { return _visibleRotationInConstrainedFrame; }
|
const glm::quat& getVisibleRotationInConstrainedFrame() const { return _visibleRotationInConstrainedFrame; }
|
||||||
|
|
||||||
bool rotationIsDefault(const glm::quat& rotation, float tolerance = EPSILON) const;
|
bool rotationIsDefault(const glm::quat& rotation, float tolerance = EPSILON) const;
|
||||||
|
bool translationIsDefault(const glm::vec3& translation, float tolerance = EPSILON) const;
|
||||||
|
|
||||||
glm::quat getDefaultRotationInParentFrame() const;
|
glm::quat getDefaultRotationInParentFrame() const;
|
||||||
const glm::vec3& getDefaultTranslationInConstrainedFrame() const;
|
glm::vec3 getDefaultTranslationInConstrainedFrame() const;
|
||||||
|
|
||||||
|
|
||||||
void clearTransformTranslation();
|
void clearTransformTranslation();
|
||||||
|
@ -110,12 +116,13 @@ public:
|
||||||
void setTransform(const glm::mat4& transform) { _transform = transform; }
|
void setTransform(const glm::mat4& transform) { _transform = transform; }
|
||||||
void setVisibleTransform(const glm::mat4& transform) { _visibleTransform = transform; }
|
void setVisibleTransform(const glm::mat4& transform) { _visibleTransform = transform; }
|
||||||
|
|
||||||
const glm::vec3& getTranslation() const { return _translation; }
|
glm::vec3 getTranslation() const { return _translation * _unitsScale; }
|
||||||
const glm::mat4& getPreTransform() const { return _preTransform; }
|
const glm::mat4& getPreTransform() const { return _preTransform; }
|
||||||
const glm::mat4& getPostTransform() const { return _postTransform; }
|
const glm::mat4& getPostTransform() const { return _postTransform; }
|
||||||
const glm::quat& getPreRotation() const { return _preRotation; }
|
const glm::quat& getPreRotation() const { return _preRotation; }
|
||||||
const glm::quat& getPostRotation() const { return _postRotation; }
|
const glm::quat& getPostRotation() const { return _postRotation; }
|
||||||
const glm::quat& getDefaultRotation() const { return _defaultRotation; }
|
const glm::quat& getDefaultRotation() const { return _defaultRotation; }
|
||||||
|
glm::vec3 getDefaultTranslation() const { return _defaultTranslation * _unitsScale; }
|
||||||
const glm::quat& getInverseDefaultRotation() const { return _inverseDefaultRotation; }
|
const glm::quat& getInverseDefaultRotation() const { return _inverseDefaultRotation; }
|
||||||
const QString& getName() const { return _name; }
|
const QString& getName() const { return _name; }
|
||||||
bool getIsFree() const { return _isFree; }
|
bool getIsFree() const { return _isFree; }
|
||||||
|
@ -144,6 +151,7 @@ private:
|
||||||
|
|
||||||
glm::quat _defaultRotation; // Not necessarilly bind rotation. See FBXJoint transform/bindTransform
|
glm::quat _defaultRotation; // Not necessarilly bind rotation. See FBXJoint transform/bindTransform
|
||||||
glm::quat _inverseDefaultRotation;
|
glm::quat _inverseDefaultRotation;
|
||||||
|
glm::vec3 _defaultTranslation;
|
||||||
glm::vec3 _translation;
|
glm::vec3 _translation;
|
||||||
QString _name;
|
QString _name;
|
||||||
int _parentIndex;
|
int _parentIndex;
|
||||||
|
@ -155,6 +163,8 @@ private:
|
||||||
glm::mat4 _preTransform;
|
glm::mat4 _preTransform;
|
||||||
glm::mat4 _postTransform;
|
glm::mat4 _postTransform;
|
||||||
glm::quat _inverseBindRotation;
|
glm::quat _inverseBindRotation;
|
||||||
|
|
||||||
|
glm::vec3 _unitsScale{1.0f, 1.0f, 1.0f};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_JointState_h
|
#endif // hifi_JointState_h
|
||||||
|
|
|
@ -270,6 +270,7 @@ void Rig::reset(const QVector<FBXJoint>& fbxJoints) {
|
||||||
}
|
}
|
||||||
for (int i = 0; i < _jointStates.size(); i++) {
|
for (int i = 0; i < _jointStates.size(); i++) {
|
||||||
_jointStates[i].setRotationInConstrainedFrame(fbxJoints.at(i).rotation, 0.0f);
|
_jointStates[i].setRotationInConstrainedFrame(fbxJoints.at(i).rotation, 0.0f);
|
||||||
|
_jointStates[i].setTranslation(fbxJoints.at(i).translation, 0.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,6 +290,16 @@ bool Rig::getJointStateRotation(int index, glm::quat& rotation) const {
|
||||||
return !state.rotationIsDefault(rotation);
|
return !state.rotationIsDefault(rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Rig::getJointStateTranslation(int index, glm::vec3& translation) const {
|
||||||
|
if (index == -1 || index >= _jointStates.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const JointState& state = _jointStates.at(index);
|
||||||
|
translation = state.getTranslation();
|
||||||
|
return !state.translationIsDefault(translation);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Rig::getVisibleJointState(int index, glm::quat& rotation) const {
|
bool Rig::getVisibleJointState(int index, glm::quat& rotation) const {
|
||||||
if (index == -1 || index >= _jointStates.size()) {
|
if (index == -1 || index >= _jointStates.size()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -302,6 +313,7 @@ void Rig::clearJointState(int index) {
|
||||||
if (index != -1 && index < _jointStates.size()) {
|
if (index != -1 && index < _jointStates.size()) {
|
||||||
JointState& state = _jointStates[index];
|
JointState& state = _jointStates[index];
|
||||||
state.setRotationInConstrainedFrame(glm::quat(), 0.0f);
|
state.setRotationInConstrainedFrame(glm::quat(), 0.0f);
|
||||||
|
state.setTranslation(state.getDefaultTranslationInConstrainedFrame(), 0.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,7 +340,7 @@ void Rig::setJointAnimatinoPriority(int index, float newPriority) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rig::setJointState(int index, bool valid, const glm::quat& rotation, float priority) {
|
void Rig::setJointRotation(int index, bool valid, const glm::quat& rotation, float priority) {
|
||||||
if (index != -1 && index < _jointStates.size()) {
|
if (index != -1 && index < _jointStates.size()) {
|
||||||
JointState& state = _jointStates[index];
|
JointState& state = _jointStates[index];
|
||||||
if (valid) {
|
if (valid) {
|
||||||
|
@ -345,6 +357,12 @@ void Rig::restoreJointRotation(int index, float fraction, float priority) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Rig::restoreJointTranslation(int index, float fraction, float priority) {
|
||||||
|
if (index != -1 && index < _jointStates.size()) {
|
||||||
|
_jointStates[index].restoreTranslation(fraction, priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Rig::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position,
|
bool Rig::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position,
|
||||||
glm::vec3 translation, glm::quat rotation) const {
|
glm::vec3 translation, glm::quat rotation) const {
|
||||||
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
|
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
|
||||||
|
@ -380,6 +398,14 @@ bool Rig::getJointRotation(int jointIndex, glm::quat& rotation) const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Rig::getJointTranslation(int jointIndex, glm::vec3& translation) const {
|
||||||
|
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
translation = _jointStates[jointIndex].getTranslation();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Rig::getJointCombinedRotation(int jointIndex, glm::quat& result, const glm::quat& rotation) const {
|
bool Rig::getJointCombinedRotation(int jointIndex, glm::quat& result, const glm::quat& rotation) const {
|
||||||
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
|
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -590,7 +616,13 @@ void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) {
|
||||||
// copy poses into jointStates
|
// copy poses into jointStates
|
||||||
const float PRIORITY = 1.0f;
|
const float PRIORITY = 1.0f;
|
||||||
for (size_t i = 0; i < poses.size(); i++) {
|
for (size_t i = 0; i < poses.size(); i++) {
|
||||||
setJointRotationInConstrainedFrame((int)i, glm::inverse(_animSkeleton->getRelativeBindPose(i).rot) * poses[i].rot, PRIORITY, false);
|
setJointRotationInConstrainedFrame((int)i,
|
||||||
|
glm::inverse(_animSkeleton->getRelativeBindPose(i).rot) * poses[i].rot,
|
||||||
|
PRIORITY,
|
||||||
|
false);
|
||||||
|
|
||||||
|
JointState& state = _jointStates[i];
|
||||||
|
setJointTranslation((int)i, true, poses[i].trans, PRIORITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -866,6 +898,7 @@ bool Rig::restoreJointPosition(int jointIndex, float fraction, float priority, c
|
||||||
foreach (int index, freeLineage) {
|
foreach (int index, freeLineage) {
|
||||||
JointState& state = _jointStates[index];
|
JointState& state = _jointStates[index];
|
||||||
state.restoreRotation(fraction, priority);
|
state.restoreRotation(fraction, priority);
|
||||||
|
state.restoreTranslation(fraction, priority);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,6 +129,7 @@ public:
|
||||||
void clearJointTransformTranslation(int jointIndex);
|
void clearJointTransformTranslation(int jointIndex);
|
||||||
void reset(const QVector<FBXJoint>& fbxJoints);
|
void reset(const QVector<FBXJoint>& fbxJoints);
|
||||||
bool getJointStateRotation(int index, glm::quat& rotation) const;
|
bool getJointStateRotation(int index, glm::quat& rotation) const;
|
||||||
|
bool getJointStateTranslation(int index, glm::vec3& translation) const;
|
||||||
void applyJointRotationDelta(int jointIndex, const glm::quat& delta, bool constrain, float priority);
|
void applyJointRotationDelta(int jointIndex, const glm::quat& delta, bool constrain, float priority);
|
||||||
JointState getJointState(int jointIndex) const; // XXX
|
JointState getJointState(int jointIndex) const; // XXX
|
||||||
bool getVisibleJointState(int index, glm::quat& rotation) const;
|
bool getVisibleJointState(int index, glm::quat& rotation) const;
|
||||||
|
@ -137,14 +138,21 @@ public:
|
||||||
void clearJointAnimationPriority(int index);
|
void clearJointAnimationPriority(int index);
|
||||||
float getJointAnimatinoPriority(int index);
|
float getJointAnimatinoPriority(int index);
|
||||||
void setJointAnimatinoPriority(int index, float newPriority);
|
void setJointAnimatinoPriority(int index, float newPriority);
|
||||||
void setJointState(int index, bool valid, const glm::quat& rotation, float priority);
|
|
||||||
|
virtual void setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation,
|
||||||
|
float priority) = 0;
|
||||||
|
virtual void setJointTranslation(int index, bool valid, const glm::vec3& translation, float priority) {}
|
||||||
|
void setJointRotation(int index, bool valid, const glm::quat& rotation, float priority);
|
||||||
|
|
||||||
void restoreJointRotation(int index, float fraction, float priority);
|
void restoreJointRotation(int index, float fraction, float priority);
|
||||||
|
void restoreJointTranslation(int index, float fraction, float priority);
|
||||||
bool getJointPositionInWorldFrame(int jointIndex, glm::vec3& position,
|
bool getJointPositionInWorldFrame(int jointIndex, glm::vec3& position,
|
||||||
glm::vec3 translation, glm::quat rotation) const;
|
glm::vec3 translation, glm::quat rotation) const;
|
||||||
|
|
||||||
bool getJointPosition(int jointIndex, glm::vec3& position) const;
|
bool getJointPosition(int jointIndex, glm::vec3& position) const;
|
||||||
bool getJointRotationInWorldFrame(int jointIndex, glm::quat& result, const glm::quat& rotation) const;
|
bool getJointRotationInWorldFrame(int jointIndex, glm::quat& result, const glm::quat& rotation) const;
|
||||||
bool getJointRotation(int jointIndex, glm::quat& rotation) const;
|
bool getJointRotation(int jointIndex, glm::quat& rotation) const;
|
||||||
|
bool getJointTranslation(int jointIndex, glm::vec3& translation) const;
|
||||||
bool getJointCombinedRotation(int jointIndex, glm::quat& result, const glm::quat& rotation) const;
|
bool getJointCombinedRotation(int jointIndex, glm::quat& result, const glm::quat& rotation) const;
|
||||||
bool getVisibleJointPositionInWorldFrame(int jointIndex, glm::vec3& position,
|
bool getVisibleJointPositionInWorldFrame(int jointIndex, glm::vec3& position,
|
||||||
glm::vec3 translation, glm::quat rotation) const;
|
glm::vec3 translation, glm::quat rotation) const;
|
||||||
|
|
|
@ -49,6 +49,7 @@ AvatarData::AvatarData() :
|
||||||
_keyState(NO_KEY_DOWN),
|
_keyState(NO_KEY_DOWN),
|
||||||
_forceFaceTrackerConnected(false),
|
_forceFaceTrackerConnected(false),
|
||||||
_hasNewJointRotations(true),
|
_hasNewJointRotations(true),
|
||||||
|
_hasNewJointTranslations(true),
|
||||||
_headData(NULL),
|
_headData(NULL),
|
||||||
_handData(NULL),
|
_handData(NULL),
|
||||||
_faceModelURL("http://invalid.com"),
|
_faceModelURL("http://invalid.com"),
|
||||||
|
@ -278,12 +279,16 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) {
|
||||||
// pupil dilation
|
// pupil dilation
|
||||||
destinationBuffer += packFloatToByte(destinationBuffer, _headData->_pupilDilation, 1.0f);
|
destinationBuffer += packFloatToByte(destinationBuffer, _headData->_pupilDilation, 1.0f);
|
||||||
|
|
||||||
// joint data
|
// joint rotation data
|
||||||
*destinationBuffer++ = _jointData.size();
|
*destinationBuffer++ = _jointData.size();
|
||||||
unsigned char* validityPosition = destinationBuffer;
|
unsigned char* validityPosition = destinationBuffer;
|
||||||
unsigned char validity = 0;
|
unsigned char validity = 0;
|
||||||
int validityBit = 0;
|
int validityBit = 0;
|
||||||
|
|
||||||
|
#ifdef WANT_DEBUG
|
||||||
|
int rotationSentCount = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
_lastSentJointData.resize(_jointData.size());
|
_lastSentJointData.resize(_jointData.size());
|
||||||
|
|
||||||
for (int i=0; i < _jointData.size(); i++) {
|
for (int i=0; i < _jointData.size(); i++) {
|
||||||
|
@ -292,7 +297,12 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) {
|
||||||
if (sendAll ||
|
if (sendAll ||
|
||||||
!cullSmallChanges ||
|
!cullSmallChanges ||
|
||||||
fabsf(glm::dot(data.rotation, _lastSentJointData[i].rotation)) <= AVATAR_MIN_ROTATION_DOT) {
|
fabsf(glm::dot(data.rotation, _lastSentJointData[i].rotation)) <= AVATAR_MIN_ROTATION_DOT) {
|
||||||
|
if (data.rotationSet) {
|
||||||
validity |= (1 << validityBit);
|
validity |= (1 << validityBit);
|
||||||
|
#ifdef WANT_DEBUG
|
||||||
|
rotationSentCount++;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (++validityBit == BITS_IN_BYTE) {
|
if (++validityBit == BITS_IN_BYTE) {
|
||||||
|
@ -317,6 +327,73 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// joint translation data
|
||||||
|
validityPosition = destinationBuffer;
|
||||||
|
validity = 0;
|
||||||
|
validityBit = 0;
|
||||||
|
|
||||||
|
#ifdef WANT_DEBUG
|
||||||
|
int translationSentCount = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float maxTranslationDimension = 0.0;
|
||||||
|
for (int i=0; i < _jointData.size(); i++) {
|
||||||
|
const JointData& data = _jointData.at(i);
|
||||||
|
if (sendAll || _lastSentJointData[i].translation != data.translation) {
|
||||||
|
if (sendAll ||
|
||||||
|
!cullSmallChanges ||
|
||||||
|
glm::distance(data.translation, _lastSentJointData[i].translation) > AVATAR_MIN_TRANSLATION) {
|
||||||
|
if (data.translationSet) {
|
||||||
|
validity |= (1 << validityBit);
|
||||||
|
#ifdef WANT_DEBUG
|
||||||
|
translationSentCount++;
|
||||||
|
#endif
|
||||||
|
maxTranslationDimension = glm::max(fabsf(data.translation.x), maxTranslationDimension);
|
||||||
|
maxTranslationDimension = glm::max(fabsf(data.translation.y), maxTranslationDimension);
|
||||||
|
maxTranslationDimension = glm::max(fabsf(data.translation.z), maxTranslationDimension);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (++validityBit == BITS_IN_BYTE) {
|
||||||
|
*destinationBuffer++ = validity;
|
||||||
|
validityBit = validity = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (validityBit != 0) {
|
||||||
|
*destinationBuffer++ = validity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO -- automatically pick translationCompressionRadix
|
||||||
|
int translationCompressionRadix = 12;
|
||||||
|
|
||||||
|
*destinationBuffer++ = translationCompressionRadix;
|
||||||
|
|
||||||
|
validityBit = 0;
|
||||||
|
validity = *validityPosition++;
|
||||||
|
for (int i = 0; i < _jointData.size(); i ++) {
|
||||||
|
const JointData& data = _jointData[ i ];
|
||||||
|
if (validity & (1 << validityBit)) {
|
||||||
|
destinationBuffer +=
|
||||||
|
packFloatVec3ToSignedTwoByteFixed(destinationBuffer, data.translation, translationCompressionRadix);
|
||||||
|
}
|
||||||
|
if (++validityBit == BITS_IN_BYTE) {
|
||||||
|
validityBit = 0;
|
||||||
|
validity = *validityPosition++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WANT_DEBUG
|
||||||
|
if (sendAll) {
|
||||||
|
qDebug() << "SENDING -- rotations:" << rotationSentCount << "translations:" << translationSentCount
|
||||||
|
<< "largest:" << maxTranslationDimension
|
||||||
|
<< "radix:" << translationCompressionRadix
|
||||||
|
<< "size:" << (int)(destinationBuffer - startPosition);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return avatarDataByteArray.left(destinationBuffer - startPosition);
|
return avatarDataByteArray.left(destinationBuffer - startPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,9 +405,18 @@ void AvatarData::doneEncoding(bool cullSmallChanges) {
|
||||||
if (_lastSentJointData[i].rotation != data.rotation) {
|
if (_lastSentJointData[i].rotation != data.rotation) {
|
||||||
if (!cullSmallChanges ||
|
if (!cullSmallChanges ||
|
||||||
fabsf(glm::dot(data.rotation, _lastSentJointData[i].rotation)) <= AVATAR_MIN_ROTATION_DOT) {
|
fabsf(glm::dot(data.rotation, _lastSentJointData[i].rotation)) <= AVATAR_MIN_ROTATION_DOT) {
|
||||||
|
if (data.rotationSet) {
|
||||||
_lastSentJointData[i].rotation = data.rotation;
|
_lastSentJointData[i].rotation = data.rotation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!cullSmallChanges ||
|
||||||
|
glm::distance(data.translation, _lastSentJointData[i].translation) > AVATAR_MIN_TRANSLATION) {
|
||||||
|
if (data.translationSet) {
|
||||||
|
_lastSentJointData[i].translation = data.translation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -556,7 +642,11 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
||||||
sourceBuffer += unpackFloatFromByte(sourceBuffer, _headData->_pupilDilation, 1.0f);
|
sourceBuffer += unpackFloatFromByte(sourceBuffer, _headData->_pupilDilation, 1.0f);
|
||||||
} // 1 byte
|
} // 1 byte
|
||||||
|
|
||||||
// joint data
|
|
||||||
|
//-----------------------
|
||||||
|
// joint rotations
|
||||||
|
//-----------------------
|
||||||
|
|
||||||
int numJoints = *sourceBuffer++;
|
int numJoints = *sourceBuffer++;
|
||||||
int bytesOfValidity = (int)ceil((float)numJoints / (float)BITS_IN_BYTE);
|
int bytesOfValidity = (int)ceil((float)numJoints / (float)BITS_IN_BYTE);
|
||||||
minPossibleSize += bytesOfValidity;
|
minPossibleSize += bytesOfValidity;
|
||||||
|
@ -569,13 +659,13 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
||||||
}
|
}
|
||||||
return maxAvailableSize;
|
return maxAvailableSize;
|
||||||
}
|
}
|
||||||
int numValidJoints = 0;
|
int numValidJointRotations = 0;
|
||||||
_jointData.resize(numJoints);
|
_jointData.resize(numJoints);
|
||||||
|
|
||||||
QVector<bool> valids;
|
QVector<bool> validRotations;
|
||||||
valids.resize(numJoints);
|
validRotations.resize(numJoints);
|
||||||
|
|
||||||
{ // validity bits
|
{ // rotation validity bits
|
||||||
unsigned char validity = 0;
|
unsigned char validity = 0;
|
||||||
int validityBit = 0;
|
int validityBit = 0;
|
||||||
for (int i = 0; i < numJoints; i++) {
|
for (int i = 0; i < numJoints; i++) {
|
||||||
|
@ -584,20 +674,19 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
||||||
}
|
}
|
||||||
bool valid = (bool)(validity & (1 << validityBit));
|
bool valid = (bool)(validity & (1 << validityBit));
|
||||||
if (valid) {
|
if (valid) {
|
||||||
++numValidJoints;
|
++numValidJointRotations;
|
||||||
}
|
}
|
||||||
valids[i] = valid;
|
validRotations[i] = valid;
|
||||||
validityBit = (validityBit + 1) % BITS_IN_BYTE;
|
validityBit = (validityBit + 1) % BITS_IN_BYTE;
|
||||||
}
|
}
|
||||||
}
|
} // 1 + bytesOfValidity bytes
|
||||||
// 1 + bytesOfValidity bytes
|
|
||||||
|
|
||||||
// each joint rotation component is stored in two bytes (sizeof(uint16_t))
|
// each joint rotation component is stored in two bytes (sizeof(uint16_t))
|
||||||
int COMPONENTS_PER_QUATERNION = 4;
|
int COMPONENTS_PER_QUATERNION = 4;
|
||||||
minPossibleSize += numValidJoints * COMPONENTS_PER_QUATERNION * sizeof(uint16_t);
|
minPossibleSize += numValidJointRotations * COMPONENTS_PER_QUATERNION * sizeof(uint16_t);
|
||||||
if (minPossibleSize > maxAvailableSize) {
|
if (minPossibleSize > maxAvailableSize) {
|
||||||
if (shouldLogError(now)) {
|
if (shouldLogError(now)) {
|
||||||
qCDebug(avatars) << "Malformed AvatarData packet after JointData;"
|
qCDebug(avatars) << "Malformed AvatarData packet after JointData rotation validity;"
|
||||||
<< " displayName = '" << _displayName << "'"
|
<< " displayName = '" << _displayName << "'"
|
||||||
<< " minPossibleSize = " << minPossibleSize
|
<< " minPossibleSize = " << minPossibleSize
|
||||||
<< " maxAvailableSize = " << maxAvailableSize;
|
<< " maxAvailableSize = " << maxAvailableSize;
|
||||||
|
@ -608,13 +697,75 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
||||||
{ // joint data
|
{ // joint data
|
||||||
for (int i = 0; i < numJoints; i++) {
|
for (int i = 0; i < numJoints; i++) {
|
||||||
JointData& data = _jointData[i];
|
JointData& data = _jointData[i];
|
||||||
if (valids[i]) {
|
if (validRotations[i]) {
|
||||||
_hasNewJointRotations = true;
|
_hasNewJointRotations = true;
|
||||||
|
data.rotationSet = true;
|
||||||
sourceBuffer += unpackOrientationQuatFromBytes(sourceBuffer, data.rotation);
|
sourceBuffer += unpackOrientationQuatFromBytes(sourceBuffer, data.rotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // numJoints * 8 bytes
|
} // numJoints * 8 bytes
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------
|
||||||
|
// joint translations
|
||||||
|
//-----------------------
|
||||||
|
|
||||||
|
// get translation validity bits -- these indicate which translations were packed
|
||||||
|
int numValidJointTranslations = 0;
|
||||||
|
QVector<bool> validTranslations;
|
||||||
|
validTranslations.resize(numJoints);
|
||||||
|
|
||||||
|
{ // translation validity bits
|
||||||
|
unsigned char validity = 0;
|
||||||
|
int validityBit = 0;
|
||||||
|
for (int i = 0; i < numJoints; i++) {
|
||||||
|
if (validityBit == 0) {
|
||||||
|
validity = *sourceBuffer++;
|
||||||
|
}
|
||||||
|
bool valid = (bool)(validity & (1 << validityBit));
|
||||||
|
if (valid) {
|
||||||
|
++numValidJointTranslations;
|
||||||
|
}
|
||||||
|
validTranslations[i] = valid;
|
||||||
|
validityBit = (validityBit + 1) % BITS_IN_BYTE;
|
||||||
|
}
|
||||||
|
} // 1 + bytesOfValidity bytes
|
||||||
|
|
||||||
|
// each joint translation component is stored in 6 bytes. 1 byte for translationCompressionRadix
|
||||||
|
minPossibleSize += numValidJointTranslations * 6 + 1;
|
||||||
|
if (minPossibleSize > maxAvailableSize) {
|
||||||
|
if (shouldLogError(now)) {
|
||||||
|
qCDebug(avatars) << "Malformed AvatarData packet after JointData translation validity;"
|
||||||
|
<< " displayName = '" << _displayName << "'"
|
||||||
|
<< " minPossibleSize = " << minPossibleSize
|
||||||
|
<< " maxAvailableSize = " << maxAvailableSize;
|
||||||
|
}
|
||||||
|
return maxAvailableSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
int translationCompressionRadix = *sourceBuffer++;
|
||||||
|
|
||||||
|
{ // joint data
|
||||||
|
for (int i = 0; i < numJoints; i++) {
|
||||||
|
JointData& data = _jointData[i];
|
||||||
|
if (validTranslations[i]) {
|
||||||
|
sourceBuffer +=
|
||||||
|
unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, data.translation, translationCompressionRadix);
|
||||||
|
_hasNewJointTranslations = true;
|
||||||
|
data.translationSet = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // numJoints * 12 bytes
|
||||||
|
|
||||||
|
#ifdef WANT_DEBUG
|
||||||
|
if (numValidJointRotations > 15) {
|
||||||
|
qDebug() << "RECEIVING -- rotations:" << numValidJointRotations
|
||||||
|
<< "translations:" << numValidJointTranslations
|
||||||
|
<< "radix:" << translationCompressionRadix
|
||||||
|
<< "size:" << (int)(sourceBuffer - startPosition);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int numBytesRead = sourceBuffer - startPosition;
|
int numBytesRead = sourceBuffer - startPosition;
|
||||||
_averageBytesReceived.updateAverage(numBytesRead);
|
_averageBytesReceived.updateAverage(numBytesRead);
|
||||||
return numBytesRead;
|
return numBytesRead;
|
||||||
|
@ -800,7 +951,7 @@ void AvatarData::changeReferential(Referential* ref) {
|
||||||
_referential = ref;
|
_referential = ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarData::setJointData(int index, const glm::quat& rotation) {
|
void AvatarData::setJointData(int index, const glm::quat& rotation, const glm::vec3& translation) {
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -813,6 +964,7 @@ void AvatarData::setJointData(int index, const glm::quat& rotation) {
|
||||||
}
|
}
|
||||||
JointData& data = _jointData[index];
|
JointData& data = _jointData[index];
|
||||||
data.rotation = rotation;
|
data.rotation = rotation;
|
||||||
|
data.translation = translation;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarData::clearJointData(int index) {
|
void AvatarData::clearJointData(int index) {
|
||||||
|
@ -854,13 +1006,67 @@ glm::quat AvatarData::getJointRotation(int index) const {
|
||||||
return index < _jointData.size() ? _jointData.at(index).rotation : glm::quat();
|
return index < _jointData.size() ? _jointData.at(index).rotation : glm::quat();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarData::setJointData(const QString& name, const glm::quat& rotation) {
|
|
||||||
|
glm::vec3 AvatarData::getJointTranslation(int index) const {
|
||||||
|
if (index == -1) {
|
||||||
|
return glm::vec3();
|
||||||
|
}
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
glm::vec3 result;
|
||||||
|
QMetaObject::invokeMethod(const_cast<AvatarData*>(this), "getJointTranslation", Qt::BlockingQueuedConnection,
|
||||||
|
Q_RETURN_ARG(glm::vec3, result), Q_ARG(int, index));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return index < _jointData.size() ? _jointData.at(index).translation : glm::vec3();
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 AvatarData::getJointTranslation(const QString& name) const {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
glm::vec3 result;
|
||||||
|
QMetaObject::invokeMethod(const_cast<AvatarData*>(this), "getJointTranslation", Qt::BlockingQueuedConnection,
|
||||||
|
Q_RETURN_ARG(glm::vec3, result), Q_ARG(const QString&, name));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return getJointTranslation(getJointIndex(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvatarData::setJointData(const QString& name, const glm::quat& rotation, const glm::vec3& translation) {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(this, "setJointData", Q_ARG(const QString&, name),
|
QMetaObject::invokeMethod(this, "setJointData", Q_ARG(const QString&, name),
|
||||||
Q_ARG(const glm::quat&, rotation));
|
Q_ARG(const glm::quat&, rotation));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setJointData(getJointIndex(name), rotation);
|
setJointData(getJointIndex(name), rotation, translation);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvatarData::setJointRotation(int index, const glm::quat& rotation) {
|
||||||
|
if (index == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "setJointRotation", Q_ARG(int, index), Q_ARG(const glm::quat&, rotation));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_jointData.size() <= index) {
|
||||||
|
_jointData.resize(index + 1);
|
||||||
|
}
|
||||||
|
JointData& data = _jointData[index];
|
||||||
|
data.rotation = rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvatarData::setJointTranslation(int index, const glm::vec3& translation) {
|
||||||
|
if (index == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "setJointTranslation", Q_ARG(int, index), Q_ARG(const glm::vec3&, translation));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_jointData.size() <= index) {
|
||||||
|
_jointData.resize(index + 1);
|
||||||
|
}
|
||||||
|
JointData& data = _jointData[index];
|
||||||
|
data.translation = translation;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarData::clearJointData(const QString& name) {
|
void AvatarData::clearJointData(const QString& name) {
|
||||||
|
@ -918,7 +1124,25 @@ void AvatarData::setJointRotations(QVector<glm::quat> jointRotations) {
|
||||||
}
|
}
|
||||||
for (int i = 0; i < jointRotations.size(); ++i) {
|
for (int i = 0; i < jointRotations.size(); ++i) {
|
||||||
if (i < _jointData.size()) {
|
if (i < _jointData.size()) {
|
||||||
setJointData(i, jointRotations[i]);
|
setJointRotation(i, jointRotations[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvatarData::setJointTranslations(QVector<glm::vec3> jointTranslations) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QVector<glm::quat> result;
|
||||||
|
QMetaObject::invokeMethod(const_cast<AvatarData*>(this),
|
||||||
|
"setJointTranslations", Qt::BlockingQueuedConnection,
|
||||||
|
Q_ARG(QVector<glm::vec3>, jointTranslations));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_jointData.size() < jointTranslations.size()) {
|
||||||
|
_jointData.resize(jointTranslations.size());
|
||||||
|
}
|
||||||
|
for (int i = 0; i < jointTranslations.size(); ++i) {
|
||||||
|
if (i < _jointData.size()) {
|
||||||
|
setJointTranslation(i, jointTranslations[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,6 +117,7 @@ const QString DEFAULT_FULL_AVATAR_MODEL_NAME = QString("Default");
|
||||||
const float AVATAR_SEND_FULL_UPDATE_RATIO = 0.02f;
|
const float AVATAR_SEND_FULL_UPDATE_RATIO = 0.02f;
|
||||||
// this controls how large a change in joint-rotation must be before the interface sends it to the avatar mixer
|
// this controls how large a change in joint-rotation must be before the interface sends it to the avatar mixer
|
||||||
const float AVATAR_MIN_ROTATION_DOT = 0.9999999f;
|
const float AVATAR_MIN_ROTATION_DOT = 0.9999999f;
|
||||||
|
const float AVATAR_MIN_TRANSLATION = 0.0001f;
|
||||||
|
|
||||||
|
|
||||||
// Where one's own Avatar begins in the world (will be overwritten if avatar data file is found).
|
// Where one's own Avatar begins in the world (will be overwritten if avatar data file is found).
|
||||||
|
@ -240,20 +241,24 @@ public:
|
||||||
Q_INVOKABLE char getHandState() const { return _handState; }
|
Q_INVOKABLE char getHandState() const { return _handState; }
|
||||||
|
|
||||||
const QVector<JointData>& getJointData() const { return _jointData; }
|
const QVector<JointData>& getJointData() const { return _jointData; }
|
||||||
void setJointData(const QVector<JointData>& jointData) { _jointData = jointData; }
|
|
||||||
|
|
||||||
Q_INVOKABLE virtual void setJointData(int index, const glm::quat& rotation);
|
Q_INVOKABLE virtual void setJointData(int index, const glm::quat& rotation, const glm::vec3& translation);
|
||||||
|
Q_INVOKABLE virtual void setJointRotation(int index, const glm::quat& rotation);
|
||||||
|
Q_INVOKABLE virtual void setJointTranslation(int index, const glm::vec3& translation);
|
||||||
Q_INVOKABLE virtual void clearJointData(int index);
|
Q_INVOKABLE virtual void clearJointData(int index);
|
||||||
Q_INVOKABLE bool isJointDataValid(int index) const;
|
Q_INVOKABLE bool isJointDataValid(int index) const;
|
||||||
Q_INVOKABLE virtual glm::quat getJointRotation(int index) const;
|
Q_INVOKABLE virtual glm::quat getJointRotation(int index) const;
|
||||||
|
Q_INVOKABLE virtual glm::vec3 getJointTranslation(int index) const;
|
||||||
|
|
||||||
Q_INVOKABLE void setJointData(const QString& name, const glm::quat& rotation);
|
Q_INVOKABLE void setJointData(const QString& name, const glm::quat& rotation, const glm::vec3& translation);
|
||||||
Q_INVOKABLE void clearJointData(const QString& name);
|
Q_INVOKABLE void clearJointData(const QString& name);
|
||||||
Q_INVOKABLE bool isJointDataValid(const QString& name) const;
|
Q_INVOKABLE bool isJointDataValid(const QString& name) const;
|
||||||
Q_INVOKABLE glm::quat getJointRotation(const QString& name) const;
|
Q_INVOKABLE glm::quat getJointRotation(const QString& name) const;
|
||||||
|
Q_INVOKABLE glm::vec3 getJointTranslation(const QString& name) const;
|
||||||
|
|
||||||
Q_INVOKABLE virtual QVector<glm::quat> getJointRotations() const;
|
Q_INVOKABLE virtual QVector<glm::quat> getJointRotations() const;
|
||||||
Q_INVOKABLE virtual void setJointRotations(QVector<glm::quat> jointRotations);
|
Q_INVOKABLE virtual void setJointRotations(QVector<glm::quat> jointRotations);
|
||||||
|
Q_INVOKABLE virtual void setJointTranslations(QVector<glm::vec3> jointTranslations);
|
||||||
|
|
||||||
Q_INVOKABLE virtual void clearJointsData();
|
Q_INVOKABLE virtual void clearJointsData();
|
||||||
|
|
||||||
|
@ -387,6 +392,7 @@ protected:
|
||||||
|
|
||||||
bool _forceFaceTrackerConnected;
|
bool _forceFaceTrackerConnected;
|
||||||
bool _hasNewJointRotations; // set in AvatarData, cleared in Avatar
|
bool _hasNewJointRotations; // set in AvatarData, cleared in Avatar
|
||||||
|
bool _hasNewJointTranslations; // set in AvatarData, cleared in Avatar
|
||||||
|
|
||||||
HeadData* _headData;
|
HeadData* _headData;
|
||||||
HandData* _handData;
|
HandData* _handData;
|
||||||
|
@ -435,6 +441,9 @@ Q_DECLARE_METATYPE(AvatarData*)
|
||||||
class JointData {
|
class JointData {
|
||||||
public:
|
public:
|
||||||
glm::quat rotation;
|
glm::quat rotation;
|
||||||
|
bool rotationSet = false;
|
||||||
|
glm::vec3 translation;
|
||||||
|
bool translationSet = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AttachmentData {
|
class AttachmentData {
|
||||||
|
|
|
@ -254,7 +254,16 @@ void Player::play() {
|
||||||
nextFrame.getJointRotations()[i],
|
nextFrame.getJointRotations()[i],
|
||||||
_frameInterpolationFactor);
|
_frameInterpolationFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVector<glm::vec3> jointTranslations(currentFrame.getJointTranslations().size());
|
||||||
|
for (int i = 0; i < currentFrame.getJointTranslations().size(); ++i) {
|
||||||
|
jointTranslations[i] =
|
||||||
|
currentFrame.getJointTranslations()[i] * (1.0f - _frameInterpolationFactor) +
|
||||||
|
nextFrame.getJointTranslations()[i] * _frameInterpolationFactor;
|
||||||
|
}
|
||||||
|
|
||||||
_avatar->setJointRotations(jointRotations);
|
_avatar->setJointRotations(jointRotations);
|
||||||
|
_avatar->setJointTranslations(jointTranslations);
|
||||||
|
|
||||||
HeadData* head = const_cast<HeadData*>(_avatar->getHeadData());
|
HeadData* head = const_cast<HeadData*>(_avatar->getHeadData());
|
||||||
if (head) {
|
if (head) {
|
||||||
|
|
|
@ -239,6 +239,7 @@ void writeRecordingToFile(RecordingPointer recording, const QString& filename) {
|
||||||
if (i == 0 ||
|
if (i == 0 ||
|
||||||
frame._jointRotations[j] != previousFrame._jointRotations[j]) {
|
frame._jointRotations[j] != previousFrame._jointRotations[j]) {
|
||||||
writeQuat(stream, frame._jointRotations[j]);
|
writeQuat(stream, frame._jointRotations[j]);
|
||||||
|
// XXX handle translations
|
||||||
mask.setBit(maskIndex);
|
mask.setBit(maskIndex);
|
||||||
}
|
}
|
||||||
maskIndex++;
|
maskIndex++;
|
||||||
|
@ -562,6 +563,9 @@ RecordingPointer readRecordingFromFile(RecordingPointer recording, const QString
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX handle translations
|
||||||
|
|
||||||
|
|
||||||
if (!mask[maskIndex++] || !readVec3(stream, frame._translation)) {
|
if (!mask[maskIndex++] || !readVec3(stream, frame._translation)) {
|
||||||
frame._translation = previousFrame._translation;
|
frame._translation = previousFrame._translation;
|
||||||
}
|
}
|
||||||
|
@ -671,6 +675,8 @@ RecordingPointer readRecordingFromRecFile(RecordingPointer recording, const QStr
|
||||||
fileStream >> baseFrame._jointRotations[i].x >> baseFrame._jointRotations[i].y >> baseFrame._jointRotations[i].z >> baseFrame._jointRotations[i].w;
|
fileStream >> baseFrame._jointRotations[i].x >> baseFrame._jointRotations[i].y >> baseFrame._jointRotations[i].z >> baseFrame._jointRotations[i].w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX handle translations
|
||||||
|
|
||||||
fileStream >> baseFrame._translation.x >> baseFrame._translation.y >> baseFrame._translation.z;
|
fileStream >> baseFrame._translation.x >> baseFrame._translation.y >> baseFrame._translation.z;
|
||||||
fileStream >> baseFrame._rotation.x >> baseFrame._rotation.y >> baseFrame._rotation.z >> baseFrame._rotation.w;
|
fileStream >> baseFrame._rotation.x >> baseFrame._rotation.y >> baseFrame._rotation.z >> baseFrame._rotation.w;
|
||||||
fileStream >> baseFrame._scale;
|
fileStream >> baseFrame._scale;
|
||||||
|
@ -737,6 +743,8 @@ RecordingPointer readRecordingFromRecFile(RecordingPointer recording, const QStr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX handle translations
|
||||||
|
|
||||||
if (mask[maskIndex++]) {
|
if (mask[maskIndex++]) {
|
||||||
stream >> frame._translation.x >> frame._translation.y >> frame._translation.z;
|
stream >> frame._translation.x >> frame._translation.y >> frame._translation.z;
|
||||||
frame._translation = context.orientationInv * frame._translation;
|
frame._translation = context.orientationInv * frame._translation;
|
||||||
|
|
|
@ -83,6 +83,7 @@ class RecordingFrame {
|
||||||
public:
|
public:
|
||||||
QVector<float> getBlendshapeCoefficients() const { return _blendshapeCoefficients; }
|
QVector<float> getBlendshapeCoefficients() const { return _blendshapeCoefficients; }
|
||||||
QVector<glm::quat> getJointRotations() const { return _jointRotations; }
|
QVector<glm::quat> getJointRotations() const { return _jointRotations; }
|
||||||
|
QVector<glm::vec3> getJointTranslations() const { return _jointTranslations; }
|
||||||
glm::vec3 getTranslation() const { return _translation; }
|
glm::vec3 getTranslation() const { return _translation; }
|
||||||
glm::quat getRotation() const { return _rotation; }
|
glm::quat getRotation() const { return _rotation; }
|
||||||
float getScale() const { return _scale; }
|
float getScale() const { return _scale; }
|
||||||
|
@ -94,6 +95,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
void setBlendshapeCoefficients(QVector<float> blendshapeCoefficients);
|
void setBlendshapeCoefficients(QVector<float> blendshapeCoefficients);
|
||||||
void setJointRotations(QVector<glm::quat> jointRotations) { _jointRotations = jointRotations; }
|
void setJointRotations(QVector<glm::quat> jointRotations) { _jointRotations = jointRotations; }
|
||||||
|
void setJointTranslations(QVector<glm::vec3> jointTranslations) { _jointTranslations = jointTranslations; }
|
||||||
void setTranslation(const glm::vec3& translation) { _translation = translation; }
|
void setTranslation(const glm::vec3& translation) { _translation = translation; }
|
||||||
void setRotation(const glm::quat& rotation) { _rotation = rotation; }
|
void setRotation(const glm::quat& rotation) { _rotation = rotation; }
|
||||||
void setScale(float scale) { _scale = scale; }
|
void setScale(float scale) { _scale = scale; }
|
||||||
|
@ -105,6 +107,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
QVector<float> _blendshapeCoefficients;
|
QVector<float> _blendshapeCoefficients;
|
||||||
QVector<glm::quat> _jointRotations;
|
QVector<glm::quat> _jointRotations;
|
||||||
|
QVector<glm::vec3> _jointTranslations;
|
||||||
glm::vec3 _translation;
|
glm::vec3 _translation;
|
||||||
glm::quat _rotation;
|
glm::quat _rotation;
|
||||||
float _scale;
|
float _scale;
|
||||||
|
|
|
@ -276,10 +276,13 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
||||||
|
|
||||||
if (jointsMapped()) {
|
if (jointsMapped()) {
|
||||||
bool newFrame;
|
bool newFrame;
|
||||||
auto frameData = getAnimationFrame(newFrame);
|
QVector<glm::quat> frameDataRotations;
|
||||||
|
QVector<glm::vec3> frameDataTranslations;
|
||||||
|
getAnimationFrame(newFrame, frameDataRotations, frameDataTranslations);
|
||||||
|
assert(frameDataRotations.size() == frameDataTranslations.size());
|
||||||
if (newFrame) {
|
if (newFrame) {
|
||||||
for (int i = 0; i < frameData.size(); i++) {
|
for (int i = 0; i < frameDataRotations.size(); i++) {
|
||||||
_model->setJointState(i, true, frameData[i]);
|
_model->setJointState(i, true, frameDataRotations[i], frameDataTranslations[i], 1.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,11 +218,13 @@ void ModelEntityItem::mapJoints(const QStringList& modelJointNames) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const QVector<glm::quat>& ModelEntityItem::getAnimationFrame(bool& newFrame) {
|
void ModelEntityItem::getAnimationFrame(bool& newFrame,
|
||||||
|
QVector<glm::quat>& rotationsResult, QVector<glm::vec3>& translationsResult) {
|
||||||
newFrame = false;
|
newFrame = false;
|
||||||
|
|
||||||
if (!hasAnimation() || !_jointMappingCompleted) {
|
if (!hasAnimation() || !_jointMappingCompleted) {
|
||||||
return _lastKnownFrameData;
|
rotationsResult = _lastKnownFrameDataRotations;
|
||||||
|
translationsResult = _lastKnownFrameDataTranslations;
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimationPointer myAnimation = getAnimation(_animationURL); // FIXME: this could be optimized
|
AnimationPointer myAnimation = getAnimation(_animationURL); // FIXME: this could be optimized
|
||||||
|
@ -242,18 +244,25 @@ const QVector<glm::quat>& ModelEntityItem::getAnimationFrame(bool& newFrame) {
|
||||||
newFrame = true;
|
newFrame = true;
|
||||||
|
|
||||||
const QVector<glm::quat>& rotations = frames[animationFrameIndex].rotations;
|
const QVector<glm::quat>& rotations = frames[animationFrameIndex].rotations;
|
||||||
|
const QVector<glm::vec3>& translations = frames[animationFrameIndex].translations;
|
||||||
|
|
||||||
_lastKnownFrameData.resize(_jointMapping.size());
|
_lastKnownFrameDataRotations.resize(_jointMapping.size());
|
||||||
|
_lastKnownFrameDataTranslations.resize(_jointMapping.size());
|
||||||
for (int j = 0; j < _jointMapping.size(); j++) {
|
for (int j = 0; j < _jointMapping.size(); j++) {
|
||||||
int rotationIndex = _jointMapping[j];
|
int index = _jointMapping[j];
|
||||||
if (rotationIndex != -1 && rotationIndex < rotations.size()) {
|
if (index != -1 && index < rotations.size()) {
|
||||||
_lastKnownFrameData[j] = rotations[rotationIndex];
|
_lastKnownFrameDataRotations[j] = rotations[index];
|
||||||
|
}
|
||||||
|
if (index != -1 && index < translations.size()) {
|
||||||
|
_lastKnownFrameDataTranslations[j] = translations[index];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _lastKnownFrameData;
|
|
||||||
|
rotationsResult = _lastKnownFrameDataRotations;
|
||||||
|
translationsResult = _lastKnownFrameDataTranslations;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModelEntityItem::isAnimatingSomething() const {
|
bool ModelEntityItem::isAnimatingSomething() const {
|
||||||
|
|
|
@ -106,7 +106,7 @@ public:
|
||||||
float getAnimationLastFrame() const { return _animationLoop.getLastFrame(); }
|
float getAnimationLastFrame() const { return _animationLoop.getLastFrame(); }
|
||||||
|
|
||||||
void mapJoints(const QStringList& modelJointNames);
|
void mapJoints(const QStringList& modelJointNames);
|
||||||
const QVector<glm::quat>& getAnimationFrame(bool& newFrame);
|
void getAnimationFrame(bool& newFrame, QVector<glm::quat>& rotationsResult, QVector<glm::vec3>& translationsResult);
|
||||||
bool jointsMapped() const { return _jointMappingCompleted; }
|
bool jointsMapped() const { return _jointMappingCompleted; }
|
||||||
|
|
||||||
bool getAnimationIsPlaying() const { return _animationLoop.isRunning(); }
|
bool getAnimationIsPlaying() const { return _animationLoop.isRunning(); }
|
||||||
|
@ -123,7 +123,8 @@ public:
|
||||||
static void cleanupLoadedAnimations();
|
static void cleanupLoadedAnimations();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QVector<glm::quat> _lastKnownFrameData;
|
QVector<glm::quat> _lastKnownFrameDataRotations;
|
||||||
|
QVector<glm::vec3> _lastKnownFrameDataTranslations;
|
||||||
int _lastKnownFrameIndex;
|
int _lastKnownFrameIndex;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -530,6 +530,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
||||||
QHash<QString, QString> typeFlags;
|
QHash<QString, QString> typeFlags;
|
||||||
|
|
||||||
QHash<QString, QString> localRotations;
|
QHash<QString, QString> localRotations;
|
||||||
|
QHash<QString, QString> localTranslations;
|
||||||
QHash<QString, QString> xComponents;
|
QHash<QString, QString> xComponents;
|
||||||
QHash<QString, QString> yComponents;
|
QHash<QString, QString> yComponents;
|
||||||
QHash<QString, QString> zComponents;
|
QHash<QString, QString> zComponents;
|
||||||
|
@ -1107,13 +1108,13 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
||||||
|
|
||||||
} else if (type == "lcl rotation") {
|
} else if (type == "lcl rotation") {
|
||||||
localRotations.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
localRotations.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||||
|
} else if (type == "lcl translation") {
|
||||||
|
localTranslations.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||||
|
|
||||||
} else if (type == "d|x") {
|
} else if (type == "d|x") {
|
||||||
xComponents.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
xComponents.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||||
|
|
||||||
} else if (type == "d|y") {
|
} else if (type == "d|y") {
|
||||||
yComponents.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
yComponents.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||||
|
|
||||||
} else if (type == "d|z") {
|
} else if (type == "d|z") {
|
||||||
zComponents.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
zComponents.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||||
|
|
||||||
|
@ -1224,6 +1225,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
||||||
for (int i = 0; i < frameCount; i++) {
|
for (int i = 0; i < frameCount; i++) {
|
||||||
FBXAnimationFrame frame;
|
FBXAnimationFrame frame;
|
||||||
frame.rotations.resize(modelIDs.size());
|
frame.rotations.resize(modelIDs.size());
|
||||||
|
frame.translations.resize(modelIDs.size());
|
||||||
geometry.animationFrames.append(frame);
|
geometry.animationFrames.append(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1247,7 +1249,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
||||||
joint.freeLineage.append(index);
|
joint.freeLineage.append(index);
|
||||||
}
|
}
|
||||||
joint.freeLineage.remove(lastFreeIndex + 1, joint.freeLineage.size() - lastFreeIndex - 1);
|
joint.freeLineage.remove(lastFreeIndex + 1, joint.freeLineage.size() - lastFreeIndex - 1);
|
||||||
joint.translation = model.translation;
|
joint.translation = model.translation; // these are usually in centimeters
|
||||||
joint.preTransform = model.preTransform;
|
joint.preTransform = model.preTransform;
|
||||||
joint.preRotation = model.preRotation;
|
joint.preRotation = model.preRotation;
|
||||||
joint.rotation = model.rotation;
|
joint.rotation = model.rotation;
|
||||||
|
@ -1287,15 +1289,26 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
||||||
geometry.jointIndices.insert(model.name, geometry.joints.size());
|
geometry.jointIndices.insert(model.name, geometry.joints.size());
|
||||||
|
|
||||||
QString rotationID = localRotations.value(modelID);
|
QString rotationID = localRotations.value(modelID);
|
||||||
AnimationCurve xCurve = animationCurves.value(xComponents.value(rotationID));
|
AnimationCurve xRotCurve = animationCurves.value(xComponents.value(rotationID));
|
||||||
AnimationCurve yCurve = animationCurves.value(yComponents.value(rotationID));
|
AnimationCurve yRotCurve = animationCurves.value(yComponents.value(rotationID));
|
||||||
AnimationCurve zCurve = animationCurves.value(zComponents.value(rotationID));
|
AnimationCurve zRotCurve = animationCurves.value(zComponents.value(rotationID));
|
||||||
|
|
||||||
|
QString translationID = localTranslations.value(modelID);
|
||||||
|
AnimationCurve xPosCurve = animationCurves.value(xComponents.value(translationID));
|
||||||
|
AnimationCurve yPosCurve = animationCurves.value(yComponents.value(translationID));
|
||||||
|
AnimationCurve zPosCurve = animationCurves.value(zComponents.value(translationID));
|
||||||
|
|
||||||
glm::vec3 defaultValues = glm::degrees(safeEulerAngles(joint.rotation));
|
glm::vec3 defaultValues = glm::degrees(safeEulerAngles(joint.rotation));
|
||||||
|
|
||||||
for (int i = 0; i < frameCount; i++) {
|
for (int i = 0; i < frameCount; i++) {
|
||||||
geometry.animationFrames[i].rotations[jointIndex] = glm::quat(glm::radians(glm::vec3(
|
geometry.animationFrames[i].rotations[jointIndex] = glm::quat(glm::radians(glm::vec3(
|
||||||
xCurve.values.isEmpty() ? defaultValues.x : xCurve.values.at(i % xCurve.values.size()),
|
xRotCurve.values.isEmpty() ? defaultValues.x : xRotCurve.values.at(i % xRotCurve.values.size()),
|
||||||
yCurve.values.isEmpty() ? defaultValues.y : yCurve.values.at(i % yCurve.values.size()),
|
yRotCurve.values.isEmpty() ? defaultValues.y : yRotCurve.values.at(i % yRotCurve.values.size()),
|
||||||
zCurve.values.isEmpty() ? defaultValues.z : zCurve.values.at(i % zCurve.values.size()))));
|
zRotCurve.values.isEmpty() ? defaultValues.z : zRotCurve.values.at(i % zRotCurve.values.size()))));
|
||||||
|
geometry.animationFrames[i].translations[jointIndex] = glm::vec3(
|
||||||
|
xPosCurve.values.isEmpty() ? defaultValues.x : xPosCurve.values.at(i % xPosCurve.values.size()),
|
||||||
|
yPosCurve.values.isEmpty() ? defaultValues.y : yPosCurve.values.at(i % yPosCurve.values.size()),
|
||||||
|
zPosCurve.values.isEmpty() ? defaultValues.z : zPosCurve.values.at(i % zPosCurve.values.size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,8 +208,8 @@ public:
|
||||||
/// A single animation frame extracted from an FBX document.
|
/// A single animation frame extracted from an FBX document.
|
||||||
class FBXAnimationFrame {
|
class FBXAnimationFrame {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
QVector<glm::quat> rotations;
|
QVector<glm::quat> rotations;
|
||||||
|
QVector<glm::vec3> translations;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A light in an FBX document.
|
/// A light in an FBX document.
|
||||||
|
|
|
@ -39,6 +39,9 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
||||||
case PacketType::EntityEdit:
|
case PacketType::EntityEdit:
|
||||||
case PacketType::EntityData:
|
case PacketType::EntityData:
|
||||||
return VERSION_ENTITIES_PARTICLE_ELLIPSOID_EMITTER;
|
return VERSION_ENTITIES_PARTICLE_ELLIPSOID_EMITTER;
|
||||||
|
case PacketType::AvatarData:
|
||||||
|
case PacketType::BulkAvatarData:
|
||||||
|
return 15;
|
||||||
default:
|
default:
|
||||||
return 14;
|
return 14;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1001,8 +1001,16 @@ void Model::clearJointState(int index) {
|
||||||
_rig->clearJointState(index);
|
_rig->clearJointState(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::setJointState(int index, bool valid, const glm::quat& rotation, float priority) {
|
void Model::setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation, float priority) {
|
||||||
_rig->setJointState(index, valid, rotation, priority);
|
_rig->setJointState(index, valid, rotation, translation, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::setJointRotation(int index, bool valid, const glm::quat& rotation, float priority) {
|
||||||
|
_rig->setJointRotation(index, valid, rotation, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::setJointTranslation(int index, bool valid, const glm::vec3& translation, float priority) {
|
||||||
|
_rig->setJointTranslation(index, valid, translation, priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Model::getParentJointIndex(int jointIndex) const {
|
int Model::getParentJointIndex(int jointIndex) const {
|
||||||
|
@ -1074,6 +1082,10 @@ bool Model::getJointRotation(int jointIndex, glm::quat& rotation) const {
|
||||||
return _rig->getJointRotation(jointIndex, rotation);
|
return _rig->getJointRotation(jointIndex, rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Model::getJointTranslation(int jointIndex, glm::vec3& translation) const {
|
||||||
|
return _rig->getJointTranslation(jointIndex, translation);
|
||||||
|
}
|
||||||
|
|
||||||
bool Model::getJointCombinedRotation(int jointIndex, glm::quat& rotation) const {
|
bool Model::getJointCombinedRotation(int jointIndex, glm::quat& rotation) const {
|
||||||
return _rig->getJointCombinedRotation(jointIndex, rotation, _rotation);
|
return _rig->getJointCombinedRotation(jointIndex, rotation, _rotation);
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,7 +126,9 @@ public:
|
||||||
QStringList getJointNames() const;
|
QStringList getJointNames() const;
|
||||||
|
|
||||||
/// Sets the joint state at the specified index.
|
/// Sets the joint state at the specified index.
|
||||||
void setJointState(int index, bool valid, const glm::quat& rotation = glm::quat(), float priority = 1.0f);
|
void setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation, float priority);
|
||||||
|
void setJointRotation(int index, bool valid, const glm::quat& rotation, float priority);
|
||||||
|
void setJointTranslation(int index, bool valid, const glm::vec3& translation, float priority);
|
||||||
|
|
||||||
bool findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
bool findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||||
BoxFace& face, QString& extraInfo, bool pickAgainstTriangles = false);
|
BoxFace& face, QString& extraInfo, bool pickAgainstTriangles = false);
|
||||||
|
@ -160,6 +162,7 @@ public:
|
||||||
/// \param rotation[out] rotation of joint in model-frame
|
/// \param rotation[out] rotation of joint in model-frame
|
||||||
/// \return true if joint exists
|
/// \return true if joint exists
|
||||||
bool getJointRotation(int jointIndex, glm::quat& rotation) const;
|
bool getJointRotation(int jointIndex, glm::quat& rotation) const;
|
||||||
|
bool getJointTranslation(int jointIndex, glm::vec3& translation) const;
|
||||||
|
|
||||||
/// Returns the index of the parent of the indexed joint, or -1 if not found.
|
/// Returns the index of the parent of the indexed joint, or -1 if not found.
|
||||||
int getParentJointIndex(int jointIndex) const;
|
int getParentJointIndex(int jointIndex) const;
|
||||||
|
|
|
@ -33,6 +33,8 @@ const vec3& Vectors::RIGHT = Vectors::UNIT_X;
|
||||||
const vec3& Vectors::UP = Vectors::UNIT_Y;
|
const vec3& Vectors::UP = Vectors::UNIT_Y;
|
||||||
const vec3& Vectors::FRONT = Vectors::UNIT_NEG_Z;
|
const vec3& Vectors::FRONT = Vectors::UNIT_NEG_Z;
|
||||||
|
|
||||||
|
const quat Quaternions::ZERO{ 1.0f, 0.0f, 0.0f, 0.0f };
|
||||||
|
|
||||||
// Safe version of glm::mix; based on the code in Nick Bobick's article,
|
// Safe version of glm::mix; based on the code in Nick Bobick's article,
|
||||||
// http://www.gamasutra.com/features/19980703/quaternions_01.htm (via Clyde,
|
// http://www.gamasutra.com/features/19980703/quaternions_01.htm (via Clyde,
|
||||||
// https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java)
|
// https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java)
|
||||||
|
|
|
@ -53,6 +53,12 @@ const glm::vec3 IDENTITY_FRONT = glm::vec3( 0.0f, 0.0f,-1.0f);
|
||||||
|
|
||||||
glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha);
|
glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha);
|
||||||
|
|
||||||
|
|
||||||
|
class Quaternions {
|
||||||
|
public:
|
||||||
|
static const quat ZERO;
|
||||||
|
};
|
||||||
|
|
||||||
class Vectors {
|
class Vectors {
|
||||||
public:
|
public:
|
||||||
static const vec3 UNIT_X;
|
static const vec3 UNIT_X;
|
||||||
|
|
Loading…
Reference in a new issue