admin管理员组文章数量:1318980
I'm using skinning / skeletal animation in ThreeJS. I have an animation, and I want to be able to move backward and forward through it, and jump to different locations within it, rather than the usual looping behaviour.
The animation is created like this, as in the example:
var animation = new THREE.Animation( mesh, geometry.animation.name );
I have tried updating the animation with negative deltas, as well as setting animation.currentTime directly:
animation.currentTime = animationLocation;
These appear to work only if I move forward in time, but if I go backward the animation breaks and I get an error:
THREE.Animation.update: Warning! Scale out of bounds: ... on bone ...
One thing that does actually work without error is to call stop()
and then play()
with a new start time:
animation.stop();
animation.play( true, animationLocation );
...however when I look at what these functions are actually doing, they involve many many function calls, looping, resetting transforms etc. This seems like a horrible way to do it, even if it works as a hack.
It may be that this functionality does not exist yet, in which case I'll try to dig in and create a function that does a minimal amount of work, but I'm hoping there is another way that I haven't found.
Can anyone help with this?
[UPDATE]
As an update on my progress, I'll post the best solution I have at this time...
I pulled out the contents of the stop()
and play()
functions, and stripped out everything I could, making some assumptions about certain values having already been set by 'play()'.
This still seems like it is probably not the best way to do it, but it is doing a bit less work than by just calling stop()
then play()
.
This is what I was able to get it down to:
THREE.Animation.prototype.gotoTime = function( time ) {
//clamp to duration of the animation:
time = THREE.Math.clamp( time, 0, this.length );
this.currentTime = time;
// reset key cache
var h, hl = this.hierarchy.length,
object;
for ( h = 0; h < hl; h ++ ) {
object = this.hierarchy[ h ];
var prevKey = object.animationCache.prevKey;
var nextKey = object.animationCache.nextKey;
prevKey.pos = this.data.hierarchy[ h ].keys[ 0 ];
prevKey.rot = this.data.hierarchy[ h ].keys[ 0 ];
prevKey.scl = this.data.hierarchy[ h ].keys[ 0 ];
nextKey.pos = this.getNextKeyWith( "pos", h, 1 );
nextKey.rot = this.getNextKeyWith( "rot", h, 1 );
nextKey.scl = this.getNextKeyWith( "scl", h, 1 );
}
//isPlaying must be true for update to work due to "early out"
//so remember the current play state:
var wasPlaying = this.isPlaying;
this.isPlaying = true;
//update with a delta time of zero:
this.update( 0 );
//reset the play state:
this.isPlaying = wasPlaying;
}
The main limitation of the function in terms of usefulness is that you can't interpolate from one arbitrary time to another. You can basically just scrub around in the animation.
I'm using skinning / skeletal animation in ThreeJS. I have an animation, and I want to be able to move backward and forward through it, and jump to different locations within it, rather than the usual looping behaviour.
The animation is created like this, as in the example:
var animation = new THREE.Animation( mesh, geometry.animation.name );
I have tried updating the animation with negative deltas, as well as setting animation.currentTime directly:
animation.currentTime = animationLocation;
These appear to work only if I move forward in time, but if I go backward the animation breaks and I get an error:
THREE.Animation.update: Warning! Scale out of bounds: ... on bone ...
One thing that does actually work without error is to call stop()
and then play()
with a new start time:
animation.stop();
animation.play( true, animationLocation );
...however when I look at what these functions are actually doing, they involve many many function calls, looping, resetting transforms etc. This seems like a horrible way to do it, even if it works as a hack.
It may be that this functionality does not exist yet, in which case I'll try to dig in and create a function that does a minimal amount of work, but I'm hoping there is another way that I haven't found.
Can anyone help with this?
[UPDATE]
As an update on my progress, I'll post the best solution I have at this time...
I pulled out the contents of the stop()
and play()
functions, and stripped out everything I could, making some assumptions about certain values having already been set by 'play()'.
This still seems like it is probably not the best way to do it, but it is doing a bit less work than by just calling stop()
then play()
.
This is what I was able to get it down to:
THREE.Animation.prototype.gotoTime = function( time ) {
//clamp to duration of the animation:
time = THREE.Math.clamp( time, 0, this.length );
this.currentTime = time;
// reset key cache
var h, hl = this.hierarchy.length,
object;
for ( h = 0; h < hl; h ++ ) {
object = this.hierarchy[ h ];
var prevKey = object.animationCache.prevKey;
var nextKey = object.animationCache.nextKey;
prevKey.pos = this.data.hierarchy[ h ].keys[ 0 ];
prevKey.rot = this.data.hierarchy[ h ].keys[ 0 ];
prevKey.scl = this.data.hierarchy[ h ].keys[ 0 ];
nextKey.pos = this.getNextKeyWith( "pos", h, 1 );
nextKey.rot = this.getNextKeyWith( "rot", h, 1 );
nextKey.scl = this.getNextKeyWith( "scl", h, 1 );
}
//isPlaying must be true for update to work due to "early out"
//so remember the current play state:
var wasPlaying = this.isPlaying;
this.isPlaying = true;
//update with a delta time of zero:
this.update( 0 );
//reset the play state:
this.isPlaying = wasPlaying;
}
The main limitation of the function in terms of usefulness is that you can't interpolate from one arbitrary time to another. You can basically just scrub around in the animation.
Share Improve this question edited Nov 19, 2012 at 10:19 null asked Oct 25, 2012 at 8:55 nullnull 1,1971 gold badge8 silver badges21 bronze badges 2- Very interesting question... I was working on an animation imported from collada, and wanted to reset the animation to frame 0 immediately after stopping it. I mistakenly tried to do so by using -> animation.update(0) -> animation.stop(), but after reading your question, tried animation.update(0) -> animation.play(false, 0) -> animation.stop()... And it's appears to work consistently. As for your problem (wanting to play animations in reverse), the first thought I had, was to just animate the reverse frames, and playback from the start of that... – Charlie Commented Mar 9, 2013 at 19:03
- Thanks for your ment. My goal was not so much to play it forward and backward, but to be able to jump around from pose to pose, interpolating between them without having to go through the frames in between. I think you can do this with morph target animations already. I noticed the other day that the morph target animations now support playing in reverse as well. Skinning is a lot more involved I think, so I guess it will take longer to have the same features. – null Commented Mar 18, 2013 at 3:03
2 Answers
Reset to default 3You can use THREE.Clock
and assign startTime
, oldTime
, elapsedTime
.
I just pletely gave up on trying to set the animation time directly, and finally accepted that I'd have to use the hack I had thought of early in my google journey
本文标签: javascriptThreeJShow to set current time in AnimationStack Overflow
版权声明:本文标题:javascript - ThreeJS - how to set current time in Animation - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742057158a2418366.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论