Skip to content

26. GLTF 的三种文件结构

Published:

上节我们加载了一个 gltf 的模型,并用 Three.js 渲染了出来:

image.png

当时用了一个 .gltf 文件还有一个 .bin 文件:

image.png

其实 gltf 模型文件一共有三种形式:

gltf 官方有个案例模型的仓库,我们可以去那看一下:

image.png

里面有很多 gltf 模型。

比如这个灯笼

image.png

它就提供了 .glb 的模型,以及 .gltf + .bin + .png 的模型。

比如这个 CesiumMan 的模型

image.png

提供了三种形式的文件:

image.png

.glb 和 .gltf + .bin + .jpg 或者 .gltf

我们用 Three.js 加载试一下:

npx create-vite gltf-structure

image.png

进入项目,安装依赖:

npm install
npm install --save three
npm install --save-dev @types/three

改下 src/main.js

import './style.css';
import * as THREE from 'three';
import {
    OrbitControls
} from 'three/addons/controls/OrbitControls.js';
import mesh from './mesh.js';

const scene = new THREE.Scene();

scene.add(mesh);

const directionLight = new THREE.DirectionalLight(0xffffff);
directionLight.position.set(100, 100, 100);
scene.add(directionLight);

const helper = new THREE.AxesHelper(100);
scene.add(helper);

const width = window.innerWidth;
const height = window.innerHeight;

const camera = new THREE.PerspectiveCamera(60, width / height, 0.1, 10000);
camera.position.set(100, 100, 100);
camera.lookAt(0, 0, 0);

const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height)

function render() {
    renderer.render(scene, camera);
    requestAnimationFrame(render);
}

render();

document.body.append(renderer.domElement);

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

创建 Scene、Light、Camera、Renderer。

改下 style.css

body {
  margin: 0;
}

把刚才那个模型下载下来(点右边的按钮下载):

image.png

下载这三个:

image.png

分别放到 public/gltf1、public/gltf2、public/gltf3 目录下:

image.png

然后创建 src/mesh.js

import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

const loader = new GLTFLoader();

const mesh = new THREE.Group();

loader.load("./gltf1/CesiumMan.gltf", function (gltf) {
    console.log(gltf);
    mesh.add(gltf.scene);
})

export default mesh;

用 GLTFLoader 把 gltf 模型加载进来。

跑下试试:

npm run dev

image.png

2025-04-05 16.29.24.gif

加载出来了,就是太小了,我们放大下:

image.png

gltf.scene.scale.set(50, 50, 50);

image.png

遍历下看看有几个 mesh:

image.png

gltf.scene.traverse(obj => {
    if(obj.isMesh) {
        console.log(obj.name, obj);
    }
})

image.png

只有一个,我们设置展示线框:

image.png

obj.material.wireframe = true;
obj.material.color.set('orange');

image.png

把颜色贴图去掉:

image.png

obj.material.map = null;

image.png

然后再加载另外两种格式的模型试试:

image.png

loader.load("./gltf2/CesiumMan.gltf", function (gltf) {
    mesh.add(gltf.scene);

    gltf.scene.scale.set(50, 50, 50);
    gltf.scene.translateX(-50);

    gltf.scene.traverse(obj => {
        if(obj.isMesh) {
            obj.material.wireframe = true;
            obj.material.color.set('lightblue');
            obj.material.map = null;
        }
    })
});

loader.load("./gltf3/CesiumMan.glb", function (gltf) {
    mesh.add(gltf.scene);

    gltf.scene.scale.set(50, 50, 50);
    gltf.scene.translateX(50);

    gltf.scene.traverse(obj => {
        if(obj.isMesh) {
            obj.material.wireframe = true;
            obj.material.color.set('lightgreen');
            obj.material.map = null;
        }
    })
});

image.png

也就是说,虽然存储的形式不一样,加载之后都是一样的。

那这三种文件形式都存了啥呢?

看一下就知道了:

全内联在 gltf 文件内是这样的:

2025-04-05 16.49.41.gif

可以看到二进制信息是以 base64 的方式写在文件里的。

这会导致文件特别大。

而 gltf + bin 是这样的:

image.png

.bin 存的是顶点信息。

再看下图片:

.gltf + .bin + .jpg 是这样的:

image.png

而 .gltf 内联是这样:

image.png

也就是说,虽然存储的都是纹理图片、顶点等信息,但一种是以文件形式单独存储,另一种则是全部 base64 内联。

而 .glb 也是全部内联,但它是二进制的,所以更小一点:

image.png

可以看到,同样是内联,.glb 小了 200k:

image.png

image.png

所以,.glb 或者 .gltf +.bin + .jpg 都是比较好的,而内联的 .gltf 在特定情况下也会用到。

案例代码上传了小册仓库

总结

这节我们学习了 .gltf 模型的三种形式:

后两种是用的最多的。

不管存储结构如何,GLTFLoader 加载进来之后都是一样的网格模型,没有区别。

评论