mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Removed rig animations
* Deleted AnimationHandle class * Removed enableAnimGraph and anableRigAnimations from Menu. * Removed *some* references to old IK system. But it is still used when computing collision bounding volumes
This commit is contained in:
parent
533773d1cd
commit
11440f92f4
13 changed files with 55 additions and 788 deletions
|
@ -2503,17 +2503,11 @@ void Application::setAvatarUpdateThreading(bool isThreaded) {
|
|||
}
|
||||
|
||||
auto myAvatar = getMyAvatar();
|
||||
bool isRigEnabled = myAvatar->getEnableRigAnimations();
|
||||
bool isGraphEnabled = myAvatar->getEnableAnimGraph();
|
||||
if (_avatarUpdate) {
|
||||
_avatarUpdate->terminate(); // Must be before we shutdown anim graph.
|
||||
}
|
||||
myAvatar->setEnableRigAnimations(false);
|
||||
myAvatar->setEnableAnimGraph(false);
|
||||
_avatarUpdate = new AvatarUpdate();
|
||||
_avatarUpdate->initialize(isThreaded);
|
||||
myAvatar->setEnableRigAnimations(isRigEnabled);
|
||||
myAvatar->setEnableAnimGraph(isGraphEnabled);
|
||||
}
|
||||
|
||||
void Application::updateLOD() {
|
||||
|
|
|
@ -440,10 +440,6 @@ Menu::Menu() {
|
|||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::FixGaze, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::EnableAvatarUpdateThreading, 0, false,
|
||||
qApp, SLOT(setAvatarUpdateThreading(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::EnableRigAnimations, 0, false,
|
||||
avatar, SLOT(setEnableRigAnimations(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::EnableAnimGraph, 0, true,
|
||||
avatar, SLOT(setEnableAnimGraph(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AnimDebugDrawBindPose, 0, false,
|
||||
avatar, SLOT(setEnableDebugDrawBindPose(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AnimDebugDrawAnimPose, 0, false,
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "Head.h"
|
||||
#include "SkeletonModel.h"
|
||||
#include "world.h"
|
||||
#include "Rig.h"
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar);
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
#include <AccountManager.h>
|
||||
#include <AddressManager.h>
|
||||
#include <AnimationHandle.h>
|
||||
#include <AudioClient.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <display-plugins/DisplayPlugin.h>
|
||||
|
@ -143,16 +142,9 @@ QByteArray MyAvatar::toByteArray(bool cullSmallChanges, bool sendAll) {
|
|||
}
|
||||
|
||||
void MyAvatar::reset(bool andReload) {
|
||||
// Gather animation mode...
|
||||
// This should be simpler when we have only graph animations always on.
|
||||
bool isRig = _rig->getEnableRig();
|
||||
// seting rig animation to true, below, will clear the graph animation menu item, so grab it now.
|
||||
bool isGraph = _rig->getEnableAnimGraph() || Menu::getInstance()->isOptionChecked(MenuOption::EnableAnimGraph);
|
||||
// ... and get to sane configuration where other activity won't bother us.
|
||||
|
||||
if (andReload) {
|
||||
qApp->setRawAvatarUpdateThreading(false);
|
||||
_rig->disableHands = true;
|
||||
setEnableRigAnimations(true);
|
||||
}
|
||||
|
||||
// Reset dynamic state.
|
||||
|
@ -189,19 +181,6 @@ void MyAvatar::reset(bool andReload) {
|
|||
//_bodySensorMatrix = newBodySensorMatrix;
|
||||
//updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes
|
||||
|
||||
_skeletonModel.simulate(0.1f); // non-zero
|
||||
setEnableRigAnimations(false);
|
||||
_skeletonModel.simulate(0.1f);
|
||||
}
|
||||
if (isRig) {
|
||||
setEnableRigAnimations(true);
|
||||
Menu::getInstance()->setIsOptionChecked(MenuOption::EnableRigAnimations, true);
|
||||
} else if (isGraph) {
|
||||
setEnableAnimGraph(true);
|
||||
Menu::getInstance()->setIsOptionChecked(MenuOption::EnableAnimGraph, true);
|
||||
}
|
||||
if (andReload) {
|
||||
_rig->disableHands = false;
|
||||
qApp->setRawAvatarUpdateThreading();
|
||||
}
|
||||
}
|
||||
|
@ -760,57 +739,6 @@ float loadSetting(QSettings& settings, const char* name, float defaultValue) {
|
|||
// Meanwhile, the main thread will also eventually lock as it tries to render us.
|
||||
// If we demand the animation from the update thread while we're locked, we'll deadlock.
|
||||
// Until we untangle this, code puts the updates back on the main thread temporarilly and starts all the loading.
|
||||
void MyAvatar::safelyLoadAnimations() {
|
||||
/*
|
||||
_rig->addAnimationByRole("idle");
|
||||
_rig->addAnimationByRole("walk");
|
||||
_rig->addAnimationByRole("backup");
|
||||
_rig->addAnimationByRole("leftTurn");
|
||||
_rig->addAnimationByRole("rightTurn");
|
||||
_rig->addAnimationByRole("leftStrafe");
|
||||
_rig->addAnimationByRole("rightStrafe");
|
||||
*/
|
||||
}
|
||||
|
||||
void MyAvatar::setEnableRigAnimations(bool isEnabled) {
|
||||
if (_rig->getEnableRig() == isEnabled) {
|
||||
return;
|
||||
}
|
||||
if (isEnabled) {
|
||||
qApp->setRawAvatarUpdateThreading(false);
|
||||
setEnableAnimGraph(false);
|
||||
Menu::getInstance()->setIsOptionChecked(MenuOption::EnableAnimGraph, false);
|
||||
safelyLoadAnimations();
|
||||
qApp->setRawAvatarUpdateThreading();
|
||||
_rig->setEnableRig(true);
|
||||
} else {
|
||||
_rig->setEnableRig(false);
|
||||
_rig->deleteAnimations();
|
||||
}
|
||||
}
|
||||
|
||||
void MyAvatar::setEnableAnimGraph(bool isEnabled) {
|
||||
if (_rig->getEnableAnimGraph() == isEnabled) {
|
||||
return;
|
||||
}
|
||||
if (isEnabled) {
|
||||
qApp->setRawAvatarUpdateThreading(false);
|
||||
setEnableRigAnimations(false);
|
||||
Menu::getInstance()->setIsOptionChecked(MenuOption::EnableRigAnimations, false);
|
||||
safelyLoadAnimations();
|
||||
if (_skeletonModel.readyToAddToScene()) {
|
||||
_rig->setEnableAnimGraph(true);
|
||||
initAnimGraph(); // must be enabled for the init to happen
|
||||
_rig->setEnableAnimGraph(false); // must be disable to safely reset threading
|
||||
}
|
||||
qApp->setRawAvatarUpdateThreading();
|
||||
_rig->setEnableAnimGraph(true);
|
||||
} else {
|
||||
_rig->setEnableAnimGraph(false);
|
||||
destroyAnimGraph();
|
||||
}
|
||||
}
|
||||
|
||||
void MyAvatar::setEnableDebugDrawBindPose(bool isEnabled) {
|
||||
_enableDebugDrawBindPose = isEnabled;
|
||||
|
||||
|
@ -875,7 +803,7 @@ void MyAvatar::loadData() {
|
|||
setCollisionSoundURL(settings.value("collisionSoundURL", DEFAULT_AVATAR_COLLISION_SOUND_URL).toString());
|
||||
|
||||
settings.endGroup();
|
||||
_rig->setEnableRig(Menu::getInstance()->isOptionChecked(MenuOption::EnableRigAnimations));
|
||||
|
||||
setEnableMeshVisible(Menu::getInstance()->isOptionChecked(MenuOption::MeshVisible));
|
||||
setEnableDebugDrawBindPose(Menu::getInstance()->isOptionChecked(MenuOption::AnimDebugDrawBindPose));
|
||||
setEnableDebugDrawAnimPose(Menu::getInstance()->isOptionChecked(MenuOption::AnimDebugDrawAnimPose));
|
||||
|
@ -1163,16 +1091,8 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN
|
|||
|
||||
const QString& urlString = fullAvatarURL.toString();
|
||||
if (urlString.isEmpty() || (fullAvatarURL != getSkeletonModelURL())) {
|
||||
bool isRigEnabled = getEnableRigAnimations();
|
||||
bool isGraphEnabled = getEnableAnimGraph();
|
||||
qApp->setRawAvatarUpdateThreading(false);
|
||||
setEnableRigAnimations(false);
|
||||
setEnableAnimGraph(false);
|
||||
|
||||
setSkeletonModelURL(fullAvatarURL);
|
||||
|
||||
setEnableRigAnimations(isRigEnabled);
|
||||
setEnableAnimGraph(isGraphEnabled);
|
||||
qApp->setRawAvatarUpdateThreading();
|
||||
UserActivityLogger::getInstance().changedModel("skeleton", urlString);
|
||||
}
|
||||
|
|
|
@ -114,10 +114,6 @@ public:
|
|||
|
||||
float getRealWorldFieldOfView() { return _realWorldFieldOfView.get(); }
|
||||
|
||||
const QList<AnimationHandlePointer>& getAnimationHandles() const { return _rig->getAnimationHandles(); }
|
||||
AnimationHandlePointer addAnimationHandle() { return _rig->createAnimationHandle(); }
|
||||
void removeAnimationHandle(const AnimationHandlePointer& handle) { _rig->removeAnimationHandle(handle); }
|
||||
|
||||
// Interrupt the current animation with a custom animation.
|
||||
Q_INVOKABLE void overrideAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame);
|
||||
|
||||
|
@ -266,11 +262,8 @@ public slots:
|
|||
|
||||
virtual void rebuildSkeletonBody() override;
|
||||
|
||||
bool getEnableRigAnimations() const { return _rig->getEnableRig(); }
|
||||
void setEnableRigAnimations(bool isEnabled);
|
||||
bool getEnableAnimGraph() const { return _rig->getEnableAnimGraph(); }
|
||||
const QString& getAnimGraphUrl() const { return _animGraphUrl; }
|
||||
void setEnableAnimGraph(bool isEnabled);
|
||||
|
||||
void setEnableDebugDrawBindPose(bool isEnabled);
|
||||
void setEnableDebugDrawAnimPose(bool isEnabled);
|
||||
void setEnableMeshVisible(bool isEnabled);
|
||||
|
@ -376,7 +369,6 @@ private:
|
|||
void maybeUpdateBillboard();
|
||||
void initHeadBones();
|
||||
void initAnimGraph();
|
||||
void safelyLoadAnimations();
|
||||
|
||||
// Avatar Preferences
|
||||
QUrl _fullAvatarURLFromPreferences;
|
||||
|
|
|
@ -251,40 +251,6 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
|
|||
// Don't take inputs if playing back a recording.
|
||||
return;
|
||||
}
|
||||
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
|
||||
// Don't Relax toward hand positions when in animGraph mode.
|
||||
if (!_rig->getEnableAnimGraph()) {
|
||||
|
||||
Hand* hand = _owningAvatar->getHand();
|
||||
auto leftPalm = hand->getCopyOfPalmData(HandData::LeftHand);
|
||||
auto rightPalm = hand->getCopyOfPalmData(HandData::RightHand);
|
||||
|
||||
const float HAND_RESTORATION_RATE = 0.25f;
|
||||
if (!leftPalm.isActive() && !rightPalm.isActive()) {
|
||||
// palms are not yet set, use mouse
|
||||
if (_owningAvatar->getHandState() == HAND_STATE_NULL) {
|
||||
restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
|
||||
} else {
|
||||
// transform into model-frame
|
||||
glm::vec3 handPosition = glm::inverse(_rotation) * (_owningAvatar->getHandPosition() - _translation);
|
||||
applyHandPosition(geometry.rightHandJointIndex, handPosition);
|
||||
}
|
||||
restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
|
||||
} else {
|
||||
if (leftPalm.isActive()) {
|
||||
applyPalmData(geometry.leftHandJointIndex, leftPalm);
|
||||
} else {
|
||||
restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
|
||||
}
|
||||
if (rightPalm.isActive()) {
|
||||
applyPalmData(geometry.rightHandJointIndex, rightPalm);
|
||||
} else {
|
||||
restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkeletonModel::renderIKConstraints(gpu::Batch& batch) {
|
||||
|
@ -344,8 +310,6 @@ void SkeletonModel::applyPalmData(int jointIndex, const PalmData& palm) {
|
|||
glm::quat inverseRotation = glm::inverse(_rotation);
|
||||
glm::vec3 palmPosition = inverseRotation * (palm.getPosition() - _translation);
|
||||
glm::quat palmRotation = inverseRotation * palm.getRotation();
|
||||
|
||||
inverseKinematics(jointIndex, palmPosition, palmRotation, PALM_PRIORITY);
|
||||
}
|
||||
|
||||
void SkeletonModel::renderJointConstraints(gpu::Batch& batch, int jointIndex) {
|
||||
|
|
|
@ -247,12 +247,7 @@ void PreferencesDialog::savePreferences() {
|
|||
myAvatar->setLeanScale(ui.leanScaleSpin->value());
|
||||
myAvatar->setClampedTargetScale(ui.avatarScaleSpin->value());
|
||||
if (myAvatar->getAnimGraphUrl() != ui.avatarAnimationEdit->text()) { // If changed, destroy the old and start with the new
|
||||
bool isEnabled = myAvatar->getEnableAnimGraph();
|
||||
myAvatar->setEnableAnimGraph(false);
|
||||
myAvatar->setAnimGraphUrl(ui.avatarAnimationEdit->text());
|
||||
if (isEnabled) {
|
||||
myAvatar->setEnableAnimGraph(true);
|
||||
}
|
||||
}
|
||||
|
||||
myAvatar->setRealWorldFieldOfView(ui.realWorldFieldOfViewSpin->value());
|
||||
|
|
|
@ -1,218 +0,0 @@
|
|||
//
|
||||
// AnimationHandle.cpp
|
||||
// libraries/animation/src/
|
||||
//
|
||||
// Created by Andrzej Kapolka on 10/18/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "AnimationHandle.h"
|
||||
#include "AnimationLogging.h"
|
||||
|
||||
void AnimationHandle::setURL(const QUrl& url) {
|
||||
if (_url != url) {
|
||||
_animation = DependencyManager::get<AnimationCache>()->getAnimation(_url = url);
|
||||
_animation->ensureLoading();
|
||||
QObject::connect(_animation.data(), &Resource::onRefresh, this, &AnimationHandle::clearJoints);
|
||||
_jointMappings.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationHandle::setPriority(float priority) {
|
||||
if (_priority == priority) {
|
||||
return;
|
||||
}
|
||||
if (isRunning()) {
|
||||
_rig->removeRunningAnimation(getAnimationHandlePointer());
|
||||
if (priority < _priority) {
|
||||
replaceMatchingPriorities(priority);
|
||||
}
|
||||
_priority = priority;
|
||||
_rig->addRunningAnimation(getAnimationHandlePointer());
|
||||
} else {
|
||||
_priority = priority;
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationHandle::setStartAutomatically(bool startAutomatically) {
|
||||
if (startAutomatically && !isRunning()) {
|
||||
// Start before setting _animationLoop value so that code in setRunning() is executed
|
||||
start();
|
||||
}
|
||||
_animationLoop.setStartAutomatically(startAutomatically);
|
||||
}
|
||||
|
||||
void AnimationHandle::setMaskedJoints(const QStringList& maskedJoints) {
|
||||
_maskedJoints = maskedJoints;
|
||||
_jointMappings.clear();
|
||||
}
|
||||
|
||||
void AnimationHandle::setRunning(bool running, bool doRestoreJoints) {
|
||||
if (running && isRunning() && (getFadePerSecond() >= 0.0f)) {
|
||||
// if we're already running, this is the same as a restart -- unless we're fading out.
|
||||
setCurrentFrame(getFirstFrame());
|
||||
return;
|
||||
}
|
||||
_animationLoop.setRunning(running);
|
||||
if (isRunning()) {
|
||||
if (!_rig->isRunningAnimation(getAnimationHandlePointer())) {
|
||||
_rig->addRunningAnimation(getAnimationHandlePointer());
|
||||
}
|
||||
} else {
|
||||
_rig->removeRunningAnimation(getAnimationHandlePointer());
|
||||
if (doRestoreJoints) {
|
||||
restoreJoints();
|
||||
}
|
||||
replaceMatchingPriorities(0.0f);
|
||||
}
|
||||
emit runningChanged(isRunning());
|
||||
}
|
||||
|
||||
AnimationHandle::AnimationHandle(RigPointer rig) :
|
||||
QObject(rig.get()),
|
||||
_rig(rig),
|
||||
_priority(1.0f),
|
||||
_fade(0.0f),
|
||||
_fadePerSecond(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
AnimationDetails AnimationHandle::getAnimationDetails() const {
|
||||
AnimationDetails details(_role, _url, getFPS(), _priority, getLoop(), getHold(),
|
||||
getStartAutomatically(), getFirstFrame(), getLastFrame(), isRunning(), getCurrentFrame());
|
||||
return details;
|
||||
}
|
||||
|
||||
void AnimationHandle::setAnimationDetails(const AnimationDetails& details) {
|
||||
setRole(details.role);
|
||||
setURL(details.url);
|
||||
setFPS(details.fps);
|
||||
setPriority(details.priority);
|
||||
setLoop(details.loop);
|
||||
setHold(details.hold);
|
||||
setStartAutomatically(details.startAutomatically);
|
||||
setFirstFrame(details.firstFrame);
|
||||
setLastFrame(details.lastFrame);
|
||||
setRunning(details.running);
|
||||
setCurrentFrame(details.currentFrame);
|
||||
|
||||
// NOTE: AnimationDetails doesn't support maskedJoints
|
||||
//setMaskedJoints(const QStringList& maskedJoints);
|
||||
}
|
||||
|
||||
|
||||
void AnimationHandle::setJointMappings(QVector<int> jointMappings) {
|
||||
_jointMappings = jointMappings;
|
||||
}
|
||||
|
||||
QVector<int> AnimationHandle::getJointMappings() {
|
||||
if (_jointMappings.isEmpty()) {
|
||||
QVector<FBXJoint> animationJoints = _animation->getGeometry().joints;
|
||||
for (int i = 0; i < animationJoints.count(); i++) {
|
||||
_jointMappings.append(_rig->indexOfJoint(animationJoints.at(i).name));
|
||||
}
|
||||
}
|
||||
return _jointMappings;
|
||||
}
|
||||
|
||||
void AnimationHandle::simulate(float deltaTime) {
|
||||
if (!_animation || !_animation->isLoaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_animationLoop.simulate(deltaTime);
|
||||
|
||||
if (getJointMappings().isEmpty()) {
|
||||
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(getCurrentFrame());
|
||||
}
|
||||
|
||||
void AnimationHandle::applyFrame(float currentFrame) {
|
||||
if (!_animation || !_animation->isLoaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const FBXGeometry& animationGeometry = _animation->getGeometry();
|
||||
int frameCount = animationGeometry.animationFrames.size();
|
||||
const FBXAnimationFrame& floorFrame = animationGeometry.animationFrames.at((int)glm::floor(currentFrame) % frameCount);
|
||||
const FBXAnimationFrame& ceilFrame = animationGeometry.animationFrames.at((int)glm::ceil(currentFrame) % frameCount);
|
||||
float frameFraction = glm::fract(currentFrame);
|
||||
|
||||
for (int i = 0; i < _jointMappings.size(); i++) {
|
||||
int mapping = _jointMappings.at(i);
|
||||
if (mapping != -1) { // allow missing bones
|
||||
_rig->setJointRotationInConstrainedFrame(mapping,
|
||||
safeMix(floorFrame.rotations.at(i),
|
||||
ceilFrame.rotations.at(i),
|
||||
frameFraction),
|
||||
_priority,
|
||||
_mix);
|
||||
|
||||
// This isn't working.
|
||||
// glm::vec3 floorTranslationPart = floorFrame.translations.at(i) * (1.0f - frameFraction);
|
||||
// glm::vec3 ceilTranslationPart = ceilFrame.translations.at(i) * frameFraction;
|
||||
// glm::vec3 floorCeilFraction = floorTranslationPart + ceilTranslationPart;
|
||||
// glm::vec3 defaultTrans = _rig->getJointDefaultTranslationInConstrainedFrame(i);
|
||||
// glm::vec3 mixedTranslation = floorCeilFraction * (1.0f - _mix) + defaultTrans * _mix;
|
||||
// _rig->setJointTranslation(mapping, true, mixedTranslation, _priority);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationHandle::replaceMatchingPriorities(float newPriority) {
|
||||
for (int i = 0; i < _jointMappings.size(); i++) {
|
||||
int mapping = _jointMappings.at(i);
|
||||
if (mapping != -1) {
|
||||
if (_priority == _rig->getJointAnimatinoPriority(mapping)) {
|
||||
_rig->setJointAnimatinoPriority(mapping, newPriority);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationHandle::restoreJoints() {
|
||||
for (int i = 0; i < _jointMappings.size(); i++) {
|
||||
int mapping = _jointMappings.at(i);
|
||||
if (mapping != -1) {
|
||||
_rig->restoreJointRotation(mapping, 1.0f, _rig->getJointAnimatinoPriority(mapping));
|
||||
_rig->restoreJointTranslation(mapping, 1.0f, _rig->getJointAnimatinoPriority(mapping));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,138 +0,0 @@
|
|||
//
|
||||
// AnimationHandle.h
|
||||
// libraries/animation/src/
|
||||
//
|
||||
// Created by Andrzej Kapolka on 10/18/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_AnimationHandle_h
|
||||
#define hifi_AnimationHandle_h
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
#include <QVector>
|
||||
|
||||
#include "AnimationCache.h"
|
||||
#include "AnimationLoop.h"
|
||||
#include "Rig.h"
|
||||
|
||||
class AnimationHandle;
|
||||
class Model;
|
||||
|
||||
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. I.e., an Animation in use by a given Rig.
|
||||
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; }
|
||||
|
||||
void setURL(const QUrl& url);
|
||||
const QUrl& getURL() const { return _url; }
|
||||
|
||||
void setPriority(float priority);
|
||||
float getPriority() const { return _priority; }
|
||||
void setMix(float mix) { _mix = mix; }
|
||||
void setFade(float fade) { _fade = fade; }
|
||||
float getFade() const { return _fade; }
|
||||
void setFadePerSecond(float fadePerSecond) { _fadePerSecond = fadePerSecond; }
|
||||
float getFadePerSecond() const { return _fadePerSecond; }
|
||||
|
||||
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 restoreJoints = true);
|
||||
bool isRunning() const { return _animationLoop.getRunning(); }
|
||||
|
||||
void setCurrentFrame(float currentFrame) { _animationLoop.setCurrentFrame(currentFrame); }
|
||||
float getCurrentFrame() const { return _animationLoop.getCurrentFrame(); }
|
||||
|
||||
AnimationDetails getAnimationDetails() const;
|
||||
void setAnimationDetails(const AnimationDetails& details);
|
||||
|
||||
void setJointMappings(QVector<int> jointMappings);
|
||||
QVector<int> getJointMappings(); // computing if necessary
|
||||
void simulate(float deltaTime);
|
||||
void applyFrame(float currentFrame);
|
||||
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); _fadePerSecond = _fade = 0.0f; }
|
||||
|
||||
private:
|
||||
|
||||
RigPointer _rig;
|
||||
AnimationPointer _animation;
|
||||
QString _role;
|
||||
QUrl _url;
|
||||
float _priority;
|
||||
float _mix; // How much of this animation to blend against what is already there. 1.0 sets to just this animation.
|
||||
float _fade; // How far are we into full strength. 0.0 uses none of this animation, 1.0 (the max) is as much as possible.
|
||||
float _fadePerSecond; // How fast should _fade change? +1.0 means _fade is increasing to 1.0 in 1 second. Negative is fading out.
|
||||
|
||||
QStringList _maskedJoints;
|
||||
QVector<int> _jointMappings;
|
||||
|
||||
AnimationLoop _animationLoop;
|
||||
};
|
||||
|
||||
|
||||
#endif // hifi_AnimationHandle_h
|
|
@ -18,117 +18,55 @@
|
|||
#include <NumericalConstants.h>
|
||||
#include <DebugDraw.h>
|
||||
|
||||
#include "AnimationHandle.h"
|
||||
#include "AnimationLogging.h"
|
||||
#include "AnimSkeleton.h"
|
||||
#include "AnimClip.h"
|
||||
#include "IKTarget.h"
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
AnimationHandlePointer Rig::createAnimationHandle() {
|
||||
AnimationHandlePointer handle(new AnimationHandle(getRigPointer()));
|
||||
_animationHandles.append(handle);
|
||||
return handle;
|
||||
}
|
||||
void Rig::removeAnimationHandle(const AnimationHandlePointer& handle) {
|
||||
handle->stop();
|
||||
// FIXME? Do we need to also animationHandle->clearJoints()? deleteAnimations(), below, was first written to do so, but did not first stop it.
|
||||
_animationHandles.removeOne(handle);
|
||||
}
|
||||
|
||||
void Rig::overrideAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame) {
|
||||
if (_enableAnimGraph) {
|
||||
|
||||
// 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));
|
||||
} else if (_userAnimState == UserAnimState::A) {
|
||||
_userAnimState = UserAnimState::B;
|
||||
clip = std::dynamic_pointer_cast<AnimClip>(_animNode->getChild((int)_userAnimState));
|
||||
}
|
||||
|
||||
// set parameters
|
||||
clip->setLoopFlag(loop);
|
||||
clip->setStartFrame(firstFrame);
|
||||
clip->setEndFrame(lastFrame);
|
||||
const float REFERENCE_FRAMES_PER_SECOND = 30.0f;
|
||||
float timeScale = fps / REFERENCE_FRAMES_PER_SECOND;
|
||||
clip->setTimeScale(timeScale);
|
||||
clip->loadURL(url);
|
||||
|
||||
_currentUserAnimURL = url;
|
||||
|
||||
// notify the userAnimStateMachine the desired state.
|
||||
_animVars.set("userAnimNone", false);
|
||||
_animVars.set("userAnimA", _userAnimState == UserAnimState::A);
|
||||
_animVars.set("userAnimB", _userAnimState == UserAnimState::B);
|
||||
|
||||
} else {
|
||||
|
||||
float priority = 1.0f;
|
||||
bool hold = true;
|
||||
QStringList maskedJoints;
|
||||
|
||||
_currentUserAnimURL = url;
|
||||
|
||||
// This is different than startAnimationByRole, in which we use the existing values if the animation already exists.
|
||||
// Here we reuse the animation handle if possible, but in any case, we set the values to those given (or defaulted).
|
||||
AnimationHandlePointer handle = nullptr;
|
||||
foreach (const AnimationHandlePointer& candidate, _animationHandles) {
|
||||
if (candidate->getURL() == url) {
|
||||
handle = candidate;
|
||||
}
|
||||
}
|
||||
if (!handle) {
|
||||
handle = createAnimationHandle();
|
||||
handle->setURL(url);
|
||||
}
|
||||
handle->setFade(1.0f); // If you want to fade, use the startAnimationByRole system.
|
||||
handle->setFPS(fps);
|
||||
handle->setPriority(priority);
|
||||
handle->setLoop(loop);
|
||||
handle->setHold(hold);
|
||||
handle->setFirstFrame(firstFrame);
|
||||
handle->setLastFrame(lastFrame);
|
||||
handle->setMaskedJoints(maskedJoints);
|
||||
handle->start();
|
||||
// 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));
|
||||
} else if (_userAnimState == UserAnimState::A) {
|
||||
_userAnimState = UserAnimState::B;
|
||||
clip = std::dynamic_pointer_cast<AnimClip>(_animNode->getChild((int)_userAnimState));
|
||||
}
|
||||
|
||||
// set parameters
|
||||
clip->setLoopFlag(loop);
|
||||
clip->setStartFrame(firstFrame);
|
||||
clip->setEndFrame(lastFrame);
|
||||
const float REFERENCE_FRAMES_PER_SECOND = 30.0f;
|
||||
float timeScale = fps / REFERENCE_FRAMES_PER_SECOND;
|
||||
clip->setTimeScale(timeScale);
|
||||
clip->loadURL(url);
|
||||
|
||||
_currentUserAnimURL = url;
|
||||
|
||||
// notify the userAnimStateMachine the desired state.
|
||||
_animVars.set("userAnimNone", false);
|
||||
_animVars.set("userAnimA", _userAnimState == UserAnimState::A);
|
||||
_animVars.set("userAnimB", _userAnimState == UserAnimState::B);
|
||||
}
|
||||
|
||||
const float FRAMES_PER_SECOND = 30.0f;
|
||||
const float FADE_FRAMES = 30.0f;
|
||||
|
||||
void Rig::restoreAnimation() {
|
||||
if (_enableAnimGraph) {
|
||||
if (_currentUserAnimURL != "") {
|
||||
_currentUserAnimURL = "";
|
||||
// notify the userAnimStateMachine the desired state.
|
||||
_animVars.set("userAnimNone", true);
|
||||
_animVars.set("userAnimA", false);
|
||||
_animVars.set("userAnimB", false);
|
||||
}
|
||||
} else {
|
||||
foreach (const AnimationHandlePointer& handle, getRunningAnimations()) {
|
||||
if (handle->getURL() == _currentUserAnimURL) {
|
||||
handle->setFade(0.0f); // right away. Will be remove during updateAnimations, without locking
|
||||
handle->setFadePerSecond(-(FRAMES_PER_SECOND / FADE_FRAMES)); // so that the updateAnimation code notices
|
||||
}
|
||||
}
|
||||
if (_currentUserAnimURL != "") {
|
||||
_currentUserAnimURL = "";
|
||||
// notify the userAnimStateMachine the desired state.
|
||||
_animVars.set("userAnimNone", true);
|
||||
_animVars.set("userAnimA", false);
|
||||
_animVars.set("userAnimB", false);
|
||||
}
|
||||
}
|
||||
|
||||
QStringList Rig::getAnimationRoles() const {
|
||||
if (_enableAnimGraph && _animNode) {
|
||||
if (_animNode) {
|
||||
QStringList list;
|
||||
_animNode->traverse([&](AnimNode::Pointer node) {
|
||||
// only report clip nodes as valid roles.
|
||||
|
@ -148,7 +86,7 @@ QStringList Rig::getAnimationRoles() const {
|
|||
}
|
||||
|
||||
void Rig::overrideRoleAnimation(const QString& role, const QString& url, float fps, bool loop, float firstFrame, float lastFrame) {
|
||||
if (_enableAnimGraph && _animNode) {
|
||||
if (_animNode) {
|
||||
AnimNode::Pointer node = _animNode->findByName(role);
|
||||
if (node) {
|
||||
_origRoleAnimations[role] = node;
|
||||
|
@ -160,11 +98,13 @@ void Rig::overrideRoleAnimation(const QString& role, const QString& url, float f
|
|||
} else {
|
||||
qCWarning(animation) << "Rig::overrideRoleAnimation could not find role " << role;
|
||||
}
|
||||
} else {
|
||||
qCWarning(animation) << "Rig::overrideRoleAnimation avatar not ready yet";
|
||||
}
|
||||
}
|
||||
|
||||
void Rig::restoreRoleAnimation(const QString& role) {
|
||||
if (_enableAnimGraph && _animNode) {
|
||||
if (_animNode) {
|
||||
AnimNode::Pointer node = _animNode->findByName(role);
|
||||
if (node) {
|
||||
auto iter = _origRoleAnimations.find(role);
|
||||
|
@ -175,43 +115,17 @@ void Rig::restoreRoleAnimation(const QString& role) {
|
|||
qCWarning(animation) << "Rig::restoreRoleAnimation could not find role " << role;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qCWarning(animation) << "Rig::overrideRoleAnimation avatar not ready yet";
|
||||
}
|
||||
}
|
||||
|
||||
void Rig::prefetchAnimation(const QString& url) {
|
||||
if (_enableAnimGraph) {
|
||||
// This will begin loading the NetworkGeometry for the given URL.
|
||||
// which should speed us up if we request it later via overrideAnimation.
|
||||
auto clipNode = std::make_shared<AnimClip>("prefetch", url, 0, 0, 1.0, false);
|
||||
_prefetchedAnimations.push_back(clipNode);
|
||||
}
|
||||
}
|
||||
|
||||
bool Rig::removeRunningAnimation(AnimationHandlePointer animationHandle) {
|
||||
return _runningAnimations.removeOne(animationHandle);
|
||||
}
|
||||
|
||||
void Rig::addRunningAnimation(AnimationHandlePointer animationHandle) {
|
||||
insertSorted(_runningAnimations, animationHandle);
|
||||
}
|
||||
|
||||
bool Rig::isRunningAnimation(AnimationHandlePointer animationHandle) {
|
||||
return _runningAnimations.contains(animationHandle);
|
||||
}
|
||||
bool Rig::isRunningRole(const QString& role) { //obviously, there are more efficient ways to do this
|
||||
for (auto animation : _runningAnimations) {
|
||||
if ((animation->getRole() == role) && (animation->getFadePerSecond() >= 0.0f)) { // Don't count those being faded out
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Rig::deleteAnimations() {
|
||||
for (auto animation : _animationHandles) {
|
||||
removeAnimationHandle(animation);
|
||||
}
|
||||
_animationHandles.clear();
|
||||
// This will begin loading the NetworkGeometry for the given URL.
|
||||
// which should speed us up if we request it later via overrideAnimation.
|
||||
auto clipNode = std::make_shared<AnimClip>("prefetch", url, 0, 0, 1.0, false);
|
||||
_prefetchedAnimations.push_back(clipNode);
|
||||
}
|
||||
|
||||
void Rig::destroyAnimGraph() {
|
||||
|
@ -483,8 +397,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
|
|||
_lastVelocity = workingVelocity;
|
||||
}
|
||||
|
||||
if (_enableAnimGraph) {
|
||||
|
||||
{
|
||||
glm::vec3 localVel = glm::inverse(worldRotation) * workingVelocity;
|
||||
|
||||
float forwardSpeed = glm::dot(localVel, IDENTITY_FRONT);
|
||||
|
@ -636,47 +549,6 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
|
|||
t += deltaTime;
|
||||
}
|
||||
|
||||
if (_enableRig) {
|
||||
bool isMoving = false;
|
||||
|
||||
glm::vec3 right = worldRotation * IDENTITY_RIGHT;
|
||||
const float PERCEPTIBLE_DELTA = 0.001f;
|
||||
const float PERCEPTIBLE_SPEED = 0.1f;
|
||||
|
||||
// Note: Separately, we've arranged for starting/stopping animations by role (as we've done here) to pick up where they've left off when fading,
|
||||
// so that you wouldn't notice the start/stop if it happens fast enough (e.g., one frame). But the print below would still be noisy.
|
||||
|
||||
float forwardSpeed = glm::dot(workingVelocity, front);
|
||||
float rightLateralSpeed = glm::dot(workingVelocity, right);
|
||||
float rightTurningDelta = glm::orientedAngle(front, _lastFront, IDENTITY_UP);
|
||||
float rightTurningSpeed = rightTurningDelta / deltaTime;
|
||||
bool isTurning = (std::abs(rightTurningDelta) > PERCEPTIBLE_DELTA) && (std::abs(rightTurningSpeed) > PERCEPTIBLE_SPEED);
|
||||
bool isStrafing = std::abs(rightLateralSpeed) > PERCEPTIBLE_SPEED;
|
||||
auto updateRole = [&](const QString& role, bool isOn) {
|
||||
isMoving = isMoving || isOn;
|
||||
if (isOn) {
|
||||
if (!isRunningRole(role)) {
|
||||
qCDebug(animation) << "Rig STARTING" << role;
|
||||
//startAnimationByRole(role);
|
||||
|
||||
}
|
||||
} else {
|
||||
if (isRunningRole(role)) {
|
||||
qCDebug(animation) << "Rig stopping" << role;
|
||||
//stopAnimationByRole(role);
|
||||
}
|
||||
}
|
||||
};
|
||||
updateRole("walk", forwardSpeed > PERCEPTIBLE_SPEED);
|
||||
updateRole("backup", forwardSpeed < -PERCEPTIBLE_SPEED);
|
||||
updateRole("rightTurn", isTurning && (rightTurningSpeed > 0.0f));
|
||||
updateRole("leftTurn", isTurning && (rightTurningSpeed < 0.0f));
|
||||
isStrafing = isStrafing && !isMoving;
|
||||
updateRole("rightStrafe", isStrafing && (rightLateralSpeed > 0.0f));
|
||||
updateRole("leftStrafe", isStrafing && (rightLateralSpeed < 0.0f));
|
||||
updateRole("idle", !isMoving); // Must be last, as it makes isMoving bogus.
|
||||
}
|
||||
|
||||
_lastFront = front;
|
||||
_lastPosition = worldPosition;
|
||||
}
|
||||
|
@ -748,12 +620,10 @@ void Rig::updateAnimationStateHandlers() { // called on avatar update thread (wh
|
|||
|
||||
void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) {
|
||||
|
||||
if (_enableAnimGraph) {
|
||||
if (!_animNode) {
|
||||
return;
|
||||
}
|
||||
if (_animNode) {
|
||||
|
||||
updateAnimationStateHandlers();
|
||||
|
||||
// evaluate the animation
|
||||
AnimNode::Triggers triggersOut;
|
||||
AnimPoseVec poses = _animNode->evaluate(_animVars, deltaTime, triggersOut);
|
||||
|
@ -770,51 +640,6 @@ void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) {
|
|||
setJointRotationInConstrainedFrame((int)i, glm::inverse(_animSkeleton->getRelativeBindPose(i).rot) * poses[i].rot, PRIORITY, 1.0f);
|
||||
setJointTranslation((int)i, true, poses[i].trans, PRIORITY);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// First normalize the fades so that they sum to 1.0.
|
||||
// update the fade data in each animation (not normalized as they are an independent propert of animation)
|
||||
foreach (const AnimationHandlePointer& handle, _runningAnimations) {
|
||||
float fadePerSecond = handle->getFadePerSecond();
|
||||
float fade = handle->getFade();
|
||||
if (fadePerSecond != 0.0f) {
|
||||
fade += fadePerSecond * deltaTime;
|
||||
if ((0.0f >= fade) || (fade >= 1.0f)) {
|
||||
fade = glm::clamp(fade, 0.0f, 1.0f);
|
||||
handle->setFadePerSecond(0.0f);
|
||||
}
|
||||
handle->setFade(fade);
|
||||
if (fade <= 0.0f) { // stop any finished animations now
|
||||
handle->setRunning(false, false); // but do not restore joints as it causes a flicker
|
||||
}
|
||||
}
|
||||
}
|
||||
// sum the remaining fade data
|
||||
float fadeTotal = 0.0f;
|
||||
foreach (const AnimationHandlePointer& handle, _runningAnimations) {
|
||||
fadeTotal += handle->getFade();
|
||||
}
|
||||
float fadeSumSoFar = 0.0f;
|
||||
foreach (const AnimationHandlePointer& handle, _runningAnimations) {
|
||||
handle->setPriority(1.0f);
|
||||
// if no fadeTotal, everyone's (typically just one running) is starting at zero. In that case, blend equally.
|
||||
float normalizedFade = (fadeTotal != 0.0f) ? (handle->getFade() / fadeTotal) : (1.0f / _runningAnimations.count());
|
||||
assert(normalizedFade != 0.0f);
|
||||
// simulate() will blend each animation result into the result so far, based on the pairwise mix at at each step.
|
||||
// i.e., slerp the 'mix' distance from the result so far towards this iteration's animation result.
|
||||
// The formula here for mix is based on the idea that, at each step:
|
||||
// fadeSum is to normalizedFade, as (1 - mix) is to mix
|
||||
// i.e., fadeSumSoFar/normalizedFade = (1 - mix)/mix
|
||||
// Then we solve for mix.
|
||||
// Sanity check: For the first animation, fadeSum = 0, and the mix will always be 1.
|
||||
// Sanity check: For equal blending, the formula is equivalent to mix = 1 / nAnimationsSoFar++
|
||||
float mix = 1.0f / ((fadeSumSoFar / normalizedFade) + 1.0f);
|
||||
assert((0.0f <= mix) && (mix <= 1.0f));
|
||||
fadeSumSoFar += normalizedFade;
|
||||
handle->setMix(mix);
|
||||
handle->simulate(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < _jointStates.size(); i++) {
|
||||
|
@ -916,11 +741,6 @@ void Rig::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm::q
|
|||
return;
|
||||
}
|
||||
|
||||
if (disableHands || (_enableAnimGraph && _animSkeleton)) {
|
||||
// the hand data goes through a different path: Rig::updateFromHandParameters() --> early-exit
|
||||
return;
|
||||
}
|
||||
|
||||
if (freeLineage.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
@ -1125,10 +945,8 @@ void Rig::updateFromHeadParameters(const HeadParameters& params, float dt) {
|
|||
}
|
||||
updateNeckJoint(params.neckJointIndex, params);
|
||||
|
||||
if (_enableAnimGraph) {
|
||||
_animVars.set("isTalking", params.isTalking);
|
||||
_animVars.set("notIsTalking", !params.isTalking);
|
||||
}
|
||||
_animVars.set("isTalking", params.isTalking);
|
||||
_animVars.set("notIsTalking", !params.isTalking);
|
||||
}
|
||||
|
||||
void Rig::updateFromEyeParameters(const EyeParameters& params) {
|
||||
|
@ -1144,21 +962,11 @@ static const glm::vec3 Z_AXIS(0.0f, 0.0f, 1.0f);
|
|||
|
||||
void Rig::updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist) {
|
||||
if (index >= 0 && _jointStates[index].getParentIndex() >= 0) {
|
||||
if (_enableAnimGraph && _animSkeleton) {
|
||||
if (_animSkeleton) {
|
||||
glm::quat absRot = (glm::angleAxis(-RADIANS_PER_DEGREE * leanSideways, Z_AXIS) *
|
||||
glm::angleAxis(-RADIANS_PER_DEGREE * leanForward, X_AXIS) *
|
||||
glm::angleAxis(RADIANS_PER_DEGREE * torsoTwist, Y_AXIS));
|
||||
_animVars.set("lean", absRot);
|
||||
} else if (!_enableAnimGraph) {
|
||||
auto& parentState = _jointStates[_jointStates[index].getParentIndex()];
|
||||
|
||||
// get the rotation axes in joint space and use them to adjust the rotation
|
||||
glm::quat inverse = glm::inverse(parentState.getRotation() * getJointDefaultRotationInParentFrame(index));
|
||||
setJointRotationInConstrainedFrame(index,
|
||||
glm::angleAxis(- RADIANS_PER_DEGREE * leanSideways, inverse * Z_AXIS) *
|
||||
glm::angleAxis(- RADIANS_PER_DEGREE * leanForward, inverse * X_AXIS) *
|
||||
glm::angleAxis(RADIANS_PER_DEGREE * torsoTwist, inverse * Y_AXIS) *
|
||||
getJointState(index).getDefaultRotation(), DEFAULT_PRIORITY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1224,7 +1032,7 @@ static void computeHeadNeckAnimVars(AnimSkeleton::ConstPointer skeleton, const A
|
|||
|
||||
void Rig::updateNeckJoint(int index, const HeadParameters& params) {
|
||||
if (index >= 0 && _jointStates[index].getParentIndex() >= 0) {
|
||||
if (_enableAnimGraph && _animSkeleton) {
|
||||
if (_animSkeleton) {
|
||||
|
||||
if (params.isInHMD) {
|
||||
glm::vec3 headPos, neckPos;
|
||||
|
@ -1272,23 +1080,6 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) {
|
|||
_animVars.unset("neckRotation");
|
||||
_animVars.set("neckType", (int)IKTarget::Type::RotationOnly);
|
||||
}
|
||||
} else if (!_enableAnimGraph) {
|
||||
|
||||
auto& state = _jointStates[index];
|
||||
auto& parentState = _jointStates[state.getParentIndex()];
|
||||
|
||||
// get the rotation axes in joint space and use them to adjust the rotation
|
||||
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() *
|
||||
glm::translate(getJointDefaultTranslationInConstrainedFrame(index)) *
|
||||
state.getPreTransform() * glm::mat4_cast(state.getPreRotation())));
|
||||
glm::vec3 pitchYawRoll = safeEulerAngles(params.localHeadOrientation);
|
||||
glm::vec3 lean = glm::radians(glm::vec3(params.leanForward, params.torsoTwist, params.leanSideways));
|
||||
pitchYawRoll -= lean;
|
||||
setJointRotationInConstrainedFrame(index,
|
||||
glm::angleAxis(-pitchYawRoll.z, glm::normalize(inverse * Z_AXIS)) *
|
||||
glm::angleAxis(pitchYawRoll.y, glm::normalize(inverse * Y_AXIS)) *
|
||||
glm::angleAxis(-pitchYawRoll.x, glm::normalize(inverse * X_AXIS)) *
|
||||
state.getDefaultRotation(), DEFAULT_PRIORITY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1314,7 +1105,7 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm
|
|||
|
||||
void Rig::updateFromHandParameters(const HandParameters& params, float dt) {
|
||||
|
||||
if (_enableAnimGraph && _animSkeleton && _animNode) {
|
||||
if (_animSkeleton && _animNode) {
|
||||
|
||||
// TODO: figure out how to obtain the yFlip from where it is actually stored
|
||||
glm::quat yFlipHACK = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
|
@ -1387,9 +1178,6 @@ void Rig::makeAnimSkeleton(const FBXGeometry& fbxGeometry) {
|
|||
}
|
||||
|
||||
void Rig::initAnimGraph(const QUrl& url, const FBXGeometry& fbxGeometry) {
|
||||
if (!_enableAnimGraph) {
|
||||
return;
|
||||
}
|
||||
|
||||
makeAnimSkeleton(fbxGeometry);
|
||||
|
||||
|
|
|
@ -46,9 +46,6 @@
|
|||
#include "AnimNodeLoader.h"
|
||||
#include "SimpleMovingAverage.h"
|
||||
|
||||
class AnimationHandle;
|
||||
typedef std::shared_ptr<AnimationHandle> AnimationHandlePointer;
|
||||
|
||||
class Rig;
|
||||
typedef std::shared_ptr<Rig> RigPointer;
|
||||
|
||||
|
@ -101,18 +98,7 @@ public:
|
|||
|
||||
virtual ~Rig() {}
|
||||
|
||||
RigPointer getRigPointer() { return shared_from_this(); }
|
||||
|
||||
AnimationHandlePointer createAnimationHandle();
|
||||
void removeAnimationHandle(const AnimationHandlePointer& handle);
|
||||
bool removeRunningAnimation(AnimationHandlePointer animationHandle);
|
||||
void addRunningAnimation(AnimationHandlePointer animationHandle);
|
||||
bool isRunningAnimation(AnimationHandlePointer animationHandle);
|
||||
bool isRunningRole(const QString& role); // There can be multiple animations per role, so this is more general than isRunningAnimation.
|
||||
const QList<AnimationHandlePointer>& getRunningAnimations() const { return _runningAnimations; }
|
||||
void deleteAnimations();
|
||||
void destroyAnimGraph();
|
||||
const QList<AnimationHandlePointer>& getAnimationHandles() const { return _animationHandles; }
|
||||
|
||||
void overrideAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame);
|
||||
void restoreAnimation();
|
||||
|
@ -187,11 +173,6 @@ public:
|
|||
|
||||
virtual void updateJointState(int index, glm::mat4 rootTransform) = 0;
|
||||
|
||||
void setEnableRig(bool isEnabled) { _enableRig = isEnabled; }
|
||||
bool getEnableRig() const { return _enableRig; }
|
||||
void setEnableAnimGraph(bool isEnabled) { _enableAnimGraph = isEnabled; }
|
||||
bool getEnableAnimGraph() const { return _enableAnimGraph; }
|
||||
|
||||
void updateFromHeadParameters(const HeadParameters& params, float dt);
|
||||
void updateFromEyeParameters(const EyeParameters& params);
|
||||
void updateFromHandParameters(const HandParameters& params, float dt);
|
||||
|
@ -204,7 +185,6 @@ public:
|
|||
|
||||
AnimNode::ConstPointer getAnimNode() const { return _animNode; }
|
||||
AnimSkeleton::ConstPointer getAnimSkeleton() const { return _animSkeleton; }
|
||||
bool disableHands {false}; // should go away with rig animation (and Rig::inverseKinematics)
|
||||
QScriptValue addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList);
|
||||
void removeAnimationStateHandler(QScriptValue handler);
|
||||
void animationStateHandlerResult(int identifier, QScriptValue result);
|
||||
|
@ -230,11 +210,6 @@ public:
|
|||
int _rightElbowJointIndex { -1 };
|
||||
int _rightShoulderJointIndex { -1 };
|
||||
|
||||
QList<AnimationHandlePointer> _animationHandles;
|
||||
QList<AnimationHandlePointer> _runningAnimations;
|
||||
|
||||
bool _enableRig { false };
|
||||
bool _enableAnimGraph { false };
|
||||
glm::vec3 _lastFront;
|
||||
glm::vec3 _lastPosition;
|
||||
glm::vec3 _lastVelocity;
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include <ViewFrustum.h>
|
||||
|
||||
#include "AbstractViewStateInterface.h"
|
||||
#include "AnimationHandle.h"
|
||||
#include "Model.h"
|
||||
#include "MeshPartPayload.h"
|
||||
|
||||
|
@ -1101,7 +1100,6 @@ void Model::deleteGeometry() {
|
|||
_blendedVertexBuffers.clear();
|
||||
_rig->clearJointStates();
|
||||
_meshStates.clear();
|
||||
_rig->deleteAnimations();
|
||||
_rig->destroyAnimGraph();
|
||||
_blendedBlendshapeCoefficients.clear();
|
||||
}
|
||||
|
|
|
@ -28,10 +28,10 @@
|
|||
#include <render/Scene.h>
|
||||
#include <Transform.h>
|
||||
|
||||
#include "AnimationHandle.h"
|
||||
#include "GeometryCache.h"
|
||||
#include "JointState.h"
|
||||
#include "TextureCache.h"
|
||||
#include "Rig.h"
|
||||
|
||||
class AbstractViewStateInterface;
|
||||
class QScriptEngine;
|
||||
|
|
Loading…
Reference in a new issue