1、格式
关于3D模型有很多格式
2、常见的格式
- OBJ
- FBX
- STL
- COLLADA
- 3DS
- GLTF
3、GLTF
glTF(gl传输格式)是一种开放格式的规范 (open format specification), 用于更高效地传输、加载3D内容。该类文件以JSON(.gltf)格式或二进制(.glb)格式提供, 外部文件存储贴图(.jpg、.png)和额外的二进制数据(.bin)。一个glTF组件可传输一个或多个场景, 包括网格、材质、贴图、蒙皮、骨架、变形目标、动画、灯光以及摄像机。
- GL Transmission Format
- 由Khronos Group团队创造
- 这几年变得特别流行
- 支持不同的数据集,像geometries,materials,cameras,lights...
- 支持多种导出格式像json,binary,embed textures
- 逐渐成为标准,很多3D软件,3D引擎,3D库都支持该格式。
不应该在任何场景为了使用GLTF格式而使用GLTF格式,比如你需要粒子效果时,没必要使用GLTF。
4、哪里可以找到模型
这里贴出一个仓库,里面有许多模型可供我们学习
5、GLTF Format
一个 GLTF 文件可以包含多个格式.
- glTF
- glTF-Binary
- glTF-Draco
- glTF-Embedded
请注意,你的操作系统可能隐藏某些格式,尽量使用编辑器打开。
5.1 GLTF
├── Duck/ # Duck模型 │ ├── glTF/ │ │ ├── Duck.gltf # JSON格式的文件 │ │ └── Duck0.bin # 二进制格式的文件 │ │ └── DuckCM.png # 纹理 复制代码
- 默认格式
- 包含多个文件
- Duck.gltf是一个JSON格式的文件,包含了cameras, lights, scenes, materials, objects transformstions, 但是不包含geometries和textures。
- Duck0.bin是一个二进制文件,包含geometries(vertices positions, UV coordinates, normals, colors, etc.)
- DuckCM.png是纹理
我们加载Duck.gltf时,其他文件会自动加载。
5.2 GLTF-BINARY
├── Duck/ # Duck模型 │ ├── glTF-Binary/ │ │ ├── Duck.glb # 二进制格式的文件 复制代码
- 只有一个文件
- 包含上面我们讨论的所有数据
- 二进制格式
- 通常更轻量
- 因为只有一个文件所以容易加载
- 很难改变其中的数据
5.3 GLTF-DRACO
├── Duck/ # Duck模型 │ ├── glTF-Draco/ │ │ ├── 0.bin │ │ └── Duck.bin │ │ └── Duck.gltf │ │ └── DuckCM.png 复制代码
- 像gltf格式,但是其中的数据经过Draco算法压缩处理
- 更轻量
5.4 GLTF-Embedded
├── Duck/ # Duck模型 │ ├── glTF-Embedded/ │ │ ├── Duck.gltf # 二进制格式的文件 复制代码
- 只有一个文件
- JSON格式
- 更重
6、在Three.js中加载模型
6.1 导入GLTFLoader
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js"; 复制代码
6.2 初始化loader
const gltfLoader = new GLTFLoader() 复制代码
6.3 使用loader
gltfLoader.load( "/models/Duck/glTF/Duck.gltf", (gltf) => { console.log("success"); console.log(gltf); }, () => { console.log("progress"); }, () => { console.log("error"); } ); 复制代码
6.4 在场景中添加模型
模型在哪?
- 这里的Mesh就是我们的模型
- 我们不需要PerspectiveCamera
- camera和duck继承自Object3D
- Object3D被缩放(scale)地很小
多种方法将模型添加到场景中
- Add the whole scene in our scene
- Add the children of the scene to our scene and ignore the PerspectiveCamera
- Filter the children before adding to the scene
- Add only the Mesh and end up with a duck with wrong scale , position and rotation
- Open the file in a 3D software, clean it and export it again
const gltfLoader = new GLTFLoader(); gltfLoader.load( "/models/Duck/glTF/Duck.gltf", (gltf) => { console.log("success"); scene.add(gltf.scene.children[0]); } ); 复制代码
导入其它格式的模型(glTF-Draco不生效)
gltfLoader.load( "/models/Duck/glTF-Binary/Duck.glb", // glTF-Binary gltfLoader.load( "/models/Duck/glTF-Embedded/Duck.gltf", // glTF-Embedded 复制代码
添加一个稍微复杂的模型(飞行头盔)
如果以上面的方式导入模型,我们只会得到模型的一部分, 我们尝试循环它们,并将它们添加到场景中
for (const child of gltf.scene.children) { scene.add(child); } 复制代码
由于我们在循环过程中,从场景1中的一部分移动的场景2中,场景1中的模型就会减少,这样就会导致我们的循环出现问题。
- 尝试使用while
while (gltf.scene.children.length) { scene.add(gltf.scene.children[0]); } 复制代码
- 使用 扩展运算符 ...
const children = [...gltf.scene.children]; for (const child of children) { scene.add(child); } 复制代码
- 更简单的方式就是直接将模型中的scene添加到我们的场景中
scene.add(gltf.scene); 复制代码
6.5 Draco Compression(Draco压缩)
Draco Compression can be usualy helpful.
- Draco 压缩这种格式会更轻量
- Draco压缩会针对于Buffer 数据
- 我们可以在其他格式中使用Draco压缩,并非只用GLTF格式的模型
- 由Google开源的
如何将Draco压缩过后的模型导入到我们的场景中呢?
使用DracoLoader
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js"; const dracoLoader = new DRACOLoader(); 复制代码
在Web Assembly中使用会更快,Three.js 提供了相应的文件夹在 /node_modules/three/examples/js/libs文件夹下的draco文件夹 将该文件夹移动的static文件夹下
dracoLoader.setDecoderPath("/draco/"); 复制代码
gltfLoader.setDRACOLoader(dracoLoader); 复制代码
这样我们也可以使用glTF-Loader文件导入模型啦,它更轻量!!
6.6 什么时候使用Draco 压缩格式
不应该什么时候都用,因为还需要加载DRACOLoader类以及Decoder。
如果模型很大,建议使用Draco格式,取决于你加载的模型大小,可以通过网站加载体验选择,做出正确的选择。
6.7 在场景中添加动画模型
gltfLoader.load("/models/Fox/glTF/Fox.gltf", 复制代码
直接导入不做处理,它会很大,我们需要缩放一下
gltfLoader.load("/models/Fox/glTF/Fox.gltf", (gltf) => { gltf.scene.scale.set(0.025, 0.025, 0.025); scene.add(gltf.scene); console.log("success"); }); 复制代码
接下来就是处理模型的动画了
我们导入的gltf对象包含了一个animations 属性,它是AnimationClip的实例。
我们需要创建AnimationMixer,它就像音乐播放器一样,帮助我们播放动画。
const mixer = new THREE.AnimationMixer(gltf.scene); 复制代码
使用clipAction方法将AnimationClips添加到mixer中
const action = mixer.clipAction(gltf.animations[0]); action.play() 复制代码
处理完了,为什么还是没有动画呢,最重要的一步还不做,那就是在每一帧中更新mixer。 这里出现了作用域的问题,需要处理一下
let mixer = null; gltfLoader.load("/models/Fox/glTF/Fox.gltf", (gltf) => { mixer = new THREE.AnimationMixer(gltf.scene); const action = mixer.clipAction(gltf.animations[0]); action.play(); gltf.scene.scale.set(0.025, 0.025, 0.025); scene.add(gltf.scene); console.log("success"); }); 复制代码
const tick = () => { const elapsedTime = clock.getElapsedTime(); const deltaTime = elapsedTime - previousTime; previousTime = elapsedTime; // Update mixer if (mixer) { mixer.update(deltaTime); } // Update controls controls.update(); // Render renderer.render(scene, camera); // Call tick again on the next frame window.requestAnimationFrame(tick); }; tick(); 复制代码
看,完美,我们成功导入了动画模型!
6.8 使用Three.js editor
Three.js 提供了一个可视化在线编辑器-Three.js editor,在其中你可以调整场景,灯光,材质等,因此我们可以先在该平台调试,感觉合适了之后再编码。
最后
看,我们成功的导入了3D模型,并且它们还带有动画,还是蛮酷的勒!
⚾如果你对本专栏感兴趣欢迎点赞关注+收藏,后面会持续更新,更多精彩知识正在等你!😘
🏉此外笔者还有其他专栏,欢迎阅读~