Skip to content

如何为 Web 优化 GLB 文件:Draco、Meshopt 与 KTX2(2026) ​

最后更新:2026 年 9 月。

一个巨大的宝箱通过管道缩小成迷你版本

为 Web 优化 GLB 时,请按以下顺序处理:首先缩小纹理(将尺寸限制在 1024 或 2048;若要减小下载体积,则重新编码为 WebP;若要节省 GPU 显存,则使用 KTX2),量化顶点数据,使用 Meshopt 压缩几何体(如果最后几百 KB 比解码时间更重要,则使用 Draco),如果三角形数量仍然高得离谱,再简化网格,最后对剩余内容执行清理、去重和合并。一个命令就能完成其中大部分工作:gltf-transform optimize in.glb out.glb --texture-compress webp。顺序很重要,因为纹理通常占文件体积的 80% 或更多,也占用了几乎全部显存。

快速解答 ​

  • **纹理占比较高的模型(大多数模型):**先将尺寸缩小到 1024 或 2048,再运行 gltf-transform webp。如果模型在手机上卡顿或崩溃,请改为转换成 KTX2,可在浏览器中使用 KTX2 压缩工具,或使用 gltf-transform etc1s/uastc。
  • **几何体占比较高的模型(扫描、CAD、AI 生成模型):**先运行 gltf-transform simplify,再运行 meshopt。Draco 能把体积压得更小一些,但解码速度较慢,并且需要体积大十倍的解码器。
  • **动画角色:**使用 Meshopt,不要使用 Draco。Draco 不会处理动画轨道和变形目标。
  • **文件必须能在你无法控制的引擎中打开:**使用 gltf-transform quantize。它不需要解码器,只使用 KHR_mesh_quantization,此处列出的所有加载器都能读取该扩展。
  • 不使用终端:GLB 优化工具可直接在浏览器中执行清理、焊接、合并、简化、将纹理缩放并转换为 WebP,以及 Meshopt 压缩,并显示每个步骤处理后的文件大小。

快速参考 ​

仅量化MeshoptDraco
扩展KHR_mesh_quantizationEXT_meshopt_compression(+ 量化)KHR_draco_mesh_compression
压缩内容顶点属性(减少位数)顶点、索引、变形目标、动画仅三角形网格几何体
28 MB 测试模型的大小22.8 MB(gzip 后 8.1 MB)5.1 MB(gzip 后 3.3 MB)2.6 MB(gzip 后 2.5 MB)
解码器无32 KB JS 模块,内嵌 WASM192 至 286 KB WASM,外加 58 KB 封装代码;JS 回退方案为 719 KB
解码速度即时,GPU 可直接读取根据规范,使用 WASM SIMD 时约为 1 GB/s根据 glTF-Transform 文档,明显慢于 Meshopt
服务器是否需要 gzip/brotli帮助很大需要,其设计就依赖这类压缩收益很小
加载器three.js、Babylon.js、PlayCanvas、glTFastthree.js r122+、Babylon.js 5.0+、glTFast(需额外软件包),不支持 PlayCanvasthree.js、Babylon.js、PlayCanvas、glTFast(需额外软件包)

下面以条形图展示相同的数据,并同时列出对比测试中的 gltfpack 和简化结果。

同一个模型,各种编解码器28.7 MB 的 TRELLIS.2 输出,978,226 个三角形。使用 gltf-transform 4.5.0 和 gltfpack 1.2。原始文件gzip 后原始文件float32 几何体,1.1 MB 纹理28.7 MB量化KHR_mesh_quantization,无需解码器22.8 MB8.1 MBmeshopt --level highEXT_meshopt_compression5.1 MB3.3 MBgltfpack -ccMeshopt,更高压缩率模式4.4 MB3.1 MBdracoKHR_draco_mesh_compression2.6 MB2.5 MBsimplify --ratio 0.25244,556 个三角形8.1 MB压缩前,因此仍可应用上面的任一种编解码器使用 optimize 默认值(ratio 0、error 0.0001)后,同一文件降至 6,582 个三角形。
Draco 在字节数上胜出,但 gzip 几乎无法进一步缩小它;Meshopt 和量化输出则依赖服务器压缩。简化是唯一会改变三角形数量的步骤,因此其 8.1 MB 是新的起点,而非终点。

