mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 17:00:13 +02:00
First pass at Rig timeScaling and blending between slow, walk and run.
This commit is contained in:
parent
11f2d29bf8
commit
5cd2786c1d
4 changed files with 65 additions and 5 deletions
|
@ -4,7 +4,7 @@
|
||||||
"id": "ikOverlay",
|
"id": "ikOverlay",
|
||||||
"type": "overlay",
|
"type": "overlay",
|
||||||
"data": {
|
"data": {
|
||||||
"alpha": 1.0,
|
"alpha": 0.0,
|
||||||
"boneSet": "fullBody"
|
"boneSet": "fullBody"
|
||||||
},
|
},
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -532,7 +532,8 @@
|
||||||
"alpha": 0.0,
|
"alpha": 0.0,
|
||||||
"sync": true,
|
"sync": true,
|
||||||
"timeScale": 1.0,
|
"timeScale": 1.0,
|
||||||
"timeScaleVar": "walkTimeScale"
|
"timeScaleVar": "walkTimeScale",
|
||||||
|
"alphaVar": "walkAlpha"
|
||||||
},
|
},
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
|
@ -558,6 +559,18 @@
|
||||||
"loopFlag": true
|
"loopFlag": true
|
||||||
},
|
},
|
||||||
"children": []
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "walkFwdRun",
|
||||||
|
"type": "clip",
|
||||||
|
"data": {
|
||||||
|
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/run_fwd.fbx",
|
||||||
|
"startFrame": 0.0,
|
||||||
|
"endFrame": 21.0,
|
||||||
|
"timeScale": 1.0,
|
||||||
|
"loopFlag": true
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -408,6 +408,41 @@ glm::mat4 Rig::getJointTransform(int jointIndex) const {
|
||||||
return _jointStates[jointIndex].getTransform();
|
return _jointStates[jointIndex].getTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Rig::calcWalkForwardAlphaAndTimeScale(float speed, float* alphaOut, float* timeScaleOut) {
|
||||||
|
|
||||||
|
// filter speed using a moving average.
|
||||||
|
_averageForwardSpeed.updateAverage(speed);
|
||||||
|
speed = _averageForwardSpeed.getAverage();
|
||||||
|
|
||||||
|
const int NUM_FWD_SPEEDS = 3;
|
||||||
|
float FWD_SPEEDS[NUM_FWD_SPEEDS] = { 0.3f, 1.4f, 2.7f }; // m/s
|
||||||
|
|
||||||
|
// first calculate alpha by lerping between speeds.
|
||||||
|
float alpha = 0.0f;
|
||||||
|
if (speed <= FWD_SPEEDS[0]) {
|
||||||
|
alpha = 0.0f;
|
||||||
|
} else if (speed > FWD_SPEEDS[NUM_FWD_SPEEDS - 1]) {
|
||||||
|
alpha = (float)(NUM_FWD_SPEEDS - 1);
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < NUM_FWD_SPEEDS - 1; i++) {
|
||||||
|
if (FWD_SPEEDS[i] < speed && speed < FWD_SPEEDS[i + 1]) {
|
||||||
|
alpha = (float)i + ((speed - FWD_SPEEDS[i]) / (FWD_SPEEDS[i + 1] - FWD_SPEEDS[i]));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now keeping the alpha fixed compute the timeScale.
|
||||||
|
// NOTE: This makes the assumption that the velocity of a linear blend between two animations is also linear.
|
||||||
|
int prevIndex = glm::floor(alpha);
|
||||||
|
int nextIndex = glm::ceil(alpha);
|
||||||
|
float animSpeed = lerp(FWD_SPEEDS[prevIndex], FWD_SPEEDS[nextIndex], (float)glm::fract(alpha));
|
||||||
|
float timeScale = glm::clamp(0.5f, 2.0f, speed / animSpeed);
|
||||||
|
|
||||||
|
*alphaOut = alpha;
|
||||||
|
*timeScaleOut = timeScale;
|
||||||
|
}
|
||||||
|
|
||||||
void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation) {
|
void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation) {
|
||||||
|
|
||||||
glm::vec3 front = worldRotation * IDENTITY_FRONT;
|
glm::vec3 front = worldRotation * IDENTITY_FRONT;
|
||||||
|
@ -435,10 +470,13 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
|
||||||
|
|
||||||
// sine wave LFO var for testing.
|
// sine wave LFO var for testing.
|
||||||
static float t = 0.0f;
|
static float t = 0.0f;
|
||||||
_animVars.set("sine", static_cast<float>(0.5 * sin(t) + 0.5));
|
_animVars.set("sine", 2.0f * static_cast<float>(0.5 * sin(t) + 0.5));
|
||||||
|
|
||||||
const float ANIM_WALK_SPEED = 1.4f; // m/s
|
float walkAlpha, walkTimeScale;
|
||||||
_animVars.set("walkTimeScale", glm::clamp(0.5f, 2.0f, glm::length(localVel) / ANIM_WALK_SPEED));
|
calcWalkForwardAlphaAndTimeScale(glm::length(localVel), &walkAlpha, &walkTimeScale);
|
||||||
|
|
||||||
|
_animVars.set("walkTimeScale", walkTimeScale);
|
||||||
|
_animVars.set("walkAlpha", walkAlpha);
|
||||||
|
|
||||||
const float MOVE_ENTER_SPEED_THRESHOLD = 0.2f; // m/sec
|
const float MOVE_ENTER_SPEED_THRESHOLD = 0.2f; // m/sec
|
||||||
const float MOVE_EXIT_SPEED_THRESHOLD = 0.07f; // m/sec
|
const float MOVE_EXIT_SPEED_THRESHOLD = 0.07f; // m/sec
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
|
|
||||||
#include "AnimNode.h"
|
#include "AnimNode.h"
|
||||||
#include "AnimNodeLoader.h"
|
#include "AnimNodeLoader.h"
|
||||||
|
#include "SimpleMovingAverage.h"
|
||||||
|
|
||||||
class AnimationHandle;
|
class AnimationHandle;
|
||||||
typedef std::shared_ptr<AnimationHandle> AnimationHandlePointer;
|
typedef std::shared_ptr<AnimationHandle> AnimationHandlePointer;
|
||||||
|
@ -206,6 +207,7 @@ public:
|
||||||
void updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist);
|
void updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist);
|
||||||
void updateNeckJoint(int index, const HeadParameters& params);
|
void updateNeckJoint(int index, const HeadParameters& params);
|
||||||
void updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAt, const glm::vec3& saccade);
|
void updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAt, const glm::vec3& saccade);
|
||||||
|
void calcWalkForwardAlphaAndTimeScale(float speed, float* alphaOut, float* timeScaleOut);
|
||||||
|
|
||||||
QVector<JointState> _jointStates;
|
QVector<JointState> _jointStates;
|
||||||
int _rootJointIndex = -1;
|
int _rootJointIndex = -1;
|
||||||
|
@ -240,6 +242,8 @@ public:
|
||||||
float _desiredStateAge = 0.0f;
|
float _desiredStateAge = 0.0f;
|
||||||
float _leftHandOverlayAlpha = 0.0f;
|
float _leftHandOverlayAlpha = 0.0f;
|
||||||
float _rightHandOverlayAlpha = 0.0f;
|
float _rightHandOverlayAlpha = 0.0f;
|
||||||
|
|
||||||
|
SimpleMovingAverage _averageForwardSpeed{ 25 };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__hifi__Rig__) */
|
#endif /* defined(__hifi__Rig__) */
|
||||||
|
|
|
@ -183,6 +183,11 @@ T toNormalizedDeviceScale(const T& value, const T& size) {
|
||||||
#define PITCH(euler) euler.x
|
#define PITCH(euler) euler.x
|
||||||
#define ROLL(euler) euler.z
|
#define ROLL(euler) euler.z
|
||||||
|
|
||||||
|
// float - linear interpolate
|
||||||
|
inline float lerp(float x, float y, float a) {
|
||||||
|
return x * (1.0f - a) + (y * a);
|
||||||
|
}
|
||||||
|
|
||||||
// vec2 lerp - linear interpolate
|
// vec2 lerp - linear interpolate
|
||||||
template<typename T, glm::precision P>
|
template<typename T, glm::precision P>
|
||||||
glm::detail::tvec2<T, P> lerp(const glm::detail::tvec2<T, P>& x, const glm::detail::tvec2<T, P>& y, T a) {
|
glm::detail::tvec2<T, P> lerp(const glm::detail::tvec2<T, P>& x, const glm::detail::tvec2<T, P>& y, T a) {
|
||||||
|
|
Loading…
Reference in a new issue