# 機能設計書 86-Skeleton

## 概要

本ドキュメントは、Three.jsにおけるスケルトン（骨格）構造を管理する `Skeleton` クラスの機能設計を定義する。Skeletonはボーン（Bone）の階層構造を保持し、SkinnedMeshのスキニングアニメーションに必要なボーン行列データを管理する。

### 本機能の処理概要

Skeletonクラスは、複数のBoneオブジェクトとそれらの逆行列（boneInverses）を管理し、GPUに送信するためのボーン行列データを生成する。ボーンテクスチャを使用してシェーダーにボーンデータを効率的に渡すことができる。

**業務上の目的・背景**：スケルタルアニメーションを実現するために、ボーンの階層構造と変換行列を一元管理する必要がある。SkinnedMeshがスキニングを行う際に、各ボーンの現在の変換とバインドポーズからのオフセットを計算するために使用される。

**機能の利用シーン**：
- キャラクターアニメーションの骨格管理
- 複数メッシュで共有するスケルトン
- ボーン名による検索（getBoneByName）
- アニメーションデータのバインド先
- GPUスキニング用のボーンテクスチャ生成

**主要な処理内容**：
1. ボーン配列とボーン逆行列の管理
2. ボーン逆行列の自動計算
3. ボーン行列のフラット化（GPUテクスチャ用）
4. ボーンテクスチャの生成と更新
5. バインドポーズへのリセット

**関連システム・外部連携**：SkinnedMesh、Bone、DataTexture、AnimationMixerと連携。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 37 | Bones Browser | 主機能 | スケルトン構造の表示 |

## 機能種別

データ管理 / GPUテクスチャ生成

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| bones | Array\<Bone\> | No | ボーン配列（デフォルト: []） | - |
| boneInverses | Array\<Matrix4\> | No | ボーン逆行列配列（デフォルト: []） | 長さがbonesと一致推奨 |

### 入力データソース

- Bone配列: 階層構造を持つボーンオブジェクト
- AnimationClip: ボーンアニメーションデータ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| uuid | string | スケルトンのUUID |
| bones | Array\<Bone\> | ボーン配列 |
| boneInverses | Array\<Matrix4\> | ボーン逆行列配列 |
| boneMatrices | Float32Array | GPU送信用のフラット化行列 |
| previousBoneMatrices | Float32Array\|null | 前フレームのボーン行列（モーションブラー用） |
| boneTexture | DataTexture\|null | ボーンテクスチャ |

### 出力先

SkinnedMeshのスキニング処理、およびGPUシェーダーに送信。

## 処理フロー

### 処理シーケンス

```
1. コンストラクタ呼び出し
   └─ bones/boneInversesの設定、init()呼び出し
2. init()
   └─ boneMatricesの確保、必要に応じてcalculateInverses()
3. calculateInverses()
   └─ 各ボーンのmatrixWorldから逆行列を計算
4. update()
   └─ 各ボーンのオフセット行列を計算、boneMatricesに格納
5. computeBoneTexture()
   └─ DataTextureとしてボーン行列をGPUに送信
```

### フローチャート

