Overte C++ Documentation
AnimUtil.h
1 //
2 // AnimUtil.h
3 //
4 // Created by Anthony J. Thibault on 9/2/15.
5 // Copyright (c) 2015 High Fidelity, Inc. All rights reserved.
6 //
7 // Distributed under the Apache License, Version 2.0.
8 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
9 //
10 
11 #ifndef hifi_AnimUtil_h
12 #define hifi_AnimUtil_h
13 
14 #include "AnimNode.h"
15 
16 #include <cmath>
17 
18 // this is where the magic happens
19 void blend(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, AnimPose* result);
20 
21 // blend between three sets of poses
22 void blend3(size_t numPoses, const AnimPose* a, const AnimPose* b, const AnimPose* c, float* alphas, AnimPose* result);
23 
24 // blend between four sets of poses
25 void blend4(size_t numPoses, const AnimPose* a, const AnimPose* b, const AnimPose* c, const AnimPose* d, float* alphas, AnimPose* result);
26 
27 // additive blending
28 void blendAdd(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, AnimPose* result);
29 
30 glm::quat averageQuats(size_t numQuats, const glm::quat* quats);
31 
32 float accumulateTime(float startFrame, float endFrame, float timeScale, float currentFrame, float dt, bool loopFlag,
33  const QString& id, AnimVariantMap& triggersOut);
34 
35 inline glm::quat safeLerp(const glm::quat& a, const glm::quat& b, float alpha) {
36  // adjust signs if necessary
37  glm::quat bTemp = b;
38  float dot = glm::dot(a, bTemp);
39  if (dot < 0.0f) {
40  bTemp = -bTemp;
41  }
42  return glm::normalize(glm::lerp(a, bTemp, alpha));
43 }
44 
45 inline glm::quat safeLinearCombine3(const glm::quat& a, const glm::quat& b, const glm::quat& c, float* alphas) {
46  // adjust signs for b & c if necessary
47  glm::quat bTemp = b;
48  float dot = glm::dot(a, bTemp);
49  if (dot < 0.0f) {
50  bTemp = -bTemp;
51  }
52  glm::quat cTemp = c;
53  dot = glm::dot(a, cTemp);
54  if (dot < 0.0f) {
55  cTemp = -cTemp;
56  }
57  return glm::normalize(alphas[0] * a + alphas[1] * bTemp + alphas[2] * cTemp);
58 }
59 
60 inline glm::quat safeLinearCombine4(const glm::quat& a, const glm::quat& b, const glm::quat& c, const glm::quat& d, float* alphas) {
61  // adjust signs for b, c & d if necessary
62  glm::quat bTemp = b;
63  float dot = glm::dot(a, bTemp);
64  if (dot < 0.0f) {
65  bTemp = -bTemp;
66  }
67  glm::quat cTemp = c;
68  dot = glm::dot(a, cTemp);
69  if (dot < 0.0f) {
70  cTemp = -cTemp;
71  }
72  glm::quat dTemp = d;
73  dot = glm::dot(a, dTemp);
74  if (dot < 0.0f) {
75  dTemp = -dTemp;
76  }
77  return glm::normalize(alphas[0] * a + alphas[1] * bTemp + alphas[2] * cTemp + alphas[3] * dTemp);
78 }
79 
80 AnimPose boneLookAt(const glm::vec3& target, const AnimPose& bone);
81 
82 // This will attempt to determine the proper body facing of a characters body
83 // assumes headRot is z-forward and y-up.
84 // and returns a bodyRot that is also z-forward and y-up
85 glm::quat computeBodyFacingFromHead(const glm::quat& headRot, const glm::vec3& up);
86 
87 
88 // Uses a approximation of a critically damped spring to smooth full AnimPoses.
89 // It provides seperate timescales for horizontal, vertical and rotation components.
90 // The timescale is roughly how much time it will take the spring will reach halfway toward it's target.
91 class CriticallyDampedSpringPoseHelper {
92 public:
93  CriticallyDampedSpringPoseHelper() : _prevPoseValid(false) {}
94 
95  void setHorizontalTranslationTimescale(float timescale) {
96  _horizontalTranslationTimescale = timescale;
97  }
98  void setVerticalTranslationTimescale(float timescale) {
99  _verticalTranslationTimescale = timescale;
100  }
101  void setRotationTimescale(float timescale) {
102  _rotationTimescale = timescale;
103  }
104 
105  AnimPose update(const AnimPose& pose, float deltaTime) {
106  if (!_prevPoseValid) {
107  _prevPose = pose;
108  _prevPoseValid = true;
109  }
110 
111  const float horizontalTranslationAlpha = glm::min(deltaTime / _horizontalTranslationTimescale, 1.0f);
112  const float verticalTranslationAlpha = glm::min(deltaTime / _verticalTranslationTimescale, 1.0f);
113  const float rotationAlpha = glm::min(deltaTime / _rotationTimescale, 1.0f);
114 
115  const float poseY = pose.trans().y;
116  AnimPose newPose = _prevPose;
117  newPose.trans() = lerp(_prevPose.trans(), pose.trans(), horizontalTranslationAlpha);
118  newPose.trans().y = std::lerp(_prevPose.trans().y, poseY, verticalTranslationAlpha);
119  newPose.rot() = safeLerp(_prevPose.rot(), pose.rot(), rotationAlpha);
120 
121  _prevPose = newPose;
122  _prevPoseValid = true;
123 
124  return newPose;
125  }
126 
127  void teleport(const AnimPose& pose) {
128  _prevPoseValid = true;
129  _prevPose = pose;
130  }
131 
132 protected:
133  AnimPose _prevPose;
134  float _horizontalTranslationTimescale { 0.15f };
135  float _verticalTranslationTimescale { 0.15f };
136  float _rotationTimescale { 0.15f };
137  bool _prevPoseValid;
138 };
139 
140 class SnapshotBlendPoseHelper {
141 public:
142  SnapshotBlendPoseHelper() : _snapshotValid(false) {}
143 
144  void setBlendDuration(float duration) {
145  _duration = duration;
146  }
147 
148  void setSnapshot(const AnimPose& pose) {
149  _snapshotValid = true;
150  _snapshotPose = pose;
151  _timer = _duration;
152  }
153 
154  AnimPose update(const AnimPose& targetPose, float deltaTime) {
155  _timer -= deltaTime;
156  if (_timer > 0.0f) {
157  float alpha = (_duration - _timer) / _duration;
158 
159  // ease in expo
160  alpha = 1.0f - powf(2.0f, -10.0f * alpha);
161 
162  AnimPose newPose = targetPose;
163  newPose.blend(_snapshotPose, alpha);
164  return newPose;
165  } else {
166  return targetPose;
167  }
168  }
169 
170 protected:
171  AnimPose _snapshotPose;
172  float _duration { 1.0f };
173  float _timer { 0.0f };
174  bool _snapshotValid { false };
175 };
176 
177 // returns true if the given point lies inside of the k-dop, specified by shapeInfo & shapePose.
178 // if the given point does lie within the k-dop, it also returns the amount of displacement necessary to push that point outward
179 // such that it lies on the surface of the kdop.
180 bool findPointKDopDisplacement(const glm::vec3& point, const AnimPose& shapePose, const HFMJointShapeInfo& shapeInfo, glm::vec3& displacementOut);
181 
182 enum EasingType {
183  EasingType_Linear,
184  EasingType_EaseInSine,
185  EasingType_EaseOutSine,
186  EasingType_EaseInOutSine,
187  EasingType_EaseInQuad,
188  EasingType_EaseOutQuad,
189  EasingType_EaseInOutQuad,
190  EasingType_EaseInCubic,
191  EasingType_EaseOutCubic,
192  EasingType_EaseInOutCubic,
193  EasingType_EaseInQuart,
194  EasingType_EaseOutQuart,
195  EasingType_EaseInOutQuart,
196  EasingType_EaseInQuint,
197  EasingType_EaseOutQuint,
198  EasingType_EaseInOutQuint,
199  EasingType_EaseInExpo,
200  EasingType_EaseOutExpo,
201  EasingType_EaseInOutExpo,
202  EasingType_EaseInCirc,
203  EasingType_EaseOutCirc,
204  EasingType_EaseInOutCirc,
205  EasingType_NumTypes
206 };
207 
208 float easingFunc(float alpha, EasingType type);
209 
210 #endif