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) { 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")); AnimPose avatarToRigPose(glm::vec3(1.0f), Quaternions::Y_180, glm::vec3(0.0f));
glm::vec3 spine2Position = myAvatar->getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar->getJointIndex("Spine2"));
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; glm::vec3 baseToTip = tipPosition - basePosition;
float baseToTipLength = glm::length(baseToTip); float baseToTipLength = glm::length(baseToTip);
glm::vec3 baseToTipNormal = baseToTip / baseToTipLength; glm::vec3 baseToTipNormal = baseToTip / baseToTipLength;
glm::vec3 baseToSpine2 = spine2Position - basePosition; glm::vec3 baseToSpine2 = spine2Position - basePosition;
float ratio = glm::dot(baseToSpine2, baseToTipNormal) / baseToTipLength; 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 // 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 // measure the total arc length along the spline
float totalArcLength = spline.arcLength(1.0f); float totalArcLength = splineFinal.arcLength(1.0f);
float t = spline.arcLengthInverse(ratio * totalArcLength); 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() && myAvatar->getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() &&
!(params.primaryControllerFlags[Rig::PrimaryControllerType_Spine2] & (uint8_t)Rig::ControllerFlags::Enabled)) { !(params.primaryControllerFlags[Rig::PrimaryControllerType_Spine2] & (uint8_t)Rig::ControllerFlags::Enabled)) {
controller::Pose headSplineControllerPose = myAvatar->getControllerPoseInSensorFrame(controller::Action::HEAD); // if (avatarHeadPose.isValid()) {
AnimPose headSplinePose(headSplineControllerPose.getRotation(), headSplineControllerPose.getTranslation());
glm::vec3 spine2TargetTranslation = computeSpine2WithHeadHipsSpline(myAvatar, sensorHips, headSplinePose); AnimPose headAvatarSpace(avatarHeadPose.getRotation(), avatarHeadPose.getTranslation());
AnimPose sensorSpine2(Quaternions::IDENTITY, spine2TargetTranslation); AnimPose headRigSpace = avatarToRigPose * headAvatarSpace;
AnimPose rigSpine2 = sensorToRigPose * sensorSpine2; 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; const float SPINE2_ROTATION_FILTER = 0.5f;
AnimPose currentSpine2Pose; AnimPose currentSpine2Pose;
@ -292,7 +316,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
} }
generateBasisVectors(up, fwd, u, v, w); 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))); 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); currentSpine2Pose.rot() = safeLerp(currentSpine2Pose.rot(), newSpinePose.rot(), SPINE2_ROTATION_FILTER);
params.primaryControllerPoses[Rig::PrimaryControllerType_Spine2] = currentSpine2Pose; params.primaryControllerPoses[Rig::PrimaryControllerType_Spine2] = currentSpine2Pose;
params.primaryControllerFlags[Rig::PrimaryControllerType_Spine2] = (uint8_t)Rig::ControllerFlags::Enabled | (uint8_t)Rig::ControllerFlags::Estimated; 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 // rig is ready
void Avatar::rigReady() { void Avatar::rigReady() {
buildUnscaledEyeHeightCache(); buildUnscaledEyeHeightCache();
buildSpine2SplineRatioCache();
} }
// rig has been reset. // rig has been reset.
void Avatar::rigReset() { void Avatar::rigReset() {
clearUnscaledEyeHeightCache(); clearUnscaledEyeHeightCache();
clearSpine2SplineRatioCache();
} }
// create new model, can return an instance of a SoftAttachmentModel rather then Model // 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() { void Avatar::clearUnscaledEyeHeightCache() {
_unscaledEyeHeightCache.set(DEFAULT_AVATAR_EYE_HEIGHT); _unscaledEyeHeightCache.set(DEFAULT_AVATAR_EYE_HEIGHT);
} }
void Avatar::clearSpine2SplineRatioCache() {
_spine2SplineRatio = DEFAULT_AVATAR_EYE_HEIGHT;
_spine2SplineOffset = glm::vec3();
}
float Avatar::getUnscaledEyeHeightFromSkeleton() const { float Avatar::getUnscaledEyeHeightFromSkeleton() const {
// TODO: if performance becomes a concern we can cache this value rather then computing it everytime. // 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 <render/Scene.h>
#include <graphics-scripting/Forward.h> #include <graphics-scripting/Forward.h>
#include <GLMHelpers.h> #include <GLMHelpers.h>
#include <CubicHermiteSpline.h>
#include "Head.h" #include "Head.h"
#include "SkeletonModel.h" #include "SkeletonModel.h"
@ -228,6 +229,9 @@ public:
virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; } 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 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 setSkeletonModelURL(const QUrl& skeletonModelURL) override;
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData) override; virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData) override;
@ -499,7 +503,9 @@ public slots:
protected: protected:
float getUnscaledEyeHeightFromSkeleton() const; float getUnscaledEyeHeightFromSkeleton() const;
void buildUnscaledEyeHeightCache(); void buildUnscaledEyeHeightCache();
void buildSpine2SplineRatioCache();
void clearUnscaledEyeHeightCache(); 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. virtual const QString& getSessionDisplayNameForTransport() const override { return _empty; } // Save a tiny bit of bandwidth. Mixer won't look at what we send.
QString _empty{}; QString _empty{};
virtual void maybeUpdateSessionDisplayNameFromTransport(const QString& sessionDisplayName) override { _sessionDisplayName = sessionDisplayName; } // don't use no-op setter! virtual void maybeUpdateSessionDisplayNameFromTransport(const QString& sessionDisplayName) override { _sessionDisplayName = sessionDisplayName; } // don't use no-op setter!
@ -552,6 +558,7 @@ protected:
float getHeadHeight() const; float getHeadHeight() const;
float getPelvisFloatingHeight() const; float getPelvisFloatingHeight() const;
glm::vec3 getDisplayNamePosition() const; glm::vec3 getDisplayNamePosition() const;
Transform calculateDisplayNameTransform(const ViewFrustum& view, const glm::vec3& textPosition) const; Transform calculateDisplayNameTransform(const ViewFrustum& view, const glm::vec3& textPosition) const;
void renderDisplayName(gpu::Batch& batch, 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 }; float _displayNameAlpha { 1.0f };
ThreadSafeValueCache<float> _unscaledEyeHeightCache { DEFAULT_AVATAR_EYE_HEIGHT }; 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::unordered_map<std::string, graphics::MultiMaterial> _materials;
std::mutex _materialsLock; 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_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_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_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_LEFT = -0.25f;
const float DEFAULT_AVATAR_SUPPORT_BASE_RIGHT = 0.25f; const float DEFAULT_AVATAR_SUPPORT_BASE_RIGHT = 0.25f;
const float DEFAULT_AVATAR_SUPPORT_BASE_FRONT = -0.20f; const float DEFAULT_AVATAR_SUPPORT_BASE_FRONT = -0.20f;