Three.js 帧动画
Three.js 一些骨骼动画、变形动画、相机动画需要通过关键帧的形式去存储运动数据。如果你想解析骨骼动画、变形动画、相机动画等动画效果,需要了解Three.js帧动画相关的APIKeyframeTrack
、AnimationClip
、AnimationMixer
、AnimationAction
等,具体可以查看Three.js文档Animation分类下的所有API介绍。
关于帧动画的一些源码案例和视频讲解可以参考本章发布的Three.js视频教程第11章。
代码案例
一般大多数项目帧动画相关的数据都是3D美术在三维软件中设置好的,作为程序员来讲,直接加载三维模型然后解析模型中帧动画包含的关键帧数据,然后通过AnimationMixer
和AnimationAction
API去解析播放帧动画。当然有些时候,也需要程序员通过KeyframeTrack
和AnimationClip
等API自定义帧动画数据。
下面代码截取自Threejs视频教程第11.1节,完整代码可以查看11.1节课程,下面的代码只是与帧动画相关的代码
下面帧动画的效果,就是一个球体网格模型模型逐渐变大,一个长方体沿着坐标轴移动同时颜色发生变化。
需要变化的两个网格模型
三维场景中创建了两个网格模型球体和长方体,分别命名了mesh1.name = "Box"
、mesh2.name = "Sphere"
/**
* 创建两个网格模型并设置一个父对象group
*/
var group = new THREE.Group(); //作为网格模型的父对象
// 网格模型1
var geometry1 = new THREE.BoxGeometry(40, 6, 6); //长方体
var material1 = new THREE.MeshLambertMaterial({
color: 0x0000ff
}); //材质对象Material
var mesh1 = new THREE.Mesh(geometry1, material1); //网格模型对象Mesh
mesh1.name = "Box"; //网格模型命名
group.add(mesh1); //网格模型添加到组中
// 网格模型2
var geometry2 = new THREE.SphereGeometry(10, 25, 25); //球体
var material2 = new THREE.MeshLambertMaterial({
color: 0xff00ff
}); //材质对象Material
var mesh2 = new THREE.Mesh(geometry2, material2); //网格模型对象Mesh
mesh2.name = "Sphere"; //网格模型命名
group.add(mesh2); //网格模型添加到组中
scene.add(group); //组添加到场景中中
创建帧动画(KeyframeTrack
和AnimationClip
)
通过关键帧构造函数KeyframeTrack
创建一个关键帧对象,里面包含了一系列的关键帧数据,每一帧网格模型的状态和它对应的时间,KeyframeTrack
函数的参数2是时间序列,参数3是参数1'Box.position'
的值序列,两组序列意义对应,也就是一个状态对应一个时间点,然后通过插值计算可以计算出来每个时间点,参数1所指向绑定对象的对应状态。
所有的关键帧对象KeyframeTrack
组要作为剪辑对象AnimationClip
构造函数参数3的元素,剪辑对象AnimationClip
的参数2主要用于设置帧动画的播放持续时间。
/**
* 编辑group子对象网格模型mesh1和mesh2的帧动画数据
*/
// 创建名为Box对象的关键帧数据
var times = [0, 10]; //关键帧时间数组,离散的时间点序列
var values = [0, 0, 0, 150, 0, 0]; //与时间点对应的值组成的数组
// 创建位置关键帧对象:0时刻对应位置0, 0, 0 10时刻对应位置150, 0, 0
var posTrack = new THREE.KeyframeTrack('Box.position', times, values);
// 创建颜色关键帧对象:10时刻对应颜色1, 0, 0 20时刻对应颜色0, 0, 1
var colorKF = new THREE.KeyframeTrack('Box.material.color', [10, 20], [1, 0, 0, 0, 0, 1]);
// 创建名为Sphere对象的关键帧数据 从0~20时间段,尺寸scale缩放3倍
var scaleTrack = new THREE.KeyframeTrack('Sphere.scale', [0, 20], [1, 1, 1, 3, 3, 3]);
// duration决定了默认的播放时间,一般取所有帧动画的最大时间
// duration偏小,帧动画数据无法播放完,偏大,播放完帧动画会继续空播放
var duration = 20;
// 多个帧动画作为元素创建一个剪辑clip对象,命名"default",持续时间20
var clip = new THREE.AnimationClip("default", duration, [posTrack, colorKF, scaleTrack]);
播放帧动画(AnimationMixer
和AnimationAction
)
相比较创建帧动画,播放帧动画比较简单,一般解析3D美术导出的包含帧动画的三维模型通过下面代码就可以,下面这一段代码解析的是上面代码创建的帧动画数据
帧动画混合器对象AnimationMixer
主要用于播放帧动画,可以播放参数对象group的所有子对象所绑定的帧动画数据,执行混合器对象AnimationMixer
的方法.clipAction(clip)
把包含关键帧数据的剪辑对象AnimationClip
作为参数会返回一个帧动画操作对象AnimationAction
,通过AnimationAction
对象的方法.play()
可以播放帧动画数据,通过该对象的.timeScale
属性可以调节播放速度。
/**
* 播放编辑好的关键帧数据
*/
// group作为混合器的参数,可以播放group中所有子对象的帧动画
var mixer = new THREE.AnimationMixer(group);
// 剪辑clip作为参数,通过混合器clipAction方法返回一个操作对象AnimationAction
var AnimationAction = mixer.clipAction(clip);
//通过操作Action设置播放方式
AnimationAction.timeScale = 20;//默认1,可以调节播放速度
// AnimationAction.loop = THREE.LoopOnce; //不循环播放
AnimationAction.play();//开始播放
在播放帧动画数据的时候,需要通知混合器对象AnimationMixer
渲染时间。
// 创建一个时钟对象Clock
var clock = new THREE.Clock();
// 渲染函数
function render() {
renderer.render(scene, camera);
requestAnimationFrame(render);
//clock.getDelta()方法获得两帧的时间间隔
// 更新混合器相关的时间
mixer.update(clock.getDelta());
}
外部模型帧动画
无论哪种格式的三维模型数据,加载后通过控制可以打印返回的对象,可以查看对象包含的顶点数据、材质数据、帧动画数据,一般找到返回对象的.animations
属性可以查看到里面包含的关键帧数据KeyframeTrack
,外部模型的更多具体案例你可以查看Threejs视频教程第12章关于骨骼动画和变形动画的介绍。
var mixer = null; //声明一个混合器变量
// 加载文件返回一个对象obj
loader.load("model.json", function(obj) {
console.log(obj)
obj.scale.set(15, 15, 15);
scene.add(obj);
// obj作为混合器的参数,可以播放obj包含的帧动画数据
mixer = new THREE.AnimationMixer(obj);
// obj.animations[0]:获得剪辑clip对象
// // 剪辑clip作为参数,通过混合器clipAction方法返回一个操作对象AnimationAction
var AnimationAction = mixer.clipAction(obj.animations[0]);
// AnimationAction.loop = THREE.LoopOnce; //不循环播放
// AnimationAction.clampWhenFinished=true;//暂停在最后一帧播放的状态
AnimationAction.play();
});
// 创建一个时钟对象Clock
var clock = new THREE.Clock();
// 渲染函数
function render() {
renderer.render(scene, camera);
requestAnimationFrame(render);
if(mixer!==null){
//clock.getDelta()方法获得两帧的时间间隔
// 更新混合器相关的时间
mixer.update(clock.getDelta());
}
}
帧动画播放暂停/继续(.paused
)
通过帧动画操作对象AnimationAction
的.paused
属性可以控制帧动画的播放状态。一般项目的开发的时候,可以结合前端框架,设置一个播放暂停按钮来控制帧动画播放状态,具体案例源码参考11.3.0案例。
// 如果是播放状态,设置为暂停状态
AnimationAction.paused = false;
// 如果是暂停状态,设置为播放状态
AnimationAction.paused = true;
设置播放时间区间(.time
和.duration
)
通过动画操作对象AnimationAction
的时间属性.time
和动画剪辑对象AnimationClip
的.duration
属性来设置特定帧动画的播放时间区间。
// 设置播放区间10~18 关键帧数据总时间是20
AnimationAction.time = 10; //操作对象设置开始播放时间
clip.duration = 18;//剪辑对象设置播放结束时间
定位在某个特定的时间
仍然是通过动画操作对象AnimationAction
的时间属性.time
和动画剪辑对象AnimationClip
的.duration
属性来实现,这个思路很简单,先通过动画操作对象的时间属性设置定位的时间点,然后把剪辑对象播放的停止时间设置为和动画操作对象的时间一致。
前端引入一个滚动条就可以通过前端滚动条调整下面.time
值绑定的时间点,就可以实现滚动条任意定位动画的位置。具体代码参考本站发布的threejs教程11.3.4源码案例。
// 开始结束时间设置为一样,相当于播放时间为0,直接跳转到时间点对应的状态
AnimationAction.time = 10; //操作对象设置开始播放时间
clip.duration = AnimationAction.time;//剪辑对象设置播放结束时间
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论