RealityKit: change the scale of a ModelEntity without changing its position - animation

I have an ModelEntity animation that move from point A to point B and takes a while to complete. When the user taps on the ModelEntity I would like to add a shrinking animation to the ModelEntity as well.
I tried adding the scale animation directly to the ModelEntity view .move but the problem there is I current transform of the model is where the model is expected to end. Causing the ModelEnity to jump to the end of the animation.
var transform = modelEntity.transform
transform.scale *= factor
modelEntity.move(to: transform, relativeTo: modelEntity.parent, duration: duration) // will not work because the translation of the transform is already at the end of the animation
Is there a way to add a scaling animation to ModelEntity that is already in the middle of a different animation and make them work together?

This was a solution to my problem:
var transform = modelEntity.transform
transform.scale *= factor
modelEntity.move(to: modelEntity.transform, relativeTo: modelEntity.parent)
modelEntity.move(to: transform, relativeTo: modelEntity.parent, duration: duration)
It looks like the problem was that I needed to get the entity to the position it was in at the middle of the animation. For some reason when you call the .move method it expects to start where it should have ended up regardless of the duration.

Related

Multiple overlapping animations on the same element in svg.js

I want to start a animation on an element while a previous animation is still active. However, calling animate() on the element queues the new animation at the end of the current animation.
For example, consider an animation where an element is being moved to a new position. Now, I also want to make it fade out when it reaches a certain position. The following queues the “once” animation at the end of the move, rather than at 80%.
rect.animate(1000).move(100, 100)
.once(0.8, function(pos, eased) {
rect.animate(200).opacity(0);
});
How do I make the element start fading out when it reaches 80% of the move? The API seems to be designed for chaining animations rather simultaneous overlapping animations.
What you are trying to do is a bit more complicated. Unforrtunately its not possible to "hack" into the current animation and add a new animation on the fly.
However what you can do is adding a new property which should be animated:
var fx = rect.animate(1000).move(100, 100)
.once(0.8, function(pos, eased) {
fx.opacity(0);
});
As you will notice that has its own problems because the oopacity immediately jumps to 80%. So this is not an approach which works for you.
Next try: Use the during method:
var morh = SVG.morph(
var fx = rect.animate(1000).move(100, 100)
.once(0.8, function(pos, eased) {
fx.during(function(pos, morphFn, easedPos) {
pos = (pos - 0.8) / 0.2
this.target().opacity(pos)
}
});
We just calculate the opacity ourselves

Slowly move a circle in PIXIJS

I have a circle with PIXI and I need that when the touch is fulfilled another object said circle returns to its original position, but it happens that I do not know any function or method for the movement to be appreciable, all I have achieved is that it disappear and appear in its initial position. How did the transition happen?
Just add the movement into rendering loop
I use PIXI.tickerTicker() for loop
let ticker = new PIXI.ticker.Ticker();
the rendering loop in your situation should be
function loop(){
renderer.render(stageContainer);
yourCircle.position.x += moveSpeed; //your question
if(resetCirclePosition)
yourCircle.position.x = defaultPos;
}
and then to start ticker use
ticker.add(loop);
ticker.start();
Look at ticker documentation http://pixijs.download/dev/docs/PIXI.ticker.Ticker.html

How to get bone transform for a particular animation frame

I have an animation with about 20 frames. I need to be able to access local transforms for each bone for a given animation frame. I know how to access the bone and its local transform (a sample of the code)
Transform root, spine1;
getChildFromName(gameObj, "Jnt_Root", out root);
getChildFromName(root, "Jnt_Spine1", out spine1);
spine1.localRotation = someValue;
All of this works fine, but I don't know the values I'm getting are from which animation frame? I assume its from frame 1 (can verify using debugger but that's not the point)
The questions is how to get and set these values for a specific frame? Thanks!
Something like this should work for getting the current transforms:
AnimationState state = animation["your_animation"];
state.enabled = true;
state.normalizedTime = (1.0f/totalAnimationTime) * specificFrame;
animation.Sample();
// get all transforms of this animation, extract your root and spine from here.
Transform[] transforms = animation.gameObject.GetComponentsInChildren<Transform>();
Or if you're trying to sample while the animation is running you could do something like:
if(animation["your_animation"].normalizedTime > 0.3 && animation["your_animation"].normalizedTime < 0.5) {
//... do something at this point in time. You'll have to figure out the frame
//from the time
}
Last I checked you can't explicitly extract a particular frame. But if you know the total length of your animation (time-wise), you can move the animation to that point with something like: (1.0f/totalAnimationTime) * specificFrame; (this assumes the keyframes are uniformly spaced.)
Once stored you should be able to modify the transforms directly but I've never tried.

Animation synchronisation in Three.js with Tween.js

I'm trying to animate sprites along a path in Three.js using Tween.js by chaining the animations in order to have something like this :
----#----#----#----#----#---- etc
Every sprite has its own tween animation, and I just delay each tween animation at the beginning. Each sprite has in fact N animations along the path (that is not a straight line) and I chain them to have a loop effect.
Everything goes well if the FPS is perfectly stable, but my problem is that if at some point I have a FPS drop, the animations of the different sprites are not in sync anymore, and the space between sprites is not equal anymore. I potentially end up with something like this :
---#--#----#-#-#-----#--- etc
I was wondering if there is a better approach for this, like having only one tween animation for all the sprites, but I don't know how to introduce the offset between each sprite on many line segments.
I cannot post the exact code has it is part of a bigger app, and won't be usable as is, but it looks like this :
// create animations
for each (sprite) {
for each (segment) {
var currentAnimation = new TWEEN.Tween(sprite.position).to({
x : segment.endpoint.x,
y : segment.endpoint.y,
z : segment.endpoint.z
}, animationTime).easing(TWEEN.Easing.Linear.None);
currentAnimation.delay(delayTime * currentSpriteNumber);
previousAnimation.chain(currentAnimation);
}
lastAnimation.chain(firstAnimation);
lastAnimation.onComplete(onEachSpriteAnimationCompleted);
}
// start the animations
for each (sprite) {
spriteFirstAnimation.start();
}
// to remove the delay when each sprite animation has made one loop,
// and instantly replace the sprite at the beginning of the path
// (my paths are not closed)
var onEachSpriteAnimationCompleted = function() {
sprite.position.set(starting position);
for each (sprite animation) {
animation.delay(0);
}
}

Starting a CAKeyframeAnimation from a non-zero time

I have a sub-layer keyframe animation defined to animate an image along a BSpline, grouped together with a rotate animation. With the sub-layer.speed set to 0, I can drag the image back and forth along the curve by adjusting the animationsGroup.timeOffset value based on the distance dragged.
What I want to do is, after a certain threshold (say %15) is to set the animation speed to 1 so the animation completes by itself, but it's not that simple. The animation either completes immediately and resets everything back to the start position, or the animiation reaches the end of the path, loops round to zero, and continues animating until it's back to the point where the animation kicks in.
What I want is:
Tstart -> drag -> T0.15 -> animation -> Tend
But what I'm getting is
Tstart -> drag -> T0.15 -> animation -> Tend -> Tstart -> T0.15
I've already looked into use of timeOffset and time-warps, and fiddled with the parameters but to no avail.
You can that outcome by wrapping your animation group in a new animation group whose duration is 0.85 times the animation groups duration. Here is a bit of code that does just that:
- (void) setTimeOffset:(double)value
{
if (value < 0.15) {
// This is what you are already doing.
_animGroup.timeOffset = value;
[_someSublayer addAnimation:_animGroup forKey:#"animGroup"];
} else if (_animGroup.speed == 0.0) {
// You must set the final position before animating otherwise the
// layer will come back to it's original position.
_someSublayer.position = _theEndPointOfYourPath;
// Now set the speed of the animation group to 1 so that it animates.
// Be sure to leave the timeOffset alone so that is starts where you want it.
_animGroup.speed = 1.0;
// Create a new animation group around it whose duration is the remaining time
// of the animation group and add that to the layer instead. It will prevent
// animGroup from wrapping.
CAAnimationGroup *outerGroup = [[CAAnimationGroup alloc] init];
outerGroup.animations = #[_animGroup];
outerGroup.duration = _animGroup.duration - _animGroup.timeOffset;
[_someSublayer addAnimation:outerGroup forKey:#"animGroup"];
}
}

Resources