# 機能設計書: スケルトン/ボーン

## 1. 機能概要

### 1.1 機能名
Skeleton3D - 骨格アニメーション

### 1.2 機能説明
Skeleton3Dは、3Dキャラクターの骨格（スケルトン）構造を管理し、ボーン（骨）の階層的な変形をサポートするノードである。メッシュをボーンにバインドすることでスキニング（皮膚変形）を実現し、アニメーションプレイヤーと連携してキャラクターアニメーションを実行する。ボーンの姿勢（ポーズ）は位置・回転・スケールで構成され、親子関係に基づいて伝播する。

### 1.3 関連画面
- 3Dビューポート（スケルトン表示）
- インスペクターパネル（ボーンプロパティ）

## 2. 機能詳細

### 2.1 主要機能一覧

| 機能ID | 機能名 | 説明 |
|--------|--------|------|
| F34-01 | ボーン階層管理 | 親子関係を持つボーンツリーの構築 |
| F34-02 | ポーズ制御 | ボーンごとの位置・回転・スケール設定 |
| F34-03 | レストポーズ | 初期姿勢の定義と管理 |
| F34-04 | スキンバインド | メッシュとスケルトンの関連付け |
| F34-05 | グローバルポーズ計算 | ワールド空間でのボーン変換行列計算 |
| F34-06 | モディファイア | 外部からのポーズ修正（IK等）のサポート |
| F34-07 | モーションスケール | アニメーションの移動量スケーリング |

### 2.2 クラス構造

```
Node3D
    └── Skeleton3D
            │
            ├── Bone (内部構造体)
            │       ├── name: String
            │       ├── parent: int
            │       ├── rest: Transform3D
            │       ├── pose_position: Vector3
            │       ├── pose_rotation: Quaternion
            │       └── pose_scale: Vector3
            │
            ├── SkinReference (スキン参照)
            │
            └── SkeletonModifier3D (モディファイア基底)
                    ├── SkeletonIK3D
                    └── CCDIK3D
```

### 2.3 主要プロパティ

| プロパティ名 | 型 | デフォルト値 | 説明 |
|-------------|-----|-------------|------|
| motion_scale | float | 1.0 | モーションスケール係数 |
| show_rest_only | bool | false | レストポーズのみ表示 |
| modifier_callback_mode_process | int | IDLE | モディファイア処理タイミング |

### 2.4 主要メソッド

| メソッド名 | 戻り値 | 説明 |
|-----------|--------|------|
| add_bone(name) | int | ボーンを追加 |
| find_bone(name) | int | ボーン名からインデックスを取得 |
| get_bone_name(bone_idx) | String | ボーン名を取得 |
| set_bone_name(bone_idx, name) | void | ボーン名を設定 |
| get_bone_parent(bone_idx) | int | 親ボーンインデックスを取得 |
| set_bone_parent(bone_idx, parent_idx) | void | 親ボーンを設定 |
| get_bone_count() | int | ボーン数を取得 |
| get_bone_rest(bone_idx) | Transform3D | レストポーズを取得 |
| set_bone_rest(bone_idx, rest) | void | レストポーズを設定 |
| get_bone_global_rest(bone_idx) | Transform3D | グローバルレストポーズを取得 |
| get_bone_pose(bone_idx) | Transform3D | ローカルポーズを取得 |
| set_bone_pose(bone_idx, pose) | void | ローカルポーズを設定 |
| get_bone_pose_position(bone_idx) | Vector3 | ポーズ位置を取得 |
| set_bone_pose_position(bone_idx, position) | void | ポーズ位置を設定 |
| get_bone_pose_rotation(bone_idx) | Quaternion | ポーズ回転を取得 |
| set_bone_pose_rotation(bone_idx, rotation) | void | ポーズ回転を設定 |
| get_bone_pose_scale(bone_idx) | Vector3 | ポーズスケールを取得 |
| set_bone_pose_scale(bone_idx, scale) | void | ポーズスケールを設定 |
| get_bone_global_pose(bone_idx) | Transform3D | グローバルポーズを取得 |
| set_bone_global_pose(bone_idx, pose) | void | グローバルポーズを設定 |
| reset_bone_pose(bone_idx) | void | ポーズをリセット |
| reset_bone_poses() | void | 全ボーンのポーズをリセット |
| is_bone_enabled(bone_idx) | bool | ボーンが有効か確認 |
| set_bone_enabled(bone_idx, enabled) | void | ボーンの有効/無効を設定 |
| clear_bones() | void | 全ボーンをクリア |
| create_skin_from_rest_transforms() | Skin | レストポーズからスキンを生成 |
| register_skin(skin) | SkinReference | スキンを登録 |
| force_update_all_bone_transforms() | void | 全ボーン変換を強制更新 |

