Better AnimDebugDraw rendering

This commit is contained in:
Anthony J. Thibault 2015-08-26 16:42:08 -07:00
parent c1333e16ed
commit b7a9b54628
8 changed files with 168 additions and 33 deletions

View file

@ -1021,6 +1021,7 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
_billboardValid = false;
_skeletonModel.setVisibleInScene(true, scene);
_headBoneSet.clear();
teardownNewAnimationSystem();
}
void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName) {
@ -1227,9 +1228,11 @@ void MyAvatar::setupNewAnimationSystem() {
}
_animSkeleton = make_shared<AnimSkeleton>(joints);
// add it to the debug renderer, so we can see it.
//AnimPose xform(_skeletonModel.getScale(), glm::quat(), _skeletonModel.getOffset());
//AnimDebugDraw::getInstance().addSkeleton("my-avatar", _animSkeleton, xform);
// add skeleton to the debug renderer, so we can see it.
/*
AnimPose xform(_skeletonModel.getScale(), glm::quat(), _skeletonModel.getOffset());
AnimDebugDraw::getInstance().addSkeleton("my-avatar", _animSkeleton, xform);
*/
// load the anim graph
// https://gist.github.com/hyperlogic/7d6a0892a7319c69e2b9
@ -1246,6 +1249,12 @@ void MyAvatar::setupNewAnimationSystem() {
});
}
void MyAvatar::teardownNewAnimationSystem() {
_animSkeleton = nullptr;
_animLoader = nullptr;
_animNode = nullptr;
}
void MyAvatar::preRender(RenderArgs* renderArgs) {
render::ScenePointer scene = Application::getInstance()->getMain3DScene();

View file

@ -202,6 +202,7 @@ signals:
private:
void setupNewAnimationSystem();
void teardownNewAnimationSystem();
glm::vec3 getWorldBodyPosition() const;
glm::quat getWorldBodyOrientation() const;

View file

@ -145,7 +145,7 @@ void AnimClip::copyFromNetworkAnim() {
int k = jointMap[j];
if (k >= 0 && k < skeletonJointCount) {
// currently FBX animations only have rotation.
_anim[i][k].rot = _skeleton->getRelativeBindPose(j).rot * geom.animationFrames[i].rotations[j];
_anim[i][k].rot = _skeleton->getRelativeBindPose(k).rot * geom.animationFrames[i].rotations[j];
}
}
}

View file

@ -27,6 +27,20 @@ glm::vec3 AnimPose::operator*(const glm::vec3& rhs) const {
return trans + (rot * (scale * rhs));
}
glm::vec3 AnimPose::xformPoint(const glm::vec3& rhs) const {
return *this * rhs;
}
// really slow
glm::vec3 AnimPose::xformVector(const glm::vec3& rhs) const {
glm::vec3 xAxis = rot * glm::vec3(scale.x, 0.0f, 0.0f);
glm::vec3 yAxis = rot * glm::vec3(0.0f, scale.y, 0.0f);
glm::vec3 zAxis = rot * glm::vec3(0.0f, 0.0f, scale.z);
glm::mat3 mat(xAxis, yAxis, zAxis);
glm::mat3 transInvMat = glm::inverse(glm::transpose(mat));
return transInvMat * rhs;
}
AnimPose AnimPose::operator*(const AnimPose& rhs) const {
return AnimPose(static_cast<glm::mat4>(*this) * static_cast<glm::mat4>(rhs));
}

View file

