move AnimationHandle from render-utils to animation. give Rig some jointstates and animation lists

This commit is contained in:
Seth Alves 2015-07-17 13:31:48 -07:00
parent 75a35f9fcf
commit bcd6b30ec3
14 changed files with 220 additions and 99 deletions

View file

@ -28,7 +28,7 @@ enum CameraMode
};
Q_DECLARE_METATYPE(CameraMode);
static int cameraModeId = qRegisterMetaType<CameraMode>();
// static int cameraModeId = qRegisterMetaType<CameraMode>();
class Camera : public QObject {
Q_OBJECT

View file

@ -49,7 +49,6 @@ void FaceModel::simulate(float deltaTime, bool fullUpdate) {
}
void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) {
Avatar* owningAvatar = static_cast<Avatar*>(_owningHead->_owningAvatar);
// get the rotation axes in joint space and use them to adjust the rotation
glm::mat3 axes = glm::mat3_cast(glm::quat());
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() *

View file

@ -488,7 +488,7 @@ void MyAvatar::loadLastRecording() {
}
AnimationHandlePointer MyAvatar::addAnimationHandle() {
AnimationHandlePointer handle = _skeletonModel.createAnimationHandle();
AnimationHandlePointer handle = _rig.createAnimationHandle();
_animationHandles.append(handle);
return handle;
}
@ -506,7 +506,7 @@ void MyAvatar::startAnimation(const QString& url, float fps, float priority,
Q_ARG(float, lastFrame), Q_ARG(const QStringList&, maskedJoints));
return;
}
AnimationHandlePointer handle = _skeletonModel.createAnimationHandle();
AnimationHandlePointer handle = _rig.createAnimationHandle();
handle->setURL(url);
handle->setFPS(fps);
handle->setPriority(priority);
@ -534,7 +534,7 @@ void MyAvatar::startAnimationByRole(const QString& role, const QString& url, flo
}
}
// no joy; use the parameters provided
AnimationHandlePointer handle = _skeletonModel.createAnimationHandle();
AnimationHandlePointer handle = _rig.createAnimationHandle();
handle->setRole(role);
handle->setURL(url);
handle->setFPS(fps);

View file

@ -156,7 +156,7 @@ AnimationPanel::AnimationPanel(AnimationsDialog* dialog, const AnimationHandlePo
buttons->addWidget(remove);
connect(remove, SIGNAL(clicked(bool)), SLOT(removeHandle()));
_stop->connect(_handle.data(), SIGNAL(runningChanged(bool)), SLOT(setEnabled(bool)));
_stop->connect(_handle.get(), SIGNAL(runningChanged(bool)), SLOT(setEnabled(bool)));
_stop->setEnabled(_handle->isRunning());
}

View file