### 2.5 Bone構造体の詳細

| フィールド名 | 型 | 説明 |
|-------------|-----|------|
| name | String | ボーン名 |
| parent | int | 親ボーンインデックス（-1でルート） |
| child_bones | Vector<int> | 子ボーンインデックス配列 |
| rest | Transform3D | レストポーズ（ローカル） |
| global_rest | Transform3D | グローバルレストポーズ |
| enabled | bool | ボーン有効フラグ |
| pose_cache_dirty | bool | ポーズキャッシュ更新フラグ |
| pose_cache | Transform3D | キャッシュされたポーズ |
| pose_position | Vector3 | ポーズ位置 |
| pose_rotation | Quaternion | ポーズ回転 |
| pose_scale | Vector3 | ポーズスケール |
| global_pose | Transform3D | グローバルポーズ |

### 2.6 シグナル

| シグナル名 | 引数 | 説明 |
|-----------|------|------|
| bone_pose_changed | bone_idx: int | ボーンポーズ変更時 |
| skeleton_updated | なし | スケルトン更新時（NOTIFICATION_UPDATE_SKELETON） |

## 3. 処理フロー

### 3.1 ボーンポーズ更新フロー

```
[アニメーション/スクリプトからポーズ設定]
      │
      ├─ set_bone_pose_position()
      ├─ set_bone_pose_rotation()
      └─ set_bone_pose_scale()
      │
      ▼
[pose_cache_dirty = true]
      │
      ▼
[_notification(NOTIFICATION_UPDATE_SKELETON)]
      │
      ▼
[_update_deferred()]
      │
      ├─ [モディファイア処理] (IK等)
      │       └─ _process_modifiers()
      │
      └─ [ボーン変換更新]
              │
              ▼
[_force_update_all_bone_transforms()]
      │
      ├─ [ルートボーンから順に処理]
      │       │
      │       └─ [各ボーン: global_pose = parent.global_pose * local_pose]
      │
      └─ [スキンバインド更新]
              └─ RenderingServer::skeleton_bone_set_transform()
```

### 3.2 グローバルポーズ計算フロー

```
[get_bone_global_pose(bone_idx)]
      │
      ▼
[bone_global_pose_dirty[bone_idx] チェック]
      │
      ├─ dirty → [_update_bone_global_pose()]
      │               │
      │               ▼
      │         [親のglobal_poseを取得（再帰）]
      │               │
      │               ▼
      │         [global_pose = parent_global * local_pose]
      │               │
      │               ▼
      │         [bone_global_pose_dirty[bone_idx] = false]
      │
      └─ clean → [キャッシュ値を返却]
```

### 3.3 データフロー図

```
[AnimationPlayer/AnimationTree]
        │
        │ set_bone_pose_*()
        ▼
┌───────────────────────────────────────┐
│            Skeleton3D                  │
│                                        │
│  ┌────────────────────────────┐       │
│  │     Bone Array             │       │
│  │  ┌─────┐ ┌─────┐ ┌─────┐  │       │
│  │  │Bone0│→│Bone1│→│Bone2│  │       │
│  │  │(root)│ │(child)│(child)││       │
│  │  └─────┘ └─────┘ └─────┘  │       │
│  └────────────────────────────┘       │
│            │                          │
│            ▼                          │
│  ┌────────────────────────────┐       │
│  │   Global Pose Calculation   │       │
│  │   (親子階層に基づく伝播)    │       │
│  └────────────────────────────┘       │
└───────────────────────────────────────┘
        │
        ▼ skin_bone_indices
┌───────────────────────────────────────┐
│          SkinReference                 │
│  - skeleton (RID)                     │
│  - bind_count                         │
└───────────────────────────────────────┘
        │
        ▼ RenderingServer
┌───────────────────────────────────────┐
│          MeshInstance3D               │
│  (スキニングされたメッシュ描画)       │
└───────────────────────────────────────┘
```

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

### 4.1 推奨読解順序

1. **データ構造の理解**
   - `scene/3d/skeleton_3d.h` (31-322行目): Skeleton3Dクラス定義
   - `scene/3d/skeleton_3d.h` (99-134行目): Bone構造体定義

2. **エントリーポイント**
   - `skeleton_3d.cpp` **_bind_methods()**: GDScriptバインディング
   - `skeleton_3d.cpp` **_notification()**: ライフサイクル処理

3. **コア処理**
   - `skeleton_3d.cpp` **_force_update_all_bone_transforms()**: ボーン変換更新
   - `skeleton_3d.cpp` **_update_bone_global_pose()**: グローバルポーズ計算

### 4.2 重要な処理ポイント

