WebGL教程_Three.js教程_郭隆邦技术博客 郭隆邦_技术博客 一对一班

Three.js帧动画

Three.js一些骨骼动画、变形动画、相机动画需要通过关键帧的形式去存储运动数据。如果你想解析骨骼动画、变形动画、相机动画等动画效果,需要了解Three.js帧动画相关的APIKeyframeTrackAnimationClipAnimationMixerAnimationAction等,具体可以查看Three.js文档Animation分类下的所有API介绍。

关于帧动画的一些源码案例和视频讲解可以参考本章发布的Three.js视频教程第11章。

代码案例

一般大多数项目帧动画相关的数据都是3D美术在三维软件中设置好的,作为程序员来讲,直接加载三维模型然后解析模型中帧动画包含的关键帧数据,然后通过AnimationMixerAnimationActionAPI去解析播放帧动画。当然有些时候,也需要程序员通过KeyframeTrackAnimationClip等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); //组添加到场景中中

创建帧动画(KeyframeTrackAnimationClip)

通过关键帧构造函数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]);

播放帧动画(AnimationMixerAnimationAction)

相比较创建帧动画,播放帧动画比较简单,一般解析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;//剪辑对象设置播放结束时间
本站版权所有,本站任何内容未经允许不得转载   备案号:豫ICP备16004767号 QQ群:187740169 (WebGL-Three.js教程)   邮箱:guolongbang@163.com