cache the spine2 spline default offset and ratio

This commit is contained in:
amantley 2019-01-30 14:47:03 -08:00
parent e36877a861
commit 2e1a4545c6
4 changed files with 94 additions and 14 deletions

View file

@ -44,25 +44,46 @@ static CubicHermiteSplineFunctorWithArcLength computeSplineFromTipAndBase(const
}
static glm::vec3 computeSpine2WithHeadHipsSpline(MyAvatar* myAvatar, AnimPose hipsIKTargetPose, AnimPose headIKTargetPose) {
glm::vec3 basePosition = myAvatar->getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar->getJointIndex("Hips"));
glm::vec3 tipPosition = myAvatar->getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar->getJointIndex("Head"));
glm::vec3 spine2Position = myAvatar->getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar->getJointIndex("Spine2"));
/*
AnimPose avatarToRigPose(glm::vec3(1.0f), Quaternions::Y_180, glm::vec3(0.0f));
AnimPose hipsDefaultPoseAvatarSpace(myAvatar->getAbsoluteDefaultJointRotationInObjectFrame(myAvatar->getJointIndex("Hips")), myAvatar->getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar->getJointIndex("Hips")));
AnimPose headDefaultPoseAvatarSpace(myAvatar->getAbsoluteDefaultJointRotationInObjectFrame(myAvatar->getJointIndex("Head")), myAvatar->getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar->getJointIndex("Head")));
AnimPose spine2DefaultPoseAvatarSpace(myAvatar->getAbsoluteDefaultJointRotationInObjectFrame(myAvatar->getJointIndex("Spine2")), myAvatar->getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar->getJointIndex("Spine2")));
AnimPose hipsDefaultPoseRigSpace = avatarToRigPose * hipsDefaultPoseAvatarSpace;
AnimPose headDefaultPoseRigSpace = avatarToRigPose * headDefaultPoseAvatarSpace;
AnimPose spine2DefaultPoseRigSpace = avatarToRigPose * spine2DefaultPoseAvatarSpace;
glm::vec3 basePosition = hipsDefaultPoseRigSpace.trans();
glm::vec3 tipPosition = headDefaultPoseRigSpace.trans();
glm::vec3 spine2Position = spine2DefaultPoseRigSpace.trans();
glm::vec3 baseToTip = tipPosition - basePosition;
float baseToTipLength = glm::length(baseToTip);
glm::vec3 baseToTipNormal = baseToTip / baseToTipLength;
glm::vec3 baseToSpine2 = spine2Position - basePosition;
float ratio = glm::dot(baseToSpine2, baseToTipNormal) / baseToTipLength;
CubicHermiteSplineFunctorWithArcLength defaultSpline = computeSplineFromTipAndBase(headDefaultPoseRigSpace, hipsDefaultPoseRigSpace);
// measure the total arc length along the spline
float totalDefaultArcLength = defaultSpline.arcLength(1.0f);
float t = defaultSpline.arcLengthInverse(ratio * totalDefaultArcLength);
glm::vec3 defaultSplineSpine2Translation = defaultSpline(t);
glm::vec3 offset = spine2Position - defaultSplineSpine2Translation;
qCDebug(animation) << "the my skeleton model numbers are " << ratio << " and " << offset;
*/
// the the ik targets to compute the spline with
CubicHermiteSplineFunctorWithArcLength spline = computeSplineFromTipAndBase(headIKTargetPose, hipsIKTargetPose);
CubicHermiteSplineFunctorWithArcLength splineFinal = computeSplineFromTipAndBase(headIKTargetPose, hipsIKTargetPose);
// measure the total arc length along the spline
float totalArcLength = spline.arcLength(1.0f);
float t = spline.arcLengthInverse(ratio * totalArcLength);
float totalArcLength = splineFinal.arcLength(1.0f);
float tFinal = splineFinal.arcLengthInverse(myAvatar->getSpine2SplineRatio() * totalArcLength);
glm::vec3 spine2Translation = spline(t);
glm::vec3 spine2Translation = splineFinal(tFinal);
return spine2Translation;
return spine2Translation + myAvatar->getSpine2SplineOffset();
}
@ -266,11 +287,14 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
myAvatar->getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() &&
!(params.primaryControllerFlags[Rig::PrimaryControllerType_Spine2] & (uint8_t)Rig::ControllerFlags::Enabled)) {
controller::Pose headSplineControllerPose = myAvatar->getControllerPoseInSensorFrame(controller::Action::HEAD);
AnimPose headSplinePose(headSplineControllerPose.getRotation(), headSplineControllerPose.getTranslation());
glm::vec3 spine2TargetTranslation = computeSpine2WithHeadHipsSpline(myAvatar, sensorHips, headSplinePose);
AnimPose sensorSpine2(Quaternions::IDENTITY, spine2TargetTranslation);
AnimPose rigSpine2 = sensorToRigPose * sensorSpine2;
// if (avatarHeadPose.isValid()) {
AnimPose headAvatarSpace(avatarHeadPose.getRotation(), avatarHeadPose.getTranslation());
AnimPose headRigSpace = avatarToRigPose * headAvatarSpace;
AnimPose hipsRigSpace = sensorToRigPose * sensorHips;
glm::vec3 spine2TargetTranslation = computeSpine2WithHeadHipsSpline(myAvatar, hipsRigSpace, headRigSpace);
//AnimPose rigSpine2(Quaternions::IDENTITY, spine2TargetTranslation);
//AnimPose rigSpine2 = sensorToRigPose * sensorSpine2;
const float SPINE2_ROTATION_FILTER = 0.5f;
AnimPose currentSpine2Pose;
@ -292,7 +316,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
}
generateBasisVectors(up, fwd, u, v, w);
AnimPose newSpinePose(glm::mat4(glm::vec4(w, 0.0f), glm::vec4(u, 0.0f), glm::vec4(v, 0.0f), glm::vec4(glm::vec3(0.0f, 0.0f, 0.0f), 1.0f)));
currentSpine2Pose.trans() = rigSpine2.trans();
currentSpine2Pose.trans() = spine2TargetTranslation;
currentSpine2Pose.rot() = safeLerp(currentSpine2Pose.rot(), newSpinePose.rot(), SPINE2_ROTATION_FILTER);
params.primaryControllerPoses[Rig::PrimaryControllerType_Spine2] = currentSpine2Pose;
params.primaryControllerFlags[Rig::PrimaryControllerType_Spine2] = (uint8_t)Rig::ControllerFlags::Enabled | (uint8_t)Rig::ControllerFlags::Estimated;

