Merge pull request #5813 from hyperlogic/tony/anim-hand-state-machines

Added point and grab support to the AnimGraph
This commit is contained in:
Howard Stearns 2015-09-15 15:47:19 -07:00
commit 848bb4fccb
10 changed files with 588 additions and 220 deletions

View file

@ -2868,8 +2868,8 @@ void Application::update(float deltaTime) {
UserInputMapper::PoseValue leftHand = userInputMapper->getPoseState(UserInputMapper::LEFT_HAND); UserInputMapper::PoseValue leftHand = userInputMapper->getPoseState(UserInputMapper::LEFT_HAND);
UserInputMapper::PoseValue rightHand = userInputMapper->getPoseState(UserInputMapper::RIGHT_HAND); UserInputMapper::PoseValue rightHand = userInputMapper->getPoseState(UserInputMapper::RIGHT_HAND);
Hand* hand = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHand(); Hand* hand = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHand();
setPalmData(hand, leftHand, deltaTime, LEFT_HAND_INDEX); setPalmData(hand, leftHand, deltaTime, LEFT_HAND_INDEX, userInputMapper->getActionState(UserInputMapper::LEFT_HAND_CLICK));
setPalmData(hand, rightHand, deltaTime, RIGHT_HAND_INDEX); setPalmData(hand, rightHand, deltaTime, RIGHT_HAND_INDEX, userInputMapper->getActionState(UserInputMapper::RIGHT_HAND_CLICK));
if (Menu::getInstance()->isOptionChecked(MenuOption::HandMouseInput)) { if (Menu::getInstance()->isOptionChecked(MenuOption::HandMouseInput)) {
emulateMouse(hand, userInputMapper->getActionState(UserInputMapper::LEFT_HAND_CLICK), emulateMouse(hand, userInputMapper->getActionState(UserInputMapper::LEFT_HAND_CLICK),
userInputMapper->getActionState(UserInputMapper::SHIFT), LEFT_HAND_INDEX); userInputMapper->getActionState(UserInputMapper::SHIFT), LEFT_HAND_INDEX);
@ -4951,7 +4951,7 @@ mat4 Application::getHMDSensorPose() const {
return mat4(); return mat4();
} }
void Application::setPalmData(Hand* hand, UserInputMapper::PoseValue pose, float deltaTime, int index) { void Application::setPalmData(Hand* hand, UserInputMapper::PoseValue pose, float deltaTime, int index, float triggerValue) {
PalmData* palm; PalmData* palm;
bool foundHand = false; bool foundHand = false;
for (size_t j = 0; j < hand->getNumPalms(); j++) { for (size_t j = 0; j < hand->getNumPalms(); j++) {
@ -5021,6 +5021,7 @@ void Application::setPalmData(Hand* hand, UserInputMapper::PoseValue pose, float
palm->setTipVelocity(glm::vec3(0.0f)); palm->setTipVelocity(glm::vec3(0.0f));
} }
palm->setTipPosition(newTipPosition); palm->setTipPosition(newTipPosition);
palm->setTrigger(triggerValue);
} }
void Application::emulateMouse(Hand* hand, float click, float shift, int index) { void Application::emulateMouse(Hand* hand, float click, float shift, int index) {

View file

@ -485,7 +485,7 @@ private:
void update(float deltaTime); void update(float deltaTime);
void setPalmData(Hand* hand, UserInputMapper::PoseValue pose, float deltaTime, int index); void setPalmData(Hand* hand, UserInputMapper::PoseValue pose, float deltaTime, int index, float triggerValue);
void emulateMouse(Hand* hand, float click, float shift, int index); void emulateMouse(Hand* hand, float click, float shift, int index);
// Various helper functions called during update() // Various helper functions called during update()

View file

@ -1296,10 +1296,13 @@ void MyAvatar::initAnimGraph() {
// ik-avatar.json // ik-avatar.json
// https://gist.github.com/hyperlogic/e58e0a24cc341ad5d060 // https://gist.github.com/hyperlogic/e58e0a24cc341ad5d060
// //
// ik-avatar-hands.json
// https://gist.githubusercontent.com/hyperlogic/04a02c47eb56d8bfaebb
//
// or run a local web-server // or run a local web-server
// python -m SimpleHTTPServer& // python -m SimpleHTTPServer&
// auto graphUrl = QUrl("http://localhost:8000/avatar.json"); //auto graphUrl = QUrl("http://localhost:8000/avatar.json");
auto graphUrl = QUrl("https://gist.githubusercontent.com/hyperlogic/e58e0a24cc341ad5d060/raw/8f824da2908fd89ad1befadd1d8f5d7b3b6efa66/ik-avatar.json"); auto graphUrl = QUrl("https://gist.githubusercontent.com/hyperlogic/04a02c47eb56d8bfaebb/raw/883c7ce8e75ad3f72a0d513c317fe4b74a41c3b8/ik-avatar-hands.json");
_rig->initAnimGraph(graphUrl, _skeletonModel.getGeometry()->getFBXGeometry()); _rig->initAnimGraph(graphUrl, _skeletonModel.getGeometry()->getFBXGeometry());
} }

View file

@ -96,6 +96,17 @@ void SkeletonModel::initJointStates(QVector<JointState> states) {
emit skeletonLoaded(); emit skeletonLoaded();
} }
static const PalmData* getPalmWithIndex(Hand* hand, int index) {
const PalmData* palm = nullptr;
for (size_t j = 0; j < hand->getNumPalms(); j++) {
if (hand->getPalms()[j].getSixenseID() == index) {
palm = &(hand->getPalms()[j]);
break;
}
}
return palm;
}
const float PALM_PRIORITY = DEFAULT_PRIORITY; const float PALM_PRIORITY = DEFAULT_PRIORITY;
// Called within Model::simulate call, below. // Called within Model::simulate call, below.
void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
@ -108,34 +119,59 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar); MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar);
const FBXGeometry& geometry = _geometry->getFBXGeometry(); const FBXGeometry& geometry = _geometry->getFBXGeometry();
Rig::HeadParameters params; Rig::HeadParameters headParams;
params.modelRotation = getRotation(); headParams.modelRotation = getRotation();
params.modelTranslation = getTranslation(); headParams.modelTranslation = getTranslation();
params.enableLean = qApp->getAvatarUpdater()->isHMDMode() && !myAvatar->getStandingHMDSensorMode(); headParams.enableLean = qApp->getAvatarUpdater()->isHMDMode() && !myAvatar->getStandingHMDSensorMode();
params.leanSideways = head->getFinalLeanSideways(); headParams.leanSideways = head->getFinalLeanSideways();
params.leanForward = head->getFinalLeanForward(); headParams.leanForward = head->getFinalLeanForward();
params.torsoTwist = head->getTorsoTwist(); headParams.torsoTwist = head->getTorsoTwist();
params.localHeadOrientation = head->getFinalOrientationInLocalFrame(); headParams.localHeadOrientation = head->getFinalOrientationInLocalFrame();
params.localHeadPitch = head->getFinalPitch(); headParams.localHeadPitch = head->getFinalPitch();
params.localHeadYaw = head->getFinalYaw(); headParams.localHeadYaw = head->getFinalYaw();
params.localHeadRoll = head->getFinalRoll(); headParams.localHeadRoll = head->getFinalRoll();
params.isInHMD = qApp->getAvatarUpdater()->isHMDMode(); headParams.isInHMD = qApp->getAvatarUpdater()->isHMDMode();
// get HMD position from sensor space into world space, and back into model space // get HMD position from sensor space into world space, and back into model space
glm::mat4 worldToModel = glm::inverse(createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition())); glm::mat4 worldToModel = glm::inverse(createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition()));
glm::vec3 yAxis(0.0f, 1.0f, 0.0f); glm::vec3 yAxis(0.0f, 1.0f, 0.0f);
glm::vec3 hmdPosition = glm::angleAxis((float)M_PI, yAxis) * transformPoint(worldToModel * myAvatar->getSensorToWorldMatrix(), myAvatar->getHMDSensorPosition()); glm::vec3 hmdPosition = glm::angleAxis((float)M_PI, yAxis) * transformPoint(worldToModel * myAvatar->getSensorToWorldMatrix(), myAvatar->getHMDSensorPosition());
params.localHeadPosition = hmdPosition; headParams.localHeadPosition = hmdPosition;
params.worldHeadOrientation = head->getFinalOrientationInWorldFrame(); headParams.worldHeadOrientation = head->getFinalOrientationInWorldFrame();
params.eyeLookAt = head->getLookAtPosition(); headParams.eyeLookAt = head->getLookAtPosition();
params.eyeSaccade = head->getSaccade(); headParams.eyeSaccade = head->getSaccade();
params.leanJointIndex = geometry.leanJointIndex; headParams.leanJointIndex = geometry.leanJointIndex;
params.neckJointIndex = geometry.neckJointIndex; headParams.neckJointIndex = geometry.neckJointIndex;
params.leftEyeJointIndex = geometry.leftEyeJointIndex; headParams.leftEyeJointIndex = geometry.leftEyeJointIndex;
params.rightEyeJointIndex = geometry.rightEyeJointIndex; headParams.rightEyeJointIndex = geometry.rightEyeJointIndex;
_rig->updateFromHeadParameters(headParams, deltaTime);
Rig::HandParameters handParams;
const PalmData* leftPalm = getPalmWithIndex(myAvatar->getHand(), LEFT_HAND_INDEX);
if (leftPalm && leftPalm->isActive()) {
handParams.isLeftEnabled = true;
handParams.leftPosition = leftPalm->getRawPosition();
handParams.leftOrientation = leftPalm->getRawRotation();
handParams.leftTrigger = leftPalm->getTrigger();
} else {
handParams.isLeftEnabled = false;
}
const PalmData* rightPalm = getPalmWithIndex(myAvatar->getHand(), RIGHT_HAND_INDEX);
if (rightPalm && rightPalm->isActive()) {
handParams.isRightEnabled = true;
handParams.rightPosition = rightPalm->getRawPosition();
handParams.rightOrientation = rightPalm->getRawRotation();
handParams.rightTrigger = rightPalm->getTrigger();
} else {
handParams.isRightEnabled = false;
}
_rig->updateFromHandParameters(handParams, deltaTime);
_rig->updateFromHeadParameters(params);
} else { } else {
// This is a little more work than we really want. // This is a little more work than we really want.
// //

View file

@ -172,7 +172,12 @@ static AnimNode::Pointer loadNode(const QJsonObject& jsonObj, const QUrl& jsonUr
qCCritical(animation) << "AnimNodeLoader, bad object in \"children\", id =" << id << ", url =" << jsonUrl.toDisplayString(); qCCritical(animation) << "AnimNodeLoader, bad object in \"children\", id =" << id << ", url =" << jsonUrl.toDisplayString();
return nullptr; return nullptr;
} }
node->addChild(loadNode(childValue.toObject(), jsonUrl)); AnimNode::Pointer child = loadNode(childValue.toObject(), jsonUrl);
if (child) {
node->addChild(child);
} else {
return nullptr;
}
} }
if ((animNodeTypeToProcessFunc(type))(node, dataObj, id, jsonUrl)) { if ((animNodeTypeToProcessFunc(type))(node, dataObj, id, jsonUrl)) {
@ -232,13 +237,15 @@ static const char* boneSetStrings[AnimOverlay::NumBoneSets] = {
"fullBody", "fullBody",
"upperBody", "upperBody",
"lowerBody", "lowerBody",
"rightArm",
"leftArm", "leftArm",
"rightArm",
"aboveTheHead", "aboveTheHead",
"belowTheHead", "belowTheHead",
"headOnly", "headOnly",
"spineOnly", "spineOnly",
"empty" "empty",
"leftHand",
"rightHand"
}; };
static AnimOverlay::BoneSet stringToBoneSetEnum(const QString& str) { static AnimOverlay::BoneSet stringToBoneSetEnum(const QString& str) {

View file

@ -26,12 +26,14 @@ void AnimOverlay::buildBoneSet(BoneSet boneSet) {
case FullBodyBoneSet: buildFullBodyBoneSet(); break; case FullBodyBoneSet: buildFullBodyBoneSet(); break;
case UpperBodyBoneSet: buildUpperBodyBoneSet(); break; case UpperBodyBoneSet: buildUpperBodyBoneSet(); break;
case LowerBodyBoneSet: buildLowerBodyBoneSet(); break; case LowerBodyBoneSet: buildLowerBodyBoneSet(); break;
case RightArmBoneSet: buildRightArmBoneSet(); break;
case LeftArmBoneSet: buildLeftArmBoneSet(); break; case LeftArmBoneSet: buildLeftArmBoneSet(); break;
case RightArmBoneSet: buildRightArmBoneSet(); break;
case AboveTheHeadBoneSet: buildAboveTheHeadBoneSet(); break; case AboveTheHeadBoneSet: buildAboveTheHeadBoneSet(); break;
case BelowTheHeadBoneSet: buildBelowTheHeadBoneSet(); break; case BelowTheHeadBoneSet: buildBelowTheHeadBoneSet(); break;
case HeadOnlyBoneSet: buildHeadOnlyBoneSet(); break; case HeadOnlyBoneSet: buildHeadOnlyBoneSet(); break;
case SpineOnlyBoneSet: buildSpineOnlyBoneSet(); break; case SpineOnlyBoneSet: buildSpineOnlyBoneSet(); break;
case LeftHandBoneSet: buildLeftHandBoneSet(); break;
case RightHandBoneSet: buildRightHandBoneSet(); break;
default: default:
case EmptyBoneSet: buildEmptyBoneSet(); break; case EmptyBoneSet: buildEmptyBoneSet(); break;
} }
@ -110,15 +112,6 @@ void AnimOverlay::buildLowerBodyBoneSet() {
_boneSetVec[hipsJoint] = 0.0f; _boneSetVec[hipsJoint] = 0.0f;
} }
void AnimOverlay::buildRightArmBoneSet() {
assert(_skeleton);
buildEmptyBoneSet();
int rightShoulderJoint = _skeleton->nameToJointIndex("RightShoulder");
for_each_child_joint(_skeleton, rightShoulderJoint, [&](int i) {
_boneSetVec[i] = 1.0f;
});
}
void AnimOverlay::buildLeftArmBoneSet() { void AnimOverlay::buildLeftArmBoneSet() {
assert(_skeleton); assert(_skeleton);
buildEmptyBoneSet(); buildEmptyBoneSet();
@ -128,6 +121,15 @@ void AnimOverlay::buildLeftArmBoneSet() {
}); });
} }
void AnimOverlay::buildRightArmBoneSet() {
assert(_skeleton);
buildEmptyBoneSet();
int rightShoulderJoint = _skeleton->nameToJointIndex("RightShoulder");
for_each_child_joint(_skeleton, rightShoulderJoint, [&](int i) {
_boneSetVec[i] = 1.0f;
});
}
void AnimOverlay::buildAboveTheHeadBoneSet() { void AnimOverlay::buildAboveTheHeadBoneSet() {
assert(_skeleton); assert(_skeleton);
buildEmptyBoneSet(); buildEmptyBoneSet();
@ -168,13 +170,31 @@ void AnimOverlay::buildEmptyBoneSet() {
} }
} }
void AnimOverlay::buildLeftHandBoneSet() {
assert(_skeleton);
buildEmptyBoneSet();
int headJoint = _skeleton->nameToJointIndex("LeftHand");
for_each_child_joint(_skeleton, headJoint, [&](int i) {
_boneSetVec[i] = 1.0f;
});
}
void AnimOverlay::buildRightHandBoneSet() {
assert(_skeleton);
buildEmptyBoneSet();
int headJoint = _skeleton->nameToJointIndex("RightHand");
for_each_child_joint(_skeleton, headJoint, [&](int i) {
_boneSetVec[i] = 1.0f;
});
}
// for AnimDebugDraw rendering // for AnimDebugDraw rendering
const AnimPoseVec& AnimOverlay::getPosesInternal() const { const AnimPoseVec& AnimOverlay::getPosesInternal() const {
return _poses; return _poses;
} }
void AnimOverlay::setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) { void AnimOverlay::setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) {
_skeleton = skeleton; AnimNode::setSkeletonInternal(skeleton);
// we have to re-build the bone set when the skeleton changes. // we have to re-build the bone set when the skeleton changes.
buildBoneSet(_boneSet); buildBoneSet(_boneSet);

View file

@ -28,14 +28,16 @@ public:
FullBodyBoneSet = 0, FullBodyBoneSet = 0,
UpperBodyBoneSet, UpperBodyBoneSet,
LowerBodyBoneSet, LowerBodyBoneSet,
RightArmBoneSet,
LeftArmBoneSet, LeftArmBoneSet,
RightArmBoneSet,
AboveTheHeadBoneSet, AboveTheHeadBoneSet,
BelowTheHeadBoneSet, BelowTheHeadBoneSet,
HeadOnlyBoneSet, HeadOnlyBoneSet,
SpineOnlyBoneSet, SpineOnlyBoneSet,
EmptyBoneSet, EmptyBoneSet,
NumBoneSets, LeftHandBoneSet,
RightHandBoneSet,
NumBoneSets
}; };
AnimOverlay(const std::string& id, BoneSet boneSet, float alpha); AnimOverlay(const std::string& id, BoneSet boneSet, float alpha);
@ -64,13 +66,15 @@ public:
void buildFullBodyBoneSet(); void buildFullBodyBoneSet();
void buildUpperBodyBoneSet(); void buildUpperBodyBoneSet();
void buildLowerBodyBoneSet(); void buildLowerBodyBoneSet();
void buildRightArmBoneSet();
void buildLeftArmBoneSet(); void buildLeftArmBoneSet();
void buildRightArmBoneSet();
void buildAboveTheHeadBoneSet(); void buildAboveTheHeadBoneSet();
void buildBelowTheHeadBoneSet(); void buildBelowTheHeadBoneSet();
void buildHeadOnlyBoneSet(); void buildHeadOnlyBoneSet();
void buildSpineOnlyBoneSet(); void buildSpineOnlyBoneSet();
void buildEmptyBoneSet(); void buildEmptyBoneSet();
void buildLeftHandBoneSet();
void buildRightHandBoneSet();
// no copies // no copies
AnimOverlay(const AnimOverlay&) = delete; AnimOverlay(const AnimOverlay&) = delete;