GLB 中的字节都用在了哪里 ​

在执行其他任何操作之前,先运行 gltf-transform inspect model.glb。它会列出每个网格及其顶点数量和属性类型、每张纹理及其编码后大小和 gpuSize,以及每段动画及其关键帧数量。本指南中的数据来自工具文档和扩展规范,以及我们本周使用 gltf-transform 4.5.0 和 gltfpack 1.2 对两个真实文件进行的对比测试。这些结果展示了你通常会遇到的两种情况。

一个 2.2 MB 的 Sketchfab 道具(低多边形杯子)包含 680 个三角形和 39 KB 几何体。其余 2.18 MB 来自三张 1024×1024 PNG,因此纹理占文件的 98%;inspect 估算,生成 mipmap 后,每张纹理会占用 5.59 MB 显存。这是手工制作资源的常见情况。

一个 28.7 MB 的 TRELLIS.2 输出则正好相反:它包含 978,226 个三角形和 27.5 MB 的 float32 几何体,而纹理仅有 1.1 MB。但这两张纹理的分辨率均为 4096×4096,inspect 显示每张纹理会占用 89.5 MB 显存。由 3D 模型生成器及同类工具生成的模型通常就是这样:网格过密、纹理分辨率过高,因此除了纹理优化,也需要执行几何体优化步骤。

字节都用在了哪里按内容划分的编码大小。右侧显示的 GPU 显存是另一项独立数据。纹理几何体其他所有内容(动画、JSON、蒙皮)典型手工制作资源纹理,占 80% 或更多其他所有内容典型构成2.2 MB Sketchfab 杯子,680 个三角形三张 1024x1024 PNG,2.18 MB(98%)几何体 39 KB5.59 MB 显存每张纹理,含 mipmap28.7 MB TRELLIS.2 输出,978,226 个三角形float32 几何体,27.5 MB纹理 1.1 MB,两张 4096x409689.5 MB 显存每张纹理,含 mipmap
“典型”一行是经验法则,另外两行则来自对比测试中的真实文件。请留意右侧一列:杯子的 1024 纹理与 TRELLIS.2 的 4096 纹理在磁盘上都很小,但占用的显存却相差悬殊。

请注意,纹理的编码大小与 GPU 占用大小并无关联。同一张 2048×2048 图像,无论是 4 MB PNG 还是 200 KB WebP,载入显存后都会占用约 22 MB,其中包括原始像素和 mipmap。只有 KTX2 能改变这个数字。

下面六个步骤按此顺序执行,因为每一步都会缩小下一步需要处理的数据量。

排查顺序先做收益最大的步骤。大小数据来自 28.7 MB 的测试模型。1纹理:限制为 1024 或 2048,再转为 WebP 或 KTX2通常占文件的 80% 以上,也占据几乎全部显存2量化28.7 MB 降至 22.8 MB(gzip 后 8.1 MB),无需解码器,所有加载器都能读取3Meshopt 或 Draco5.1 MB(gzip 后 3.3 MB)或 2.6 MB(gzip 后 2.5 MB),客户端需要解码器4简化以 0.25 的比例从 978,226 个三角形降至 244,556 个,游戏视距下看起来相同5清理、去重、合并、实例化零成本收益:移除未被引用的内容,将 200 次绘制调用缩减到寥寥几次6动画:重采样移除位于相邻关键帧连线上的关键帧,实际使用中无损
按数字从上到下操作。第 1 步和第 4 步能减少最多字节;除非是一个巨型的单一网格,否则第 2 步不会产生可见变化;对绑定了骨骼的角色执行第 5 步时需要谨慎,因为合并会融合本应活动的部件。

第 1 步:纹理 ​

两个不同的问题,需要两种不同的解决方式。

