Merge pull request #5724 from hyperlogic/tony/anim-debug-draw-improvements

AnimDebugDraw Improvements
This commit is contained in:
Seth Alves 2015-09-08 17:07:51 -07:00
commit e06461ea15
8 changed files with 158 additions and 70 deletions

View file

@ -735,7 +735,7 @@ void MyAvatar::setEnableDebugDrawAnimPose(bool isEnabled) {
_enableDebugDrawAnimPose = isEnabled; _enableDebugDrawAnimPose = isEnabled;
if (!isEnabled) { if (!isEnabled) {
AnimDebugDraw::getInstance().removeAnimNode("myAvatar"); AnimDebugDraw::getInstance().removePoses("myAvatar");
} }
} }
@ -1248,8 +1248,6 @@ void MyAvatar::initAnimGraph() {
void MyAvatar::destroyAnimGraph() { void MyAvatar::destroyAnimGraph() {
_rig->destroyAnimGraph(); _rig->destroyAnimGraph();
AnimDebugDraw::getInstance().removeSkeleton("myAvatar");
AnimDebugDraw::getInstance().removeAnimNode("myAvatar");
} }
void MyAvatar::preRender(RenderArgs* renderArgs) { void MyAvatar::preRender(RenderArgs* renderArgs) {
@ -1261,26 +1259,35 @@ void MyAvatar::preRender(RenderArgs* renderArgs) {
initHeadBones(); initHeadBones();
_skeletonModel.setCauterizeBoneSet(_headBoneSet); _skeletonModel.setCauterizeBoneSet(_headBoneSet);
initAnimGraph(); initAnimGraph();
_debugDrawSkeleton = std::make_shared<AnimSkeleton>(_skeletonModel.getGeometry()->getFBXGeometry());
} }
if (_enableDebugDrawBindPose || _enableDebugDrawAnimPose) { if (_enableDebugDrawBindPose || _enableDebugDrawAnimPose) {
AnimSkeleton::ConstPointer animSkeleton = _rig->getAnimSkeleton(); // bones are aligned such that z is forward, not -z.
AnimNode::ConstPointer animNode = _rig->getAnimNode();
// bones space is rotated
glm::quat rotY180 = glm::angleAxis((float)M_PI, glm::vec3(0.0f, 1.0f, 0.0f)); glm::quat rotY180 = glm::angleAxis((float)M_PI, glm::vec3(0.0f, 1.0f, 0.0f));
AnimPose xform(glm::vec3(1), rotY180 * getOrientation(), getPosition()); 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); 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 (_enableDebugDrawAnimPose && _debugDrawSkeleton) {
if (animNode && animSkeleton && _enableDebugDrawAnimPose && _rig->getEnableAnimGraph()) {
glm::vec4 cyan(0.1f, 0.6f, 0.6f, 1.0f); 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);
} }
} }

View file

@ -321,6 +321,7 @@ private:
bool _enableDebugDrawBindPose = false; bool _enableDebugDrawBindPose = false;
bool _enableDebugDrawAnimPose = false; bool _enableDebugDrawAnimPose = false;
AnimSkeleton::ConstPointer _debugDrawSkeleton = nullptr;
}; };
#endif // hifi_MyAvatar_h #endif // hifi_MyAvatar_h

View file

