本文是Three.js电子书的12.4节
本节课给大家展示两个变形动画的案例,一个是鸟的飞行变形动画,一个是通过滚动条控制人体的变形案例。
加载完三维模型后,通过console.log(geometry.morphTargets)
可以在浏览器控制台查看模型的变形数据。
// 通过加载器JSONLoader加载变形动画模型文件./人/umich_ucs.json
var loader = new THREE.JSONLoader();
loader.load("./人/umich_ucs.json", function(geometry, materials) {
// console.log(geometry);
// console.log(materials);
// 通过平均面法线来计算顶点法线,效果更光滑
geometry.computeVertexNormals();
var mesh = new THREE.Mesh(geometry, materials[0]);
// 材质对象开启渲染目标
mesh.material.morphTargets = true
mesh.rotateX(-Math.PI / 2);
mesh.position.y = -50;
scene.add(mesh); //插入到场景中
// 查看变形目标数据
console.log(geometry.morphTargets);
})
你可以在代码中给网格模型的.morphTargetInfluences
属性赋予不同的值,测试人的胖瘦变化。
// 变胖
mesh.morphTargetInfluences[0] = 1;
// 变瘦
mesh.morphTargetInfluences[4] = 1;
下面代码中的滚动条
是通过vue的UI库element-ui实现的,你也可以换别的方式,这都是前端的内容,不再多说。
<div id="app">
<div class="block" style="display:inline;width:500px">
<el-slider v-model="time" show-input :max=1 :step=0.01>el-slider>
div>
div>
下面代码通过vuejs把网格模型Mesh的.morphTargetInfluences
属性和滚动条进行绑定,只要滚动条改变就可以同步改变mesh.morphTargetInfluences
属性值,mesh.morphTargetInfluences
属性值改变,人的胖瘦自然跟着改变。
var loader = new THREE.JSONLoader(); //创建加载器
loader.load("./人/umich_ucs.json", function(geometry, materials) {
// 通过平均面法线来计算顶点法线,效果更光滑
geometry.computeVertexNormals();
var mesh = new THREE.Mesh(geometry, materials[0]);
// 材质对象开启渲染目标
mesh.material.morphTargets = true
mesh.rotateX(-Math.PI / 2);
mesh.position.y = -50;
scene.add(mesh); //插入到场景中
//实例化vue
vm = new Vue({
el: "#app",
data: {
time: 0,
},
watch: {
time: function(value) {
mesh.morphTargetInfluences[0] = value; // 变胖
// mesh.morphTargetInfluences[4] = value; // 变瘦
}
},
})
})
通过混合器AnimationMixer获取模型中的变形动画关键帧数据然后进行播放。
var loader = new THREE.JSONLoader(); //创建加载器
var mixer = null; //声明一个混合器变量
loader.load("./鸟/flamingo.json", function(geometry) {
// console.log(geometry);
var material = new THREE.MeshPhongMaterial({
morphTargets: true,
vertexColors: THREE.FaceColors,
});
// 通过平均面法线来计算顶点法线,效果更光滑
geometry.computeVertexNormals();
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh); //插入到场景中
// 创建一个混合器,播放网格模型模型的变形动画
mixer = new THREE.AnimationMixer(mesh);
// geometry.animations[0]:获得剪辑对象clip
var AnimationAction=mixer.clipAction(geometry.animations[0]);
// AnimationAction.timeScale = 0.5; //默认1,可以调节播放速度
// AnimationAction.loop = THREE.LoopOnce; //不循环播放
// AnimationAction.clampWhenFinished=true;//暂停在最后一帧播放的状态
AnimationAction.play();//播放动画
})
在渲染函数中,通过时钟类Clock获得两次渲染的时间间隔,然后执行mixer.update();
传递给混合器AnimationMixer
。
// 创建一个时钟对象Clock
var clock = new THREE.Clock();
// 渲染函数
function render() {
renderer.render(scene, camera); //执行渲染操作
requestAnimationFrame(render); //请求再次执行渲染函数render,渲染下一帧
//clock.getDelta()方法获得两帧的时间间隔
// 更新混合器相关的时间
mixer.update(clock.getDelta());
}
render();