three.js 示例学习 | 05-加载glTF 模型

2,728 阅读3分钟

前言

本篇是使用three.js 提供的加载器加载 glTF 模型展示,并进行动作控制。直接使用three.js编程建模比较麻烦,实际开发时的模型会借助一些3D建模工具进行建模,如Blender、C4D、3Dmax。导出的文件再加载到three.js 场景中展示。

实现

添加基本代码

import * as THREE from 'three';

let camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight,1, 10000);
camera.position.y = 300;

let scene = new THREE.Scene();
scene.background = new THREE.Color( 0xf0f0f0 );

let renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio( window.devicePixelRatio );
renderer.outputEncoding = THREE.sRGBEncoding;
document.body.appendChild(renderer.domElement);

const light1 = new THREE.DirectionalLight( 0xefefff, 1.5 );
light1.position.set( 1, 1, 1 ).normalize();
scene.add( light1 );

const light2 = new THREE.DirectionalLight( 0xFFFFFF, 1.5 );
light2.position.set( - 1, - 1, - 1 ).normalize();
scene.add( light2 );

基本结构和灯光。

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';

const loader = new GLTFLoader();
let mixer: THREE.AnimationMixer;
loader.load( 'models/Horse.glb', function ( gltf ) {

  mesh = gltf.scene.children[ 0 ];
  mesh.scale.set( 1.5, 1.5, 1.5 );
  scene.add( mesh );
  mixer = new THREE.AnimationMixer( mesh );
  mixer.clipAction( gltf.animations[ 0 ] ).setDuration( 1 ).play();

} );

GLTFLoader 是用于 glTF 2.0 资源的加载器。该类文件以JSON(.gltf)格式或二进制(.glb)格式提供数据。一个 glTF 文件可以包含一个或多个场景。包括网格、材质、贴图、动画等等。

AnimationMixer 动画混合器。用于控制场景内对象动画运动。

将 glTF 上的动画(animations) 使用clipAction() 方法生成一个可调用的动画对象(AnimationAction),setDuration 方法为设置单次循环的时间,play() 即播放。

加载的 glTF 模型文件的数据结构如下

1659425432190.jpg

function animate() {
  requestAnimationFrame( animate );
  render();
}
let prevTime = Date.now();
const radius = 600;
let theta = 0;
function render() {
  theta += 0.1;
  camera.position.x = radius * Math.sin( THREE.MathUtils.degToRad( theta ) );
  camera.position.z = radius * Math.cos( THREE.MathUtils.degToRad( theta ) );
  
  camera.lookAt( 0, 150, 0 );
  if ( mixer ) {
    const time = Date.now();
    mixer.update( ( time - prevTime ) * 0.001 );
    prevTime = time;
  }
  
  renderer.render( scene, camera );

}
animate();

添加旋转动画,camera 在X-Z面上以radius = 600 进行旋转,mixer.update 推进混合器时间并更新动画,这个传入的时间大小会影响动画的播放速率。

hurse.gif

添加与模型交互

官网示例没有添加控制器,没法交互,我们修改一下代码,变得可以通过键盘控制模型马的奔跑。

let animation;
loader.load('models/Horse.glb',(model) => {
    ......
    //mixer.clipAction( gltf.animations[ 0 ] ).setDuration( 1 ).play();
    animation = mixer.clipAction(  gltf.animations[0] );
});

将动画混合器得到的动画调度存到变量中。

const consorl = new OrbitControls(camera, renderer.domElement);

// EVENTS
document.addEventListener( 'keydown', onKeyDown );
document.addEventListener( 'keyup', onKeyUp );
let walk = false;
function onKeyDown(e) {
    if (e.code === 'KeyW') {
        animation.play();
        walk = true;
    }
}

function onKeyUp(e) {
    if (e.code === 'KeyW') {
        walk = false;
    }
}

添加轨道控制器和事件监听。

function animate() {
  ......
  // 修改mixer 执行条件
  if ( mixer && walk) {
        const time = Date.now();
        mixer.update( ( time - prevTime ) * 0.001);
        prevTime = time;
    } else if (mixer) {
        mixer.stopAllAction();
    }
}

修改动画混合器的执行条件。这样就可以通过按键 W 来控制模型奔跑的动作。

hurse1.gif

关于glTF 模型

glTF 是一个非常全面的格式,几乎支持所有的常见功能,支持颜色、动画、CSG、细节网格工作、纹理、相机、光线、相对定位等重要功能。

借用 juejin.cn/post/701692… 一张表格来描述glTF 格式的模型在3D 模型格式中的优点:

1d7b595d026949d5b20e5f2b403dfba2_tplv-k3u1fbpfcp-zoom-in-crop-mark_3024_0_0_0.jpg

  • glTF的目标是作为一个中转格式,而不是另一个新的3D数据格式.
  • 使用JSON来描述场景结构,可以方便地被应用程序分析处理。
  • glTF导出格式有两种后缀格式:.gltf 和 .glb。 .gltf 格式为JSON 数据储存,.glb 是压缩为二进制文件进行储存,占比空间会更小。

结语

通过本篇示例我们可以了解到three.js 是如何加载glTF 模型,将模型展示在3D场景中并通过交互播放模型中的动画。

参考官网示例:threejs.org/examples/#w…

本篇以上代码也已放到了github上:github.com/wenxuan12/3… ,可供做印证参考。