mcpField
T
threejs-agents-model-optimizer

threejs-agents-model-optimizer

github.com/impertio-studio开发23153 次安装30 周前更新
代码仓库

关于 threejs-agents-model-optimizer

面向 Three.js 项目开发者的 GLB 与 glTF 模型优化技能,按评估、网格和纹理处理、压缩、LOD 生成及验证组织流程。

主要功能

  1. 01模型体积与复杂度评估
  2. 02网格清理与简化
  3. 03纹理缩放与压缩
  4. 04Draco 与 meshopt 压缩指南
  5. 05LOD 生成与验证

适用场景

  1. 01按 Web 体积预算准备 GLB 资源
  2. 02减少纹理和网格占用
  3. 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 外,安装时一起下载的参考资料和脚本。

.gitkeep
references/
anti-patterns.md
examples.md
methods.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 MB50K 个三角形1024x1024
桌面网页5 MB200K 个三角形2048x2048
桌面应用20 MB500K 个三角形4096x4096
主视觉资源(单个)1 MB30K 个三角形1024x1024
工具选择
工具最适用于安装
gltf-transform完整流程、可编写脚本、Node.js APInpm 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.750.0005轻微精简,保留细节
中等0.500.001质量与大小均衡
激进0.250.005生成 LOD1/LOD2
极限0.100.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
属性ETC1SUASTC
文件大小非常小(缩小 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. 文件大小——符合第 1 步设定的目标预算
  2. 视觉质量——在 Three.js 查看器中加载,并与原始模型对比
  3. 包围盒——尺寸与原始模型相同(无缩放错误)
  4. 材质——所有纹理均已加载,没有缺失贴图
  5. 动画——所有片段均能正常播放(如适用)
  6. 性能——测量绘制调用次数和帧耗时
# 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);

参考链接

官方来源

评论

支持 Markdown