mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 06:44:06 +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",
|
||||
"type": "overlay",
|
||||
"data": {
|
||||
"alpha": 1.0,
|
||||
"alpha": 0.0,
|
||||
"boneSet": "fullBody"
|
||||
},
|
||||
"children": [
|
||||
|
@ -532,7 +532,8 @@
|
|||
"alpha": 0.0,
|
||||
"sync": true,
|
||||
"timeScale": 1.0,
|
||||
"timeScaleVar": "walkTimeScale"
|
||||
"timeScaleVar": "walkTimeScale",
|
||||
"alphaVar": "walkAlpha"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
|
@ -558,6 +559,18 @@
|
|||
"loopFlag": true
|
||||
},
|
||||
"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();
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
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.
|
||||
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
|
||||
_animVars.set("walkTimeScale", glm::clamp(0.5f, 2.0f, glm::length(localVel) / ANIM_WALK_SPEED));
|
||||
float walkAlpha, walkTimeScale;
|
||||
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_EXIT_SPEED_THRESHOLD = 0.07f; // m/sec
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
#include "AnimNode.h"
|
||||
#include "AnimNodeLoader.h"
|
||||
#include "SimpleMovingAverage.h"
|
||||
|
||||
class AnimationHandle;
|
||||
typedef std::shared_ptr<AnimationHandle> AnimationHandlePointer;
|
||||
|
@ -206,6 +207,7 @@ public:
|
|||
void updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist);
|
||||
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 calcWalkForwardAlphaAndTimeScale(float speed, float* alphaOut, float* timeScaleOut);
|
||||
|
||||
QVector<JointState> _jointStates;
|
||||
int _rootJointIndex = -1;
|
||||
|
@ -240,6 +242,8 @@ public:
|
|||
float _desiredStateAge = 0.0f;
|
||||
float _leftHandOverlayAlpha = 0.0f;
|
||||
float _rightHandOverlayAlpha = 0.0f;
|
||||
|
||||
SimpleMovingAverage _averageForwardSpeed{ 25 };
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__Rig__) */
|
||||
|
|
|
@ -183,6 +183,11 @@ T toNormalizedDeviceScale(const T& value, const T& size) {
|
|||
#define PITCH(euler) euler.x
|
||||
#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
|
||||
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) {
|
||||
|
|
Loading…
Reference in a new issue