View file

@ -952,7 +952,7 @@ glm::quat Rig::getJointDefaultRotationInParentFrame(int jointIndex) {
return _jointStates[jointIndex].getDefaultRotationInParentFrame(); return _jointStates[jointIndex].getDefaultRotationInParentFrame();
} }
void Rig::updateFromHeadParameters(const HeadParameters& params) { void Rig::updateFromHeadParameters(const HeadParameters& params, float dt) {
if (params.enableLean) { if (params.enableLean) {
updateLeanJoint(params.leanJointIndex, params.leanSideways, params.leanForward, params.torsoTwist); updateLeanJoint(params.leanJointIndex, params.leanSideways, params.leanForward, params.torsoTwist);
} }
@ -1048,6 +1048,52 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm
} }
} }
void Rig::updateFromHandParameters(const HandParameters& params, float dt) {
if (_enableAnimGraph && _animSkeleton) {
// set leftHand grab vars
_animVars.set("isLeftHandIdle", false);
_animVars.set("isLeftHandPoint", false);
_animVars.set("isLeftHandGrab", false);
// Split the trigger range into three zones.
bool rampOut = false;
if (params.leftTrigger > 0.6666f) {
_animVars.set("isLeftHandGrab", true);
} else if (params.leftTrigger > 0.3333f) {
_animVars.set("isLeftHandPoint", true);
} else {
_animVars.set("isLeftHandIdle", true);
rampOut = true;
}
const float OVERLAY_RAMP_OUT_SPEED = 6.0f; // ramp in and out over 1/6th of a sec
_leftHandOverlayAlpha = glm::clamp(_leftHandOverlayAlpha + (rampOut ? -1.0f : 1.0f) * OVERLAY_RAMP_OUT_SPEED * dt, 0.0f, 1.0f);
_animVars.set("leftHandOverlayAlpha", _leftHandOverlayAlpha);
_animVars.set("leftHandGrabBlend", params.leftTrigger);
// set leftHand grab vars
_animVars.set("isRightHandIdle", false);
_animVars.set("isRightHandPoint", false);
_animVars.set("isRightHandGrab", false);
// Split the trigger range into three zones
rampOut = false;
if (params.rightTrigger > 0.6666f) {
_animVars.set("isRightHandGrab", true);
} else if (params.rightTrigger > 0.3333f) {
_animVars.set("isRightHandPoint", true);
} else {
_animVars.set("isRightHandIdle", true);
rampOut = true;
}
_rightHandOverlayAlpha = glm::clamp(_rightHandOverlayAlpha + (rampOut ? -1.0f : 1.0f) * OVERLAY_RAMP_OUT_SPEED * dt, 0.0f, 1.0f);
_animVars.set("rightHandOverlayAlpha", _rightHandOverlayAlpha);
_animVars.set("rightHandGrabBlend", params.rightTrigger);
}
}
void Rig::initAnimGraph(const QUrl& url, const FBXGeometry& fbxGeometry) { void Rig::initAnimGraph(const QUrl& url, const FBXGeometry& fbxGeometry) {
if (!_enableAnimGraph) { if (!_enableAnimGraph) {
return; return;

View file

@ -76,6 +76,17 @@ public:
void dump() const; void dump() const;
}; };
struct HandParameters {
bool isLeftEnabled;
bool isRightEnabled;
glm::vec3 leftPosition = glm::vec3();
glm::quat leftOrientation = glm::quat();
glm::vec3 rightPosition = glm::vec3();
glm::quat rightOrientation = glm::quat();
float leftTrigger = 0.0f;
float rightTrigger = 0.0f;
};
virtual ~Rig() {} virtual ~Rig() {}
RigPointer getRigPointer() { return shared_from_this(); } RigPointer getRigPointer() { return shared_from_this(); }
@ -168,10 +179,12 @@ public:
void setEnableAnimGraph(bool isEnabled) { _enableAnimGraph = isEnabled; } void setEnableAnimGraph(bool isEnabled) { _enableAnimGraph = isEnabled; }
bool getEnableAnimGraph() const { return _enableAnimGraph; } bool getEnableAnimGraph() const { return _enableAnimGraph; }
void updateFromHeadParameters(const HeadParameters& params); void updateFromHeadParameters(const HeadParameters& params, float dt);
void updateEyeJoints(int leftEyeIndex, int rightEyeIndex, const glm::vec3& modelTranslation, const glm::quat& modelRotation, void updateEyeJoints(int leftEyeIndex, int rightEyeIndex, const glm::vec3& modelTranslation, const glm::quat& modelRotation,
const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade = glm::vec3(0.0f)); const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade = glm::vec3(0.0f));
void updateFromHandParameters(const HandParameters& params, float dt);
virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation, virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation,
float scale, float priority) = 0; float scale, float priority) = 0;
@ -215,6 +228,8 @@ public:
Move Move
}; };
RigRole _state = RigRole::Idle; RigRole _state = RigRole::Idle;
float _leftHandOverlayAlpha = 0.0f;
float _rightHandOverlayAlpha = 0.0f;
}; };
#endif /* defined(__hifi__Rig__) */ #endif /* defined(__hifi__Rig__) */

