3DモデルをWebで配信する際、ファイルサイズは重要な課題です。本記事では、Draco圧縮 を使ってGLBファイルを87%削減した事例と、圧縮時の注意点(特にUV座標)について解説します。
https://3dtiles-viewer.vercel.app/glb-viewer.html

使用データ
- モデル : Rotunde Brunnen(噴水のある円形建築物)
- 出典 : Sketchfab
- 形式 : GLB (glTF 2.0 Binary)
Draco圧縮とは
DracoはGoogleが開発したオープンソースの3Dメッシュ圧縮ライブラリです。glTF 2.0ではKHR_draco_mesh_compression拡張として標準サポートされています。
圧縮の仕組み
- 量子化(Quantization) : 頂点座標やUV座標を指定ビット数に丸める
- 予測符号化 : 隣接頂点との差分を予測して符号化
- エントロピー符号化 : 予測誤差を効率的に圧縮
圧縮コマンド
# gltf-transformを使用
npx gltf-transform draco input.glb output-draco.glb
# オプション付き(高品質設定)
npx gltf-transform draco input.glb output-draco.glb \
--quantize-position 14 \
--quantize-normal 10 \
--quantize-texcoord 12
圧縮結果の比較
ファイルサイズ
| ファイル | サイズ | 削減率 |
|---|---|---|
| rotunde-brunnen.glb(元) | 94.7 MB | - |
| rotunde-brunnen-draco.glb | 12.5 MB | 87%削減 |
メッシュ構造
| 項目 | 元ファイル | Draco圧縮後 |
|---|---|---|
| メッシュ数 | 38 | 2(統合) |
| 三角形数 | 約175万 | 約167万 |
| テクスチャ | 1024x1024 PNG | 同一 |
| バウンディングボックス | ほぼ同一 | ほぼ同一 |
精度
視覚的な精度低下はありません 。
- バウンディングボックスがほぼ同一 → 形状は保持
- デフォルトの量子化設定(位置14bit)で十分な精度
- 科学計測用途でなければ問題なし
HTTP転送時の圧縮との関係
Webサーバー(Vercel、Nginx等)は、HTTPレスポンスに対してBrotli やgzip 圧縮を自動適用します。Draco圧縮との関係を実測値で確認しました。
実測: Vercelでの転送サイズ
| ファイル | ファイルサイズ | 転送サイズ (Brotli) | Brotli効果 |
|---|---|---|---|
| 元ファイル | 94.7 MB | 58.5 MB | 38%削減 |
| Draco圧縮 | 12.5 MB | 12.4 MB | ほぼ0% |
# 元ファイルのHTTPレスポンスヘッダー
content-encoding: br
content-length: 61338605 # 約58.5MB
# Draco圧縮ファイルのHTTPレスポンスヘッダー
content-encoding: br
content-length: 12991149 # 約12.4MB
なぜDracoファイルにBrotliが効かないのか
Draco圧縮は内部でエントロピー符号化 (データの冗長性を除去)を行っています。これはBrotliやgzipと同様の原理のため、二重圧縮の効果がほとんどない のです。
総合比較: 実際の転送効率
| 項目 | 元ファイル | Draco |
|---|---|---|
| ファイルサイズ | 94.7 MB | 12.5 MB |
| 転送サイズ(Brotli適用後) | 58.5 MB | 12.4 MB |
| 実質的な転送削減 | - | 79%削減 |
| ダウンロード時間 (10Mbps) | ~47秒 | ~10秒 |
| ダウンロード時間 (100Mbps) | ~4.7秒 | ~1秒 |
Dracoを使うメリット(転送観点)
- 転送サイズが小さい → ダウンロード高速化
- サーバーストレージ削減 → ホスティングコスト削減
- Brotli圧縮のCPU負荷が不要 → サーバー負荷軽減
- CDNキャッシュ効率向上 → 小さいファイルはキャッシュヒット率向上
注意: ストリーミングには非対応
GLBファイルは全データをダウンロードしてからレンダリング されます。プログレッシブロード(徐々に表示)には対応していません。
プログレッシブロードが必要な場合は以下を検討:
- 3D Tiles : LOD(Level of Detail)による段階的読み込み
- glTF + EXT_meshopt_compression : メッシュの段階的デコード
量子化とUV座標の問題
問題: UV座標が[0,1]範囲外の場合
Draco圧縮で最も注意が必要 なのがUV座標です。
テクスチャのタイリング(繰り返し)を使用するモデルでは、UV座標が[0,1]の範囲を超えることがあります。
例: タイリング用UV
u: 0.0 ~ 10.0 (10回繰り返し)
v: 0.0 ~ 10.0
なぜ問題が起きるのか
Draco圧縮は量子化 を行います。デフォルトでUV座標は10〜12bitに量子化されます。
| UV範囲 | 10bit量子化での精度 | 影響 |
|---|---|---|
| [0, 1] | 1/1024 ≈ 0.001 | 問題なし |
| [0, 10] | 10/1024 ≈ 0.01 | 軽微なズレ |
| [0, 100] | 100/1024 ≈ 0.1 | 目立つズレ |
発生する問題
- テクスチャの継ぎ目(シーム)
- テクスチャのズレ・歪み
- タイリング境界での不連続
解決策
1. UV座標の量子化ビット数を増やす
npx gltf-transform draco input.glb output.glb \
--quantize-texcoord 14 # デフォルト10→14に増加
| ビット数 | ステップ数 | [0,100]範囲での精度 |
|---|---|---|
| 10 | 1,024 | 0.0977 |
| 12 | 4,096 | 0.0244 |
| 14 | 16,384 | 0.0061 |
| 16 | 65,536 | 0.0015 |
2. UVを[0,1]範囲に正規化してからタイリング
// シェーダー側でタイリング
vec2 tiledUV = fract(uv * 10.0); // 10回繰り返し
3. 大きなUV範囲のメッシュはDraco圧縮しない
# 特定のメッシュを除外(手動で分離が必要)
gltf-transformの便利なコマンド
ファイル情報の確認
# 詳細情報を表示
npx gltf-transform inspect model.glb
# 検証
npx gltf-transform validate model.glb
その他の最適化
# テクスチャ圧縮(WebP)
npx gltf-transform webp input.glb output.glb
# テクスチャリサイズ
npx gltf-transform resize input.glb output.glb --width 1024 --height 1024
# 重複頂点の削除
npx gltf-transform dedup input.glb output.glb
# 最適化パイプライン(複数処理を一度に)
npx gltf-transform optimize input.glb output.glb
ビューアでの読み込み
Three.jsでDraco圧縮GLBを読み込む場合、DRACOLoaderの設定が必要です。
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
const loader = new GLTFLoader();
// Dracoデコーダーの設定
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('https://www.gstatic.com/draco/versioned/decoders/1.5.6/');
loader.setDRACOLoader(dracoLoader);
// 読み込み
loader.load('model-draco.glb', (gltf) => {
scene.add(gltf.scene);
});
まとめ
| 項目 | 内容 |
|---|---|
| 圧縮率 | 80〜90%のサイズ削減が可能 |
| 精度 | 通常用途では視覚的な劣化なし |
| 注意点 | UV座標が[0,1]範囲外の場合は設定調整が必要 |
| ツール | gltf-transformが便利 |
推奨設定
# 一般的なWeb配信用
npx gltf-transform draco input.glb output.glb
# 高精度が必要な場合
npx gltf-transform draco input.glb output.glb \
--quantize-position 16 \
--quantize-normal 12 \
--quantize-texcoord 14
# UV範囲が広い場合
npx gltf-transform draco input.glb output.glb \
--quantize-texcoord 16