# 機能設計書 2-BufferGeometry

## 概要

本ドキュメントは、Three.jsライブラリにおける頂点データを効率的に管理するジオメトリクラスであるBufferGeometryの機能設計について記述する。BufferGeometryは、メッシュ・ライン・ポイントのジオメトリデータ（頂点位置、面インデックス、法線、色、UV座標など）をバッファとして管理し、GPUへの効率的なデータ転送を実現する。

### 本機能の処理概要

BufferGeometryクラスは、3Dオブジェクトの形状を定義するための頂点データをTypedArrayとして管理する。これにより、従来のGeometryクラス（非推奨）と比較して、メモリ効率とGPU転送パフォーマンスが大幅に向上する。

**業務上の目的・背景**：WebGL/WebGPUでは、GPUとの間で頂点データを効率的にやり取りすることがパフォーマンスの鍵となる。BufferGeometryは、頂点データをGPUバッファに直接マッピング可能な形式で保持することで、レンダリングパフォーマンスを最大化する。これは特に、大量のポリゴンを持つ複雑なモデルや、頻繁に頂点を更新するアニメーションにおいて重要となる。

**機能の利用シーン**：
- 3Dモデルのインポート時にジオメトリデータを格納する場面
- プロシージャルにジオメトリを生成する場面（地形、パーティクル等）
- 頂点シェーダーでカスタム属性を使用する場面
- モーフターゲットアニメーションを実装する場面
- 境界ボックス/球を計算してカリングを最適化する場面

**主要な処理内容**：
1. **頂点属性管理**: setAttribute()、getAttribute()、deleteAttribute()による頂点属性の管理
2. **インデックスバッファ**: setIndex()、getIndex()によるインデックス付きジオメトリの管理
3. **グループ管理**: addGroup()、clearGroups()によるマテリアルグループの管理
4. **境界計算**: computeBoundingBox()、computeBoundingSphere()による境界ボリュームの計算
5. **法線・接線計算**: computeVertexNormals()、computeTangents()による頂点法線・接線の自動計算
6. **変換適用**: applyMatrix4()、translate()、rotateX/Y/Z()、scale()によるジオメトリ変換
7. **シリアライズ**: toJSON()によるJSON形式でのシリアライズ

**関連システム・外部連携**：
- BufferAttributeクラスによる個別属性データの管理
- WebGLRenderer/WebGPURendererによるGPUバッファへのアップロード
- Mesh、Line、Pointsなどのレンダラブルオブジェクトからの参照
- ローダー（GLTFLoader、OBJLoader等）からのジオメトリ生成

**権限による制御**：特になし（ライブラリレベルの機能のため、アプリケーション側での権限管理は行わない）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | Sidebar - Geometry | 主機能 | 選択オブジェクトのジオメトリ情報表示・編集 |
| 21 | WebGL基本サンプル | 補助機能 | ジオメトリデータの管理 |
| 23 | WebGL上級サンプル | 主機能 | カスタムジオメトリの構築 |
| 40 | ユニットテスト | 主機能 | BufferGeometryクラスのテスト |

## 機能種別

データ管理 / 計算処理 / シリアライズ

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| attributes | Object | No | 頂点属性の辞書 | キーは属性名、値はBufferAttribute |
| index | BufferAttribute/Array | No | インデックスバッファ | Uint16またはUint32 |
| groups | Array | No | マテリアルグループ | start, count, materialIndexを持つオブジェクト配列 |
| morphAttributes | Object | No | モーフターゲット属性 | キーは属性名、値はBufferAttribute配列 |
| morphTargetsRelative | boolean | No | モーフターゲットの相対モード | デフォルト: false |
| drawRange | Object | No | 描画範囲 | start, countを持つオブジェクト |
| boundingBox | Box3 | No | 境界ボックス | null可（計算で取得） |
| boundingSphere | Sphere | No | 境界球 | null可（計算で取得） |

### 入力データソース

- プログラムコードによる直接設定
- GLTFLoader、OBJLoader等からのジオメトリデータ
- BufferGeometryLoaderによるJSONデシリアライズ
- 各種Geometryクラス（BoxGeometry等）からの継承

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | number | 一意のID（自動採番） |
| uuid | string | UUID |
| attributes | Object | 頂点属性の辞書 |
| index | BufferAttribute | インデックスバッファ |
| groups | Array | マテリアルグループ |
| boundingBox | Box3 | 計算された境界ボックス |
| boundingSphere | Sphere | 計算された境界球 |

### 出力先

- WebGLRenderer/WebGPURendererへの頂点データ提供
- シリアライズ時のJSONオブジェクト
- disposeイベントによるリソース解放通知

## 処理フロー

### 処理シーケンス