下载大小可以通过调整尺寸和重新编码来解决。很少有道具需要超过 1024×1024 的纹理,即使主角也很少需要超过 2048。gltf-transform resize --width 1024 --height 1024 会限制尺寸且绝不会放大,而 gltf-transform webp 会使用 sharp 重新编码。在杯子模型上,仅使用 WebP 就将文件从 2.23 MB 缩小到 246 KB。先将尺寸调整到 512 后,文件进一步缩小到 96 KB,对于这种大小的道具没有可见变化。WebP 需要 EXT_texture_webp,Web 引擎可以读取它,但 Unity 的 glTFast 不行(其功能表称它“不会得到支持”)。

GPU 显存占用和上传时间只能通过使用 Basis Universal 超级压缩的 KTX2 来解决。它能让纹理一直以 GPU 块格式存入显存,所需内存比原始 RGBA 少 4 到 8 倍。由于相关设置非常重要,下文会用单独一节介绍。

压力测试中有一点需要注意:gltf-transform optimize 默认使用 --texture-compress auto,它会以纹理的原始格式重新编码。在杯子模型上,这反而让 PNG 变大,文件从 2.2 MB 增长到 2.8 MB。请明确传入 webp 或 ktx2。

第 2 步:量化 ​

量化会用更少的位数存储每项顶点属性。位置数据会从三个 32 位浮点数变为三个 16 位整数,缩放和偏移会被整合到节点变换中(对于蒙皮网格,则整合到 inverseBindMatrices 中)。KHR_mesh_quantization 规范指出,典型顶点的数据量大约为 20 字节,而不是 48 字节。它是已经批准的 Khronos 扩展,不需要解码器:GPU 会直接读取整数属性,因此量化文件不仅能减少网络传输量,也能降低显存占用。

glTF-Transform 的默认设置是位置 14 位、法线和切线 10 位、UV 12 位、颜色和权重 8 位。gltfpack 则分别为 14、8、12 和 8 位。除非是一个巨型的单一网格,否则两者都不会带来可见变化;对于巨型网格,在整个范围内使用 14 位精度可能会出现棱面。单独使用量化的收益有限:我们的 28 MB 模型降至原始 22.8 MB,gzip 后为 8.1 MB。它真正的作用是作为 Meshopt 的前半部分,以及在不确定目标加载器能力时提供安全的输出。Draco 会使用相同的默认设置在内部执行量化,因此不要在 draco 之前运行 quantize。

第 3 步:Meshopt 或 Draco ​

两者都是有损几何编解码器,会在上传 GPU 之前解码成普通缓冲区,因此都不会让模型渲染得更快。它们缩小的是下载体积。二者的区别在于压缩哪些内容、解码速度有多快,以及需要附带多大的解码器。

Meshopt(EXT_meshopt_compression)在 bufferView 层级工作,因此顶点属性、索引、变形目标增量和动画关键帧都会被压缩。它被设计为叠加在量化之上,并位于 gzip 或 brotli 之下:该编解码器让字节排列更规则,再由 CDN 的通用压缩器完成剩余工作。规范给出的解码速度在使用 WebAssembly SIMD 时约为 1 GB/s,而 three.js 解码器只是一个 32 KB 的模块。在测试模型上,使用默认的 --level high 后,原始大小为 5.1 MB,gzip 后为 3.3 MB。

Draco(KHR_draco_mesh_compression)只压缩三角形网格图元。动画、变形目标、点和线会原样保留。它的压缩力度更大,同一模型可缩小到 2.6 MB;由于输出已经非常紧凑,gzip 几乎没有帮助。代价是解码时间和解码器体积:glTF-Transform 的文档明确指出,Meshopt 的解码速度快得多;three.js 附带的 WASM 解码器为 286 KB(glTF 分支版本为 192 KB),另加一个 58 KB 的封装器,以及一个 719 KB 的 JavaScript 回退版本。Draco 还会重新排序,并且可能改变顶点数量。

因此:动画内容、带变形目标的内容、需要重点优化手机加载时间的内容,以及启用了 brotli 传输的内容,都应选择 Meshopt。当资源是静态网格、几何体占据主要体积,并且值得用更慢的首帧换取 20% 到 30% 的网络传输缩减时,选择 Draco。不确定?选 Meshopt。在同一文件上,gltfpack 的 -cc(更强压缩模式下的 Meshopt)结果为原始 4.4 MB,gzip 后 3.1 MB。

