# 機能設計書 84-LOD

## 概要

本ドキュメントは、Three.jsにおける詳細度切り替え機能 `LOD` (Level of Detail) クラスの機能設計を定義する。LODはカメラからの距離に応じて異なる詳細度のオブジェクトを表示し、レンダリングパフォーマンスを最適化する機能を提供する。

### 本機能の処理概要

LODクラスは、複数の詳細度レベル（高精細、中精細、低精細など）のオブジェクトを管理し、カメラとの距離に基づいて適切なレベルを自動的に選択して表示する。これにより、遠くのオブジェクトは簡略化されたモデルで描画され、GPUの負荷を軽減できる。

**業務上の目的・背景**：3Dアプリケーションにおいて、大規模なシーンや多数のオブジェクトを効率的にレンダリングするための最適化技術として必要である。遠くのオブジェクトに高精細モデルを使用しても視覚的な差異は少ないため、簡略化モデルで描画することでパフォーマンスを向上させる。

**機能の利用シーン**：
- 大規模な3Dシーン（都市、森林、地形など）
- 多数のインスタンスを含むシーン
- VR/ARアプリケーションでのパフォーマンス最適化
- ゲームにおけるオープンワールド表現
- CADビューアでの大規模アセンブリ表示

**主要な処理内容**：
1. LODレベルの登録（addLevel）
2. カメラ距離に基づくレベル選択
3. ヒステリシスによるフリッカリング防止
4. 自動更新またはマニュアル更新の切り替え
5. レイキャスト時の適切なレベル選択

**関連システム・外部連携**：WebGLRenderer/WebGPURendererと連携し、フレームごとに適切なLODレベルを選択する。

**権限による制御**：特になし（Three.jsはクライアントサイドライブラリ）

## 関連画面

画面機能マッピング.csvに本機能（No.84）の関連画面情報は記載されていない。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | - |

## 機能種別

パフォーマンス最適化 / 自動レベル切り替え

## 入力仕様

### 入力パラメータ

コンストラクタはパラメータを取らない。

#### addLevelメソッド

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| object | Object3D | Yes | このレベルで表示するオブジェクト | - |
| distance | number | No | この詳細度を使用する距離（デフォルト: 0） | 絶対値に変換される |
| hysteresis | number | No | フリッカリング防止閾値（デフォルト: 0） | - |

### 入力データソース

- 各詳細度レベルのObject3D（Mesh等）
- カメラ位置情報（update時）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| isLOD | boolean | 型判定フラグ（常にtrue） |
| levels | Array\<{object, distance, hysteresis}\> | LODレベル配列 |
| autoUpdate | boolean | 自動更新フラグ（デフォルト: true） |
| _currentLevel | number | 現在のLODレベルインデックス |

### 出力先

選択されたLODレベルのオブジェクトがレンダリングされる。

## 処理フロー

### 処理シーケンス

```
1. コンストラクタ呼び出し
   └─ Object3Dの初期化、levels配列の初期化
2. addLevel()でレベル追加
   └─ 距離でソートして挿入、子オブジェクトとして追加
3. update()でレベル切り替え
   └─ カメラ距離計算 → 適切なレベル選択 → visible切り替え
4. raycast()時
   └─ 現在の距離に適したレベルでレイキャスト実行
```

### フローチャート

