THREE.KeyframeTrack
是用来设置动画的对象,以一定的时间过渡到一定值的对象。
1、KeyframeTrack 对象
1.1、构造函数
KeyframeTrack( name : String, times : Array, values : Array, interpolation : Constant )
name
、 一个帧动画的标识符,指以这个标识进行帧动画
times
、时间数组,内部会转换为Float32Array
values
、帧数组,在times
时间内所要执行的数值,Float32Array
类型
interpolation
、常用差值模式(离散的,线性,平滑),默认是InterpolateLinear
线性,是一个常量
常量设置参考 Animation Constants
1.2、使用示例
例如:让一个几何体BoxGeometry
在10
秒内从向量Vector3(0, 0, 0)
平滑过渡到Vector3(100, 0, 0)
,那么可以通过KeyframeTrack
来创建帧动画对象。
var times = [0, 10];.//离散的时间序列
var values = [0, 0, 0, 100, 0, 0];//过渡的值
// 创建帧动画对象,使box几何体,在10秒内移动到(100, 0, 0)的位置
var posKeyframeTrack = new THREE.KeyframeTrack('box.position', times, values)
这个帧动画是以几何体的position
属性进行线性过渡的,同样可以使几何体的材质属性以及其他是离散值的属性都可以进行帧跟踪变化。
1.3、小示例
如图需要实现的效果,需要三个几何体对象在特定的时间,位置和颜色的过渡。
1.3.1、创建几何体
1、首先,需要创建三个几何体,并且把他们放到一个Group
中,然后加入到场景中。
var group = new THREE.Group();
var geometry = new THREE.BoxGeometry(10, 10, 10);
var material = new THREE.MeshLambertMaterial({color: 0xff0000});
var materia2 = new THREE.MeshLambertMaterial({color: 0x00ff00});
var materia3 = new THREE.MeshLambertMaterial({color: 0x0000ff});
var box1 = new THREE.Mesh(geometry, material);
var box2 = new THREE.Mesh(geometry, materia2);
var box3 = new THREE.Mesh(geometry, materia3);
box1.name = 'box1';
box2.name = 'box2';
box3.name = 'box3';
group.add(box1, box2, box3);
scene.add(group);
2、然后,分别创建关于这三个几何体的KeyframeTrack
对象,进行位置和颜色的变化
/*1、创建帧动画序列 KeyframeTrack */
var times = [0, 10];
/* 离散的时间点序列 */
var position_x = [0, 0, 0, 100, 0, 0];
var position_y = [0, 0, 0, 0, 100, 0];
var position_z = [0, 0, 0, 0, 0, 100];
/* 在 times 时间执行的过渡值 Float32Array 类型 */
var color_r = [1, 0, 0, 0, 1, 0];
var color_g = [0, 1, 0, 0, 0, 1];
var color_b = [0, 0, 1, 1, 0, 0];
上面分别以类型化数组的形式定义了,需要过渡的点和颜色。
3、创建KeyframeTrack
对象
/* 创建 KeyframeTrack 对象 0 -- 10 之内位置变化*/
var pos1_Keyframe = new THREE.KeyframeTrack('box1.position', times, position_x);
var pos2_Keyframe = new THREE.KeyframeTrack('box2.position', times, position_y);
var pos3_Keyframe = new THREE.KeyframeTrack('box3.position', times, position_z);
/* 0 -- 10 之内颜色的变化 */
var color1_Keyframe = new THREE.KeyframeTrack('box1.material.color', times, color_r);
var color2_Keyframe = new THREE.KeyframeTrack('box2.material.color', times, color_g);
var color3_Keyframe = new THREE.KeyframeTrack('box3.material.color', times, color_b);
4、创建好帧动画之后就需要对keyframeTrack
进行剪辑 需要通过THREE.AnimationClip
对象
THREE.AnimationClip对象是一组可以重复使用的关键帧轨迹,它代表一个动画,多个KeyframeTrack
构成一个剪辑动画AnimationClip
/* 2、 剪辑keyframeTrack 对象 */
var duration = 10;
/* 多个帧动画创建一个 剪辑对象 命名为 boxAnimation */
var clip = new THREE.AnimationClip('boxAnimation', duration, [
pos1_Keyframe,
pos2_Keyframe,
pos3_Keyframe,
color1_Keyframe,
color2_Keyframe,
color3_Keyframe
]);
5、通过THREE.AnimationMixer
混合器,通过KeyframeTrack
以及剪辑器AnimationClip
对象,仅仅构成动画的数据基础,实际的动画播放需要通过AnimationMixer
来控制,AnimationMixer
就想一个动画控制台,它可以同时控制多个动画,以及合并它们。
var mixer = new THREE.AnimationMixer(group);
// 通过混合器获取AnimationAction对象,来进一步的对动画进行控制
var action = mixer.clipAction(clip);
6、AnimationMixer
是一个混合器,每个动画或者多个动画组都有一个AnimationMixer
,也就是一个动画播放器,但是AnimationMixer
需要通过AnimationAction
去控制动画实际的状态,具体是暂停还是循环以及淡入淡出等等,都需要AnimationAction
来控制,通过播放器对象AnimationMixer
可以获得一个控制器对象AnimationAction
// 通过混合器获取到该动画的控制器对象
var action = mixer.clipAction(clip);
/* 可以调节播放速度 默认值为 1 */
action.timeScale = 5;
/* 开始播放 setLoop()设置循环换模式和次数, play()播放动画*/
action.setLoop(THREE.LoopPingPong, 4).play();
常量设置参考 Animation Constants
7、创建好播放器以及控制之后还需要对动画进行每一帧的跟踪
/* 数据更新 */
var clock = new THREE.Clock();// three.js 时钟对象
function update() {
mixer.update(clock.getDelta());// 更新每一帧的混合器
}
8、示例效果
示例:帧动画效果
2、AnimationAction对象
通过THREE.AnimationMixer()
可以获取到一个THREE.AnimationAction()
然后可以控制动画的循环模式一个次数,淡入淡出等等
2.1、暂停和播放
AnimationAction
的paused
可以控制动画的暂停和播放,是一个boolean
值
修改上述小示例,可以在执行动画期间来控制动画的播放和暂停。
<!-- 添加按钮 -->
<input type="button" value="on/off" id="control-btn">
修改paused
的值
document.getElementById('control-btn').onclick = function () {
action.paused = !action.paused;
};
2.2、动画暂停在最后一帧
可以通过设置AnimationAction.clampWhenFinished
的属性值(布尔值),若为ture
的话可以使动画暂停在最后一帧播放的状态。
2.3、设置开始播放的时间
通过设置AnimationAction.time
属性,可以设置开始播放动画的时间,如果AnimationAction.time = 5
,则动画会在5秒后开始执行
2.4、播放特定的时间段
通过设置AnimationAction.time
属性和AnimationClip.duration
可以在特定的时间段来播放动画,例如一个动画需要执行20
秒,设置动画开始时间为10秒即设置AnimationAction.time = 10
,以及动画结束时间为AnimationClip.duration = 15
,则动画会 10 - 15
之间运行。
2.5、将动画定位谋个时间点
将动画定位在谋个时间点,只需要设置动画开始的时间和结束的时间一致就可以。
例如:首先,设置动画开始时间为AnimationAction.time = 10
,然后设置AnimationClip.duration = AnimationAction.time
即可直接定位到特定的时间点。
3、动画事件
可以通过给AnimationMixer
播放器添加loop
和finished
事件来获取动画一个循环一个动画结束时的回调
mixer.addEventListener( 'loop', function( e ) { …} ); // properties of e: type, action and loopDelta
mixer.addEventListener( 'finished', function( e ) { …} ); // properties of e: type, action and direction
小示例添加如下代码
mixer.addEventListener('loop', function (e) {
console.log('帧动画循环回调:', e);
});
mixer.addEventListener('finished', function (e) {
console.log('帧动画结束回调:', e);
})
运行并查看控制台
具体其他动画操作的属性和方法,请参考THREE.AnimationAction
4、示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="../../../three.png">
<title>暂停和播放帧动画</title>
<style>
body {
margin: 0;
overflow: hidden; /* 溢出隐藏 */
}
input {
position: absolute;
right: 0;
top: 1px;
}
</style>
<script src="../../libs/build/three-r93.js"></script>
<script src="../../libs/examples/js/controls/OrbitControls.js"></script>
</head>
<body>
<input type="button" value="on/off" id="control-btn">
<script>
var scene, camera, renderer, controls;
var clock = new THREE.Clock();
/* 场景 */
function initScene() {
scene = new THREE.Scene();
}
/* 相机 */
function initCamera() {
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
camera.position.set(100, 100, 200);
camera.lookAt(new THREE.Vector3(0, 0, 0));
}
/* 渲染器 */
function initRender() {
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
/* 灯光 */
function initLight() {
scene.add(new THREE.AmbientLight(0xffffff));
var spotLight1 = new THREE.SpotLight(0xffffff);
spotLight1.position.set(-400, -400, -400);
var spotLight2 = new THREE.SpotLight(0xffffff);
spotLight2.position.set(400, 400, 400);
scene.add(spotLight1);
scene.add(spotLight2);
}
/* 控制器 */
function initControls() {
controls = new THREE.OrbitControls(camera, renderer.domElement);
}
var mixer;
var action;
document.getElementById('control-btn').onclick = function () {
action.paused = !action.paused;
};
function initContent() {
var axesHelper = new THREE.AxesHelper(100);
scene.add(axesHelper);
var group = new THREE.Group();
var geometry = new THREE.BoxGeometry(10, 10, 10);
var material = new THREE.MeshLambertMaterial({color: 0xff0000});
var materia2 = new THREE.MeshLambertMaterial({color: 0x00ff00});
var materia3 = new THREE.MeshLambertMaterial({color: 0x0000ff});
var box1 = new THREE.Mesh(geometry, material);
var box2 = new THREE.Mesh(geometry, materia2);
var box3 = new THREE.Mesh(geometry, materia3);
box1.name = 'box1';
box2.name = 'box2';
box3.name = 'box3';
group.add(box1, box2, box3);
scene.add(group);
/*1、创建帧动画序列 KeyframeTrack */
var times = [0, 10];
/* 离散的时间点序列 */
var position_x = [0, 0, 0, 100, 0, 0];
var position_y = [0, 0, 0, 0, 100, 0];
var position_z = [0, 0, 0, 0, 0, 100];
/* 在 times 时间执行的过渡值 Float32Array 类型 */
var color_r = [1, 0, 0, 0, 1, 0];
var color_g = [0, 1, 0, 0, 0, 1];
var color_b = [0, 0, 1, 1, 0, 0];
/* 颜色过渡值 */
/* 创建 KeyframeTrack 对象 0 -- 10 之内位置变化*/
var pos1_Keyframe = new THREE.KeyframeTrack('box1.position', times, position_x);
var pos2_Keyframe = new THREE.KeyframeTrack('box2.position', times, position_y);
var pos3_Keyframe = new THREE.KeyframeTrack('box3.position', times, position_z);
/* 0 -- 10 之内颜色的变化 */
var color1_Keyframe = new THREE.KeyframeTrack('box1.material.color', times, color_r);
var color2_Keyframe = new THREE.KeyframeTrack('box2.material.color', times, color_g);
var color3_Keyframe = new THREE.KeyframeTrack('box3.material.color', times, color_b);
/* 2、 剪辑keyframeTrack 对象 */
var duration = 10;
/* 多个帧动画创建一个 剪辑对象 命名为 boxAnimation */
var clip = new THREE.AnimationClip('boxAnimation', duration, [
pos1_Keyframe,
pos2_Keyframe,
pos3_Keyframe,
color1_Keyframe,
color2_Keyframe,
color3_Keyframe
]);
/* 3、播放编辑好的动画对象 */
mixer = new THREE.AnimationMixer(group);
action = mixer.clipAction(clip);
/* 可以调节播放速度 默认值为 1 */
action.timeScale = 5;
/* 开始播放 */
action.setLoop(THREE.LoopPingPong, 4).play();
}
/* 窗口变动触发 */
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
/* 数据更新 */
function update() {
controls.update();
mixer.update(clock.getDelta());
}
/* 初始化 */
function init() {
initScene();
initCamera();
initRender();
initLight();
initControls();
initContent();
/* 监听事件 */
window.addEventListener('resize', onWindowResize, false);
mixer.addEventListener('loop', function (e) {
console.log('帧动画循环回调:', e);
});
mixer.addEventListener('finished', function (e) {
console.log('帧动画结束回调:', e);
})
}
/* 循环渲染 */
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
update();
}
/* 初始加载 */
(function () {
init();
animate();
})();
</script>
</body>
</html>