第 4 步:简化 ​

如果模型压缩后仍然很大,那就是三角形太多,而任何编解码器都无法解决这个问题。两个工具都使用 meshoptimizer 简化器,它接受目标比例和误差上限,并在先达到其中任一条件时停止。

gltf-transform simplify --ratio 0.25 --error 0.01 的目标是在偏差不超过网格半径 1% 的范围内,将顶点数降至 25%。在拥有 97.8 万个三角形的模型上,这会得到 244,556 个三角形,压缩前为 8.1 MB,在游戏视距下看起来完全相同。optimize 的默认值比你想象的更激进:--simplify-ratio 0 搭配 --simplify-error 0.0001,意思是“在 0.01% 的误差范围内尽可能多地移除”。在同一个过度细分的模型上,它将三角形数量锐减至 6,582 个,因为生成器在平面上浪费了将近一百万个三角形。简化前应先焊接(optimize 会这样做),因为分离的顶点会让简化器停在接缝处。

gltfpack 的 -si 0.25 表达的是同一概念,-se 0.01 是默认误差上限,-sa 会忽略质量直接达到目标比例,-slb 则锁定边界顶点,避免模块化网格之间出现裂缝。硬表面道具通常可以轻松承受 50% 的简化;扫描和 AI 生成的网格通常可以移除 90%;绑定了骨骼的角色则需要注意关节附近,因为折叠顶点也会折叠蒙皮权重。

第 5 步:清理、去重、合并、实例化 ​

这些都是零成本收益,optimize 会执行全部操作。prune 会移除未被任何内容引用的材质、纹理、访问器和节点,并将纯色纹理转换为材质参数。dedup 会合并导出器重复写入的相同访问器和纹理。flatten 会折叠层级结构,join 会合并共享同一材质的网格,正是它能将 200 次绘制调用缩减到寥寥几次。instance(从 5 个副本起)会将重复网格转换为 EXT_mesh_gpu_instancing,而 palette 会合并仅颜色不同的材质。

不要对绑定了骨骼的角色或游戏中需要分部件移动的内容执行 join 或 flatten,因为这些部件会消失并融入单个网格。gltfpack 提供的规避方式是 -kn(保留已命名节点)和 -km(保留已命名材质)。

第 6 步:动画 ​

导出器经常在每一帧上烘焙关键帧。gltf-transform resample 会移除位于相邻关键帧连线上的关键帧(默认容差为 1e-4),在实际使用中是无损的。gltfpack 的 -af 30 会以 30 Hz 对每条轨道进行重采样,并在 Meshopt 压缩之前,将位移量化为 16 位、旋转量化为 12 位、缩放量化为 16 位(-at、-ar、-as)。对于只有少量动画片段的典型角色,这一步的收益不大。但对于动作库,它可能节省大部分字节。

命令行 ​

glTF-Transform 的 CLI 安装命令为 npm install --global @gltf-transform/cli,也可以使用 npx @gltf-transform/cli。一条命令完成:

bash
gltf-transform optimize in.glb out.glb --texture-compress webp --texture-size 1024

它会依次执行去重、实例化、调色板合并、层级扁平化、网格合并、焊接、简化(比例 0,误差 0.0001)、重采样、清理、稀疏化、以 1024 为尺寸上限的纹理压缩,以及 high 级别的 Meshopt 压缩。添加 --compress draco 可使用 Draco,添加 --compress quantize 可仅执行量化;对于绑定了骨骼或带关节的模型,使用 --no-join --no-flatten;如果轮廓比文件大小更重要,则使用 --simplify false;如果已安装 KTX-Software,则使用 --texture-compress ktx2。

需要精细控制时,可以逐步执行:

bash
gltf-transform inspect in.glb
gltf-transform resize in.glb a.glb --width 1024 --height 1024
gltf-transform webp a.glb b.glb --quality 80
gltf-transform weld b.glb c.glb
gltf-transform simplify c.glb d.glb --ratio 0.5 --error 0.001
gltf-transform meshopt d.glb out.glb --level high

