mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-15 21:18:06 +02:00
Merge pull request #7649 from hyperlogic/tony/simplify-away-mode
away.js: fix for permanent disabling avatar IK
This commit is contained in:
commit
e4f8a67e60
4 changed files with 82 additions and 145 deletions
|
@ -35,49 +35,26 @@ var OVERLAY_DATA_HMD = {
|
|||
alpha: 1,
|
||||
scale: 2,
|
||||
isFacingAvatar: true,
|
||||
drawInFront: true
|
||||
drawInFront: true
|
||||
};
|
||||
|
||||
// ANIMATION
|
||||
// We currently don't have play/stopAnimation integrated with the animation graph, but we can get the same effect
|
||||
// using an animation graph with a state that we turn on and off through the animation var defined with that state.
|
||||
var awayAnimationHandlerId, activeAnimationHandlerId, stopper;
|
||||
var AWAY_INTRO = {
|
||||
url: "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/kneel.fbx",
|
||||
playbackRate: 30.0,
|
||||
loopFlag: false,
|
||||
startFrame: 0.0,
|
||||
endFrame: 83.0
|
||||
};
|
||||
|
||||
// prefetch the kneel animation so it's resident in memory when we need it.
|
||||
MyAvatar.prefetchAnimation(AWAY_INTRO.url);
|
||||
|
||||
function playAwayAnimation() {
|
||||
function animateAway() {
|
||||
return {isAway: true, isNotAway: false, isNotMoving: false, ikOverlayAlpha: 0.0};
|
||||
}
|
||||
if (stopper) {
|
||||
stopper = false;
|
||||
MyAvatar.removeAnimationStateHandler(activeAnimationHandlerId); // do it now, before making new assignment
|
||||
}
|
||||
awayAnimationHandlerId = MyAvatar.addAnimationStateHandler(animateAway, null);
|
||||
MyAvatar.overrideAnimation(AWAY_INTRO.url, AWAY_INTRO.playbackRate, AWAY_INTRO.loopFlag, AWAY_INTRO.startFrame, AWAY_INTRO.endFrame);
|
||||
}
|
||||
|
||||
function stopAwayAnimation() {
|
||||
MyAvatar.removeAnimationStateHandler(awayAnimationHandlerId);
|
||||
if (stopper) {
|
||||
print('WARNING: unexpected double stop');
|
||||
return;
|
||||
}
|
||||
// How do we know when to turn ikOverlayAlpha back on?
|
||||
// It cannot be as soon as we want to stop the away animation, because then things will look goofy as we come out of that animation.
|
||||
// (Imagine an away animation that sits or kneels, and then stands back up when coming out of it. If head is at the HMD, then it won't
|
||||
// want to track the standing up animation.)
|
||||
// The anim graph will trigger awayOutroOnDone when awayOutro is finished.
|
||||
var backToNormal = false;
|
||||
stopper = true;
|
||||
function animateActive(state) {
|
||||
if (state.awayOutroOnDone) {
|
||||
backToNormal = true;
|
||||
stopper = false;
|
||||
} else if (state.ikOverlayAlpha) {
|
||||
// Once the right state gets reflected back to us, we don't need the hander any more.
|
||||
// But we are locked against handler changes during the execution of a handler, so remove asynchronously.
|
||||
Script.setTimeout(function () { MyAvatar.removeAnimationStateHandler(activeAnimationHandlerId); }, 0);
|
||||
}
|
||||
// It might be cool to "come back to life" by fading the ik overlay back in over a short time. But let's see how this goes.
|
||||
return {isAway: false, isNotAway: true, ikOverlayAlpha: backToNormal ? 1.0 : 0.0}; // IWBNI we had a way of deleting an anim var.
|
||||
}
|
||||
activeAnimationHandlerId = MyAvatar.addAnimationStateHandler(animateActive, ['ikOverlayAlpha', 'awayOutroOnDone']);
|
||||
MyAvatar.restoreAnimation();
|
||||
}
|
||||
|
||||
// OVERLAY
|
||||
|
@ -113,15 +90,17 @@ function showOverlay() {
|
|||
var screen = Controller.getViewportDimensions();
|
||||
|
||||
// keep the overlay it's natural size and always center it...
|
||||
Overlays.editOverlay(overlay, { visible: true,
|
||||
x: ((screen.x - OVERLAY_WIDTH) / 2),
|
||||
Overlays.editOverlay(overlay, { visible: true,
|
||||
x: ((screen.x - OVERLAY_WIDTH) / 2),
|
||||
y: ((screen.y - OVERLAY_HEIGHT) / 2) });
|
||||
}
|
||||
}
|
||||
|
||||
function hideOverlay() {
|
||||
Overlays.editOverlay(overlay, {visible: false});
|
||||
Overlays.editOverlay(overlayHMD, {visible: false});
|
||||
}
|
||||
|
||||
hideOverlay();
|
||||
|
||||
function maybeMoveOverlay() {
|
||||
|
@ -171,6 +150,7 @@ function safeGetHMDMounted() {
|
|||
}
|
||||
return HMD.mounted;
|
||||
}
|
||||
|
||||
var wasHmdMounted = safeGetHMDMounted();
|
||||
|
||||
function goAway() {
|
||||
|
@ -277,7 +257,7 @@ Script.update.connect(maybeGoAway);
|
|||
Controller.mousePressEvent.connect(goActive);
|
||||
Controller.keyPressEvent.connect(maybeGoActive);
|
||||
// Note peek() so as to not interfere with other mappings.
|
||||
eventMapping.from(Controller.Standard.LeftPrimaryThumb).peek().to(goActive);
|
||||
eventMapping.from(Controller.Standard.LeftPrimaryThumb).peek().to(goActive);
|
||||
eventMapping.from(Controller.Standard.RightPrimaryThumb).peek().to(goActive);
|
||||
eventMapping.from(Controller.Standard.LeftSecondaryThumb).peek().to(goActive);
|
||||
eventMapping.from(Controller.Standard.RightSecondaryThumb).peek().to(goActive);
|
||||
|
|
|
@ -246,7 +246,6 @@
|
|||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
||||
{ "var": "isTurningRight", "state": "turnRight" },
|
||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||
{ "var": "isAway", "state": "awayIntro" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
|
@ -266,7 +265,6 @@
|
|||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
||||
{ "var": "isTurningRight", "state": "turnRight" },
|
||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||
{ "var": "isAway", "state": "awayIntro" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
|
@ -285,7 +283,6 @@
|
|||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
||||
{ "var": "isTurningRight", "state": "turnRight" },
|
||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||
{ "var": "isAway", "state": "awayIntro" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
|
@ -304,7 +301,6 @@
|
|||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
||||
{ "var": "isTurningRight", "state": "turnRight" },
|
||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||
{ "var": "isAway", "state": "awayIntro" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
|
@ -323,7 +319,6 @@
|
|||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
||||
{ "var": "isTurningRight", "state": "turnRight" },
|
||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||
{ "var": "isAway", "state": "awayIntro" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
|
@ -342,7 +337,6 @@
|
|||
{ "var": "isMovingRight", "state": "strafeRight" },
|
||||
{ "var": "isTurningRight", "state": "turnRight" },
|
||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||
{ "var": "isAway", "state": "awayIntro" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
|
@ -361,7 +355,6 @@
|
|||
{ "var": "isMovingRight", "state": "strafeRight" },
|
||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||
{ "var": "isAway", "state": "awayIntro" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
|
@ -380,7 +373,6 @@
|
|||
{ "var": "isMovingRight", "state": "strafeRight" },
|
||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
||||
{ "var": "isTurningRight", "state": "turnRight" },
|
||||
{ "var": "isAway", "state": "awayIntro" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
|
@ -388,37 +380,11 @@
|
|||
{ "var": "isInAirRun", "state": "inAirRun" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "awayIntro",
|
||||
"interpTarget": 30,
|
||||
"interpDuration": 30,
|
||||
"transitions": [
|
||||
{ "var": "isNotAway", "state": "awayOutro" },
|
||||
{ "var": "awayIntroOnDone", "state": "away"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "away",
|
||||
"interpTarget": 3,
|
||||
"interpDuration": 3,
|
||||
"transitions": [
|
||||
{ "var": "isNotAway", "state": "awayOutro" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "awayOutro",
|
||||
"interpTarget": 3,
|
||||
"interpDuration": 3,
|
||||
"transitions": [
|
||||
{ "var": "awayOutroOnDone", "state": "idle" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "fly",
|
||||
"interpTarget": 6,
|
||||
"interpDuration": 6,
|
||||
"transitions": [
|
||||
{ "var": "isAway", "state": "awayIntro" },
|
||||
{ "var": "isNotFlying", "state": "idle" }
|
||||
]
|
||||
},
|
||||
|
@ -427,7 +393,6 @@
|
|||
"interpTarget": 0,
|
||||
"interpDuration": 6,
|
||||
"transitions": [
|
||||
{ "var": "isAway", "state": "awayIntro" },
|
||||
{ "var": "isNotTakeoff", "state": "inAirStand" }
|
||||
]
|
||||
},
|
||||
|
@ -436,7 +401,6 @@
|
|||
"interpTarget": 0,
|
||||
"interpDuration": 6,
|
||||
"transitions": [
|
||||
{ "var": "isAway", "state": "awayIntro" },
|
||||
{ "var": "isNotTakeoff", "state": "inAirRun" }
|
||||
]
|
||||
},
|
||||
|
@ -446,7 +410,6 @@
|
|||
"interpDuration": 6,
|
||||
"interpType": "snapshotPrev",
|
||||
"transitions": [
|
||||
{ "var": "isAway", "state": "awayIntro" },
|
||||
{ "var": "isNotInAir", "state": "landStandImpact" }
|
||||
]
|
||||
},
|
||||
|
@ -456,7 +419,6 @@
|
|||
"interpDuration": 6,
|
||||
"interpType": "snapshotPrev",
|
||||
"transitions": [
|
||||
{ "var": "isAway", "state": "awayIntro" },
|
||||
{ "var": "isNotInAir", "state": "landRun" }
|
||||
]
|
||||
},
|
||||
|
@ -465,7 +427,6 @@
|
|||
"interpTarget": 6,
|
||||
"interpDuration": 4,
|
||||
"transitions": [
|
||||
{ "var": "isAway", "state": "awayIntro" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
|
@ -483,7 +444,6 @@
|
|||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
||||
{ "var": "isTurningRight", "state": "turnRight" },
|
||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||
{ "var": "isAway", "state": "awayIntro" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
|
@ -497,7 +457,6 @@
|
|||
"interpTarget": 1,
|
||||
"interpDuration": 7,
|
||||
"transitions": [
|
||||
{ "var": "isAway", "state": "awayIntro" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
|
@ -754,42 +713,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "awayIntro",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/kneel.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 83.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": false
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "away",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/kneel.fbx",
|
||||
"startFrame": 83.0,
|
||||
"endFrame": 84.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": true
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "awayOutro",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/kneel.fbx",
|
||||
"startFrame": 84.0,
|
||||
"endFrame": 167.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": false
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "fly",
|
||||
"type": "clip",
|
||||
|
|
|
@ -48,36 +48,47 @@ const glm::vec3 DEFAULT_NECK_POS(0.0f, 0.70f, 0.0f);
|
|||
|
||||
void Rig::overrideAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame) {
|
||||
|
||||
// find an unused AnimClip clipNode
|
||||
std::shared_ptr<AnimClip> clip;
|
||||
if (_userAnimState == UserAnimState::None || _userAnimState == UserAnimState::B) {
|
||||
_userAnimState = UserAnimState::A;
|
||||
clip = std::dynamic_pointer_cast<AnimClip>(_animNode->findByName("userAnimA"));
|
||||
} else if (_userAnimState == UserAnimState::A) {
|
||||
_userAnimState = UserAnimState::B;
|
||||
clip = std::dynamic_pointer_cast<AnimClip>(_animNode->findByName("userAnimB"));
|
||||
UserAnimState::ClipNodeEnum clipNodeEnum;
|
||||
if (_userAnimState.clipNodeEnum == UserAnimState::None || _userAnimState.clipNodeEnum == UserAnimState::B) {
|
||||
clipNodeEnum = UserAnimState::A;
|
||||
} else {
|
||||
clipNodeEnum = UserAnimState::B;
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (_animNode) {
|
||||
// find an unused AnimClip clipNode
|
||||
std::shared_ptr<AnimClip> clip;
|
||||
if (clipNodeEnum == UserAnimState::A) {
|
||||
clip = std::dynamic_pointer_cast<AnimClip>(_animNode->findByName("userAnimA"));
|
||||
} else {
|
||||
clip = std::dynamic_pointer_cast<AnimClip>(_animNode->findByName("userAnimB"));
|
||||
}
|
||||
|
||||
_currentUserAnimURL = url;
|
||||
if (clip) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
// store current user anim state.
|
||||
_userAnimState = { clipNodeEnum, url, fps, loop, firstFrame, lastFrame };
|
||||
|
||||
// notify the userAnimStateMachine the desired state.
|
||||
_animVars.set("userAnimNone", false);
|
||||
_animVars.set("userAnimA", _userAnimState == UserAnimState::A);
|
||||
_animVars.set("userAnimB", _userAnimState == UserAnimState::B);
|
||||
_animVars.set("userAnimA", clipNodeEnum == UserAnimState::A);
|
||||
_animVars.set("userAnimB", clipNodeEnum == UserAnimState::B);
|
||||
}
|
||||
|
||||
void Rig::restoreAnimation() {
|
||||
if (_currentUserAnimURL != "") {
|
||||
_currentUserAnimURL = "";
|
||||
if (_userAnimState.clipNodeEnum != UserAnimState::None) {
|
||||
_userAnimState.clipNodeEnum = UserAnimState::None;
|
||||
|
||||
// notify the userAnimStateMachine the desired state.
|
||||
_animVars.set("userAnimNone", true);
|
||||
_animVars.set("userAnimA", false);
|
||||
|
@ -1129,6 +1140,14 @@ void Rig::initAnimGraph(const QUrl& url) {
|
|||
connect(_animLoader.get(), &AnimNodeLoader::success, [this](AnimNode::Pointer nodeIn) {
|
||||
_animNode = nodeIn;
|
||||
_animNode->setSkeleton(_animSkeleton);
|
||||
|
||||
if (_userAnimState.clipNodeEnum != UserAnimState::None) {
|
||||
// restore the user animation we had before reset.
|
||||
UserAnimState origState = _userAnimState;
|
||||
_userAnimState = { UserAnimState::None, "", 30.0f, false, 0.0f, 0.0f };
|
||||
overrideAnimation(origState.url, origState.fps, origState.loop, origState.firstFrame, origState.lastFrame);
|
||||
}
|
||||
|
||||
});
|
||||
connect(_animLoader.get(), &AnimNodeLoader::error, [url](int error, QString str) {
|
||||
qCCritical(animation) << "Error loading" << url.toDisplayString() << "code = " << error << "str =" << str;
|
||||
|
|
|
@ -289,13 +289,28 @@ public:
|
|||
RigRole _state { RigRole::Idle };
|
||||
RigRole _desiredState { RigRole::Idle };
|
||||
float _desiredStateAge { 0.0f };
|
||||
enum class UserAnimState {
|
||||
None = 0,
|
||||
A,
|
||||
B
|
||||
|
||||
struct UserAnimState {
|
||||
enum ClipNodeEnum {
|
||||
None = 0,
|
||||
A,
|
||||
B
|
||||
};
|
||||
|
||||
UserAnimState() : clipNodeEnum(UserAnimState::None) {}
|
||||
UserAnimState(ClipNodeEnum clipNodeEnumIn, const QString& urlIn, float fpsIn, bool loopIn, float firstFrameIn, float lastFrameIn) :
|
||||
clipNodeEnum(clipNodeEnumIn), url(urlIn), fps(fpsIn), loop(loopIn), firstFrame(firstFrameIn), lastFrame(lastFrameIn) {}
|
||||
|
||||
ClipNodeEnum clipNodeEnum;
|
||||
QString url;
|
||||
float fps;
|
||||
bool loop;
|
||||
float firstFrame;
|
||||
float lastFrame;
|
||||
};
|
||||
UserAnimState _userAnimState { UserAnimState::None };
|
||||
QString _currentUserAnimURL;
|
||||
|
||||
UserAnimState _userAnimState;
|
||||
|
||||
float _leftHandOverlayAlpha { 0.0f };
|
||||
float _rightHandOverlayAlpha { 0.0f };
|
||||
|
||||
|
|
Loading…
Reference in a new issue