From c83af43d0e93d1b6f27417240abbc3326d975c32 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 21 Oct 2015 17:34:09 -0700 Subject: [PATCH] Added strafe and backward blending --- .../defaultAvatar_full/avatar-animation.json | 118 ++++++++++++++---- libraries/animation/src/Rig.cpp | 53 +++++--- libraries/animation/src/Rig.h | 3 +- 3 files changed, 133 insertions(+), 41 deletions(-) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index e75e806df6..723176c17e 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -4,7 +4,7 @@ "id": "ikOverlay", "type": "overlay", "data": { - "alpha": 0.0, + "alpha": 1.0, "boneSet": "fullBody" }, "children": [ @@ -532,8 +532,8 @@ "alpha": 0.0, "sync": true, "timeScale": 1.0, - "timeScaleVar": "walkTimeScale", - "alphaVar": "walkAlpha" + "timeScaleVar": "moveForwardTimeScale", + "alphaVar": "moveForwardAlpha" }, "children": [ { @@ -576,16 +576,40 @@ }, { "id": "walkBwd", - "type": "clip", + "type": "blendLinear", "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/walk_bwd.fbx", - "startFrame": 0.0, - "endFrame": 37.0, + "alpha": 1.0, + "sync": true, "timeScale": 1.0, - "loopFlag": true, - "timeScaleVar": "walkTimeScale" + "timeScaleVar": "moveBackwardTimeScale", + "alphaVar": "moveBackwardAlpha" }, - "children": [] + "children": [ + { + "id": "walkBwdShort", + "type": "clip", + "data": { + "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/walk_short_bwd.fbx", + "startFrame": 0.0, + "endFrame": 38.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "walkBwdNormal", + "type": "clip", + "data": { + "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/walk_bwd.fbx", + "startFrame": 0.0, + "endFrame": 36.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] }, { "id": "turnLeft", @@ -613,27 +637,77 @@ }, { "id": "strafeLeft", - "type": "clip", + "type": "blendLinear", "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/side_step_left.fbx", - "startFrame": 0.0, - "endFrame": 30.0, + "alpha": 0.0, + "sync": true, "timeScale": 1.0, - "loopFlag": true + "timeScaleVar": "moveLateralTimeScale", + "alphaVar": "moveLateralAlpha" }, - "children": [] + "children": [ + { + "id": "strafeLeftShort", + "type": "clip", + "data": { + "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/side_step_short_left.fbx", + "startFrame": 0.0, + "endFrame": 28.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "strafeLeftNormal", + "type": "clip", + "data": { + "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/side_step_left.fbx", + "startFrame": 0.0, + "endFrame": 30.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] }, { "id": "strafeRight", - "type": "clip", + "type": "blendLinear", "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/side_step_right.fbx", - "startFrame": 0.0, - "endFrame": 30.0, + "alpha": 0.0, + "sync": true, "timeScale": 1.0, - "loopFlag": true + "timeScaleVar": "moveLateralTimeScale", + "alphaVar": "moveLateralAlpha" }, - "children": [] + "children": [ + { + "id": "strafeRightShort", + "type": "clip", + "data": { + "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/side_step_short_right.fbx", + "startFrame": 0.0, + "endFrame": 28.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "strafeRightNormal", + "type": "clip", + "data": { + "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/side_step_right.fbx", + "startFrame": 0.0, + "endFrame": 30.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] } ] } diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 9179e7675f..cf1d1bc703 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -408,25 +408,20 @@ glm::mat4 Rig::getJointTransform(int jointIndex) const { return _jointStates[jointIndex].getTransform(); } -void Rig::calcWalkForwardAlphaAndTimeScale(float speed, float* alphaOut, float* timeScaleOut) { +void Rig::calcAnimAlphaAndTimeScale(float speed, const std::vector& referenceSpeeds, float* alphaOut, float* timeScaleOut) const { - // 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 + assert(referenceSpeeds.size() > 0); // first calculate alpha by lerping between speeds. float alpha = 0.0f; - if (speed <= FWD_SPEEDS[0]) { + if (speed <= referenceSpeeds.front()) { alpha = 0.0f; - } else if (speed > FWD_SPEEDS[NUM_FWD_SPEEDS - 1]) { - alpha = (float)(NUM_FWD_SPEEDS - 1); + } else if (speed > referenceSpeeds.back()) { + alpha = (float)(referenceSpeeds.size() - 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])); + for (size_t i = 0; i < referenceSpeeds.size() - 1; i++) { + if (referenceSpeeds[i] < speed && speed < referenceSpeeds[i + 1]) { + alpha = (float)i + ((speed - referenceSpeeds[i]) / (referenceSpeeds[i + 1] - referenceSpeeds[i])); break; } } @@ -436,13 +431,18 @@ void Rig::calcWalkForwardAlphaAndTimeScale(float speed, float* alphaOut, float* // 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 animSpeed = lerp(referenceSpeeds[prevIndex], referenceSpeeds[nextIndex], (float)glm::fract(alpha)); float timeScale = glm::clamp(0.5f, 2.0f, speed / animSpeed); *alphaOut = alpha; *timeScaleOut = timeScale; } +// animation reference speeds. +static const std::vector FORWARD_SPEEDS = { 0.4f, 1.4f, 2.5f }; // m/s +static const std::vector BACKWARD_SPEEDS = { 0.45f, 1.4f }; // m/s +static const std::vector LATERAL_SPEEDS = { 0.2f, 0.65f }; // m/s + void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation) { glm::vec3 front = worldRotation * IDENTITY_FRONT; @@ -468,15 +468,32 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos float lateralSpeed = glm::dot(localVel, IDENTITY_RIGHT); float turningSpeed = glm::orientedAngle(front, _lastFront, IDENTITY_UP) / deltaTime; + // filter speeds using a simple moving average. + _averageForwardSpeed.updateAverage(forwardSpeed); + _averageLateralSpeed.updateAverage(lateralSpeed); + // sine wave LFO var for testing. static float t = 0.0f; _animVars.set("sine", 2.0f * static_cast(0.5 * sin(t) + 0.5)); - float walkAlpha, walkTimeScale; - calcWalkForwardAlphaAndTimeScale(glm::length(localVel), &walkAlpha, &walkTimeScale); + float moveForwardAlpha = 0.0f; + float moveForwardTimeScale = 1.0f; + float moveBackwardAlpha = 0.0f; + float moveBackwardTimeScale = 1.0f; + float moveLateralAlpha = 0.0f; + float moveLateralTimeScale = 1.0f; - _animVars.set("walkTimeScale", walkTimeScale); - _animVars.set("walkAlpha", walkAlpha); + // calcuate the animation alpha and timeScale values based on current speeds and animation reference speeds. + calcAnimAlphaAndTimeScale(_averageForwardSpeed.getAverage(), FORWARD_SPEEDS, &moveForwardAlpha, &moveForwardTimeScale); + calcAnimAlphaAndTimeScale(-_averageForwardSpeed.getAverage(), BACKWARD_SPEEDS, &moveBackwardAlpha, &moveBackwardTimeScale); + calcAnimAlphaAndTimeScale(fabsf(_averageLateralSpeed.getAverage()), LATERAL_SPEEDS, &moveLateralAlpha, &moveLateralTimeScale); + + _animVars.set("moveFowardTimeScale", moveForwardTimeScale); + _animVars.set("moveForwardAlpha", moveForwardAlpha); + _animVars.set("moveBackwardTimeScale", moveBackwardTimeScale); + _animVars.set("moveBackwardAlpha", moveBackwardAlpha); + _animVars.set("moveLateralTimeScale", moveLateralTimeScale); + _animVars.set("moveLateralAlpha", moveLateralAlpha); const float MOVE_ENTER_SPEED_THRESHOLD = 0.2f; // m/sec const float MOVE_EXIT_SPEED_THRESHOLD = 0.07f; // m/sec diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 93692eb00c..d1031c017a 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -208,7 +208,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); + void calcAnimAlphaAndTimeScale(float speed, const std::vector& referenceSpeeds, float* alphaOut, float* timeScaleOut) const; QVector _jointStates; int _rootJointIndex = -1; @@ -245,6 +245,7 @@ public: float _rightHandOverlayAlpha = 0.0f; SimpleMovingAverage _averageForwardSpeed{ 25 }; + SimpleMovingAverage _averageLateralSpeed{ 25 }; }; #endif /* defined(__hifi__Rig__) */