View file

@ -52,190 +52,426 @@
"children": [] "children": []
}, },
{ {
"id": "mainStateMachine", "id": "rightHandOverlay",
"type": "stateMachine", "type": "overlay",
"data": { "data": {
"currentState": "idle", "alpha": 1.0,
"states": [ "boneSet": "rightHand",
{ "alphaVar": "rightHandOverlayAlpha"
"id": "idle",
"interpTarget": 6,
"interpDuration": 6,
"transitions": [
{ "var": "isMovingForward", "state": "walkFwd" },
{ "var": "isMovingBackward", "state": "walkBwd" },
{ "var": "isMovingRight", "state": "strafeRight" },
{ "var": "isMovingLeft", "state": "strafeLeft" },
{ "var": "isTurningRight", "state": "turnRight" },
{ "var": "isTurningLeft", "state": "turnLeft" }
]
},
{
"id": "walkFwd",
"interpTarget": 6,
"interpDuration": 6,
"transitions": [
{ "var": "isNotMoving", "state": "idle" },
{ "var": "isMovingBackward", "state": "walkBwd" },
{ "var": "isMovingRight", "state": "strafeRight" },
{ "var": "isMovingLeft", "state": "strafeLeft" },
{ "var": "isTurningRight", "state": "turnRight" },
{ "var": "isTurningLeft", "state": "turnLeft" }
]
},
{
"id": "walkBwd",
"interpTarget": 6,
"interpDuration": 6,
"transitions": [
{ "var": "isNotMoving", "state": "idle" },
{ "var": "isMovingForward", "state": "walkFwd" },
{ "var": "isMovingRight", "state": "strafeRight" },
{ "var": "isMovingLeft", "state": "strafeLeft" },
{ "var": "isTurningRight", "state": "turnRight" },
{ "var": "isTurningLeft", "state": "turnLeft" }
]
},
{
"id": "strafeRight",
"interpTarget": 6,
"interpDuration": 6,
"transitions": [
{ "var": "isNotMoving", "state": "idle" },
{ "var": "isMovingForward", "state": "walkFwd" },
{ "var": "isMovingBackward", "state": "walkBwd" },
{ "var": "isMovingLeft", "state": "strafeLeft" },
{ "var": "isTurningRight", "state": "turnRight" },
{ "var": "isTurningLeft", "state": "turnLeft" }
]
},
{
"id": "strafeLeft",
"interpTarget": 6,
"interpDuration": 6,
"transitions": [
{ "var": "isNotMoving", "state": "idle" },
{ "var": "isMovingForward", "state": "walkFwd" },
{ "var": "isMovingBackward", "state": "walkBwd" },
{ "var": "isMovingRight", "state": "strafeRight" },
{ "var": "isTurningRight", "state": "turnRight" },
{ "var": "isTurningLeft", "state": "turnLeft" }
]
},
{
"id": "turnRight",
"interpTarget": 6,
"interpDuration": 6,
"transitions": [
{ "var": "isNotTurning", "state": "idle" },
{ "var": "isMovingForward", "state": "walkFwd" },
{ "var": "isMovingBackward", "state": "walkBwd" },
{ "var": "isMovingRight", "state": "strafeRight" },
{ "var": "isMovingLeft", "state": "strafeLeft" },
{ "var": "isTurningLeft", "state": "turnLeft" }
]
},
{
"id": "turnLeft",
"interpTarget": 6,
"interpDuration": 6,
"transitions": [
{ "var": "isNotTurning", "state": "idle" },
{ "var": "isMovingForward", "state": "walkFwd" },
{ "var": "isMovingBackward", "state": "walkBwd" },
{ "var": "isMovingRight", "state": "strafeRight" },
{ "var": "isMovingLeft", "state": "strafeLeft" },
{ "var": "isTurningRight", "state": "turnRight" }
]
}
]
}, },
"children": [ "children": [
{ {
"id": "idle", "id": "rightHandStateMachine",
"type": "clip", "type": "stateMachine",
"data": { "data": {
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/idle.fbx", "currentState": "rightHandIdle",
"startFrame": 0.0, "states": [
"endFrame": 90.0, {
"timeScale": 1.0, "id": "rightHandIdle",
"loopFlag": true "interpTarget": 3,
"interpDuration": 3,
"transitions": [
{ "var": "isRightHandPoint", "state": "rightHandPointIntro" },
{ "var": "isRightHandGrab", "state": "rightHandGrab" }
]
},
{
"id": "rightHandPointIntro",
"interpTarget": 3,
"interpDuration": 3,
"transitions": [
{ "var": "isRightHandIdle", "state": "rightHandIdle" },
{ "var": "isRightHandPointIntroOnDone", "state": "rightHandPointHold" },
{ "var": "isRightHandGrab", "state": "rightHandGrab" }
]
},
{
"id": "rightHandPointHold",
"interpTarget": 3,
"interpDuration": 3,
"transitions": [
{ "var": "isRightHandIdle", "state": "rightHandPointOutro" },
{ "var": "isRightHandGrab", "state": "rightHandGrab" }
]
},
{
"id": "rightHandPointOutro",
"interpTarget": 3,
"interpDuration": 3,
"transitions": [
{ "var": "isRightHandPointOutroOnDone", "state": "rightHandIdle" },
{ "var": "isRightHandGrab", "state": "rightHandGrab" },
{ "var": "isRightHandPoint", "state": "rightHandPointHold" }
]
},
{
"id": "rightHandGrab",
"interpTarget": 3,
"interpDuration": 3,
"transitions": [
{ "var": "isRightHandIdle", "state": "rightHandIdle" },
{ "var": "isRightHandPoint_DISABLED", "state": "rightHandPointHold" }
]
}
]
}, },
"children": [] "children": [
{
"id": "rightHandIdle",
"type": "clip",
"data": {
"url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/right_hand_point.fbx",
"startFrame": 0.0,
"endFrame": 0.0,
"timeScale": 1.0,
"loopFlag": true
},
"children": []
},
{
"id": "rightHandPointHold",
"type": "clip",
"data": {
"url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/right_hand_point.fbx",
"startFrame": 12.0,
"endFrame": 12.0,
"timeScale": 1.0,
"loopFlag": true
},
"children": []
},
{
"id": "rightHandPointIntro",
"type": "clip",
"data": {
"url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/right_hand_point.fbx",
"startFrame": 0.0,
"endFrame": 12.0,
"timeScale": 1.0,
"loopFlag": false
},
"children": []
},
{
"id": "rightHandPointOutro",
"type": "clip",
"data": {
"url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/right_hand_point.fbx",
"startFrame": 0.0,
"endFrame": 65.0,
"timeScale": 1.0,
"loopFlag": false
},
"children": []
},
{
"id": "rightHandGrab",
"type": "blendLinear",
"data": {
"alpha": 0.0,
"alphaVar": "rightHandGrabBlend"
},
"children": [
{
"id": "rightHandOpen",
"type": "clip",
"data": {
"url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/right_hand_point.fbx",
"startFrame": 0.0,
"endFrame": 0.0,
"timeScale": 1.0,
"loopFlag": true
},
"children": []
},
{
"id": "rightHandClose",
"type": "clip",
"data": {
"url": "http://hifi-public.s3.amazonaws.com/ozan/anim/squeeze_hands/right_hand_anim.fbx",
"startFrame": 15.0,
"endFrame": 15.0,
"timeScale": 1.0,
"loopFlag": true
},
"children": []
}
]
}
]
}, },
{ {
"id": "walkFwd", "id": "leftHandOverlay",
"type": "clip", "type": "overlay",
"data": { "data": {
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/walk_fwd.fbx", "alpha": 1.0,
"startFrame": 0.0, "boneSet": "leftHand",
"endFrame": 35.0, "alphaVar" : "leftHandOverlay"
"timeScale": 1.0,
"loopFlag": true,
"timeScaleVar": "walkTimeScale"
}, },
"children": [] "children": [
}, {
{ "id": "leftHandStateMachine",
"id": "walkBwd", "type": "stateMachine",
"type": "clip", "data": {
"data": { "currentState": "leftHandIdle",
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/walk_bwd.fbx", "states": [
"startFrame": 0.0, {
"endFrame": 37.0, "id": "leftHandIdle",
"timeScale": 1.0, "interpTarget": 6,
"loopFlag": true, "interpDuration": 6,
"timeScaleVar": "walkTimeScale" "transitions": [
}, { "var": "isLeftHandPoint", "state": "leftHandPoint" },
"children": [] { "var": "isLeftHandGrab", "state": "leftHandGrab" }
}, ]
{ },
"id": "turnLeft", {
"type": "clip", "id": "leftHandPoint",
"data": { "interpTarget": 6,
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/turn_left.fbx", "interpDuration": 6,
"startFrame": 0.0, "transitions": [
"endFrame": 28.0, { "var": "isLeftHandIdle", "state": "leftHandIdle" },
"timeScale": 1.0, { "var": "isLeftHandGrab", "state": "leftHandGrab" }
"loopFlag": true ]
}, },
"children": [] {
}, "id": "leftHandGrab",
{ "interpTarget": 6,
"id": "turnRight", "interpDuration": 6,
"type": "clip", "transitions": [
"data": { { "var": "isLeftHandIdle", "state": "leftHandIdle" },
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/turn_right.fbx", { "var": "isLeftHandPoint", "state": "leftHandPoint" }
"startFrame": 0.0, ]
"endFrame": 30.0, }
"timeScale": 1.0, ]
"loopFlag": true },
}, "children": [
"children": [] {
}, "id": "leftHandIdle",
{ "type": "clip",
"id": "strafeLeft", "data": {
"type": "clip", "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/squeeze_hands/left_hand_anim.fbx",
"data": { "startFrame": 30.0,
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/strafe_left.fbx", "endFrame": 30.0,
"startFrame": 0.0, "timeScale": 1.0,
"endFrame": 31.0, "loopFlag": true
"timeScale": 1.0, },
"loopFlag": true "children": []
}, },
"children": [] {
}, "id": "leftHandPoint",
{ "type": "clip",
"id": "strafeRight", "data": {
"type": "clip", "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/squeeze_hands/left_hand_anim.fbx",
"data": { "startFrame": 0.0,
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/strafe_right.fbx", "endFrame": 0.0,
"startFrame": 0.0, "timeScale": 1.0,
"endFrame": 31.0, "loopFlag": true
"timeScale": 1.0, },
"loopFlag": true "children": []
}, },
"children": [] {
"id": "leftHandGrab",
"type": "clip",
"data": {
"url": "http://hifi-public.s3.amazonaws.com/ozan/anim/squeeze_hands/left_hand_anim.fbx",
"startFrame": 15.0,
"endFrame": 15.0,
"timeScale": 1.0,
"loopFlag": true
},
"children": []
}
]
},
{
"id": "mainStateMachine",
"type": "stateMachine",
"data": {
"currentState": "idle",
"states": [
{
"id": "idle",
"interpTarget": 6,
"interpDuration": 6,
"transitions": [
{ "var": "isMovingForward", "state": "walkFwd" },
{ "var": "isMovingBackward", "state": "walkBwd" },
{ "var": "isMovingRight", "state": "strafeRight" },
{ "var": "isMovingLeft", "state": "strafeLeft" },
{ "var": "isTurningRight", "state": "turnRight" },
{ "var": "isTurningLeft", "state": "turnLeft" }
]
},
{
"id": "walkFwd",
"interpTarget": 6,
"interpDuration": 6,
"transitions": [
{ "var": "isNotMoving", "state": "idle" },
{ "var": "isMovingBackward", "state": "walkBwd" },
{ "var": "isMovingRight", "state": "strafeRight" },
{ "var": "isMovingLeft", "state": "strafeLeft" },
{ "var": "isTurningRight", "state": "turnRight" },
{ "var": "isTurningLeft", "state": "turnLeft" }
]
},
{
"id": "walkBwd",
"interpTarget": 6,
"interpDuration": 6,
"transitions": [
{ "var": "isNotMoving", "state": "idle" },
{ "var": "isMovingForward", "state": "walkFwd" },
{ "var": "isMovingRight", "state": "strafeRight" },
{ "var": "isMovingLeft", "state": "strafeLeft" },
{ "var": "isTurningRight", "state": "turnRight" },
{ "var": "isTurningLeft", "state": "turnLeft" }
]
},
{
"id": "strafeRight",
"interpTarget": 6,
"interpDuration": 6,
"transitions": [
{ "var": "isNotMoving", "state": "idle" },
{ "var": "isMovingForward", "state": "walkFwd" },
{ "var": "isMovingBackward", "state": "walkBwd" },
{ "var": "isMovingLeft", "state": "strafeLeft" },
{ "var": "isTurningRight", "state": "turnRight" },
{ "var": "isTurningLeft", "state": "turnLeft" }
]
},
{
"id": "strafeLeft",
"interpTarget": 6,
"interpDuration": 6,
"transitions": [
{ "var": "isNotMoving", "state": "idle" },
{ "var": "isMovingForward", "state": "walkFwd" },
{ "var": "isMovingBackward", "state": "walkBwd" },
{ "var": "isMovingRight", "state": "strafeRight" },
{ "var": "isTurningRight", "state": "turnRight" },
{ "var": "isTurningLeft", "state": "turnLeft" }
]
},
{
"id": "turnRight",
"interpTarget": 6,
"interpDuration": 6,
"transitions": [
{ "var": "isNotTurning", "state": "idle" },
{ "var": "isMovingForward", "state": "walkFwd" },
{ "var": "isMovingBackward", "state": "walkBwd" },
{ "var": "isMovingRight", "state": "strafeRight" },
{ "var": "isMovingLeft", "state": "strafeLeft" },
{ "var": "isTurningLeft", "state": "turnLeft" }
]
},
{
"id": "turnLeft",
"interpTarget": 6,
"interpDuration": 6,
"transitions": [
{ "var": "isNotTurning", "state": "idle" },
{ "var": "isMovingForward", "state": "walkFwd" },
{ "var": "isMovingBackward", "state": "walkBwd" },
{ "var": "isMovingRight", "state": "strafeRight" },
{ "var": "isMovingLeft", "state": "strafeLeft" },
{ "var": "isTurningRight", "state": "turnRight" }
]
}
]
},
"children": [
{
"id": "idle",
"type": "clip",
"data": {
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/idle.fbx",
"startFrame": 0.0,
"endFrame": 90.0,
"timeScale": 1.0,
"loopFlag": true
},
"children": []
},
{
"id": "walkFwd",
"type": "clip",
"data": {
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/walk_fwd.fbx",
"startFrame": 0.0,
"endFrame": 35.0,
"timeScale": 1.0,
"loopFlag": true,
"timeScaleVar": "walkTimeScale"
},
"children": []
},
{
"id": "walkBwd",
"type": "clip",
"data": {
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/walk_bwd.fbx",
"startFrame": 0.0,
"endFrame": 37.0,
"timeScale": 1.0,
"loopFlag": true,
"timeScaleVar": "walkTimeScale"
},
"children": []
},
{
"id": "turnLeft",
"type": "clip",
"data": {
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/turn_left.fbx",
"startFrame": 0.0,
"endFrame": 28.0,
"timeScale": 1.0,
"loopFlag": true
},
"children": []
},
{
"id": "turnRight",
"type": "clip",
"data": {
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/turn_right.fbx",
"startFrame": 0.0,
"endFrame": 30.0,
"timeScale": 1.0,
"loopFlag": true
},
"children": []
},
{
"id": "strafeLeft",
"type": "clip",
"data": {
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/strafe_left.fbx",
"startFrame": 0.0,
"endFrame": 31.0,
"timeScale": 1.0,
"loopFlag": true
},
"children": []
},
{
"id": "strafeRight",
"type": "clip",
"data": {
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/strafe_right.fbx",
"startFrame": 0.0,
"endFrame": 31.0,
"timeScale": 1.0,
"loopFlag": true
},
"children": []
}
]
}
]
} }
] ]
} }