# 機能設計書 3-BufferAttribute

## 概要

本ドキュメントは、Three.jsライブラリにおける頂点属性データを管理するBufferAttributeクラスの機能設計について記述する。BufferAttributeは、BufferGeometryで使用される頂点位置、法線、UV座標、頂点色などの属性データをTypedArrayとして効率的に管理し、GPUへのデータ転送を最適化する。

### 本機能の処理概要

BufferAttributeクラスは、頂点属性データ（位置、法線、UV、色など）をTypedArray形式で保持し、個々の頂点データへのアクセス・変更メソッドを提供する。また、データの正規化、行列変換、シリアライズなどの機能も備える。

**業務上の目的・背景**：3Dグラフィックスでは、各頂点に対して複数の属性（位置、法線、テクスチャ座標など）を関連付ける必要がある。BufferAttributeは、これらの属性データをGPUが直接読み取れる形式（TypedArray）で管理し、WebGL/WebGPUのバッファオブジェクトとシームレスに連携することで、高パフォーマンスなレンダリングを実現する。特に大量の頂点を持つモデルでは、この効率的なデータ管理が不可欠となる。

**機能の利用シーン**：
- BufferGeometryに頂点属性（position、normal、uv等）を設定する場面
- プロシージャルジオメトリ生成で頂点データを動的に作成する場面
- アニメーションで頂点データをリアルタイムに更新する場面
- カスタム頂点属性をシェーダーに渡す場面
- 頂点カラーやスキニングウェイトを設定する場面

**主要な処理内容**：
1. **データ格納**: TypedArrayによる頂点属性データの格納
2. **要素アクセス**: getX/Y/Z/W()、setX/Y/Z/W()、setXYZ()等による個別要素へのアクセス
3. **正規化処理**: normalizedフラグによる整数データの正規化
4. **行列変換**: applyMatrix3()、applyMatrix4()、applyNormalMatrix()による一括変換
5. **更新通知**: needsUpdate、versionによるGPU更新の管理
6. **部分更新**: updateRangesによる効率的な部分更新
7. **シリアライズ**: toJSON()によるJSON形式でのシリアライズ

**関連システム・外部連携**：
- BufferGeometryによる属性の管理
- WebGLRenderer/WebGPURendererによるGPUバッファへのアップロード
- InterleavedBufferAttributeとの共通インターフェース
- シェーダーのattribute変数との対応

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 23 | WebGL上級サンプル | 補助機能 | 頂点属性データの管理 |

## 機能種別

データ管理 / 変換処理 / シリアライズ

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| array | TypedArray | Yes | 属性データを格納する配列 | 通常の配列はエラー |
| itemSize | number | Yes | 1頂点あたりの要素数 | 1-4が一般的 |
| normalized | boolean | No | 整数値を正規化するか | デフォルト: false |
| usage | number | No | バッファの使用パターン | デフォルト: StaticDrawUsage |
| gpuType | number | No | GPU上の型 | デフォルト: FloatType |

### 入力データソース

- プログラムコードによる直接生成
- ローダー（GLTFLoader等）からのデータ
- プロシージャル生成アルゴリズムからの出力

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | number | 一意のID（自動採番） |
| name | string | 属性名 |
| array | TypedArray | 属性データ配列 |
| itemSize | number | 1頂点あたりの要素数 |
| count | number | 頂点数（array.length / itemSize） |
| normalized | boolean | 正規化フラグ |
| version | number | バージョン番号（更新時にインクリメント） |

### 出力先

- BufferGeometryのattributesプロパティ
- WebGL/WebGPUバッファオブジェクト
- シリアライズ時のJSONオブジェクト

## 処理フロー

### 処理シーケンス

```
1. コンストラクタ呼び出し
   └─ TypedArray検証（通常配列はエラー）
   └─ プロパティ初期化（array, itemSize, count, normalized等）
   └─ id生成

2. データ設定
   └─ setXYZ(index, x, y, z) / setXYZW()
   └─ normalizedがtrueの場合は値を正規化
   └─ 配列に値を格納

3. データ取得
   └─ getX(index) / getY(index) / getZ(index) / getW(index)
   └─ normalizedがtrueの場合は非正規化して返す

4. 行列変換
   └─ applyMatrix4(matrix)
       └─ 各頂点に対してmatrix適用
       └─ setXYZ()で結果を格納
   └─ applyNormalMatrix(matrix)
       └─ 各頂点に対して法線行列適用

5. 更新通知
   └─ needsUpdate = true
       └─ version++
   └─ レンダラーがGPUに再アップロード

6. 部分更新
   └─ addUpdateRange(start, count)
       └─ updateRangesに範囲追加
   └─ clearUpdateRanges()
       └─ 範囲をクリア

7. シリアライズ
   └─ toJSON()
       └─ itemSize, type, array, normalizedを出力
```

### フローチャート

