解析外部模型变形动画目标数据

优质
小牛编辑
125浏览
2023-12-01

本节课给大家展示两个变形动画的案例,一个是鸟的飞行变形动画,一个是通过滚动条控制人体的变形案例。

加载查看模型变形动画数据

加载完三维模型后,通过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;

滚动条调节人胖瘦

下面代码中的滚动条<el-slider...></el-slider>是通过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();