以gLTF格式加载3D模型
此笔记记录于DISCOVER three.js,大多数为其中的摘要,少数为笔者自己的理解
基本介绍
在过去三十年左右的时间里, 人们在创建标准3D资源交换格式方面进行了许多尝试。直到最近, FBX、 OBJ (Wavefront)和 DAE (Collada)格式仍然是其中最受欢迎的格式,尽管它们都存在阻碍其广泛采用的问题。比如OBJ不支持动画,FBX是属于Autodesk的封闭格式,Collada规范过于复杂,导致大文件难以加载。
然而,最近,一个名为glTF的新成员已成为在网络上交换3D资源的事实上的标准格式。 glTF(GL传输格式),有时被称为 3D中的JPEG,由 Kronos Group创建,他们负责WebGL、OpenGL和一大堆其他图形API。glTF最初于2017年发布,现在是在网络和许多其他领域交换3D资源的最佳格式。在本书中,我们将始终使用glTF,如果可能,您也应该这样做。它专为在网络上共享模型而设计,因此文件大小尽可能小,并且您的模型将快速加载。
但是,由于glTF相对较新,您最喜欢的应用程序可能还没有导出器。在这种情况下,您可以在使用模型之前将它们转换为glTF,或者使用其他加载器,例如FBXLoaderor
或者OBJLoader
。所有three.js加载器的工作方式相同,因此如果您确实需要使用另一个加载器,本章中的所有内容仍然适用,只有细微差别。
glTF文件以标准和二进制形式出现。这些有不同的扩展名:
- 标准 .gltf 文件未压缩,可能附带一个额外的 .bin 数据文件。
- 二进制 .glb 文件将所有数据包含在一个文件中。
标准和二进制glTF文件都可能包含嵌入在文件中的纹理或可能引用外部纹理。由于二进制 .glb 文件要小得多,因此最好使用这种类型。另一方面,未压缩的 .gltf 在文本编辑器中很容易阅读,因此它们可能对调试有用。
目录
birds.js
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { setupModel } from './setupModel.js';
async function loadBirds() {
const loader = new GLTFLoader();
const [parrotData, flamingoData, storkData] = await Promise.all([
loader.loadAsync('/assets/models/Parrot.glb'),
loader.loadAsync('/assets/models/Flamingo.glb'),
loader.loadAsync('/assets/models/Stork.glb'),
]);
console.log('Squaaawk!', parrotData);
const parrot = setupModel(parrotData);
parrot.position.set(0, 0, 2.5);
const flamingo = setupModel(flamingoData);
flamingo.position.set(7.5, 0, -10);
const stork = setupModel(storkData);
stork.position.set(0, -2.5, -10);
return {
parrot,
flamingo,
stork,
};
}
export { loadBirds };
setupModel.js
function setupModel(data) {
const model = data.scene.children[0];
return model;
}
export { setupModel };
World.js
import { loadBirds } from './components/birds/birds.js';
import { createCamera } from './components/camera.js';
import { createLights } from './components/lights.js';
import { createScene } from './components/scene.js';
import { createControls } from './systems/controls.js';
import { createRenderer } from './systems/renderer.js';
import { Resizer } from './systems/Resizer.js';
import { Loop } from './systems/Loop.js';
let camera;
let controls;
let renderer;
let scene;
let loop;
class World {
constructor(container) {
camera = createCamera();
renderer = createRenderer();
scene = createScene();
loop = new Loop(camera, scene, renderer);
container.append(renderer.domElement);
controls = createControls(camera, renderer.domElement);
const { ambientLight, mainLight } = createLights();
loop.updatables.push(controls);
scene.add(ambientLight, mainLight);
const resizer = new Resizer(container, camera, renderer);
}
async init() {
const { parrot, flamingo, stork } = await loadBirds();
// move the target to the center of the front bird
controls.target.copy(parrot.position);
scene.add(parrot, flamingo, stork);
}
render() {
renderer.render(scene, camera);
}
start() {
loop.start();
}
stop() {
loop.stop();
}
}
export { World };
GLTFLoader返回的数据
{
animations: [AnimationClip]
asset: {generator: "Khronos Blender glTF 2.0 I/O", version: "2.0"}
cameras: []
parser: GLTFParser {json: {…}, extensions: {…}, options: {…}, cache: {…}, primitiveCache: {…}, …}
scene: Scene {uuid: "1CF93318-696B-4411-B672-4C12C46DF7E1", name: "Scene", type: "Scene", parent: null, children: Array(0), …}
scenes: [Scene]
userData: {}
**proto**: Object
}
gltfData.animations
是一个动画剪辑数组。在这里,有一个飞行动画。我们将在 下一章中使用它。gltfData.assets
包含显示此glTF文件的元数据 — 使用 Blender导出器创建。gltfData.cameras
是一组相机。该文件不包含任何摄像机,因此数组为空。gltfData.parser
包含关于GLTFLoader
的技术细节。gltfData.scene
是一个包含文件中的任何网格的Group
。这是我们将找到鹦鹉模型的地方。gltfData.scenes
: glTF格式支持将多个场景存储在一个文件中。在实践中,很少使用此功能。gltfData.userData
可能包含额外的非标准数据。
_ __proto__
是每个JavaScript对象都有的标准属性,你可以忽略它。_
通常,您只需要**.animations
、.cameras
和.scene
**(而不是.scenes
!),您可以放心地忽略其他所有内容。