diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5880f4ee3c..96fdd6a9e1 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -5322,15 +5322,17 @@ void MyAvatar::addAvatarHandsToFlow(const std::shared_ptr& otherAvatar) } } -void MyAvatar::useFlow(const QVariantMap& physicsConfig, const QVariantMap& collisionsConfig) { +void MyAvatar::useFlow(bool isActive, bool isCollidable, const QVariantMap& physicsConfig, const QVariantMap& collisionsConfig) { if (_skeletonModel->isLoaded()) { auto &flow = _skeletonModel->getRig().getFlow(); - flow.init(); + flow.init(isActive, isCollidable); + auto &collisionSystem = flow.getCollisionSystem(); + collisionSystem.setActive(isCollidable); auto physicsGroups = physicsConfig.keys(); if (physicsGroups.size() > 0) { for (auto &groupName : physicsGroups) { auto &settings = physicsConfig[groupName].toMap(); - FlowPhysicsSettings physicsSettings = flow.getPhysicsSettingsForGroup(groupName); + FlowPhysicsSettings physicsSettings; if (settings.contains("active")) { physicsSettings._active = settings["active"].toBool(); } @@ -5357,7 +5359,6 @@ void MyAvatar::useFlow(const QVariantMap& physicsConfig, const QVariantMap& coll } auto collisionJoints = collisionsConfig.keys(); if (collisionJoints.size() > 0) { - auto &collisionSystem = flow.getCollisionSystem(); collisionSystem.resetCollisions(); for (auto &jointName : collisionJoints) { int jointIndex = getJointIndex(jointName); @@ -5372,7 +5373,6 @@ void MyAvatar::useFlow(const QVariantMap& physicsConfig, const QVariantMap& coll } collisionSystem.addCollisionSphere(jointIndex, collisionsSettings); } - } } } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index f98ae9208a..2c8dedd430 100755 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1189,12 +1189,14 @@ public: /**jsdoc * Init flow simulation on avatar. * @function MyAvatar.useFlow + * @param {boolean} - Set to true to activate flow simulation. + * @param {boolean} - Set to true to activate collisions. * @param {Object} physicsConfig - object with the customized physic parameters * i.e. {"hair": {"active": true, "stiffness": 0.0, "radius": 0.04, "gravity": -0.035, "damping": 0.8, "inertia": 0.8, "delta": 0.35}} * @param {Object} collisionsConfig - object with the customized collision parameters * i.e. {"Spine2": {"type": "sphere", "radius": 0.14, "offset": {"x": 0.0, "y": 0.2, "z": 0.0}}} */ - Q_INVOKABLE void useFlow(const QVariantMap& flowConfig = QVariantMap(), const QVariantMap& collisionsConfig = QVariantMap()); + Q_INVOKABLE void useFlow(bool isActive, bool isCollidable, const QVariantMap& physicsConfig = QVariantMap(), const QVariantMap& collisionsConfig = QVariantMap()); public slots: diff --git a/libraries/animation/src/Flow.cpp b/libraries/animation/src/Flow.cpp index 3db0068434..607b2775e0 100644 --- a/libraries/animation/src/Flow.cpp +++ b/libraries/animation/src/Flow.cpp @@ -93,8 +93,7 @@ FlowCollisionResult FlowCollisionSystem::computeCollision(const std::vector FlowCollisionSystem::checkFlowThreadCollisions( return results; }; -int FlowCollisionSystem::findSelfCollisionWithJoint(int jointIndex) { - for (size_t i = 0; i < _selfCollisions.size(); i++) { - if (_selfCollisions[i]._jointIndex == jointIndex) { - return (int)i; - } - } - return -1; -}; - -void FlowCollisionSystem::modifySelfCollisionRadius(int jointIndex, float radius) { - int collisionIndex = findSelfCollisionWithJoint(jointIndex); - if (collisionIndex > -1) { - _selfCollisions[collisionIndex]._initialRadius = radius; - //_selfCollisions[collisionIndex]._radius = _scale * radius; - } -}; - -void FlowCollisionSystem::modifySelfCollisionYOffset(int jointIndex, float offset) { - int collisionIndex = findSelfCollisionWithJoint(jointIndex); - if (collisionIndex > -1) { - auto currentOffset = _selfCollisions[collisionIndex]._offset; - _selfCollisions[collisionIndex]._initialOffset = glm::vec3(currentOffset.x, offset, currentOffset.z); - //_selfCollisions[collisionIndex]._offset = _selfCollisions[collisionIndex]._initialOffset * _scale; - } -}; - -void FlowCollisionSystem::modifySelfCollisionOffset(int jointIndex, const glm::vec3& offset) { - int collisionIndex = findSelfCollisionWithJoint(jointIndex); - if (collisionIndex > -1) { - _selfCollisions[collisionIndex]._initialOffset = offset; - //_selfCollisions[collisionIndex]._offset = _selfCollisions[collisionIndex]._initialOffset * _scale; - } -}; FlowCollisionSettings FlowCollisionSystem::getCollisionSettingsByJoint(int jointIndex) { for (auto &collision : _selfCollisions) { if (collision._jointIndex == jointIndex) { @@ -243,13 +209,11 @@ void FlowNode::update(float deltaTime, const glm::vec3& accelerationOffset) { // Add offset _acceleration += accelerationOffset; - - //glm::vec3 deltaAcceleration = timeRatio * _acceleration * glm::pow(_settings._delta * _scale, 2); - glm::vec3 deltaAcceleration = timeRatio * _acceleration * glm::pow(_settings._delta, 2); + float accelerationFactor = glm::pow(_settings._delta, 2) * timeRatio; + glm::vec3 deltaAcceleration = _acceleration * accelerationFactor; // Calculate new position - _currentPosition = (_currentPosition + _currentVelocity * _settings._damping) + deltaAcceleration; - } - else { + _currentPosition = _currentPosition + (_currentVelocity * _settings._damping) + deltaAcceleration; + } else { _acceleration = glm::vec3(0.0f); _currentVelocity = glm::vec3(0.0f); } @@ -273,8 +237,7 @@ void FlowNode::solveCollisions(const FlowCollisionResult& collision) { if (_colliding) { _currentPosition = _currentPosition + collision._normal * collision._offset; _previousCollision = collision; - } - else { + } else { _previousCollision = FlowCollisionResult(); } }; @@ -317,7 +280,8 @@ void FlowJoint::update(float deltaTime) { glm::vec3 accelerationOffset = glm::vec3(0.0f); if (_node._settings._stiffness > 0.0f) { glm::vec3 recoveryVector = _recoveryPosition - _node._currentPosition; - accelerationOffset = recoveryVector * glm::pow(_node._settings._stiffness, 3); + float recoveryFactor = glm::pow(_node._settings._stiffness, 3); + accelerationOffset = recoveryVector * recoveryFactor; } _node.update(deltaTime, accelerationOffset); if (_node._anchored) { @@ -386,7 +350,8 @@ void FlowThread::computeRecovery() { glm::quat parentRotation = parentJoint._parentWorldRotation * parentJoint._initialRotation; for (size_t i = 1; i < _joints.size(); i++) { auto joint = _jointsPointer->at(_joints[i]); - glm::quat rotation = i == 1 ? parentRotation : rotation * parentJoint._initialRotation; + glm::quat rotation; + rotation = (i == 1) ? parentRotation : parentJoint._initialRotation; _jointsPointer->at(_joints[i])._recoveryPosition = joint._recoveryPosition = parentJoint._recoveryPosition + (rotation * (joint._initialTranslation * 0.01f)); parentJoint = joint; } @@ -395,8 +360,11 @@ void FlowThread::computeRecovery() { void FlowThread::update(float deltaTime) { if (getActive()) { _positions.clear(); - _radius = _jointsPointer->at(_joints[0])._node._settings._radius; - computeRecovery(); + auto &firstJoint = _jointsPointer->at(_joints[0]); + _radius = firstJoint._node._settings._radius; + if (firstJoint._node._settings._stiffness > 0.0f) { + computeRecovery(); + } for (size_t i = 0; i < _joints.size(); i++) { auto &joint = _jointsPointer->at(_joints[i]); joint.update(deltaTime); @@ -405,11 +373,10 @@ void FlowThread::update(float deltaTime) { } }; -void FlowThread::solve(bool useCollisions, FlowCollisionSystem& collisionSystem) { +void FlowThread::solve(FlowCollisionSystem& collisionSystem) { if (getActive()) { - if (useCollisions) { + if (collisionSystem.getActive()) { auto bodyCollisions = collisionSystem.checkFlowThreadCollisions(this); - int handTouchedJoint = -1; for (size_t i = 0; i < _joints.size(); i++) { int index = _joints[i]; _jointsPointer->at(index).solve(bodyCollisions[i]); @@ -471,10 +438,15 @@ bool FlowThread::getActive() { return _jointsPointer->at(_joints[0])._node._active; }; -void Flow::init() { - if (!_initialized) { - calculateConstraints(); +void Flow::init(bool isActive, bool isCollidable) { + if (isActive) { + if (!_initialized) { + calculateConstraints(); + } + } else { + cleanUp(); } + } void Flow::calculateConstraints() { @@ -509,18 +481,18 @@ void Flow::calculateConstraints() { if (isFlowJoint || isSimJoint) { group = ""; if (isSimJoint) { - qDebug() << "FLOW is sim: " << name; - for (size_t j = 1; j < name.size() - 1; j++) { + for (int j = 1; j < name.size() - 1; j++) { bool toFloatSuccess; - auto subname = (QStringRef(&name, (int)(name.size() - j), 1)).toString().toFloat(&toFloatSuccess); - if (!toFloatSuccess && (name.size() - j) > simPrefix.size()) { - group = QStringRef(&name, simPrefix.size(), (int)(name.size() - j + 1)).toString(); + QStringRef(&name, (int)(name.size() - j), 1).toString().toFloat(&toFloatSuccess); + if (!toFloatSuccess && (name.size() - j) > (int)simPrefix.size()) { + group = QStringRef(&name, (int)simPrefix.size(), (int)(name.size() - j + 1)).toString(); break; } } if (group.isEmpty()) { - group = QStringRef(&name, simPrefix.size(), name.size() - 1).toString(); + group = QStringRef(&name, (int)simPrefix.size(), name.size() - 1).toString(); } + qCDebug(animation) << "Sim joint added to flow: " << name; } else { group = split[1]; } @@ -559,12 +531,12 @@ void Flow::calculateConstraints() { std::vector roots; - for (auto& itr = _flowJointData.begin(); itr != _flowJointData.end(); itr++) { - if (_flowJointData.find(itr->second._parentIndex) == _flowJointData.end()) { - itr->second._node._anchored = true; - roots.push_back(itr->first); + for (auto &joint :_flowJointData) { + if (_flowJointData.find(joint.second._parentIndex) == _flowJointData.end()) { + joint.second._node._anchored = true; + roots.push_back(joint.first); } else { - _flowJointData[itr->second._parentIndex]._childIndex = itr->first; + _flowJointData[joint.second._parentIndex]._childIndex = joint.first; } } @@ -629,6 +601,10 @@ void Flow::cleanUp() { _initialized = false; _isScaleSet = false; _active = false; + if (_rig) { + _rig->clearJointStates(); + } + } void Flow::setTransform(float scale, const glm::vec3& position, const glm::quat& rotation) { @@ -638,52 +614,49 @@ void Flow::setTransform(float scale, const glm::vec3& position, const glm::quat& _active = _initialized; } +void Flow::setScale(float scale) { + if (!_isScaleSet) { + for (auto &joint : _flowJointData) { + joint.second._initialLength = joint.second._length / _scale; + } + _isScaleSet = true; + } + _lastScale = _scale; + _collisionSystem.setScale(_scale); + for (size_t i = 0; i < _jointThreads.size(); i++) { + for (size_t j = 0; j < _jointThreads[i]._joints.size(); j++) { + auto &joint = _flowJointData[_jointThreads[i]._joints[j]]; + joint._node._settings._radius = joint._node._initialRadius * _scale; + joint._length = joint._initialLength * _scale; + } + _jointThreads[i].resetLength(); + } +} + void Flow::update(float deltaTime) { if (_initialized && _active) { - QElapsedTimer _timer; - _timer.start(); + uint64_t startTime = usecTimestampNow(); + uint64_t updateExpiry = startTime + MAX_UPDATE_FLOW_TIME_BUDGET; if (_scale != _lastScale) { - if (!_isScaleSet) { - for (auto &joint: _flowJointData) { - joint.second._initialLength = joint.second._length / _scale; - } - _isScaleSet = true; - } - _lastScale = _scale; - _collisionSystem.setScale(_scale); - for (int i = 0; i < _jointThreads.size(); i++) { - for (int j = 0; j < _jointThreads[i]._joints.size(); j++) { - auto &joint = _flowJointData[_jointThreads[i]._joints[j]]; - joint._node._settings._radius = joint._node._initialRadius * _scale; - joint._length = joint._initialLength * _scale; - } - _jointThreads[i].resetLength(); - } + setScale(_scale); } updateJoints(); for (size_t i = 0; i < _jointThreads.size(); i++) { size_t index = _invertThreadLoop ? _jointThreads.size() - 1 - i : i; auto &thread = _jointThreads[index]; thread.update(deltaTime); - thread.solve(USE_COLLISIONS, _collisionSystem); + thread.solve(_collisionSystem); if (!updateRootFramePositions(index)) { return; } thread.apply(); - if (_timer.elapsed() > MAX_UPDATE_FLOW_TIME_BUDGET) { + if (usecTimestampNow() > updateExpiry) { break; qWarning(animation) << "Flow Bones ran out of time updating threads"; } } setJoints(); _invertThreadLoop = !_invertThreadLoop; - _deltaTime += _timer.nsecsElapsed(); - _updates++; - if (_deltaTime > _deltaTimeLimit) { - qDebug() << "Flow C++ update " << _deltaTime / _updates << " nanoSeconds "; - _deltaTime = 0; - _updates = 0; - } } } @@ -753,15 +726,6 @@ void Flow::setOthersCollision(const QUuid& otherId, int jointIndex, const glm::v _collisionSystem.addCollisionSphere(jointIndex, settings, position, false, true); } -FlowPhysicsSettings Flow::getPhysicsSettingsForGroup(const QString& group) { - for (auto &joint : _flowJointData) { - if (joint.second._group.toUpper() == group.toUpper()) { - return joint.second._node._settings; - } - } - return FlowPhysicsSettings(); -} - void Flow::setPhysicsSettingsForGroup(const QString& group, const FlowPhysicsSettings& settings) { for (auto &joint : _flowJointData) { if (joint.second._group.toUpper() == group.toUpper()) { diff --git a/libraries/animation/src/Flow.h b/libraries/animation/src/Flow.h index 7f77df0beb..bb15846b5e 100644 --- a/libraries/animation/src/Flow.h +++ b/libraries/animation/src/Flow.h @@ -11,7 +11,6 @@ #ifndef hifi_Flow_h #define hifi_Flow_h -#include #include #include #include @@ -22,11 +21,7 @@ class Rig; class AnimSkeleton; -const bool SHOW_AVATAR = true; -const bool SHOW_DEBUG_SHAPES = false; -const bool SHOW_SOLID_SHAPES = false; const bool SHOW_DUMMY_JOINTS = false; -const bool USE_COLLISIONS = true; const int LEFT_HAND = 0; const int RIGHT_HAND = 1; @@ -55,7 +50,7 @@ const float DUMMY_JOINT_DISTANCE = 0.05f; const float ISOLATED_JOINT_STIFFNESS = 0.0f; const float ISOLATED_JOINT_LENGTH = 0.05f; -const float DEFAULT_STIFFNESS = 0.8f; +const float DEFAULT_STIFFNESS = 0.0f; const float DEFAULT_GRAVITY = -0.0096f; const float DEFAULT_DAMPING = 0.85f; const float DEFAULT_INERTIA = 0.8f; @@ -76,7 +71,7 @@ struct FlowPhysicsSettings { _radius = radius; } bool _active{ true }; - float _stiffness{ 0.0f }; + float _stiffness{ DEFAULT_STIFFNESS }; float _gravity{ DEFAULT_GRAVITY }; float _damping{ DEFAULT_DAMPING }; float _inertia{ DEFAULT_INERTIA }; @@ -158,11 +153,6 @@ public: std::vector checkFlowThreadCollisions(FlowThread* flowThread); - int findSelfCollisionWithJoint(int jointIndex); - void modifySelfCollisionRadius(int jointIndex, float radius); - void modifySelfCollisionYOffset(int jointIndex, float offset); - void modifySelfCollisionOffset(int jointIndex, const glm::vec3& offset); - std::vector& getSelfCollisions() { return _selfCollisions; }; void setOthersCollisions(const std::vector& othersCollisions) { _othersCollisions = othersCollisions; } void prepareCollisions(); @@ -171,11 +161,14 @@ public: void setScale(float scale); FlowCollisionSettings getCollisionSettingsByJoint(int jointIndex); void setCollisionSettingsByJoint(int jointIndex, const FlowCollisionSettings& settings); + void setActive(bool active) { _active = active; } + bool getActive() const { return _active; } protected: std::vector _selfCollisions; std::vector _othersCollisions; std::vector _allCollisions; - float _scale{ 1.0f }; + float _scale { 1.0f }; + bool _active { false }; }; class FlowNode { @@ -260,7 +253,7 @@ public: void computeFlowThread(int rootIndex); void computeRecovery(); void update(float deltaTime); - void solve(bool useCollisions, FlowCollisionSystem& collisionSystem); + void solve(FlowCollisionSystem& collisionSystem); void computeJointRotations(); void apply(); bool getActive(); @@ -277,7 +270,7 @@ public: class Flow { public: Flow(Rig* rig) { _rig = rig; }; - void init(); + void init(bool isActive, bool isCollidable); bool isActive() { return _active; } void calculateConstraints(); void update(float deltaTime); @@ -286,7 +279,6 @@ public: const std::vector& getThreads() const { return _jointThreads; } void setOthersCollision(const QUuid& otherId, int jointIndex, const glm::vec3& position); FlowCollisionSystem& getCollisionSystem() { return _collisionSystem; } - FlowPhysicsSettings getPhysicsSettingsForGroup(const QString& group); void setPhysicsSettingsForGroup(const QString& group, const FlowPhysicsSettings& settings); private: void setJoints(); @@ -294,6 +286,7 @@ private: void updateJoints(); bool updateRootFramePositions(size_t threadIndex); bool worldToJointPoint(const glm::vec3& position, const int jointIndex, glm::vec3& jointSpacePosition) const; + void setScale(float scale); Rig* _rig; float _scale { 1.0f }; float _lastScale{ 1.0f }; @@ -306,9 +299,6 @@ private: bool _initialized { false }; bool _active { false }; bool _isScaleSet { false }; - int _deltaTime { 0 }; - int _deltaTimeLimit { 4000000 }; - int _updates { 0 }; bool _invertThreadLoop { false }; };