# 🌀 Animation（アニメーション）

FBX ファイル内のアニメーションは、****スタック (**`<strong class="editor-theme-bold editor-theme-code">ufbx_anim_stack</strong>`**)****<span style="white-space: pre-wrap;"> と呼ばれる </span>****レイヤー (**`<strong class="editor-theme-bold editor-theme-code">ufbx_anim_layer</strong>`**)****<span style="white-space: pre-wrap;"> の集合として表現されます。</span>  
各スタックは、ファイル内の 1 つのアニメーションクリップ（または「テイク」）に対応します。

****ufbx****<span style="white-space: pre-wrap;"> ではアニメーションを </span>`<span class="editor-theme-code">ufbx_anim</span>`<span style="white-space: pre-wrap;"> デスクリプタを通して扱います。</span>  
これにより、「複数レイヤーを合成したスタック」か「単一レイヤー」かを  
統一されたインターフェースで選択・評価できます。

### <span style="white-space: pre-wrap;">🔹 </span>`<span class="editor-theme-code">ufbx_anim</span>`<span style="white-space: pre-wrap;"> インスタンスを取得できる場所</span>

- `<span class="editor-theme-code">ufbx_scene.anim</span>`：シーンのデフォルトアニメーションスタック
- `<span class="editor-theme-code">ufbx_anim_stack.anim</span>`：合成済みアニメーションスタック
- `<span class="editor-theme-code">ufbx_anim_layer.anim</span>`：個別のアニメーションレイヤー
- `<span class="editor-theme-code">ufbx_create_anim()</span>`：カスタムアニメーションデスクリプタを作成

---

## 🎛 評価（Evaluation）

**ufbx**<span style="white-space: pre-wrap;"> はファイル内のアニメーションカーブを直接扱えますが、</span>  
それらを手動で解釈するのは非常に複雑です。

主な理由は次の通りです：

- <span style="white-space: pre-wrap;">⏩ 時間が非線形な </span>****キュービック補間カーブ****
- <span style="white-space: pre-wrap;">🔄 回転順序を持つ </span>****オイラー角回転カーブ****
- <span style="white-space: pre-wrap;">⚙️ </span>****プリ／ポスト回転、ピボット、オフセット****<span style="white-space: pre-wrap;"> などの複雑なノード変換</span>
- <span style="white-space: pre-wrap;">🎨 </span>****アニメーションレイヤーの合成****

こうした複雑さを避けるため、  
<span style="white-space: pre-wrap;">これらを内部で処理してくれる </span>**ufbx**<span style="white-space: pre-wrap;"> の「評価ユーティリティ」を使用することが推奨されます。</span>

特に、下記の「アニメーションのベイク（baking）」は、  
複雑な FBX アニメーションを扱いやすい形式に変換する良い出発点です。

---

## 🌍 シーン全体の評価（Scene Evaluation）

<span style="white-space: pre-wrap;">最も簡単な方法は </span>**`<strong class="editor-theme-bold editor-theme-code">ufbx_evaluate_scene()</strong>`**<span style="white-space: pre-wrap;"> を使うことです。</span>  
これは指定した時刻におけるアニメーションをすべて適用し、  
<span style="white-space: pre-wrap;">新しい </span>`<span class="editor-theme-code">ufbx_scene</span>`<span style="white-space: pre-wrap;"> を生成する「重い」関数です。</span>

<span style="white-space: pre-wrap;">結果のシーンは通常の </span>`<span class="editor-theme-code">ufbx_scene</span>`<span style="white-space: pre-wrap;"> と同様に扱えます。</span>

---

## 🔧 アニメーションのベイク（Animation Baking）

<span style="white-space: pre-wrap;">FBX ファイル内のアニメーションは </span>**`<strong class="editor-theme-bold editor-theme-code">ufbx_bake_anim()</strong>`**<span style="white-space: pre-wrap;"> を使って</span>  
より単純な形式に「ベイク」できます。

この関数は、トランスフォームアニメーションを  
線形補間のトラック（translation／quaternion rotation／scale）に変換します。  
トランスフォーム以外のプロパティも線形補間キーとしてベイクされます。

ベイクアルゴリズムは単純な再サンプリングではなく、  
キーフレームの頻度などを考慮して効率的に処理します。  
ただし、****キュービック補間****や****オイラー回転****は  
クォータニオンに再サンプリングする必要があります。

### 🎚 サンプリング設定

- `<span class="editor-theme-code">ufbx_bake_opts.resample_rate</span>`：再サンプリングレートの設定
- `<span class="editor-theme-code">ufbx_bake_opts.minimum_sample_rate</span>`：高頻度キーをスキップして二重サンプリングを防止

---

### 💻 C 言語例

