Merge branch 'master' of https://github.com/highfidelity/hifi into decouple-avatar-updates

This commit is contained in:
Howard Stearns 2015-09-09 10:37:11 -07:00
commit 73a5714d66
19 changed files with 297 additions and 199 deletions

View file

@ -14,7 +14,7 @@ Script.load("selectAudioDevice.js");
Script.load("inspect.js"); Script.load("inspect.js");
Script.load("notifications.js"); Script.load("notifications.js");
Script.load("users.js"); Script.load("users.js");
Script.load("handControllerGrab.js"); Script.load("controllers/handControllerGrab.js");
Script.load("grab.js"); Script.load("grab.js");
Script.load("directory.js"); Script.load("directory.js");
Script.load("dialTone.js"); Script.load("dialTone.js");

View file

@ -71,7 +71,7 @@
if (_this.injector == null) { if (_this.injector == null) {
_this.injector = Audio.playSound(_this.song, { _this.injector = Audio.playSound(_this.song, {
position: props.position, // position of boombox entity position: props.position, // position of boombox entity
volume: 0.5, volume: 0.1,
loop: true loop: true
}); });
} else { } else {

View file

@ -96,20 +96,44 @@ mergeObjects = function(proto, custom) {
return result; return result;
} }
LOG_WARN = 1;
logWarn = function(str) { logWarn = function(str) {
print(str); if (LOG_WARN) {
print(str);
}
} }
LOG_ERROR = 1;
logError = function(str) { logError = function(str) {
print(str); if (LOG_ERROR) {
print(str);
}
} }
LOG_INFO = 1;
logInfo = function(str) { logInfo = function(str) {
print(str); if (LOG_INFO) {
print(str);
}
} }
LOG_DEBUG = 0;
logDebug = function(str) { logDebug = function(str) {
print(str); if (LOG_DEBUG) {
print(str);
}
}
LOG_TRACE = 0;
logTrace = function(str) {
if (LOG_TRACE) {
print(str);
}
} }
// Computes the penetration between a point and a sphere (centered at the origin) // Computes the penetration between a point and a sphere (centered at the origin)

View file

@ -26,7 +26,7 @@
this.collisionWithEntity = function(myID, otherID, collision) { this.collisionWithEntity = function(myID, otherID, collision) {
//if(Entites.getEntityProperties(otherID).userData.objectType==='') { merge bubbles?} //if(Entites.getEntityProperties(otherID).userData.objectType==='') { merge bubbles?}
Entities.deleteEntity(myID); // Entities.deleteEntity(myID);
// this.burstBubbleSound(collision.contactPoint) // this.burstBubbleSound(collision.contactPoint)
}; };

View file

@ -35,7 +35,7 @@ var wand = Entities.addEntity({
}); });
function cleanup() { function cleanup() {
//Entities.deleteEntity(wand); Entities.deleteEntity(wand);
} }

View file

