From cf8f9fa1b68eabd9c1e75a47af685f126b95218d Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Mon, 4 Feb 2019 11:28:42 -0700 Subject: [PATCH 01/16] Threads created correctly --- interface/src/avatar/AvatarManager.cpp | 103 ++++++++++++++++++ interface/src/avatar/AvatarManager.h | 9 ++ libraries/animation/src/Rig.cpp | 6 +- libraries/animation/src/Rig.h | 3 + .../src/avatars-renderer/Avatar.h | 3 + libraries/entities/src/EntityTree.cpp | 6 + libraries/entities/src/EntityTree.h | 1 + 7 files changed, 129 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 1eb87c16f0..c9e099df21 100755 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -760,6 +760,109 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic return result; } +RayToAvatarIntersectionResult AvatarManager::findRayIntersectionOld(const PickRay& ray, + const QScriptValue& avatarIdsToInclude, + const QScriptValue& avatarIdsToDiscard) { + QVector avatarsToInclude = qVectorEntityItemIDFromScriptValue(avatarIdsToInclude); + QVector avatarsToDiscard = qVectorEntityItemIDFromScriptValue(avatarIdsToDiscard); + + return findRayIntersectionVectorOld(ray, avatarsToInclude, avatarsToDiscard); +} + +RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVectorOld(const PickRay& ray, + const QVector& avatarsToInclude, + const QVector& avatarsToDiscard) { + RayToAvatarIntersectionResult result; + if (QThread::currentThread() != thread()) { + BLOCKING_INVOKE_METHOD(const_cast(this), "findRayIntersectionVector", + Q_RETURN_ARG(RayToAvatarIntersectionResult, result), + Q_ARG(const PickRay&, ray), + Q_ARG(const QVector&, avatarsToInclude), + Q_ARG(const QVector&, avatarsToDiscard)); + return result; + } + + // It's better to intersect the ray against the avatar's actual mesh, but this is currently difficult to + // do, because the transformed mesh data only exists over in GPU-land. As a compromise, this code + // intersects against the avatars capsule and then against the (T-pose) mesh. The end effect is that picking + // against the avatar is sort-of right, but you likely wont be able to pick against the arms. + + // TODO -- find a way to extract transformed avatar mesh data from the rendering engine. + + std::vector sortedAvatars; + auto avatarHashCopy = getHashCopy(); + for (auto avatarData : avatarHashCopy) { + auto avatar = std::static_pointer_cast(avatarData); + if ((avatarsToInclude.size() > 0 && !avatarsToInclude.contains(avatar->getID())) || + (avatarsToDiscard.size() > 0 && avatarsToDiscard.contains(avatar->getID()))) { + continue; + } + + float distance = FLT_MAX; +#if 0 + // if we weren't picking against the capsule, we would want to pick against the avatarBounds... + SkeletonModelPointer avatarModel = avatar->getSkeletonModel(); + AABox avatarBounds = avatarModel->getRenderableMeshBound(); + if (avatarBounds.contains(ray.origin)) { + distance = 0.0f; + } + else { + float boundDistance = FLT_MAX; + BoxFace face; + glm::vec3 surfaceNormal; + if (avatarBounds.findRayIntersection(ray.origin, ray.direction, boundDistance, face, surfaceNormal)) { + distance = boundDistance; + } + } +#else + glm::vec3 start; + glm::vec3 end; + float radius; + avatar->getCapsule(start, end, radius); + findRayCapsuleIntersection(ray.origin, ray.direction, start, end, radius, distance); +#endif + + if (distance < FLT_MAX) { + sortedAvatars.emplace_back(distance, avatar); + } + } + + if (sortedAvatars.size() > 1) { + static auto comparator = [](const SortedAvatar& left, const SortedAvatar& right) { return left.first < right.first; }; + std::sort(sortedAvatars.begin(), sortedAvatars.end(), comparator); + } + + for (auto it = sortedAvatars.begin(); it != sortedAvatars.end(); ++it) { + const SortedAvatar& sortedAvatar = *it; + // We can exit once avatarCapsuleDistance > bestDistance + if (sortedAvatar.first > result.distance) { + break; + } + + float distance = FLT_MAX; + BoxFace face; + glm::vec3 surfaceNormal; + QVariantMap extraInfo; + SkeletonModelPointer avatarModel = sortedAvatar.second->getSkeletonModel(); + if (avatarModel->findRayIntersectionAgainstSubMeshes(ray.origin, ray.direction, distance, face, surfaceNormal, extraInfo, true)) { + if (distance < result.distance) { + result.intersects = true; + result.avatarID = sortedAvatar.second->getID(); + result.distance = distance; + result.face = face; + result.surfaceNormal = surfaceNormal; + result.extraInfo = extraInfo; + } + } + } + + if (result.intersects) { + result.intersection = ray.origin + ray.direction * result.distance; + } + + return result; +} + ParabolaToAvatarIntersectionResult AvatarManager::findParabolaIntersectionVector(const PickParabola& pick, const QVector& avatarsToInclude, const QVector& avatarsToDiscard) { diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 50d9e80e8b..66f28206e0 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -157,6 +157,15 @@ public: const QVector& avatarsToDiscard, bool pickAgainstMesh); + Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersectionOld(const PickRay& ray, + const QScriptValue& avatarIdsToInclude = QScriptValue(), + const QScriptValue& avatarIdsToDiscard = QScriptValue()); + + Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersectionVectorOld(const PickRay& ray, + const QVector& avatarsToInclude, + const QVector& avatarsToDiscard); + + /**jsdoc * @function AvatarManager.findParabolaIntersectionVector * @param {PickParabola} pick diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index bc4dca54f2..8a05bdd018 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -34,7 +34,6 @@ #include "IKTarget.h" #include "PathUtils.h" - static int nextRigId = 1; static std::map rigRegistry; static std::mutex rigRegistryMutex; @@ -1871,7 +1870,7 @@ void Rig::initAnimGraph(const QUrl& url) { auto roleState = roleAnimState.second; overrideRoleAnimation(roleState.role, roleState.url, roleState.fps, roleState.loop, roleState.firstFrame, roleState.lastFrame); } - + _flow.setRig(this); emit onLoadComplete(); }); connect(_animLoader.get(), &AnimNodeLoader::error, [url](int error, QString str) { @@ -1903,6 +1902,9 @@ void Rig::initAnimGraph(const QUrl& url) { connect(_networkLoader.get(), &AnimNodeLoader::error, [networkUrl](int error, QString str) { qCritical(animation) << "Error loading: code = " << error << "str =" << str; }); + connect(this, &Rig::onLoadComplete, [&]() { + _flow.calculateConstraints(); + }); } } diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 41c25a3c3e..9bd2ed528a 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -25,6 +25,7 @@ #include "AnimNodeLoader.h" #include "SimpleMovingAverage.h" #include "AnimUtil.h" +#include "Flow.h" class Rig; class AnimInverseKinematics; @@ -233,6 +234,7 @@ public: const AnimContext::DebugAlphaMap& getDebugAlphaMap() const { return _lastContext.getDebugAlphaMap(); } const AnimVariantMap& getAnimVars() const { return _lastAnimVars; } const AnimContext::DebugStateMachineMap& getStateMachineMap() const { return _lastContext.getStateMachineMap(); } + void computeFlowSkeleton() { _flow.calculateConstraints(); } signals: void onLoadComplete(); @@ -424,6 +426,7 @@ protected: SnapshotBlendPoseHelper _hipsBlendHelper; ControllerParameters _previousControllerParameters; + Flow _flow; }; #endif /* defined(__hifi__Rig__) */ diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index b43fe012b7..4ba2ffc07d 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -35,6 +35,7 @@ #include "MetaModelPayload.h" #include "MultiSphereShape.h" +#include "Flow.h" namespace render { template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar); @@ -285,6 +286,8 @@ public: */ Q_INVOKABLE glm::quat jointToWorldRotation(const glm::quat& rotation, const int jointIndex = -1) const; + Q_INVOKABLE void callFlow() { _skeletonModel->getRig().computeFlowSkeleton(); }; + virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override; virtual void setAttachmentData(const QVector& attachmentData) override; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 954462a9f2..47064bdbd3 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -2943,6 +2943,12 @@ int EntityTree::getJointIndex(const QUuid& entityID, const QString& name) const } return entity->getJointIndex(name); } +void EntityTree::callFlowSkeleton(const QUuid& entityID) { + /* + EntityTree* nonConstThis = const_cast(this); + EntityItemPointer entity = nonConstThis->findEntityByEntityItemID(entityID); + */ +} QStringList EntityTree::getJointNames(const QUuid& entityID) const { EntityTree* nonConstThis = const_cast(this); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index f9b7b8d67f..cc80083e0d 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -240,6 +240,7 @@ public: // these are used to call through to EntityItems Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name) const; Q_INVOKABLE QStringList getJointNames(const QUuid& entityID) const; + Q_INVOKABLE void callFlowSkeleton(const QUuid& entityID); void knowAvatarID(QUuid avatarID) { _avatarIDs += avatarID; } void forgetAvatarID(QUuid avatarID) { _avatarIDs -= avatarID; } From 02646fb8a9fffe8ba36c05103f29852ad0db26e5 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 7 Feb 2019 14:09:53 -0700 Subject: [PATCH 02/16] Working flow as rig param --- libraries/animation/src/Flow.cpp | 714 ++++++++++++++++++ libraries/animation/src/Flow.h | 315 ++++++++ libraries/animation/src/Rig.cpp | 5 +- libraries/animation/src/Rig.h | 1 + .../src/avatars-renderer/Avatar.cpp | 18 + 5 files changed, 1052 insertions(+), 1 deletion(-) create mode 100644 libraries/animation/src/Flow.cpp create mode 100644 libraries/animation/src/Flow.h diff --git a/libraries/animation/src/Flow.cpp b/libraries/animation/src/Flow.cpp new file mode 100644 index 0000000000..a10d413d90 --- /dev/null +++ b/libraries/animation/src/Flow.cpp @@ -0,0 +1,714 @@ +// +// Flow.cpp +// +// Created by Luis Cuenca on 1/21/2019. +// Copyright 2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Flow.h" +#include "Rig.h" +#include "AnimSkeleton.h" + +FlowCollisionSphere::FlowCollisionSphere(const int& jointIndex, const FlowCollisionSettings& settings) { + _jointIndex = jointIndex; + _radius = _initialRadius = settings._radius; + _offset = _initialOffset = settings._offset; + _entityID = settings._entityID; +} + +FlowCollisionResult FlowCollisionSphere::computeSphereCollision(const glm::vec3& point, float radius) const { + FlowCollisionResult result; + auto centerToJoint = point - _position; + result._distance = glm::length(centerToJoint) - radius; + result._offset = _radius - result._distance; + result._normal = glm::normalize(centerToJoint); + result._radius = _radius; + result._position = _position; + return result; +} + +FlowCollisionResult FlowCollisionSphere::checkSegmentCollision(const glm::vec3& point1, const glm::vec3& point2, const FlowCollisionResult& collisionResult1, const FlowCollisionResult& collisionResult2) { + FlowCollisionResult result; + auto segment = point2 - point1; + auto segmentLength = glm::length(segment); + auto maxDistance = glm::sqrt(glm::pow(collisionResult1._radius, 2) + glm::pow(segmentLength, 2)); + if (collisionResult1._distance < maxDistance && collisionResult2._distance < maxDistance) { + float segmentPercentage = collisionResult1._distance / (collisionResult1._distance + collisionResult2._distance); + glm::vec3 collisionPoint = point1 + segment * segmentPercentage; + glm::vec3 centerToSegment = collisionPoint - _position; + float distance = glm::length(centerToSegment); + if (distance < _radius) { + result._offset = _radius - distance; + result._position = _position; + result._radius = _radius; + result._normal = glm::normalize(centerToSegment); + result._distance = distance; + } + } + return result; +} + +void FlowCollisionSphere::update() { + // TODO + // Fill this +} + +void FlowCollisionSystem::addCollisionSphere(int jointIndex, const FlowCollisionSettings& settings) { + _collisionSpheres.push_back(FlowCollisionSphere(jointIndex, settings)); +}; + +void FlowCollisionSystem::addCollisionShape(int jointIndex, const FlowCollisionSettings& settings) { + auto name = JOINT_COLLISION_PREFIX + jointIndex; + switch (settings._type) { + case FlowCollisionType::CollisionSphere: + addCollisionSphere(jointIndex, settings); + break; + default: + break; + } +}; + +bool FlowCollisionSystem::addCollisionToJoint(int jointIndex) { + if (_collisionSpheres.size() >= COLLISION_SHAPES_LIMIT) { + return false; + } + int collisionIndex = findCollisionWithJoint(jointIndex); + if (collisionIndex == -1) { + addCollisionShape(jointIndex, FlowCollisionSettings()); + return true; + } + else { + return false; + } +}; + +void FlowCollisionSystem::removeCollisionFromJoint(int jointIndex) { + int collisionIndex = findCollisionWithJoint(jointIndex); + if (collisionIndex > -1) { + _collisionSpheres.erase(_collisionSpheres.begin() + collisionIndex); + } +}; + +void FlowCollisionSystem::update() { + for (size_t i = 0; i < _collisionSpheres.size(); i++) { + _collisionSpheres[i].update(); + } +}; + +FlowCollisionResult FlowCollisionSystem::computeCollision(const std::vector collisions) { + FlowCollisionResult result; + if (collisions.size() > 1) { + for (size_t i = 0; i < collisions.size(); i++) { + result._offset += collisions[i]._offset; + result._normal = result._normal + collisions[i]._normal * collisions[i]._distance; + result._position = result._position + collisions[i]._position; + result._radius += collisions[i]._radius; + result._distance += collisions[i]._distance; + } + result._offset = result._offset / collisions.size(); + result._radius = 0.5f * glm::length(result._normal); + result._normal = glm::normalize(result._normal); + result._position = result._position / (float)collisions.size(); + result._distance = result._distance / collisions.size(); + } + else if (collisions.size() == 1) { + result = collisions[0]; + } + result._count = (int)collisions.size(); + return result; +}; + +void FlowCollisionSystem::setScale(float scale) { + _scale = scale; + for (size_t j = 0; j < _collisionSpheres.size(); j++) { + _collisionSpheres[j]._radius = _collisionSpheres[j]._initialRadius * scale; + _collisionSpheres[j]._offset = _collisionSpheres[j]._initialOffset * scale; + } +}; + +std::vector FlowCollisionSystem::checkFlowThreadCollisions(FlowThread* flowThread, bool checkSegments) { + std::vector> FlowThreadResults; + FlowThreadResults.resize(flowThread->_joints.size()); + for (size_t j = 0; j < _collisionSpheres.size(); j++) { + FlowCollisionSphere &sphere = _collisionSpheres[j]; + FlowCollisionResult rootCollision = sphere.computeSphereCollision(flowThread->_positions[0], flowThread->_radius); + std::vector collisionData = { rootCollision }; + bool tooFar = rootCollision._distance >(flowThread->_length + rootCollision._radius); + FlowCollisionResult nextCollision; + if (!tooFar) { + if (checkSegments) { + for (size_t i = 1; i < flowThread->_joints.size(); i++) { + auto prevCollision = collisionData[i - 1]; + nextCollision = _collisionSpheres[j].computeSphereCollision(flowThread->_positions[i], flowThread->_radius); + collisionData.push_back(nextCollision); + if (prevCollision._offset > 0.0f) { + if (i == 1) { + FlowThreadResults[i - 1].push_back(prevCollision); + } + } + else if (nextCollision._offset > 0.0f) { + FlowThreadResults[i].push_back(nextCollision); + } + else { + FlowCollisionResult segmentCollision = _collisionSpheres[j].checkSegmentCollision(flowThread->_positions[i - 1], flowThread->_positions[i], prevCollision, nextCollision); + if (segmentCollision._offset > 0) { + FlowThreadResults[i - 1].push_back(segmentCollision); + FlowThreadResults[i].push_back(segmentCollision); + } + } + } + } + else { + if (rootCollision._offset > 0.0f) { + FlowThreadResults[0].push_back(rootCollision); + } + for (size_t i = 1; i < flowThread->_joints.size(); i++) { + nextCollision = _collisionSpheres[j].computeSphereCollision(flowThread->_positions[i], flowThread->_radius); + if (nextCollision._offset > 0.0f) { + FlowThreadResults[i].push_back(nextCollision); + } + } + } + } + } + + std::vector results; + for (size_t i = 0; i < flowThread->_joints.size(); i++) { + results.push_back(computeCollision(FlowThreadResults[i])); + } + return results; +}; + +int FlowCollisionSystem::findCollisionWithJoint(int jointIndex) { + for (size_t i = 0; i < _collisionSpheres.size(); i++) { + if (_collisionSpheres[i]._jointIndex == jointIndex) { + return (int)i; + } + } + return -1; +}; + +void FlowCollisionSystem::modifyCollisionRadius(int jointIndex, float radius) { + int collisionIndex = findCollisionWithJoint(jointIndex); + if (collisionIndex > -1) { + _collisionSpheres[collisionIndex]._initialRadius = radius; + _collisionSpheres[collisionIndex]._radius = _scale * radius; + } +}; + +void FlowCollisionSystem::modifyCollisionYOffset(int jointIndex, float offset) { + int collisionIndex = findCollisionWithJoint(jointIndex); + if (collisionIndex > -1) { + auto currentOffset = _collisionSpheres[collisionIndex]._offset; + _collisionSpheres[collisionIndex]._initialOffset = glm::vec3(currentOffset.x, offset, currentOffset.z); + _collisionSpheres[collisionIndex]._offset = _collisionSpheres[collisionIndex]._initialOffset * _scale; + } +}; + +void FlowCollisionSystem::modifyCollisionOffset(int jointIndex, const glm::vec3& offset) { + int collisionIndex = findCollisionWithJoint(jointIndex); + if (collisionIndex > -1) { + _collisionSpheres[collisionIndex]._initialOffset = offset; + _collisionSpheres[collisionIndex]._offset = _collisionSpheres[collisionIndex]._initialOffset * _scale; + } +}; + +void FlowNode::update(const glm::vec3& accelerationOffset) { + _acceleration = glm::vec3(0.0f, _settings._gravity, 0.0f); + _previousVelocity = _currentVelocity; + _currentVelocity = _currentPosition - _previousPosition; + _previousPosition = _currentPosition; + if (!_anchored) { + // Add inertia + auto deltaVelocity = _previousVelocity - _currentVelocity; + auto centrifugeVector = glm::length(deltaVelocity) != 0.0f ? glm::normalize(deltaVelocity) : glm::vec3(); + _acceleration = _acceleration + centrifugeVector * _settings._inertia * glm::length(_currentVelocity); + + // Add offset + _acceleration += accelerationOffset; + // Calculate new position + _currentPosition = (_currentPosition + _currentVelocity * _settings._damping) + + (_acceleration * glm::pow(_settings._delta * _scale, 2)); + } + else { + _acceleration = glm::vec3(0.0f); + _currentVelocity = glm::vec3(0.0f); + } +}; + + +void FlowNode::solve(const glm::vec3& constrainPoint, float maxDistance, const FlowCollisionResult& collision) { + solveConstraints(constrainPoint, maxDistance); + solveCollisions(collision); +}; + +void FlowNode::solveConstraints(const glm::vec3& constrainPoint, float maxDistance) { + glm::vec3 constrainVector = _currentPosition - constrainPoint; + float difference = maxDistance / glm::length(constrainVector); + _currentPosition = difference < 1.0 ? constrainPoint + constrainVector * difference : _currentPosition; +}; + +void FlowNode::solveCollisions(const FlowCollisionResult& collision) { + _colliding = collision._offset > 0.0f; + _collision = collision; + if (_colliding) { + _currentPosition = _currentPosition + collision._normal * collision._offset; + _previousCollision = collision; + } + else { + _previousCollision = FlowCollisionResult(); + } +}; + +void FlowNode::apply(const QString& name, bool forceRendering) { + // TODO + // Render here ?? + /* + jointDebug.setDebugSphere(name, self.currentPosition, 2 * self.radius, { red: self.collision && self.collision.collisionCount > 1 ? 0 : 255, + green : self.colliding ? 0 : 255, + blue : 0 }, forceRendering); + */ +}; + +FlowJoint::FlowJoint(int jointIndex, int parentIndex, int childIndex, const QString& name, const QString& group, float scale, const FlowPhysicsSettings& settings) { + _index = jointIndex; + _name = name; + _group = group; + _scale = scale; + _childIndex = childIndex; + _parentIndex = parentIndex; + _node = FlowNode(glm::vec3(), settings); +}; + +void FlowJoint::setInitialData(const glm::vec3& initialPosition, const glm::vec3& initialTranslation, const glm::quat& initialRotation, const glm::vec3& parentPosition) { + _initialPosition = initialPosition; + _node._initialPosition = initialPosition; + _node._previousPosition = initialPosition; + _node._currentPosition = initialPosition; + _initialTranslation = initialTranslation; + _initialRotation = initialRotation; + _translationDirection = glm::normalize(_initialTranslation); + _parentPosition = parentPosition; + _length = glm::length(_initialPosition - parentPosition); + _originalLength = _length / _scale; +} + +void FlowJoint::setUpdatedData(const glm::vec3& updatedPosition, const glm::vec3& updatedTranslation, const glm::quat& updatedRotation, const glm::vec3& parentPosition, const glm::quat& parentWorldRotation) { + _updatedPosition = updatedPosition; + _updatedRotation = updatedRotation; + _updatedTranslation = updatedTranslation; + _parentPosition = parentPosition; + _parentWorldRotation = parentWorldRotation; +} + +void FlowJoint::setRecoveryPosition(const glm::vec3& recoveryPosition) { + _recoveryPosition = recoveryPosition; + _applyRecovery = true; +} + +void FlowJoint::update() { + 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); + } + _node.update(accelerationOffset); + if (_node._anchored) { + if (!_isDummy) { + _node._currentPosition = _updatedPosition; + } else { + _node._currentPosition = _parentPosition; + } + } +}; + +void FlowJoint::solve(const FlowCollisionResult& collision) { + _node.solve(_parentPosition, _length, collision); +}; + +FlowDummyJoint::FlowDummyJoint(const glm::vec3& initialPosition, int index, int parentIndex, int childIndex, float scale, FlowPhysicsSettings settings) : + FlowJoint(index, parentIndex, childIndex, DUMMY_KEYWORD + "_" + index, DUMMY_KEYWORD, scale, settings) { + _isDummy = true; + _initialPosition = initialPosition; + _node = FlowNode(_initialPosition, settings); + _length = DUMMY_JOINT_DISTANCE; +} + + +FlowThread::FlowThread(int rootIndex, std::map* joints) { + _jointsPointer = joints; + computeFlowThread(rootIndex); +} + +void FlowThread::resetLength() { + _length = 0.0f; + for (size_t i = 1; i < _joints.size(); i++) { + int index = _joints[i]; + _length += (*_jointsPointer)[index]._length; + } +} + +void FlowThread::computeFlowThread(int rootIndex) { + int parentIndex = rootIndex; + if (_jointsPointer->size() == 0) { + return; + } + int childIndex = (*_jointsPointer)[parentIndex]._childIndex; + std::vector indexes = { parentIndex }; + for (size_t i = 0; i < _jointsPointer->size(); i++) { + if (childIndex > -1) { + indexes.push_back(childIndex); + childIndex = (*_jointsPointer)[childIndex]._childIndex; + } else { + break; + } + } + for (size_t i = 0; i < indexes.size(); i++) { + int index = indexes[i]; + _joints.push_back(index); + if (i > 0) { + _length += (*_jointsPointer)[index]._length; + } + } +}; + +void FlowThread::computeRecovery() { + int parentIndex = _joints[0]; + auto parentJoint = (*_jointsPointer)[parentIndex]; + (*_jointsPointer)[parentIndex]._recoveryPosition = parentJoint._recoveryPosition = parentJoint._node._currentPosition; + glm::quat parentRotation = parentJoint._parentWorldRotation * parentJoint._initialRotation; + for (size_t i = 1; i < _joints.size(); i++) { + auto joint = (*_jointsPointer)[_joints[i]]; + glm::quat rotation = i == 1 ? parentRotation : rotation * parentJoint._initialRotation; + (*_jointsPointer)[_joints[i]]._recoveryPosition = joint._recoveryPosition = parentJoint._recoveryPosition + (rotation * (joint._initialTranslation * 0.01f)); + parentJoint = joint; + } +}; + +void FlowThread::update() { + if (getActive()) { + _positions.clear(); + _radius = (*_jointsPointer)[_joints[0]]._node._settings._radius; + computeRecovery(); + for (size_t i = 0; i < _joints.size(); i++) { + auto &joint = (*_jointsPointer)[_joints[i]]; + joint.update(); + _positions.push_back(joint._node._currentPosition); + } + } +}; + +void FlowThread::solve(bool useCollisions, FlowCollisionSystem& collisionSystem) { + if (getActive()) { + if (useCollisions) { + auto bodyCollisions = collisionSystem.checkFlowThreadCollisions(this, false); + int handTouchedJoint = -1; + for (size_t i = 0; i < _joints.size(); i++) { + int index = _joints[i]; + if (bodyCollisions[i]._offset > 0.0f) { + (*_jointsPointer)[index].solve(bodyCollisions[i]); + } else { + (*_jointsPointer)[index].solve(FlowCollisionResult()); + } + } + } else { + for (size_t i = 0; i < _joints.size(); i++) { + int index = _joints[i]; + (*_jointsPointer)[index].solve(FlowCollisionResult()); + } + } + } +}; + +void FlowThread::computeJointRotations() { + + auto pos0 = _rootFramePositions[0]; + auto pos1 = _rootFramePositions[1]; + + auto joint0 = (*_jointsPointer)[_joints[0]]; + auto joint1 = (*_jointsPointer)[_joints[1]]; + + auto initial_pos1 = pos0 + (joint0._initialRotation * (joint1._initialTranslation * 0.01f)); + + auto vec0 = initial_pos1 - pos0; + auto vec1 = pos1 - pos0; + + auto delta = rotationBetween(vec0, vec1); + + joint0._currentRotation = (*_jointsPointer)[_joints[0]]._currentRotation = delta * joint0._initialRotation; + + for (size_t i = 1; i < _joints.size() - 1; i++) { + auto nextJoint = (*_jointsPointer)[_joints[i + 1]]; + for (size_t j = i; j < _joints.size(); j++) { + _rootFramePositions[j] = glm::inverse(joint0._currentRotation) * _rootFramePositions[j] - (joint0._initialTranslation * 0.01f); + } + pos0 = _rootFramePositions[i]; + pos1 = _rootFramePositions[i + 1]; + initial_pos1 = pos0 + joint1._initialRotation * (nextJoint._initialTranslation * 0.01f); + + vec0 = initial_pos1 - pos0; + vec1 = pos1 - pos0; + + delta = rotationBetween(vec0, vec1); + + joint1._currentRotation = (*_jointsPointer)[joint1._index]._currentRotation = delta * joint1._initialRotation; + joint0 = joint1; + joint1 = nextJoint; + } +}; + +void FlowThread::apply() { + if (!getActive()) { + return; + } + computeJointRotations(); +}; + +bool FlowThread::getActive() { + return (*_jointsPointer)[_joints[0]]._node._active; +}; + +void Flow::setRig(Rig* rig) { + _rig = rig; +}; + +void Flow::calculateConstraints() { + cleanUp(); + if (!_rig) { + return; + } + int rightHandIndex = -1; + auto flowPrefix = FLOW_JOINT_PREFIX.toUpper(); + auto simPrefix = SIM_JOINT_PREFIX.toUpper(); + auto skeleton = _rig->getAnimSkeleton(); + if (skeleton) { + for (int i = 0; i < skeleton->getNumJoints(); i++) { + auto name = skeleton->getJointName(i); + if (name == "RightHand") { + rightHandIndex = i; + } + auto parentIndex = skeleton->getParentIndex(i); + if (parentIndex == -1) { + continue; + } + auto jointChildren = skeleton->getChildrenOfJoint(i); + // auto childIndex = jointChildren.size() > 0 ? jointChildren[0] : -1; + auto group = QStringRef(&name, 0, 3).toString().toUpper(); + auto split = name.split("_"); + bool isSimJoint = (group == simPrefix); + bool isFlowJoint = split.size() > 2 && split[0].toUpper() == flowPrefix; + if (isFlowJoint || isSimJoint) { + group = ""; + if (isSimJoint) { + qDebug() << "FLOW is sim: " << name; + for (size_t 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(); + break; + } + } + if (group.isEmpty()) { + group = QStringRef(&name, simPrefix.size(), name.size() - 1).toString(); + } + } else { + group = split[1]; + } + if (!group.isEmpty()) { + _flowJointKeywords.push_back(group); + FlowPhysicsSettings jointSettings; + if (PRESET_FLOW_DATA.find(group) != PRESET_FLOW_DATA.end()) { + jointSettings = PRESET_FLOW_DATA.at(group); + } else { + jointSettings = DEFAULT_JOINT_SETTINGS; + } + if (_flowJointData.find(i) == _flowJointData.end()) { + auto flowJoint = FlowJoint(i, parentIndex, -1, name, group, _scale, jointSettings); + _flowJointData.insert(std::pair(i, flowJoint)); + } + } + } else { + if (PRESET_COLLISION_DATA.find(name) != PRESET_COLLISION_DATA.end()) { + _collisionSystem.addCollisionShape(i, PRESET_COLLISION_DATA.at(name)); + } + } + if (isFlowJoint || isSimJoint) { + auto jointInfo = FlowJointInfo(i, parentIndex, -1, name); + _flowJointInfos.push_back(jointInfo); + } + } + } + + for (auto &jointData : _flowJointData) { + int jointIndex = jointData.first; + glm::vec3 jointPosition, parentPosition, jointTranslation; + glm::quat jointRotation; + _rig->getJointPositionInWorldFrame(jointIndex, jointPosition, _entityPosition, _entityRotation); + _rig->getJointPositionInWorldFrame(jointData.second._parentIndex, parentPosition, _entityPosition, _entityRotation); + _rig->getJointTranslation(jointIndex, jointTranslation); + _rig->getJointRotation(jointIndex, jointRotation); + + jointData.second.setInitialData(jointPosition, jointTranslation, jointRotation, parentPosition); + } + + 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); + } else { + _flowJointData[itr->second._parentIndex]._childIndex = itr->first; + } + } + + for (size_t i = 0; i < roots.size(); i++) { + FlowThread thread = FlowThread(roots[i], &_flowJointData); + // add threads with at least 2 joints + if (thread._joints.size() > 0) { + if (thread._joints.size() == 1) { + int jointIndex = roots[i]; + auto joint = _flowJointData[jointIndex]; + auto jointPosition = joint._updatedPosition; + auto newSettings = FlowPhysicsSettings(joint._node._settings); + newSettings._stiffness = ISOLATED_JOINT_STIFFNESS; + int extraIndex = (int)_flowJointData.size(); + auto newJoint = FlowDummyJoint(jointPosition, extraIndex, jointIndex, -1, _scale, newSettings); + newJoint._isDummy = false; + newJoint._length = ISOLATED_JOINT_LENGTH; + newJoint._childIndex = extraIndex; + newJoint._group = _flowJointData[jointIndex]._group; + thread = FlowThread(jointIndex, &_flowJointData); + } + _jointThreads.push_back(thread); + } + } + + if (_jointThreads.size() == 0) { + _rig->clearJointStates(); + } + + + if (SHOW_DUMMY_JOINTS && rightHandIndex > -1) { + int jointCount = (int)_flowJointData.size(); + int extraIndex = (int)_flowJointData.size(); + glm::vec3 rightHandPosition; + _rig->getJointPositionInWorldFrame(rightHandIndex, rightHandPosition, _entityPosition, _entityRotation); + int parentIndex = rightHandIndex; + for (int i = 0; i < DUMMY_JOINT_COUNT; i++) { + int childIndex = (i == (DUMMY_JOINT_COUNT - 1)) ? -1 : extraIndex + 1; + auto newJoint = FlowDummyJoint(rightHandPosition, extraIndex, parentIndex, childIndex, _scale, DEFAULT_JOINT_SETTINGS); + _flowJointData.insert(std::pair(extraIndex, newJoint)); + parentIndex = extraIndex; + extraIndex++; + } + _flowJointData[jointCount]._node._anchored = true; + + auto extraThread = FlowThread(jointCount, &_flowJointData); + _jointThreads.push_back(extraThread); + } + _initialized = _jointThreads.size() > 0; +} + +void Flow::cleanUp() { + _flowJointData.clear(); + _jointThreads.clear(); + _flowJointKeywords.clear(); + _flowJointInfos.clear(); + } + +void Flow::setTransform(float scale, const glm::vec3& position, const glm::quat& rotation) { + _scale = scale; + for (auto &joint : _flowJointData) { + joint.second._scale = scale; + joint.second._node._scale = scale; + } + _entityPosition = position; + _entityRotation = rotation; + _active = true; +} + +void Flow::update() { + _timer.start(); + if (_initialized && _active) { + updateJoints(); + if (USE_COLLISIONS) { + _collisionSystem.update(); + } + int count = 0; + for (auto &thread : _jointThreads) { + thread.update(); + thread.solve(USE_COLLISIONS, _collisionSystem); + if (!updateRootFramePositions(count++)) { + return; + } + thread.apply(); + } + setJoints(); + } + _elapsedTime = ((1.0 - _tau) * _elapsedTime + _tau * _timer.nsecsElapsed()); + _deltaTime += _elapsedTime; + if (_deltaTime > _deltaTimeLimit) { + qDebug() << "Flow C++ update" << _elapsedTime; + _deltaTime = 0.0; + } + +} + +bool Flow::worldToJointPoint(const glm::vec3& position, const int jointIndex, glm::vec3& jointSpacePosition) const { + glm::vec3 jointPos; + glm::quat jointRot; + if (_rig->getJointPositionInWorldFrame(jointIndex, jointPos, _entityPosition, _entityRotation) && _rig->getJointRotationInWorldFrame(jointIndex, jointRot, _entityRotation)) { + glm::vec3 modelOffset = position - jointPos; + jointSpacePosition = glm::inverse(jointRot) * modelOffset; + return true; + } + return false; +} + +bool Flow::updateRootFramePositions(int threadIndex) { + auto &joints = _jointThreads[threadIndex]._joints; + int rootIndex = _flowJointData[joints[0]]._parentIndex; + _jointThreads[threadIndex]._rootFramePositions.clear(); + for (size_t j = 0; j < joints.size(); j++) { + glm::vec3 jointPos; + if (worldToJointPoint(_flowJointData[joints[j]]._node._currentPosition, rootIndex, jointPos)) { + _jointThreads[threadIndex]._rootFramePositions.push_back(jointPos); + } else { + return false; + } + } + return true; +} + +void Flow::updateJoints() { + for (auto &jointData : _flowJointData) { + int jointIndex = jointData.first; + glm::vec3 jointPosition, parentPosition, jointTranslation; + glm::quat jointRotation, parentWorldRotation; + _rig->getJointPositionInWorldFrame(jointIndex, jointPosition, _entityPosition, _entityRotation); + _rig->getJointPositionInWorldFrame(jointData.second._parentIndex, parentPosition, _entityPosition, _entityRotation); + _rig->getJointTranslation(jointIndex, jointTranslation); + _rig->getJointRotation(jointIndex, jointRotation); + _rig->getJointRotationInWorldFrame(jointData.second._parentIndex, parentWorldRotation, _entityRotation); + jointData.second.setUpdatedData(jointPosition, jointTranslation, jointRotation, parentPosition, parentWorldRotation); + } + auto &collisions = _collisionSystem.getCollisions(); + for (auto &collision : collisions) { + _rig->getJointPositionInWorldFrame(collision._jointIndex, collision._position, _entityPosition, _entityRotation); + } +} + +void Flow::setJoints() { + for (auto &thread : _jointThreads) { + auto &joints = thread._joints; + for (int jointIndex : joints) { + auto &joint = _flowJointData[jointIndex]; + _rig->setJointRotation(jointIndex, true, joint._currentRotation, 2.0f); + } + } +} diff --git a/libraries/animation/src/Flow.h b/libraries/animation/src/Flow.h new file mode 100644 index 0000000000..c93cf91673 --- /dev/null +++ b/libraries/animation/src/Flow.h @@ -0,0 +1,315 @@ +// +// Flow.h +// +// Created by Luis Cuenca on 1/21/2019. +// Copyright 2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_Flow_h +#define hifi_Flow_h + +#include +#include +#include +#include +#include +#include +#include + +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; + +const float HAPTIC_TOUCH_STRENGTH = 0.25f; +const float HAPTIC_TOUCH_DURATION = 10.0f; +const float HAPTIC_SLOPE = 0.18f; +const float HAPTIC_THRESHOLD = 40.0f; + +const QString FLOW_JOINT_PREFIX = "flow"; +const QString SIM_JOINT_PREFIX = "sim"; + +const QString JOINT_COLLISION_PREFIX = "joint_"; +const QString HAND_COLLISION_PREFIX = "hand_"; +const float HAND_COLLISION_RADIUS = 0.03f; +const float HAND_TOUCHING_DISTANCE = 2.0f; + +const int COLLISION_SHAPES_LIMIT = 4; + +const QString DUMMY_KEYWORD = "Extra"; +const int DUMMY_JOINT_COUNT = 8; +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_GRAVITY = -0.0096f; +const float DEFAULT_DAMPING = 0.85f; +const float DEFAULT_INERTIA = 0.8f; +const float DEFAULT_DELTA = 0.55f; +const float DEFAULT_RADIUS = 0.01f; + +struct FlowPhysicsSettings { + FlowPhysicsSettings() {}; + FlowPhysicsSettings(bool active, float stiffness, float gravity, float damping, float inertia, float delta, float radius) { + _active = active; + _stiffness = stiffness; + _gravity = gravity; + _damping = damping; + _inertia = inertia; + _delta = delta; + _radius = radius; + } + bool _active{ true }; + float _stiffness{ 0.0f }; + float _gravity{ DEFAULT_GRAVITY }; + float _damping{ DEFAULT_DAMPING }; + float _inertia{ DEFAULT_INERTIA }; + float _delta{ DEFAULT_DELTA }; + float _radius{ DEFAULT_RADIUS }; +}; + +enum FlowCollisionType { + CollisionSphere = 0 +}; + +struct FlowCollisionSettings { + FlowCollisionSettings() {}; + FlowCollisionSettings(const QUuid& id, const FlowCollisionType& type, const glm::vec3& offset, float radius) { + _entityID = id; + _type = type; + _offset = offset; + _radius = radius; + }; + QUuid _entityID; + FlowCollisionType _type { FlowCollisionType::CollisionSphere }; + float _radius { 0.05f }; + glm::vec3 _offset; +}; + +const FlowPhysicsSettings DEFAULT_JOINT_SETTINGS; + +const std::map PRESET_FLOW_DATA = { {"hair", FlowPhysicsSettings()}, + {"skirt", FlowPhysicsSettings(true, 1.0f, DEFAULT_GRAVITY, 0.65f, 0.8f, 0.45f, 0.01f)}, + {"breast", FlowPhysicsSettings(true, 1.0f, DEFAULT_GRAVITY, 0.65f, 0.8f, 0.45f, 0.01f)} }; + +const std::map PRESET_COLLISION_DATA = { + { "Head", FlowCollisionSettings(QUuid(), FlowCollisionType::CollisionSphere, glm::vec3(0.0f, 0.06f, 0.0f), 0.08f)}, + { "LeftArm", FlowCollisionSettings(QUuid(), FlowCollisionType::CollisionSphere, glm::vec3(0.0f, 0.02f, 0.0f), 0.05f) }, + { "Head", FlowCollisionSettings(QUuid(), FlowCollisionType::CollisionSphere, glm::vec3(0.0f, 0.04f, 0.0f), 0.0f) } +}; + +const std::vector HAND_COLLISION_JOINTS = { "RightHandMiddle1", "RightHandThumb3", "LeftHandMiddle1", "LeftHandThumb3", "RightHandMiddle3", "LeftHandMiddle3" }; + +struct FlowJointInfo { + FlowJointInfo() {}; + FlowJointInfo(int index, int parentIndex, int childIndex, const QString& name) { + _index = index; + _parentIndex = parentIndex; + _childIndex = childIndex; + _name = name; + } + int _index { -1 }; + QString _name; + int _parentIndex { -1 }; + int _childIndex { -1 }; +}; + +struct FlowCollisionResult { + int _count { 0 }; + float _offset { 0.0f }; + glm::vec3 _position; + float _radius { 0.0f }; + glm::vec3 _normal; + float _distance { 0.0f }; +}; + +class FlowCollisionSphere { +public: + FlowCollisionSphere() {}; + FlowCollisionSphere(const int& jointIndex, const FlowCollisionSettings& settings); + void setPosition(const glm::vec3& position) { _position = position; } + FlowCollisionResult computeSphereCollision(const glm::vec3& point, float radius) const; + FlowCollisionResult checkSegmentCollision(const glm::vec3& point1, const glm::vec3& point2, const FlowCollisionResult& collisionResult1, const FlowCollisionResult& collisionResult2); + void update(); + + QUuid _entityID; + int _jointIndex { -1 }; + float _radius { 0.0f }; + float _initialRadius{ 0.0f }; + glm::vec3 _offset; + glm::vec3 _initialOffset; + glm::vec3 _position; +}; + +class FlowThread; + +class FlowCollisionSystem { +public: + FlowCollisionSystem() {}; + void addCollisionSphere(int jointIndex, const FlowCollisionSettings& settings); + void addCollisionShape(int jointIndex, const FlowCollisionSettings& settings); + bool addCollisionToJoint(int jointIndex); + void removeCollisionFromJoint(int jointIndex); + void update(); + FlowCollisionResult computeCollision(const std::vector collisions); + void setScale(float scale); + + std::vector checkFlowThreadCollisions(FlowThread* flowThread, bool checkSegments); + + int findCollisionWithJoint(int jointIndex); + void modifyCollisionRadius(int jointIndex, float radius); + void modifyCollisionYOffset(int jointIndex, float offset); + void modifyCollisionOffset(int jointIndex, const glm::vec3& offset); + + std::vector& getCollisions() { return _collisionSpheres; }; +private: + std::vector _collisionSpheres; + float _scale{ 1.0f }; +}; + +class FlowNode { +public: + FlowNode() {}; + FlowNode(const glm::vec3& initialPosition, FlowPhysicsSettings settings) : + _initialPosition(initialPosition), _previousPosition(initialPosition), _currentPosition(initialPosition){}; + + FlowPhysicsSettings _settings; + glm::vec3 _initialPosition; + glm::vec3 _previousPosition; + glm::vec3 _currentPosition; + + glm::vec3 _currentVelocity; + glm::vec3 _previousVelocity; + glm::vec3 _acceleration; + + FlowCollisionResult _collision; + FlowCollisionResult _previousCollision; + + float _initialRadius { 0.0f }; + float _scale{ 1.0f }; + + bool _anchored { false }; + bool _colliding { false }; + bool _active { true }; + + void update(const glm::vec3& accelerationOffset); + void solve(const glm::vec3& constrainPoint, float maxDistance, const FlowCollisionResult& collision); + void solveConstraints(const glm::vec3& constrainPoint, float maxDistance); + void solveCollisions(const FlowCollisionResult& collision); + void apply(const QString& name, bool forceRendering); +}; + +class FlowJoint { +public: + FlowJoint() {}; + FlowJoint(int jointIndex, int parentIndex, int childIndex, const QString& name, const QString& group, float scale, const FlowPhysicsSettings& settings); + void setInitialData(const glm::vec3& initialPosition, const glm::vec3& initialTranslation, const glm::quat& initialRotation, const glm::vec3& parentPosition); + void setUpdatedData(const glm::vec3& updatedPosition, const glm::vec3& updatedTranslation, const glm::quat& updatedRotation, const glm::vec3& parentPosition, const glm::quat& parentWorldRotation); + void setRecoveryPosition(const glm::vec3& recoveryPosition); + void update(); + void solve(const FlowCollisionResult& collision); + + int _index{ -1 }; + int _parentIndex{ -1 }; + int _childIndex{ -1 }; + QString _name; + QString _group; + bool _isDummy{ false }; + glm::vec3 _initialPosition; + glm::vec3 _initialTranslation; + glm::quat _initialRotation; + + glm::vec3 _updatedPosition; + glm::vec3 _updatedTranslation; + glm::quat _updatedRotation; + + glm::quat _currentRotation; + glm::vec3 _recoveryPosition; + + glm::vec3 _parentPosition; + glm::quat _parentWorldRotation; + + FlowNode _node; + glm::vec3 _translationDirection; + float _scale { 1.0f }; + float _length { 0.0f }; + float _originalLength { 0.0f }; + bool _applyRecovery { false }; +}; + +class FlowDummyJoint : public FlowJoint { +public: + FlowDummyJoint(const glm::vec3& initialPosition, int index, int parentIndex, int childIndex, float scale, FlowPhysicsSettings settings); +}; + + +class FlowThread { +public: + FlowThread() {}; + FlowThread(int rootIndex, std::map* joints); + + void resetLength(); + void computeFlowThread(int rootIndex); + void computeRecovery(); + void update(); + void solve(bool useCollisions, FlowCollisionSystem& collisionSystem); + void computeJointRotations(); + void apply(); + bool getActive(); + void setRootFramePositions(const std::vector& rootFramePositions) { _rootFramePositions = rootFramePositions; }; + + std::vector _joints; + std::vector _positions; + float _radius{ 0.0f }; + float _length{ 0.0f }; + std::map* _jointsPointer; + std::vector _rootFramePositions; + +}; + +class Flow { +public: + Flow() {}; + void setRig(Rig* rig); + void calculateConstraints(); + void update(); + void setTransform(float scale, const glm::vec3& position, const glm::quat& rotation); + const std::map& getJoints() const { return _flowJointData; } + const std::vector& getThreads() const { return _jointThreads; } +private: + void setJoints(); + void cleanUp(); + void updateJoints(); + bool updateRootFramePositions(int threadIndex); + bool worldToJointPoint(const glm::vec3& position, const int jointIndex, glm::vec3& jointSpacePosition) const; + Rig* _rig; + float _scale { 1.0f }; + glm::vec3 _entityPosition; + glm::quat _entityRotation; + std::map _flowJointData; + std::vector _jointThreads; + std::vector _flowJointKeywords; + std::vector _flowJointInfos; + FlowCollisionSystem _collisionSystem; + bool _initialized { false }; + bool _active { false }; + int _deltaTime{ 0 }; + int _deltaTimeLimit{ 4000 }; + int _elapsedTime{ 0 }; + float _tau = 0.1f; + QElapsedTimer _timer; +}; + +#endif // hifi_Flow_h diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 8a05bdd018..5042c00be6 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -748,7 +748,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos glm::vec3 forward = worldRotation * IDENTITY_FORWARD; glm::vec3 workingVelocity = worldVelocity; - + _flow.setTransform(sensorToWorldScale, worldPosition, worldRotation * Quaternions::Y_180); { glm::vec3 localVel = glm::inverse(worldRotation) * workingVelocity; @@ -1212,12 +1212,15 @@ void Rig::updateAnimations(float deltaTime, const glm::mat4& rootTransform, cons _networkVars = networkTriggersOut; _lastContext = context; } + applyOverridePoses(); buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses); buildAbsoluteRigPoses(_networkPoseSet._relativePoses, _networkPoseSet._absolutePoses); // copy internal poses to external poses + _flow.update(); { QWriteLocker writeLock(&_externalPoseSetLock); + _externalPoseSet = _internalPoseSet; } } diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 9bd2ed528a..50d13d348e 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -235,6 +235,7 @@ public: const AnimVariantMap& getAnimVars() const { return _lastAnimVars; } const AnimContext::DebugStateMachineMap& getStateMachineMap() const { return _lastContext.getStateMachineMap(); } void computeFlowSkeleton() { _flow.calculateConstraints(); } + const Flow& getFlow() const { return _flow; } signals: void onLoadComplete(); diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 07c1ca9a32..223813eecb 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -722,6 +722,24 @@ void Avatar::postUpdate(float deltaTime, const render::ScenePointer& scene) { DebugDraw::getInstance().drawRay(rightEyePosition, rightEyePosition + rightEyeRotation * Vectors::UNIT_Z * EYE_RAY_LENGTH, RED); } } + const bool DEBUG_FLOW = true; + if (_skeletonModel->isLoaded() && DEBUG_FLOW) { + auto flow = _skeletonModel->getRig().getFlow(); + auto joints = flow.getJoints(); + auto threads = flow.getThreads(); + for (auto &thread : threads) { + auto& jointIndexes = thread._joints; + for (size_t i = 1; i < jointIndexes.size(); i++) { + auto index1 = jointIndexes[i - 1]; + auto index2 = jointIndexes[i]; + // glm::vec3 pos1 = joint.second._node._currentPosition; + // glm::vec3 pos2 = joints.find(joint.second._parentIndex) != joints.end() ? joints[joint.second._parentIndex]._node._currentPosition : getJointPosition(joint.second._parentIndex); + // DebugDraw::getInstance().drawRay(pos1, pos2, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); + DebugDraw::getInstance().drawRay(joints[index1]._node._currentPosition, joints[index2]._node._currentPosition, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); + + } + } + } fixupModelsInScene(scene); updateFitBoundingBox(); From 942e9ccdfd4ddf7d920a07f1ce37f9a1ed6ed797 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Mon, 11 Feb 2019 18:21:00 -0700 Subject: [PATCH 03/16] Hand collisions working --- interface/src/avatar/AvatarManager.cpp | 8 + interface/src/avatar/OtherAvatar.cpp | 1 - interface/src/avatar/OtherAvatar.h | 1 + libraries/animation/src/Flow.cpp | 245 ++++++++++++------------- libraries/animation/src/Flow.h | 69 ++++--- libraries/animation/src/Rig.h | 2 +- 6 files changed, 162 insertions(+), 164 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index c9e099df21..50e8546979 100755 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -271,6 +271,14 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { if (avatar->getSkeletonModel()->isLoaded()) { // remove the orb if it is there avatar->removeOrb(); + if (avatar->getWorkloadRegion() == workload::Region::R1) { + auto &flow = _myAvatar->getSkeletonModel()->getRig().getFlow(); + for (auto &handJointName : HAND_COLLISION_JOINTS) { + int jointIndex = avatar->getJointIndex(handJointName); + glm::vec3 position = avatar->getJointPosition(jointIndex); + flow.setOthersCollision(avatar->getID(), jointIndex, position); + } + } if (avatar->needsPhysicsUpdate()) { _avatarsToChangeInPhysics.insert(avatar); } diff --git a/interface/src/avatar/OtherAvatar.cpp b/interface/src/avatar/OtherAvatar.cpp index a3950c8e96..695481b709 100755 --- a/interface/src/avatar/OtherAvatar.cpp +++ b/interface/src/avatar/OtherAvatar.cpp @@ -365,7 +365,6 @@ void OtherAvatar::simulate(float deltaTime, bool inView) { PROFILE_RANGE(simulation, "grabs"); applyGrabChanges(); } - updateFadingStatus(); } diff --git a/interface/src/avatar/OtherAvatar.h b/interface/src/avatar/OtherAvatar.h index 3ecd35413f..6398be9313 100644 --- a/interface/src/avatar/OtherAvatar.h +++ b/interface/src/avatar/OtherAvatar.h @@ -50,6 +50,7 @@ public: void rebuildCollisionShape() override; void setWorkloadRegion(uint8_t region); + uint8_t getWorkloadRegion() { return _workloadRegion; } bool shouldBeInPhysicsSimulation() const; bool needsPhysicsUpdate() const; diff --git a/libraries/animation/src/Flow.cpp b/libraries/animation/src/Flow.cpp index a10d413d90..87d7155abd 100644 --- a/libraries/animation/src/Flow.cpp +++ b/libraries/animation/src/Flow.cpp @@ -12,11 +12,23 @@ #include "Rig.h" #include "AnimSkeleton.h" -FlowCollisionSphere::FlowCollisionSphere(const int& jointIndex, const FlowCollisionSettings& settings) { +const std::map PRESET_FLOW_DATA = { { "hair", FlowPhysicsSettings() }, +{ "skirt", FlowPhysicsSettings(true, 1.0f, DEFAULT_GRAVITY, 0.65f, 0.8f, 0.45f, 0.01f) }, +{ "breast", FlowPhysicsSettings(true, 1.0f, DEFAULT_GRAVITY, 0.65f, 0.8f, 0.45f, 0.01f) } }; + +const std::map PRESET_COLLISION_DATA = { + { "Spine2", FlowCollisionSettings(QUuid(), FlowCollisionType::CollisionSphere, glm::vec3(0.0f, 0.2f, 0.0f), 0.14f) }, + { "LeftArm", FlowCollisionSettings(QUuid(), FlowCollisionType::CollisionSphere, glm::vec3(0.0f, 0.02f, 0.0f), 0.05f) }, + { "RightArm", FlowCollisionSettings(QUuid(), FlowCollisionType::CollisionSphere, glm::vec3(0.0f, 0.02f, 0.0f), 0.05f) }, + { "HeadTop_End", FlowCollisionSettings(QUuid(), FlowCollisionType::CollisionSphere, glm::vec3(0.0f, -0.15f, 0.0f), 0.09f) } +}; + +FlowCollisionSphere::FlowCollisionSphere(const int& jointIndex, const FlowCollisionSettings& settings, bool isTouch) { _jointIndex = jointIndex; _radius = _initialRadius = settings._radius; _offset = _initialOffset = settings._offset; _entityID = settings._entityID; + _isTouch = isTouch; } FlowCollisionResult FlowCollisionSphere::computeSphereCollision(const glm::vec3& point, float radius) const { @@ -51,53 +63,21 @@ FlowCollisionResult FlowCollisionSphere::checkSegmentCollision(const glm::vec3& return result; } -void FlowCollisionSphere::update() { - // TODO - // Fill this +void FlowCollisionSystem::addCollisionSphere(int jointIndex, const FlowCollisionSettings& settings, const glm::vec3& position, bool isSelfCollision, bool isTouch) { + auto collision = FlowCollisionSphere(jointIndex, settings, isTouch); + collision.setPosition(position); + if (isSelfCollision) { + _selfCollisions.push_back(collision); + } else { + _othersCollisions.push_back(collision); + } + +}; +void FlowCollisionSystem::resetCollisions() { + _allCollisions.clear(); + _othersCollisions.clear(); + _selfCollisions.clear(); } - -void FlowCollisionSystem::addCollisionSphere(int jointIndex, const FlowCollisionSettings& settings) { - _collisionSpheres.push_back(FlowCollisionSphere(jointIndex, settings)); -}; - -void FlowCollisionSystem::addCollisionShape(int jointIndex, const FlowCollisionSettings& settings) { - auto name = JOINT_COLLISION_PREFIX + jointIndex; - switch (settings._type) { - case FlowCollisionType::CollisionSphere: - addCollisionSphere(jointIndex, settings); - break; - default: - break; - } -}; - -bool FlowCollisionSystem::addCollisionToJoint(int jointIndex) { - if (_collisionSpheres.size() >= COLLISION_SHAPES_LIMIT) { - return false; - } - int collisionIndex = findCollisionWithJoint(jointIndex); - if (collisionIndex == -1) { - addCollisionShape(jointIndex, FlowCollisionSettings()); - return true; - } - else { - return false; - } -}; - -void FlowCollisionSystem::removeCollisionFromJoint(int jointIndex) { - int collisionIndex = findCollisionWithJoint(jointIndex); - if (collisionIndex > -1) { - _collisionSpheres.erase(_collisionSpheres.begin() + collisionIndex); - } -}; - -void FlowCollisionSystem::update() { - for (size_t i = 0; i < _collisionSpheres.size(); i++) { - _collisionSpheres[i].update(); - } -}; - FlowCollisionResult FlowCollisionSystem::computeCollision(const std::vector collisions) { FlowCollisionResult result; if (collisions.size() > 1) { @@ -123,50 +103,51 @@ FlowCollisionResult FlowCollisionSystem::computeCollision(const std::vector FlowCollisionSystem::checkFlowThreadCollisions(FlowThread* flowThread, bool checkSegments) { +std::vector FlowCollisionSystem::checkFlowThreadCollisions(FlowThread* flowThread) { std::vector> FlowThreadResults; FlowThreadResults.resize(flowThread->_joints.size()); - for (size_t j = 0; j < _collisionSpheres.size(); j++) { - FlowCollisionSphere &sphere = _collisionSpheres[j]; + for (size_t j = 0; j < _allCollisions.size(); j++) { + FlowCollisionSphere &sphere = _allCollisions[j]; FlowCollisionResult rootCollision = sphere.computeSphereCollision(flowThread->_positions[0], flowThread->_radius); std::vector collisionData = { rootCollision }; bool tooFar = rootCollision._distance >(flowThread->_length + rootCollision._radius); FlowCollisionResult nextCollision; if (!tooFar) { - if (checkSegments) { + if (sphere._isTouch) { for (size_t i = 1; i < flowThread->_joints.size(); i++) { auto prevCollision = collisionData[i - 1]; - nextCollision = _collisionSpheres[j].computeSphereCollision(flowThread->_positions[i], flowThread->_radius); + nextCollision = _allCollisions[j].computeSphereCollision(flowThread->_positions[i], flowThread->_radius); collisionData.push_back(nextCollision); + bool isTouching = false; if (prevCollision._offset > 0.0f) { if (i == 1) { FlowThreadResults[i - 1].push_back(prevCollision); + isTouching = true; } - } - else if (nextCollision._offset > 0.0f) { + } else if (nextCollision._offset > 0.0f) { FlowThreadResults[i].push_back(nextCollision); - } - else { - FlowCollisionResult segmentCollision = _collisionSpheres[j].checkSegmentCollision(flowThread->_positions[i - 1], flowThread->_positions[i], prevCollision, nextCollision); + isTouching = true; + } else { + FlowCollisionResult segmentCollision = _allCollisions[j].checkSegmentCollision(flowThread->_positions[i - 1], flowThread->_positions[i], prevCollision, nextCollision); if (segmentCollision._offset > 0) { FlowThreadResults[i - 1].push_back(segmentCollision); FlowThreadResults[i].push_back(segmentCollision); + isTouching = true; } } } - } - else { + } else { if (rootCollision._offset > 0.0f) { FlowThreadResults[0].push_back(rootCollision); } for (size_t i = 1; i < flowThread->_joints.size(); i++) { - nextCollision = _collisionSpheres[j].computeSphereCollision(flowThread->_positions[i], flowThread->_radius); + nextCollision = _allCollisions[j].computeSphereCollision(flowThread->_positions[i], flowThread->_radius); if (nextCollision._offset > 0.0f) { FlowThreadResults[i].push_back(nextCollision); } @@ -182,40 +163,49 @@ std::vector FlowCollisionSystem::checkFlowThreadCollisions( return results; }; -int FlowCollisionSystem::findCollisionWithJoint(int jointIndex) { - for (size_t i = 0; i < _collisionSpheres.size(); i++) { - if (_collisionSpheres[i]._jointIndex == jointIndex) { +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::modifyCollisionRadius(int jointIndex, float radius) { - int collisionIndex = findCollisionWithJoint(jointIndex); +void FlowCollisionSystem::modifySelfCollisionRadius(int jointIndex, float radius) { + int collisionIndex = findSelfCollisionWithJoint(jointIndex); if (collisionIndex > -1) { - _collisionSpheres[collisionIndex]._initialRadius = radius; - _collisionSpheres[collisionIndex]._radius = _scale * radius; + _selfCollisions[collisionIndex]._initialRadius = radius; + _selfCollisions[collisionIndex]._radius = _scale * radius; } }; -void FlowCollisionSystem::modifyCollisionYOffset(int jointIndex, float offset) { - int collisionIndex = findCollisionWithJoint(jointIndex); +void FlowCollisionSystem::modifySelfCollisionYOffset(int jointIndex, float offset) { + int collisionIndex = findSelfCollisionWithJoint(jointIndex); if (collisionIndex > -1) { - auto currentOffset = _collisionSpheres[collisionIndex]._offset; - _collisionSpheres[collisionIndex]._initialOffset = glm::vec3(currentOffset.x, offset, currentOffset.z); - _collisionSpheres[collisionIndex]._offset = _collisionSpheres[collisionIndex]._initialOffset * _scale; + auto currentOffset = _selfCollisions[collisionIndex]._offset; + _selfCollisions[collisionIndex]._initialOffset = glm::vec3(currentOffset.x, offset, currentOffset.z); + _selfCollisions[collisionIndex]._offset = _selfCollisions[collisionIndex]._initialOffset * _scale; } }; -void FlowCollisionSystem::modifyCollisionOffset(int jointIndex, const glm::vec3& offset) { - int collisionIndex = findCollisionWithJoint(jointIndex); +void FlowCollisionSystem::modifySelfCollisionOffset(int jointIndex, const glm::vec3& offset) { + int collisionIndex = findSelfCollisionWithJoint(jointIndex); if (collisionIndex > -1) { - _collisionSpheres[collisionIndex]._initialOffset = offset; - _collisionSpheres[collisionIndex]._offset = _collisionSpheres[collisionIndex]._initialOffset * _scale; + _selfCollisions[collisionIndex]._initialOffset = offset; + _selfCollisions[collisionIndex]._offset = _selfCollisions[collisionIndex]._initialOffset * _scale; } }; + +void FlowCollisionSystem::prepareCollisions() { + _allCollisions.clear(); + _allCollisions.resize(_selfCollisions.size() + _othersCollisions.size()); + std::copy(_selfCollisions.begin(), _selfCollisions.begin() + _selfCollisions.size(), _allCollisions.begin()); + std::copy(_othersCollisions.begin(), _othersCollisions.begin() + _othersCollisions.size(), _allCollisions.begin() + _selfCollisions.size()); + _othersCollisions.clear(); +} + void FlowNode::update(const glm::vec3& accelerationOffset) { _acceleration = glm::vec3(0.0f, _settings._gravity, 0.0f); _previousVelocity = _currentVelocity; @@ -263,16 +253,6 @@ void FlowNode::solveCollisions(const FlowCollisionResult& collision) { } }; -void FlowNode::apply(const QString& name, bool forceRendering) { - // TODO - // Render here ?? - /* - jointDebug.setDebugSphere(name, self.currentPosition, 2 * self.radius, { red: self.collision && self.collision.collisionCount > 1 ? 0 : 255, - green : self.colliding ? 0 : 255, - blue : 0 }, forceRendering); - */ -}; - FlowJoint::FlowJoint(int jointIndex, int parentIndex, int childIndex, const QString& name, const QString& group, float scale, const FlowPhysicsSettings& settings) { _index = jointIndex; _name = name; @@ -347,7 +327,7 @@ void FlowThread::resetLength() { _length = 0.0f; for (size_t i = 1; i < _joints.size(); i++) { int index = _joints[i]; - _length += (*_jointsPointer)[index]._length; + _length += _jointsPointer->at(index)._length; } } @@ -356,12 +336,12 @@ void FlowThread::computeFlowThread(int rootIndex) { if (_jointsPointer->size() == 0) { return; } - int childIndex = (*_jointsPointer)[parentIndex]._childIndex; + int childIndex = _jointsPointer->at(parentIndex)._childIndex; std::vector indexes = { parentIndex }; for (size_t i = 0; i < _jointsPointer->size(); i++) { if (childIndex > -1) { indexes.push_back(childIndex); - childIndex = (*_jointsPointer)[childIndex]._childIndex; + childIndex = _jointsPointer->at(childIndex)._childIndex; } else { break; } @@ -370,20 +350,20 @@ void FlowThread::computeFlowThread(int rootIndex) { int index = indexes[i]; _joints.push_back(index); if (i > 0) { - _length += (*_jointsPointer)[index]._length; + _length += _jointsPointer->at(index)._length; } } }; void FlowThread::computeRecovery() { int parentIndex = _joints[0]; - auto parentJoint = (*_jointsPointer)[parentIndex]; - (*_jointsPointer)[parentIndex]._recoveryPosition = parentJoint._recoveryPosition = parentJoint._node._currentPosition; + auto parentJoint = _jointsPointer->at(parentIndex); + _jointsPointer->at(parentIndex)._recoveryPosition = parentJoint._recoveryPosition = parentJoint._node._currentPosition; glm::quat parentRotation = parentJoint._parentWorldRotation * parentJoint._initialRotation; for (size_t i = 1; i < _joints.size(); i++) { - auto joint = (*_jointsPointer)[_joints[i]]; + auto joint = _jointsPointer->at(_joints[i]); glm::quat rotation = i == 1 ? parentRotation : rotation * parentJoint._initialRotation; - (*_jointsPointer)[_joints[i]]._recoveryPosition = joint._recoveryPosition = parentJoint._recoveryPosition + (rotation * (joint._initialTranslation * 0.01f)); + _jointsPointer->at(_joints[i])._recoveryPosition = joint._recoveryPosition = parentJoint._recoveryPosition + (rotation * (joint._initialTranslation * 0.01f)); parentJoint = joint; } }; @@ -391,10 +371,10 @@ void FlowThread::computeRecovery() { void FlowThread::update() { if (getActive()) { _positions.clear(); - _radius = (*_jointsPointer)[_joints[0]]._node._settings._radius; + _radius = _jointsPointer->at(_joints[0])._node._settings._radius; computeRecovery(); for (size_t i = 0; i < _joints.size(); i++) { - auto &joint = (*_jointsPointer)[_joints[i]]; + auto &joint = _jointsPointer->at(_joints[i]); joint.update(); _positions.push_back(joint._node._currentPosition); } @@ -404,20 +384,16 @@ void FlowThread::update() { void FlowThread::solve(bool useCollisions, FlowCollisionSystem& collisionSystem) { if (getActive()) { if (useCollisions) { - auto bodyCollisions = collisionSystem.checkFlowThreadCollisions(this, false); + auto bodyCollisions = collisionSystem.checkFlowThreadCollisions(this); int handTouchedJoint = -1; for (size_t i = 0; i < _joints.size(); i++) { int index = _joints[i]; - if (bodyCollisions[i]._offset > 0.0f) { - (*_jointsPointer)[index].solve(bodyCollisions[i]); - } else { - (*_jointsPointer)[index].solve(FlowCollisionResult()); - } + _jointsPointer->at(index).solve(bodyCollisions[i]); } } else { for (size_t i = 0; i < _joints.size(); i++) { int index = _joints[i]; - (*_jointsPointer)[index].solve(FlowCollisionResult()); + _jointsPointer->at(index).solve(FlowCollisionResult()); } } } @@ -428,8 +404,8 @@ void FlowThread::computeJointRotations() { auto pos0 = _rootFramePositions[0]; auto pos1 = _rootFramePositions[1]; - auto joint0 = (*_jointsPointer)[_joints[0]]; - auto joint1 = (*_jointsPointer)[_joints[1]]; + auto joint0 = _jointsPointer->at(_joints[0]); + auto joint1 = _jointsPointer->at(_joints[1]); auto initial_pos1 = pos0 + (joint0._initialRotation * (joint1._initialTranslation * 0.01f)); @@ -438,10 +414,10 @@ void FlowThread::computeJointRotations() { auto delta = rotationBetween(vec0, vec1); - joint0._currentRotation = (*_jointsPointer)[_joints[0]]._currentRotation = delta * joint0._initialRotation; + joint0._currentRotation = _jointsPointer->at(_joints[0])._currentRotation = delta * joint0._initialRotation; for (size_t i = 1; i < _joints.size() - 1; i++) { - auto nextJoint = (*_jointsPointer)[_joints[i + 1]]; + auto nextJoint = _jointsPointer->at(_joints[i + 1]); for (size_t j = i; j < _joints.size(); j++) { _rootFramePositions[j] = glm::inverse(joint0._currentRotation) * _rootFramePositions[j] - (joint0._initialTranslation * 0.01f); } @@ -454,7 +430,7 @@ void FlowThread::computeJointRotations() { delta = rotationBetween(vec0, vec1); - joint1._currentRotation = (*_jointsPointer)[joint1._index]._currentRotation = delta * joint1._initialRotation; + joint1._currentRotation = _jointsPointer->at(joint1._index)._currentRotation = delta * joint1._initialRotation; joint0 = joint1; joint1 = nextJoint; } @@ -468,7 +444,7 @@ void FlowThread::apply() { }; bool FlowThread::getActive() { - return (*_jointsPointer)[_joints[0]]._node._active; + return _jointsPointer->at(_joints[0])._node._active; }; void Flow::setRig(Rig* rig) { @@ -484,12 +460,17 @@ void Flow::calculateConstraints() { auto flowPrefix = FLOW_JOINT_PREFIX.toUpper(); auto simPrefix = SIM_JOINT_PREFIX.toUpper(); auto skeleton = _rig->getAnimSkeleton(); + std::vector handsIndices; + _collisionSystem.resetCollisions(); if (skeleton) { for (int i = 0; i < skeleton->getNumJoints(); i++) { auto name = skeleton->getJointName(i); if (name == "RightHand") { rightHandIndex = i; } + if (std::find(HAND_COLLISION_JOINTS.begin(), HAND_COLLISION_JOINTS.end(), name) != HAND_COLLISION_JOINTS.end()) { + handsIndices.push_back(i); + } auto parentIndex = skeleton->getParentIndex(i); if (parentIndex == -1) { continue; @@ -533,7 +514,7 @@ void Flow::calculateConstraints() { } } else { if (PRESET_COLLISION_DATA.find(name) != PRESET_COLLISION_DATA.end()) { - _collisionSystem.addCollisionShape(i, PRESET_COLLISION_DATA.at(name)); + _collisionSystem.addCollisionSphere(i, PRESET_COLLISION_DATA.at(name)); } } if (isFlowJoint || isSimJoint) { @@ -591,8 +572,6 @@ void Flow::calculateConstraints() { if (_jointThreads.size() == 0) { _rig->clearJointStates(); } - - if (SHOW_DUMMY_JOINTS && rightHandIndex > -1) { int jointCount = (int)_flowJointData.size(); int extraIndex = (int)_flowJointData.size(); @@ -611,6 +590,13 @@ void Flow::calculateConstraints() { auto extraThread = FlowThread(jointCount, &_flowJointData); _jointThreads.push_back(extraThread); } + if (handsIndices.size() > 0) { + FlowCollisionSettings handSettings; + handSettings._radius = HAND_COLLISION_RADIUS; + for (size_t i = 0; i < handsIndices.size(); i++) { + _collisionSystem.addCollisionSphere(handsIndices[i], handSettings, glm::vec3(), true, true); + } + } _initialized = _jointThreads.size() > 0; } @@ -633,12 +619,10 @@ void Flow::setTransform(float scale, const glm::vec3& position, const glm::quat& } void Flow::update() { + QElapsedTimer _timer; _timer.start(); if (_initialized && _active) { updateJoints(); - if (USE_COLLISIONS) { - _collisionSystem.update(); - } int count = 0; for (auto &thread : _jointThreads) { thread.update(); @@ -650,11 +634,12 @@ void Flow::update() { } setJoints(); } - _elapsedTime = ((1.0 - _tau) * _elapsedTime + _tau * _timer.nsecsElapsed()); - _deltaTime += _elapsedTime; + _deltaTime += _timer.nsecsElapsed(); + _updates++; if (_deltaTime > _deltaTimeLimit) { - qDebug() << "Flow C++ update" << _elapsedTime; - _deltaTime = 0.0; + qDebug() << "Flow C++ update " << _deltaTime / _updates << " nanoSeconds"; + _deltaTime = 0; + _updates = 0; } } @@ -697,10 +682,15 @@ void Flow::updateJoints() { _rig->getJointRotationInWorldFrame(jointData.second._parentIndex, parentWorldRotation, _entityRotation); jointData.second.setUpdatedData(jointPosition, jointTranslation, jointRotation, parentPosition, parentWorldRotation); } - auto &collisions = _collisionSystem.getCollisions(); - for (auto &collision : collisions) { + auto &selfCollisions = _collisionSystem.getSelfCollisions(); + for (auto &collision : selfCollisions) { + glm::quat jointRotation; _rig->getJointPositionInWorldFrame(collision._jointIndex, collision._position, _entityPosition, _entityRotation); + _rig->getJointRotationInWorldFrame(collision._jointIndex, jointRotation, _entityRotation); + glm::vec3 worldOffset = jointRotation * collision._offset; + collision._position = collision._position + worldOffset; } + _collisionSystem.prepareCollisions(); } void Flow::setJoints() { @@ -712,3 +702,10 @@ void Flow::setJoints() { } } } + +void Flow::setOthersCollision(const QUuid& otherId, int jointIndex, const glm::vec3& position) { + FlowCollisionSettings settings; + settings._entityID = otherId; + settings._radius = HAND_COLLISION_RADIUS; + _collisionSystem.addCollisionSphere(jointIndex, settings, position, false, true); +} \ No newline at end of file diff --git a/libraries/animation/src/Flow.h b/libraries/animation/src/Flow.h index c93cf91673..ec98b32265 100644 --- a/libraries/animation/src/Flow.h +++ b/libraries/animation/src/Flow.h @@ -39,6 +39,8 @@ const float HAPTIC_THRESHOLD = 40.0f; const QString FLOW_JOINT_PREFIX = "flow"; const QString SIM_JOINT_PREFIX = "sim"; +const std::vector HAND_COLLISION_JOINTS = { "RightHandMiddle1", "RightHandThumb3", "LeftHandMiddle1", "LeftHandThumb3", "RightHandMiddle3", "LeftHandMiddle3" }; + const QString JOINT_COLLISION_PREFIX = "joint_"; const QString HAND_COLLISION_PREFIX = "hand_"; const float HAND_COLLISION_RADIUS = 0.03f; @@ -100,18 +102,6 @@ struct FlowCollisionSettings { const FlowPhysicsSettings DEFAULT_JOINT_SETTINGS; -const std::map PRESET_FLOW_DATA = { {"hair", FlowPhysicsSettings()}, - {"skirt", FlowPhysicsSettings(true, 1.0f, DEFAULT_GRAVITY, 0.65f, 0.8f, 0.45f, 0.01f)}, - {"breast", FlowPhysicsSettings(true, 1.0f, DEFAULT_GRAVITY, 0.65f, 0.8f, 0.45f, 0.01f)} }; - -const std::map PRESET_COLLISION_DATA = { - { "Head", FlowCollisionSettings(QUuid(), FlowCollisionType::CollisionSphere, glm::vec3(0.0f, 0.06f, 0.0f), 0.08f)}, - { "LeftArm", FlowCollisionSettings(QUuid(), FlowCollisionType::CollisionSphere, glm::vec3(0.0f, 0.02f, 0.0f), 0.05f) }, - { "Head", FlowCollisionSettings(QUuid(), FlowCollisionType::CollisionSphere, glm::vec3(0.0f, 0.04f, 0.0f), 0.0f) } -}; - -const std::vector HAND_COLLISION_JOINTS = { "RightHandMiddle1", "RightHandThumb3", "LeftHandMiddle1", "LeftHandThumb3", "RightHandMiddle3", "LeftHandMiddle3" }; - struct FlowJointInfo { FlowJointInfo() {}; FlowJointInfo(int index, int parentIndex, int childIndex, const QString& name) { @@ -138,19 +128,22 @@ struct FlowCollisionResult { class FlowCollisionSphere { public: FlowCollisionSphere() {}; - FlowCollisionSphere(const int& jointIndex, const FlowCollisionSettings& settings); + FlowCollisionSphere(const int& jointIndex, const FlowCollisionSettings& settings, bool isTouch = false); void setPosition(const glm::vec3& position) { _position = position; } FlowCollisionResult computeSphereCollision(const glm::vec3& point, float radius) const; FlowCollisionResult checkSegmentCollision(const glm::vec3& point1, const glm::vec3& point2, const FlowCollisionResult& collisionResult1, const FlowCollisionResult& collisionResult2); - void update(); QUuid _entityID; - int _jointIndex { -1 }; - float _radius { 0.0f }; - float _initialRadius{ 0.0f }; + glm::vec3 _offset; glm::vec3 _initialOffset; glm::vec3 _position; + + bool _isTouch { false }; + int _jointIndex { -1 }; + int collisionIndex { -1 }; + float _radius { 0.0f }; + float _initialRadius{ 0.0f }; }; class FlowThread; @@ -158,24 +151,26 @@ class FlowThread; class FlowCollisionSystem { public: FlowCollisionSystem() {}; - void addCollisionSphere(int jointIndex, const FlowCollisionSettings& settings); - void addCollisionShape(int jointIndex, const FlowCollisionSettings& settings); - bool addCollisionToJoint(int jointIndex); - void removeCollisionFromJoint(int jointIndex); - void update(); + void addCollisionSphere(int jointIndex, const FlowCollisionSettings& settings, const glm::vec3& position = { 0.0f, 0.0f, 0.0f }, bool isSelfCollision = true, bool isTouch = false); FlowCollisionResult computeCollision(const std::vector collisions); void setScale(float scale); - std::vector checkFlowThreadCollisions(FlowThread* flowThread, bool checkSegments); + std::vector checkFlowThreadCollisions(FlowThread* flowThread); - int findCollisionWithJoint(int jointIndex); - void modifyCollisionRadius(int jointIndex, float radius); - void modifyCollisionYOffset(int jointIndex, float offset); - void modifyCollisionOffset(int jointIndex, const glm::vec3& offset); + 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& getCollisions() { return _collisionSpheres; }; -private: - std::vector _collisionSpheres; + std::vector& getSelfCollisions() { return _selfCollisions; }; + void setOthersCollisions(const std::vector& othersCollisions) { _othersCollisions = othersCollisions; } + void prepareCollisions(); + void resetCollisions(); + void resetOthersCollisions() { _othersCollisions.clear(); } +protected: + std::vector _selfCollisions; + std::vector _othersCollisions; + std::vector _allCollisions; float _scale{ 1.0f }; }; @@ -208,7 +203,6 @@ public: void solve(const glm::vec3& constrainPoint, float maxDistance, const FlowCollisionResult& collision); void solveConstraints(const glm::vec3& constrainPoint, float maxDistance); void solveCollisions(const FlowCollisionResult& collision); - void apply(const QString& name, bool forceRendering); }; class FlowJoint { @@ -268,7 +262,7 @@ public: void computeJointRotations(); void apply(); bool getActive(); - void setRootFramePositions(const std::vector& rootFramePositions) { _rootFramePositions = rootFramePositions; }; + void setRootFramePositions(const std::vector& rootFramePositions) { _rootFramePositions = rootFramePositions; } std::vector _joints; std::vector _positions; @@ -276,7 +270,6 @@ public: float _length{ 0.0f }; std::map* _jointsPointer; std::vector _rootFramePositions; - }; class Flow { @@ -288,6 +281,8 @@ public: void setTransform(float scale, const glm::vec3& position, const glm::quat& rotation); const std::map& getJoints() const { return _flowJointData; } const std::vector& getThreads() const { return _jointThreads; } + void setOthersCollision(const QUuid& otherId, int jointIndex, const glm::vec3& position); + FlowCollisionSystem& getCollisionSystem() { return _collisionSystem; } private: void setJoints(); void cleanUp(); @@ -305,11 +300,9 @@ private: FlowCollisionSystem _collisionSystem; bool _initialized { false }; bool _active { false }; - int _deltaTime{ 0 }; - int _deltaTimeLimit{ 4000 }; - int _elapsedTime{ 0 }; - float _tau = 0.1f; - QElapsedTimer _timer; + int _deltaTime { 0 }; + int _deltaTimeLimit { 4000000 }; + int _updates { 0 }; }; #endif // hifi_Flow_h diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 50d13d348e..47c9697dac 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -235,7 +235,7 @@ public: const AnimVariantMap& getAnimVars() const { return _lastAnimVars; } const AnimContext::DebugStateMachineMap& getStateMachineMap() const { return _lastContext.getStateMachineMap(); } void computeFlowSkeleton() { _flow.calculateConstraints(); } - const Flow& getFlow() const { return _flow; } + Flow& getFlow() { return _flow; } signals: void onLoadComplete(); From 954cac907dfa002317308d30c213860a3be249a8 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Tue, 12 Feb 2019 15:02:56 -0700 Subject: [PATCH 04/16] Other avatars after update and mod timer when active --- interface/src/avatar/AvatarManager.cpp | 11 +++------- interface/src/avatar/MyAvatar.cpp | 8 +++++++ interface/src/avatar/MyAvatar.h | 2 ++ libraries/animation/src/Flow.cpp | 30 +++++++++++--------------- libraries/animation/src/Flow.h | 1 - 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 50e8546979..d2ba7149f2 100755 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -271,14 +271,6 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { if (avatar->getSkeletonModel()->isLoaded()) { // remove the orb if it is there avatar->removeOrb(); - if (avatar->getWorkloadRegion() == workload::Region::R1) { - auto &flow = _myAvatar->getSkeletonModel()->getRig().getFlow(); - for (auto &handJointName : HAND_COLLISION_JOINTS) { - int jointIndex = avatar->getJointIndex(handJointName); - glm::vec3 position = avatar->getJointPosition(jointIndex); - flow.setOthersCollision(avatar->getID(), jointIndex, position); - } - } if (avatar->needsPhysicsUpdate()) { _avatarsToChangeInPhysics.insert(avatar); } @@ -305,6 +297,9 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { avatar->setIsNewAvatar(false); } avatar->simulate(deltaTime, inView); + if (avatar->getSkeletonModel()->isLoaded() && avatar->getWorkloadRegion() == workload::Region::R1) { + _myAvatar->addAvatarHandsToFlow(avatar); + } avatar->updateRenderItem(renderTransaction); avatar->updateSpaceProxy(workloadTransaction); avatar->setLastRenderUpdateTime(startTime); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 92d9270d20..d5f8f8a3ec 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -5312,3 +5312,11 @@ void MyAvatar::releaseGrab(const QUuid& grabID) { } } +void MyAvatar::addAvatarHandsToFlow(const std::shared_ptr& otherAvatar) { + auto &flow = _skeletonModel->getRig().getFlow(); + for (auto &handJointName : HAND_COLLISION_JOINTS) { + int jointIndex = otherAvatar->getJointIndex(handJointName); + glm::vec3 position = otherAvatar->getJointPosition(jointIndex); + flow.setOthersCollision(otherAvatar->getID(), jointIndex, position); + } +} diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 0d27988543..996abcabf2 100755 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1182,6 +1182,8 @@ public: void updateAvatarEntity(const QUuid& entityID, const QByteArray& entityData) override; void avatarEntityDataToJson(QJsonObject& root) const override; int sendAvatarDataPacket(bool sendAll = false) override; + + void addAvatarHandsToFlow(const std::shared_ptr& otherAvatar); public slots: diff --git a/libraries/animation/src/Flow.cpp b/libraries/animation/src/Flow.cpp index 87d7155abd..8aee4dc53c 100644 --- a/libraries/animation/src/Flow.cpp +++ b/libraries/animation/src/Flow.cpp @@ -461,7 +461,6 @@ void Flow::calculateConstraints() { auto simPrefix = SIM_JOINT_PREFIX.toUpper(); auto skeleton = _rig->getAnimSkeleton(); std::vector handsIndices; - _collisionSystem.resetCollisions(); if (skeleton) { for (int i = 0; i < skeleton->getNumJoints(); i++) { auto name = skeleton->getJointName(i); @@ -517,10 +516,6 @@ void Flow::calculateConstraints() { _collisionSystem.addCollisionSphere(i, PRESET_COLLISION_DATA.at(name)); } } - if (isFlowJoint || isSimJoint) { - auto jointInfo = FlowJointInfo(i, parentIndex, -1, name); - _flowJointInfos.push_back(jointInfo); - } } } @@ -604,7 +599,9 @@ void Flow::cleanUp() { _flowJointData.clear(); _jointThreads.clear(); _flowJointKeywords.clear(); - _flowJointInfos.clear(); + _collisionSystem.resetCollisions(); + _initialized = false; + _active = false; } void Flow::setTransform(float scale, const glm::vec3& position, const glm::quat& rotation) { @@ -619,9 +616,9 @@ void Flow::setTransform(float scale, const glm::vec3& position, const glm::quat& } void Flow::update() { - QElapsedTimer _timer; - _timer.start(); if (_initialized && _active) { + QElapsedTimer _timer; + _timer.start(); updateJoints(); int count = 0; for (auto &thread : _jointThreads) { @@ -633,15 +630,14 @@ void Flow::update() { thread.apply(); } setJoints(); - } - _deltaTime += _timer.nsecsElapsed(); - _updates++; - if (_deltaTime > _deltaTimeLimit) { - qDebug() << "Flow C++ update " << _deltaTime / _updates << " nanoSeconds"; - _deltaTime = 0; - _updates = 0; - } - + _deltaTime += _timer.nsecsElapsed(); + _updates++; + if (_deltaTime > _deltaTimeLimit) { + qDebug() << "Flow C++ update " << _deltaTime / _updates << " nanoSeconds"; + _deltaTime = 0; + _updates = 0; + } + } } bool Flow::worldToJointPoint(const glm::vec3& position, const int jointIndex, glm::vec3& jointSpacePosition) const { diff --git a/libraries/animation/src/Flow.h b/libraries/animation/src/Flow.h index ec98b32265..9c088bf263 100644 --- a/libraries/animation/src/Flow.h +++ b/libraries/animation/src/Flow.h @@ -296,7 +296,6 @@ private: std::map _flowJointData; std::vector _jointThreads; std::vector _flowJointKeywords; - std::vector _flowJointInfos; FlowCollisionSystem _collisionSystem; bool _initialized { false }; bool _active { false }; From bebbbc643b46132b1aacce363e3c66b3942197fb Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Wed, 13 Feb 2019 06:27:49 -0700 Subject: [PATCH 05/16] add deltaTime to simulation --- libraries/animation/src/Flow.cpp | 43 ++++++++++++++++++-------------- libraries/animation/src/Flow.h | 13 +++++----- libraries/animation/src/Rig.cpp | 5 ++-- 3 files changed, 33 insertions(+), 28 deletions(-) diff --git a/libraries/animation/src/Flow.cpp b/libraries/animation/src/Flow.cpp index 8aee4dc53c..ec17a56a4a 100644 --- a/libraries/animation/src/Flow.cpp +++ b/libraries/animation/src/Flow.cpp @@ -206,22 +206,26 @@ void FlowCollisionSystem::prepareCollisions() { _othersCollisions.clear(); } -void FlowNode::update(const glm::vec3& accelerationOffset) { +void FlowNode::update(float deltaTime, const glm::vec3& accelerationOffset) { _acceleration = glm::vec3(0.0f, _settings._gravity, 0.0f); _previousVelocity = _currentVelocity; _currentVelocity = _currentPosition - _previousPosition; _previousPosition = _currentPosition; if (!_anchored) { // Add inertia + const float FPS = 60.0f; + float timeRatio = (FPS * deltaTime); + auto deltaVelocity = _previousVelocity - _currentVelocity; auto centrifugeVector = glm::length(deltaVelocity) != 0.0f ? glm::normalize(deltaVelocity) : glm::vec3(); - _acceleration = _acceleration + centrifugeVector * _settings._inertia * glm::length(_currentVelocity); + _acceleration = _acceleration + centrifugeVector * _settings._inertia * glm::length(_currentVelocity) * (1 / timeRatio); // Add offset _acceleration += accelerationOffset; - // Calculate new position - _currentPosition = (_currentPosition + _currentVelocity * _settings._damping) + - (_acceleration * glm::pow(_settings._delta * _scale, 2)); + + glm::vec3 deltaAcceleration = timeRatio * _acceleration * glm::pow(_settings._delta * _scale, 2); + // Calculate new position + _currentPosition = (_currentPosition + _currentVelocity * _settings._damping) + deltaAcceleration; } else { _acceleration = glm::vec3(0.0f); @@ -289,13 +293,13 @@ void FlowJoint::setRecoveryPosition(const glm::vec3& recoveryPosition) { _applyRecovery = true; } -void FlowJoint::update() { +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); } - _node.update(accelerationOffset); + _node.update(deltaTime, accelerationOffset); if (_node._anchored) { if (!_isDummy) { _node._currentPosition = _updatedPosition; @@ -368,14 +372,14 @@ void FlowThread::computeRecovery() { } }; -void FlowThread::update() { +void FlowThread::update(float deltaTime) { if (getActive()) { _positions.clear(); _radius = _jointsPointer->at(_joints[0])._node._settings._radius; computeRecovery(); for (size_t i = 0; i < _joints.size(); i++) { auto &joint = _jointsPointer->at(_joints[i]); - joint.update(); + joint.update(deltaTime); _positions.push_back(joint._node._currentPosition); } } @@ -447,10 +451,6 @@ bool FlowThread::getActive() { return _jointsPointer->at(_joints[0])._node._active; }; -void Flow::setRig(Rig* rig) { - _rig = rig; -}; - void Flow::calculateConstraints() { cleanUp(); if (!_rig) { @@ -593,6 +593,9 @@ void Flow::calculateConstraints() { } } _initialized = _jointThreads.size() > 0; + if (_initialized) { + _mtimer.restart(); + } } void Flow::cleanUp() { @@ -615,14 +618,14 @@ void Flow::setTransform(float scale, const glm::vec3& position, const glm::quat& _active = true; } -void Flow::update() { +void Flow::update(float deltaTime) { if (_initialized && _active) { - QElapsedTimer _timer; - _timer.start(); + QElapsedTimer timer; + timer.start(); updateJoints(); int count = 0; for (auto &thread : _jointThreads) { - thread.update(); + thread.update(deltaTime); thread.solve(USE_COLLISIONS, _collisionSystem); if (!updateRootFramePositions(count++)) { return; @@ -630,10 +633,12 @@ void Flow::update() { thread.apply(); } setJoints(); - _deltaTime += _timer.nsecsElapsed(); + _deltaTime += timer.nsecsElapsed(); _updates++; if (_deltaTime > _deltaTimeLimit) { - qDebug() << "Flow C++ update " << _deltaTime / _updates << " nanoSeconds"; + qint64 currentTime = _mtimer.elapsed(); + qDebug() << "Flow C++ update " << _deltaTime / _updates << " nanoSeconds " << (currentTime - _lastTime) / _updates << " miliseconds since last update"; + _lastTime = currentTime; _deltaTime = 0; _updates = 0; } diff --git a/libraries/animation/src/Flow.h b/libraries/animation/src/Flow.h index 9c088bf263..ff21d4a776 100644 --- a/libraries/animation/src/Flow.h +++ b/libraries/animation/src/Flow.h @@ -199,7 +199,7 @@ public: bool _colliding { false }; bool _active { true }; - void update(const glm::vec3& accelerationOffset); + void update(float deltaTime, const glm::vec3& accelerationOffset); void solve(const glm::vec3& constrainPoint, float maxDistance, const FlowCollisionResult& collision); void solveConstraints(const glm::vec3& constrainPoint, float maxDistance); void solveCollisions(const FlowCollisionResult& collision); @@ -212,7 +212,7 @@ public: void setInitialData(const glm::vec3& initialPosition, const glm::vec3& initialTranslation, const glm::quat& initialRotation, const glm::vec3& parentPosition); void setUpdatedData(const glm::vec3& updatedPosition, const glm::vec3& updatedTranslation, const glm::quat& updatedRotation, const glm::vec3& parentPosition, const glm::quat& parentWorldRotation); void setRecoveryPosition(const glm::vec3& recoveryPosition); - void update(); + void update(float deltaTime); void solve(const FlowCollisionResult& collision); int _index{ -1 }; @@ -257,7 +257,7 @@ public: void resetLength(); void computeFlowThread(int rootIndex); void computeRecovery(); - void update(); + void update(float deltaTime); void solve(bool useCollisions, FlowCollisionSystem& collisionSystem); void computeJointRotations(); void apply(); @@ -274,10 +274,9 @@ public: class Flow { public: - Flow() {}; - void setRig(Rig* rig); + Flow(Rig* rig) { _rig = rig; }; void calculateConstraints(); - void update(); + void update(float deltaTime); void setTransform(float scale, const glm::vec3& position, const glm::quat& rotation); const std::map& getJoints() const { return _flowJointData; } const std::vector& getThreads() const { return _jointThreads; } @@ -302,6 +301,8 @@ private: int _deltaTime { 0 }; int _deltaTimeLimit { 4000000 }; int _updates { 0 }; + QElapsedTimer _mtimer; + long _lastTime { 0 }; }; #endif // hifi_Flow_h diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 5042c00be6..e6e4f74c11 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -75,7 +75,7 @@ static const QString MAIN_STATE_MACHINE_RIGHT_FOOT_ROTATION("mainStateMachineRig static const QString MAIN_STATE_MACHINE_RIGHT_FOOT_POSITION("mainStateMachineRightFootPosition"); -Rig::Rig() { +Rig::Rig() : _flow(this) { // Ensure thread-safe access to the rigRegistry. std::lock_guard guard(rigRegistryMutex); @@ -1217,7 +1217,7 @@ void Rig::updateAnimations(float deltaTime, const glm::mat4& rootTransform, cons buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses); buildAbsoluteRigPoses(_networkPoseSet._relativePoses, _networkPoseSet._absolutePoses); // copy internal poses to external poses - _flow.update(); + _flow.update(deltaTime); { QWriteLocker writeLock(&_externalPoseSetLock); @@ -1873,7 +1873,6 @@ void Rig::initAnimGraph(const QUrl& url) { auto roleState = roleAnimState.second; overrideRoleAnimation(roleState.role, roleState.url, roleState.fps, roleState.loop, roleState.firstFrame, roleState.lastFrame); } - _flow.setRig(this); emit onLoadComplete(); }); connect(_animLoader.get(), &AnimNodeLoader::error, [url](int error, QString str) { From 05d50f32ba974a7700cbc5bdc0c15b5cee7691a6 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Wed, 13 Feb 2019 08:16:22 -0700 Subject: [PATCH 06/16] time budget --- libraries/animation/src/Flow.cpp | 27 ++++++++++++++------------- libraries/animation/src/Flow.h | 7 ++++--- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/libraries/animation/src/Flow.cpp b/libraries/animation/src/Flow.cpp index ec17a56a4a..ab22e25326 100644 --- a/libraries/animation/src/Flow.cpp +++ b/libraries/animation/src/Flow.cpp @@ -593,9 +593,6 @@ void Flow::calculateConstraints() { } } _initialized = _jointThreads.size() > 0; - if (_initialized) { - _mtimer.restart(); - } } void Flow::cleanUp() { @@ -620,25 +617,29 @@ void Flow::setTransform(float scale, const glm::vec3& position, const glm::quat& void Flow::update(float deltaTime) { if (_initialized && _active) { - QElapsedTimer timer; - timer.start(); + QElapsedTimer _timer; + _timer.start(); updateJoints(); - int count = 0; - for (auto &thread : _jointThreads) { + 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); - if (!updateRootFramePositions(count++)) { + if (!updateRootFramePositions(index)) { return; } thread.apply(); + if (_timer.elapsed() > MAX_UPDATE_FLOW_TIME_BUDGET) { + break; + qWarning(animation) << "Flow Bones ran out of time updating threads"; + } } setJoints(); - _deltaTime += timer.nsecsElapsed(); + _invertThreadLoop = !_invertThreadLoop; + _deltaTime += _timer.nsecsElapsed(); _updates++; if (_deltaTime > _deltaTimeLimit) { - qint64 currentTime = _mtimer.elapsed(); - qDebug() << "Flow C++ update " << _deltaTime / _updates << " nanoSeconds " << (currentTime - _lastTime) / _updates << " miliseconds since last update"; - _lastTime = currentTime; + qDebug() << "Flow C++ update " << _deltaTime / _updates << " nanoSeconds "; _deltaTime = 0; _updates = 0; } @@ -656,7 +657,7 @@ bool Flow::worldToJointPoint(const glm::vec3& position, const int jointIndex, gl return false; } -bool Flow::updateRootFramePositions(int threadIndex) { +bool Flow::updateRootFramePositions(size_t threadIndex) { auto &joints = _jointThreads[threadIndex]._joints; int rootIndex = _flowJointData[joints[0]]._parentIndex; _jointThreads[threadIndex]._rootFramePositions.clear(); diff --git a/libraries/animation/src/Flow.h b/libraries/animation/src/Flow.h index ff21d4a776..a06f785da2 100644 --- a/libraries/animation/src/Flow.h +++ b/libraries/animation/src/Flow.h @@ -62,6 +62,8 @@ const float DEFAULT_INERTIA = 0.8f; const float DEFAULT_DELTA = 0.55f; const float DEFAULT_RADIUS = 0.01f; +const uint64_t MAX_UPDATE_FLOW_TIME_BUDGET = 2000; + struct FlowPhysicsSettings { FlowPhysicsSettings() {}; FlowPhysicsSettings(bool active, float stiffness, float gravity, float damping, float inertia, float delta, float radius) { @@ -286,7 +288,7 @@ private: void setJoints(); void cleanUp(); void updateJoints(); - bool updateRootFramePositions(int threadIndex); + bool updateRootFramePositions(size_t threadIndex); bool worldToJointPoint(const glm::vec3& position, const int jointIndex, glm::vec3& jointSpacePosition) const; Rig* _rig; float _scale { 1.0f }; @@ -301,8 +303,7 @@ private: int _deltaTime { 0 }; int _deltaTimeLimit { 4000000 }; int _updates { 0 }; - QElapsedTimer _mtimer; - long _lastTime { 0 }; + bool _invertThreadLoop { false }; }; #endif // hifi_Flow_h From 3e66bce11262807205f8f2506233707c6abd61ef Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 14 Feb 2019 18:30:37 -0700 Subject: [PATCH 07/16] set useFlow function --- interface/src/avatar/MyAvatar.cpp | 55 ++++++++++ interface/src/avatar/MyAvatar.h | 10 ++ libraries/animation/src/Flow.cpp | 102 ++++++++++++++---- libraries/animation/src/Flow.h | 20 ++-- libraries/animation/src/Rig.cpp | 4 +- .../src/avatars-renderer/Avatar.cpp | 1 - 6 files changed, 161 insertions(+), 31 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index d5f8f8a3ec..ce751add0b 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -5320,3 +5320,58 @@ void MyAvatar::addAvatarHandsToFlow(const std::shared_ptr& otherAvatar) flow.setOthersCollision(otherAvatar->getID(), jointIndex, position); } } + +void MyAvatar::useFlow(const QVariantMap& physicsConfig, const QVariantMap& collisionsConfig) { + if (_skeletonModel->isLoaded()) { + auto &flow = _skeletonModel->getRig().getFlow(); + flow.init(); + auto physicsGroups = physicsConfig.keys(); + if (physicsGroups.size() > 0) { + for (auto &groupName : physicsGroups) { + auto &settings = physicsConfig[groupName].toMap(); + FlowPhysicsSettings physicsSettings = flow.getPhysicsSettingsForGroup(groupName); + if (settings.contains("active")) { + physicsSettings._active = settings["active"].toBool(); + } + if (settings.contains("damping")) { + physicsSettings._damping = settings["damping"].toFloat(); + } + if (settings.contains("delta")) { + physicsSettings._delta = settings["delta"].toFloat(); + } + if (settings.contains("gravity")) { + physicsSettings._gravity = settings["gravity"].toFloat(); + } + if (settings.contains("inertia")) { + physicsSettings._inertia = settings["inertia"].toFloat(); + } + if (settings.contains("radius")) { + physicsSettings._radius = settings["radius"].toFloat(); + } + if (settings.contains("stiffness")) { + physicsSettings._stiffness = settings["stiffness"].toFloat(); + } + flow.setPhysicsSettingsForGroup(groupName, physicsSettings); + } + } + auto collisionJoints = collisionsConfig.keys(); + if (collisionJoints.size() > 0) { + auto &collisionSystem = flow.getCollisionSystem(); + collisionSystem.resetCollisions(); + for (auto &jointName : collisionJoints) { + int jointIndex = getJointIndex(jointName); + FlowCollisionSettings collisionsSettings; + auto &settings = collisionsConfig[jointName].toMap(); + collisionsSettings._entityID = getID(); + if (settings.contains("radius")) { + collisionsSettings._radius = settings["radius"].toFloat(); + } + if (settings.contains("offset")) { + collisionsSettings._offset = vec3FromVariant(settings["offset"]); + } + collisionSystem.addCollisionSphere(jointIndex, collisionsSettings); + } + + } + } +} \ No newline at end of file diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 996abcabf2..f753da4fa0 100755 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1185,6 +1185,16 @@ public: void addAvatarHandsToFlow(const std::shared_ptr& otherAvatar); + /**jsdoc + * Init flow simulation on avatar. + * @function MyAvatar.useFlow + * @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()); + public slots: /**jsdoc diff --git a/libraries/animation/src/Flow.cpp b/libraries/animation/src/Flow.cpp index ab22e25326..3db0068434 100644 --- a/libraries/animation/src/Flow.cpp +++ b/libraries/animation/src/Flow.cpp @@ -176,7 +176,7 @@ void FlowCollisionSystem::modifySelfCollisionRadius(int jointIndex, float radius int collisionIndex = findSelfCollisionWithJoint(jointIndex); if (collisionIndex > -1) { _selfCollisions[collisionIndex]._initialRadius = radius; - _selfCollisions[collisionIndex]._radius = _scale * radius; + //_selfCollisions[collisionIndex]._radius = _scale * radius; } }; @@ -185,7 +185,7 @@ void FlowCollisionSystem::modifySelfCollisionYOffset(int jointIndex, float offse 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; + //_selfCollisions[collisionIndex]._offset = _selfCollisions[collisionIndex]._initialOffset * _scale; } }; @@ -193,11 +193,27 @@ void FlowCollisionSystem::modifySelfCollisionOffset(int jointIndex, const glm::v int collisionIndex = findSelfCollisionWithJoint(jointIndex); if (collisionIndex > -1) { _selfCollisions[collisionIndex]._initialOffset = offset; - _selfCollisions[collisionIndex]._offset = _selfCollisions[collisionIndex]._initialOffset * _scale; + //_selfCollisions[collisionIndex]._offset = _selfCollisions[collisionIndex]._initialOffset * _scale; } }; - - +FlowCollisionSettings FlowCollisionSystem::getCollisionSettingsByJoint(int jointIndex) { + for (auto &collision : _selfCollisions) { + if (collision._jointIndex == jointIndex) { + return FlowCollisionSettings(collision._entityID, FlowCollisionType::CollisionSphere, collision._initialOffset, collision._initialRadius); + } + } + return FlowCollisionSettings(); +} +void FlowCollisionSystem::setCollisionSettingsByJoint(int jointIndex, const FlowCollisionSettings& settings) { + for (auto &collision : _selfCollisions) { + if (collision._jointIndex == jointIndex) { + collision._initialRadius = settings._radius; + collision._initialOffset = settings._offset; + collision._radius = _scale * settings._radius; + collision._offset = _scale * settings._offset; + } + } +} void FlowCollisionSystem::prepareCollisions() { _allCollisions.clear(); _allCollisions.resize(_selfCollisions.size() + _othersCollisions.size()); @@ -206,6 +222,11 @@ void FlowCollisionSystem::prepareCollisions() { _othersCollisions.clear(); } +FlowNode::FlowNode(const glm::vec3& initialPosition, FlowPhysicsSettings settings) { + _initialPosition = _previousPosition = _currentPosition = initialPosition; + _initialRadius = settings._radius; +} + void FlowNode::update(float deltaTime, const glm::vec3& accelerationOffset) { _acceleration = glm::vec3(0.0f, _settings._gravity, 0.0f); _previousVelocity = _currentVelocity; @@ -215,15 +236,16 @@ void FlowNode::update(float deltaTime, const glm::vec3& accelerationOffset) { // Add inertia const float FPS = 60.0f; float timeRatio = (FPS * deltaTime); - + float invertedTimeRatio = timeRatio > 0.0f ? 1.0f / timeRatio : 1.0f; auto deltaVelocity = _previousVelocity - _currentVelocity; auto centrifugeVector = glm::length(deltaVelocity) != 0.0f ? glm::normalize(deltaVelocity) : glm::vec3(); - _acceleration = _acceleration + centrifugeVector * _settings._inertia * glm::length(_currentVelocity) * (1 / timeRatio); + _acceleration = _acceleration + centrifugeVector * _settings._inertia * glm::length(_currentVelocity) * invertedTimeRatio; // Add offset _acceleration += accelerationOffset; - glm::vec3 deltaAcceleration = timeRatio * _acceleration * glm::pow(_settings._delta * _scale, 2); + //glm::vec3 deltaAcceleration = timeRatio * _acceleration * glm::pow(_settings._delta * _scale, 2); + glm::vec3 deltaAcceleration = timeRatio * _acceleration * glm::pow(_settings._delta, 2); // Calculate new position _currentPosition = (_currentPosition + _currentVelocity * _settings._damping) + deltaAcceleration; } @@ -257,11 +279,10 @@ void FlowNode::solveCollisions(const FlowCollisionResult& collision) { } }; -FlowJoint::FlowJoint(int jointIndex, int parentIndex, int childIndex, const QString& name, const QString& group, float scale, const FlowPhysicsSettings& settings) { +FlowJoint::FlowJoint(int jointIndex, int parentIndex, int childIndex, const QString& name, const QString& group, const FlowPhysicsSettings& settings) { _index = jointIndex; _name = name; _group = group; - _scale = scale; _childIndex = childIndex; _parentIndex = parentIndex; _node = FlowNode(glm::vec3(), settings); @@ -276,8 +297,7 @@ void FlowJoint::setInitialData(const glm::vec3& initialPosition, const glm::vec3 _initialRotation = initialRotation; _translationDirection = glm::normalize(_initialTranslation); _parentPosition = parentPosition; - _length = glm::length(_initialPosition - parentPosition); - _originalLength = _length / _scale; + _initialLength = _length = glm::length(_initialPosition - parentPosition); } void FlowJoint::setUpdatedData(const glm::vec3& updatedPosition, const glm::vec3& updatedTranslation, const glm::quat& updatedRotation, const glm::vec3& parentPosition, const glm::quat& parentWorldRotation) { @@ -313,8 +333,8 @@ void FlowJoint::solve(const FlowCollisionResult& collision) { _node.solve(_parentPosition, _length, collision); }; -FlowDummyJoint::FlowDummyJoint(const glm::vec3& initialPosition, int index, int parentIndex, int childIndex, float scale, FlowPhysicsSettings settings) : - FlowJoint(index, parentIndex, childIndex, DUMMY_KEYWORD + "_" + index, DUMMY_KEYWORD, scale, settings) { +FlowDummyJoint::FlowDummyJoint(const glm::vec3& initialPosition, int index, int parentIndex, int childIndex, FlowPhysicsSettings settings) : + FlowJoint(index, parentIndex, childIndex, DUMMY_KEYWORD + "_" + index, DUMMY_KEYWORD, settings) { _isDummy = true; _initialPosition = initialPosition; _node = FlowNode(_initialPosition, settings); @@ -451,6 +471,12 @@ bool FlowThread::getActive() { return _jointsPointer->at(_joints[0])._node._active; }; +void Flow::init() { + if (!_initialized) { + calculateConstraints(); + } +} + void Flow::calculateConstraints() { cleanUp(); if (!_rig) { @@ -507,7 +533,7 @@ void Flow::calculateConstraints() { jointSettings = DEFAULT_JOINT_SETTINGS; } if (_flowJointData.find(i) == _flowJointData.end()) { - auto flowJoint = FlowJoint(i, parentIndex, -1, name, group, _scale, jointSettings); + auto flowJoint = FlowJoint(i, parentIndex, -1, name, group, jointSettings); _flowJointData.insert(std::pair(i, flowJoint)); } } @@ -553,7 +579,7 @@ void Flow::calculateConstraints() { auto newSettings = FlowPhysicsSettings(joint._node._settings); newSettings._stiffness = ISOLATED_JOINT_STIFFNESS; int extraIndex = (int)_flowJointData.size(); - auto newJoint = FlowDummyJoint(jointPosition, extraIndex, jointIndex, -1, _scale, newSettings); + auto newJoint = FlowDummyJoint(jointPosition, extraIndex, jointIndex, -1, newSettings); newJoint._isDummy = false; newJoint._length = ISOLATED_JOINT_LENGTH; newJoint._childIndex = extraIndex; @@ -575,7 +601,7 @@ void Flow::calculateConstraints() { int parentIndex = rightHandIndex; for (int i = 0; i < DUMMY_JOINT_COUNT; i++) { int childIndex = (i == (DUMMY_JOINT_COUNT - 1)) ? -1 : extraIndex + 1; - auto newJoint = FlowDummyJoint(rightHandPosition, extraIndex, parentIndex, childIndex, _scale, DEFAULT_JOINT_SETTINGS); + auto newJoint = FlowDummyJoint(rightHandPosition, extraIndex, parentIndex, childIndex, DEFAULT_JOINT_SETTINGS); _flowJointData.insert(std::pair(extraIndex, newJoint)); parentIndex = extraIndex; extraIndex++; @@ -601,24 +627,39 @@ void Flow::cleanUp() { _flowJointKeywords.clear(); _collisionSystem.resetCollisions(); _initialized = false; + _isScaleSet = false; _active = false; } void Flow::setTransform(float scale, const glm::vec3& position, const glm::quat& rotation) { _scale = scale; - for (auto &joint : _flowJointData) { - joint.second._scale = scale; - joint.second._node._scale = scale; - } _entityPosition = position; _entityRotation = rotation; - _active = true; + _active = _initialized; } void Flow::update(float deltaTime) { if (_initialized && _active) { QElapsedTimer _timer; _timer.start(); + 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(); + } + } updateJoints(); for (size_t i = 0; i < _jointThreads.size(); i++) { size_t index = _invertThreadLoop ? _jointThreads.size() - 1 - i : i; @@ -710,4 +751,21 @@ void Flow::setOthersCollision(const QUuid& otherId, int jointIndex, const glm::v settings._entityID = otherId; settings._radius = HAND_COLLISION_RADIUS; _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()) { + joint.second._node._settings = settings; + } + } } \ No newline at end of file diff --git a/libraries/animation/src/Flow.h b/libraries/animation/src/Flow.h index a06f785da2..7f77df0beb 100644 --- a/libraries/animation/src/Flow.h +++ b/libraries/animation/src/Flow.h @@ -155,7 +155,6 @@ public: FlowCollisionSystem() {}; void addCollisionSphere(int jointIndex, const FlowCollisionSettings& settings, const glm::vec3& position = { 0.0f, 0.0f, 0.0f }, bool isSelfCollision = true, bool isTouch = false); FlowCollisionResult computeCollision(const std::vector collisions); - void setScale(float scale); std::vector checkFlowThreadCollisions(FlowThread* flowThread); @@ -169,6 +168,9 @@ public: void prepareCollisions(); void resetCollisions(); void resetOthersCollisions() { _othersCollisions.clear(); } + void setScale(float scale); + FlowCollisionSettings getCollisionSettingsByJoint(int jointIndex); + void setCollisionSettingsByJoint(int jointIndex, const FlowCollisionSettings& settings); protected: std::vector _selfCollisions; std::vector _othersCollisions; @@ -179,8 +181,7 @@ protected: class FlowNode { public: FlowNode() {}; - FlowNode(const glm::vec3& initialPosition, FlowPhysicsSettings settings) : - _initialPosition(initialPosition), _previousPosition(initialPosition), _currentPosition(initialPosition){}; + FlowNode(const glm::vec3& initialPosition, FlowPhysicsSettings settings); FlowPhysicsSettings _settings; glm::vec3 _initialPosition; @@ -195,7 +196,6 @@ public: FlowCollisionResult _previousCollision; float _initialRadius { 0.0f }; - float _scale{ 1.0f }; bool _anchored { false }; bool _colliding { false }; @@ -210,7 +210,7 @@ public: class FlowJoint { public: FlowJoint() {}; - FlowJoint(int jointIndex, int parentIndex, int childIndex, const QString& name, const QString& group, float scale, const FlowPhysicsSettings& settings); + FlowJoint(int jointIndex, int parentIndex, int childIndex, const QString& name, const QString& group, const FlowPhysicsSettings& settings); void setInitialData(const glm::vec3& initialPosition, const glm::vec3& initialTranslation, const glm::quat& initialRotation, const glm::vec3& parentPosition); void setUpdatedData(const glm::vec3& updatedPosition, const glm::vec3& updatedTranslation, const glm::quat& updatedRotation, const glm::vec3& parentPosition, const glm::quat& parentWorldRotation); void setRecoveryPosition(const glm::vec3& recoveryPosition); @@ -241,13 +241,13 @@ public: glm::vec3 _translationDirection; float _scale { 1.0f }; float _length { 0.0f }; - float _originalLength { 0.0f }; + float _initialLength { 0.0f }; bool _applyRecovery { false }; }; class FlowDummyJoint : public FlowJoint { public: - FlowDummyJoint(const glm::vec3& initialPosition, int index, int parentIndex, int childIndex, float scale, FlowPhysicsSettings settings); + FlowDummyJoint(const glm::vec3& initialPosition, int index, int parentIndex, int childIndex, FlowPhysicsSettings settings); }; @@ -277,6 +277,8 @@ public: class Flow { public: Flow(Rig* rig) { _rig = rig; }; + void init(); + bool isActive() { return _active; } void calculateConstraints(); void update(float deltaTime); void setTransform(float scale, const glm::vec3& position, const glm::quat& rotation); @@ -284,6 +286,8 @@ 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(); void cleanUp(); @@ -292,6 +296,7 @@ private: bool worldToJointPoint(const glm::vec3& position, const int jointIndex, glm::vec3& jointSpacePosition) const; Rig* _rig; float _scale { 1.0f }; + float _lastScale{ 1.0f }; glm::vec3 _entityPosition; glm::quat _entityRotation; std::map _flowJointData; @@ -300,6 +305,7 @@ private: FlowCollisionSystem _collisionSystem; bool _initialized { false }; bool _active { false }; + bool _isScaleSet { false }; int _deltaTime { 0 }; int _deltaTimeLimit { 4000000 }; int _updates { 0 }; diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index e6e4f74c11..9b6d97d919 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1905,7 +1905,9 @@ void Rig::initAnimGraph(const QUrl& url) { qCritical(animation) << "Error loading: code = " << error << "str =" << str; }); connect(this, &Rig::onLoadComplete, [&]() { - _flow.calculateConstraints(); + if (_flow.isActive()) { + _flow.calculateConstraints(); + } }); } } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 223813eecb..50cb813c3a 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -736,7 +736,6 @@ void Avatar::postUpdate(float deltaTime, const render::ScenePointer& scene) { // glm::vec3 pos2 = joints.find(joint.second._parentIndex) != joints.end() ? joints[joint.second._parentIndex]._node._currentPosition : getJointPosition(joint.second._parentIndex); // DebugDraw::getInstance().drawRay(pos1, pos2, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); DebugDraw::getInstance().drawRay(joints[index1]._node._currentPosition, joints[index2]._node._currentPosition, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); - } } } From 88eae0f2ec7586fae9d286d5af9cacaf9b3634b7 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 14 Feb 2019 18:49:49 -0700 Subject: [PATCH 08/16] Remove test functions --- interface/src/avatar/AvatarManager.cpp | 103 ------------------ interface/src/avatar/AvatarManager.h | 9 -- .../src/avatars-renderer/Avatar.h | 3 - libraries/entities/src/EntityTree.cpp | 6 - libraries/entities/src/EntityTree.h | 1 - 5 files changed, 122 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index d2ba7149f2..685619aed8 100755 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -763,109 +763,6 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic return result; } -RayToAvatarIntersectionResult AvatarManager::findRayIntersectionOld(const PickRay& ray, - const QScriptValue& avatarIdsToInclude, - const QScriptValue& avatarIdsToDiscard) { - QVector avatarsToInclude = qVectorEntityItemIDFromScriptValue(avatarIdsToInclude); - QVector avatarsToDiscard = qVectorEntityItemIDFromScriptValue(avatarIdsToDiscard); - - return findRayIntersectionVectorOld(ray, avatarsToInclude, avatarsToDiscard); -} - -RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVectorOld(const PickRay& ray, - const QVector& avatarsToInclude, - const QVector& avatarsToDiscard) { - RayToAvatarIntersectionResult result; - if (QThread::currentThread() != thread()) { - BLOCKING_INVOKE_METHOD(const_cast(this), "findRayIntersectionVector", - Q_RETURN_ARG(RayToAvatarIntersectionResult, result), - Q_ARG(const PickRay&, ray), - Q_ARG(const QVector&, avatarsToInclude), - Q_ARG(const QVector&, avatarsToDiscard)); - return result; - } - - // It's better to intersect the ray against the avatar's actual mesh, but this is currently difficult to - // do, because the transformed mesh data only exists over in GPU-land. As a compromise, this code - // intersects against the avatars capsule and then against the (T-pose) mesh. The end effect is that picking - // against the avatar is sort-of right, but you likely wont be able to pick against the arms. - - // TODO -- find a way to extract transformed avatar mesh data from the rendering engine. - - std::vector sortedAvatars; - auto avatarHashCopy = getHashCopy(); - for (auto avatarData : avatarHashCopy) { - auto avatar = std::static_pointer_cast(avatarData); - if ((avatarsToInclude.size() > 0 && !avatarsToInclude.contains(avatar->getID())) || - (avatarsToDiscard.size() > 0 && avatarsToDiscard.contains(avatar->getID()))) { - continue; - } - - float distance = FLT_MAX; -#if 0 - // if we weren't picking against the capsule, we would want to pick against the avatarBounds... - SkeletonModelPointer avatarModel = avatar->getSkeletonModel(); - AABox avatarBounds = avatarModel->getRenderableMeshBound(); - if (avatarBounds.contains(ray.origin)) { - distance = 0.0f; - } - else { - float boundDistance = FLT_MAX; - BoxFace face; - glm::vec3 surfaceNormal; - if (avatarBounds.findRayIntersection(ray.origin, ray.direction, boundDistance, face, surfaceNormal)) { - distance = boundDistance; - } - } -#else - glm::vec3 start; - glm::vec3 end; - float radius; - avatar->getCapsule(start, end, radius); - findRayCapsuleIntersection(ray.origin, ray.direction, start, end, radius, distance); -#endif - - if (distance < FLT_MAX) { - sortedAvatars.emplace_back(distance, avatar); - } - } - - if (sortedAvatars.size() > 1) { - static auto comparator = [](const SortedAvatar& left, const SortedAvatar& right) { return left.first < right.first; }; - std::sort(sortedAvatars.begin(), sortedAvatars.end(), comparator); - } - - for (auto it = sortedAvatars.begin(); it != sortedAvatars.end(); ++it) { - const SortedAvatar& sortedAvatar = *it; - // We can exit once avatarCapsuleDistance > bestDistance - if (sortedAvatar.first > result.distance) { - break; - } - - float distance = FLT_MAX; - BoxFace face; - glm::vec3 surfaceNormal; - QVariantMap extraInfo; - SkeletonModelPointer avatarModel = sortedAvatar.second->getSkeletonModel(); - if (avatarModel->findRayIntersectionAgainstSubMeshes(ray.origin, ray.direction, distance, face, surfaceNormal, extraInfo, true)) { - if (distance < result.distance) { - result.intersects = true; - result.avatarID = sortedAvatar.second->getID(); - result.distance = distance; - result.face = face; - result.surfaceNormal = surfaceNormal; - result.extraInfo = extraInfo; - } - } - } - - if (result.intersects) { - result.intersection = ray.origin + ray.direction * result.distance; - } - - return result; -} - ParabolaToAvatarIntersectionResult AvatarManager::findParabolaIntersectionVector(const PickParabola& pick, const QVector& avatarsToInclude, const QVector& avatarsToDiscard) { diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 66f28206e0..50d9e80e8b 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -157,15 +157,6 @@ public: const QVector& avatarsToDiscard, bool pickAgainstMesh); - Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersectionOld(const PickRay& ray, - const QScriptValue& avatarIdsToInclude = QScriptValue(), - const QScriptValue& avatarIdsToDiscard = QScriptValue()); - - Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersectionVectorOld(const PickRay& ray, - const QVector& avatarsToInclude, - const QVector& avatarsToDiscard); - - /**jsdoc * @function AvatarManager.findParabolaIntersectionVector * @param {PickParabola} pick diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 4ba2ffc07d..b43fe012b7 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -35,7 +35,6 @@ #include "MetaModelPayload.h" #include "MultiSphereShape.h" -#include "Flow.h" namespace render { template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar); @@ -286,8 +285,6 @@ public: */ Q_INVOKABLE glm::quat jointToWorldRotation(const glm::quat& rotation, const int jointIndex = -1) const; - Q_INVOKABLE void callFlow() { _skeletonModel->getRig().computeFlowSkeleton(); }; - virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override; virtual void setAttachmentData(const QVector& attachmentData) override; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 47064bdbd3..954462a9f2 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -2943,12 +2943,6 @@ int EntityTree::getJointIndex(const QUuid& entityID, const QString& name) const } return entity->getJointIndex(name); } -void EntityTree::callFlowSkeleton(const QUuid& entityID) { - /* - EntityTree* nonConstThis = const_cast(this); - EntityItemPointer entity = nonConstThis->findEntityByEntityItemID(entityID); - */ -} QStringList EntityTree::getJointNames(const QUuid& entityID) const { EntityTree* nonConstThis = const_cast(this); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index cc80083e0d..f9b7b8d67f 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -240,7 +240,6 @@ public: // these are used to call through to EntityItems Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name) const; Q_INVOKABLE QStringList getJointNames(const QUuid& entityID) const; - Q_INVOKABLE void callFlowSkeleton(const QUuid& entityID); void knowAvatarID(QUuid avatarID) { _avatarIDs += avatarID; } void forgetAvatarID(QUuid avatarID) { _avatarIDs -= avatarID; } From 98c321c71863ddf1e2c1ca6703c41834458c683c Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Fri, 15 Feb 2019 09:40:49 -0700 Subject: [PATCH 09/16] Fix warnings --- interface/src/avatar/MyAvatar.cpp | 10 +- interface/src/avatar/MyAvatar.h | 4 +- libraries/animation/src/Flow.cpp | 164 ++++++++++++------------------ libraries/animation/src/Flow.h | 28 ++--- 4 files changed, 81 insertions(+), 125 deletions(-) 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 }; }; From c966f71cb1e040bde1a87a439dabb96c7e9e5cd9 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Fri, 15 Feb 2019 10:17:37 -0700 Subject: [PATCH 10/16] More fixes --- interface/src/avatar/MyAvatar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 96fdd6a9e1..f2e69ab5d3 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -5331,7 +5331,7 @@ void MyAvatar::useFlow(bool isActive, bool isCollidable, const QVariantMap& phys auto physicsGroups = physicsConfig.keys(); if (physicsGroups.size() > 0) { for (auto &groupName : physicsGroups) { - auto &settings = physicsConfig[groupName].toMap(); + auto settings = physicsConfig[groupName].toMap(); FlowPhysicsSettings physicsSettings; if (settings.contains("active")) { physicsSettings._active = settings["active"].toBool(); @@ -5363,7 +5363,7 @@ void MyAvatar::useFlow(bool isActive, bool isCollidable, const QVariantMap& phys for (auto &jointName : collisionJoints) { int jointIndex = getJointIndex(jointName); FlowCollisionSettings collisionsSettings; - auto &settings = collisionsConfig[jointName].toMap(); + auto settings = collisionsConfig[jointName].toMap(); collisionsSettings._entityID = getID(); if (settings.contains("radius")) { collisionsSettings._radius = settings["radius"].toFloat(); From b670f72e8422f966d58a684831e93c30cfbf2063 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Fri, 15 Feb 2019 12:35:17 -0700 Subject: [PATCH 11/16] fix warning on linux --- libraries/animation/src/Flow.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/libraries/animation/src/Flow.cpp b/libraries/animation/src/Flow.cpp index 607b2775e0..974dd8dc54 100644 --- a/libraries/animation/src/Flow.cpp +++ b/libraries/animation/src/Flow.cpp @@ -46,7 +46,7 @@ FlowCollisionResult FlowCollisionSphere::checkSegmentCollision(const glm::vec3& FlowCollisionResult result; auto segment = point2 - point1; auto segmentLength = glm::length(segment); - auto maxDistance = glm::sqrt(glm::pow(collisionResult1._radius, 2) + glm::pow(segmentLength, 2)); + auto maxDistance = glm::sqrt(powf(collisionResult1._radius, 2.0f) + powf(segmentLength, 2.0f)); if (collisionResult1._distance < maxDistance && collisionResult2._distance < maxDistance) { float segmentPercentage = collisionResult1._distance / (collisionResult1._distance + collisionResult2._distance); glm::vec3 collisionPoint = point1 + segment * segmentPercentage; @@ -123,21 +123,17 @@ std::vector FlowCollisionSystem::checkFlowThreadCollisions( auto prevCollision = collisionData[i - 1]; nextCollision = _allCollisions[j].computeSphereCollision(flowThread->_positions[i], flowThread->_radius); collisionData.push_back(nextCollision); - bool isTouching = false; if (prevCollision._offset > 0.0f) { if (i == 1) { FlowThreadResults[i - 1].push_back(prevCollision); - isTouching = true; } } else if (nextCollision._offset > 0.0f) { FlowThreadResults[i].push_back(nextCollision); - isTouching = true; } else { FlowCollisionResult segmentCollision = _allCollisions[j].checkSegmentCollision(flowThread->_positions[i - 1], flowThread->_positions[i], prevCollision, nextCollision); if (segmentCollision._offset > 0) { FlowThreadResults[i - 1].push_back(segmentCollision); FlowThreadResults[i].push_back(segmentCollision); - isTouching = true; } } } @@ -209,7 +205,7 @@ void FlowNode::update(float deltaTime, const glm::vec3& accelerationOffset) { // Add offset _acceleration += accelerationOffset; - float accelerationFactor = glm::pow(_settings._delta, 2) * timeRatio; + float accelerationFactor = powf(_settings._delta, 2.0f) * timeRatio; glm::vec3 deltaAcceleration = _acceleration * accelerationFactor; // Calculate new position _currentPosition = _currentPosition + (_currentVelocity * _settings._damping) + deltaAcceleration; @@ -280,7 +276,7 @@ void FlowJoint::update(float deltaTime) { glm::vec3 accelerationOffset = glm::vec3(0.0f); if (_node._settings._stiffness > 0.0f) { glm::vec3 recoveryVector = _recoveryPosition - _node._currentPosition; - float recoveryFactor = glm::pow(_node._settings._stiffness, 3); + float recoveryFactor = powf(_node._settings._stiffness, 3.0f); accelerationOffset = recoveryVector * recoveryFactor; } _node.update(deltaTime, accelerationOffset); From 04e57d0dd1af9a90836c2b549f62f0bf8e0b10f7 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Tue, 19 Feb 2019 17:45:46 -0700 Subject: [PATCH 12/16] No Rig pointer on Flow class, solve network animations and fixed bug --- interface/src/avatar/MyAvatar.cpp | 8 +- libraries/animation/src/Flow.cpp | 419 ++++++++++-------- libraries/animation/src/Flow.h | 87 +++- libraries/animation/src/Rig.cpp | 43 +- libraries/animation/src/Rig.h | 8 +- .../src/avatars-renderer/Avatar.cpp | 11 +- 6 files changed, 355 insertions(+), 221 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index f2e69ab5d3..f7c1052354 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -5317,15 +5317,17 @@ void MyAvatar::addAvatarHandsToFlow(const std::shared_ptr& otherAvatar) auto &flow = _skeletonModel->getRig().getFlow(); for (auto &handJointName : HAND_COLLISION_JOINTS) { int jointIndex = otherAvatar->getJointIndex(handJointName); - glm::vec3 position = otherAvatar->getJointPosition(jointIndex); - flow.setOthersCollision(otherAvatar->getID(), jointIndex, position); + if (jointIndex != -1) { + glm::vec3 position = otherAvatar->getJointPosition(jointIndex); + flow.setOthersCollision(otherAvatar->getID(), jointIndex, position); + } } } void MyAvatar::useFlow(bool isActive, bool isCollidable, const QVariantMap& physicsConfig, const QVariantMap& collisionsConfig) { if (_skeletonModel->isLoaded()) { + _skeletonModel->getRig().initFlow(isActive); auto &flow = _skeletonModel->getRig().getFlow(); - flow.init(isActive, isCollidable); auto &collisionSystem = flow.getCollisionSystem(); collisionSystem.setActive(isCollidable); auto physicsGroups = physicsConfig.keys(); diff --git a/libraries/animation/src/Flow.cpp b/libraries/animation/src/Flow.cpp index 974dd8dc54..86252b698d 100644 --- a/libraries/animation/src/Flow.cpp +++ b/libraries/animation/src/Flow.cpp @@ -197,7 +197,7 @@ void FlowNode::update(float deltaTime, const glm::vec3& accelerationOffset) { if (!_anchored) { // Add inertia const float FPS = 60.0f; - float timeRatio = (FPS * deltaTime); + float timeRatio = _scale * (FPS * deltaTime); float invertedTimeRatio = timeRatio > 0.0f ? 1.0f / timeRatio : 1.0f; auto deltaVelocity = _previousVelocity - _currentVelocity; auto centrifugeVector = glm::length(deltaVelocity) != 0.0f ? glm::normalize(deltaVelocity) : glm::vec3(); @@ -224,7 +224,7 @@ void FlowNode::solve(const glm::vec3& constrainPoint, float maxDistance, const F void FlowNode::solveConstraints(const glm::vec3& constrainPoint, float maxDistance) { glm::vec3 constrainVector = _currentPosition - constrainPoint; float difference = maxDistance / glm::length(constrainVector); - _currentPosition = difference < 1.0 ? constrainPoint + constrainVector * difference : _currentPosition; + _currentPosition = difference < 1.0f ? constrainPoint + constrainVector * difference : _currentPosition; }; void FlowNode::solveCollisions(const FlowCollisionResult& collision) { @@ -244,14 +244,13 @@ FlowJoint::FlowJoint(int jointIndex, int parentIndex, int childIndex, const QStr _group = group; _childIndex = childIndex; _parentIndex = parentIndex; - _node = FlowNode(glm::vec3(), settings); + FlowNode(glm::vec3(), settings); }; void FlowJoint::setInitialData(const glm::vec3& initialPosition, const glm::vec3& initialTranslation, const glm::quat& initialRotation, const glm::vec3& parentPosition) { _initialPosition = initialPosition; - _node._initialPosition = initialPosition; - _node._previousPosition = initialPosition; - _node._currentPosition = initialPosition; + _previousPosition = initialPosition; + _currentPosition = initialPosition; _initialTranslation = initialTranslation; _initialRotation = initialRotation; _translationDirection = glm::normalize(_initialTranslation); @@ -274,33 +273,48 @@ void FlowJoint::setRecoveryPosition(const glm::vec3& recoveryPosition) { void FlowJoint::update(float deltaTime) { glm::vec3 accelerationOffset = glm::vec3(0.0f); - if (_node._settings._stiffness > 0.0f) { - glm::vec3 recoveryVector = _recoveryPosition - _node._currentPosition; - float recoveryFactor = powf(_node._settings._stiffness, 3.0f); + if (_settings._stiffness > 0.0f) { + glm::vec3 recoveryVector = _recoveryPosition - _currentPosition; + float recoveryFactor = powf(_settings._stiffness, 3.0f); accelerationOffset = recoveryVector * recoveryFactor; } - _node.update(deltaTime, accelerationOffset); - if (_node._anchored) { + FlowNode::update(deltaTime, accelerationOffset); + if (_anchored) { if (!_isDummy) { - _node._currentPosition = _updatedPosition; + _currentPosition = _updatedPosition; } else { - _node._currentPosition = _parentPosition; + _currentPosition = _parentPosition; } } }; +void FlowJoint::setScale(float scale, bool initScale) { + if (initScale) { + _initialLength = _length / scale; + } + _settings._radius = _initialRadius * scale; + _length = _initialLength * scale; + _scale = scale; +} + void FlowJoint::solve(const FlowCollisionResult& collision) { - _node.solve(_parentPosition, _length, collision); + FlowNode::solve(_parentPosition, _length, collision); }; FlowDummyJoint::FlowDummyJoint(const glm::vec3& initialPosition, int index, int parentIndex, int childIndex, FlowPhysicsSettings settings) : FlowJoint(index, parentIndex, childIndex, DUMMY_KEYWORD + "_" + index, DUMMY_KEYWORD, settings) { _isDummy = true; _initialPosition = initialPosition; - _node = FlowNode(_initialPosition, settings); _length = DUMMY_JOINT_DISTANCE; } +void FlowDummyJoint::toIsolatedJoint(float length, int childIndex, const QString& group) { + _isDummy = false; + _length = length; + _childIndex = childIndex; + _group = group; + +} FlowThread::FlowThread(int rootIndex, std::map* joints) { _jointsPointer = joints; @@ -342,46 +356,38 @@ void FlowThread::computeFlowThread(int rootIndex) { void FlowThread::computeRecovery() { int parentIndex = _joints[0]; auto parentJoint = _jointsPointer->at(parentIndex); - _jointsPointer->at(parentIndex)._recoveryPosition = parentJoint._recoveryPosition = parentJoint._node._currentPosition; + _jointsPointer->at(parentIndex)._recoveryPosition = parentJoint._recoveryPosition = parentJoint._currentPosition; 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; - rotation = (i == 1) ? parentRotation : parentJoint._initialRotation; - _jointsPointer->at(_joints[i])._recoveryPosition = joint._recoveryPosition = parentJoint._recoveryPosition + (rotation * (joint._initialTranslation * 0.01f)); + _jointsPointer->at(_joints[i])._recoveryPosition = joint._recoveryPosition = parentJoint._recoveryPosition + (parentRotation * (joint._initialTranslation * 0.01f)); parentJoint = joint; } }; void FlowThread::update(float deltaTime) { - if (getActive()) { - _positions.clear(); - 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); - _positions.push_back(joint._node._currentPosition); - } + _positions.clear(); + auto &firstJoint = _jointsPointer->at(_joints[0]); + _radius = firstJoint._settings._radius; + computeRecovery(); + for (size_t i = 0; i < _joints.size(); i++) { + auto &joint = _jointsPointer->at(_joints[i]); + joint.update(deltaTime); + _positions.push_back(joint._currentPosition); } }; void FlowThread::solve(FlowCollisionSystem& collisionSystem) { - if (getActive()) { - if (collisionSystem.getActive()) { - auto bodyCollisions = collisionSystem.checkFlowThreadCollisions(this); - for (size_t i = 0; i < _joints.size(); i++) { - int index = _joints[i]; - _jointsPointer->at(index).solve(bodyCollisions[i]); - } - } else { - for (size_t i = 0; i < _joints.size(); i++) { - int index = _joints[i]; - _jointsPointer->at(index).solve(FlowCollisionResult()); - } + if (collisionSystem.getActive()) { + auto bodyCollisions = collisionSystem.checkFlowThreadCollisions(this); + for (size_t i = 0; i < _joints.size(); i++) { + int index = _joints[i]; + _jointsPointer->at(index).solve(bodyCollisions[i]); + } + } else { + for (size_t i = 0; i < _joints.size(); i++) { + int index = _joints[i]; + _jointsPointer->at(index).solve(FlowCollisionResult()); } } }; @@ -421,94 +427,102 @@ void FlowThread::computeJointRotations() { joint0 = joint1; joint1 = nextJoint; } -}; - -void FlowThread::apply() { - if (!getActive()) { - return; - } - computeJointRotations(); -}; - -bool FlowThread::getActive() { - return _jointsPointer->at(_joints[0])._node._active; -}; - -void Flow::init(bool isActive, bool isCollidable) { - if (isActive) { - if (!_initialized) { - calculateConstraints(); - } - } else { - cleanUp(); - } - + } -void Flow::calculateConstraints() { +void FlowThread::setScale(float scale, bool initScale) { + for (size_t i = 0; i < _joints.size(); i++) { + auto &joint = _jointsPointer->at(_joints[i]); + joint.setScale(scale, initScale); + } + resetLength(); +} + +FlowThread& FlowThread::operator=(const FlowThread& otherFlowThread) { + for (int jointIndex: otherFlowThread._joints) { + auto& joint = otherFlowThread._jointsPointer->at(jointIndex); + auto& myJoint = _jointsPointer->at(jointIndex); + myJoint._acceleration = joint._acceleration; + myJoint._currentPosition = joint._currentPosition; + myJoint._currentRotation = joint._currentRotation; + myJoint._currentVelocity = joint._currentVelocity; + myJoint._length = joint._length; + myJoint._parentPosition = joint._parentPosition; + myJoint._parentWorldRotation = joint._parentWorldRotation; + myJoint._previousPosition = joint._previousPosition; + myJoint._previousVelocity = joint._previousVelocity; + myJoint._scale = joint._scale; + myJoint._translationDirection = joint._translationDirection; + myJoint._updatedPosition = joint._updatedPosition; + myJoint._updatedRotation = joint._updatedRotation; + myJoint._updatedTranslation = joint._updatedTranslation; + } + return *this; +} + +void Flow::calculateConstraints(const std::shared_ptr& skeleton, + AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses) { cleanUp(); - if (!_rig) { + if (!skeleton) { return; } int rightHandIndex = -1; auto flowPrefix = FLOW_JOINT_PREFIX.toUpper(); auto simPrefix = SIM_JOINT_PREFIX.toUpper(); - auto skeleton = _rig->getAnimSkeleton(); std::vector handsIndices; - if (skeleton) { - for (int i = 0; i < skeleton->getNumJoints(); i++) { - auto name = skeleton->getJointName(i); - if (name == "RightHand") { - rightHandIndex = i; - } - if (std::find(HAND_COLLISION_JOINTS.begin(), HAND_COLLISION_JOINTS.end(), name) != HAND_COLLISION_JOINTS.end()) { - handsIndices.push_back(i); - } - auto parentIndex = skeleton->getParentIndex(i); - if (parentIndex == -1) { - continue; - } - auto jointChildren = skeleton->getChildrenOfJoint(i); - // auto childIndex = jointChildren.size() > 0 ? jointChildren[0] : -1; - auto group = QStringRef(&name, 0, 3).toString().toUpper(); - auto split = name.split("_"); - bool isSimJoint = (group == simPrefix); - bool isFlowJoint = split.size() > 2 && split[0].toUpper() == flowPrefix; - if (isFlowJoint || isSimJoint) { - group = ""; - if (isSimJoint) { - for (int j = 1; j < name.size() - 1; j++) { - bool toFloatSuccess; - 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, (int)simPrefix.size(), name.size() - 1).toString(); - } - qCDebug(animation) << "Sim joint added to flow: " << name; - } else { - group = split[1]; - } - if (!group.isEmpty()) { - _flowJointKeywords.push_back(group); - FlowPhysicsSettings jointSettings; - if (PRESET_FLOW_DATA.find(group) != PRESET_FLOW_DATA.end()) { - jointSettings = PRESET_FLOW_DATA.at(group); - } else { - jointSettings = DEFAULT_JOINT_SETTINGS; - } - if (_flowJointData.find(i) == _flowJointData.end()) { - auto flowJoint = FlowJoint(i, parentIndex, -1, name, group, jointSettings); - _flowJointData.insert(std::pair(i, flowJoint)); + + for (int i = 0; i < skeleton->getNumJoints(); i++) { + auto name = skeleton->getJointName(i); + if (name == "RightHand") { + rightHandIndex = i; + } + if (std::find(HAND_COLLISION_JOINTS.begin(), HAND_COLLISION_JOINTS.end(), name) != HAND_COLLISION_JOINTS.end()) { + handsIndices.push_back(i); + } + auto parentIndex = skeleton->getParentIndex(i); + if (parentIndex == -1) { + continue; + } + auto jointChildren = skeleton->getChildrenOfJoint(i); + // auto childIndex = jointChildren.size() > 0 ? jointChildren[0] : -1; + auto group = QStringRef(&name, 0, 3).toString().toUpper(); + auto split = name.split("_"); + bool isSimJoint = (group == simPrefix); + bool isFlowJoint = split.size() > 2 && split[0].toUpper() == flowPrefix; + if (isFlowJoint || isSimJoint) { + group = ""; + if (isSimJoint) { + for (int j = 1; j < name.size() - 1; j++) { + bool toFloatSuccess; + 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, (int)simPrefix.size(), name.size() - 1).toString(); + } + qCDebug(animation) << "Sim joint added to flow: " << name; } else { - if (PRESET_COLLISION_DATA.find(name) != PRESET_COLLISION_DATA.end()) { - _collisionSystem.addCollisionSphere(i, PRESET_COLLISION_DATA.at(name)); + group = split[1]; + } + if (!group.isEmpty()) { + _flowJointKeywords.push_back(group); + FlowPhysicsSettings jointSettings; + if (PRESET_FLOW_DATA.find(group) != PRESET_FLOW_DATA.end()) { + jointSettings = PRESET_FLOW_DATA.at(group); + } else { + jointSettings = DEFAULT_JOINT_SETTINGS; } + if (_flowJointData.find(i) == _flowJointData.end()) { + auto flowJoint = FlowJoint(i, parentIndex, -1, name, group, jointSettings); + _flowJointData.insert(std::pair(i, flowJoint)); + } + } + } else { + if (PRESET_COLLISION_DATA.find(name) != PRESET_COLLISION_DATA.end()) { + _collisionSystem.addCollisionSphere(i, PRESET_COLLISION_DATA.at(name)); } } } @@ -517,10 +531,10 @@ void Flow::calculateConstraints() { int jointIndex = jointData.first; glm::vec3 jointPosition, parentPosition, jointTranslation; glm::quat jointRotation; - _rig->getJointPositionInWorldFrame(jointIndex, jointPosition, _entityPosition, _entityRotation); - _rig->getJointPositionInWorldFrame(jointData.second._parentIndex, parentPosition, _entityPosition, _entityRotation); - _rig->getJointTranslation(jointIndex, jointTranslation); - _rig->getJointRotation(jointIndex, jointRotation); + getJointPositionInWorldFrame(absolutePoses, jointIndex, jointPosition, _entityPosition, _entityRotation); + getJointPositionInWorldFrame(absolutePoses, jointData.second.getParentIndex(), parentPosition, _entityPosition, _entityRotation); + getJointTranslation(relativePoses, jointIndex, jointTranslation); + getJointRotation(relativePoses, jointIndex, jointRotation); jointData.second.setInitialData(jointPosition, jointTranslation, jointRotation, parentPosition); } @@ -528,11 +542,11 @@ void Flow::calculateConstraints() { std::vector roots; for (auto &joint :_flowJointData) { - if (_flowJointData.find(joint.second._parentIndex) == _flowJointData.end()) { - joint.second._node._anchored = true; + if (_flowJointData.find(joint.second.getParentIndex()) == _flowJointData.end()) { + joint.second.setAnchored(true); roots.push_back(joint.first); } else { - _flowJointData[joint.second._parentIndex]._childIndex = joint.first; + _flowJointData[joint.second.getParentIndex()].setChildIndex(joint.first); } } @@ -543,15 +557,12 @@ void Flow::calculateConstraints() { if (thread._joints.size() == 1) { int jointIndex = roots[i]; auto joint = _flowJointData[jointIndex]; - auto jointPosition = joint._updatedPosition; - auto newSettings = FlowPhysicsSettings(joint._node._settings); + auto jointPosition = joint.getUpdatedPosition(); + auto newSettings = FlowPhysicsSettings(joint.getSettings()); newSettings._stiffness = ISOLATED_JOINT_STIFFNESS; int extraIndex = (int)_flowJointData.size(); auto newJoint = FlowDummyJoint(jointPosition, extraIndex, jointIndex, -1, newSettings); - newJoint._isDummy = false; - newJoint._length = ISOLATED_JOINT_LENGTH; - newJoint._childIndex = extraIndex; - newJoint._group = _flowJointData[jointIndex]._group; + newJoint.toIsolatedJoint(ISOLATED_JOINT_LENGTH, extraIndex, _flowJointData[jointIndex].getGroup()); thread = FlowThread(jointIndex, &_flowJointData); } _jointThreads.push_back(thread); @@ -559,13 +570,13 @@ void Flow::calculateConstraints() { } if (_jointThreads.size() == 0) { - _rig->clearJointStates(); + onCleanup(); } if (SHOW_DUMMY_JOINTS && rightHandIndex > -1) { int jointCount = (int)_flowJointData.size(); int extraIndex = (int)_flowJointData.size(); glm::vec3 rightHandPosition; - _rig->getJointPositionInWorldFrame(rightHandIndex, rightHandPosition, _entityPosition, _entityRotation); + getJointPositionInWorldFrame(absolutePoses, rightHandIndex, rightHandPosition, _entityPosition, _entityRotation); int parentIndex = rightHandIndex; for (int i = 0; i < DUMMY_JOINT_COUNT; i++) { int childIndex = (i == (DUMMY_JOINT_COUNT - 1)) ? -1 : extraIndex + 1; @@ -574,7 +585,7 @@ void Flow::calculateConstraints() { parentIndex = extraIndex; extraIndex++; } - _flowJointData[jointCount]._node._anchored = true; + _flowJointData[jointCount].setAnchored(true); auto extraThread = FlowThread(jointCount, &_flowJointData); _jointThreads.push_back(extraThread); @@ -596,70 +607,70 @@ void Flow::cleanUp() { _collisionSystem.resetCollisions(); _initialized = false; _isScaleSet = false; - _active = false; - if (_rig) { - _rig->clearJointStates(); - } - + onCleanup(); } void Flow::setTransform(float scale, const glm::vec3& position, const glm::quat& rotation) { _scale = scale; _entityPosition = position; _entityRotation = rotation; - _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(); + _jointThreads[i].setScale(_scale, !_isScaleSet); } + if (_lastScale != _scale) { + _lastScale = _scale; + _isScaleSet = true; + } + } -void Flow::update(float deltaTime) { +void Flow::update(float deltaTime, AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses, const std::vector& overrideFlags) { if (_initialized && _active) { uint64_t startTime = usecTimestampNow(); uint64_t updateExpiry = startTime + MAX_UPDATE_FLOW_TIME_BUDGET; if (_scale != _lastScale) { 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(_collisionSystem); - if (!updateRootFramePositions(index)) { + if (!updateRootFramePositions(absolutePoses, index)) { return; } - thread.apply(); + thread.computeJointRotations(); if (usecTimestampNow() > updateExpiry) { break; - qWarning(animation) << "Flow Bones ran out of time updating threads"; + qWarning(animation) << "Flow Bones ran out of time while updating threads"; } } - setJoints(); + setJoints(relativePoses, overrideFlags); + updateJoints(relativePoses, absolutePoses); _invertThreadLoop = !_invertThreadLoop; } } -bool Flow::worldToJointPoint(const glm::vec3& position, const int jointIndex, glm::vec3& jointSpacePosition) const { +void Flow::updateAbsolutePoses(const AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses) { + for (auto &joint : _flowJointData) { + int index = joint.second.getIndex(); + int parentIndex = joint.second.getParentIndex(); + if (index >= 0 && index < relativePoses.size() && + parentIndex >= 0 && parentIndex < absolutePoses.size()) { + absolutePoses[index] = absolutePoses[parentIndex] * relativePoses[index]; + } + } +} + +bool Flow::worldToJointPoint(const AnimPoseVec& absolutePoses, const glm::vec3& position, const int jointIndex, glm::vec3& jointSpacePosition) const { glm::vec3 jointPos; glm::quat jointRot; - if (_rig->getJointPositionInWorldFrame(jointIndex, jointPos, _entityPosition, _entityRotation) && _rig->getJointRotationInWorldFrame(jointIndex, jointRot, _entityRotation)) { + if (getJointPositionInWorldFrame(absolutePoses, jointIndex, jointPos, _entityPosition, _entityRotation) && + getJointRotationInWorldFrame(absolutePoses, jointIndex, jointRot, _entityRotation)) { glm::vec3 modelOffset = position - jointPos; jointSpacePosition = glm::inverse(jointRot) * modelOffset; return true; @@ -667,13 +678,13 @@ bool Flow::worldToJointPoint(const glm::vec3& position, const int jointIndex, gl return false; } -bool Flow::updateRootFramePositions(size_t threadIndex) { +bool Flow::updateRootFramePositions(const AnimPoseVec& absolutePoses, size_t threadIndex) { auto &joints = _jointThreads[threadIndex]._joints; - int rootIndex = _flowJointData[joints[0]]._parentIndex; + int rootIndex = _flowJointData[joints[0]].getParentIndex(); _jointThreads[threadIndex]._rootFramePositions.clear(); for (size_t j = 0; j < joints.size(); j++) { glm::vec3 jointPos; - if (worldToJointPoint(_flowJointData[joints[j]]._node._currentPosition, rootIndex, jointPos)) { + if (worldToJointPoint(absolutePoses, _flowJointData[joints[j]].getCurrentPosition(), rootIndex, jointPos)) { _jointThreads[threadIndex]._rootFramePositions.push_back(jointPos); } else { return false; @@ -682,35 +693,38 @@ bool Flow::updateRootFramePositions(size_t threadIndex) { return true; } -void Flow::updateJoints() { +void Flow::updateJoints(AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses) { + updateAbsolutePoses(relativePoses, absolutePoses); for (auto &jointData : _flowJointData) { int jointIndex = jointData.first; glm::vec3 jointPosition, parentPosition, jointTranslation; glm::quat jointRotation, parentWorldRotation; - _rig->getJointPositionInWorldFrame(jointIndex, jointPosition, _entityPosition, _entityRotation); - _rig->getJointPositionInWorldFrame(jointData.second._parentIndex, parentPosition, _entityPosition, _entityRotation); - _rig->getJointTranslation(jointIndex, jointTranslation); - _rig->getJointRotation(jointIndex, jointRotation); - _rig->getJointRotationInWorldFrame(jointData.second._parentIndex, parentWorldRotation, _entityRotation); + getJointPositionInWorldFrame(absolutePoses, jointIndex, jointPosition, _entityPosition, _entityRotation); + getJointPositionInWorldFrame(absolutePoses, jointData.second.getParentIndex(), parentPosition, _entityPosition, _entityRotation); + getJointTranslation(relativePoses, jointIndex, jointTranslation); + getJointRotation(relativePoses, jointIndex, jointRotation); + getJointRotationInWorldFrame(absolutePoses, jointData.second.getParentIndex(), parentWorldRotation, _entityRotation); jointData.second.setUpdatedData(jointPosition, jointTranslation, jointRotation, parentPosition, parentWorldRotation); } auto &selfCollisions = _collisionSystem.getSelfCollisions(); for (auto &collision : selfCollisions) { glm::quat jointRotation; - _rig->getJointPositionInWorldFrame(collision._jointIndex, collision._position, _entityPosition, _entityRotation); - _rig->getJointRotationInWorldFrame(collision._jointIndex, jointRotation, _entityRotation); + getJointPositionInWorldFrame(absolutePoses, collision._jointIndex, collision._position, _entityPosition, _entityRotation); + getJointRotationInWorldFrame(absolutePoses, collision._jointIndex, jointRotation, _entityRotation); glm::vec3 worldOffset = jointRotation * collision._offset; collision._position = collision._position + worldOffset; } _collisionSystem.prepareCollisions(); } -void Flow::setJoints() { +void Flow::setJoints(AnimPoseVec& relativePoses, const std::vector& overrideFlags) { for (auto &thread : _jointThreads) { auto &joints = thread._joints; for (int jointIndex : joints) { auto &joint = _flowJointData[jointIndex]; - _rig->setJointRotation(jointIndex, true, joint._currentRotation, 2.0f); + if (jointIndex >= 0 && jointIndex < (int)relativePoses.size() && !overrideFlags[jointIndex]) { + relativePoses[jointIndex].rot() = joint.getCurrentRotation(); + } } } } @@ -724,8 +738,61 @@ void Flow::setOthersCollision(const QUuid& otherId, int jointIndex, const glm::v void Flow::setPhysicsSettingsForGroup(const QString& group, const FlowPhysicsSettings& settings) { for (auto &joint : _flowJointData) { - if (joint.second._group.toUpper() == group.toUpper()) { - joint.second._node._settings = settings; + if (joint.second.getGroup().toUpper() == group.toUpper()) { + joint.second.setSettings(settings); } } +} + +bool Flow::getJointPositionInWorldFrame(const AnimPoseVec& absolutePoses, int jointIndex, glm::vec3& position, glm::vec3 translation, glm::quat rotation) const { + if (jointIndex >= 0 && jointIndex < (int)absolutePoses.size()) { + glm::vec3 poseSetTrans = absolutePoses[jointIndex].trans(); + position = (rotation * poseSetTrans) + translation; + if (!isNaN(position)) { + return true; + } else { + position = glm::vec3(0.0f); + } + } + return false; +} + +bool Flow::getJointRotationInWorldFrame(const AnimPoseVec& absolutePoses, int jointIndex, glm::quat& result, const glm::quat& rotation) const { + if (jointIndex >= 0 && jointIndex < (int)absolutePoses.size()) { + result = rotation * absolutePoses[jointIndex].rot(); + return true; + } else { + return false; + } +} + +bool Flow::getJointRotation(const AnimPoseVec& relativePoses, int jointIndex, glm::quat& rotation) const { + if (jointIndex >= 0 && jointIndex < (int)relativePoses.size()) { + rotation = relativePoses[jointIndex].rot(); + return true; + } else { + return false; + } +} + +bool Flow::getJointTranslation(const AnimPoseVec& relativePoses, int jointIndex, glm::vec3& translation) const { + if (jointIndex >= 0 && jointIndex < (int)relativePoses.size()) { + translation = relativePoses[jointIndex].trans(); + return true; + } else { + return false; + } +} + +Flow& Flow::operator=(const Flow& otherFlow) { + _active = otherFlow.getActive(); + _scale = otherFlow.getScale(); + _isScaleSet = true; + auto &threads = otherFlow.getThreads(); + if (threads.size() == _jointThreads.size()) { + for (size_t i = 0; i < _jointThreads.size(); i++) { + _jointThreads[i] = threads[i]; + } + } + return *this; } \ No newline at end of file diff --git a/libraries/animation/src/Flow.h b/libraries/animation/src/Flow.h index bb15846b5e..e3e20e25f9 100644 --- a/libraries/animation/src/Flow.h +++ b/libraries/animation/src/Flow.h @@ -17,6 +17,7 @@ #include #include #include +#include "AnimPose.h" class Rig; class AnimSkeleton; @@ -175,6 +176,13 @@ class FlowNode { public: FlowNode() {}; FlowNode(const glm::vec3& initialPosition, FlowPhysicsSettings settings); + + void update(float deltaTime, const glm::vec3& accelerationOffset); + void solve(const glm::vec3& constrainPoint, float maxDistance, const FlowCollisionResult& collision); + void solveConstraints(const glm::vec3& constrainPoint, float maxDistance); + void solveCollisions(const FlowCollisionResult& collision); + +protected: FlowPhysicsSettings _settings; glm::vec3 _initialPosition; @@ -194,15 +202,14 @@ public: bool _colliding { false }; bool _active { true }; - void update(float deltaTime, const glm::vec3& accelerationOffset); - void solve(const glm::vec3& constrainPoint, float maxDistance, const FlowCollisionResult& collision); - void solveConstraints(const glm::vec3& constrainPoint, float maxDistance); - void solveCollisions(const FlowCollisionResult& collision); + float _scale{ 1.0f }; }; -class FlowJoint { +class FlowJoint : public FlowNode { public: - FlowJoint() {}; + friend class FlowThread; + + FlowJoint(): FlowNode() {}; FlowJoint(int jointIndex, int parentIndex, int childIndex, const QString& name, const QString& group, const FlowPhysicsSettings& settings); void setInitialData(const glm::vec3& initialPosition, const glm::vec3& initialTranslation, const glm::quat& initialRotation, const glm::vec3& parentPosition); void setUpdatedData(const glm::vec3& updatedPosition, const glm::vec3& updatedTranslation, const glm::quat& updatedRotation, const glm::vec3& parentPosition, const glm::quat& parentWorldRotation); @@ -210,13 +217,30 @@ public: void update(float deltaTime); void solve(const FlowCollisionResult& collision); + void setScale(float scale, bool initScale); + bool isAnchored() { return _anchored; } + void setAnchored(bool anchored) { _anchored = anchored; } + + const FlowPhysicsSettings& getSettings() { return _settings; } + void setSettings(const FlowPhysicsSettings& settings) { _settings = settings; } + + const glm::vec3& getCurrentPosition() { return _currentPosition; } + int getIndex() { return _index; } + int getParentIndex() { return _parentIndex; } + void setChildIndex(int index) { _childIndex = index; } + const glm::vec3& getUpdatedPosition() { return _updatedPosition; } + const QString& getGroup() { return _group; } + const glm::quat& getCurrentRotation() { return _currentRotation; } + +protected: + int _index{ -1 }; int _parentIndex{ -1 }; int _childIndex{ -1 }; QString _name; QString _group; bool _isDummy{ false }; - glm::vec3 _initialPosition; + glm::vec3 _initialTranslation; glm::quat _initialRotation; @@ -229,24 +253,26 @@ public: glm::vec3 _parentPosition; glm::quat _parentWorldRotation; - - FlowNode _node; glm::vec3 _translationDirection; - float _scale { 1.0f }; + float _length { 0.0f }; float _initialLength { 0.0f }; + bool _applyRecovery { false }; }; class FlowDummyJoint : public FlowJoint { public: FlowDummyJoint(const glm::vec3& initialPosition, int index, int parentIndex, int childIndex, FlowPhysicsSettings settings); + void toIsolatedJoint(float length, int childIndex, const QString& group); }; class FlowThread { public: FlowThread() {}; + FlowThread& operator=(const FlowThread& otherFlowThread); + FlowThread(int rootIndex, std::map* joints); void resetLength(); @@ -255,9 +281,8 @@ public: void update(float deltaTime); void solve(FlowCollisionSystem& collisionSystem); void computeJointRotations(); - void apply(); - bool getActive(); void setRootFramePositions(const std::vector& rootFramePositions) { _rootFramePositions = rootFramePositions; } + void setScale(float scale, bool initScale = false); std::vector _joints; std::vector _positions; @@ -267,27 +292,41 @@ public: std::vector _rootFramePositions; }; -class Flow { +class Flow : public QObject{ + Q_OBJECT public: - Flow(Rig* rig) { _rig = rig; }; - void init(bool isActive, bool isCollidable); - bool isActive() { return _active; } - void calculateConstraints(); - void update(float deltaTime); + Flow() { } + Flow& operator=(const Flow& otherFlow); + bool getActive() const { return _active; } + void setActive(bool active) { _active = active; } + bool isInitialized() const { return _initialized; } + float getScale() const { return _scale; } + void calculateConstraints(const std::shared_ptr& skeleton, AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses); + void update(float deltaTime, AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses, const std::vector& overrideFlags); void setTransform(float scale, const glm::vec3& position, const glm::quat& rotation); const std::map& getJoints() const { return _flowJointData; } const std::vector& getThreads() const { return _jointThreads; } void setOthersCollision(const QUuid& otherId, int jointIndex, const glm::vec3& position); FlowCollisionSystem& getCollisionSystem() { return _collisionSystem; } void setPhysicsSettingsForGroup(const QString& group, const FlowPhysicsSettings& settings); -private: - void setJoints(); void cleanUp(); - void updateJoints(); - bool updateRootFramePositions(size_t threadIndex); - bool worldToJointPoint(const glm::vec3& position, const int jointIndex, glm::vec3& jointSpacePosition) const; + +signals: + void onCleanup(); + +private: + void updateAbsolutePoses(const AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses); + bool getJointPositionInWorldFrame(const AnimPoseVec& absolutePoses, int jointIndex, glm::vec3& position, glm::vec3 translation, glm::quat rotation) const; + bool getJointRotationInWorldFrame(const AnimPoseVec& absolutePoses, int jointIndex, glm::quat& result, const glm::quat& rotation) const; + bool getJointRotation(const AnimPoseVec& relativePoses, int jointIndex, glm::quat& rotation) const; + bool getJointTranslation(const AnimPoseVec& relativePoses, int jointIndex, glm::vec3& translation) const; + bool worldToJointPoint(const AnimPoseVec& absolutePoses, const glm::vec3& position, const int jointIndex, glm::vec3& jointSpacePosition) const; + + void setJoints(AnimPoseVec& relativePoses, const std::vector& overrideFlags); + void updateJoints(AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses); + bool updateRootFramePositions(const AnimPoseVec& absolutePoses, size_t threadIndex); void setScale(float scale); - Rig* _rig; + float _scale { 1.0f }; float _lastScale{ 1.0f }; glm::vec3 _entityPosition; diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 8cc5fcc337..eb02f07e62 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -74,7 +74,7 @@ static const QString MAIN_STATE_MACHINE_RIGHT_FOOT_ROTATION("mainStateMachineRig static const QString MAIN_STATE_MACHINE_RIGHT_FOOT_POSITION("mainStateMachineRightFootPosition"); -Rig::Rig() : _flow(this) { +Rig::Rig() { // Ensure thread-safe access to the rigRegistry. std::lock_guard guard(rigRegistryMutex); @@ -361,7 +361,6 @@ void Rig::reset(const HFMModel& hfmModel) { _animSkeleton = std::make_shared(hfmModel); - _internalPoseSet._relativePoses.clear(); _internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses(); @@ -745,7 +744,8 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos glm::vec3 forward = worldRotation * IDENTITY_FORWARD; glm::vec3 workingVelocity = worldVelocity; - _flow.setTransform(sensorToWorldScale, worldPosition, worldRotation * Quaternions::Y_180); + _internalFlow.setTransform(sensorToWorldScale, worldPosition, worldRotation * Quaternions::Y_180); + _networkFlow.setTransform(sensorToWorldScale, worldPosition, worldRotation * Quaternions::Y_180); { glm::vec3 localVel = glm::inverse(worldRotation) * workingVelocity; @@ -1209,10 +1209,21 @@ void Rig::updateAnimations(float deltaTime, const glm::mat4& rootTransform, cons } applyOverridePoses(); - buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses); - buildAbsoluteRigPoses(_networkPoseSet._relativePoses, _networkPoseSet._absolutePoses); + + buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses); + _internalFlow.update(deltaTime, _internalPoseSet._relativePoses, _internalPoseSet._absolutePoses, _internalPoseSet._overrideFlags); + + if (_sendNetworkNode) { + if (_internalFlow.getActive() && !_networkFlow.getActive()) { + _networkFlow = _internalFlow; + } + buildAbsoluteRigPoses(_networkPoseSet._relativePoses, _networkPoseSet._absolutePoses); + _networkFlow.update(deltaTime, _networkPoseSet._relativePoses, _networkPoseSet._absolutePoses, _internalPoseSet._overrideFlags); + } else if (_networkFlow.getActive()) { + _networkFlow.setActive(false); + } + // copy internal poses to external poses - _flow.update(deltaTime); { QWriteLocker writeLock(&_externalPoseSetLock); @@ -1899,11 +1910,15 @@ void Rig::initAnimGraph(const QUrl& url) { connect(_networkLoader.get(), &AnimNodeLoader::error, [networkUrl](int error, QString str) { qCritical(animation) << "Error loading: code = " << error << "str =" << str; }); + + /* connect(this, &Rig::onLoadComplete, [&]() { - if (_flow.isActive()) { - _flow.calculateConstraints(); + if (_internalFlow.getActive()) { + _internalFlow.calculateConstraints(_animSkeleton, _internalPoseSet._relativePoses, _internalPoseSet._absolutePoses); + _networkFlow.calculateConstraints(_animSkeleton, _internalPoseSet._relativePoses, _internalPoseSet._absolutePoses); } }); + */ } } @@ -2111,3 +2126,15 @@ void Rig::computeAvatarBoundingCapsule( glm::vec3 capsuleCenter = transformPoint(_geometryToRigTransform, (0.5f * (totalExtents.maximum + totalExtents.minimum))); localOffsetOut = capsuleCenter - hipsPosition; } + +void Rig::initFlow(bool isActive) { + _internalFlow.setActive(isActive); + if (isActive) { + if (!_internalFlow.isInitialized()) { + _internalFlow.calculateConstraints(_animSkeleton, _internalPoseSet._relativePoses, _internalPoseSet._absolutePoses); + _networkFlow.calculateConstraints(_animSkeleton, _internalPoseSet._relativePoses, _internalPoseSet._absolutePoses); + } + } else { + _internalFlow.cleanUp(); + } +} \ No newline at end of file diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 47c9697dac..2f0e2ad65b 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -234,8 +234,9 @@ public: const AnimContext::DebugAlphaMap& getDebugAlphaMap() const { return _lastContext.getDebugAlphaMap(); } const AnimVariantMap& getAnimVars() const { return _lastAnimVars; } const AnimContext::DebugStateMachineMap& getStateMachineMap() const { return _lastContext.getStateMachineMap(); } - void computeFlowSkeleton() { _flow.calculateConstraints(); } - Flow& getFlow() { return _flow; } + void initFlow(bool isActive); + Flow& getFlow() { return _internalFlow; } + signals: void onLoadComplete(); @@ -427,7 +428,8 @@ protected: SnapshotBlendPoseHelper _hipsBlendHelper; ControllerParameters _previousControllerParameters; - Flow _flow; + Flow _internalFlow; + Flow _networkFlow; }; #endif /* defined(__hifi__Rig__) */ diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 3b1065a3ca..be5eea5161 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -729,18 +729,15 @@ void Avatar::postUpdate(float deltaTime, const render::ScenePointer& scene) { } const bool DEBUG_FLOW = true; if (_skeletonModel->isLoaded() && DEBUG_FLOW) { - auto flow = _skeletonModel->getRig().getFlow(); - auto joints = flow.getJoints(); - auto threads = flow.getThreads(); + Flow* flow = _skeletonModel->getRig().getFlow(); + auto joints = flow->getJoints(); + auto threads = flow->getThreads(); for (auto &thread : threads) { auto& jointIndexes = thread._joints; for (size_t i = 1; i < jointIndexes.size(); i++) { auto index1 = jointIndexes[i - 1]; auto index2 = jointIndexes[i]; - // glm::vec3 pos1 = joint.second._node._currentPosition; - // glm::vec3 pos2 = joints.find(joint.second._parentIndex) != joints.end() ? joints[joint.second._parentIndex]._node._currentPosition : getJointPosition(joint.second._parentIndex); - // DebugDraw::getInstance().drawRay(pos1, pos2, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); - DebugDraw::getInstance().drawRay(joints[index1]._node._currentPosition, joints[index2]._node._currentPosition, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); + DebugDraw::getInstance().drawRay(joints[index1].getCurrentPosition(), joints[index2].getCurrentPosition(), glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); } } } From fa44687de6caad2ee9242f504948174a9758db71 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Wed, 20 Feb 2019 09:22:39 -0700 Subject: [PATCH 13/16] fix errors and remove debug draw --- libraries/animation/src/Flow.cpp | 4 ++-- .../src/avatars-renderer/Avatar.cpp | 14 -------------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/libraries/animation/src/Flow.cpp b/libraries/animation/src/Flow.cpp index 86252b698d..480ded2002 100644 --- a/libraries/animation/src/Flow.cpp +++ b/libraries/animation/src/Flow.cpp @@ -659,8 +659,8 @@ void Flow::updateAbsolutePoses(const AnimPoseVec& relativePoses, AnimPoseVec& ab for (auto &joint : _flowJointData) { int index = joint.second.getIndex(); int parentIndex = joint.second.getParentIndex(); - if (index >= 0 && index < relativePoses.size() && - parentIndex >= 0 && parentIndex < absolutePoses.size()) { + if (index >= 0 && index < (int)relativePoses.size() && + parentIndex >= 0 && parentIndex < (int)absolutePoses.size()) { absolutePoses[index] = absolutePoses[parentIndex] * relativePoses[index]; } } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index be5eea5161..e6881b0efe 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -727,20 +727,6 @@ void Avatar::postUpdate(float deltaTime, const render::ScenePointer& scene) { DebugDraw::getInstance().drawRay(rightEyePosition, rightEyePosition + rightEyeRotation * Vectors::UNIT_Z * EYE_RAY_LENGTH, RED); } } - const bool DEBUG_FLOW = true; - if (_skeletonModel->isLoaded() && DEBUG_FLOW) { - Flow* flow = _skeletonModel->getRig().getFlow(); - auto joints = flow->getJoints(); - auto threads = flow->getThreads(); - for (auto &thread : threads) { - auto& jointIndexes = thread._joints; - for (size_t i = 1; i < jointIndexes.size(); i++) { - auto index1 = jointIndexes[i - 1]; - auto index2 = jointIndexes[i]; - DebugDraw::getInstance().drawRay(joints[index1].getCurrentPosition(), joints[index2].getCurrentPosition(), glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); - } - } - } fixupModelsInScene(scene); updateFitBoundingBox(); From bea7680864f4d7f39621701fce973f925169934c Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Wed, 20 Feb 2019 10:57:11 -0700 Subject: [PATCH 14/16] Fix shared_ptr not part of std error --- libraries/animation/src/Flow.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/animation/src/Flow.h b/libraries/animation/src/Flow.h index e3e20e25f9..5fe7b7acbc 100644 --- a/libraries/animation/src/Flow.h +++ b/libraries/animation/src/Flow.h @@ -11,6 +11,7 @@ #ifndef hifi_Flow_h #define hifi_Flow_h +#include #include #include #include From ec4d069011c6dea61029644222a22a10128d1fef Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 21 Feb 2019 12:00:19 -0700 Subject: [PATCH 15/16] Allow threads with only one joint, remove dummy joints and unused constants --- libraries/animation/src/Flow.cpp | 79 ++++++++++++++------------------ libraries/animation/src/Flow.h | 47 ++++++------------- libraries/animation/src/Rig.cpp | 11 ++--- 3 files changed, 54 insertions(+), 83 deletions(-) diff --git a/libraries/animation/src/Flow.cpp b/libraries/animation/src/Flow.cpp index 480ded2002..9fb0306fa3 100644 --- a/libraries/animation/src/Flow.cpp +++ b/libraries/animation/src/Flow.cpp @@ -252,6 +252,7 @@ void FlowJoint::setInitialData(const glm::vec3& initialPosition, const glm::vec3 _previousPosition = initialPosition; _currentPosition = initialPosition; _initialTranslation = initialTranslation; + _currentRotation = initialRotation; _initialRotation = initialRotation; _translationDirection = glm::normalize(_initialTranslation); _parentPosition = parentPosition; @@ -280,7 +281,7 @@ void FlowJoint::update(float deltaTime) { } FlowNode::update(deltaTime, accelerationOffset); if (_anchored) { - if (!_isDummy) { + if (!_isHelper) { _currentPosition = _updatedPosition; } else { _currentPosition = _parentPosition; @@ -301,19 +302,10 @@ void FlowJoint::solve(const FlowCollisionResult& collision) { FlowNode::solve(_parentPosition, _length, collision); }; -FlowDummyJoint::FlowDummyJoint(const glm::vec3& initialPosition, int index, int parentIndex, int childIndex, FlowPhysicsSettings settings) : - FlowJoint(index, parentIndex, childIndex, DUMMY_KEYWORD + "_" + index, DUMMY_KEYWORD, settings) { - _isDummy = true; +void FlowJoint::toHelperJoint(const glm::vec3& initialPosition, float length) { _initialPosition = initialPosition; - _length = DUMMY_JOINT_DISTANCE; -} - -void FlowDummyJoint::toIsolatedJoint(float length, int childIndex, const QString& group) { - _isDummy = false; + _isHelper = true; _length = length; - _childIndex = childIndex; - _group = group; - } FlowThread::FlowThread(int rootIndex, std::map* joints) { @@ -344,6 +336,7 @@ void FlowThread::computeFlowThread(int rootIndex) { break; } } + _length = 0.0f; for (size_t i = 0; i < indexes.size(); i++) { int index = indexes[i]; _joints.push_back(index); @@ -456,6 +449,7 @@ FlowThread& FlowThread::operator=(const FlowThread& otherFlowThread) { myJoint._updatedPosition = joint._updatedPosition; myJoint._updatedRotation = joint._updatedRotation; myJoint._updatedTranslation = joint._updatedTranslation; + myJoint._isHelper = joint._isHelper; } return *this; } @@ -532,9 +526,9 @@ void Flow::calculateConstraints(const std::shared_ptr& skeleton, glm::vec3 jointPosition, parentPosition, jointTranslation; glm::quat jointRotation; getJointPositionInWorldFrame(absolutePoses, jointIndex, jointPosition, _entityPosition, _entityRotation); - getJointPositionInWorldFrame(absolutePoses, jointData.second.getParentIndex(), parentPosition, _entityPosition, _entityRotation); getJointTranslation(relativePoses, jointIndex, jointTranslation); getJointRotation(relativePoses, jointIndex, jointRotation); + getJointPositionInWorldFrame(absolutePoses, jointData.second.getParentIndex(), parentPosition, _entityPosition, _entityRotation); jointData.second.setInitialData(jointPosition, jointTranslation, jointRotation, parentPosition); } @@ -549,47 +543,36 @@ void Flow::calculateConstraints(const std::shared_ptr& skeleton, _flowJointData[joint.second.getParentIndex()].setChildIndex(joint.first); } } - + int extraIndex = -1; for (size_t i = 0; i < roots.size(); i++) { FlowThread thread = FlowThread(roots[i], &_flowJointData); // add threads with at least 2 joints if (thread._joints.size() > 0) { if (thread._joints.size() == 1) { int jointIndex = roots[i]; - auto joint = _flowJointData[jointIndex]; - auto jointPosition = joint.getUpdatedPosition(); - auto newSettings = FlowPhysicsSettings(joint.getSettings()); - newSettings._stiffness = ISOLATED_JOINT_STIFFNESS; - int extraIndex = (int)_flowJointData.size(); - auto newJoint = FlowDummyJoint(jointPosition, extraIndex, jointIndex, -1, newSettings); - newJoint.toIsolatedJoint(ISOLATED_JOINT_LENGTH, extraIndex, _flowJointData[jointIndex].getGroup()); - thread = FlowThread(jointIndex, &_flowJointData); + auto &joint = _flowJointData[jointIndex]; + auto &jointPosition = joint.getUpdatedPosition(); + auto newSettings = joint.getSettings(); + extraIndex = extraIndex > -1 ? extraIndex + 1 : skeleton->getNumJoints(); + joint.setChildIndex(extraIndex); + auto newJoint = FlowJoint(extraIndex, jointIndex, -1, joint.getName(), joint.getGroup(), newSettings); + newJoint.toHelperJoint(jointPosition, HELPER_JOINT_LENGTH); + glm::vec3 translation = glm::vec3(0.0f, HELPER_JOINT_LENGTH, 0.0f); + newJoint.setInitialData(jointPosition + translation, 100.0f * translation , Quaternions::IDENTITY, jointPosition); + _flowJointData.insert(std::pair(extraIndex, newJoint)); + FlowThread newThread = FlowThread(jointIndex, &_flowJointData); + if (newThread._joints.size() > 1) { + _jointThreads.push_back(newThread); + } + } else { + _jointThreads.push_back(thread); } - _jointThreads.push_back(thread); } } if (_jointThreads.size() == 0) { onCleanup(); } - if (SHOW_DUMMY_JOINTS && rightHandIndex > -1) { - int jointCount = (int)_flowJointData.size(); - int extraIndex = (int)_flowJointData.size(); - glm::vec3 rightHandPosition; - getJointPositionInWorldFrame(absolutePoses, rightHandIndex, rightHandPosition, _entityPosition, _entityRotation); - int parentIndex = rightHandIndex; - for (int i = 0; i < DUMMY_JOINT_COUNT; i++) { - int childIndex = (i == (DUMMY_JOINT_COUNT - 1)) ? -1 : extraIndex + 1; - auto newJoint = FlowDummyJoint(rightHandPosition, extraIndex, parentIndex, childIndex, DEFAULT_JOINT_SETTINGS); - _flowJointData.insert(std::pair(extraIndex, newJoint)); - parentIndex = extraIndex; - extraIndex++; - } - _flowJointData[jointCount].setAnchored(true); - - auto extraThread = FlowThread(jointCount, &_flowJointData); - _jointThreads.push_back(extraThread); - } if (handsIndices.size() > 0) { FlowCollisionSettings handSettings; handSettings._radius = HAND_COLLISION_RADIUS; @@ -699,10 +682,16 @@ void Flow::updateJoints(AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses) int jointIndex = jointData.first; glm::vec3 jointPosition, parentPosition, jointTranslation; glm::quat jointRotation, parentWorldRotation; - getJointPositionInWorldFrame(absolutePoses, jointIndex, jointPosition, _entityPosition, _entityRotation); + if (!jointData.second.isHelper()) { + getJointPositionInWorldFrame(absolutePoses, jointIndex, jointPosition, _entityPosition, _entityRotation); + getJointTranslation(relativePoses, jointIndex, jointTranslation); + getJointRotation(relativePoses, jointIndex, jointRotation); + } else { + jointPosition = jointData.second.getCurrentPosition(); + jointTranslation = jointData.second.getCurrentTranslation(); + jointRotation = jointData.second.getCurrentRotation(); + } getJointPositionInWorldFrame(absolutePoses, jointData.second.getParentIndex(), parentPosition, _entityPosition, _entityRotation); - getJointTranslation(relativePoses, jointIndex, jointTranslation); - getJointRotation(relativePoses, jointIndex, jointRotation); getJointRotationInWorldFrame(absolutePoses, jointData.second.getParentIndex(), parentWorldRotation, _entityRotation); jointData.second.setUpdatedData(jointPosition, jointTranslation, jointRotation, parentPosition, parentWorldRotation); } @@ -753,7 +742,7 @@ bool Flow::getJointPositionInWorldFrame(const AnimPoseVec& absolutePoses, int jo } else { position = glm::vec3(0.0f); } - } + } return false; } diff --git a/libraries/animation/src/Flow.h b/libraries/animation/src/Flow.h index 5fe7b7acbc..35464e9420 100644 --- a/libraries/animation/src/Flow.h +++ b/libraries/animation/src/Flow.h @@ -23,11 +23,6 @@ class Rig; class AnimSkeleton; -const bool SHOW_DUMMY_JOINTS = false; - -const int LEFT_HAND = 0; -const int RIGHT_HAND = 1; - const float HAPTIC_TOUCH_STRENGTH = 0.25f; const float HAPTIC_TOUCH_DURATION = 10.0f; const float HAPTIC_SLOPE = 0.18f; @@ -38,19 +33,8 @@ const QString SIM_JOINT_PREFIX = "sim"; const std::vector HAND_COLLISION_JOINTS = { "RightHandMiddle1", "RightHandThumb3", "LeftHandMiddle1", "LeftHandThumb3", "RightHandMiddle3", "LeftHandMiddle3" }; -const QString JOINT_COLLISION_PREFIX = "joint_"; -const QString HAND_COLLISION_PREFIX = "hand_"; const float HAND_COLLISION_RADIUS = 0.03f; -const float HAND_TOUCHING_DISTANCE = 2.0f; - -const int COLLISION_SHAPES_LIMIT = 4; - -const QString DUMMY_KEYWORD = "Extra"; -const int DUMMY_JOINT_COUNT = 8; -const float DUMMY_JOINT_DISTANCE = 0.05f; - -const float ISOLATED_JOINT_STIFFNESS = 0.0f; -const float ISOLATED_JOINT_LENGTH = 0.05f; +const float HELPER_JOINT_LENGTH = 0.05f; const float DEFAULT_STIFFNESS = 0.0f; const float DEFAULT_GRAVITY = -0.0096f; @@ -212,6 +196,7 @@ public: FlowJoint(): FlowNode() {}; FlowJoint(int jointIndex, int parentIndex, int childIndex, const QString& name, const QString& group, const FlowPhysicsSettings& settings); + void toHelperJoint(const glm::vec3& initialPosition, float length); void setInitialData(const glm::vec3& initialPosition, const glm::vec3& initialTranslation, const glm::quat& initialRotation, const glm::vec3& parentPosition); void setUpdatedData(const glm::vec3& updatedPosition, const glm::vec3& updatedTranslation, const glm::quat& updatedRotation, const glm::vec3& parentPosition, const glm::quat& parentWorldRotation); void setRecoveryPosition(const glm::vec3& recoveryPosition); @@ -219,19 +204,23 @@ public: void solve(const FlowCollisionResult& collision); void setScale(float scale, bool initScale); - bool isAnchored() { return _anchored; } + bool isAnchored() const { return _anchored; } void setAnchored(bool anchored) { _anchored = anchored; } + bool isHelper() const { return _isHelper; } const FlowPhysicsSettings& getSettings() { return _settings; } void setSettings(const FlowPhysicsSettings& settings) { _settings = settings; } - const glm::vec3& getCurrentPosition() { return _currentPosition; } - int getIndex() { return _index; } - int getParentIndex() { return _parentIndex; } + const glm::vec3& getCurrentPosition() const { return _currentPosition; } + int getIndex() const { return _index; } + int getParentIndex() const { return _parentIndex; } void setChildIndex(int index) { _childIndex = index; } - const glm::vec3& getUpdatedPosition() { return _updatedPosition; } - const QString& getGroup() { return _group; } - const glm::quat& getCurrentRotation() { return _currentRotation; } + const glm::vec3& getUpdatedPosition() const { return _updatedPosition; } + const QString& getGroup() const { return _group; } + const QString& getName() const { return _name; } + const glm::quat& getCurrentRotation() const { return _currentRotation; } + const glm::vec3& getCurrentTranslation() const { return _initialTranslation; } + const glm::vec3& getInitialPosition() const { return _initialPosition; } protected: @@ -240,7 +229,8 @@ protected: int _childIndex{ -1 }; QString _name; QString _group; - bool _isDummy{ false }; + + bool _isHelper{ false }; glm::vec3 _initialTranslation; glm::quat _initialRotation; @@ -262,13 +252,6 @@ protected: bool _applyRecovery { false }; }; -class FlowDummyJoint : public FlowJoint { -public: - FlowDummyJoint(const glm::vec3& initialPosition, int index, int parentIndex, int childIndex, FlowPhysicsSettings settings); - void toIsolatedJoint(float length, int childIndex, const QString& group); -}; - - class FlowThread { public: FlowThread() {}; diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index eb02f07e62..7a00a8ecf2 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1911,14 +1911,12 @@ void Rig::initAnimGraph(const QUrl& url) { qCritical(animation) << "Error loading: code = " << error << "str =" << str; }); - /* connect(this, &Rig::onLoadComplete, [&]() { - if (_internalFlow.getActive()) { - _internalFlow.calculateConstraints(_animSkeleton, _internalPoseSet._relativePoses, _internalPoseSet._absolutePoses); - _networkFlow.calculateConstraints(_animSkeleton, _internalPoseSet._relativePoses, _internalPoseSet._absolutePoses); - } + _internalFlow.setActive(false); + _internalFlow.cleanUp(); + _networkFlow.setActive(false); + _networkFlow.cleanUp(); }); - */ } } @@ -2136,5 +2134,6 @@ void Rig::initFlow(bool isActive) { } } else { _internalFlow.cleanUp(); + _networkFlow.cleanUp(); } } \ No newline at end of file From dcbf57ee0b5df0fcde392bc14534c26db6ee85dc Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 21 Feb 2019 16:41:24 -0700 Subject: [PATCH 16/16] Fix linux warning and HMD breaks flow --- libraries/animation/src/Flow.cpp | 4 ---- libraries/animation/src/Rig.cpp | 7 ------- libraries/render-utils/src/Model.cpp | 1 + 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/libraries/animation/src/Flow.cpp b/libraries/animation/src/Flow.cpp index 9fb0306fa3..3bb80b9375 100644 --- a/libraries/animation/src/Flow.cpp +++ b/libraries/animation/src/Flow.cpp @@ -460,16 +460,12 @@ void Flow::calculateConstraints(const std::shared_ptr& skeleton, if (!skeleton) { return; } - int rightHandIndex = -1; auto flowPrefix = FLOW_JOINT_PREFIX.toUpper(); auto simPrefix = SIM_JOINT_PREFIX.toUpper(); std::vector handsIndices; for (int i = 0; i < skeleton->getNumJoints(); i++) { auto name = skeleton->getJointName(i); - if (name == "RightHand") { - rightHandIndex = i; - } if (std::find(HAND_COLLISION_JOINTS.begin(), HAND_COLLISION_JOINTS.end(), name) != HAND_COLLISION_JOINTS.end()) { handsIndices.push_back(i); } diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 7a00a8ecf2..4d5488cad2 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1910,13 +1910,6 @@ void Rig::initAnimGraph(const QUrl& url) { connect(_networkLoader.get(), &AnimNodeLoader::error, [networkUrl](int error, QString str) { qCritical(animation) << "Error loading: code = " << error << "str =" << str; }); - - connect(this, &Rig::onLoadComplete, [&]() { - _internalFlow.setActive(false); - _internalFlow.cleanUp(); - _networkFlow.setActive(false); - _networkFlow.cleanUp(); - }); } } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 260e25009e..f61ae28db4 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1158,6 +1158,7 @@ void Model::setURL(const QUrl& url) { resource->setLoadPriority(this, _loadingPriority); _renderWatcher.setResource(resource); } + _rig.initFlow(false); onInvalidate(); }