```mermaid
flowchart TD
    A[BufferAttribute生成] --> B{TypedArray?}
    B -->|No| C[TypeError]
    B -->|Yes| D[プロパティ初期化]
    D --> E{データ操作}
    E -->|設定| F[setXYZ等]
    F --> G{normalized?}
    G -->|Yes| H[値を正規化]
    G -->|No| I[そのまま格納]
    H --> I
    I --> J[needsUpdate = true]
    J --> E
    E -->|取得| K[getX等]
    K --> L{normalized?}
    L -->|Yes| M[値を非正規化]
    L -->|No| N[そのまま返す]
    M --> N
    N --> E
    E -->|変換| O[applyMatrix4等]
    O --> P[各頂点に変換適用]
    P --> J
    E -->|レンダリング| Q{version変更?}
    Q -->|Yes| R[GPUにアップロード]
    Q -->|No| S[キャッシュ使用]
    R --> T[onUploadCallback]
    T --> E
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | TypedArray必須 | 通常のArrayは使用不可 | コンストラクタ呼び出し時 |
| BR-02 | 正規化マッピング | 整数型でnormalized=trueの場合、値を0-1（符号なし）または-1-1（符号あり）にマッピング | get/set時 |
| BR-03 | バージョン管理 | needsUpdate=trueでversionが自動インクリメント | needsUpdate設定時 |
| BR-04 | 使用パターン不変 | usage（使用パターン）は初回使用後に変更不可 | レンダリング後 |
| BR-05 | Float16自動変換 | Float16BufferAttributeは内部でUint16Arrayとして管理、get/set時に変換 | Float16使用時 |

### 計算ロジック

**正規化処理（normalize）:**
```javascript
// 整数値を0-1または-1-1に正規化してから格納
function normalize(value, array) {
    // array.constructor（Uint8Array, Int16Arrayなど）に応じて正規化
    // Uint8: value / 255
    // Int8: max(value / 127, -1)
    // Uint16: value / 65535
    // 等
}
```

**非正規化処理（denormalize）:**
```javascript
// 正規化された値を元の整数範囲に戻す
function denormalize(value, array) {
    // array.constructor に応じて非正規化
    // Uint8: Math.round(value * 255)
    // Int8: Math.round(value * 127)
    // 等
}
```

**Float16変換:**
```javascript
// Float16BufferAttribute では half float 変換を使用
getX(index) {
    return fromHalfFloat(this.array[index * this.itemSize]);
}
setX(index, x) {
    this.array[index * this.itemSize] = toHalfFloat(x);
}
```

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| TypeError | 例外 | コンストラクタに通常配列を渡した | TypedArrayを使用するよう修正 |

### リトライ仕様

該当なし

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

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

## パフォーマンス要件

- TypedArrayを使用することでメモリ効率とアクセス速度を最適化
- 部分更新（updateRanges）により、変更部分のみGPUにアップロード可能
- StaticDrawUsageの場合、GPUはバッファを最適化してキャッシュ
- DynamicDrawUsageで頻繁な更新に対応

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

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

## 備考

- Float16BufferAttributeはブラウザのFloat16Array非対応を考慮し、Uint16Arrayで内部管理
- onUploadCallbackを使用して、GPU転送後にCPU側のデータをクリーンアップ可能
- 派生クラス（Int8BufferAttribute、Uint8BufferAttribute等）は配列型の自動変換を提供

---

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

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

### 推奨読解順序

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

BufferAttributeの基本構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | BufferAttribute.js | `src/core/BufferAttribute.js` | クラス定義とプロパティ構造 |
| 1-2 | constants.js | `src/constants.js` | StaticDrawUsage、FloatTypeなどの定数定義 |

**読解のコツ**: BufferAttributeはTypedArray（Float32Array、Uint16Array等）を内部に持ち、itemSizeで1頂点あたりの要素数を指定する。count = array.length / itemSize で頂点数を算出。

#### Step 2: コンストラクタを理解する

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

**主要処理フロー**:
1. **29-136行目**: コンストラクタ
2. **31-35行目**: 通常配列の検証（TypeErrorをスロー）
3. **53行目**: id自動採番
4. **68行目**: arrayの設定
5. **77行目**: itemSizeの設定
6. **86行目**: countの計算（array.length / itemSize）
7. **97行目**: normalizedの設定
8. **108行目**: usageのデフォルト（StaticDrawUsage）
9. **127行目**: gpuTypeのデフォルト（FloatType）

#### Step 3: データアクセスメソッドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | BufferAttribute.js | `src/core/BufferAttribute.js` | getX/Y/Z/W(), setX/Y/Z/W(), setXYZ(), setXYZW() |

**主要処理フロー**:
- **416-424行目**: getX() - X成分の取得（正規化考慮）
- **433-441行目**: setX() - X成分の設定（正規化考慮）
- **577-595行目**: setXYZ() - XYZ成分の一括設定
- **607-627行目**: setXYZW() - XYZW成分の一括設定

#### Step 4: 行列変換を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | BufferAttribute.js | `src/core/BufferAttribute.js` | applyMatrix3(), applyMatrix4(), applyNormalMatrix() |

**主要処理フロー**:
- **260-288行目**: applyMatrix3() - itemSize 2または3に対応
- **297-311行目**: applyMatrix4() - 4x4行列の適用
- **320-334行目**: applyNormalMatrix() - 法線行列の適用
- **343-357行目**: transformDirection() - 方向ベクトルの変換

#### Step 5: 更新管理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | BufferAttribute.js | `src/core/BufferAttribute.js` | needsUpdate, version, updateRanges |

**主要処理フロー**:
- **152-156行目**: needsUpdateセッター（version++）
- **178-182行目**: addUpdateRange() - 部分更新範囲の追加
- **187-191行目**: clearUpdateRanges() - 範囲のクリア
- **637-643行目**: onUpload() - アップロード後コールバック設定

#### Step 6: 派生クラスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | BufferAttribute.js | `src/core/BufferAttribute.js` | Int8BufferAttribute, Float32BufferAttribute, Float16BufferAttribute等 |

**主要処理フロー**:
- **685-700行目**: Int8BufferAttribute - Int8Arrayへの自動変換
- **849-1006行目**: Float16BufferAttribute - half float対応
- **1014-1029行目**: Float32BufferAttribute - Float32Arrayへの自動変換

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

```
BufferAttribute
    │
    ├─ constructor(array, itemSize, normalized)
    │      ├─ Array検証 → TypeError
    │      ├─ id自動採番
    │      └─ プロパティ初期化
    │
    ├─ getX(index) / getY() / getZ() / getW()
    │      ├─ array[index * itemSize + offset]
    │      └─ denormalize() [if normalized]
    │
    ├─ setX(index, value) / setY() / setZ() / setW()
    │      ├─ normalize() [if normalized]
    │      └─ array[index * itemSize + offset] = value
    │
    ├─ setXYZ(index, x, y, z)
    │      ├─ normalize() [if normalized]
    │      └─ array設定
    │
    ├─ applyMatrix4(matrix)
    │      ├─ for each vertex:
    │      │      ├─ _vector.fromBufferAttribute(this, i)
    │      │      ├─ _vector.applyMatrix4(matrix)
    │      │      └─ setXYZ(i, _vector.x, _vector.y, _vector.z)
    │      └─ return this
    │
    ├─ needsUpdate = true
    │      └─ version++
    │
    └─ toJSON()
           └─ {itemSize, type, array, normalized}