@ -761,7 +761,7 @@ void MyAvatar::setEnableDebugDrawAnimPose(bool isEnabled) {
_enableDebugDrawAnimPose = isEnabled; _enableDebugDrawAnimPose = isEnabled;
if (!isEnabled) { if (!isEnabled) {
AnimDebugDraw::getInstance().removeAnimNode("myAvatar"); AnimDebugDraw::getInstance().removePoses("myAvatar");
} }
} }
@ -1274,8 +1274,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) {
@ -1287,26 +1285,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

@ -323,6 +323,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

@ -103,13 +103,15 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
_rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation()); _rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation());
} }
Model::updateRig(deltaTime, parentTransform); Model::updateRig(deltaTime, parentTransform);
Head* head = _owningAvatar->getHead();
if (_owningAvatar->isMyAvatar()) { if (_owningAvatar->isMyAvatar()) {
MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar);
const FBXGeometry& geometry = _geometry->getFBXGeometry(); const FBXGeometry& geometry = _geometry->getFBXGeometry();
Head* head = _owningAvatar->getHead();
Rig::HeadParameters params; Rig::HeadParameters params;
params.modelRotation = getRotation(); params.modelRotation = getRotation();
params.modelTranslation = getTranslation(); params.modelTranslation = getTranslation();
params.enableLean = qApp->isHMDMode() && !myAvatar->getStandingHMDSensorMode();
params.leanSideways = head->getFinalLeanSideways(); params.leanSideways = head->getFinalLeanSideways();
params.leanForward = head->getFinalLeanForward(); params.leanForward = head->getFinalLeanForward();
params.torsoTwist = head->getTorsoTwist(); params.torsoTwist = head->getTorsoTwist();
@ -133,7 +135,6 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
// However, in the !isLookingAtMe case, the eyes aren't rotating the way they should right now. // However, in the !isLookingAtMe case, the eyes aren't rotating the way they should right now.
// We will revisit that as priorities allow, and particularly after the new rig/animation/joints. // We will revisit that as priorities allow, and particularly after the new rig/animation/joints.
const FBXGeometry& geometry = _geometry->getFBXGeometry(); const FBXGeometry& geometry = _geometry->getFBXGeometry();
Head* head = _owningAvatar->getHead();
// If the head is not positioned, updateEyeJoints won't get the math right // If the head is not positioned, updateEyeJoints won't get the math right
glm::quat headOrientation; glm::quat headOrientation;
_rig->getJointRotation(geometry.headJointIndex, headOrientation); _rig->getJointRotation(geometry.headJointIndex, headOrientation);
@ -548,14 +549,24 @@ void SkeletonModel::computeBoundingShape() {
totalExtents.addPoint(glm::vec3(0.0f)); totalExtents.addPoint(glm::vec3(0.0f));
int numStates = _rig->getJointStateCount(); int numStates = _rig->getJointStateCount();
for (int i = 0; i < numStates; i++) { for (int i = 0; i < numStates; i++) {
// compute the default transform of this joint
const JointState& state = _rig->getJointState(i); const JointState& state = _rig->getJointState(i);
// Each joint contributes a sphere at its position const glm::mat4& jointTransform = state.getTransform();
glm::vec3 axis(state.getBoneRadius()); float scale = extractUniformScale(jointTransform);
glm::vec3 jointPosition = state.getPosition();
totalExtents.addPoint(jointPosition + axis); // Each joint contributes a capsule defined by FBXJoint.shapeInfo.
totalExtents.addPoint(jointPosition - axis); // For totalExtents we use the capsule endpoints expanded by the radius.
const FBXJointShapeInfo& shapeInfo = geometry.joints.at(i).shapeInfo;
for (int j = 0; j < shapeInfo.points.size(); ++j) {
glm::vec3 transformedPoint = extractTranslation(jointTransform * glm::translate(shapeInfo.points[j]));
vec3 radius(scale * shapeInfo.radius);
totalExtents.addPoint(transformedPoint + radius);
totalExtents.addPoint(transformedPoint - radius);
}
// HACK so that default legless robot doesn't knuckle-drag
if (shapeInfo.points.size() == 0 && (state.getName() == "LeftFoot" || state.getName() == "RightFoot")) {
totalExtents.addPoint(extractTranslation(jointTransform));
}
} }
// compute bounding shape parameters // compute bounding shape parameters

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

@ -41,7 +41,6 @@ void JointState::copyState(const JointState& other) {
// DO NOT copy _constraint // DO NOT copy _constraint
_name = other._name; _name = other._name;
_isFree = other._isFree; _isFree = other._isFree;
_boneRadius = other._boneRadius;
_parentIndex = other._parentIndex; _parentIndex = other._parentIndex;
_defaultRotation = other._defaultRotation; _defaultRotation = other._defaultRotation;
_inverseDefaultRotation = other._inverseDefaultRotation; _inverseDefaultRotation = other._inverseDefaultRotation;
@ -58,7 +57,6 @@ JointState::JointState(const FBXJoint& joint) {
_rotationInConstrainedFrame = joint.rotation; _rotationInConstrainedFrame = joint.rotation;
_name = joint.name; _name = joint.name;
_isFree = joint.isFree; _isFree = joint.isFree;
_boneRadius = joint.boneRadius;
_parentIndex = joint.parentIndex; _parentIndex = joint.parentIndex;
_translation = joint.translation; _translation = joint.translation;
_defaultRotation = joint.rotation; _defaultRotation = joint.rotation;

View file

@ -118,7 +118,6 @@ public:
const glm::quat& getDefaultRotation() const { return _defaultRotation; } const glm::quat& getDefaultRotation() const { return _defaultRotation; }
const glm::quat& getInverseDefaultRotation() const { return _inverseDefaultRotation; } const glm::quat& getInverseDefaultRotation() const { return _inverseDefaultRotation; }
const QString& getName() const { return _name; } const QString& getName() const { return _name; }
float getBoneRadius() const { return _boneRadius; }
bool getIsFree() const { return _isFree; } bool getIsFree() const { return _isFree; }
float getAnimationPriority() const { return _animationPriority; } float getAnimationPriority() const { return _animationPriority; }
void setAnimationPriority(float priority) { _animationPriority = priority; } void setAnimationPriority(float priority) { _animationPriority = priority; }
@ -149,7 +148,6 @@ private:
QString _name; QString _name;
int _parentIndex; int _parentIndex;
bool _isFree; bool _isFree;
float _boneRadius;
glm::vec3 _rotationMin; glm::vec3 _rotationMin;
glm::vec3 _rotationMax; glm::vec3 _rotationMax;
glm::quat _preRotation; glm::quat _preRotation;

View file

@ -477,7 +477,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
} }
if (glm::length(localVel) > moveThresh) { if (glm::length(localVel) > moveThresh) {
if (fabs(forwardSpeed) > 0.5f * fabs(lateralSpeed)) { if (fabsf(forwardSpeed) > 0.5f * fabsf(lateralSpeed)) {
if (forwardSpeed > 0.0f) { if (forwardSpeed > 0.0f) {
// forward // forward
_animVars.set("isMovingForward", true); _animVars.set("isMovingForward", true);
@ -501,7 +501,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
} }
_state = RigRole::Move; _state = RigRole::Move;
} else { } else {
if (fabs(turningSpeed) > turnThresh) { if (fabsf(turningSpeed) > turnThresh) {
if (turningSpeed > 0.0f) { if (turningSpeed > 0.0f) {
// turning right // turning right
_animVars.set("isTurningRight", true); _animVars.set("isTurningRight", true);
@ -901,19 +901,20 @@ 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();
} }
} }
void Rig::setJointTransform(int jointIndex, glm::mat4 newTransform) {
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
return;
}
_jointStates[jointIndex].setTransform(newTransform);
}
void Rig::setJointVisibleTransform(int jointIndex, glm::mat4 newTransform) { void Rig::setJointVisibleTransform(int jointIndex, glm::mat4 newTransform) {
if (jointIndex == -1 || jointIndex >= _jointStates.size()) { if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
return; return;
@ -936,7 +937,9 @@ glm::quat Rig::getJointDefaultRotationInParentFrame(int jointIndex) {
} }
void Rig::updateFromHeadParameters(const HeadParameters& params) { void Rig::updateFromHeadParameters(const HeadParameters& params) {
updateLeanJoint(params.leanJointIndex, params.leanSideways, params.leanForward, params.torsoTwist); if (params.enableLean) {
updateLeanJoint(params.leanJointIndex, params.leanSideways, params.leanForward, params.torsoTwist);
}
updateNeckJoint(params.neckJointIndex, params.localHeadOrientation, params.leanSideways, params.leanForward, params.torsoTwist); updateNeckJoint(params.neckJointIndex, params.localHeadOrientation, params.leanSideways, params.leanForward, params.torsoTwist);
updateEyeJoints(params.leftEyeJointIndex, params.rightEyeJointIndex, params.modelTranslation, params.modelRotation, updateEyeJoints(params.leftEyeJointIndex, params.rightEyeJointIndex, params.modelTranslation, params.modelRotation,
params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade); params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade);
@ -1010,16 +1013,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,13 +50,13 @@ 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 {
float leanSideways = 0.0f; // degrees float leanSideways = 0.0f; // degrees
float leanForward = 0.0f; // degrees float leanForward = 0.0f; // degrees
float torsoTwist = 0.0f; // degrees float torsoTwist = 0.0f; // degrees
bool enableLean = false;
glm::quat modelRotation = glm::quat(); glm::quat modelRotation = glm::quat();
glm::quat localHeadOrientation = glm::quat(); glm::quat localHeadOrientation = glm::quat();
glm::quat worldHeadOrientation = glm::quat(); glm::quat worldHeadOrientation = glm::quat();
@ -133,7 +133,6 @@ public:
glm::vec3 translation, glm::quat rotation) const; glm::vec3 translation, glm::quat rotation) const;
bool getVisibleJointRotationInWorldFrame(int jointIndex, glm::quat& result, glm::quat rotation) const; bool getVisibleJointRotationInWorldFrame(int jointIndex, glm::quat& result, glm::quat rotation) const;
glm::mat4 getJointTransform(int jointIndex) const; glm::mat4 getJointTransform(int jointIndex) const;
void setJointTransform(int jointIndex, glm::mat4 newTransform);
glm::mat4 getJointVisibleTransform(int jointIndex) const; glm::mat4 getJointVisibleTransform(int jointIndex) const;
void setJointVisibleTransform(int jointIndex, glm::mat4 newTransform); void setJointVisibleTransform(int jointIndex, glm::mat4 newTransform);
// Start or stop animations as needed. // Start or stop animations as needed.
@ -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

@ -1257,21 +1257,7 @@ QString getString(const QVariant& value) {
return list.isEmpty() ? value.toString() : list.at(0).toString(); return list.isEmpty() ? value.toString() : list.at(0).toString();
} }
class JointShapeInfo { typedef std::vector<glm::vec3> ShapeVertices;
public:
JointShapeInfo() : numVertices(0),
sumVertexWeights(0.0f), sumWeightedRadii(0.0f), numVertexWeights(0),
boneBegin(0.0f), averageRadius(0.0f) {
}
// NOTE: the points here are in the "joint frame" which has the "jointEnd" at the origin
int numVertices; // num vertices from contributing meshes
float sumVertexWeights; // sum of all vertex weights
float sumWeightedRadii; // sum of weighted vertices
int numVertexWeights; // num vertices that contributed to sums
glm::vec3 boneBegin; // parent joint location (in joint frame)
float averageRadius;
};
class AnimationCurve { class AnimationCurve {
public: public:
@ -2282,22 +2268,21 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
joint.postTransform = model.postTransform; joint.postTransform = model.postTransform;
joint.rotationMin = model.rotationMin; joint.rotationMin = model.rotationMin;
joint.rotationMax = model.rotationMax; joint.rotationMax = model.rotationMax;
glm::quat combinedRotation = model.preRotation * model.rotation * model.postRotation; glm::quat combinedRotation = joint.preRotation * joint.rotation * joint.postRotation;
if (joint.parentIndex == -1) { if (joint.parentIndex == -1) {
joint.transform = geometry.offset * glm::translate(model.translation) * model.preTransform * joint.transform = geometry.offset * glm::translate(joint.translation) * joint.preTransform *
glm::mat4_cast(combinedRotation) * model.postTransform; glm::mat4_cast(combinedRotation) * joint.postTransform;
joint.inverseDefaultRotation = glm::inverse(combinedRotation); joint.inverseDefaultRotation = glm::inverse(combinedRotation);
joint.distanceToParent = 0.0f; joint.distanceToParent = 0.0f;
} else { } else {
const FBXJoint& parentJoint = geometry.joints.at(joint.parentIndex); const FBXJoint& parentJoint = geometry.joints.at(joint.parentIndex);
joint.transform = parentJoint.transform * glm::translate(model.translation) * joint.transform = parentJoint.transform * glm::translate(joint.translation) *
model.preTransform * glm::mat4_cast(combinedRotation) * model.postTransform; joint.preTransform * glm::mat4_cast(combinedRotation) * joint.postTransform;
joint.inverseDefaultRotation = glm::inverse(combinedRotation) * parentJoint.inverseDefaultRotation; joint.inverseDefaultRotation = glm::inverse(combinedRotation) * parentJoint.inverseDefaultRotation;
joint.distanceToParent = glm::distance(extractTranslation(parentJoint.transform), joint.distanceToParent = glm::distance(extractTranslation(parentJoint.transform),
extractTranslation(joint.transform)); extractTranslation(joint.transform));
} }
joint.boneRadius = 0.0f;
joint.inverseBindRotation = joint.inverseDefaultRotation; joint.inverseBindRotation = joint.inverseDefaultRotation;
joint.name = model.name; joint.name = model.name;
@ -2326,9 +2311,10 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
zCurve.values.isEmpty() ? defaultValues.z : zCurve.values.at(i % zCurve.values.size())))); zCurve.values.isEmpty() ? defaultValues.z : zCurve.values.at(i % zCurve.values.size()))));
} }
} }
// for each joint we allocate a JointShapeInfo in which we'll store collision shape info
QVector<JointShapeInfo> jointShapeInfos; // NOTE: shapeVertices are in joint-frame
jointShapeInfos.resize(geometry.joints.size()); QVector<ShapeVertices> shapeVertices;
shapeVertices.resize(geometry.joints.size());
// find our special joints // find our special joints
geometry.leftEyeJointIndex = modelIDs.indexOf(jointEyeLeftID); geometry.leftEyeJointIndex = modelIDs.indexOf(jointEyeLeftID);
@ -2585,8 +2571,10 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
boneDirection /= boneLength; boneDirection /= boneLength;
} }
} }
float radiusScale = extractUniformScale(joint.transform * fbxCluster.inverseBindMatrix);
JointShapeInfo& jointShapeInfo = jointShapeInfos[jointIndex]; float clusterScale = extractUniformScale(fbxCluster.inverseBindMatrix);
glm::mat4 meshToJoint = glm::inverse(joint.bindTransform) * modelTransform;
ShapeVertices& points = shapeVertices[jointIndex];
float totalWeight = 0.0f; float totalWeight = 0.0f;
for (int j = 0; j < cluster.indices.size(); j++) { for (int j = 0; j < cluster.indices.size(); j++) {
@ -2595,18 +2583,13 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
totalWeight += weight; totalWeight += weight;
for (QMultiHash<int, int>::const_iterator it = extracted.newIndices.constFind(oldIndex); for (QMultiHash<int, int>::const_iterator it = extracted.newIndices.constFind(oldIndex);
it != extracted.newIndices.end() && it.key() == oldIndex; it++) { it != extracted.newIndices.end() && it.key() == oldIndex; it++) {
// expand the bone radius for vertices with at least 1/4 weight
// remember vertices with at least 1/4 weight
const float EXPANSION_WEIGHT_THRESHOLD = 0.25f; const float EXPANSION_WEIGHT_THRESHOLD = 0.25f;
if (weight > EXPANSION_WEIGHT_THRESHOLD) { if (weight > EXPANSION_WEIGHT_THRESHOLD) {
const glm::vec3& vertex = extracted.mesh.vertices.at(it.value()); // transform to joint-frame and save for later
float proj = glm::dot(boneDirection, boneEnd - vertex); const glm::mat4 vertexTransform = meshToJoint * glm::translate(extracted.mesh.vertices.at(it.value()));
float radiusWeight = (proj < 0.0f || proj > boneLength) ? 0.5f * weight : weight; points.push_back(extractTranslation(vertexTransform) * clusterScale);
jointShapeInfo.sumVertexWeights += radiusWeight;
jointShapeInfo.sumWeightedRadii += radiusWeight * radiusScale * glm::distance(vertex, boneEnd - boneDirection * proj);
++jointShapeInfo.numVertexWeights;
++jointShapeInfo.numVertices;
} }
// look for an unused slot in the weights vector // look for an unused slot in the weights vector
@ -2649,54 +2632,16 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
// this is a single-mesh joint // this is a single-mesh joint
int jointIndex = maxJointIndex; int jointIndex = maxJointIndex;
FBXJoint& joint = geometry.joints[jointIndex]; FBXJoint& joint = geometry.joints[jointIndex];
JointShapeInfo& jointShapeInfo = jointShapeInfos[jointIndex];
glm::mat4 transformJointToMesh = inverseModelTransform * joint.bindTransform; // transform cluster vertices to joint-frame and save for later
glm::vec3 boneEnd = extractTranslation(transformJointToMesh); float clusterScale = extractUniformScale(firstFBXCluster.inverseBindMatrix);
glm::vec3 boneBegin = boneEnd; glm::mat4 meshToJoint = glm::inverse(joint.bindTransform) * modelTransform;
ShapeVertices& points = shapeVertices[jointIndex];
glm::vec3 boneDirection;
float boneLength = 0.0f;
if (joint.parentIndex != -1) {
boneBegin = extractTranslation(inverseModelTransform * geometry.joints[joint.parentIndex].bindTransform);
boneDirection = boneEnd - boneBegin;
boneLength = glm::length(boneDirection);
if (boneLength > EPSILON) {
boneDirection /= boneLength;
}
}
float radiusScale = extractUniformScale(joint.transform * firstFBXCluster.inverseBindMatrix);
// compute average vertex
glm::vec3 averageVertex(0.0f);
foreach (const glm::vec3& vertex, extracted.mesh.vertices) { foreach (const glm::vec3& vertex, extracted.mesh.vertices) {
float proj = glm::dot(boneDirection, boneEnd - vertex); const glm::mat4 vertexTransform = meshToJoint * glm::translate(vertex);
float radiusWeight = (proj < 0.0f || proj > boneLength) ? 0.5f : 1.0f; points.push_back(extractTranslation(vertexTransform) * clusterScale);
jointShapeInfo.sumVertexWeights += radiusWeight;
jointShapeInfo.sumWeightedRadii += radiusWeight * radiusScale * glm::distance(vertex, boneEnd - boneDirection * proj);
++jointShapeInfo.numVertexWeights;
averageVertex += vertex;
} }
// compute joint's radius
int numVertices = extracted.mesh.vertices.size();
jointShapeInfo.numVertices = numVertices;
if (numVertices > 0) {
// compute average radius
averageVertex /= (float)jointShapeInfo.numVertices;
float averageRadius = 0.0f;
foreach (const glm::vec3& vertex, extracted.mesh.vertices) {
averageRadius += glm::distance(vertex, averageVertex);
}
averageRadius *= radiusScale / (float)jointShapeInfo.numVertices;
// final radius is minimum of average and weighted
float weightedRadius = jointShapeInfo.sumWeightedRadii / jointShapeInfo.sumVertexWeights;
jointShapeInfo.averageRadius = glm::min(weightedRadius, averageRadius);
}
// clear sumVertexWeights (this flags it as a single-mesh joint for later)
jointShapeInfo.sumVertexWeights = 0.0f;
} }
extracted.mesh.isEye = (maxJointIndex == geometry.leftEyeJointIndex || maxJointIndex == geometry.rightEyeJointIndex); extracted.mesh.isEye = (maxJointIndex == geometry.leftEyeJointIndex || maxJointIndex == geometry.rightEyeJointIndex);
@ -2721,24 +2666,59 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
glm::vec3 defaultCapsuleAxis(0.0f, 1.0f, 0.0f); glm::vec3 defaultCapsuleAxis(0.0f, 1.0f, 0.0f);
for (int i = 0; i < geometry.joints.size(); ++i) { for (int i = 0; i < geometry.joints.size(); ++i) {
FBXJoint& joint = geometry.joints[i]; FBXJoint& joint = geometry.joints[i];
JointShapeInfo& jointShapeInfo = jointShapeInfos[i];
if (joint.parentIndex == -1) { // NOTE: points are in joint-frame
jointShapeInfo.boneBegin = glm::vec3(0.0f); // compute average point
ShapeVertices& points = shapeVertices[i];
glm::vec3 avgPoint = glm::vec3(0.0f);
for (uint32_t j = 0; j < points.size(); ++j) {
avgPoint += points[j];
}
avgPoint /= (float)points.size();
// compute axis from begin to avgPoint
glm::vec3 begin(0.0f);
glm::vec3 end = avgPoint;
glm::vec3 axis = end - begin;
float axisLength = glm::length(axis);
if (axisLength > EPSILON) {
axis /= axisLength;
} else { } else {
const FBXJoint& parentJoint = geometry.joints[joint.parentIndex]; axis = glm::vec3(0.0f);
glm::quat inverseRotation = glm::inverse(extractRotation(joint.transform));
jointShapeInfo.boneBegin = inverseRotation * (extractTranslation(parentJoint.transform) - extractTranslation(joint.transform));
} }
if (jointShapeInfo.sumVertexWeights > 0.0f) { // measure average cylindrical radius
// mutiple meshes contributed to the bone radius and now that all float avgRadius = 0.0f;
// contributing meshes are done we can finally compute the boneRadius if (points.size() > 0) {
joint.boneRadius = jointShapeInfo.sumWeightedRadii / jointShapeInfo.sumVertexWeights; float minProjection = FLT_MAX;
} else { float maxProjection = -FLT_MIN;
// single-mesh joint for (uint32_t j = 0; j < points.size(); ++j) {
joint.boneRadius = jointShapeInfo.averageRadius; glm::vec3 offset = points[j] - avgPoint;
float projection = glm::dot(offset, axis);
maxProjection = glm::max(maxProjection, projection);
minProjection = glm::min(minProjection, projection);
avgRadius += glm::length(offset - projection * axis);
}
avgRadius /= (float)points.size();
// compute endpoints of capsule in joint-frame
glm::vec3 capsuleBegin = avgPoint;
glm::vec3 capsuleEnd = avgPoint;
if (maxProjection - minProjection < 2.0f * avgRadius) {
// the mesh-as-cylinder approximation is too short to collide as a capsule
// so we'll collapse it to a sphere (although that isn't a very good approximation)
capsuleBegin = avgPoint + 0.5f * (maxProjection + minProjection) * axis;
capsuleEnd = capsuleBegin;
} else {
capsuleBegin = avgPoint + (minProjection + avgRadius) * axis;
capsuleEnd = avgPoint + (maxProjection - avgRadius) * axis;
}
// save points for later
joint.shapeInfo.points.push_back(capsuleBegin);
joint.shapeInfo.points.push_back(capsuleEnd);
} }
joint.shapeInfo.radius = avgRadius;
} }
geometry.palmDirection = parseVec3(mapping.value("palmDirection", "0, -1, 0").toString()); geometry.palmDirection = parseVec3(mapping.value("palmDirection", "0, -1, 0").toString());