将最后一行替换为 gltf-transform draco d.glb out.glb(--encode-speed 和 --decode-speed 的取值范围是 0 到 10,默认为 5,数值越低文件越小),或者替换为 gltf-transform quantize d.glb out.glb。

gltfpack 可以通过 npm install -g gltfpack 安装,也可以从 meshoptimizer 的发布页面获取原生二进制文件;README 建议大文件使用后者。它的默认设置已经会执行量化、针对 GPU 缓存优化顶点顺序并合并网格:

bash
gltfpack -i in.glb -o out.glb -cc -si 0.5 -tw -tl 1024 -kn

-cc 是更高压缩模式下的 Meshopt(-c 是快速模式,-cf 会为不支持解码器的加载器添加未压缩回退数据)。-si 0.5 会在 -se 0.01 的误差范围内将三角形数量减半。-tw 将纹理转换为 WebP,-tl 1024 限制其尺寸。-kn 保留已命名节点。若要使用 KTX2,请将 -tw 替换为 -tc(ETC1S)或 -tc -tu(UASTC);这需要使用链接了 Basis Universal 的 gltfpack 构建版本。

如果两个 CLI 都无法使用,浏览器工具可以运行相同的处理流程。

GLB 优化器页面,显示一个 4.0 MB 的示例角色缩小到 676 KB,并列出每一步后的大小
无需终端的方式:在浏览器中执行清理、焊接、合并、简化、将纹理调整尺寸并转换为 WebP,以及 Meshopt 压缩;每一步之后都会显示大小,让你看出究竟是哪一步发挥了作用。

KTX2:ETC1S 还是 UASTC ​

KTX2 是 Khronos 的 GPU 纹理容器。使用 Basis Universal 超级压缩后,纹理会在加载时转码为设备支持的块格式(桌面端为 BC,移动端为 ASTC 或 ETC2),并在内存中保持压缩状态。对应的 glTF 扩展是 KHR_texture_basisu。 Basis 有两种模式。ETC1S 是体积较小的一种:Basis README 给出的磁盘占用约为每像素 0.3 到 3 位,并提供类似 JPEG 的质量调节参数(1 到 255,默认 128);转码为 BC1、ETC1 等格式后,内存占用为每像素 4 位。它适合用于道具的基础颜色纹理。UASTC 是偏重质量的一种:内存占用为每像素 8 位,是 ASTC 4×4 的 19 模式子集,质量级别为 0 到 4(默认 2,glTF-Transform 的帮助信息标示其质量为 47.47 dB)。UASTC 文件在磁盘上的体积较大,因此应搭配 Zstandard 使用:glTF-Transform 的 uastc 默认使用 --zstd 18,而 ktx create --zstd 接受 1 到 22 的值。

一张带有 Mipmap 的 2048×2048 纹理,其占用计算结果为:RGBA8 约 22 MB,UASTC 约 5.6 MB,ETC1S 转码为 4 bpp 格式后约 2.8 MB。

有三条重要规则。法线贴图和数据贴图应使用 UASTC 与线性色彩空间。 glTF-Transform 警告称,RGB 法线贴图以及遮蔽/粗糙度/金属度贴图使用 ETC1S 时可能效果不佳;规范还要求颜色纹理标记为 sRGB,非颜色数据标记为线性。glTF-Transform 会按纹理槽位自动设置。在 KTX2 压缩器中,这由 sRGB 开关控制:颜色纹理开启,法线贴图和数据贴图关闭。尺寸必须是 4 的倍数,并建议使用 2 的幂。生成 Mipmap。 规范指出,若 KTX2 使用带 Mipmap 的缩小过滤,就应包含完整的 Mipmap 金字塔,否则引擎必须在运行时解压并生成。glTF-Transform 和浏览器工具默认启用 Mipmap,而 ktx create 使用 --generate-mipmap。

glTF-Transform 命令需要 KTX-Software 4.4.0 或更高版本提供的 ktx 二进制文件:

bash
gltf-transform uastc in.glb a.glb --level 2 --zstd 18 --slots "{normalTexture,occlusionTexture,metallicRoughnessTexture}"
gltf-transform etc1s a.glb out.glb --quality 128