```
1. コンストラクタ呼び出し
   └─ EventDispatcherの初期化
   └─ プロパティの初期化（attributes, index, groups等）
   └─ id, uuidの生成

2. 属性設定
   └─ setAttribute(name, attribute)
   └─ attributes辞書への登録

3. インデックス設定
   └─ setIndex(index)
   └─ 配列の場合はUint16/Uint32BufferAttributeに変換

4. 境界計算
   └─ computeBoundingBox()
       └─ position属性からBox3を計算
       └─ モーフターゲットも考慮
   └─ computeBoundingSphere()
       └─ position属性からSphereを計算

5. 法線計算
   └─ computeVertexNormals()
       └─ 面法線の計算
       └─ 共有頂点では法線を平均化

6. 変換適用
   └─ applyMatrix4(matrix)
       └─ position属性に行列適用
       └─ normal属性に法線行列適用
       └─ 境界の再計算

7. シリアライズ
   └─ toJSON()
       └─ index, attributes, morphAttributes等をJSON化

8. 破棄
   └─ dispose()
       └─ disposeイベント発行
```

### フローチャート

```mermaid
flowchart TD
    A[BufferGeometry生成] --> B[属性設定]
    B --> C{インデックス必要?}
    C -->|Yes| D[setIndex]
    C -->|No| E[境界計算]
    D --> E
    E --> F[computeBoundingBox]
    F --> G[computeBoundingSphere]
    G --> H{法線必要?}
    H -->|Yes| I[computeVertexNormals]
    H -->|No| J{変換適用?}
    I --> J
    J -->|Yes| K[applyMatrix4]
    K --> L[境界再計算]
    L --> J
    J -->|No| M{レンダリング}
    M -->|Yes| N[GPUへアップロード]
    N --> M
    M -->|No| O{破棄?}
    O -->|Yes| P[dispose]
    P --> Q[イベント発行]
    O -->|No| B
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | インデックス型自動選択 | 頂点数に応じてUint16/Uint32を自動選択 | setIndex()で配列を渡した場合 |
| BR-02 | 境界の遅延計算 | boundingBox/Sphereはnullで初期化、必要時に計算 | computeBounding*()呼び出し時 |
| BR-03 | 法線自動正規化 | computeVertexNormals()後に自動で正規化 | computeVertexNormals()実行時 |
| BR-04 | モーフターゲット考慮 | 境界計算時にモーフターゲットも含める | morphAttributes存在時 |
| BR-05 | グループ排他 | 各頂点/インデックスは1つのグループにのみ属する | addGroup()使用時 |

### 計算ロジック

**境界ボックスの計算:**
```javascript
boundingBox.setFromBufferAttribute(position);
// モーフターゲットがある場合は拡張
for (morphAttribute of morphAttributesPosition) {
    if (morphTargetsRelative) {
        boundingBox.expandByPoint(boundingBox.min + morphBox.min);
        boundingBox.expandByPoint(boundingBox.max + morphBox.max);
    } else {
        boundingBox.expandByPoint(morphBox.min);
        boundingBox.expandByPoint(morphBox.max);
    }
}
```

**頂点法線の計算:**
```javascript
// 面法線を計算: cb = (C - B) x (A - B)
cb.subVectors(pC, pB);
ab.subVectors(pA, pB);
cb.cross(ab);
// 各頂点に加算（共有頂点では平均化）
nA.add(cb); nB.add(cb); nC.add(cb);
// 最後に正規化
normalizeNormals();
```

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

### 操作別データベース影響一覧

該当なし（BufferGeometryはデータベースを使用しない）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | エラー | computeTangents()で必要な属性がない | コンソールにエラー出力 |
| - | 警告 | setFromPoints()でバッファサイズ不足 | 警告出力、部分更新 |
| - | エラー | GLBufferAttributeで境界計算を試みた | 手動設定を促すエラー出力 |
| - | エラー | boundingBoxにNaN値が含まれる | position属性の確認を促すエラー出力 |

### リトライ仕様

該当なし

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

該当なし（メモリ上のオブジェクト操作のみ）

## パフォーマンス要件

- 大規模ジオメトリ（100万頂点以上）でも効率的に動作する必要がある
- computeVertexNormals()はO(n)の計算量（nは頂点数）
- 境界計算は初回のみ実行し、結果をキャッシュ
- 頂点データ変更時はneedsUpdate=trueで部分更新可能

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

該当なし（クライアントサイドのグラフィックスライブラリ）

## 備考

- TypedArray以外の通常配列を渡すとエラーとなる（BufferAttributeコンストラクタで検証）
- モーフターゲットデータはレンダリング後に変更不可（新規ジオメトリが必要）

---

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

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

### 推奨読解順序

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

BufferGeometryが管理するデータの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | BufferAttribute.js | `src/core/BufferAttribute.js` | 個別属性データの構造、TypedArrayの管理方法 |
| 1-2 | Box3.js | `src/math/Box3.js` | 境界ボックスの構造 |
| 1-3 | Sphere.js | `src/math/Sphere.js` | 境界球の構造 |

**読解のコツ**: BufferGeometryのattributesプロパティは、属性名をキー、BufferAttributeを値とするオブジェクト。position、normal、uv、colorなどが標準的な属性名。

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

BufferGeometryクラスの基本構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | BufferGeometry.js | `src/core/BufferGeometry.js` | コンストラクタでのプロパティ初期化 |

**主要処理フロー**:
1. **53-198行目**: コンストラクタ - プロパティ初期化
2. **73行目**: 自動採番ID生成
3. **81行目**: UUID生成
4. **101行目**: indexの初期化（null）
5. **131行目**: attributesの初期化（空オブジェクト）
6. **164行目**: groupsの初期化（空配列）

#### Step 3: 属性管理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | BufferGeometry.js | `src/core/BufferGeometry.js` | setAttribute(), getAttribute(), deleteAttribute() |

**主要処理フロー**:
- **267-270行目**: getAttribute() - 属性の取得
- **280-286行目**: setAttribute() - 属性の設定
- **294-300行目**: deleteAttribute() - 属性の削除
- **308-312行目**: hasAttribute() - 属性の存在確認

#### Step 4: インデックス管理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | BufferGeometry.js | `src/core/BufferGeometry.js` | setIndex(), getIndex() |

**主要処理フロー**:
- **205-209行目**: getIndex() - インデックスの取得
- **217-231行目**: setIndex() - インデックスの設定（配列の場合は自動変換）

#### Step 5: 境界計算を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | BufferGeometry.js | `src/core/BufferGeometry.js` | computeBoundingBox(), computeBoundingSphere() |

**主要処理フロー**:
- **628-696行目**: computeBoundingBox() - 境界ボックス計算
- **703-813行目**: computeBoundingSphere() - 境界球計算
- **658-682行目**: モーフターゲットを考慮した境界拡張

#### Step 6: 法線計算を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | BufferGeometry.js | `src/core/BufferGeometry.js` | computeVertexNormals(), normalizeNormals() |

**主要処理フロー**:
- **987-1077行目**: computeVertexNormals() - 頂点法線の計算
- **1019-1047行目**: インデックス付きジオメトリの法線計算
- **1051-1067行目**: 非インデックスジオメトリの法線計算
- **1083-1097行目**: normalizeNormals() - 法線の正規化

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

```
BufferGeometry (extends EventDispatcher)
    │
    ├─ constructor()
    │      ├─ super() → EventDispatcher
    │      ├─ generateUUID()
    │      └─ プロパティ初期化
    │
    ├─ setAttribute(name, attribute)
    │      └─ this.attributes[name] = attribute
    │
    ├─ setIndex(index)
    │      ├─ arrayNeedsUint32(index)
    │      └─ Uint32BufferAttribute / Uint16BufferAttribute
    │
    ├─ computeBoundingBox()
    │      ├─ new Box3()
    │      ├─ boundingBox.setFromBufferAttribute(position)
    │      └─ モーフターゲット処理
    │
    ├─ computeBoundingSphere()
    │      ├─ new Sphere()
    │      ├─ _box.setFromBufferAttribute(position)
    │      └─ 半径計算
    │
    ├─ computeVertexNormals()
    │      ├─ 面法線計算
    │      ├─ 頂点法線蓄積
    │      └─ normalizeNormals()
    │
    ├─ applyMatrix4(matrix)
    │      ├─ position.applyMatrix4(matrix)
    │      ├─ normal.applyNormalMatrix()
    │      └─ 境界再計算
    │
    └─ dispose()
           └─ dispatchEvent({ type: 'dispose' })
