tween.js 用户指南 - 与 Three.js 配合使用的补间动画库

tween.js 用户指南 - 与 Three.js 配合使用的补间动画库

太阳火神的美丽人生 (http://blog.csdn.net/opengl_es)

本文遵循“署名-非商业用途-保持一致”创作公用协议

转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS、Android、Html5、Arduino、pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作。

Learning Three.js - Tween.js for Smooth Animation

tween.js 用户指南
tween.js user guide

注意,这是一个进行中的工作,请原谅其中的不足。无论何时,你看到标记为 TODO 的内容,就说明它是还未做的部分。如果你有哪些东西不清楚或缺少细节内容,请提交一个问题,以帮助使这个指南变得更好。或者如果你觉得你也可以提供帮助的话,你可以随意提交你自已的说明或改进。
NOTE this is a work in progress, please excuse the gaps. Wherever you see something marked as TODO, it's not done yet. If you something is unclear or missing details, please file an issue and help make this guide better. Or feel free to submit clarifications or improvements of your own if you feel you can help too!

什么是补间动画?他们如何工作?为什么你想要使用它们?
What is a tween? How do they work? Why do you want to use them?

A tween (from in-between) is a concept that allows you to change the values of the properties of an object in a smooth way. You just tell it which properties you want to change, which final values should they have when the tween finishes running, and how long should this take, and the tweening engine will take care of finding the intermediate values from the starting to the ending point. For example, suppose you have a position object with x and y coordinates:

var position = { x: 100, y: 0 }

If you wanted to change the x value from 100 to 200, you'd do this:

// Create a tween for position first
var tween = new TWEEN.Tween(position);

// Then tell the tween we want to animate the x property over 1000 milliseconds
tween.to({ x: 200 }, 1000);

Actually this won't do anything yet. The tween has been created but it's not active. You need to start it:

// And set it to start
tween.start();

Finally in order to run as smoothly as possible you should call the TWEEN.update function in the same main loop you're using for animating. This generally looks like this:

animate();

function animate() {
    requestAnimationFrame(animate);
    // [...]
    TWEEN.update();
    // [...]
}

This will take care of updating all active tweens; after 1 second (i.e. 1000 milliseconds) position.x will be 200.

But unless you print the value of x to the console, you can't see its value changing. You might want to use the onUpdate callback:

tween.onUpdate(function() {
    console.log(this.x);
});

This function will be called each time the tween is updated; how often this happens depends on many factors--how fast (and how busy!) your computer or device is, for example.

So far we've only used tweens to print values to the console, but you could use it for things such as animating positions of three.js objects:

var tween = new TWEEN.Tween(cube.position);
        .to({ x: 100, y: 100, z: 100 }, 10000)
        .start();

animate();

function animate() {
    requestAnimationFrame(animate);
    TWEEN.update();

    threeRenderer.render(scene, camera);
}

In this case, because the three.js renderer will look at the object's position before rendering, you don't need to use an explicitonUpdate callback.

You might have noticed something different here too: we're chaining the tween function calls! Each tween function returns the tween instance, so you can rewrite the following code:

var tween = new TWEEN.Tween(position);
tween.to({ x: 200 }, 1000);
tween.start();

into this

var tween = new TWEEN.Tween(position)
    .to({ x: 200 }, 1000)
    .start();

You'll see this a lot in the examples, so it's good to be familiar with it! Check 04-simplest for a working example.

使用 tween.js 的动画
Animating with tween.js

Tween.js doesn't run by itself. You need to tell it when to run, by explicitly calling the update method. The recommended method is to do this inside your main animation loop, which should be called with requestAnimationFrame for getting the best graphics performance:

We've seen this example before:

animate();

function animate() {
    requestAnimationFrame(animate);
    // [...]
    TWEEN.update();
    // [...]
}

If called without parameters, update will determine the current time in order to find out how long has it been since the last time it ran.

However you can also pass an explicit time parameter to update. Thus,

TWEEN.update(100);

means "update with time = 100 milliseconds". You can use this to make sure that all the time-dependent functions in your code are using the very same time value. For example suppose you've got a player and want to run tweens in sync. Your animate code could look like this:

var currentTime = player.currentTime;
TWEEN.update(currentTime);

We use explicit time values for the unit tests. You can have a look at TestTweens to see how we call TWEEN.update() with different values in order to simulate time passing.

控制一个补间动画
Controlling a tween

启动和停止
start
 and stop

So far we've learnt about the Tween.start method, but there are more methods that control individual tweens. Probably the most important one is the start counterpart: stop. If you want to cancel a tween, just call this method over an individual tween:

tween.stop();

Stopping a tween that was never started or that has already been stopped has no effect. No errors are thrown either.

The start method also accepts a time parameter. If you use it, the tween won't start until that particular moment in time; otherwise it will start as soon as possible (i.e. on the next call to TWEEN.update).

更新
update

Individual tweens also have an update method---this is in fact called by TWEEN.update. You generally don't need to call this directly, but might be useful if you're doing crazy hacks.


链接
chain

Things get more interesting when you sequence different tweens in order, i.e. setup one tween to start once a previous one has finished. We call this chaining tweens, and it's done with the chain method. Thus, to make tweenB start after tweenA finishes:

tweenA.chain(tweenB);

Or, for an infinite chain, set tweenA to start once tweenB finishes:

tweenA.chain(tweenB);
tweenB.chain(tweenA);

Check Hello world to see an example of these infinite chains.


重复
repeat

If you wanted a tween to repeat forever you could chain it to itself, but a better way is to use the repeat method. It accepts a parameter that describes how many repetitions you want:

tween.repeat(10); // repeats 10 times and stops
tween.repeat(Infinity); // repeats forever

Check the Repeat example.


摇摇乐
yoyo

This function only has effect if used along with repeat. When active, the behaviour of the tween will be like a yoyo, i.e. it will bounce to and from the start and end values, instead of just repeating the same sequence from the beginning.

延迟
delay

More complex arrangements might require delaying a tween before it actually starts running. You can do that using the delaymethod:

tween.delay(1000);
tween.start();

will start executing 1 second after the start method has been called.

控制所有的补间动画
Controlling all the tweens

The following methods are found in the TWEEN global object, and you generally won't need to use most of them, except for update.

TWEEN.update(time)

We've already talked about this method. It is used to update all the active tweens.

If time is not specified, it will use the current time.

TWEEN.getAll and TWEEN.removeAll

Used to get a reference to the active tweens array and to remove all of them from the array with just one call, respectively.

TWEEN.add(tween) and TWEEN.remove(tween)

Used to add a tween to the list of active tweens, or to remove an specific one from the list, respectively.

These methods are usually used internally only, but are exposed just in case you want to do something funny.

修改 easing 功能(AKA make it councy)
Changing the easing function (AKA make it bouncy)

Tween.js will perform the interpolation between values (i.e. the easing) in a linear manner, so the change will be directly proportional to the elapsed time. This is predictable but also quite uninteresting visually wise. Worry not--this behaviour can be easily changed using the easing method. For example:

tween.easing(TWEEN.Easing.Quadratic.In);

This will result in the tween slowly starting to change towards the final value, accelerating towards the middle, and then quickly reaching its final value. In contrast, TWEEN.Easing.Quadratic.Out would start changing quickly towards the value, but then slow down as it approaches the final value.

可用的 easing 函数
Available easing functions: TWEEN.Easing

There are a few existing easing functions provided with tween.js. They are grouped by the type of equation they represent: Linear, Quadratic, Cubic, Quartic, Quintic, Sinusoidal, Exponential, Circular, Elastic, Back and Bounce, and then by the easing type: In, Out and InOut.

Probably the names won't be saying anything to you unless you're familiar with these concepts already, so it is probably the time to check the Graphs example, which graphs all the curves in one page so you can compare how they look at a glance.

Credit where credit is due: these functions are derived from the original set of equations that Robert Penner graciously made available as free software a few years ago, but have been optimised to play nicely with JavaScript.

使用自定义的 easing 函数
Using a custom easing function

Not only can you use any of the existing functions, but you can also provide your own, as long as it follows a couple of conventions:

  • it must accept one parameter:
    • k: the easing progress, or how far along the duration of the tween we are. Allowed values are in the range [0, 1].
  • it must return a value based on the input parameters.

The easing function is only called once per tween on each update, no matter how many properties are to be changed. The result is then used with the initial value and the difference (the deltas) between this and the final values, as in this pseudocode:

easedElapsed = easing(k);
for each property:
    newPropertyValue = initialPropertyValue + propertyDelta * easedElapsed;

For the performance obsessed people out there: the deltas are calculated only when start() is called on a tween.

So let's suppose you wanted to use a custom easing function that eased the values but appplied a Math.floor to the output, so only the integer part would be returned, resulting in a sort of step-ladder output:

function tenStepEasing(k) {
    return Math.floor(k * 10) / 10;
}

And you could use it in a tween by simply calling its easing method, as we've seen before:

tween.easing(tenStepEasing);

Check the graphs for custom easing functions example to see this in action (and also some metaprogramming for generating step functions).

回调
Callbacks

Another powerful feature is to be able to run your own functions at specific times in each tween's life cycle. This is usually required when changing properties is not enough.

For example, suppose you're trying to animate some object whose properties can't be accessed directly but require you to call a setter instead. You can use an update callback to read the new updated values and then manually call the setters:

var trickyObjTween = new TWEEN.Tween({
    propertyA: trickyObj.getPropertyA(),
    propertyB: trickyObj.getPropertyB()
})
    .to({ propertyA: 100, propertyB: 200 })
    .onUpdate(function() {
        this.setA( this.propertyA );
        this.setB( this.propertyB );
    });

Or imagine you want to ensure the values of an object are in an specific state each time the tween is started. You'll assign a startcallback:

var tween = new TWEEN.Tween(obj)
    .to({ x: 100 })
    .onStart(function() {
        this.x = 0;
    });

The scope for each callback is the tweened object.

启动时回调
onStart

Executed right before the tween starts-i.e. before the deltas are calculated. This is the place to reset values in order to have the tween always start from the same point, for example.

停止时回调
onStop

Executed when a tween is explicitly stopped (not when it is completed normally), and before stopping any possible chained tween.

更新时回调
onUpdate

Executed each time the tween is updated, after the values have been actually updated.

完成时回调
onComplete

Executed when a tween is finished normally (i.e. not stopped).

高级补间动画
Advanced tweening

相对值
Relative values

You can also use relative values when using the to method. When the tween is started, Tween.js will read the current property values and apply the relative values to find out the new final values. But you need to use quotes or the values will be taken as absolute. Let's see this with an example:

// This will make the `x` property be 100, always
var absoluteTween = new TWEEN.Tween(absoluteObj).to({ x: 100 });

// Suppose absoluteObj.x is 0 now
absoluteTween.start(); // Makes x go to 100

// Suppose absoluteObj.x is -100 now
absoluteTween.start(); // Makes x go to 100

// In contrast...

// This will make the `x` property be 100 units more,
// relative to the actual value when it starts
var relativeTween = new TWEEN.Tween(relativeObj).to({ x: "+100" });

// Suppose relativeObj.x is 0 now
relativeTween.start(); // Makes x go to 0 +100 = 100

// Suppose relativeObj.x is -100 now
relativeTween.start(); // Makes x go to -100 +100 = 0

Check 09_relative_values for an example.

补间到数组值
Tweening to arrays of values

In addition to tweening to an absolute or a relative value, you can also have Tween.js change properties across a series of values. To do this, you just need to specify an array of values instead of a single value for a property. For example:

var tween = new TWEEN.Tween(relativeObj).to({ x: [0, -100, 100] });

will make x go from its initial value to 0, -100 and 100.

The way these values are calculated is as follows:

  • first the tween progress is calculated as usual
  • the progress (from 0 to 1) is used as input for the interpolation function
  • based on the progress and the array of values, an interpolated value is generated

For example, when the tween has just started (progress is 0), the interpolation function will return the first value in the array. When the tween is halfway, the interpolation function will return a value approximately in the middle of the array, and when the tween is at the end, the interpolation function will return the last value.

You can change the interpolation function with the interpolation method. For example:

tween.interpolation( TWEEN.Interpolation.Bezier );

The following values are available:

  • TWEEN.Interpolation.Linear
  • TWEEN.Interpolation.Bezier
  • TWEEN.Interpolation.CatmullRom

The default is Linear.

Note that the interpolation function is global to all properties that are tweened with arrays in the same tween. You can't make property A change with an array and a Linear function, and property B with an array too and a Bezier function using the same tween; you should use two tween objects running over the same object but modifying different properties and using different interpolation functions.

Check 06_array_interpolation for an example.

获得最佳性能
Getting the best performance

While Tween.js tries to be performant on its own, nothing prevents you from using it in a way that is counterperformant. Here are some of the ways you can avoid slowing down your projects when using Tween.js (or when animating in the web, in general).

使用高性能的 CSS
Use performant CSS

When you try to animate the position of an element in the page, the easiest solution is to animate the top and left style properties, like this:

var element = document.getElementById('myElement');
var tween = new TWEEN.Tween({ top: 0, left: 0 })
    .to({ top: 100, left: 100 }, 1000)
    .onUpdate(function() {
        element.style.top = this.top + 'px';
        element.style.left = this.left + 'px';
    });

but this is really inefficient because altering these properties forces the browser to recalculate the layout on each update, and this is a very costly operation. Instead of using these, you should use transform, which doesn't invalidate the layout and will also be hardware accelerated when possible, like this:

var element = document.getElementById('myElement');
var tween = new TWEEN.Tween({ top: 0, left: 0 })
    .to({ top: 100, left: 100 }, 1000)
    .onUpdate(function() {
        element.style.transform = 'translate(' + this.left + 'px, ' + this.top + 'px);';
    });

If you want to read more about this, have a look at this article.

However, if your animation needs are that simple, it might be better to just use CSS animations or transitions, where applicable, so that the browser can optimise as much as possible. Tween.js is most useful when your animation needs involve complex arrangements, i.e. you need to sync several tweens together, have some start after one has finished, loop them a number of times, etc.

做好垃圾回收(别名 GC)
Be good to the Garbage collector (alias the GC)

If you use an onUpdate callback, you need to be very careful with what you put on it. This function will be called many times per second, so if you're doing costly operations on each update, you might block the main thread and cause horrible jank, or---if your operations involve memory allocations, you'll end up getting the garbage collector to run too often, and cause jank too. So just don't do either of those things. Keep your onUpdate callbacks very lightweight, and be sure to also use a memory profiler while you're developing.

超级补间动画
Crazy tweening

This is something you might not use often, but you can use the tweening equations outside of Tween.js. They're just functions, after all. So you could use them to calculate smooth curves as input data. For example, they're used to generate audio data in this experiment.

时间: 2025-01-31 05:59:47

tween.js 用户指南 - 与 Three.js 配合使用的补间动画库的相关文章

实例详细讲解Flash动画的Tween补间

flash动画 说到补间,很多人都会想到在时间轴里定义两个关键帧,然后创建一个补间,其实AS也可以完成等效的工作,而且能完成的更好. 要用程序创建补间,有两种方法,一种是通过setInterval函数,定时移动mc,可以达到效果,但比较麻烦.第二种就是今天要推荐的通过Tween类来创建补间动画. 为什么Tween比setInterval方便呢,首先代码量少,看着舒服,其次,Tween类可以使用一些比较有名的缓动类,还有,Tween类可以广播和侦听事件,这三点就足以让我们选择Tween而不是set

KeyboardJS 开发指南 - 与 Three.js 配合使用的捕捉键盘组合键库

KeyboardJS 开发指南 - 与 Three.js 配合使用的捕捉键盘组合键库 太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS.Android.Html5.Arduino.pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. A JavaScript library for bindi

《node.js开发指南》观后感

最近在当当网上买了一本<node.js开发指南>,从学习node.js到现在看的第一本中文教程,也算献出了自己处子之身啊,哈哈.前后大约花了4,5个小时通读了node.js部分,附录部分只是略过了,谈一下感想把. 1.本书的定位: 就像书中的前言部分所述,确实是针对node.js还未入门的初学者准备的,但是有一个前提,如果之前没写过像php等后端的语言读本书可能有点迷茫.所以本书的定位人群应该是对后端脚本语言有过一定开发经验,并且熟悉javascript语法的人. 2.本书的组成部分: 个人感

《写给PHP开发者的Node.js学习指南》一第 2 章 简单的Node.js框架2.1 HTTP服务器

第 2 章 简单的Node.js框架 写给PHP开发者的Node.js学习指南 在之前的章节,我介绍了一个用于PHP到Node.js转换的开发环境,以及如何使用它进行转换.在本章,我们将开始使用这个开发环境并进行实际的转换. 2.1 HTTP服务器 写给PHP开发者的Node.js学习指南 在PHP中,一个PHP文件代表一个HTML页面.一个Web服务器,比如Apache,当请求一个PHP页面时,Web服务器会运行PHP.但是在Node.js里,Node.js的main文件代表了整个服务器.No

《写给PHP开发者的Node.js学习指南》一2.2 预定义的PHP变量

2.2 预定义的PHP变量 写给PHP开发者的Node.js学习指南 当一个支持PHP的Web服务器执行一个PHP页面时,它并不是仅提供一个未处理的对某个页面的HTTP request,然后执行这个页面.如果它这样做的话,那么每一个PHP页面都需要大量额外的代码来解析原始的HTTP request并且把这些值用更方便的方式存储起来.相反,PHP引擎解码原始的HTTP请求,并将数据填充到一堆众所周知的PHP全局变量中.这些全局变量被正确填充才能保证PHP页面正常工作. 由于我们采用的基本方法是将P

《Ext JS权威指南》——3.2节在IE中调试

3.2 在IE中调试 在IE 8之前,在IE中的调试就只有可怜的alert命令了,虽然可以在Visual Studio中进行调试,但太麻烦了.Firebug Lite虽然也发布了支持IE的版本,但是需要在页面中加入Firebug Lite的脚本文件才行,而且在Firebug中的很多功能不能用.就目前来说,做得比较好的还是Debugbar工具,不过与Firebug比起来还是有很大的差距.3.2.1 使用Debugbar和Companion.js调试 1.介绍 Debugbar虽然可以与Firebu

《写给PHP开发者的Node.js学习指南》一导读

前 言 写给PHP开发者的Node.js学习指南 为什么要写这本书呢? 就互联网语言来说,PHP产生于1995年,是一门很古老的语言:而Node.js产生于2009年,是一门非常新的语言.结合PHP和Node.js你可以鸟瞰整个Web服务器从起源到现在的历史过程以及其中的改变.但是更重要的是,这些内容告诉了我们哪些没有改变--没有改变的那些,是整个行业公认的最佳实践--以及一点点未来可能的样子. PHP与Node.js最大的不同在于,PHP是一门阻塞型语言,依赖于API并且在执行结束前并不返回任

jquery.cookie.js使用指南_jquery

jquery.cookie.js是一个轻量级的cookie插件,可以读取.写入.删除cookie. jquery.cookie.js的配置 首先包含jQuery的库文件,在后面包含jquery.cookie.js的库文件. 复制代码 代码如下: <script type="text/javascript" src="js/jquery-1.6.2.min.js"></script> <script type="text/jav

前端任务构建利器Gulp.js使用指南

在软件开发中,任务运行器的好处是不言而喻的.它们可以帮助自动运行常见的冗长的任务,让你可以专注于更重要的事情中,比如敲出很棒的代码.说的严肃点,自动运行一些比如图片压缩.代码压缩.单元测试以及更多的任务的技能,简直就是节省时间的利器. 对于很多前端开发者而言,时下使用最多的任务管理器就是Grunt了,一个可以让你在Gruntfile.js文件中使用JavaScript定义 各种运行任务的工具.基本上,只要你了解JavaScript,创建一个Grunt任务是非常简单直接的事情.丰富的第三方插件比如