View file

@ -1420,11 +1420,13 @@ void Avatar::setModelURLFinished(bool success) {
// rig is ready
void Avatar::rigReady() {
buildUnscaledEyeHeightCache();
buildSpine2SplineRatioCache();
}
// rig has been reset.
void Avatar::rigReset() {
clearUnscaledEyeHeightCache();
clearSpine2SplineRatioCache();
}
// create new model, can return an instance of a SoftAttachmentModel rather then Model
@ -1821,10 +1823,54 @@ void Avatar::buildUnscaledEyeHeightCache() {
}
}
static CubicHermiteSplineFunctorWithArcLength computeSplineFromTipAndBase(const AnimPose& tipPose, const AnimPose& basePose, float baseGain = 1.0f, float tipGain = 1.0f) {
float linearDistance = glm::length(basePose.trans() - tipPose.trans());
glm::vec3 p0 = basePose.trans();
glm::vec3 m0 = baseGain * linearDistance * (basePose.rot() * Vectors::UNIT_Y);
glm::vec3 p1 = tipPose.trans();
glm::vec3 m1 = tipGain * linearDistance * (tipPose.rot() * Vectors::UNIT_Y);
return CubicHermiteSplineFunctorWithArcLength(p0, m0, p1, m1);
}
void Avatar::buildSpine2SplineRatioCache() {
if (_skeletonModel) {
auto& rig = _skeletonModel->getRig();
AnimPose hipsRigDefaultPose = rig.getAbsoluteDefaultPose(rig.indexOfJoint("Hips"));
AnimPose headRigDefaultPose(rig.getAbsoluteDefaultPose(rig.indexOfJoint("Head")));
glm::vec3 basePosition = hipsRigDefaultPose.trans();
glm::vec3 tipPosition = headRigDefaultPose.trans();
glm::vec3 spine2Position = rig.getAbsoluteDefaultPose(rig.indexOfJoint("Spine2")).trans();
glm::vec3 baseToTip = tipPosition - basePosition;
float baseToTipLength = glm::length(baseToTip);
glm::vec3 baseToTipNormal = baseToTip / baseToTipLength;
glm::vec3 baseToSpine2 = spine2Position - basePosition;
_spine2SplineRatio = glm::dot(baseToSpine2, baseToTipNormal) / baseToTipLength;
CubicHermiteSplineFunctorWithArcLength defaultSpline = computeSplineFromTipAndBase(headRigDefaultPose, hipsRigDefaultPose);
// measure the total arc length along the spline
float totalDefaultArcLength = defaultSpline.arcLength(1.0f);
float t = defaultSpline.arcLengthInverse(_spine2SplineRatio * totalDefaultArcLength);
glm::vec3 defaultSplineSpine2Translation = defaultSpline(t);
_spine2SplineOffset = spine2Position - defaultSplineSpine2Translation;
qCDebug(avatars_renderer) << "the avatar spline numbers are " << _spine2SplineRatio << " and " << _spine2SplineOffset;
}
}
void Avatar::clearUnscaledEyeHeightCache() {
_unscaledEyeHeightCache.set(DEFAULT_AVATAR_EYE_HEIGHT);
}
void Avatar::clearSpine2SplineRatioCache() {
_spine2SplineRatio = DEFAULT_AVATAR_EYE_HEIGHT;
_spine2SplineOffset = glm::vec3();
}
float Avatar::getUnscaledEyeHeightFromSkeleton() const {
// TODO: if performance becomes a concern we can cache this value rather then computing it everytime.

View file

@ -22,6 +22,7 @@
#include <render/Scene.h>
#include <graphics-scripting/Forward.h>
#include <GLMHelpers.h>
#include <CubicHermiteSpline.h>
#include "Head.h"
#include "SkeletonModel.h"
@ -228,6 +229,9 @@ public:
virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; }
virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override { return false; }
virtual glm::vec3 getSpine2SplineOffset() const { return _spine2SplineOffset; }
virtual float getSpine2SplineRatio() const { return _spine2SplineRatio; }
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override;
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData) override;
@ -499,7 +503,9 @@ public slots:
protected:
float getUnscaledEyeHeightFromSkeleton() const;
void buildUnscaledEyeHeightCache();
void buildSpine2SplineRatioCache();
void clearUnscaledEyeHeightCache();
void clearSpine2SplineRatioCache();
virtual const QString& getSessionDisplayNameForTransport() const override { return _empty; } // Save a tiny bit of bandwidth. Mixer won't look at what we send.
QString _empty{};
virtual void maybeUpdateSessionDisplayNameFromTransport(const QString& sessionDisplayName) override { _sessionDisplayName = sessionDisplayName; } // don't use no-op setter!
@ -552,6 +558,7 @@ protected:
float getHeadHeight() const;
float getPelvisFloatingHeight() const;
glm::vec3 getDisplayNamePosition() const;
Transform calculateDisplayNameTransform(const ViewFrustum& view, const glm::vec3& textPosition) const;
void renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const glm::vec3& textPosition) const;
@ -607,6 +614,8 @@ protected:
float _displayNameAlpha { 1.0f };
ThreadSafeValueCache<float> _unscaledEyeHeightCache { DEFAULT_AVATAR_EYE_HEIGHT };
float _spine2SplineRatio { DEFAULT_SPINE2_SPLINE_PROPORTION };
glm::vec3 _spine2SplineOffset;
std::unordered_map<std::string, graphics::MultiMaterial> _materials;
std::mutex _materialsLock;

View file

@ -20,6 +20,7 @@ const float DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD = 0.11f; // meters
const float DEFAULT_AVATAR_NECK_TO_TOP_OF_HEAD = 0.185f; // meters
const float DEFAULT_AVATAR_NECK_HEIGHT = DEFAULT_AVATAR_HEIGHT - DEFAULT_AVATAR_NECK_TO_TOP_OF_HEAD;
const float DEFAULT_AVATAR_EYE_HEIGHT = DEFAULT_AVATAR_HEIGHT - DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD;
const float DEFAULT_SPINE2_SPLINE_PROPORTION = 0.75f;
const float DEFAULT_AVATAR_SUPPORT_BASE_LEFT = -0.25f;
const float DEFAULT_AVATAR_SUPPORT_BASE_RIGHT = 0.25f;
const float DEFAULT_AVATAR_SUPPORT_BASE_FRONT = -0.20f;