# 機能設計書 104-ObjectLoader

## 概要

本ドキュメントは、Three.jsライブラリにおけるJSON Object/Scene形式ファイルの読み込み機能「ObjectLoader」の設計について記述する。ObjectLoaderは、Three.jsのtoJSON()で出力されたシリアライズ済みシーンやオブジェクトを読み込み、完全な3Dオブジェクト階層を復元するローダークラスである。

### 本機能の処理概要

**業務上の目的・背景**：3Dシーンやオブジェクトの永続化、共有、再利用のために、Three.jsは独自のJSONフォーマットを提供している。ObjectLoaderは、このJSONフォーマットを解析し、ジオメトリ、マテリアル、テクスチャ、アニメーション、ライト、カメラなどを含む完全なシーン階層を復元する。これにより、エディターで作成したシーンのロードや、事前に構築されたシーンの動的読み込みが可能になる。

**機能の利用シーン**：
- Three.js Editorで保存したシーンのロード
- 事前構築されたゲームレベルやシーンのロード
- オブジェクトやシーンのインポート/エクスポート
- シーンのプリセット読み込み
- リソースのプリロードと動的ロード

**主要な処理内容**：
1. FileLoaderを使用してJSONファイルを読み込み
2. メタデータの検証（フォーマット確認）
3. 各リソースタイプの並列パース
   - shapes, animations, geometries, images, textures, materials
4. parseObject()によるオブジェクト階層の再構築
5. スケルトンのバインドとライトターゲットの解決
6. onLoadコールバックへの完成オブジェクト渡し

**関連システム・外部連携**：
- FileLoader: JSONファイルの読み込み
- ImageLoader: テクスチャ用画像の読み込み
- BufferGeometryLoader: ジオメトリのパース
- MaterialLoader: マテリアルのパース
- AnimationClip: アニメーションのパース
- LoadingManager: 読み込み進捗管理

**権限による制御**：特になし

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 直接関連する画面なし（プログラムからの利用が主） |

## 機能種別

データ読み込み / シーンローダー / オブジェクト復元

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| url | string | Yes | 読み込むJSONファイルのパス/URL | なし |
| onLoad | function(Object3D) | No | 読み込み完了時のコールバック | なし |
| onProgress | function | No | 進捗コールバック | なし |
| onError | function | No | エラー発生時のコールバック | なし |
| manager | LoadingManager | No | ローディングマネージャー | なし |

### 入力データソース

**JSON Object/Scene Format 4**
```json
{
  "metadata": { "type": "Object" | "Scene", "version": 4.6 },
  "geometries": [...],
  "materials": [...],
  "textures": [...],
  "images": [...],
  "shapes": [...],
  "skeletons": [...],
  "animations": [...],
  "object": { "type": "Scene", "children": [...] }
}
```

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| object | Object3D/Scene | パースされた3Dオブジェクト（通常Scene） |

### 出力先

- onLoadコールバック関数への引数として渡される
- parse()メソッドの戻り値として返却

## 処理フロー

### 処理シーケンス

```
1. load()メソッド呼び出し
   └─ URLからリソースパスを抽出
2. FileLoader.load()でJSONファイル取得
3. JSON.parse()でオブジェクトに変換
4. メタデータ検証
   └─ type === 'geometry'の場合エラー
5. parse()メソッド呼び出し
   ├─ parseAnimations() - アニメーションクリップ
   ├─ parseShapes() - Shapeオブジェクト
   ├─ parseGeometries() - ジオメトリ（BufferGeometryLoader使用）
   ├─ parseImages() - 画像（ImageLoader使用）
   ├─ parseTextures() - テクスチャ
   ├─ parseMaterials() - マテリアル（MaterialLoader使用）
   └─ parseObject() - オブジェクト階層（再帰処理）
6. bindSkeletons() - SkinnedMeshにスケルトンをバインド
7. bindLightTargets() - DirectionalLight/SpotLightのtarget解決
8. onLoadコールバック実行
```

### フローチャート

