WIP checkin

* AnimManipulator: added absolute and relative position and translation support
* Rig: added _overrideFlags and _overridePoses for script overrides.
This commit is contained in:
Anthony J. Thibault 2015-11-16 18:49:47 -08:00
parent 516aff2ee0
commit 80eb247b9c
10 changed files with 258 additions and 87 deletions

View file

@ -75,7 +75,7 @@ function updateJoints(factor){
for (var i = 0; i < startPoseAndTransition.length; i++){
var scaledTransition = Vec3.multiply(startPoseAndTransition[i].transition, factor);
var rotation = Vec3.sum(startPoseAndTransition[i].start, scaledTransition);
MyAvatar.setJointData(startPoseAndTransition[i].joint, Quat.fromVec3Degrees( rotation ));
MyAvatar.setJointRotation(startPoseAndTransition[i].joint, Quat.fromVec3Degrees( rotation ));
}
}
@ -282,7 +282,8 @@ function update(deltaTime){
MyAvatar.position.z != avatarOldPosition.z ||
locationChanged) {
avatarOldPosition = MyAvatar.position;
/*
var SEARCH_RADIUS = 50;
var foundModels = Entities.findEntities(MyAvatar.position, SEARCH_RADIUS);
// Let's remove indicator that got out of radius
@ -306,6 +307,7 @@ function update(deltaTime){
if (hiddingSeats && passedTime >= animationLenght) {
showIndicators(true);
}
*/
}
}
var oldHost = location.hostname;

View file

@ -104,7 +104,7 @@
"data": {
"alpha": 0.0,
"joints": [
{ "var": "lean", "jointName": "Spine" }
{ "type": "absoluteRotation", "jointName": "Spine", "var": "lean" }
]
},
"children": []

View file

