关于 threejs-agents-model-optimizer
面向 Three.js 项目开发者的 GLB 与 glTF 模型优化技能,按评估、网格和纹理处理、压缩、LOD 生成及验证组织流程。
主要功能
- 01模型体积与复杂度评估
- 02网格清理与简化
- 03纹理缩放与压缩
- 04Draco 与 meshopt 压缩指南
- 05LOD 生成与验证
适用场景
- 01按 Web 体积预算准备 GLB 资源
- 02减少纹理和网格占用
- 03生成并检查模型 LOD 版本
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ impertio-studio/ three.js-claude-skill-package --skill threejs-agents-model-optimizer安装后在 Claude Code 中输入/threejs-agents-model-optimizer确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
.gitkeepreferences/anti-patterns.mdexamples.mdmethods.md详细介绍
threejs-agents-model-optimizer
快速参考
优化流程概览
INPUT (.glb/.gltf)
|
v
[1. ASSESS] ── polygon count, texture sizes, file size, draw calls
|
v
[2. MESH OPTIMIZE] ── dedup, flatten, join, weld, simplify
|
v
[3. TEXTURE OPTIMIZE] ── resize, KTX2 compress, atlas
|
v
[4. COMPRESS] ── Draco mesh compression, quantize attributes
|
v
[5. VALIDATE] ── visual diff, file size check, runtime test
|
v
OUTPUT (optimized .glb)
目标文件大小预算
| 平台 | 最大文件大小 | 最大多边形数 | 最大纹理尺寸 |
|---|---|---|---|
| 移动端网页 | 2 MB | 50K 个三角形 | 1024x1024 |
| 桌面网页 | 5 MB | 200K 个三角形 | 2048x2048 |
| 桌面应用 | 20 MB | 500K 个三角形 | 4096x4096 |
| 主视觉资源(单个) | 1 MB | 30K 个三角形 | 1024x1024 |
工具选择
| 工具 | 最适用于 | 安装 |
|---|---|---|
gltf-transform | 完整流程、可编写脚本、Node.js API | npm i @gltf-transform/cli |
gltfpack | 快速的一次性压缩 | npm i -g gltfpack |
| Blender | 手动网格编辑、UV 重排 | Blender 3.6+ |
关键警告
绝不要跳过评估步骤——盲目优化会浪费时间,且可能导致结果比原始模型更差。
绝不要对同一个文件同时应用 Draco 压缩和 meshopt 压缩——两者互斥。二选一。
绝不要在移动端对漫反射颜色贴图使用 KTX2 UASTC——UASTC 纹理在 VRAM 中每个纹素占用 8-16 字节。移动端目标的颜色贴图务必使用 ETC1S。
绝不要在未经视觉验证的情况下,将网格简化到原始规模的 10% 以下——过度简化会破坏轮廓和 UV 映射。
务必在发布前对优化后的模型进行视觉验证——自动化指标无法检测所有视觉瑕疵。
务必在版本控制中保留未经优化的原始模型——优化是有损且不可逆的。
第 1 步:评估
优化之前,务必收集以下指标:
# Using gltf-transform CLI
npx gltf-transform inspect model.glb
# Key output to check:
# - Mesh count and total triangle count
# - Texture count, dimensions, and format
# - Total file size (uncompressed)
# - Accessor count (indicates potential deduplication)
# - Animation track count
评估决策树
File size > target budget?
├── YES: Textures > 50% of file size?
│ ├── YES → Start with texture optimization (Step 3)
│ └── NO → Start with mesh optimization (Step 2)
└── NO: Draw calls > 50?
├── YES → Merge meshes (join/flatten)
└── NO → Only apply compression (Step 4)
多边形数量指南
| 资源类型 | 目标三角形数 | 备注 |
|---|---|---|
| 背景道具 | 100-500 | 细节尽量少 |
| 中景物体 | 1K-5K | 可见,但不是主视觉 |
| 主视觉/焦点物体 | 10K-50K | 高细节,可近距离观察 |
| 角色 | 15K-30K | 配合 LOD 链 |
| 完整场景 | 100K-300K | 所有物体的总和 |
| 建筑(BIM) | 200K-500K | 从 CAD 简化而来 |
第 2 步:网格优化
gltf-transform 网格流程
务必按以下顺序执行这些操作:
# 1. Remove duplicate accessors and unused data
npx gltf-transform dedup input.glb deduped.glb
# 2. Flatten node hierarchy (removes empty nodes)
npx gltf-transform flatten deduped.glb flat.glb
# 3. Join meshes sharing the same material
npx gltf-transform join flat.glb joined.glb
# 4. Weld vertices (merge vertices within tolerance)
npx gltf-transform weld joined.glb welded.glb --tolerance 0.0001
# 5. Simplify mesh (reduce triangle count)
npx gltf-transform simplify welded.glb simplified.glb \
--ratio 0.5 \
--error 0.001
# 6. Remove unused resources
npx gltf-transform prune simplified.glb output.glb
组合流程(单条命令)
npx gltf-transform optimize input.glb output.glb \
--compress draco \
--texture-compress ktx2
网格简化设置
| 质量级别 | 比例 | 误差容差 | 用途 |
|---|---|---|---|
| 最小 | 0.75 | 0.0005 | 轻微精简,保留细节 |
| 中等 | 0.50 | 0.001 | 质量与大小均衡 |
| 激进 | 0.25 | 0.005 | 生成 LOD1/LOD2 |
| 极限 | 0.10 | 0.01 | 仅用于 LOD3 和远景物体 |
焊接设置
| 容差 | 效果 |
|---|---|
| 0.0001 | 保守——仅合并几乎完全相同的顶点 |
| 0.001 | 标准——适用于大多数模型 |
| 0.01 | 激进——可能导致硬边处出现明显接缝 |
第 3 步:纹理优化
纹理决策树
Texture type?
├── Color/Diffuse (baseColorTexture)
│ ├── Mobile → ETC1S (KTX2), max 1024px
│ └── Desktop → UASTC (KTX2), max 2048px
├── Normal map
│ └── ALWAYS UASTC (KTX2) — ETC1S causes visible artifacts on normals
├── ORM (occlusion/roughness/metallic)
│ └── ETC1S (KTX2) — perceptual quality less critical
├── Emissive
│ └── ETC1S (KTX2) — unless HDR, then keep as-is
└── HDR environment
└── Keep as .hdr or .exr — do NOT KTX2 compress
KTX2 压缩命令
# ETC1S: smaller file, lower quality (color maps, ORM)
npx gltf-transform ktx2 input.glb output.glb \
--slots "baseColorTexture,emissiveTexture,occlusionTexture" \
--filter "baseColorTexture=etc1s" \
--quality 128
# UASTC: larger file, higher quality (normal maps)
npx gltf-transform ktx2 input.glb output.glb \
--slots "normalTexture" \
--filter "normalTexture=uastc"
KTX2:ETC1S 与 UASTC
| 属性 | ETC1S | UASTC |
|---|---|---|
| 文件大小 | 非常小(缩小 6-8 倍) | 中等(缩小 2-4 倍) |
| VRAM 占用 | 小 | 大(每个纹素占用 8-16 字节) |
| 质量 | 适用于颜色 | 接近无损 |
| 解码速度 | 快 | 需要转码 |
| 最适用于 | 颜色贴图、ORM、自发光贴图 | 法线贴图、细节纹理 |
纹理缩放
# Resize all textures to max 1024x1024
npx gltf-transform resize input.glb output.glb --width 1024 --height 1024
# Resize only textures larger than 2048px
npx gltf-transform resize input.glb output.glb --width 2048 --height 2048
第 4 步:网格压缩
Draco 压缩
# Default Draco compression
npx gltf-transform draco input.glb output.glb
# Draco with quality settings
npx gltf-transform draco input.glb output.glb \
--quantize-position 14 \
--quantize-normal 10 \
--quantize-texcoord 12 \
--quantize-color 8
Draco 量化位数
| 属性 | 默认 | 高质量 | 激进 |
|---|---|---|---|
| 位置 | 14 位 | 16 位 | 11 位 |
| 法线 | 10 位 | 12 位 | 8 位 |
| 纹理坐标 | 12 位 | 14 位 | 10 位 |
| 颜色 | 8 位 | 10 位 | 6 位 |
位数越高,质量越好,文件也越大。对于大多数模型,14 位位置精度已足够。
不使用 Draco 的量化
# Quantize attributes (reduces file size without Draco dependency)
npx gltf-transform quantize input.glb output.glb
在 Three.js 中加载 Draco 压缩模型
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
const dracoLoader = new DRACOLoader();
// ALWAYS set the decoder path — Draco uses WASM
dracoLoader.setDecoderPath('https://www.gstatic.com/draco/versioned/decoders/1.5.6/');
dracoLoader.preload();
const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(dracoLoader);
gltfLoader.load('model-draco.glb', (gltf) => {
scene.add(gltf.scene);
});
// ALWAYS dispose when done
dracoLoader.dispose();
加载 KTX2 压缩纹理
import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js';
const ktx2Loader = new KTX2Loader();
// ALWAYS set the transcoder path — KTX2 uses WASM basis_transcoder
ktx2Loader.setTranscoderPath('https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/libs/basis/');
ktx2Loader.detectSupport(renderer);
const gltfLoader = new GLTFLoader();
gltfLoader.setKTX2Loader(ktx2Loader);
第 5 步:验证
验证清单
优化后,务必检查:
- 文件大小——符合第 1 步设定的目标预算
- 视觉质量——在 Three.js 查看器中加载,并与原始模型对比
- 包围盒——尺寸与原始模型相同(无缩放错误)
- 材质——所有纹理均已加载,没有缺失贴图
- 动画——所有片段均能正常播放(如适用)
- 性能——测量绘制调用次数和帧耗时
# Compare file sizes
ls -la original.glb optimized.glb
# Validate GLTF structure
npx gltf-transform inspect optimized.glb
# Check for errors
npx gltf-transform validate optimized.glb
生成 LOD
LOD 链策略
| LOD 级别 | 屏幕覆盖率 | 三角形比例 | 距离 |
|---|---|---|---|
| LOD0 | 屏幕的 >30% | 1.0(完整) | 近 |
| LOD1 | 屏幕的 10-30% | 0.5 | 中 |
| LOD2 | 屏幕的 3-10% | 0.25 | 远 |
| LOD3 | 屏幕的 <3% | 0.10 | 很远 |
使用 gltf-transform 生成 LOD
# Generate LOD chain
npx gltf-transform simplify model.glb lod0.glb --ratio 1.0
npx gltf-transform simplify model.glb lod1.glb --ratio 0.5 --error 0.001
npx gltf-transform simplify model.glb lod2.glb --ratio 0.25 --error 0.005
npx gltf-transform simplify model.glb lod3.glb --ratio 0.10 --error 0.01
Three.js LOD 实现
import * as THREE from 'three';
const lod = new THREE.LOD();
// ALWAYS add LODs from highest to lowest detail
lod.addLevel(meshLOD0, 0); // distance 0 = closest
lod.addLevel(meshLOD1, 10); // switch at 10 units
lod.addLevel(meshLOD2, 30); // switch at 30 units
lod.addLevel(meshLOD3, 80); // switch at 80 units
scene.add(lod);
// In render loop — ALWAYS call update for LOD switching
lod.update(camera);
gltfpack 替代方案
如需快速进行一次性优化,而无需构建流水线:
# Install
npm install -g gltfpack
# Optimize with meshopt compression
gltfpack -i input.glb -o output.glb -cc -tc
# Flags:
# -cc mesh compression (meshopt)
# -tc texture compression (KTX2/BasisU)
# -si N simplify to ratio (0.0-1.0)
# -tp texture power-of-two resize
切勿将 gltfpack 的 meshopt 输出与 gltf-transform Draco 混用——这两种压缩格式不兼容。
加载 Meshopt 压缩模型
import { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js';
const gltfLoader = new GLTFLoader();
gltfLoader.setMeshoptDecoder(MeshoptDecoder);
Blender 导出优化
从 Blender 导出为 glTF 时:
| 设置 | 推荐值 | 原因 |
|---|---|---|
| 格式 | glTF Binary (.glb) | 单个文件,体积更小 |
| 应用修改器 | 开启 | 烘焙程序化几何体 |
| 压缩 | 关闭 | 导出后使用 gltf-transform 压缩 |
| 纹理 | 包含 | 嵌入 .glb |
| 限定范围 | 选定对象 | 避免导出隐藏或未使用的对象 |
| +Y 朝上 | 开启 | 符合 Three.js 约定 |
切勿在 Blender 导出器中启用 Draco——Blender 的 Draco 实现已过时。导出后务必使用 gltf-transform 或 gltfpack 进行压缩。
使用 gltf-transform API 编写 Node.js 脚本
import { NodeIO } from '@gltf-transform/core';
import { dedup, flatten, join, weld, simplify,
textureCompress, draco, prune, quantize } from '@gltf-transform/functions';
import draco3d from 'draco3dgltf';
import sharp from 'sharp';
const io = new NodeIO()
.registerExtensions(KHRONOS_EXTENSIONS)
.registerDependencies({
'draco3d.decoder': await draco3d.createDecoderModule(),
'draco3d.encoder': await draco3d.createEncoderModule(),
});
const document = await io.read('input.glb');
// ALWAYS run transforms in dependency order
await document.transform(
dedup(),
flatten(),
join(),
weld({ tolerance: 0.0001 }),
simplify({ ratio: 0.5, error: 0.001 }),
textureCompress({ targetFormat: 'ktx2' }),
draco(),
prune(),
quantize(),
);
await io.write('output.glb', document);
参考链接
- references/methods.md——gltf-transform API 和 Three.js 加载器方法
- references/examples.md——完整的优化流水线示例
- references/anti-patterns.md——常见的优化错误
官方来源
评论
支持 Markdown