Overte C++ Documentation
Flow.h
1 //
2 // Flow.h
3 //
4 // Created by Luis Cuenca on 1/21/2019.
5 // Copyright 2019 High Fidelity, Inc.
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_Flow_h
12 #define hifi_Flow_h
13 
14 #include <memory>
15 #include <qstring.h>
16 #include <glm/glm.hpp>
17 #include <glm/gtx/quaternion.hpp>
18 #include <vector>
19 #include <map>
20 #include <quuid.h>
21 #include "AnimPose.h"
22 
23 class Rig;
24 class AnimSkeleton;
25 
26 const float HAPTIC_TOUCH_STRENGTH = 0.25f;
27 const float HAPTIC_TOUCH_DURATION = 10.0f;
28 const float HAPTIC_SLOPE = 0.18f;
29 const float HAPTIC_THRESHOLD = 40.0f;
30 
31 const QString FLOW_JOINT_PREFIX = "flow";
32 const QString SIM_JOINT_PREFIX = "sim";
33 
34 const std::vector<QString> HAND_COLLISION_JOINTS = { "RightHandMiddle1", "RightHandThumb3", "LeftHandMiddle1", "LeftHandThumb3", "RightHandMiddle3", "LeftHandMiddle3" };
35 
36 const float HAND_COLLISION_RADIUS = 0.03f;
37 const float HELPER_JOINT_LENGTH = 0.05f;
38 
39 const float DEFAULT_STIFFNESS = 0.0f;
40 const float DEFAULT_GRAVITY = -0.0096f;
41 const float DEFAULT_DAMPING = 0.85f;
42 const float DEFAULT_INERTIA = 0.8f;
43 const float DEFAULT_DELTA = 0.55f;
44 const float DEFAULT_RADIUS = 0.01f;
45 
46 const uint64_t MAX_UPDATE_FLOW_TIME_BUDGET = 2000;
47 
48 struct FlowPhysicsSettings {
49  FlowPhysicsSettings() {};
50  FlowPhysicsSettings(bool active, float stiffness, float gravity, float damping, float inertia, float delta, float radius) {
51  _active = active;
52  _stiffness = stiffness;
53  _gravity = gravity;
54  _damping = damping;
55  _inertia = inertia;
56  _delta = delta;
57  _radius = radius;
58  }
59  bool _active{ true };
60  float _stiffness{ DEFAULT_STIFFNESS };
61  float _gravity{ DEFAULT_GRAVITY };
62  float _damping{ DEFAULT_DAMPING };
63  float _inertia{ DEFAULT_INERTIA };
64  float _delta{ DEFAULT_DELTA };
65  float _radius{ DEFAULT_RADIUS };
66 };
67 
68 enum FlowCollisionType {
69  CollisionSphere = 0
70 };
71 
72 struct FlowCollisionSettings {
73  FlowCollisionSettings() {};
74  FlowCollisionSettings(const QUuid& id, const FlowCollisionType& type, const glm::vec3& offset, float radius) {
75  _entityID = id;
76  _type = type;
77  _offset = offset;
78  _radius = radius;
79  };
80  QUuid _entityID;
81  FlowCollisionType _type { FlowCollisionType::CollisionSphere };
82  float _radius { 0.05f };
83  glm::vec3 _offset;
84 };
85 
86 const FlowPhysicsSettings DEFAULT_JOINT_SETTINGS;
87 
88 struct FlowJointInfo {
89  FlowJointInfo() {};
90  FlowJointInfo(int index, int parentIndex, int childIndex, const QString& name) {
91  _index = index;
92  _parentIndex = parentIndex;
93  _childIndex = childIndex;
94  _name = name;
95  }
96  int _index { -1 };
97  QString _name;
98  int _parentIndex { -1 };
99  int _childIndex { -1 };
100 };
101 
102 struct FlowCollisionResult {
103  int _count { 0 };
104  float _offset { 0.0f };
105  glm::vec3 _position;
106  float _radius { 0.0f };
107  glm::vec3 _normal;
108  float _distance { 0.0f };
109 };
110 
111 class FlowCollisionSphere {
112 public:
113  FlowCollisionSphere() {};
114  FlowCollisionSphere(const int& jointIndex, const FlowCollisionSettings& settings, bool isTouch = false);
115  void setPosition(const glm::vec3& position) { _position = position; }
116  FlowCollisionResult computeSphereCollision(const glm::vec3& point, float radius) const;
117  FlowCollisionResult checkSegmentCollision(const glm::vec3& point1, const glm::vec3& point2, const FlowCollisionResult& collisionResult1, const FlowCollisionResult& collisionResult2);
118 
119  QUuid _entityID;
120 
121  glm::vec3 _offset;
122  glm::vec3 _initialOffset;
123  glm::vec3 _position;
124 
125  bool _isTouch { false };
126  int _jointIndex { -1 };
127  int collisionIndex { -1 };
128  float _radius { 0.0f };
129  float _initialRadius{ 0.0f };
130 };
131 
132 class FlowThread;
133 
134 class FlowCollisionSystem {
135 public:
136  FlowCollisionSystem() {};
137  void addCollisionSphere(int jointIndex, const FlowCollisionSettings& settings, const glm::vec3& position = { 0.0f, 0.0f, 0.0f }, bool isSelfCollision = true, bool isTouch = false);
138  FlowCollisionResult computeCollision(const std::vector<FlowCollisionResult> collisions);
139 
140  std::vector<FlowCollisionResult> checkFlowThreadCollisions(FlowThread* flowThread);
141 
142  std::vector<FlowCollisionSphere>& getSelfCollisions() { return _selfCollisions; };
143  std::vector<FlowCollisionSphere>& getSelfTouchCollisions() { return _selfTouchCollisions; };
144  void setOthersCollisions(const std::vector<FlowCollisionSphere>& othersCollisions) { _othersCollisions = othersCollisions; }
145  void prepareCollisions();
146  void resetCollisions();
147  void resetOthersCollisions() { _othersCollisions.clear(); }
148  void setScale(float scale);
149  FlowCollisionSettings getCollisionSettingsByJoint(int jointIndex);
150  void setCollisionSettingsByJoint(int jointIndex, const FlowCollisionSettings& settings);
151  void setActive(bool active) { _active = active; }
152  bool getActive() const { return _active; }
153  const std::vector<FlowCollisionSphere>& getCollisions() const { return _selfCollisions; }
154  void clearSelfCollisions() { _selfCollisions.clear(); }
155 protected:
156  std::vector<FlowCollisionSphere> _selfCollisions;
157  std::vector<FlowCollisionSphere> _othersCollisions;
158  std::vector<FlowCollisionSphere> _selfTouchCollisions;
159  std::vector<FlowCollisionSphere> _allCollisions;
160  float _scale { 1.0f };
161  bool _active { false };
162 };
163 
164 class FlowNode {
165 public:
166  FlowNode() {};
167  FlowNode(const glm::vec3& initialPosition, FlowPhysicsSettings settings);
168 
169  void update(float deltaTime, const glm::vec3& accelerationOffset);
170  void solve(const glm::vec3& constrainPoint, float maxDistance, const FlowCollisionResult& collision);
171  void solveConstraints(const glm::vec3& constrainPoint, float maxDistance);
172  void solveCollisions(const FlowCollisionResult& collision);
173 
174 protected:
175 
176  FlowPhysicsSettings _settings;
177  glm::vec3 _initialPosition;
178  glm::vec3 _previousPosition;
179  glm::vec3 _currentPosition;
180 
181  glm::vec3 _currentVelocity;
182  glm::vec3 _previousVelocity;
183  glm::vec3 _acceleration;
184 
185  FlowCollisionResult _collision;
186  FlowCollisionResult _previousCollision;
187 
188  float _initialRadius { 0.0f };
189 
190  bool _anchored { false };
191  bool _colliding { false };
192  bool _active { true };
193 
194  float _scale{ 1.0f };
195 };
196 
197 class FlowJoint : public FlowNode {
198 public:
199  friend class FlowThread;
200 
201  FlowJoint(): FlowNode() {};
202  FlowJoint(int jointIndex, int parentIndex, int childIndex, const QString& name, const QString& group, const FlowPhysicsSettings& settings);
203  void toHelperJoint(const glm::vec3& initialPosition, float length);
204  void setInitialData(const glm::vec3& initialPosition, const glm::vec3& initialTranslation, const glm::quat& initialRotation, const glm::vec3& parentPosition);
205  void setUpdatedData(const glm::vec3& updatedPosition, const glm::vec3& updatedTranslation, const glm::quat& updatedRotation, const glm::vec3& parentPosition, const glm::quat& parentWorldRotation);
206  void setRecoveryPosition(const glm::vec3& recoveryPosition);
207  void update(float deltaTime);
208  void solve(const FlowCollisionResult& collision);
209 
210  void setScale(float scale, bool initScale);
211  bool isAnchored() const { return _anchored; }
212  void setAnchored(bool anchored) { _anchored = anchored; }
213  bool isHelper() const { return _isHelper; }
214 
215  const FlowPhysicsSettings& getSettings() { return _settings; }
216  void setSettings(const FlowPhysicsSettings& settings) { _settings = settings; _initialRadius = _settings._radius; }
217 
218  const glm::vec3& getCurrentPosition() const { return _currentPosition; }
219  int getIndex() const { return _index; }
220  int getParentIndex() const { return _parentIndex; }
221  void setChildIndex(int index) { _childIndex = index; }
222  const glm::vec3& getUpdatedPosition() const { return _updatedPosition; }
223  const QString& getGroup() const { return _group; }
224  const QString& getName() const { return _name; }
225  const glm::quat& getCurrentRotation() const { return _currentRotation; }
226  const glm::vec3& getCurrentTranslation() const { return _initialTranslation; }
227  const glm::vec3& getInitialPosition() const { return _initialPosition; }
228  const glm::quat& getInitialRotation() const { return _initialRotation; }
229  bool isColliding() const { return _colliding; }
230 
231 protected:
232 
233  int _index{ -1 };
234  int _parentIndex{ -1 };
235  int _childIndex{ -1 };
236  QString _name;
237  QString _group;
238 
239  bool _isHelper{ false };
240 
241  glm::vec3 _initialTranslation;
242  glm::quat _initialRotation;
243 
244  glm::vec3 _updatedPosition;
245  glm::vec3 _updatedTranslation;
246  glm::quat _updatedRotation;
247 
248  glm::quat _currentRotation;
249  glm::vec3 _recoveryPosition;
250 
251  glm::vec3 _parentPosition;
252  glm::quat _parentWorldRotation;
253  glm::vec3 _translationDirection;
254 
255  float _length { 0.0f };
256  float _initialLength { 0.0f };
257 
258  bool _applyRecovery { false };
259 };
260 
261 class FlowThread {
262 public:
263  FlowThread() {};
264  FlowThread& operator=(const FlowThread& otherFlowThread);
265 
266  FlowThread(int rootIndex, std::map<int, FlowJoint>* joints, float rigScale);
267 
268  void resetLength();
269  void computeFlowThread(int rootIndex);
270  void computeRecovery();
271  void update(float deltaTime);
272  void solve(FlowCollisionSystem& collisionSystem);
273  void computeJointRotations();
274  void setRootFramePositions(const std::vector<glm::vec3>& rootFramePositions) { _rootFramePositions = rootFramePositions; }
275  void setScale(float scale, bool initScale = false);
276 
277  std::vector<int> _joints;
278  std::vector<glm::vec3> _positions;
279  float _radius{ 0.0f };
280  float _length{ 0.0f };
281  // 100.0f was default rig scale when it was hardcoded but it caused issues with most avatars
282  float _rigScale { 100.0f };
283  std::map<int, FlowJoint>* _jointsPointer;
284  std::vector<glm::vec3> _rootFramePositions;
285 };
286 
287 class Flow : public QObject{
288  Q_OBJECT
289 public:
290  Flow(Rig *rig) : _rig (rig) {};
291  Flow& operator=(const Flow& otherFlow);
292  bool getActive() const { return _active; }
293  void setActive(bool active) { _active = active; }
294  bool isInitialized() const { return _initialized; }
295  float getScale() const { return _scale; }
296  void calculateConstraints(const std::shared_ptr<AnimSkeleton>& skeleton, AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses);
297  void update(float deltaTime, AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses, const std::vector<bool>& overrideFlags);
298  void setTransform(float scale, const glm::vec3& position, const glm::quat& rotation);
299  const std::map<int, FlowJoint>& getJoints() const { return _flowJointData; }
300  const std::vector<FlowThread>& getThreads() const { return _jointThreads; }
301  void setOthersCollision(const QUuid& otherId, int jointIndex, const glm::vec3& position);
302  FlowCollisionSystem& getCollisionSystem() { return _collisionSystem; }
303  void setPhysicsSettingsForGroup(const QString& group, const FlowPhysicsSettings& settings);
304  const std::map<QString, FlowPhysicsSettings>& getGroupSettings() const { return _groupSettings; }
305  void cleanUp();
306  void updateScale() { setScale(_scale); }
307 
308 signals:
309  void onCleanup();
310 
311 private:
312  void updateAbsolutePoses(const AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses);
313  bool getJointPositionInWorldFrame(const AnimPoseVec& absolutePoses, int jointIndex, glm::vec3& position, glm::vec3 translation, glm::quat rotation) const;
314  bool getJointRotationInWorldFrame(const AnimPoseVec& absolutePoses, int jointIndex, glm::quat& result, const glm::quat& rotation) const;
315  bool getJointRotation(const AnimPoseVec& relativePoses, int jointIndex, glm::quat& rotation) const;
316  bool getJointTranslation(const AnimPoseVec& relativePoses, int jointIndex, glm::vec3& translation) const;
317  bool worldToJointPoint(const AnimPoseVec& absolutePoses, const glm::vec3& position, const int jointIndex, glm::vec3& jointSpacePosition) const;
318 
319  void setJoints(AnimPoseVec& relativePoses, const std::vector<bool>& overrideFlags);
320  void updateJoints(AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses);
321  void updateCollisionJoint(FlowCollisionSphere& collision, AnimPoseVec& absolutePoses);
322  bool updateRootFramePositions(const AnimPoseVec& absolutePoses, size_t threadIndex);
323  void updateGroupSettings(const QString& group, const FlowPhysicsSettings& settings);
324  void setScale(float scale);
325 
326  float _scale { 1.0f };
327  float _lastScale{ 1.0f };
328  // Rig to which flow system belongs, it's used for getting rig scale
329  Rig *_rig { nullptr };
330  glm::vec3 _entityPosition;
331  glm::quat _entityRotation;
332  std::map<int, FlowJoint> _flowJointData;
333  std::map<QString, FlowPhysicsSettings> _groupSettings;
334  std::vector<FlowThread> _jointThreads;
335  std::vector<QString> _flowJointKeywords;
336  FlowCollisionSystem _collisionSystem;
337  bool _initialized { false };
338  bool _active { false };
339  bool _isScaleSet { false };
340  bool _invertThreadLoop { false };
341 };
342 
343 #endif // hifi_Flow_h