```mermaid
flowchart TD
    A[load開始] --> B[FileLoader.load]
    B --> C[JSON.parse]
    C --> D{metadata検証}
    D -->|Invalid| E[Error]
    D -->|Valid| F[parseAnimations]
    F --> G[parseShapes]
    G --> H[parseGeometries]
    H --> I[parseImages]
    I --> J[parseTextures]
    J --> K[parseMaterials]
    K --> L[parseObject]
    L --> M[parseSkeletons]
    M --> N[bindSkeletons]
    N --> O[bindLightTargets]
    O --> P{画像読み込み完了?}
    P -->|No| Q[待機]
    P -->|Yes| R[onLoad実行]
    Q --> P
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-104-1 | メタデータ検証 | metadata.type === 'geometry'は非サポート | 常時 |
| BR-104-2 | リソースパス自動解決 | path未設定時はURLからベースパスを抽出 | this.path === '' |
| BR-104-3 | 非同期画像読み込み | parseImages()は画像読み込み完了まで待機 | 画像が含まれる場合 |
| BR-104-4 | UUID参照解決 | ジオメトリ/マテリアル/テクスチャはUUIDで参照 | 常時 |
| BR-104-5 | 再帰的子オブジェクト | parseObject()は子オブジェクトを再帰的に処理 | children存在時 |

### 計算ロジック

特になし

## データベース操作仕様

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | JSON解析エラー | 不正なJSONファイル | onErrorコールバック実行 |
| - | メタデータエラー | metadata未定義またはtype='geometry' | onErrorコールバック実行 |
| - | 画像読み込みエラー | テクスチャ画像の取得失敗 | manager.itemError()呼び出し |
| - | リソース参照エラー | UUID参照先が見つからない | warnログ出力、処理続行 |

### リトライ仕様

自動リトライ機能なし

## トランザクション仕様

該当なし

## パフォーマンス要件

- 画像の並列読み込みによる最適化
- キャッシュを活用したマテリアル重複排除

## セキュリティ考慮事項

- ImageLoader経由でCORS対応
- 外部リソースのcrossOrigin設定

## 備考

- async/await対応: loadAsync()、parseAsync()メソッド提供
- サポートオブジェクトタイプ: Scene, PerspectiveCamera, OrthographicCamera, AmbientLight, DirectionalLight, PointLight, RectAreaLight, SpotLight, HemisphereLight, LightProbe, SkinnedMesh, Mesh, InstancedMesh, BatchedMesh, LOD, Line, LineLoop, LineSegments, Points, Sprite, Group, Bone, Object3D

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: 入力データ構造を理解する

ObjectLoaderが処理するJSON Object/Scene Formatの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ObjectLoader.js | `src/loaders/ObjectLoader.js` | 68-80行目: JSDocコメントにフォーマット概要 |

**読解のコツ**: JSONフォーマットは metadata, geometries, materials, textures, images, shapes, skeletons, animations, object の各セクションで構成される。

#### Step 2: ファイル読み込みフローを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ObjectLoader.js | `src/loaders/ObjectLoader.js` | 105-149行目: load()メソッド |

**主要処理フロー**:
- **109行目**: リソースパス自動解決（LoaderUtils.extractUrlBase）
- **112-116行目**: FileLoaderの設定と読み込み開始
- **122行目**: JSON.parse()でパース
- **136-137行目**: メタデータ検証
- **145行目**: parse()呼び出し

#### Step 3: リソースパース処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ObjectLoader.js | `src/loaders/ObjectLoader.js` | 195-266行目: parse()/parseAsync() |

**主要処理フロー**:
- **197-199行目**: animations, shapes, geometries のパース
- **201-205行目**: images のパース（非同期、完了時onLoad実行）
- **207-208行目**: textures, materials のパース
- **210-214行目**: object, skeletons パースとバインド

#### Step 4: オブジェクト階層の再構築を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ObjectLoader.js | `src/loaders/ObjectLoader.js` | 743-1193行目: parseObject() |

**主要処理フロー**:
- **809-1094行目**: switch文による型別オブジェクト生成
- **1096-1142行目**: 共通プロパティの設定（uuid, name, matrix, shadow等）
- **1144-1154行目**: 子オブジェクトの再帰処理
- **1156-1168行目**: アニメーションの関連付け
- **1170-1189行目**: LODレベルの設定

### プログラム呼び出し階層図

```
ObjectLoader.load(url, onLoad, onProgress, onError)
    │
    ├─ LoaderUtils.extractUrlBase(url)
    │
    ├─ FileLoader.load(url)
    │      └─ JSON.parse(text)
    │
    └─ parse(json, onLoad)
           │
           ├─ parseAnimations(json.animations)
           │      └─ AnimationClip.parse()
           │
           ├─ parseShapes(json.shapes)
           │      └─ Shape.fromJSON()
           │
           ├─ parseGeometries(json.geometries, shapes)
           │      └─ BufferGeometryLoader.parse()
           │      └─ Geometries[type].fromJSON()
           │
           ├─ parseImages(json.images, onImageLoad)
           │      └─ ImageLoader.load()
           │
           ├─ parseTextures(json.textures, images)
           │      └─ new CubeTexture/DataTexture/Texture
           │
           ├─ parseMaterials(json.materials, textures)
           │      └─ MaterialLoader.parse()
           │
           ├─ parseObject(json.object, geometries, materials, textures, animations)
           │      └─ 再帰的に子オブジェクト処理
           │
           ├─ parseSkeletons(json.skeletons, object)
           │      └─ Skeleton.fromJSON()
           │
           ├─ bindSkeletons(object, skeletons)
           │
           └─ bindLightTargets(object)
```

### データフロー図

```
[入力]                    [処理]                           [出力]

JSON File ──▶ FileLoader ──▶ JSON Object ──▶ parse()
                                   │
              ┌────────────────────┼────────────────────┐
              │                    │                    │
              ▼                    ▼                    ▼
       parseAnimations      parseGeometries       parseImages
              │                    │                    │
              └────────────────────┼────────────────────┘
                                   ▼
                            parseTextures
                                   │
                                   ▼
                            parseMaterials
                                   │
                                   ▼
                            parseObject ──▶ Object3D/Scene
                                   │
                                   ▼
                     bindSkeletons / bindLightTargets
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ObjectLoader.js | `src/loaders/ObjectLoader.js` | ソース | メインローダー（1274行） |
| FileLoader.js | `src/loaders/FileLoader.js` | ソース | JSONファイル取得 |
| ImageLoader.js | `src/loaders/ImageLoader.js` | ソース | テクスチャ画像取得 |
| BufferGeometryLoader.js | `src/loaders/BufferGeometryLoader.js` | ソース | ジオメトリパース |
| MaterialLoader.js | `src/loaders/MaterialLoader.js` | ソース | マテリアルパース |
| LoaderUtils.js | `src/loaders/LoaderUtils.js` | ソース | URL解析ユーティリティ |
| AnimationClip.js | `src/animation/AnimationClip.js` | ソース | アニメーションパース |
| Shape.js | `src/extras/core/Shape.js` | ソース | シェイプパース |
| Skeleton.js | `src/objects/Skeleton.js` | ソース | スケルトンパース |
