目前,3D 模型的格式有成千上万种可供选择,但每一种格式都具有不同的目的、用途以及复杂性。 虽然 three.js 已经提供了多种导入工具, 但是选择正确的文件格式以及工作流程将可以节省很多时间,以及避免遭受很多挫折。某些格式难以使用,或者实时体验效率低下,或者目前尚未得到完全支持。
# ThreeJS 支持的模型格式
推荐使用 glTF(gl 传输格式)。.GLB 和.GLTF 是这种格式的这两种不同版本, 都可以被很好地支持。由于 glTF 这种格式是专注于在程序运行时呈现三维物体的,所以它的传输效率非常高,且加载速度非常快。 功能方面则包括了网格、材质、纹理、皮肤、骨骼、变形目标、动画、灯光和摄像机。
当 glTF 不可用的时候,诸如 FBX、OBJ 或者 COLLADA 等等其它广受欢迎的格式在 Three.js 中也是可以使用、并且定期维护的。
# glTF 加载器:GLTFLoader
GLTFLoader 用于载入 glTF 2.0 资源的加载器。
# glTF 简介
glTF(gl 传输格式)是一种开放格式的规范 (open format specification), 用于更高效地传输、加载 3D 内容。该类文件以 JSON(.gltf)格式或二进制(.glb)格式提供, 外部文件存储贴图(.jpg、.png)和额外的二进制数据(.bin)。一个 glTF 组件可传输一个或多个场景, 包括网格、材质、贴图、蒙皮、骨架、变形目标、动画、灯光以及摄像机。
# glTF 模型加载器
ThreeJS 内置了 GLTF 模型加载器,用于加载 GLTF 模型资源。
GLTFLoader uses ImageBitmapLoader whenever possible. Be advised that image bitmaps are not automatically GC-collected when they are no longer referenced, and they require special handling during the disposal process. More information in the How to dispose of objects guide.
# DRACOLoader 模型解压器
用于加载经过 Draco 压缩的图形库。
Draco 是一个开源的库,主要用于压缩和解压缩三维模型及点云。 以客户端上解压缩为代价,显著减少压缩的图形。
独立的 Draco 文件后缀为 .drc
,其中包含顶点坐标,法线,颜色和其他的属性, Draco 文件不包含材质,纹理,动画和节点结构 - 为了能使用这些特征,需要将 Draco 图形 嵌入到 GLTF 文件中。使用 glTF-Pipeline 可以将一个普通的 GLTF 文件转化为经过 Draco 压缩的 GLTF 文件。 当使用 Draco 压缩的 GLTF 模型时,GLTFLoader 内部会调用 DRACOLoader。
推荐创建一个 DRACOLoader 实例并重用,可以有效避免重复创建加载多个解压器实例。
# ThreeJS 加载 GLTF 模型
以下,使用 GLTFLoader 加载官网提供的模型数据,核心代码段如下,
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js"; //GLTF 加载器 | |
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js"; | |
//TODO: 添加光源 | |
const light = new THREE.PointLight(0xffffff, 1000, 1000); | |
light.position.set(15, 15, 15); | |
scene.add(light); | |
scene.background = new THREE.Color(0xbfe3dd); | |
//TODO: 加载模型 | |
const modelPath = "models/LittlestTokyo.glb"; | |
const gltfLoader = new GLTFLoader(); | |
const dracoLoader = new DRACOLoader(); | |
dracoLoader.setDecoderPath("draco/"); | |
gltfLoader.setDRACOLoader(dracoLoader); | |
gltfLoader.load(modelPath, function (gltfData) { | |
console.log("onload::", gltfData); | |
//TODO: 加载 glb 模型到场景中 | |
const model = gltfData.scene; | |
model.position.set(1, 1, 0); | |
model.scale.set(0.01, 0.01, 0.01); | |
scene.add(model); | |
}); |
# 模型动画:AnimationMixer
在上述案例中,注意到该模型数据携带有一个动画,那么如何在 Web3D 页面中播放这个动画呢?
# AnimationMixer 模型动画混合器
ThreeJS 提供了 AnimationMixer 模型动画混合器,是用于场景中特定对象的动画的播放器。当场景中的多个对象独立动画时,每个对象都可以使用同一个动画混合器。
通过 clipAction 方法,可以传入预定义的模型动画参数,并可以获取到一个 AnimationAction 实例。
# AnimationAction 动画调度器
AnimationAction 实例,用于调度存储在 AnimationClips 中的动画,通过调用其 play () 方法,可以主动唤起混合器激活动画。
# ThreeJS 播放模型动画
修改上述加载 GLTF 模型的代码如下,即可播放模型动画,
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js"; //GLTF 加载器 | |
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js"; | |
//TODO: 创建时钟 | |
const clock = new THREE.Clock(); | |
//TODO: 添加光源 | |
const light = new THREE.PointLight(0xffffff, 1000, 1000); | |
light.position.set(15, 15, 15); | |
scene.add(light); | |
scene.background = new THREE.Color(0xbfe3dd); | |
//TODO: 声明动画混合器 | |
let mixer = null; | |
//TODO: 加载模型 | |
const modelPath = "models/LittlestTokyo.glb"; | |
const gltfLoader = new GLTFLoader(); | |
const dracoLoader = new DRACOLoader(); | |
dracoLoader.setDecoderPath("draco/"); | |
gltfLoader.setDRACOLoader(dracoLoader); | |
gltfLoader.load(modelPath, function (gltfData) { | |
console.log("onload::", gltfData); | |
//TODO: 加载 glb 模型到场景中 | |
const model = gltfData.scene; | |
model.position.set(1, 1, 0); | |
model.scale.set(0.01, 0.01, 0.01); | |
scene.add(model); | |
//TODO: 激活动画 | |
mixer = new THREE.AnimationMixer( model ); | |
mixer.clipAction( gltfData.animations[ 0 ] ).play(); | |
animate() | |
}); | |
//TODO: 修改 animate 渲染函数逻辑如下 | |
//TODO: 渲染函数 | |
function animate() { | |
requestAnimationFrame(animate); | |
//TODO: 更新轨道控制器 | |
orbitControls.update(); | |
//TODO: 更新模型动画 | |
if(mixer){ | |
const delta = clock.getDelta(); | |
mixer.update(delta); | |
} | |
//TODO: 渲染 | |
renderer.render(scene, camera); | |
} |