View file

@ -55,15 +55,21 @@ public:
QVector<glm::vec3> normals; QVector<glm::vec3> normals;
}; };
struct FBXJointShapeInfo {
// same units and frame as FBXJoint.translation
QVector<glm::vec3> points;
float radius;
};
/// A single joint (transformation node) extracted from an FBX document. /// A single joint (transformation node) extracted from an FBX document.
class FBXJoint { class FBXJoint {
public: public:
bool isFree; FBXJointShapeInfo shapeInfo;
QVector<int> freeLineage; QVector<int> freeLineage;
bool isFree;
int parentIndex; int parentIndex;
float distanceToParent; float distanceToParent;
float boneRadius;
// http://download.autodesk.com/us/fbx/20112/FBX_SDK_HELP/SDKRef/a00209.html // http://download.autodesk.com/us/fbx/20112/FBX_SDK_HELP/SDKRef/a00209.html

View file

@ -441,7 +441,6 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping,
geometry.joints[0].isFree = false; geometry.joints[0].isFree = false;
geometry.joints[0].parentIndex = -1; geometry.joints[0].parentIndex = -1;
geometry.joints[0].distanceToParent = 0; geometry.joints[0].distanceToParent = 0;
geometry.joints[0].boneRadius = 0;
geometry.joints[0].translation = glm::vec3(0, 0, 0); geometry.joints[0].translation = glm::vec3(0, 0, 0);
geometry.joints[0].rotationMin = glm::vec3(0, 0, 0); geometry.joints[0].rotationMin = glm::vec3(0, 0, 0);
geometry.joints[0].rotationMax = glm::vec3(0, 0, 0); geometry.joints[0].rotationMax = glm::vec3(0, 0, 0);
@ -617,7 +616,6 @@ void fbxDebugDump(const FBXGeometry& fbxgeo) {
qCDebug(modelformat) << " freeLineage" << joint.freeLineage; qCDebug(modelformat) << " freeLineage" << joint.freeLineage;
qCDebug(modelformat) << " parentIndex" << joint.parentIndex; qCDebug(modelformat) << " parentIndex" << joint.parentIndex;
qCDebug(modelformat) << " distanceToParent" << joint.distanceToParent; qCDebug(modelformat) << " distanceToParent" << joint.distanceToParent;
qCDebug(modelformat) << " boneRadius" << joint.boneRadius;
qCDebug(modelformat) << " translation" << joint.translation; qCDebug(modelformat) << " translation" << joint.translation;
qCDebug(modelformat) << " preTransform" << joint.preTransform; qCDebug(modelformat) << " preTransform" << joint.preTransform;
qCDebug(modelformat) << " preRotation" << joint.preRotation; qCDebug(modelformat) << " preRotation" << joint.preRotation;

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;