@ -58,7 +58,52 @@ AnimPose::operator glm::mat4() const {
glm::vec4(zAxis, 0.0f), glm::vec4(trans, 1.0f)); glm::vec4(zAxis, 0.0f), glm::vec4(trans, 1.0f));
} }
AnimSkeleton::AnimSkeleton(const FBXGeometry& fbxGeometry) {
// convert to std::vector of joints
std::vector<FBXJoint> 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<FBXJoint>& joints, const AnimPose& geometryOffset) { AnimSkeleton::AnimSkeleton(const std::vector<FBXJoint>& 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();
}
const AnimPose& AnimSkeleton::getAbsoluteBindPose(int jointIndex) const {
return _absoluteBindPoses[jointIndex];
}
const 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<FBXJoint>& joints, const AnimPose& geometryOffset) {
_joints = joints; _joints = joints;
// build a cache of bind poses // build a cache of bind poses
@ -113,35 +158,6 @@ AnimSkeleton::AnimSkeleton(const std::vector<FBXJoint>& 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 #ifndef NDEBUG
void AnimSkeleton::dump() const { void AnimSkeleton::dump() const {
qCDebug(animation) << "["; qCDebug(animation) << "[";

View file

@ -47,16 +47,17 @@ public:
using Pointer = std::shared_ptr<AnimSkeleton>; using Pointer = std::shared_ptr<AnimSkeleton>;
using ConstPointer = std::shared_ptr<const AnimSkeleton>; using ConstPointer = std::shared_ptr<const AnimSkeleton>;
AnimSkeleton(const FBXGeometry& fbxGeometry);
AnimSkeleton(const std::vector<FBXJoint>& joints, const AnimPose& geometryOffset); AnimSkeleton(const std::vector<FBXJoint>& joints, const AnimPose& geometryOffset);
int nameToJointIndex(const QString& jointName) const; int nameToJointIndex(const QString& jointName) const;
const QString& getJointName(int jointIndex) const; const QString& getJointName(int jointIndex) const;
int getNumJoints() const; int getNumJoints() const;
// absolute pose, not relative to parent // absolute pose, not relative to parent
AnimPose getAbsoluteBindPose(int jointIndex) const; const AnimPose& getAbsoluteBindPose(int jointIndex) const;
// relative to parent pose // relative to parent pose
AnimPose getRelativeBindPose(int jointIndex) const; const AnimPose& getRelativeBindPose(int jointIndex) const;
int getParentIndex(int jointIndex) const; int getParentIndex(int jointIndex) const;
@ -66,6 +67,8 @@ public:
#endif #endif
protected: protected:
void buildSkeletonFromJoints(const std::vector<FBXJoint>& joints, const AnimPose& geometryOffset);
std::vector<FBXJoint> _joints; std::vector<FBXJoint> _joints;
AnimPoseVec _absoluteBindPoses; AnimPoseVec _absoluteBindPoses;
AnimPoseVec _relativeBindPoses; AnimPoseVec _relativeBindPoses;

View file

@ -901,6 +901,14 @@ glm::quat Rig::setJointRotationInConstrainedFrame(int jointIndex, glm::quat targ
return endRotation; 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() { void Rig::updateVisibleJointStates() {
for (int i = 0; i < _jointStates.size(); i++) { for (int i = 0; i < _jointStates.size(); i++) {
_jointStates[i].slaveVisibleTransform(); _jointStates[i].slaveVisibleTransform();
@ -1010,16 +1018,7 @@ void Rig::initAnimGraph(const QUrl& url, const FBXGeometry& fbxGeometry) {
return; return;
} }
// convert to std::vector of joints _animSkeleton = std::make_shared<AnimSkeleton>(fbxGeometry);
std::vector<FBXJoint> 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<AnimSkeleton>(joints, geometryOffset);
// load the anim graph // load the anim graph
_animLoader.reset(new AnimNodeLoader(url)); _animLoader.reset(new AnimNodeLoader(url));

View file

@ -50,7 +50,6 @@ class Rig;
typedef std::shared_ptr<Rig> RigPointer; typedef std::shared_ptr<Rig> RigPointer;
class Rig : public QObject, public std::enable_shared_from_this<Rig> { class Rig : public QObject, public std::enable_shared_from_this<Rig> {
public: public:
struct HeadParameters { struct HeadParameters {
@ -153,6 +152,7 @@ public:
glm::vec3 getJointDefaultTranslationInConstrainedFrame(int jointIndex); glm::vec3 getJointDefaultTranslationInConstrainedFrame(int jointIndex);
glm::quat setJointRotationInConstrainedFrame(int jointIndex, glm::quat targetRotation, glm::quat setJointRotationInConstrainedFrame(int jointIndex, glm::quat targetRotation,
float priority, bool constrain = false, float mix = 1.0f); float priority, bool constrain = false, float mix = 1.0f);
bool getJointRotationInConstrainedFrame(int jointIndex, glm::quat& rotOut) const;
glm::quat getJointDefaultRotationInParentFrame(int jointIndex); glm::quat getJointDefaultRotationInParentFrame(int jointIndex);
void updateVisibleJointStates(); void updateVisibleJointStates();

View file

@ -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); _skeletons[key] = SkeletonInfo(skeleton, rootPose, color);
} }
void AnimDebugDraw::removeSkeleton(std::string key) { void AnimDebugDraw::removeSkeleton(const std::string& key) {
_skeletons.erase(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); _animNodes[key] = AnimNodeInfo(animNode, rootPose, color);
} }
void AnimDebugDraw::removeAnimNode(std::string key) { void AnimDebugDraw::removeAnimNode(const std::string& key) {
_animNodes.erase(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 red = toRGBA(255, 0, 0, 255);
static const uint32_t green = toRGBA(0, 255, 0, 255); static const uint32_t green = toRGBA(0, 255, 0, 255);
static const uint32_t blue = toRGBA(0, 0, 255, 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) { 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; AnimPose finalPose = rootPose * pose;
glm::vec3 base = rootPose * pose.trans; 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->pos = base;
v->rgba = red; v->rgba = red;
v++; 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->rgba = red;
v++; v++;
@ -213,7 +223,7 @@ static void addBone(const AnimPose& rootPose, const AnimPose& pose, float radius
v->pos = base; v->pos = base;
v->rgba = green; v->rgba = green;
v++; 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->rgba = green;
v++; v++;
@ -231,7 +241,7 @@ static void addBone(const AnimPose& rootPose, const AnimPose& pose, float radius
v->pos = base; v->pos = base;
v->rgba = blue; v->rgba = blue;
v++; 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->rgba = blue;
v++; v++;
@ -322,11 +332,11 @@ void AnimDebugDraw::update() {
const size_t VERTICES_PER_BONE = (6 + (NUM_CIRCLE_SLICES * 2) * 3); const size_t VERTICES_PER_BONE = (6 + (NUM_CIRCLE_SLICES * 2) * 3);
const size_t VERTICES_PER_LINK = 8 * 2; 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. // figure out how many verts we will need.
int numVerts = 0; int numVerts = 0;
for (auto&& iter : _skeletons) { for (auto& iter : _skeletons) {
AnimSkeleton::ConstPointer& skeleton = std::get<0>(iter.second); AnimSkeleton::ConstPointer& skeleton = std::get<0>(iter.second);
numVerts += skeleton->getNumJoints() * VERTICES_PER_BONE; numVerts += skeleton->getNumJoints() * VERTICES_PER_BONE;
for (int i = 0; i < skeleton->getNumJoints(); i++) { for (int i = 0; i < skeleton->getNumJoints(); i++) {
@ -337,7 +347,7 @@ void AnimDebugDraw::update() {
} }
} }
for (auto&& iter : _animNodes) { for (auto& iter : _animNodes) {
AnimNode::ConstPointer& animNode = std::get<0>(iter.second); AnimNode::ConstPointer& animNode = std::get<0>(iter.second);
auto poses = animNode->getPosesInternal(); auto poses = animNode->getPosesInternal();
numVerts += poses.size() * VERTICES_PER_BONE; numVerts += poses.size() * VERTICES_PER_BONE;
@ -350,10 +360,21 @@ 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); data._vertexBuffer->resize(sizeof(Vertex) * numVerts);
Vertex* verts = (Vertex*)data._vertexBuffer->editData(); Vertex* verts = (Vertex*)data._vertexBuffer->editData();
Vertex* v = verts; Vertex* v = verts;
for (auto&& iter : _skeletons) { for (auto& iter : _skeletons) {
AnimSkeleton::ConstPointer& skeleton = std::get<0>(iter.second); AnimSkeleton::ConstPointer& skeleton = std::get<0>(iter.second);
AnimPose rootPose = std::get<1>(iter.second); AnimPose rootPose = std::get<1>(iter.second);
int hipsIndex = skeleton->nameToJointIndex("Hips"); int hipsIndex = skeleton->nameToJointIndex("Hips");
@ -380,7 +401,7 @@ void AnimDebugDraw::update() {
} }
} }
for (auto&& iter : _animNodes) { for (auto& iter : _animNodes) {
AnimNode::ConstPointer& animNode = std::get<0>(iter.second); AnimNode::ConstPointer& animNode = std::get<0>(iter.second);
AnimPose rootPose = std::get<1>(iter.second); AnimPose rootPose = std::get<1>(iter.second);
if (animNode->_skeleton) { if (animNode->_skeleton) {
@ -418,6 +439,42 @@ 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<AnimPose> absAnimPose;
absAnimPose.resize(skeleton->getNumJoints());
for (int i = 0; i < skeleton->getNumJoints(); i++) {
const 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] * pose;
} else {
absAnimPose[i] = pose;
}
// draw bone
addBone(rootPose, absAnimPose[i], radius, v);
// draw link to parent
if (parentIndex >= 0) {
assert(parentIndex < skeleton->getNumJoints());
addLink(rootPose, absAnimPose[i], absAnimPose[parentIndex], radius, color, v);
}
}
}
assert(numVerts == (v - verts)); assert(numVerts == (v - verts));
data._indexBuffer->resize(sizeof(uint16_t) * numVerts); data._indexBuffer->resize(sizeof(uint16_t) * numVerts);

View file

@ -27,11 +27,14 @@ public:
AnimDebugDraw(); AnimDebugDraw();
~AnimDebugDraw(); ~AnimDebugDraw();
void addSkeleton(std::string key, AnimSkeleton::ConstPointer skeleton, const AnimPose& rootPose, const glm::vec4& color); void addSkeleton(const std::string& key, AnimSkeleton::ConstPointer skeleton, const AnimPose& rootPose, const glm::vec4& color);
void removeSkeleton(std::string key); void removeSkeleton(const std::string& key);
void addAnimNode(std::string key, AnimNode::ConstPointer animNode, const AnimPose& rootPose, const glm::vec4& color); void addAnimNode(const std::string& key, AnimNode::ConstPointer animNode, const AnimPose& rootPose, const glm::vec4& color);
void removeAnimNode(std::string key); 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(); void update();
@ -44,9 +47,11 @@ protected:
typedef std::tuple<AnimSkeleton::ConstPointer, AnimPose, glm::vec4> SkeletonInfo; typedef std::tuple<AnimSkeleton::ConstPointer, AnimPose, glm::vec4> SkeletonInfo;
typedef std::tuple<AnimNode::ConstPointer, AnimPose, glm::vec4> AnimNodeInfo; typedef std::tuple<AnimNode::ConstPointer, AnimPose, glm::vec4> AnimNodeInfo;
typedef std::tuple<AnimSkeleton::ConstPointer, AnimPoseVec, AnimPose, glm::vec4> PosesInfo;
std::unordered_map<std::string, SkeletonInfo> _skeletons; std::unordered_map<std::string, SkeletonInfo> _skeletons;
std::unordered_map<std::string, AnimNodeInfo> _animNodes; std::unordered_map<std::string, AnimNodeInfo> _animNodes;
std::unordered_map<std::string, PosesInfo> _poses;
// no copies // no copies
AnimDebugDraw(const AnimDebugDraw&) = delete; AnimDebugDraw(const AnimDebugDraw&) = delete;