```c
void bake_animation(ufbx_scene *scene, ufbx_anim *anim)
{
    ufbx_baked_anim *bake = ufbx_bake_anim(scene, anim, NULL, NULL);
    assert(bake);

    for (size_t i = 0; i < bake->nodes.count; i++) {
        ufbx_baked_node *bake_node = &bake->nodes.data[i];
        ufbx_node *scene_node = scene->nodes.data[bake_node->typed_id];

        printf("  node %s:\n", scene_node->name.data);
        printf("    translation: %zu keys\n", bake_node->translation_keys.count);
        printf("    rotation: %zu keys\n", bake_node->rotation_keys.count);
        printf("    scale: %zu keys\n", bake_node->scale_keys.count);
    }

    ufbx_free_baked_anim(bake);
}

void bake_animations(ufbx_scene *scene)
{
    for (size_t i = 0; i < scene->anim_stacks.count; i++) {
        ufbx_anim_stack *stack = scene->anim_stacks.data[i];
        printf("stack %s:\n", stack->name.data);
        bake_animation(scene, stack->anim);
    }
}
```

---

### 💻 C++ 例

```cpp
void bake_animation(ufbx_scene *scene, ufbx_anim *anim)
{
    ufbx_baked_anim *bake = ufbx_bake_anim(scene, anim, NULL, NULL);
    assert(bake);

    for (const ufbx_baked_node &bake_node : bake->nodes) {
        ufbx_node *scene_node = scene->nodes[bake_node.typed_id];
        printf("  node %s:\n", scene_node->name.data);
        printf("    translation: %zu keys\n", bake_node.translation_keys.count);
        printf("    rotation: %zu keys\n", bake_node.rotation_keys.count);
        printf("    scale: %zu keys\n", bake_node.scale_keys.count);
    }

    ufbx_free_baked_anim(bake);
}

void bake_animations(ufbx_scene *scene)
{
    for (ufbx_anim_stack *stack : scene->anim_stacks) {
        printf("stack %s:\n", stack->name.data);
        bake_animation(scene, stack->anim);
    }
}
```

---

### 💻 Rust 例

```rust
fn bake_animation(scene: &ufbx::Scene, anim: &ufbx::Anim) {
    let bake = ufbx::bake_anim(scene, anim, ufbx::BakeOpts::default())
        .expect("expected to bake animation");

    for bake_node in &bake.nodes {
        let scene_node = &scene.nodes[bake_node.typed_id as usize];

        println!("  node {}:", scene_node.element.name);
        println!("    translation: {} keys", bake_node.translation_keys.len());
        println!("    rotation: {} keys", bake_node.rotation_keys.len());
        println!("    scale: {} keys", bake_node.scale_keys.len());
    }
}

fn bake_animations(scene: &ufbx::Scene) {
    for stack in &scene.anim_stacks {
        println!("stack {}:", stack.element.name);
        bake_animation(scene, &stack.anim);
    }
}
```

---

## ⚙️ トランスフォーム・プロパティの評価

**ufbx**<span style="white-space: pre-wrap;"> は個々の要素を特定の時刻で評価するための低レベル API も提供しています。</span>

<table id="bkmrk-%E9%96%A2%E6%95%B0%E5%90%8D%E5%86%85%E5%AE%B9ufbx_evaluate_t"><colgroup><col></col><col></col></colgroup><tbody><tr><th>関数名

</th><th>内容

</th></tr><tr><td>`<span class="editor-theme-code">ufbx_evaluate_transform()</span>`

</td><td>ノードの位置・回転（クォータニオン）・スケールを評価

</td></tr><tr><td>`<span class="editor-theme-code">ufbx_evaluate_blend_weight()</span>`

</td><td>ブレンドシェイプのウェイトを評価

</td></tr><tr><td>`<span class="editor-theme-code">ufbx_evaluate_prop()</span>`

</td><td>任意の FBX プロパティ値を評価

</td></tr><tr><td>`<span class="editor-theme-code">ufbx_evaluate_props()</span>`

</td><td>要素全体のプロパティをまとめて評価

</td></tr></tbody></table>

さらに低レベルの関数：

<table id="bkmrk-%E9%96%A2%E6%95%B0%E5%90%8D%E5%86%85%E5%AE%B9ufbx_evaluate_a"><colgroup><col></col><col></col></colgroup><tbody><tr><th>関数名

</th><th>内容

</th></tr><tr><td>`<span class="editor-theme-code">ufbx_evaluate_anim_value_real()</span>`

<span style="white-space: pre-wrap;"> / </span>

`<span class="editor-theme-code">ufbx_evaluate_anim_value_vec3()</span>`

</td><td>`<span class="editor-theme-code">ufbx_anim_value</span>`

<span style="white-space: pre-wrap;"> を評価</span>

</td></tr><tr><td>`<span class="editor-theme-code">ufbx_evaluate_curve()</span>`

</td><td><span style="white-space: pre-wrap;">単一の </span>

`<span class="editor-theme-code">ufbx_anim_curve</span>`

<span style="white-space: pre-wrap;"> を評価</span>

</td></tr></tbody></table>