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