@ -20,8 +20,12 @@ struct AnimPose {
AnimPose(const glm::vec3& scaleIn, const glm::quat& rotIn, const glm::vec3& transIn) : scale(scaleIn), rot(rotIn), trans(transIn) {}
static const AnimPose identity;
glm::vec3 operator*(const glm::vec3& rhs) const;
glm::vec3 xformPoint(const glm::vec3& rhs) const;
glm::vec3 xformVector(const glm::vec3& rhs) const; // really slow
glm::vec3 operator*(const glm::vec3& rhs) const; // same as xformPoint
AnimPose operator*(const AnimPose& rhs) const;
AnimPose inverse() const;
operator glm::mat4() const;

View file

@ -10,10 +10,11 @@
#include "animdebugdraw_vert.h"
#include "animdebugdraw_frag.h"
#include <gpu/Batch.h>
#include "AnimDebugDraw.h"
#include "AbstractViewStateInterface.h"
#include "RenderUtilsLogging.h"
#include "GLMHelpers.h"
#include "AnimDebugDraw.h"
struct Vertex {
glm::vec3 pos;
@ -165,45 +166,120 @@ static const uint32_t green = toRGBA(0, 255, 0, 255);
static const uint32_t blue = toRGBA(0, 0, 255, 255);
static const uint32_t cyan = toRGBA(0, 128, 128, 255);
static void addWireframeSphereWithAxes(const AnimPose& rootPose, const AnimPose& pose, float radius, Vertex*& v) {
const int NUM_CIRCLE_SLICES = 24;
static void addBone(const AnimPose& rootPose, const AnimPose& pose, float radius, Vertex*& v) {
AnimPose finalPose = rootPose * pose;
glm::vec3 base = rootPose * pose.trans;
glm::vec3 xRing[NUM_CIRCLE_SLICES + 1]; // one extra for last index.
glm::vec3 yRing[NUM_CIRCLE_SLICES + 1];
glm::vec3 zRing[NUM_CIRCLE_SLICES + 1];
const float dTheta = (2.0f * (float)M_PI) / NUM_CIRCLE_SLICES;
for (int i = 0; i < NUM_CIRCLE_SLICES + 1; i++) {
float rCosTheta = radius * cos(dTheta * i);
float rSinTheta = radius * sin(dTheta * i);
xRing[i] = finalPose * glm::vec3(0.0f, rCosTheta, rSinTheta);
yRing[i] = finalPose * glm::vec3(rCosTheta, 0.0f, rSinTheta);
zRing[i] = finalPose *glm::vec3(rCosTheta, rSinTheta, 0.0f);
}
// x-axis
v->pos = base;
v->rgba = red;
v++;
v->pos = rootPose * (pose.trans + pose.rot * glm::vec3(radius, 0.0f, 0.0f));
v->pos = finalPose * glm::vec3(radius * 2.0f, 0.0f, 0.0f);
v->rgba = red;
v++;
// x-ring
for (int i = 0; i < NUM_CIRCLE_SLICES; i++) {
v->pos = xRing[i];
v->rgba = red;
v++;
v->pos = xRing[i + 1];
v->rgba = red;
v++;
}
// y-axis
v->pos = base;
v->rgba = green;
v++;
v->pos = rootPose * (pose.trans + pose.rot * glm::vec3(0.0f, radius, 0.0f));
v->pos = finalPose * glm::vec3(0.0f, radius * 2.0f, 0.0f);
v->rgba = green;
v++;
// y-ring
for (int i = 0; i < NUM_CIRCLE_SLICES; i++) {
v->pos = yRing[i];
v->rgba = green;
v++;
v->pos = yRing[i + 1];
v->rgba = green;
v++;
}
// z-axis
v->pos = base;
v->rgba = blue;
v++;
v->pos = rootPose * (pose.trans + pose.rot * glm::vec3(0.0f, 0.0f, radius));
v->pos = finalPose * glm::vec3(0.0f, 0.0f, radius * 2.0f);
v->rgba = blue;
v++;
// z-ring
for (int i = 0; i < NUM_CIRCLE_SLICES; i++) {
v->pos = zRing[i];
v->rgba = blue;
v++;
v->pos = zRing[i + 1];
v->rgba = blue;
v++;
}
}
static void addWireframeBoneAxis(const AnimPose& rootPose, const AnimPose& pose,
const AnimPose& parentPose, float radius, Vertex*& v) {
v->pos = rootPose * pose.trans;
v->rgba = cyan;
v++;
v->pos = rootPose * parentPose.trans;
v->rgba = cyan;
v++;
}
static void addLink(const AnimPose& rootPose, const AnimPose& pose,
const AnimPose& parentPose, float radius, Vertex*& v) {
AnimPose pose0 = rootPose * parentPose;
AnimPose pose1 = rootPose * pose;
glm::vec3 boneAxisWorld = glm::normalize(pose1.trans - pose0.trans);
glm::vec3 boneAxis0 = glm::normalize(pose0.inverse().xformVector(boneAxisWorld));
glm::vec3 boneAxis1 = glm::normalize(pose1.inverse().xformVector(boneAxisWorld));
glm::vec3 uAxis, vAxis, wAxis;
generateBasisVectors(boneAxis0, glm::vec3(1, 0, 0), uAxis, vAxis, wAxis);
const int NUM_BASE_CORNERS = 4;
glm::vec3 boneBaseCorners[NUM_BASE_CORNERS];
boneBaseCorners[0] = pose0 * ((uAxis * radius) + (vAxis * radius) + (wAxis * radius));
boneBaseCorners[1] = pose0 * ((uAxis * radius) - (vAxis * radius) + (wAxis * radius));
boneBaseCorners[2] = pose0 * ((uAxis * radius) - (vAxis * radius) - (wAxis * radius));
boneBaseCorners[3] = pose0 * ((uAxis * radius) + (vAxis * radius) - (wAxis * radius));
glm::vec3 boneTip = pose1 * (boneAxis1 * -radius);
for (int i = 0; i < NUM_BASE_CORNERS; i++) {
v->pos = boneBaseCorners[i];
v->rgba = cyan;
v++;
v->pos = boneBaseCorners[(i + 1) % NUM_BASE_CORNERS];
v->rgba = cyan;
v++;
}
for (int i = 0; i < NUM_BASE_CORNERS; i++) {
v->pos = boneBaseCorners[i];
v->rgba = cyan;
v++;
v->pos = boneTip;
v->rgba = cyan;
v++;
}
}
void AnimDebugDraw::update() {
@ -215,15 +291,20 @@ void AnimDebugDraw::update() {
render::PendingChanges pendingChanges;
pendingChanges.updateItem<AnimDebugDrawData>(_itemID, [&](AnimDebugDrawData& data) {
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;
// figure out how many verts we will need.
int numVerts = 0;
for (auto&& iter : _skeletons) {
AnimSkeleton::Pointer& skeleton = iter.second.first;
numVerts += skeleton->getNumJoints() * 6;
numVerts += skeleton->getNumJoints() * VERTICES_PER_BONE;
for (int i = 0; i < skeleton->getNumJoints(); i++) {
auto parentIndex = skeleton->getParentIndex(i);
if (parentIndex >= 0) {
numVerts += 2;
numVerts += VERTICES_PER_LINK;
}
}
}
@ -231,12 +312,12 @@ void AnimDebugDraw::update() {
for (auto&& iter : _animNodes) {
AnimNode::Pointer& animNode = iter.second.first;
auto poses = animNode->getPosesInternal();
numVerts += poses.size() * 6;
numVerts += poses.size() * VERTICES_PER_BONE;
auto skeleton = animNode->getSkeleton();
for (size_t i = 0; i < poses.size(); i++) {
auto parentIndex = skeleton->getParentIndex(i);
if (parentIndex >= 0) {
numVerts += 2;
numVerts += VERTICES_PER_LINK;
}
}
}
@ -251,16 +332,17 @@ void AnimDebugDraw::update() {
for (int i = 0; i < skeleton->getNumJoints(); i++) {
AnimPose pose = skeleton->getAbsoluteBindPose(i);
// draw axes
const float radius = 0.1f;
addWireframeSphereWithAxes(rootPose, pose, radius, v);
const float radius = BONE_RADIUS / (pose.scale.x * rootPose.scale.x);
// line to parent.
// draw bone
addBone(rootPose, pose, radius, v);
// draw link to parent
auto parentIndex = skeleton->getParentIndex(i);
if (parentIndex >= 0) {
assert(parentIndex < skeleton->getNumJoints());
AnimPose parentPose = skeleton->getAbsoluteBindPose(parentIndex);
addWireframeBoneAxis(rootPose, pose, parentPose, radius, v);
addLink(rootPose, pose, parentPose, radius, v);
}
}
}
@ -284,14 +366,13 @@ void AnimDebugDraw::update() {
absAnimPose[i] = poses[i];
}
// draw axes
const float radius = 0.1f;
addWireframeSphereWithAxes(rootPose, absAnimPose[i], radius, v);
const float radius = BONE_RADIUS / (absAnimPose[i].scale.x * rootPose.scale.x);
addBone(rootPose, absAnimPose[i], radius, v);
if (parentIndex >= 0) {
assert((size_t)parentIndex < poses.size());
// draw line to parent
addWireframeBoneAxis(rootPose, absAnimPose[i], absAnimPose[parentIndex], radius, v);
addLink(rootPose, absAnimPose[i], absAnimPose[parentIndex], radius, v);
}
}
}

View file

@ -411,3 +411,21 @@ glm::vec3 transformPoint(const glm::mat4& m, const glm::vec3& p) {
return glm::vec3(temp.x / temp.w, temp.y / temp.w, temp.z / temp.w);
}
glm::vec3 transformVector(const glm::mat4& m, const glm::vec3& v) {
glm::mat3 rot(m);
return glm::inverse(glm::transpose(rot)) * v;
}
void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& secondaryAxis,
glm::vec3& uAxisOut, glm::vec3& vAxisOut, glm::vec3& wAxisOut) {
uAxisOut = glm::normalize(primaryAxis);
wAxisOut = glm::cross(uAxisOut, secondaryAxis);
if (glm::length(wAxisOut) > 0.0f) {
wAxisOut = glm::normalize(wAxisOut);
} else {
wAxisOut = glm::normalize(glm::cross(uAxisOut, glm::vec3(0, 1, 0)));
}
vAxisOut = glm::cross(wAxisOut, uAxisOut);
}

View file

@ -198,5 +198,13 @@ glm::mat4 createMatFromQuatAndPos(const glm::quat& q, const glm::vec3& p);
glm::quat cancelOutRollAndPitch(const glm::quat& q);
glm::mat4 cancelOutRollAndPitch(const glm::mat4& m);
glm::vec3 transformPoint(const glm::mat4& m, const glm::vec3& p);
glm::vec3 transformVector(const glm::mat4& m, const glm::vec3& v);
// Calculate an orthogonal basis from a primary and secondary axis.
// The uAxis, vAxis & wAxis will form an orthognal basis.
// The primary axis will be the uAxis.
// The vAxis will be as close as possible to to the secondary axis.
void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& secondaryAxis,
glm::vec3& uAxisOut, glm::vec3& vAxisOut, glm::vec3& wAxisOut);
#endif // hifi_GLMHelpers_h