@ -35,7 +35,6 @@ void Cube3DOverlay::render(RenderArgs* args) {
// TODO: handle registration point??
glm::vec3 position = getPosition();
glm::vec3 center = getCenter();
glm::vec3 dimensions = getDimensions();
glm::quat rotation = getRotation();

View file

@ -30,7 +30,7 @@ void LocalModelsOverlay::update(float deltatime) {
void LocalModelsOverlay::render(RenderArgs* args) {
if (_visible) {
float glowLevel = getGlowLevel(); // FIXME, glowing removed for now
// float glowLevel = getGlowLevel(); // FIXME, glowing removed for now
auto batch = args ->_batch;
Application* app = Application::getInstance();

View file

@ -10,7 +10,7 @@
//
#include "AnimationHandle.h"
#include "Model.h"
void AnimationHandle::setURL(const QUrl& url) {
if (_url != url) {
@ -20,28 +20,17 @@ void AnimationHandle::setURL(const QUrl& url) {
}
}
static void insertSorted(QList<AnimationHandlePointer>& handles, const AnimationHandlePointer& handle) {
for (QList<AnimationHandlePointer>::iterator it = handles.begin(); it != handles.end(); it++) {
if (handle->getPriority() > (*it)->getPriority()) {
handles.insert(it, handle);
return;
}
}
handles.append(handle);
}
void AnimationHandle::setPriority(float priority) {
if (_priority == priority) {
return;
}
if (isRunning()) {
_model->_runningAnimations.removeOne(_self);
_rig->removeRunningAnimation(getAnimationHandlePointer());
if (priority < _priority) {
replaceMatchingPriorities(priority);
}
_priority = priority;
insertSorted(_model->_runningAnimations, _self);
_rig->addRunningAnimation(getAnimationHandlePointer());
} else {
_priority = priority;
}
@ -68,21 +57,21 @@ void AnimationHandle::setRunning(bool running) {
}
_animationLoop.setRunning(running);
if (isRunning()) {
if (!_model->_runningAnimations.contains(_self)) {
insertSorted(_model->_runningAnimations, _self);
if (!_rig->isRunningAnimation(getAnimationHandlePointer())) {
_rig->addRunningAnimation(getAnimationHandlePointer());
}
} else {
_model->_runningAnimations.removeOne(_self);
_rig->removeRunningAnimation(getAnimationHandlePointer());
restoreJoints();
replaceMatchingPriorities(0.0f);
}
emit runningChanged(isRunning());
}
AnimationHandle::AnimationHandle(Model* model) :
QObject(model),
_model(model),
_priority(1.0f)
AnimationHandle::AnimationHandle(RigPointer rig) :
QObject(rig.get()),
_rig(rig),
_priority(1.0f)
{
}
@ -110,42 +99,52 @@ void AnimationHandle::setAnimationDetails(const AnimationDetails& details) {
}
void AnimationHandle::setJointMappings(QVector<int> jointMappings) {
_jointMappings = jointMappings;
}
void AnimationHandle::simulate(float deltaTime) {
if (!_animation || !_animation->isLoaded()) {
return;
}
_animationLoop.simulate(deltaTime);
// update the joint mappings if necessary/possible
if (_jointMappings.isEmpty()) {
if (_model && _model->isActive()) {
_jointMappings = _model->getGeometry()->getJointMappings(_animation);
}
if (_jointMappings.isEmpty()) {
return;
}
if (!_maskedJoints.isEmpty()) {
const FBXGeometry& geometry = _model->getGeometry()->getFBXGeometry();
for (int i = 0; i < _jointMappings.size(); i++) {
int& mapping = _jointMappings[i];
if (mapping != -1 && _maskedJoints.contains(geometry.joints.at(mapping).name)) {
mapping = -1;
}
}
}
qDebug() << "AnimationHandle::simulate -- _jointMappings.isEmpty()";
return;
}
// // update the joint mappings if necessary/possible
// if (_jointMappings.isEmpty()) {
// if (_model && _model->isActive()) {
// _jointMappings = _model->getGeometry()->getJointMappings(_animation);
// }
// if (_jointMappings.isEmpty()) {
// return;
// }
// if (!_maskedJoints.isEmpty()) {
// const FBXGeometry& geometry = _model->getGeometry()->getFBXGeometry();
// for (int i = 0; i < _jointMappings.size(); i++) {
// int& mapping = _jointMappings[i];
// if (mapping != -1 && _maskedJoints.contains(geometry.joints.at(mapping).name)) {
// mapping = -1;
// }
// }
// }
// }
const FBXGeometry& animationGeometry = _animation->getGeometry();
if (animationGeometry.animationFrames.isEmpty()) {
stop();
return;
}
if (_animationLoop.getMaxFrameIndexHint() != animationGeometry.animationFrames.size()) {
_animationLoop.setMaxFrameIndexHint(animationGeometry.animationFrames.size());
}
// blend between the closest two frames
applyFrame(getFrameIndex());
}
@ -154,17 +153,21 @@ void AnimationHandle::applyFrame(float frameIndex) {
if (!_animation || !_animation->isLoaded()) {
return;
}
const FBXGeometry& animationGeometry = _animation->getGeometry();
int frameCount = animationGeometry.animationFrames.size();
const FBXAnimationFrame& floorFrame = animationGeometry.animationFrames.at((int)glm::floor(frameIndex) % frameCount);
const FBXAnimationFrame& ceilFrame = animationGeometry.animationFrames.at((int)glm::ceil(frameIndex) % frameCount);
float frameFraction = glm::fract(frameIndex);
QVector<JointState> jointStates = _rig->getJointStates();
for (int i = 0; i < _jointMappings.size(); i++) {
int mapping = _jointMappings.at(i);
if (mapping != -1) {
JointState& state = _model->_jointStates[mapping];
state.setRotationInConstrainedFrame(safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction), _priority);
JointState& state = jointStates[mapping];
state.setRotationInConstrainedFrame(safeMix(floorFrame.rotations.at(i),
ceilFrame.rotations.at(i),
frameFraction),
_priority);
}
}
}
@ -173,7 +176,8 @@ void AnimationHandle::replaceMatchingPriorities(float newPriority) {
for (int i = 0; i < _jointMappings.size(); i++) {
int mapping = _jointMappings.at(i);
if (mapping != -1) {
JointState& state = _model->_jointStates[mapping];
QVector<JointState> jointStates = _rig->getJointStates();
JointState& state = jointStates[mapping];
if (_priority == state._animationPriority) {
state._animationPriority = newPriority;
}
@ -185,9 +189,9 @@ void AnimationHandle::restoreJoints() {
for (int i = 0; i < _jointMappings.size(); i++) {
int mapping = _jointMappings.at(i);
if (mapping != -1) {
JointState& state = _model->_jointStates[mapping];
QVector<JointState> jointStates = _rig->getJointStates();
JointState& state = jointStates[mapping];
state.restoreRotation(1.0f, state._animationPriority);
}
}
}

View file

@ -18,22 +18,43 @@
#include <QUrl>
#include <QVector>
#include <AnimationCache.h>
#include <AnimationLoop.h>
#include "AnimationCache.h"
#include "AnimationLoop.h"
#include "Rig.h"
class AnimationHandle;
class Model;
typedef QSharedPointer<AnimationHandle> AnimationHandlePointer;
typedef QWeakPointer<AnimationHandle> WeakAnimationHandlePointer;
typedef std::shared_ptr<AnimationHandle> AnimationHandlePointer;
typedef std::weak_ptr<AnimationHandle> WeakAnimationHandlePointer;
inline uint qHash(const std::shared_ptr<AnimationHandle>& a, uint seed) {
// return qHash(a.get(), seed);
AnimationHandle* strongRef = a ? a.get() : nullptr;
return qHash(strongRef, seed);
}
inline uint qHash(const std::weak_ptr<AnimationHandle>& a, uint seed) {
AnimationHandlePointer strongPointer = a.lock();
AnimationHandle* strongRef = strongPointer ? strongPointer.get() : nullptr;
return qHash(strongRef, seed);
}
// inline uint qHash(const WeakAnimationHandlePointer& handle, uint seed) {
// return qHash(handle.data(), seed);
// }
/// Represents a handle to a model animation.
class AnimationHandle : public QObject {
class AnimationHandle : public QObject, public std::enable_shared_from_this<AnimationHandle> {
Q_OBJECT
public:
AnimationHandle(RigPointer rig);
AnimationHandlePointer getAnimationHandlePointer() { return shared_from_this(); }
void setRole(const QString& role) { _role = role; }
const QString& getRole() const { return _role; }
@ -45,26 +66,26 @@ public:
void setMaskedJoints(const QStringList& maskedJoints);
const QStringList& getMaskedJoints() const { return _maskedJoints; }
void setFPS(float fps) { _animationLoop.setFPS(fps); }
float getFPS() const { return _animationLoop.getFPS(); }
void setLoop(bool loop) { _animationLoop.setLoop(loop); }
bool getLoop() const { return _animationLoop.getLoop(); }
void setHold(bool hold) { _animationLoop.setHold(hold); }
bool getHold() const { return _animationLoop.getHold(); }
void setStartAutomatically(bool startAutomatically);
bool getStartAutomatically() const { return _animationLoop.getStartAutomatically(); }
void setFirstFrame(float firstFrame) { _animationLoop.setFirstFrame(firstFrame); }
float getFirstFrame() const { return _animationLoop.getFirstFrame(); }
void setLastFrame(float lastFrame) { _animationLoop.setLastFrame(lastFrame); }
float getLastFrame() const { return _animationLoop.getLastFrame(); }
void setRunning(bool running);
bool isRunning() const { return _animationLoop.isRunning(); }
@ -74,30 +95,25 @@ public:
AnimationDetails getAnimationDetails() const;
void setAnimationDetails(const AnimationDetails& details);
void setJointMappings(QVector<int> jointMappings);
void simulate(float deltaTime);
void applyFrame(float frameIndex);
void replaceMatchingPriorities(float newPriority);
void restoreJoints();
void clearJoints() { _jointMappings.clear(); }
signals:
void runningChanged(bool running);
public slots:
void start() { setRunning(true); }
void stop() { setRunning(false); }
private:
friend class Model;
AnimationHandle(Model* model);
void simulate(float deltaTime);
void applyFrame(float frameIndex);
void replaceMatchingPriorities(float newPriority);
void restoreJoints();
void clearJoints() { _jointMappings.clear(); }
Model* _model;
WeakAnimationHandlePointer _self;
RigPointer _rig;
AnimationPointer _animation;
QString _role;
QUrl _url;
@ -105,8 +121,11 @@ private:
QStringList _maskedJoints;
QVector<int> _jointMappings;
AnimationLoop _animationLoop;
static QHash<QWeakPointer<Animation>, QVector<int>> _jointMappingsCache;
static QVector<int> getJointMappings(const AnimationPointer& animation);
};

View file

@ -9,4 +9,85 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "AnimationHandle.h"
#include "Rig.h"
bool Rig::removeRunningAnimation(AnimationHandlePointer animationHandle) {
return _runningAnimations.removeOne(animationHandle);
}
static void insertSorted(QList<AnimationHandlePointer>& handles, const AnimationHandlePointer& handle) {
for (QList<AnimationHandlePointer>::iterator it = handles.begin(); it != handles.end(); it++) {
if (handle->getPriority() > (*it)->getPriority()) {
handles.insert(it, handle);
return;
}
}
handles.append(handle);
}
void Rig::addRunningAnimation(AnimationHandlePointer animationHandle) {
insertSorted(_runningAnimations, animationHandle);
}
bool Rig::isRunningAnimation(AnimationHandlePointer animationHandle) {
return _runningAnimations.contains(animationHandle);
}
void Rig::initJointStates(glm::vec3 scale, glm::vec3 offset, QVector<JointState> states) {
_jointStates = states;
initJointTransforms(scale, offset);
int numStates = _jointStates.size();
float radius = 0.0f;
for (int i = 0; i < numStates; ++i) {
float distance = glm::length(_jointStates[i].getPosition());
if (distance > radius) {
radius = distance;
}
_jointStates[i].buildConstraint();
}
for (int i = 0; i < _jointStates.size(); i++) {
_jointStates[i].slaveVisibleTransform();
}
// XXX update AnimationHandles from here?
}
void Rig::initJointTransforms(glm::vec3 scale, glm::vec3 offset) {
// compute model transforms
int numStates = _jointStates.size();
for (int i = 0; i < numStates; ++i) {
JointState& state = _jointStates[i];
const FBXJoint& joint = state.getFBXJoint();
int parentIndex = joint.parentIndex;
if (parentIndex == -1) {
// const FBXGeometry& geometry = _geometry->getFBXGeometry();
// NOTE: in practice geometry.offset has a non-unity scale (rather than a translation)
glm::mat4 parentTransform = glm::scale(scale) * glm::translate(offset); // * geometry.offset; XXX
state.initTransform(parentTransform);
} else {
const JointState& parentState = _jointStates.at(parentIndex);
state.initTransform(parentState.getTransform());
}
}
}
void Rig::resetJoints() {
if (_jointStates.isEmpty()) {
return;
}
// const FBXGeometry& geometry = _geometry->getFBXGeometry();
for (int i = 0; i < _jointStates.size(); i++) {
const FBXJoint& fbxJoint = _jointStates[i].getFBXJoint();
_jointStates[i].setRotationInConstrainedFrame(fbxJoint.rotation, 0.0f);
}
}
AnimationHandlePointer Rig::createAnimationHandle() {
AnimationHandlePointer handle(new AnimationHandle(getRigPointer()));
_animationHandles.insert(handle);
return handle;
}

View file

@ -16,8 +16,39 @@
#include <QObject>
class Rig : public QObject {
#include "JointState.h"
class AnimationHandle;
typedef std::shared_ptr<AnimationHandle> AnimationHandlePointer;
// typedef QWeakPointer<AnimationHandle> WeakAnimationHandlePointer;
class Rig;
typedef std::shared_ptr<Rig> RigPointer;
class Rig : public QObject, public std::enable_shared_from_this<Rig> {
public:
RigPointer getRigPointer() { return shared_from_this(); }
bool removeRunningAnimation(AnimationHandlePointer animationHandle);
void addRunningAnimation(AnimationHandlePointer animationHandle);
bool isRunningAnimation(AnimationHandlePointer animationHandle);
const QList<AnimationHandlePointer>& getRunningAnimations() const { return _runningAnimations; }
void initJointStates(glm::vec3 scale, glm::vec3 offset, QVector<JointState> states);
void initJointTransforms(glm::vec3 scale, glm::vec3 offset);
void resetJoints();
QVector<JointState> getJointStates() { return _jointStates; }
AnimationHandlePointer createAnimationHandle();
protected:
QVector<JointState> _jointStates;
QSet<AnimationHandlePointer> _animationHandles;
QList<AnimationHandlePointer> _runningAnimations;
};
#endif /* defined(__hifi__Rig__) */

View file

@ -1255,17 +1255,6 @@ QStringList Model::getJointNames() const {
return isActive() ? _geometry->getFBXGeometry().getJointNames() : QStringList();
}
uint qHash(const WeakAnimationHandlePointer& handle, uint seed) {
return qHash(handle.data(), seed);
}
AnimationHandlePointer Model::createAnimationHandle() {
AnimationHandlePointer handle(new AnimationHandle(this));
handle->_self = handle;
_animationHandles.insert(handle);
return handle;
}
// virtual override from PhysicsEntity
void Model::buildShapes() {
// TODO: figure out how to load/build collision shapes for general models
@ -1830,9 +1819,9 @@ void Model::deleteGeometry() {
clearShapes();
for (QSet<WeakAnimationHandlePointer>::iterator it = _animationHandles.begin(); it != _animationHandles.end(); ) {
AnimationHandlePointer handle = it->toStrongRef();
AnimationHandlePointer handle = it->lock();
if (handle) {
handle->_jointMappings.clear();
handle->clearJoints();
it++;
} else {
it = _animationHandles.erase(it);

View file

@ -209,7 +209,6 @@ public:
QStringList getJointNames() const;
AnimationHandlePointer createAnimationHandle();
const QList<AnimationHandlePointer>& getRunningAnimations() const { return _runningAnimations; }