From 69e463bbfdcfbacc2e185e6059d8e980be9c42a5 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 4 Sep 2015 16:01:05 -0700 Subject: [PATCH] AnimDebugDraw Improvements * Now always works, regardless of whether or not Rig or AnimGraph animations are enabled. * Changed joint radius to 1 cm. * Changed xyz axis length to 4 cm. --- interface/src/avatar/MyAvatar.cpp | 31 ++++---- interface/src/avatar/MyAvatar.h | 1 + libraries/animation/src/AnimSkeleton.cpp | 74 ++++++++++++-------- libraries/animation/src/AnimSkeleton.h | 3 + libraries/animation/src/JointState.h | 2 + libraries/animation/src/Rig.cpp | 19 +++-- libraries/animation/src/Rig.h | 3 + libraries/render-utils/src/AnimDebugDraw.cpp | 74 +++++++++++++++++--- libraries/render-utils/src/AnimDebugDraw.h | 13 ++-- 9 files changed, 157 insertions(+), 63 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index de7e2ba8fb..89ebe650d0 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -735,7 +735,7 @@ void MyAvatar::setEnableDebugDrawAnimPose(bool isEnabled) { _enableDebugDrawAnimPose = isEnabled; if (!isEnabled) { - AnimDebugDraw::getInstance().removeAnimNode("myAvatar"); + AnimDebugDraw::getInstance().removePoses("myAvatar"); } } @@ -1248,8 +1248,6 @@ void MyAvatar::initAnimGraph() { void MyAvatar::destroyAnimGraph() { _rig->destroyAnimGraph(); - AnimDebugDraw::getInstance().removeSkeleton("myAvatar"); - AnimDebugDraw::getInstance().removeAnimNode("myAvatar"); } void MyAvatar::preRender(RenderArgs* renderArgs) { @@ -1261,26 +1259,35 @@ void MyAvatar::preRender(RenderArgs* renderArgs) { initHeadBones(); _skeletonModel.setCauterizeBoneSet(_headBoneSet); initAnimGraph(); + _debugDrawSkeleton = std::make_shared(_skeletonModel.getGeometry()->getFBXGeometry()); } if (_enableDebugDrawBindPose || _enableDebugDrawAnimPose) { - AnimSkeleton::ConstPointer animSkeleton = _rig->getAnimSkeleton(); - AnimNode::ConstPointer animNode = _rig->getAnimNode(); - - // bones space is rotated + // bones are aligned such that z is forward, not -z. glm::quat rotY180 = glm::angleAxis((float)M_PI, glm::vec3(0.0f, 1.0f, 0.0f)); AnimPose xform(glm::vec3(1), rotY180 * getOrientation(), getPosition()); - if (animSkeleton && _enableDebugDrawBindPose) { + if (_enableDebugDrawBindPose && _debugDrawSkeleton) { glm::vec4 gray(0.2f, 0.2f, 0.2f, 0.2f); - AnimDebugDraw::getInstance().addSkeleton("myAvatar", animSkeleton, xform, gray); + AnimDebugDraw::getInstance().addSkeleton("myAvatar", _debugDrawSkeleton, xform, gray); } - // This only works for when new anim system is enabled, at the moment. - if (animNode && animSkeleton && _enableDebugDrawAnimPose && _rig->getEnableAnimGraph()) { + if (_enableDebugDrawAnimPose && _debugDrawSkeleton) { glm::vec4 cyan(0.1f, 0.6f, 0.6f, 1.0f); - AnimDebugDraw::getInstance().addAnimNode("myAvatar", animNode, xform, cyan); + + // build AnimPoseVec from JointStates. + AnimPoseVec poses; + poses.reserve(_debugDrawSkeleton->getNumJoints()); + for (int i = 0; i < _debugDrawSkeleton->getNumJoints(); i++) { + AnimPose pose = _debugDrawSkeleton->getRelativeBindPose(i); + glm::quat jointRot; + _rig->getJointRotationInConstrainedFrame(i, jointRot); + pose.rot = pose.rot * jointRot; + poses.push_back(pose); + } + + AnimDebugDraw::getInstance().addPoses("myAvatar", _debugDrawSkeleton, poses, xform, cyan); } } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index fadb5d669c..e743dea860 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -321,6 +321,7 @@ private: bool _enableDebugDrawBindPose = false; bool _enableDebugDrawAnimPose = false; + AnimSkeleton::ConstPointer _debugDrawSkeleton = nullptr; }; #endif // hifi_MyAvatar_h diff --git a/libraries/animation/src/AnimSkeleton.cpp b/libraries/animation/src/AnimSkeleton.cpp index 3f11607f26..fdc20db63c 100644 --- a/libraries/animation/src/AnimSkeleton.cpp +++ b/libraries/animation/src/AnimSkeleton.cpp @@ -58,7 +58,52 @@ AnimPose::operator glm::mat4() const { glm::vec4(zAxis, 0.0f), glm::vec4(trans, 1.0f)); } +AnimSkeleton::AnimSkeleton(const FBXGeometry& fbxGeometry) { + // convert to std::vector of joints + std::vector joints; + joints.reserve(fbxGeometry.joints.size()); + for (auto& joint : fbxGeometry.joints) { + joints.push_back(joint); + } + + AnimPose geometryOffset(fbxGeometry.offset); + buildSkeletonFromJoints(joints, geometryOffset); +} + AnimSkeleton::AnimSkeleton(const std::vector& joints, const AnimPose& geometryOffset) { + buildSkeletonFromJoints(joints, geometryOffset); +} + +int AnimSkeleton::nameToJointIndex(const QString& jointName) const { + for (size_t i = 0; i < _joints.size(); i++) { + if (_joints[i].name == jointName) { + return i; + } + } + return -1; +} + +int AnimSkeleton::getNumJoints() const { + return _joints.size(); +} + +AnimPose AnimSkeleton::getAbsoluteBindPose(int jointIndex) const { + return _absoluteBindPoses[jointIndex]; +} + +AnimPose AnimSkeleton::getRelativeBindPose(int jointIndex) const { + return _relativeBindPoses[jointIndex]; +} + +int AnimSkeleton::getParentIndex(int jointIndex) const { + return _joints[jointIndex].parentIndex; +} + +const QString& AnimSkeleton::getJointName(int jointIndex) const { + return _joints[jointIndex].name; +} + +void AnimSkeleton::buildSkeletonFromJoints(const std::vector& joints, const AnimPose& geometryOffset) { _joints = joints; // build a cache of bind poses @@ -113,35 +158,6 @@ AnimSkeleton::AnimSkeleton(const std::vector& joints, const AnimPose& } } -int AnimSkeleton::nameToJointIndex(const QString& jointName) const { - for (size_t i = 0; i < _joints.size(); i++) { - if (_joints[i].name == jointName) { - return i; - } - } - return -1; -} - -int AnimSkeleton::getNumJoints() const { - return _joints.size(); -} - -AnimPose AnimSkeleton::getAbsoluteBindPose(int jointIndex) const { - return _absoluteBindPoses[jointIndex]; -} - -AnimPose AnimSkeleton::getRelativeBindPose(int jointIndex) const { - return _relativeBindPoses[jointIndex]; -} - -int AnimSkeleton::getParentIndex(int jointIndex) const { - return _joints[jointIndex].parentIndex; -} - -const QString& AnimSkeleton::getJointName(int jointIndex) const { - return _joints[jointIndex].name; -} - #ifndef NDEBUG void AnimSkeleton::dump() const { qCDebug(animation) << "["; diff --git a/libraries/animation/src/AnimSkeleton.h b/libraries/animation/src/AnimSkeleton.h index c0c5036cc7..973e32232d 100644 --- a/libraries/animation/src/AnimSkeleton.h +++ b/libraries/animation/src/AnimSkeleton.h @@ -47,6 +47,7 @@ public: using Pointer = std::shared_ptr; using ConstPointer = std::shared_ptr; + AnimSkeleton(const FBXGeometry& fbxGeometry); AnimSkeleton(const std::vector& joints, const AnimPose& geometryOffset); int nameToJointIndex(const QString& jointName) const; const QString& getJointName(int jointIndex) const; @@ -66,6 +67,8 @@ public: #endif protected: + void buildSkeletonFromJoints(const std::vector& joints, const AnimPose& geometryOffset); + std::vector _joints; AnimPoseVec _absoluteBindPoses; AnimPoseVec _relativeBindPoses; diff --git a/libraries/animation/src/JointState.h b/libraries/animation/src/JointState.h index 4f45661eb2..1fa7576b74 100644 --- a/libraries/animation/src/JointState.h +++ b/libraries/animation/src/JointState.h @@ -26,6 +26,8 @@ class AngularConstraint; class JointState { public: + friend class MyAvatar; + JointState() {} JointState(const JointState& other) { copyState(other); } JointState(const FBXJoint& joint); diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index f2ea922ab7..18e6eff095 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -901,6 +901,14 @@ glm::quat Rig::setJointRotationInConstrainedFrame(int jointIndex, glm::quat targ return endRotation; } +bool Rig::getJointRotationInConstrainedFrame(int jointIndex, glm::quat& quatOut) const { + if (jointIndex == -1 || _jointStates.isEmpty()) { + return false; + } + quatOut = _jointStates[jointIndex].getRotationInConstrainedFrame(); + return true; +} + void Rig::updateVisibleJointStates() { for (int i = 0; i < _jointStates.size(); i++) { _jointStates[i].slaveVisibleTransform(); @@ -1010,16 +1018,7 @@ void Rig::initAnimGraph(const QUrl& url, const FBXGeometry& fbxGeometry) { return; } - // convert to std::vector of joints - std::vector joints; - joints.reserve(fbxGeometry.joints.size()); - for (auto& joint : fbxGeometry.joints) { - joints.push_back(joint); - } - - // create skeleton - AnimPose geometryOffset(fbxGeometry.offset); - _animSkeleton = std::make_shared(joints, geometryOffset); + _animSkeleton = std::make_shared(fbxGeometry); // load the anim graph _animLoader.reset(new AnimNodeLoader(url)); diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 0bf0645b4d..4d37dc92e6 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -51,6 +51,8 @@ typedef std::shared_ptr RigPointer; class Rig : public QObject, public std::enable_shared_from_this { + friend MyAvatar; + public: struct HeadParameters { @@ -153,6 +155,7 @@ public: glm::vec3 getJointDefaultTranslationInConstrainedFrame(int jointIndex); glm::quat setJointRotationInConstrainedFrame(int jointIndex, glm::quat targetRotation, float priority, bool constrain = false, float mix = 1.0f); + bool getJointRotationInConstrainedFrame(int jointIndex, glm::quat& rotOut) const; glm::quat getJointDefaultRotationInParentFrame(int jointIndex); void updateVisibleJointStates(); diff --git a/libraries/render-utils/src/AnimDebugDraw.cpp b/libraries/render-utils/src/AnimDebugDraw.cpp index 1c0f7e0054..44a58b3d67 100644 --- a/libraries/render-utils/src/AnimDebugDraw.cpp +++ b/libraries/render-utils/src/AnimDebugDraw.cpp @@ -152,22 +152,30 @@ AnimDebugDraw::~AnimDebugDraw() { } } -void AnimDebugDraw::addSkeleton(std::string key, AnimSkeleton::ConstPointer skeleton, const AnimPose& rootPose, const glm::vec4& color) { +void AnimDebugDraw::addSkeleton(const std::string& key, AnimSkeleton::ConstPointer skeleton, const AnimPose& rootPose, const glm::vec4& color) { _skeletons[key] = SkeletonInfo(skeleton, rootPose, color); } -void AnimDebugDraw::removeSkeleton(std::string key) { +void AnimDebugDraw::removeSkeleton(const std::string& key) { _skeletons.erase(key); } -void AnimDebugDraw::addAnimNode(std::string key, AnimNode::ConstPointer animNode, const AnimPose& rootPose, const glm::vec4& color) { +void AnimDebugDraw::addAnimNode(const std::string& key, AnimNode::ConstPointer animNode, const AnimPose& rootPose, const glm::vec4& color) { _animNodes[key] = AnimNodeInfo(animNode, rootPose, color); } -void AnimDebugDraw::removeAnimNode(std::string key) { +void AnimDebugDraw::removeAnimNode(const std::string& key) { _animNodes.erase(key); } +void AnimDebugDraw::addPoses(const std::string& key, AnimSkeleton::ConstPointer skeleton, const AnimPoseVec& poses, const AnimPose& rootPose, const glm::vec4& color) { + _poses[key] = PosesInfo(skeleton, poses, rootPose, color); +} + +void AnimDebugDraw::removePoses(const std::string& key) { + _poses.erase(key); +} + static const uint32_t red = toRGBA(255, 0, 0, 255); static const uint32_t green = toRGBA(0, 255, 0, 255); static const uint32_t blue = toRGBA(0, 0, 255, 255); @@ -176,6 +184,8 @@ const int NUM_CIRCLE_SLICES = 24; static void addBone(const AnimPose& rootPose, const AnimPose& pose, float radius, Vertex*& v) { + const float XYZ_AXIS_LENGTH = radius * 4.0f; + AnimPose finalPose = rootPose * pose; glm::vec3 base = rootPose * pose.trans; @@ -195,7 +205,7 @@ static void addBone(const AnimPose& rootPose, const AnimPose& pose, float radius v->pos = base; v->rgba = red; v++; - v->pos = finalPose * glm::vec3(radius * 2.0f, 0.0f, 0.0f); + v->pos = finalPose * glm::vec3(XYZ_AXIS_LENGTH, 0.0f, 0.0f); v->rgba = red; v++; @@ -213,7 +223,7 @@ static void addBone(const AnimPose& rootPose, const AnimPose& pose, float radius v->pos = base; v->rgba = green; v++; - v->pos = finalPose * glm::vec3(0.0f, radius * 2.0f, 0.0f); + v->pos = finalPose * glm::vec3(0.0f, XYZ_AXIS_LENGTH, 0.0f); v->rgba = green; v++; @@ -231,7 +241,7 @@ static void addBone(const AnimPose& rootPose, const AnimPose& pose, float radius v->pos = base; v->rgba = blue; v++; - v->pos = finalPose * glm::vec3(0.0f, 0.0f, radius * 2.0f); + v->pos = finalPose * glm::vec3(0.0f, 0.0f, XYZ_AXIS_LENGTH); v->rgba = blue; v++; @@ -322,7 +332,7 @@ void AnimDebugDraw::update() { const size_t VERTICES_PER_BONE = (6 + (NUM_CIRCLE_SLICES * 2) * 3); const size_t VERTICES_PER_LINK = 8 * 2; - const float BONE_RADIUS = 0.0075f; + const float BONE_RADIUS = 0.01f; // 1 cm // figure out how many verts we will need. int numVerts = 0; @@ -350,6 +360,17 @@ void AnimDebugDraw::update() { } } + for (auto&& iter : _poses) { + AnimSkeleton::ConstPointer& skeleton = std::get<0>(iter.second); + numVerts += skeleton->getNumJoints() * VERTICES_PER_BONE; + for (int i = 0; i < skeleton->getNumJoints(); i++) { + auto parentIndex = skeleton->getParentIndex(i); + if (parentIndex >= 0) { + numVerts += VERTICES_PER_LINK; + } + } + } + data._vertexBuffer->resize(sizeof(Vertex) * numVerts); Vertex* verts = (Vertex*)data._vertexBuffer->editData(); Vertex* v = verts; @@ -418,6 +439,43 @@ void AnimDebugDraw::update() { } } + for (auto&& iter : _poses) { + AnimSkeleton::ConstPointer& skeleton = std::get<0>(iter.second); + AnimPoseVec& poses = std::get<1>(iter.second); + AnimPose rootPose = std::get<2>(iter.second); + int hipsIndex = skeleton->nameToJointIndex("Hips"); + if (hipsIndex >= 0) { + rootPose.trans -= skeleton->getRelativeBindPose(hipsIndex).trans; + } + glm::vec4 color = std::get<3>(iter.second); + + std::vector absAnimPose; + absAnimPose.resize(skeleton->getNumJoints()); + + for (int i = 0; i < skeleton->getNumJoints(); i++) { + AnimPose pose = poses[i]; + + const float radius = BONE_RADIUS / (pose.scale.x * rootPose.scale.x); + + auto parentIndex = skeleton->getParentIndex(i); + if (parentIndex >= 0) { + absAnimPose[i] = absAnimPose[parentIndex] * poses[i]; + } else { + absAnimPose[i] = poses[i]; + } + + // draw bone + addBone(rootPose, absAnimPose[i], radius, v); + + // draw link to parent + if (parentIndex >= 0) { + assert(parentIndex < skeleton->getNumJoints()); + AnimPose parentPose = poses[parentIndex]; + addLink(rootPose, absAnimPose[i], absAnimPose[parentIndex], radius, color, v); + } + } + } + assert(numVerts == (v - verts)); data._indexBuffer->resize(sizeof(uint16_t) * numVerts); diff --git a/libraries/render-utils/src/AnimDebugDraw.h b/libraries/render-utils/src/AnimDebugDraw.h index 489213b80b..cd17f62590 100644 --- a/libraries/render-utils/src/AnimDebugDraw.h +++ b/libraries/render-utils/src/AnimDebugDraw.h @@ -27,11 +27,14 @@ public: AnimDebugDraw(); ~AnimDebugDraw(); - void addSkeleton(std::string key, AnimSkeleton::ConstPointer skeleton, const AnimPose& rootPose, const glm::vec4& color); - void removeSkeleton(std::string key); + void addSkeleton(const std::string& key, AnimSkeleton::ConstPointer skeleton, const AnimPose& rootPose, const glm::vec4& color); + void removeSkeleton(const std::string& key); - void addAnimNode(std::string key, AnimNode::ConstPointer animNode, const AnimPose& rootPose, const glm::vec4& color); - void removeAnimNode(std::string key); + void addAnimNode(const std::string& key, AnimNode::ConstPointer animNode, const AnimPose& rootPose, const glm::vec4& color); + void removeAnimNode(const std::string& key); + + void addPoses(const std::string& key, AnimSkeleton::ConstPointer skeleton, const AnimPoseVec& poses, const AnimPose& rootPose, const glm::vec4& color); + void removePoses(const std::string& key); void update(); @@ -44,9 +47,11 @@ protected: typedef std::tuple SkeletonInfo; typedef std::tuple AnimNodeInfo; + typedef std::tuple PosesInfo; std::unordered_map _skeletons; std::unordered_map _animNodes; + std::unordered_map _poses; // no copies AnimDebugDraw(const AnimDebugDraw&) = delete;