```mermaid
flowchart TD
    A[Skeleton生成] --> B[bones/boneInverses設定]
    B --> C[init呼び出し]
    C --> D[boneMatrices確保]
    D --> E{boneInverses空?}
    E -->|Yes| F[calculateInverses呼び出し]
    E -->|No| G{bones数と一致?}
    G -->|No| H[警告出力、空Matrix4で埋める]
    G -->|Yes| I[初期化完了]
    F --> I
    H --> I
    I --> J[update呼び出し]
    J --> K[各ボーンのオフセット行列計算]
    K --> L[boneMatricesに格納]
    L --> M{boneTexture存在?}
    M -->|Yes| N[needsUpdate=true]
    M -->|No| O[処理終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-86-01 | 逆行列自動計算 | boneInversesが空の場合、自動計算される | コンストラクタ/init時 |
| BR-86-02 | 配列長不一致警告 | bones数とboneInverses数が異なると警告 | init時 |
| BR-86-03 | テクスチャサイズ | 4の倍数、最小4x4で必要十分なサイズ | computeBoneTexture時 |
| BR-86-04 | オフセット行列 | offset = bone.matrixWorld * boneInverse | update時 |

### 計算ロジック

ボーンテクスチャサイズの計算:
```javascript
// 1行列 = 4ピクセル（RGBA × 4列）
let size = Math.sqrt(bones.length * 4);
size = Math.ceil(size / 4) * 4;  // 4の倍数に切り上げ
size = Math.max(size, 4);         // 最小4
```

オフセット行列の計算:
```javascript
offsetMatrix.multiplyMatrices(bone.matrixWorld, boneInverse);
```

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 警告 | bones数とboneInverses数の不一致 | コンソールに警告、空Matrix4で補完 |
| - | 警告 | fromJSON時にボーンが見つからない | 新規Boneで代替 |

### リトライ仕様

特になし

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

該当なし

## パフォーマンス要件

- boneMatricesはFloat32Arrayで効率的なメモリレイアウト
- boneTextureはGPUに直接送信可能
- update()は毎フレーム呼び出されるため軽量設計

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

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

## 備考

- dispose()でboneTextureを解放
- clone()でボーンと逆行列をコピー
- toJSON()/fromJSON()でシリアライズ対応

---

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

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

### 推奨読解順序

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

Skeletonが管理するデータを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Skeleton.js | `src/objects/Skeleton.js` | プロパティ定義（bones, boneInverses, boneMatrices） |
| 1-2 | Bone.js | `src/objects/Bone.js` | Boneオブジェクトの構造 |
| 1-3 | DataTexture.js | `src/textures/DataTexture.js` | ボーンテクスチャの実体 |

**読解のコツ**: boneMatricesは16要素（4x4行列）× ボーン数のFloat32Array。

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

Skeletonクラスのメソッドを理解する。

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

**主要処理フロー**:
1. **46-93行目**: コンストラクタでプロパティ初期化、init()呼び出し
2. **100-133行目**: init()でboneMatrices確保、boneInverses検証
3. **139-157行目**: calculateInverses()で逆行列計算
4. **208-234行目**: update()でオフセット行列計算
5. **252-276行目**: computeBoneTexture()でGPUテクスチャ生成

#### Step 3: シリアライズを理解する

JSON形式でのデータ保存・復元を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Skeleton.js | `src/objects/Skeleton.js` | toJSON, fromJSON |

**主要処理フロー**:
- **326-351行目**: fromJSON()でUUIDからボーンを復元
- **359-388行目**: toJSON()でシリアライズ

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

```
Skeleton
    │
    ├─ bones[] (Bone配列)
    │      └─ Object3D (継承)
    │             └─ matrixWorld (ワールド行列)
    │
    ├─ boneInverses[] (Matrix4配列)
    │      └─ バインドポーズの逆行列
    │
    ├─ boneMatrices (Float32Array)
    │      └─ GPU送信用フラット化行列
    │
    ├─ boneTexture (DataTexture)
    │      └─ RGBAFormat, FloatType
    │
    ├─ init()
    │      └─ boneMatrices確保、boneInverses検証
    │
    ├─ calculateInverses()
    │      └─ bone.matrixWorld.invert()
    │
    ├─ update()
    │      └─ オフセット行列計算、boneMatrices更新
    │
    ├─ pose()
    │      └─ バインドポーズに戻す
    │
    └─ computeBoneTexture()
           └─ DataTexture生成、boneMatrices設定
```

### データフロー図

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

Bone[] ──────────────▶ Skeleton Constructor ──▶ Skeleton Object
(階層構造あり)                │                      │
                              │                      ├─ uuid
Matrix4[] ───────────────────┘                      ├─ bones[]
(boneInverses、省略可)                               ├─ boneInverses[]
                                                     ├─ boneMatrices
                                                     └─ boneTexture: null

bone.matrixWorld ────▶ update() ─────────────▶ boneMatrices更新
boneInverses              │                      boneTexture.needsUpdate
                          │
                          └─ offsetMatrix = matrixWorld * boneInverse

Skeleton ────────────▶ computeBoneTexture() ─▶ DataTexture
boneMatrices                  │                  (size x size, RGBA, Float)
                              │
                              └─ テクスチャサイズ計算、DataTexture生成
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Skeleton.js | `src/objects/Skeleton.js` | ソース | スケルトンのメインクラス |
| Bone.js | `src/objects/Bone.js` | ソース | ボーンクラス |
| DataTexture.js | `src/textures/DataTexture.js` | ソース | ボーンテクスチャ |
| Matrix4.js | `src/math/Matrix4.js` | ソース | 行列変換 |
| MathUtils.js | `src/math/MathUtils.js` | ソース | UUID生成 |
| constants.js | `src/constants.js` | ソース | RGBAFormat, FloatType定義 |