派生クラス:
├─ Int8BufferAttribute(array, itemSize, normalized)
│      └─ super(new Int8Array(array), itemSize, normalized)
├─ Float16BufferAttribute(array, itemSize, normalized)
│      ├─ super(new Uint16Array(array), itemSize, normalized)
│      └─ getX/setX等をオーバーライド（toHalfFloat/fromHalfFloat使用）
└─ Float32BufferAttribute(array, itemSize, normalized)
       └─ super(new Float32Array(array), itemSize, normalized)
```

### データフロー図

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

TypedArray ────────→ constructor() ────→ BufferAttribute
                          │                    │
                          ↓                    │
                     プロパティ初期化           │
                          │                    │
                          ↓                    ↓
              ┌───────────────────────────────────┐
              │        データアクセス              │
              │                                   │
   値 ────────→ setX/Y/Z/W() ──┐                 │
              │               │                  │
              │         [normalized]             │
              │               ↓                  │
              │         normalize()              │
              │               │                  │
              │               ↓                  │
              │         array[index]             │
              │               │                  │
              │               ↓                  │
              │         getX/Y/Z/W() ────→ 値    │
              │               ↑                  │
              │         denormalize()            │
              │         [normalized]             │
              └───────────────────────────────────┘
                          │
                          ↓
           needsUpdate = true ────→ version++
                          │
                          ↓
              ┌─────────────────────┐
              │ WebGLRenderer/      │
              │ WebGPURenderer      │
              │                     │
              │ GPU Buffer Upload   │
              └─────────────────────┘
                          │
                          ↓
                  onUploadCallback()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| BufferAttribute.js | `src/core/BufferAttribute.js` | ソース | BufferAttributeクラス本体と派生クラス |
| BufferGeometry.js | `src/core/BufferGeometry.js` | ソース | 属性を管理するジオメトリクラス |
| constants.js | `src/constants.js` | ソース | 使用パターン、型の定数定義 |
| MathUtils.js | `src/math/MathUtils.js` | ソース | normalize/denormalize関数 |
| DataUtils.js | `src/extras/DataUtils.js` | ソース | toHalfFloat/fromHalfFloat関数 |
| Vector3.js | `src/math/Vector3.js` | ソース | 行列変換時の一時ベクトル |
| Vector2.js | `src/math/Vector2.js` | ソース | 2D属性の行列変換時 |