#### Bone構造体の定義（skeleton_3d.h: 99-134行目）
```cpp
struct Bone {
    String name;
    int parent = -1;
    Vector<int> child_bones;
    Transform3D rest;
    Transform3D global_rest;
    bool enabled = true;
    bool pose_cache_dirty = true;
    Transform3D pose_cache;
    Vector3 pose_position;
    Quaternion pose_rotation;
    Vector3 pose_scale = Vector3(1, 1, 1);
    Transform3D global_pose;
    // ...
};
```

#### ポーズキャッシュ更新（skeleton_3d.h: 118-124行目）
```cpp
void update_pose_cache() {
    if (pose_cache_dirty) {
        pose_cache.basis.set_quaternion_scale(pose_rotation, pose_scale);
        pose_cache.origin = pose_position;
        pose_cache_dirty = false;
    }
}
```

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

```
Skeleton3D::set_bone_pose_position()
    │
    └── Skeleton3D::_make_dirty()
            └── _update_deferred(UPDATE_FLAG_POSE)

Skeleton3D::_notification(NOTIFICATION_INTERNAL_PROCESS)
    │
    └── Skeleton3D::_update_deferred()
            │
            ├── _process_modifiers()
            │       └── [各SkeletonModifier3D].process_modification()
            │
            └── _force_update_all_bone_transforms()
                    │
                    ├── _update_process_order()
                    │
                    └── [各ボーンを順番に処理]
                            │
                            ├── bones[i].update_pose_cache()
                            │
                            └── _update_bone_global_pose(i)
                                    │
                                    ├── parent.global_pose取得
                                    │
                                    └── global_pose = parent_global * local_pose

Skeleton3D::register_skin(skin)
    │
    └── SkinReference::_skin_changed()
            │
            └── RenderingServer::skeleton_bone_set_transform()
```

### 4.4 関連ファイル一覧

| ファイルパス | 種別 | 役割 |
|-------------|------|------|
| scene/3d/skeleton_3d.h | ヘッダー | Skeleton3Dクラス定義 |
| scene/3d/skeleton_3d.cpp | 実装 | Skeleton3D実装 |
| scene/resources/3d/skin.h | ヘッダー | Skinリソース定義 |
| scene/resources/3d/skin.cpp | 実装 | スキンバインド情報 |
| servers/rendering/rendering_server_default.h | ヘッダー | スケルトンRID管理 |

## 5. 設計上の考慮事項

### 5.1 パフォーマンス
- nested_set_offset/nested_set_spanによる効率的なサブツリー更新
- ポーズキャッシュによる不要な行列計算の回避
- 遅延更新（_update_deferred）によるバッチ処理

### 5.2 精度
- Quaternionによる回転表現でジンバルロック回避
- グローバルポーズの遅延計算で整合性確保

### 5.3 拡張性
- SkeletonModifier3Dによるモディファイアシステム
- IK、物理シミュレーション等の外部システムとの連携

## 6. 使用例

### 6.1 ボーン情報の取得
```gdscript
@onready var skeleton = $Skeleton3D

func _ready():
    # ボーン数の取得
    var bone_count = skeleton.get_bone_count()
    print("Bone count: ", bone_count)

    # ボーン名からインデックスを取得
    var head_idx = skeleton.find_bone("Head")
    print("Head bone index: ", head_idx)

    # ボーンの親子関係
    var parent_idx = skeleton.get_bone_parent(head_idx)
    var parent_name = skeleton.get_bone_name(parent_idx)
    print("Head's parent: ", parent_name)
```

### 6.2 ボーンポーズの操作
```gdscript
func look_at_target(target_position: Vector3):
    var head_idx = skeleton.find_bone("Head")

    # 現在のグローバルポーズを取得
    var global_pose = skeleton.get_bone_global_pose(head_idx)

    # ターゲット方向への回転を計算
    var direction = (target_position - global_pose.origin).normalized()
    var new_rotation = Quaternion(Vector3.FORWARD, direction)

    # ローカル回転に変換して設定
    var parent_global = skeleton.get_bone_global_pose(skeleton.get_bone_parent(head_idx))
    var local_rotation = parent_global.basis.inverse() * Basis(new_rotation)
    skeleton.set_bone_pose_rotation(head_idx, local_rotation.get_rotation_quaternion())
```

### 6.3 プロシージャルアニメーション
```gdscript
func _process(delta):
    # 呼吸アニメーション
    var chest_idx = skeleton.find_bone("Chest")
    var breath = sin(Time.get_ticks_msec() * 0.002) * 0.02 + 1.0
    skeleton.set_bone_pose_scale(chest_idx, Vector3(breath, breath, breath))
```

## 7. 関連機能
- [No.31 AnimationPlayer](./31-AnimationPlayer.md) - アニメーション再生
- [No.35 IK（逆運動学）](./35-IK.md) - インバースキネマティクス