```

### データフロー図

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

Float32Array ──┐
(positions)    │
               │
Float32Array ──┼─→ setAttribute() ──→ attributes{} ───┐
(normals)      │                                       │
               │                                       ↓
Float32Array ──┘                                  ┌─────────┐
(uvs)                                             │Renderer │
                                                  │         │
Uint16/32Array → setIndex() ────→ index ─────────│ GPU     │
                                                  │ Buffer  │
                    ┌─────────────┐               └─────────┘
attributes{} ──────→│computeBound│
                    │  ingBox()  │──→ boundingBox ──→ Frustum
                    └─────────────┘                    Culling

                    ┌─────────────┐
attributes{} ──────→│computeVertex│
(positions)         │  Normals()  │──→ normal属性 ──→ Lighting
                    └─────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| BufferGeometry.js | `src/core/BufferGeometry.js` | ソース | BufferGeometryクラス本体 |
| BufferAttribute.js | `src/core/BufferAttribute.js` | ソース | 頂点属性データ管理 |
| EventDispatcher.js | `src/core/EventDispatcher.js` | ソース | イベント機能の基底クラス |
| Box3.js | `src/math/Box3.js` | ソース | 境界ボックス |
| Sphere.js | `src/math/Sphere.js` | ソース | 境界球 |
| Vector3.js | `src/math/Vector3.js` | ソース | 3次元ベクトル |
| Vector2.js | `src/math/Vector2.js` | ソース | 2次元ベクトル（UV座標用） |
| Matrix4.js | `src/math/Matrix4.js` | ソース | 変換行列 |
| Matrix3.js | `src/math/Matrix3.js` | ソース | 法線行列 |
| MathUtils.js | `src/math/MathUtils.js` | ソース | UUID生成などのユーティリティ |