先对数据纹理槽使用 UASTC,再对其余纹理使用 ETC1S。通常的组合就是:基础颜色和自发光纹理使用 ETC1S,法线贴图和 ORM 贴图使用 UASTC。

加载处理结果 ​

除量化外,每种编解码方式都需要在客户端提供解码器。

three.js。 GLTFLoader 无需任何设置即可读取 KHR_mesh_quantization 和 EXT_texture_webp。其他格式则需要挂载解码器;这些解码器随 three 包提供,位于 examples/jsm/libs/ 下的 draco/、basis/ 和 meshopt_decoder.module.js。将 draco/ 和 basis/ 复制到公共路径,然后:

js
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js'
import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js'
import { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js'

const draco = new DRACOLoader().setDecoderPath('/libs/draco/')
const ktx2 = new KTX2Loader().setTranscoderPath('/libs/basis/').detectSupport(renderer)
const loader = new GLTFLoader()
  .setDRACOLoader(draco)
  .setKTX2Loader(ktx2)
  .setMeshoptDecoder(MeshoptDecoder)

浏览器支持时,DRACOLoader 会选用 WASM 解码器,否则回退到 JS。detectSupport(renderer) 使 KTX2Loader 能够根据设备的 GPU 选择转码目标格式。

Babylon.js。 glTF 加载器支持 Draco、Meshopt(自 5.0 起支持,无需设置)和 KTX2,它会从 https://cdn.babylonjs.com 下载解码器,并在 Web Worker 中运行。若要自行托管,可设置 Tools.CDNBaseUrl,也可以分别指定各项配置:DracoDecoder.DefaultConfiguration(wasmUrl、wasmBinaryUrl、fallbackUrl)、MeshoptCompression.Configuration.decoder.url,以及用于 KTX2 转码器集合的 KhronosTextureContainer2.URLConfig。使用 npm 时,@babylonjs/ktx2decoder 已包含这些转码器。

PlayCanvas。 Draco 通过 dracoInitialize({ jsUrl, wasmUrl, numWorkers, lazyInit }) 配置,编辑器也能在导入时进行 Draco 压缩。KTX2 通过 basisInitialize({ glueUrl, wasmUrl, fallbackUrl }) 配置。截至引擎 2.x,GLB 解析器仍不支持 EXT_meshopt_compression(2020 年提交的功能请求依然未关闭),因此面向 PlayCanvas 时,应选择 Draco 或仅量化的输出。

Unity。 官方导入器是 glTFast(com.unity.cloud.gltfast)。KHR_mesh_quantization 开箱即用;Draco 需要 com.unity.cloud.draco,KTX2 需要 com.unity.cloud.ktx,Meshopt 需要 com.unity.meshopt.decompress。WebP 按设计不受支持,因此面向 Unity 时应使用 KTX2。

移动端网页游戏的目标指标 ​

这方面没有正式规范,但有一些能让手机稳定运行的参考数字。首个场景的网络传输总量应控制在约 10 MB 以内,其余内容采用流式加载(资源流式加载教程介绍了分级方案和相关代码)。纹理显存占用应控制在 150 到 200 MB 以内,相当于四到五张 RGBA8 格式的 2048 纹理,或约三十张 ETC1S 纹理。道具应控制在 5,000 个三角形以内,主角角色控制在 30,000 到 50,000 个三角形以内,绘制调用维持在较低的数百次范围。道具使用 1024 纹理,只有相机会近距离观察的对象才使用 2048 纹理。提供 GLB 文件时应启用 Brotli 或 gzip,因为 Meshopt 和量化输出依赖它们来缩小传输体积。

发布前验证 ​

文件大小只是最容易检查的数字。在 GLB 查看器中打开处理结果,并检查其余指标:扩展面板可确认 EXT_meshopt_compression、KHR_draco_mesh_compression 或 KHR_texture_basisu 是否确实写入文件;纹理选项卡会按实际显存占用从大到小列出每张纹理;状态栏则显示实时绘制调用次数和三角形数量。随后,从玩家实际看到模型的距离检查轮廓和 UV 接缝处是否存在简化瑕疵,并播放所有动画,确保合并操作没有把本应移动的部件融合在一起。如果源文件一开始不是 GLB,请先通过 FBX 转 GLB 转换器处理 FBX 或 OBJ,这样压缩的就是游戏最终实际加载的文件。

GLB 查看器页面,其中显示一个青蛙角色,以及包含三角形、绘制调用、骨骼和几何体大小的概览面板
在这里打开压缩后的输出文件,确认扩展确实已写入文件;然后从状态栏查看绘制调用次数和三角形数量,并从纹理选项卡查看每张纹理的实际显存占用。

常见问题 ​

如何减小 GLB 文件体积? ​

运行 gltf-transform inspect,查看主要体积来自纹理还是几何体。如果是纹理,将其尺寸缩小到 1024 或 2048,并转换为 WebP 或 KTX2。如果是几何体,先进行简化,再使用 Meshopt 或 Draco 压缩。gltf-transform optimize in.glb out.glb --texture-compress webp 可以完成整个处理流程,而浏览器中的 GLB 优化器无需安装即可完成同样的操作。

Draco 与 Meshopt:哪个更好? ​

对大多数网页游戏而言,Meshopt 更好。它的解码速度快得多,解码器只有 32 KB,而不是数百 KB 的 WASM;它还能压缩动画和变形目标,而 Draco 会跳过这些数据。Draco 对静态网格生成的文件更小(在我们的 28 MB 测试模型上,经 gzip 后分别为 2.6 MB 和 3.3 MB),并且它是 PlayCanvas 支持的方案。因此,当资源是静态扫描模型,且大部分体积来自几何体时,Draco 更有优势。

什么是 KTX2?它与 Basis 有什么区别? ​

Basis Universal 是压缩编解码器,包含 ETC1S 和 UASTC 两种模式。KTX2 是 Khronos 的容器文件格式,用于保存经过 Basis 压缩的纹理数据、Mipmap 和元数据;glTF 通过 KHR_texture_basisu 引用它。旧版工作流使用独立的 .basis 文件。应使用 .ktx2。

应该使用 ETC1S 还是 UASTC? ​

基础颜色纹理和不会被近距离观察的内容使用 ETC1S:文件小,显存占用为每像素 4 位。法线贴图、粗糙度/金属度/遮蔽贴图以及主角纹理使用 UASTC,并启用 Zstandard 超级压缩,使下载体积保持合理。将颜色纹理标记为 sRGB,将数据纹理标记为线性,否则法线的着色效果会出错。

如何压缩 glTF 纹理? ​

若要减小下载体积,先运行 gltf-transform resize,再运行 gltf-transform webp。若要减少 GPU 内存占用,请在安装 KTX-Software 后运行 gltf-transform etc1s 或 uastc,也可以将 PNG 拖放到 KTX2 压缩器中。无论采用哪种方式,都应先限制纹理尺寸:一张 4096 纹理以 RGBA8 格式加载时会占用 89 MB 显存,几乎没有理由在浏览器中使用这种纹理。

为什么我的 GLB 对移动端 three.js 来说太大? ​

问题通常不在文件大小,而在纹理内存。四张 2048 RGBA 纹理在场景尚未绘制任何内容前,就会占用约 90 MB 显存;手机浏览器在占用超过数百 MB 后可能会终止标签页。将纹理转换为 KTX2,使其在 GPU 上保持压缩状态;能用 1024 时就限制为 1024;并调用 KTX2Loader.detectSupport(renderer),使其转码为设备支持的格式。

gltfpack 与 gltf-transform 的功能相同吗? ​

大体相同。gltfpack 是 meshoptimizer 项目提供的单个原生二进制程序,默认会执行量化、针对 GPU 缓存重新排列顶点、合并网格并使用 Meshopt 压缩。glTF-Transform 是 Node 库和 CLI,将相同操作拆分为可编写脚本的独立步骤;它还支持输出 Draco,而 gltfpack 不支持。在我们的测试文件上,两者生成的 Meshopt 输出体积差异在约 10% 以内。

相关内容 ​