@ -605,9 +605,9 @@ void SkeletonModel::computeBoundingShape() {
*/
// AJT: REMOVE HARDCODED BOUNDING VOLUME
_boundingCapsuleRadius = 0.5f;
_boundingCapsuleHeight = 2.0f;
_boundingCapsuleLocalOffset = glm::vec3(0.0f, 1.0f, 0.0f);
_boundingCapsuleRadius = 0.3f;
_boundingCapsuleHeight = 1.3f;
_boundingCapsuleLocalOffset = glm::vec3(0.0f, -0.25f, 0.0f);
}
void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha) {

View file

@ -46,39 +46,15 @@ const AnimPoseVec& AnimManipulator::overlay(const AnimVariantMap& animVars, floa
if (jointVar.jointIndex >= 0) {
AnimPose defaultAbsPose;
// use the underPose as our default value if we can.
AnimPose defaultRelPose;
AnimPose parentAbsPose = AnimPose::identity;
if (jointVar.jointIndex <= (int)underPoses.size()) {
// jointVar is an absolute rotation, if it is not set we will use the underPose as our default value
defaultRelPose = underPoses[jointVar.jointIndex];
defaultAbsPose = _skeleton->getAbsolutePose(jointVar.jointIndex, underPoses);
defaultAbsPose.rot = animVars.lookup(jointVar.var, defaultAbsPose.rot);
// because jointVar is absolute, we must use an absolute parent frame to convert into a relative pose.
int parentIndex = _skeleton->getParentIndex(jointVar.jointIndex);
if (parentIndex >= 0) {
parentAbsPose = _skeleton->getAbsolutePose(parentIndex, underPoses);
}
} else {
// jointVar is an absolute rotation, if it is not set we will use the bindPose as our default value
defaultRelPose = AnimPose::identity;
defaultAbsPose = _skeleton->getAbsoluteBindPose(jointVar.jointIndex);
defaultAbsPose.rot = animVars.lookup(jointVar.var, defaultAbsPose.rot);
// because jointVar is absolute, we must use an absolute parent frame to convert into a relative pose
// here we use the bind pose
int parentIndex = _skeleton->getParentIndex(jointVar.jointIndex);
if (parentIndex >= 0) {
parentAbsPose = _skeleton->getAbsoluteBindPose(parentIndex);
}
}
// convert from absolute to relative
AnimPose relPose = parentAbsPose.inverse() * defaultAbsPose;
AnimPose relPose = computeRelativePoseFromJointVar(animVars, jointVar, defaultRelPose, underPoses);
// blend with underPose
::blend(1, &defaultRelPose, &relPose, _alpha, &_poses[jointVar.jointIndex]);
@ -114,3 +90,44 @@ const AnimPoseVec& AnimManipulator::getPosesInternal() const {
void AnimManipulator::addJointVar(const JointVar& jointVar) {
_jointVars.push_back(jointVar);
}
void AnimManipulator::removeAllJointVars() {
_jointVars.clear();
}
AnimPose AnimManipulator::computeRelativePoseFromJointVar(const AnimVariantMap& animVars, const JointVar& jointVar,
const AnimPose& defaultRelPose, const AnimPoseVec& underPoses) {
AnimPose defaultAbsPose = _skeleton->getAbsolutePose(jointVar.jointIndex, underPoses);
if (jointVar.type == JointVar::Type::AbsoluteRotation || jointVar.type == JointVar::Type::AbsolutePosition) {
if (jointVar.type == JointVar::Type::AbsoluteRotation) {
defaultAbsPose.rot = animVars.lookup(jointVar.var, defaultAbsPose.rot);
} else if (jointVar.type == JointVar::Type::AbsolutePosition) {
defaultAbsPose.trans = animVars.lookup(jointVar.var, defaultAbsPose.trans);
}
// because jointVar is absolute, we must use an absolute parent frame to convert into a relative pose.
AnimPose parentAbsPose = AnimPose::identity;
int parentIndex = _skeleton->getParentIndex(jointVar.jointIndex);
if (parentIndex >= 0) {
parentAbsPose = _skeleton->getAbsolutePose(parentIndex, underPoses);
}
// convert from absolute to relative
return parentAbsPose.inverse() * defaultAbsPose;
} else {
// override the default rel pose
AnimPose relPose = defaultRelPose;
if (jointVar.type == JointVar::Type::RelativeRotation) {
relPose.rot = animVars.lookup(jointVar.var, defaultRelPose.rot);
} else if (jointVar.type == JointVar::Type::RelativePosition) {
relPose.trans = animVars.lookup(jointVar.var, defaultRelPose.trans);
}
return relPose;
}
}

View file

@ -30,19 +30,33 @@ public:
virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) override;
struct JointVar {
JointVar(const QString& varIn, const QString& jointNameIn) : var(varIn), jointName(jointNameIn), jointIndex(-1), hasPerformedJointLookup(false) {}
enum class Type {
AbsoluteRotation = 0,
AbsolutePosition,
RelativeRotation,
RelativePosition,
NumTypes
};
JointVar(const QString& varIn, const QString& jointNameIn, Type typeIn) : var(varIn), jointName(jointNameIn), type(typeIn), jointIndex(-1), hasPerformedJointLookup(false) {}
QString var = "";
QString jointName = "";
Type type = Type::AbsoluteRotation;
int jointIndex = -1;
bool hasPerformedJointLookup = false;
bool isRelative = false;
};
void addJointVar(const JointVar& jointVar);
void removeAllJointVars();
protected:
// for AnimDebugDraw rendering
virtual const AnimPoseVec& getPosesInternal() const override;
AnimPose computeRelativePoseFromJointVar(const AnimVariantMap& animVars, const JointVar& jointVar,
const AnimPose& defaultRelPose, const AnimPoseVec& underPoses);
AnimPoseVec _poses;
float _alpha;
QString _alphaVar;

View file

@ -55,6 +55,41 @@ static const char* animNodeTypeToString(AnimNode::Type type) {
return nullptr;
}
static AnimNode::Type stringToAnimNodeType(const QString& str) {
// O(n), move to map when number of types becomes large.
const int NUM_TYPES = static_cast<int>(AnimNode::Type::NumTypes);
for (int i = 0; i < NUM_TYPES; i++) {
AnimNode::Type type = static_cast<AnimNode::Type>(i);
if (str == animNodeTypeToString(type)) {
return type;
}
}
return AnimNode::Type::NumTypes;
}
static const char* animManipulatorJointVarTypeToString(AnimManipulator::JointVar::Type type) {
switch (type) {
case AnimManipulator::JointVar::Type::AbsoluteRotation: return "absoluteRotation";
case AnimManipulator::JointVar::Type::AbsolutePosition: return "absolutePosition";
case AnimManipulator::JointVar::Type::RelativeRotation: return "relativeRotation";
case AnimManipulator::JointVar::Type::RelativePosition: return "relativePosition";
case AnimManipulator::JointVar::Type::NumTypes: return nullptr;
};
return nullptr;
}
static AnimManipulator::JointVar::Type stringToAnimManipulatorJointVarType(const QString& str) {
// O(n), move to map when number of types becomes large.
const int NUM_TYPES = static_cast<int>(AnimManipulator::JointVar::Type::NumTypes);
for (int i = 0; i < NUM_TYPES; i++) {
AnimManipulator::JointVar::Type type = static_cast<AnimManipulator::JointVar::Type>(i);
if (str == animManipulatorJointVarTypeToString(type)) {
return type;
}
}
return AnimManipulator::JointVar::Type::NumTypes;
}
static NodeLoaderFunc animNodeTypeToLoaderFunc(AnimNode::Type type) {
switch (type) {
case AnimNode::Type::Clip: return loadClipNode;
@ -120,17 +155,6 @@ static NodeProcessFunc animNodeTypeToProcessFunc(AnimNode::Type type) {
} \
float NAME = (float)NAME##_VAL.toDouble()
static AnimNode::Type stringToEnum(const QString& str) {
// O(n), move to map when number of types becomes large.
const int NUM_TYPES = static_cast<int>(AnimNode::Type::NumTypes);
for (int i = 0; i < NUM_TYPES; i++) {
AnimNode::Type type = static_cast<AnimNode::Type>(i);
if (str == animNodeTypeToString(type)) {
return type;
}
}
return AnimNode::Type::NumTypes;
}
static AnimNode::Pointer loadNode(const QJsonObject& jsonObj, const QUrl& jsonUrl) {
auto idVal = jsonObj.value("id");
@ -146,7 +170,7 @@ static AnimNode::Pointer loadNode(const QJsonObject& jsonObj, const QUrl& jsonUr
return nullptr;
}
QString typeStr = typeVal.toString();
AnimNode::Type type = stringToEnum(typeStr);
AnimNode::Type type = stringToAnimNodeType(typeStr);
if (type == AnimNode::Type::NumTypes) {
qCCritical(animation) << "AnimNodeLoader, unknown node type" << typeStr << ", id =" << id << ", url =" << jsonUrl.toDisplayString();
return nullptr;
@ -355,10 +379,17 @@ static AnimNode::Pointer loadManipulatorNode(const QJsonObject& jsonObj, const Q
}
auto jointObj = jointValue.toObject();
READ_STRING(var, jointObj, id, jsonUrl, nullptr);
READ_STRING(type, jointObj, id, jsonUrl, nullptr);
READ_STRING(jointName, jointObj, id, jsonUrl, nullptr);
READ_STRING(var, jointObj, id, jsonUrl, nullptr);
AnimManipulator::JointVar jointVar(var, jointName);
AnimManipulator::JointVar::Type jointVarType = stringToAnimManipulatorJointVarType(type);
if (jointVarType == AnimManipulator::JointVar::Type::NumTypes) {
qCCritical(animation) << "AnimNodeLoader, bad type in \"joints\", id =" << id << ", url =" << jsonUrl.toDisplayString();
return nullptr;
}
AnimManipulator::JointVar jointVar(var, jointName, jointVarType);
node->addJointVar(jointVar);
};

View file

@ -78,25 +78,40 @@ void AvatarRig::setHandPosition(int jointIndex,
void AvatarRig::setJointTranslation(int index, bool valid, const glm::vec3& translation, float priority) {
if (index != -1 && index < _jointStates.size()) {
JointState& state = _jointStates[index];
if (valid) {
state.setTranslation(translation, priority);
} else {
state.restoreTranslation(1.0f, priority);
// AJT: LEGACY
{
JointState& state = _jointStates[index];
if (valid) {
state.setTranslation(translation, priority);
} else {
state.restoreTranslation(1.0f, priority);
}
}
_overrideFlags[index] = true;
_overridePoses[index].trans = translation;
}
}
void AvatarRig::setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation, float priority) {
if (index != -1 && index < _jointStates.size()) {
JointState& state = _jointStates[index];
if (valid) {
state.setRotationInConstrainedFrame(rotation, priority);
state.setTranslation(translation, priority);
} else {
state.restoreRotation(1.0f, priority);
state.restoreTranslation(1.0f, priority);
// AJT: LEGACY
{
JointState& state = _jointStates[index];
if (valid) {
state.setRotationInConstrainedFrame(rotation, priority);
state.setTranslation(translation, priority);
} else {
state.restoreRotation(1.0f, priority);
state.restoreTranslation(1.0f, priority);
}
}
_overrideFlags[index] = true;
_overridePoses[index].rot = rotation;
_overridePoses[index].trans = translation;
}
}

View file

@ -13,13 +13,20 @@
void EntityRig::setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation, float priority) {
if (index != -1 && index < _jointStates.size()) {
JointState& state = _jointStates[index];
if (valid) {
state.setRotationInConstrainedFrame(rotation, priority);
// state.setTranslation(translation, priority);
} else {
state.restoreRotation(1.0f, priority);
// state.restoreTranslation(1.0f, priority);
// AJT: LEGACY
{
JointState& state = _jointStates[index];
if (valid) {
state.setRotationInConstrainedFrame(rotation, priority);
// state.setTranslation(translation, priority);
} else {
state.restoreRotation(1.0f, priority);
// state.restoreTranslation(1.0f, priority);
}
}
_overrideFlags[index] = true;
_overridePoses[index].rot = rotation;
}
}

View file

@ -23,16 +23,28 @@
#include "AnimClip.h"
#include "IKTarget.h"
#ifdef NDEBUG
#define ASSERT()
#else
#define ASSERT(cond) \
do { \
if (!(cond)) { \
int* ptr = nullptr; \
*ptr = 10; \
} \
} while (0)
#endif
void Rig::overrideAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame) {
// find an unused AnimClip clipNode
std::shared_ptr<AnimClip> clip;
if (_userAnimState == UserAnimState::None || _userAnimState == UserAnimState::B) {
_userAnimState = UserAnimState::A;
clip = std::dynamic_pointer_cast<AnimClip>(_animNode->getChild((int)_userAnimState));
clip = std::dynamic_pointer_cast<AnimClip>(_animNode->findByName("userAnimA"));
} else if (_userAnimState == UserAnimState::A) {
_userAnimState = UserAnimState::B;
clip = std::dynamic_pointer_cast<AnimClip>(_animNode->getChild((int)_userAnimState));
clip = std::dynamic_pointer_cast<AnimClip>(_animNode->findByName("userAnimB"));
}
// set parameters
@ -132,6 +144,10 @@ void Rig::destroyAnimGraph() {
_animSkeleton = nullptr;
_animLoader = nullptr;
_animNode = nullptr;
_relativePoses.clear();
_absolutePoses.clear();
_overridePoses.clear();
_overrideFlags.clear();
}
void Rig::initJointStates(const FBXGeometry& geometry, glm::mat4 modelOffset, int rootJointIndex,
@ -139,7 +155,18 @@ void Rig::initJointStates(const FBXGeometry& geometry, glm::mat4 modelOffset, in
int rightHandJointIndex, int rightElbowJointIndex, int rightShoulderJointIndex) {
_animSkeleton = std::make_shared<AnimSkeleton>(geometry);
_relativePoses.resize(_animSkeleton->getNumJoints());
_relativePoses.clear();
_relativePoses.resize(_animSkeleton->getNumJoints(), AnimPose::identity);
_absolutePoses.clear();
_absolutePoses.resize(_animSkeleton->getNumJoints(), AnimPose::identity);
_overridePoses.clear();
_overridePoses.resize(_animSkeleton->getNumJoints(), AnimPose::identity);
_overrideFlags.clear();
_overrideFlags.resize(_animSkeleton->getNumJoints(), true);
// AJT: LEGACY
{
@ -264,14 +291,25 @@ bool Rig::getJointStateTranslation(int index, glm::vec3& translation) const {
void Rig::clearJointState(int index) {
if (index != -1 && index < _jointStates.size()) {
// AJT: REMOVE
/*
JointState& state = _jointStates[index];
state.setRotationInConstrainedFrame(glm::quat(), 0.0f);
state.setTranslation(state.getDefaultTranslationInConstrainedFrame(), 0.0f);
*/
_overrideFlags[index] = false;
}
}
void Rig::clearJointStates() {
_jointStates.clear();
// AJT: LEGACY
/*
{
_jointStates.clear();
}
*/
_overrideFlags.clear();
_overrideFlags.resize(_animSkeleton->getNumJoints());
}
void Rig::clearJointAnimationPriority(int index) {
@ -375,12 +413,33 @@ glm::mat4 Rig::getJointTransform(int jointIndex) const {
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
return glm::mat4();
}
/*
// AJT: test if _absolutePoses are the same as jointTransforms
glm::mat4 newMat = _absolutePoses[jointIndex];
glm::mat4 oldMat = _jointStates[jointIndex].getTransform();
const float EPSILON = 0.0001f;
if (glm::length(newMat[0] - oldMat[0]) > EPSILON ||
glm::length(newMat[1] - oldMat[1]) > EPSILON ||
glm::length(newMat[2] - oldMat[2]) > EPSILON ||
glm::length(newMat[3] - oldMat[3]) > EPSILON) {
// error?
qCDebug(animation) << "AJT: mismatch for joint[" << jointIndex;
qCDebug(animation) << "AJT: oldMat = " << AnimPose(oldMat);
qCDebug(animation) << "AJT: newMat = " << AnimPose(newMat);
}
*/
// AJT: LEGACY
return _jointStates[jointIndex].getTransform();
}
void Rig::calcAnimAlpha(float speed, const std::vector<float>& referenceSpeeds, float* alphaOut) const {
assert(referenceSpeeds.size() > 0);
ASSERT(referenceSpeeds.size() > 0);
// calculate alpha from linear combination of referenceSpeeds.
float alpha = 0.0f;
@ -664,33 +723,38 @@ void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) {
// evaluate the animation
AnimNode::Triggers triggersOut;
AnimPoseVec poses = _animNode->evaluate(_animVars, deltaTime, triggersOut);
_relativePoses = _animNode->evaluate(_animVars, deltaTime, triggersOut);
if (_relativePoses.size() != _animSkeleton->getNumJoints()) {
// animations haven't been loaded yet.
_relativePoses.resize(_animSkeleton->getNumJoints(), AnimPose::identity);
}
_animVars.clearTriggers();
for (auto& trigger : triggersOut) {
_animVars.setTrigger(trigger);
}
clearJointStatePriorities();
// AJT: LEGACY
{
clearJointStatePriorities();
// copy poses into jointStates
const float PRIORITY = 1.0f;
for (size_t i = 0; i < poses.size(); i++) {
setJointRotationInConstrainedFrame((int)i, glm::inverse(_animSkeleton->getRelativeBindPose(i).rot) * poses[i].rot, PRIORITY, 1.0f);
setJointTranslation((int)i, true, poses[i].trans, PRIORITY);
// copy poses into jointStates
const float PRIORITY = 1.0f;
for (size_t i = 0; i < _relativePoses.size(); i++) {
setJointRotationInConstrainedFrame((int)i, glm::inverse(_animSkeleton->getRelativeBindPose(i).rot) * _relativePoses[i].rot, PRIORITY, 1.0f);
setJointTranslation((int)i, true, _relativePoses[i].trans, PRIORITY);
}
}
}
// AJT: REMOVE
/*
for (int i = 0; i < _jointStates.size(); i++) {
updateJointState(i, rootTransform);
}
*/
setModelOffset(rootTransform);
//applyOverridePoses();
buildAbsolutePoses();
for (int i = 0; i < _jointStates.size(); i++) {
_jointStates[i].resetTransformChanged();
// AJT: LEGACY
{
for (int i = 0; i < _jointStates.size(); i++) {
_jointStates[i].resetTransformChanged();
}
}
}
@ -1154,12 +1218,29 @@ bool Rig::getModelOffset(glm::vec3& modelOffsetOut) const {
}
}
void Rig::applyOverridePoses() {
if (!_animSkeleton) {
return;
}
ASSERT(_animSkeleton->getNumJoints() == _relativePoses.size());
ASSERT(_animSkeleton->getNumJoints() == _overrideFlags.size());
ASSERT(_animSkeleton->getNumJoints() == _overridePoses.size());
for (size_t i = 0; i < _overrideFlags.size(); i++) {
if (_overrideFlags[i]) {
_relativePoses[i] = _overridePoses[i];
}
}
}
void Rig::buildAbsolutePoses() {
if (!_animSkeleton) {
return;
}
assert(_animSkeleton->getNumJoints() == _relativePoses.size());
ASSERT(_animSkeleton->getNumJoints() == _relativePoses.size());
_absolutePoses.resize(_relativePoses.size());
for (int i = 0; i < (int)_relativePoses.size(); i++) {
int parentIndex = _animSkeleton->getParentIndex(i);

View file

@ -17,6 +17,7 @@
#include <QObject>
#include <QMutex>
#include <QScriptValue>
#include <vector>
#include "JointState.h" // We might want to change this (later) to something that doesn't depend on gpu, fbx and model. -HRS
@ -165,6 +166,7 @@ public:
protected:
void updateAnimationStateHandlers();
void applyOverridePoses();
void buildAbsolutePoses();
void updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist);
@ -178,6 +180,8 @@ public:
AnimPose _modelOffset;
AnimPoseVec _relativePoses;
AnimPoseVec _absolutePoses;
AnimPoseVec _overridePoses;
std::vector<bool> _overrideFlags;
int _rootJointIndex { -1 };