```mermaid
flowchart TD
    A[LOD生成] --> B[levels配列初期化]
    B --> C[addLevel呼び出し]
    C --> D[距離順ソート挿入]
    D --> E[子としてオブジェクト追加]
    E --> F{autoUpdate?}
    F -->|Yes| G[レンダラーがupdate呼び出し]
    F -->|No| H[手動でupdate呼び出し]
    G --> I[カメラ距離計算]
    H --> I
    I --> J[適切なレベル選択]
    J --> K{ヒステリシス適用}
    K --> L[visible切り替え]
    L --> M[_currentLevel更新]
    M --> N[レンダリング]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-84-01 | 距離順ソート | レベルは距離の昇順でソートされる | addLevel時 |
| BR-84-02 | レベル0が最高詳細度 | 距離0のレベルが最も詳細（近距離用） | 常時 |
| BR-84-03 | ヒステリシス | レベル境界でのフリッカリング防止 | update時 |
| BR-84-04 | カメラズーム考慮 | distance / camera.zoomで実効距離を計算 | update時 |
| BR-84-05 | 自動更新 | autoUpdate=trueでレンダラーが自動呼び出し | フレームごと |

### 計算ロジック

ヒステリシス適用時の実効距離:
```javascript
// 現在表示中のレベルの場合、境界を内側にシフト
if (levels[i].object.visible) {
    levelDistance -= levelDistance * levels[i].hysteresis;
}
```

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

該当なし（Three.jsはクライアントサイドライブラリ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | - | - | - |

### リトライ仕様

特になし

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

該当なし

## パフォーマンス要件

- LOD自体の更新処理は軽量
- 適切なLODレベル設定により描画ポリゴン数を大幅削減可能
- ヒステリシスによりレベル切り替え頻度を抑制

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

特になし（クライアントサイドレンダリング）

## 備考

- LODレベルが1つのみの場合、update()は何もしない
- removeLevel()で特定距離のレベルを削除可能
- getCurrentLevel()で現在のレベルインデックスを取得可能
- toJSON()でシリアライズ対応

---

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

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

### 推奨読解順序

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

LODレベルの構造とプロパティを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | LOD.js | `src/objects/LOD.js` | levels配列の構造 `{object, distance, hysteresis}` |

**読解のコツ**: levelsはObject.definePropertiesで定義されており、enumerable: trueである点に注意。

#### Step 2: エントリーポイントを理解する

LODクラスの主要メソッドを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | LOD.js | `src/objects/LOD.js` | コンストラクタ、addLevel、update |

**主要処理フロー**:
1. **38-85行目**: コンストラクタでisLOD、_currentLevel、levels、autoUpdateを初期化
2. **116-140行目**: addLevel()で距離順にレベルを挿入
3. **188-220行目**: getObjectForDistance()で適切なオブジェクトを選択
4. **250-298行目**: update()でカメラ距離に基づきvisibleを切り替え

#### Step 3: レイキャスト処理を理解する

LODのレイキャスト処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | LOD.js | `src/objects/LOD.js` | raycast()メソッド |

**主要処理フロー**:
- **228-242行目**: getObjectForDistance()で適切なレベルを選択してraycast委譲

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

```
LOD
    │
    ├─ Object3D (継承)
    │      ├─ add() / remove() (子管理)
    │      └─ updateMatrixWorld() (行列更新)
    │
    ├─ levels[] (LODレベル配列)
    │      └─ {object: Object3D, distance: number, hysteresis: number}
    │
    ├─ addLevel()
    │      └─ 距離順ソート挿入、Object3D.add()呼び出し
    │
    ├─ removeLevel()
    │      └─ 距離一致レベル削除、Object3D.remove()呼び出し
    │
    ├─ update()
    │      └─ カメラ距離計算 → visible切り替え → _currentLevel更新
    │
    ├─ getObjectForDistance()
    │      └─ 距離に応じたオブジェクト取得（ヒステリシス考慮）
    │
    └─ raycast()
           └─ getObjectForDistance() → object.raycast()
```

### データフロー図

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

addLevel(object, dist) ─▶ levels配列に挿入 ─▶ levels[]更新
                              │
                              └─ childrenに追加

camera.position ─────▶ update(camera) ─────▶ visible切り替え
LOD.matrixWorld           │                    _currentLevel更新
                          │
                          ├─ 距離計算 (distanceTo / zoom)
                          ├─ ヒステリシス適用
                          └─ レベル選択

Raycaster.ray ────────▶ raycast() ──────────▶ intersects[]
                           │
                           ├─ getObjectForDistance()
                           └─ 選択オブジェクトにraycast委譲
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| LOD.js | `src/objects/LOD.js` | ソース | LODメインクラス |
| Object3D.js | `src/core/Object3D.js` | ソース | 3Dオブジェクトの基底クラス |
| Vector3.js | `src/math/Vector3.js` | ソース | 3Dベクトル（位置計算） |
| Camera.js | `src/cameras/Camera.js` | ソース | カメラ基底クラス |
| PerspectiveCamera.js | `src/cameras/PerspectiveCamera.js` | ソース | 透視投影カメラ |
