mirror of
https://github.com/overte-org/overte.git
synced 2025-04-25 21:36:12 +02:00
208 lines
6.7 KiB
C++
208 lines
6.7 KiB
C++
//
|
|
// AnimUtil.h
|
|
//
|
|
// Created by Anthony J. Thibault on 9/2/15.
|
|
// Copyright (c) 2015 High Fidelity, Inc. All rights reserved.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
#ifndef hifi_AnimUtil_h
|
|
#define hifi_AnimUtil_h
|
|
|
|
#include "AnimNode.h"
|
|
|
|
// this is where the magic happens
|
|
void blend(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, AnimPose* result);
|
|
|
|
// blend between three sets of poses
|
|
void blend3(size_t numPoses, const AnimPose* a, const AnimPose* b, const AnimPose* c, float* alphas, AnimPose* result);
|
|
|
|
// blend between four sets of poses
|
|
void blend4(size_t numPoses, const AnimPose* a, const AnimPose* b, const AnimPose* c, const AnimPose* d, float* alphas, AnimPose* result);
|
|
|
|
// additive blending
|
|
void blendAdd(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, AnimPose* result);
|
|
|
|
glm::quat averageQuats(size_t numQuats, const glm::quat* quats);
|
|
|
|
float accumulateTime(float startFrame, float endFrame, float timeScale, float currentFrame, float dt, bool loopFlag,
|
|
const QString& id, AnimVariantMap& triggersOut);
|
|
|
|
inline glm::quat safeLerp(const glm::quat& a, const glm::quat& b, float alpha) {
|
|
// adjust signs if necessary
|
|
glm::quat bTemp = b;
|
|
float dot = glm::dot(a, bTemp);
|
|
if (dot < 0.0f) {
|
|
bTemp = -bTemp;
|
|
}
|
|
return glm::normalize(glm::lerp(a, bTemp, alpha));
|
|
}
|
|
|
|
inline glm::quat safeLinearCombine3(const glm::quat& a, const glm::quat& b, const glm::quat& c, float* alphas) {
|
|
// adjust signs for b & c if necessary
|
|
glm::quat bTemp = b;
|
|
float dot = glm::dot(a, bTemp);
|
|
if (dot < 0.0f) {
|
|
bTemp = -bTemp;
|
|
}
|
|
glm::quat cTemp = c;
|
|
dot = glm::dot(a, cTemp);
|
|
if (dot < 0.0f) {
|
|
cTemp = -cTemp;
|
|
}
|
|
return glm::normalize(alphas[0] * a + alphas[1] * bTemp + alphas[2] * cTemp);
|
|
}
|
|
|
|
inline glm::quat safeLinearCombine4(const glm::quat& a, const glm::quat& b, const glm::quat& c, const glm::quat& d, float* alphas) {
|
|
// adjust signs for b, c & d if necessary
|
|
glm::quat bTemp = b;
|
|
float dot = glm::dot(a, bTemp);
|
|
if (dot < 0.0f) {
|
|
bTemp = -bTemp;
|
|
}
|
|
glm::quat cTemp = c;
|
|
dot = glm::dot(a, cTemp);
|
|
if (dot < 0.0f) {
|
|
cTemp = -cTemp;
|
|
}
|
|
glm::quat dTemp = d;
|
|
dot = glm::dot(a, dTemp);
|
|
if (dot < 0.0f) {
|
|
dTemp = -dTemp;
|
|
}
|
|
return glm::normalize(alphas[0] * a + alphas[1] * bTemp + alphas[2] * cTemp + alphas[3] * dTemp);
|
|
}
|
|
|
|
AnimPose boneLookAt(const glm::vec3& target, const AnimPose& bone);
|
|
|
|
// This will attempt to determine the proper body facing of a characters body
|
|
// assumes headRot is z-forward and y-up.
|
|
// and returns a bodyRot that is also z-forward and y-up
|
|
glm::quat computeBodyFacingFromHead(const glm::quat& headRot, const glm::vec3& up);
|
|
|
|
|
|
// Uses a approximation of a critically damped spring to smooth full AnimPoses.
|
|
// It provides seperate timescales for horizontal, vertical and rotation components.
|
|
// The timescale is roughly how much time it will take the spring will reach halfway toward it's target.
|
|
class CriticallyDampedSpringPoseHelper {
|
|
public:
|
|
CriticallyDampedSpringPoseHelper() : _prevPoseValid(false) {}
|
|
|
|
void setHorizontalTranslationTimescale(float timescale) {
|
|
_horizontalTranslationTimescale = timescale;
|
|
}
|
|
void setVerticalTranslationTimescale(float timescale) {
|
|
_verticalTranslationTimescale = timescale;
|
|
}
|
|
void setRotationTimescale(float timescale) {
|
|
_rotationTimescale = timescale;
|
|
}
|
|
|
|
AnimPose update(const AnimPose& pose, float deltaTime) {
|
|
if (!_prevPoseValid) {
|
|
_prevPose = pose;
|
|
_prevPoseValid = true;
|
|
}
|
|
|
|
const float horizontalTranslationAlpha = glm::min(deltaTime / _horizontalTranslationTimescale, 1.0f);
|
|
const float verticalTranslationAlpha = glm::min(deltaTime / _verticalTranslationTimescale, 1.0f);
|
|
const float rotationAlpha = glm::min(deltaTime / _rotationTimescale, 1.0f);
|
|
|
|
const float poseY = pose.trans().y;
|
|
AnimPose newPose = _prevPose;
|
|
newPose.trans() = lerp(_prevPose.trans(), pose.trans(), horizontalTranslationAlpha);
|
|
newPose.trans().y = lerp(_prevPose.trans().y, poseY, verticalTranslationAlpha);
|
|
newPose.rot() = safeLerp(_prevPose.rot(), pose.rot(), rotationAlpha);
|
|
|
|
_prevPose = newPose;
|
|
_prevPoseValid = true;
|
|
|
|
return newPose;
|
|
}
|
|
|
|
void teleport(const AnimPose& pose) {
|
|
_prevPoseValid = true;
|
|
_prevPose = pose;
|
|
}
|
|
|
|
protected:
|
|
AnimPose _prevPose;
|
|
float _horizontalTranslationTimescale { 0.15f };
|
|
float _verticalTranslationTimescale { 0.15f };
|
|
float _rotationTimescale { 0.15f };
|
|
bool _prevPoseValid;
|
|
};
|
|
|
|
class SnapshotBlendPoseHelper {
|
|
public:
|
|
SnapshotBlendPoseHelper() : _snapshotValid(false) {}
|
|
|
|
void setBlendDuration(float duration) {
|
|
_duration = duration;
|
|
}
|
|
|
|
void setSnapshot(const AnimPose& pose) {
|
|
_snapshotValid = true;
|
|
_snapshotPose = pose;
|
|
_timer = _duration;
|
|
}
|
|
|
|
AnimPose update(const AnimPose& targetPose, float deltaTime) {
|
|
_timer -= deltaTime;
|
|
if (_timer > 0.0f) {
|
|
float alpha = (_duration - _timer) / _duration;
|
|
|
|
// ease in expo
|
|
alpha = 1.0f - powf(2.0f, -10.0f * alpha);
|
|
|
|
AnimPose newPose = targetPose;
|
|
newPose.blend(_snapshotPose, alpha);
|
|
return newPose;
|
|
} else {
|
|
return targetPose;
|
|
}
|
|
}
|
|
|
|
protected:
|
|
AnimPose _snapshotPose;
|
|
float _duration { 1.0f };
|
|
float _timer { 0.0f };
|
|
bool _snapshotValid { false };
|
|
};
|
|
|
|
// returns true if the given point lies inside of the k-dop, specified by shapeInfo & shapePose.
|
|
// if the given point does lie within the k-dop, it also returns the amount of displacement necessary to push that point outward
|
|
// such that it lies on the surface of the kdop.
|
|
bool findPointKDopDisplacement(const glm::vec3& point, const AnimPose& shapePose, const HFMJointShapeInfo& shapeInfo, glm::vec3& displacementOut);
|
|
|
|
enum EasingType {
|
|
EasingType_Linear,
|
|
EasingType_EaseInSine,
|
|
EasingType_EaseOutSine,
|
|
EasingType_EaseInOutSine,
|
|
EasingType_EaseInQuad,
|
|
EasingType_EaseOutQuad,
|
|
EasingType_EaseInOutQuad,
|
|
EasingType_EaseInCubic,
|
|
EasingType_EaseOutCubic,
|
|
EasingType_EaseInOutCubic,
|
|
EasingType_EaseInQuart,
|
|
EasingType_EaseOutQuart,
|
|
EasingType_EaseInOutQuart,
|
|
EasingType_EaseInQuint,
|
|
EasingType_EaseOutQuint,
|
|
EasingType_EaseInOutQuint,
|
|
EasingType_EaseInExpo,
|
|
EasingType_EaseOutExpo,
|
|
EasingType_EaseInOutExpo,
|
|
EasingType_EaseInCirc,
|
|
EasingType_EaseOutCirc,
|
|
EasingType_EaseInOutCirc,
|
|
EasingType_NumTypes
|
|
};
|
|
|
|
float easingFunc(float alpha, EasingType type);
|
|
|
|
#endif
|