threejs-agents-model-optimizer について
Three.js プロジェクトの開発者向けに、GLB と glTF モデルを最適化するスキルです。評価からメッシュ・テクスチャ処理、圧縮、LOD 生成、検証までの手順を示します。
主な機能
- 01モデル容量と複雑さの評価
- 02メッシュの整理と簡略化
- 03テクスチャのリサイズと圧縮
- 04Draco と meshopt の圧縮ガイド
- 05LOD の生成と検証
活用シーン
- 01Web の容量予算に合わせた 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 triangles | 1024x1024 |
| デスクトップウェブ | 5 MB | 200K triangles | 2048x2048 |
| デスクトップアプリ | 20 MB | 500K triangles | 4096x4096 |
| ヒーローアセット(単体) | 1 MB | 30K triangles | 1024x1024 |
ツールの選択
| ツール | 最適な用途 | インストール |
|---|---|---|
gltf-transform | フルパイプライン、スクリプト化可能、Node.js API | npm i @gltf-transform/cli |
gltfpack | 高速な単発圧縮 | npm i -g gltfpack |
| Blender | 手動でのメッシュ編集、UVの再パック | Blender 3.6+ |
重要な警告
絶対に 評価のステップを省略しないでください。闇雲な最適化は時間の無駄になり、元のモデルよりも悪い結果を招く可能性があります。
絶対に 同じファイルにDraco圧縮とmeshopt圧縮を適用しないでください。この2つは併用できません。どちらか一方を選んでください。
絶対に モバイル向けのディフューズカラーマップにKTX2 UASTCを使用しないでください。UASTCテクスチャはVRAMで1テクセルあたり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使用量 | 少ない | 多い(1テクセルあたり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 bits | 16 bits | 11 bits |
| 法線 | 10 bits | 12 bits | 8 bits |
| テクスチャ座標 | 12 bits | 14 bits | 10 bits |
| 色 | 8 bits | 10 bits | 6 bits |
ビット数を増やすと品質が向上し、ファイルサイズも大きくなります。ほとんどのモデルでは、位置に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) | 単一ファイルで、サイズが小さい |
| モディファイアーを適用 | ON | プロシージャルジオメトリをベイクする |
| 圧縮 | OFF | エクスポート後に gltf-transform で圧縮する |
| テクスチャ | 含める | .glb に埋め込まれる |
| 対象を限定 | 選択したオブジェクト | 非表示または未使用のオブジェクトのエクスポートを防ぐ |
| +Y を上方向にする | ON | 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 -- よくある最適化の失敗