mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 10:47:11 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into decouple-avatar-updates
This commit is contained in:
commit
73a5714d66
19 changed files with 297 additions and 199 deletions
|
@ -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");
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -35,7 +35,7 @@ var wand = Entities.addEntity({
|
||||||
});
|
});
|
||||||
|
|
||||||
function cleanup() {
|
function cleanup() {
|
||||||
//Entities.deleteEntity(wand);
|
Entities.deleteEntity(wand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) << "[";
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue