# ufbx Documentation(Japanese)

ufbx Documentation(Japanese)

# OverView

# ufbx

![ufbx logo](https://ufbx.github.io/static/ufbx-cube.svg)### 🧩 ufbx — 単一ソースファイルの FBX ローダー

****ufbx****<span style="white-space: pre-wrap;"> は、単一のソースファイルで構成された FBX ローダーです。</span>  
<span style="white-space: pre-wrap;">このライブラリは、FBX ファイル形式を簡単に扱える </span>****ユーザーフレンドリーなインターフェース****<span style="white-space: pre-wrap;">を提供することを目的とし、必要に応じて </span>****高度な機能にも完全対応****しています。

---

### 特徴

- ****単一ファイル構成****：C99 / C++11 に対応した1つのソースファイルで完結
- ****堅牢なエラーハンドリング****：無効なファイルやメモリ不足などにも安全に対応
- ****型安全なAPI****：C++およびRustバインディングでは境界チェック付きスライスを使用
- ****徹底したテストとファジング（fuzzing）****<span style="white-space: pre-wrap;"> による高信頼性</span>

---

### 💾 ダウンロードと使用例

```c
ufbx_load_opts opts = { 0 }; // 任意設定、デフォルトを使う場合は NULL を渡す
ufbx_error error;            // 任意、エラーを無視する場合は NULL を渡す
ufbx_scene *scene = ufbx_load_file("my_scene.fbx", &opts, &error);
if (!scene) {
    fprintf(stderr, "読み込みに失敗しました: %s\n", error.description.data);
    exit(1);
}

// 読み込まれた `scene` を自由に利用できます。
// これはただのプレーンなデータ構造です！

// 例: シーン内のすべてのオブジェクトを列挙して表示
for (size_t i = 0; i < scene->nodes.count; i++) {
    ufbx_node *node = scene->nodes.data[i];
    if (node->is_root) continue;

    printf("オブジェクト: %s\n", node->name.data);
    if (node->mesh) {
        printf("→ メッシュ（%zu 面）\n", node->mesh->faces.count);
    }
}

ufbx_free_scene(scene);
```

---

### 💡 補足

<span style="white-space: pre-wrap;">上記コードをコンパイルすれば、任意の </span>`<span class="editor-theme-code">.fbx</span>`<span style="white-space: pre-wrap;"> ファイルを読み込み、ノード（オブジェクト）やメッシュ情報を列挙できます。</span>  
`<span class="editor-theme-code">scene</span>`<span style="white-space: pre-wrap;"> 構造体には、マテリアル、トランスフォーム、アニメーションなどの詳細情報も格納されています。</span>

# Getting started

# Getting started

## Setup

### C / C++

<span style="white-space: pre-wrap;"> </span>**ufbx**<span style="white-space: pre-wrap;">はシングルソースライブラリなので、必要なのは2つのファイルだけ（ </span>`<span class="editor-theme-code">ufbx.c</span>`<span style="white-space: pre-wrap;"> </span><span style="color: rgb(36, 41, 47); background-color: rgb(252, 252, 252);">and</span><span style="white-space: pre-wrap;"> </span>`<span class="editor-theme-code">ufbx.h</span>`）です。最も簡単な方法は、[https://github.com/bqqbarbhg/ufbx](https://github.com/bqqbarbhg/ufbx)からダウンロードすることです。マスターブランチには、ライブラリの最新の安定バージョンが含まれています。  
単一の**ヘッダー**ライブラリとは異なり、残りのコードと一緒にコンパイルする必要があります。あるいは、#include "ufbx.c"で単一のファイルでコンパイルすることも可能です。  
*****ufbx**** *は**libc 外部に依存しませんが、C 標準数学ライブラリ`<span class="editor-theme-code">-</span>``<span class="editor-theme-code">lm</span>`をリンクするために渡す必要がある場合があります。

```
gcc -lm ufbx.c main.c -o main
clang -lm ufbx.c main.c -o main
```

## シーンの読み込み

<span style="white-space: pre-wrap;"> </span>**ufbx**を使い始めるには、まずシーンをロードする必要があります。シーンをロードした後は、返された[`<span class="editor-theme-code">ufbx_scene</span>`](https://ufbx.github.io/reference#ufbx_scene)構造体を調べるだけで、かなり先の処理を行うことができます。ファイルからシーンをロードし、シーン階層内のオブジェクトを表すすべてのノードの名前を出力してみましょう。

```c++
#include <stdio.h>
#include "ufbx.h"

int main()
{
    ufbx_scene *scene = ufbx_load_file("my_scene.fbx", nullptr, nullptr);

    for (ufbx_node *node : scene->nodes) {
        printf("%s\n", node->name.data);
    }

    ufbx_free_scene(scene);
    return 0;
}
```

上記の例では、シーンをデフォルトオプションでロードし、エラー処理に関してはかなり厳格に行いました。これを修正するには、ロード中に発生したエラーに関する情報を取得するために[`<span class="editor-theme-code">ufbx_error</span>`](https://ufbx.github.io/reference#ufbx_error)を使用します。  
オプションを渡すこともできます[`<span class="editor-theme-code">ufbx_load_opts</span>`](https://ufbx.github.io/reference#ufbx_load_opts)。FBXシーンには様々な座標系と単位系があり、**ufbxは**読み込み時にそれらを正規化することをサポートしています。ここでは、1メートル単位の右手Y軸上座標系を要求しています。

```c++
#include <stdio.h>
#include "ufbx.h"

int main()
{
    ufbx_load_opts opts = { };
    opts.target_axes = ufbx_axes_right_handed_y_up;
    opts.target_unit_meters = 1.0f;

    ufbx_error error;
    ufbx_scene *scene = ufbx_load_file("my_scene.fbx", &opts, &error);
    if (!scene) {
        fprintf(stderr, "Failed to load scene: %s\n", error.description.data);
        return 1;
    }

    for (ufbx_node *node : scene->nodes) {
        printf("%s\n", node->name.data);
    }

    ufbx_free_scene(scene);
    return 0;
}
```

必要に応じて、 を使用してメモリからシーンをロードし[`<span class="editor-theme-code">ufbx_load_memory</span>`](https://ufbx.github.io/reference#ufbx_load_memory)`<span class="editor-theme-code">()</span>`たり、 を使用してカスタム ストリームをロードすることもできます[`<span class="editor-theme-code">ufbx_load_stream</span>`](https://ufbx.github.io/reference#ufbx_load_stream)`<span class="editor-theme-code">()</span>`。

## データ型

<span style="white-space: pre-wrap;"> </span>**ufbx は**シーンをデータとして表現することを目的としているため、返されたデータを調べるだけで多くのことを行うことができます[`<span class="editor-theme-code">ufbx_scene</span>`](https://ufbx.github.io/reference#ufbx_scene)。  
多くのCライブラリとは異なり、**ufbxは**<span style="white-space: pre-wrap;">長さ情報のない生のポインタを公開しないため、C以外の言語でも境界チェックが可能です。ufbx内の可変長データはすべて、 </span>**以下**の型で表現されます。

```c++
// UTF-8 encoded string of `length` bytes, always NULL terminated
struct ufbx_string {
    const char *data;
    size_t length;
};

// Arbitrary binary data of `size` bytes
struct ufbx_blob {
    const char *data;
    size_t size;
};

// List of `count` objects of type T
struct ufbx_T_list {
    T *data;
    size_t count;

    // Bounds-checked indexing and iterator support in C++
    T &operator[](size_t index) const;
    T *begin() const;
    T *end() const;
};
```

[`<span class="editor-theme-code">ufbx_string</span>`](https://ufbx.github.io/reference#ufbx_string)、[`<span class="editor-theme-code">ufbx_blob</span>`](https://ufbx.github.io/reference#ufbx_blob)<span style="white-space: pre-wrap;">、または </span>`<span class="editor-theme-code">ufbx_T_list</span>`<span style="white-space: pre-wrap;"> に含まれていないすべてのポインタは、</span>  
****1つのオブジェクトを指す****<span style="white-space: pre-wrap;"> か、あるいは </span>[`<span class="editor-theme-code">ufbx_nullable</span>`](https://ufbx.github.io/reference#ufbx_nullable)<span style="white-space: pre-wrap;">が指定されている場合には </span>****NULL****<span style="white-space: pre-wrap;"> である可能性があります。</span>  
逆に言えば、[`<span class="editor-theme-code">ufbx_nullable</span>`](https://ufbx.github.io/reference#ufbx_nullable)が****付いていないポインタ****<span style="white-space: pre-wrap;">は、必ず </span>****1つの有効なオブジェクト****<span style="white-space: pre-wrap;"> を指すことが保証されています。</span>

---

デバッグ時にこれらの構造体を視覚的に確認しやすくするために、[`<span class="editor-theme-code">ufbx.natvis</span>`](https://github.com/bqqbarbhg/ufbx/blob/master/misc/ufbx.natvis)<span style="white-space: pre-wrap;"> をダウンロードして利用できます。</span>  
<span style="white-space: pre-wrap;">これは少なくとも </span>****MSVC****<span style="white-space: pre-wrap;">（Visual Studio）および </span>****VS Code****<span style="white-space: pre-wrap;"> でサポートされています。</span>

# Elements

# Elements（要素） — ufbx ドキュメント日本語訳

---

## 概要

ufbx のほぼすべては、`<span class="editor-theme-code">struct ufbx_element</span>`<span style="white-space: pre-wrap;"> のような「基底クラス」風の表現を持つ </span>****要素（element）****<span style="white-space: pre-wrap;"> で構成されます。要素は </span>`<span class="editor-theme-code">name</span>`<span style="white-space: pre-wrap;">（名前）や、FBX のキー/値プロパティのための </span>`<span class="editor-theme-code">props</span>`（プロパティ集合）といった共通プロパティを含みます。

`<span class="editor-theme-code">ufbx_node</span>`、`<span class="editor-theme-code">ufbx_mesh</span>`、`<span class="editor-theme-code">ufbx_material</span>`<span style="white-space: pre-wrap;"> といった「派生」型は、無名 </span>`<span class="editor-theme-code">union</span>`<span style="white-space: pre-wrap;"> として </span>`<span class="editor-theme-code">ufbx_element</span>`<span style="white-space: pre-wrap;"> ヘッダを埋め込んでおり、</span>`<span class="editor-theme-code">ufbx_element</span>`<span style="white-space: pre-wrap;"> へキャストしたり、</span>`<span class="editor-theme-code">ufbx_element</span>`<span style="white-space: pre-wrap;"> の共通プロパティへ直接アクセスできます。</span>

---

## 例（C）

```c++
void list_nodes(ufbx_scene *scene)
{
    for (size_t i = 0; i < scene->nodes.count; i++) {
        ufbx_node *node = scene->nodes.data[i];

        printf("Node: '%s'\n", node->element.name.data);

        // 同等の省略形:
        printf("Node: '%s'\n", node->name.data);
    }
}
```

---

## Element IDs（要素ID）

`<span class="editor-theme-code">ufbx_scene</span>`<span style="white-space: pre-wrap;"> は利便性のためにネストしたポインタ構造をとりますが、識別子（ID）を使えると便利なことがよくあります：</span>

- `<span class="editor-theme-code">ufbx_element.element_id</span>`：シーン全体で一意な連番インデックス（`<span class="editor-theme-code">scene.elements</span>`<span style="white-space: pre-wrap;"> 内）</span>
- `<span class="editor-theme-code">ufbx_element.typed_id</span>`：同一種別内での連番インデックス（例：`<span class="editor-theme-code">scene.nodes</span>`<span style="white-space: pre-wrap;"> 内）</span>

これらのインデックスを使えば、`<span class="editor-theme-code">ufbx_scene</span>`<span style="white-space: pre-wrap;"> 内の配列をインデックス指定で取り出せます。</span>

### C

```c
assert(node == scene->nodes.data[node->typed_id]);
assert(node == (ufbx_node*)scene->elements.data[node->element_id]);

assert(mesh == scene->meshes.data[mesh->typed_id]);
assert(mesh == (ufbx_mesh*)scene->elements.data[mesh->element_id]);
```

### C++

```c++
assert(node == scene->nodes[node->typed_id]);
assert(node == (ufbx_node*)scene->elements[node->element_id]);
assert(mesh == scene->meshes[mesh->typed_id]);
assert(mesh == (ufbx_mesh*)scene->elements[mesh->element_id]);
```

### Rust

```rust
use std::ptr;

assert!(ptr::eq(node, scene.nodes[node.element.typed_id]));
assert!(ptr::eq(&node.element, scene.elements[node.element.element_id]));

assert!(ptr::eq(mesh, scene.meshes[mesh.element.typed_id]));
assert!(ptr::eq(&mesh.element, scene.elements[mesh.element.element_id]));
```

> これらのインデックスは、****同じファイルを複数回読み込む範囲では安定****していますが、****ファイルを再エクスポートしただけでも****必ずしも安定とは限りません。

---

## Properties（プロパティ）

<span style="white-space: pre-wrap;">FBX は各要素に対して汎用的なキー/値のプロパティを持っており、ufbx はそれを </span>`<span class="editor-theme-code">ufbx_element.props</span>`<span style="white-space: pre-wrap;"> 経由で公開します。多くの場合 ufbx はこれらを内部でフィールドへ解釈します（例：</span>`<span class="editor-theme-code">ufbx_node.local_transform</span>`、`<span class="editor-theme-code">ufbx_light.intensity</span>`<span style="white-space: pre-wrap;">）。ただし、以下のようなケースでは </span>`<span class="editor-theme-code">ufbx_props</span>`<span style="white-space: pre-wrap;"> を直接使うとよいでしょう：</span>

- `<span class="editor-theme-code">ufbx_anim_curve</span>`<span style="white-space: pre-wrap;"> を用いたアニメーションカーブの手動解釈</span>
- ユーザー定義のカスタムプロパティ
- 非標準なマテリアル定義の取り扱い

ufbx は FBX の値を直感的に見えるよう多くの補正を行いますが、`<span class="editor-theme-code">ufbx_props</span>`<span style="white-space: pre-wrap;"> を直接読む場合には </span>****FBX 固有のクセ****<span style="white-space: pre-wrap;"> に注意してください。例えばライトには "Intensity"（強度）というプロパティがあり、FBX はしばしば DCC ツールで入力した値の </span>****100 倍****<span style="white-space: pre-wrap;"> を格納します。ufbx はこのクセを緩和するため </span>****値を 100 で割る****<span style="white-space: pre-wrap;"> 補正を試みますが、FBX プロパティを直接読むと期待と異なる結果になることがあります。</span>

### C 例（Intensity を比較表示）

```c
void print_intensity(ufbx_light *light)
{
    // `light->props` は `light->element.props` の省略形
    ufbx_prop *prop = ufbx_find_prop(&light->props, "Intensity");
    assert(prop);

    printf("ufbx_light.intensity: %.2f\n", light->intensity);
    printf("ufbx_props.Intensity: %.2f\n", prop->value_real);
}
```

### C++ 例

```c++
void print_intensity(ufbx_light *light)
{
    // `light->props` は `light->element.props` の省略形
    ufbx_prop *prop = ufbx_find_prop(&light->props, "Intensity");
    assert(prop);

    printf("ufbx_light.intensity: %.2f\n", light->intensity);
    printf("ufbx_props.Intensity: %.2f\n", prop->value_real);
}
```

### Rust 例

```rust
fn print_intensity(light: &ufbx::Light) {
    let prop = light.element.props
        .find_prop("Intensity")
        .expect("expected to find 'Intensity'");

    println!("ufbx_light.intensity: {:.2}", light.intensity);
    // 注意：Rust バインディングの表現は実装に依存する場合があります
    println!("ufbx_props.Intensity: {:.2}", prop.value_vec4.x);
}
```

#### 例（Blender で強度 2.0 のライトを持つシーン）

```
ufbx_light.intensity: 2.00
ufbx_props.Intensity: 200.00
```

---

## 脚注

1. <span style="white-space: pre-wrap;">FBX のファイルフォーマットではこれらを </span>****Objects****<span style="white-space: pre-wrap;"> と呼びますが、3D モデルの文脈では “object” という語が多義的すぎるため、ufbx では </span>****elements****<span style="white-space: pre-wrap;"> と呼んでいます。</span>

---

## クレジット / ライセンス

<p class="callout warning">本文・コード例は ufbx の公開ライセンス（MIT / Unlicense）に基づき翻訳・再構成しています。必要に応じてクレジット表記を併記してください：  
`<span class="editor-theme-code">© 2020 Samuli Raivio — Original docs under Unlicense/MIT. Japanese translation by <YzLearning>.</span>`</p>

- 原文： ufbx docs “Elements” ページ
- ライセンス： MIT / Unlicense（二重ライセンス）
- <span style="white-space: pre-wrap;">推奨クレジット： </span>`<span class="editor-theme-code">© 2020 Samuli Raivio — Original docs under Unlicense/MIT.</span>`
- 訳者：［YzLearnig］（必要に応じて記入）

# Nodes（ノード）

## 概要

****Nodes（ノード）****（`<span class="editor-theme-code">ufbx_node</span>`<span style="white-space: pre-wrap;">）は、FBX ファイルの </span>****シーングラフ（Scene Graph）****<span style="white-space: pre-wrap;"> を構成する要素です。</span>  
ノード自体は、変換情報（`<span class="editor-theme-code">ufbx_node.local_transform</span>`）と階層構造（`<span class="editor-theme-code">ufbx_node.parent</span>`<span style="white-space: pre-wrap;"> / </span>`<span class="editor-theme-code">ufbx_node.children[]</span>`）を保持します。

<span style="white-space: pre-wrap;">ノードは </span>****属性（attribute）****<span style="white-space: pre-wrap;"> によって機能が拡張されます。たとえば、</span>`<span class="editor-theme-code">ufbx_mesh</span>`<span style="white-space: pre-wrap;"> や </span>`<span class="editor-theme-code">ufbx_light</span>`<span style="white-space: pre-wrap;"> などです。</span>  
1つの属性が複数のノードに参照されることもあり、同じメッシュを異なるトランスフォームでインスタンス化することができます。

ノードは共通属性を直接保持しており、たとえば：

- `<span class="editor-theme-code">ufbx_node.mesh</span>`
- `<span class="editor-theme-code">ufbx_node.light</span>`

などを通じてアクセスできます。  
<span style="white-space: pre-wrap;">より珍しい属性は </span>`<span class="editor-theme-code">ufbx_node.attrib</span>`<span style="white-space: pre-wrap;"> に格納されており、</span>`<span class="editor-theme-code">ufbx_as_bone()</span>`<span style="white-space: pre-wrap;"> のようなヘルパ関数で具体的な型へキャスト（または </span>`<span class="editor-theme-code">NULL</span>`）できます。

逆に、「ノードがどの属性を持つか」を列挙する代わりに、「ある属性がどのノードで使用されているか」を調べることもできます。  
各属性（例：`<span class="editor-theme-code">ufbx_mesh</span>`<span style="white-space: pre-wrap;">）には </span>`<span class="editor-theme-code">ufbx_element.instances[]</span>`<span style="white-space: pre-wrap;"> フィールドがあり、それを参照しているすべてのノードを取得できます。</span>

---

## Transforms（変換）

ノードのローカル変換は、****平行移動（translation）・回転（rotation）・スケール（scale）****<span style="white-space: pre-wrap;"> の組み合わせで表されます。</span>  
<span style="white-space: pre-wrap;">これらは </span>`<span class="editor-theme-code">ufbx_node.local_transform</span>`<span style="white-space: pre-wrap;"> に格納され、</span>****親ノードに対する相対的な変換****<span style="white-space: pre-wrap;"> を表します。</span>

ノードはさらに以下のような便利フィールドも持っています：

- `<span class="editor-theme-code">ufbx_node.node_to_parent</span>`（親ノード座標系への行列）
- `<span class="editor-theme-code">ufbx_node.node_to_world</span>`（ワールド座標系への行列）

FBX の内部変換は非常に複雑ですが、ufbx ではこれを隠蔽するための機能を数多く備えています。  
`<span class="editor-theme-code">ufbx_node</span>`<span style="white-space: pre-wrap;"> のフィールドや </span>`<span class="editor-theme-code">ufbx_evaluate_transform()</span>`、`<span class="editor-theme-code">ufbx_bake_anim()</span>`<span style="white-space: pre-wrap;"> などを利用すれば、複雑さを意識せずに扱えます。</span>

（FBX の内部的な変換構造については「Node Transforms」セクションで詳細に説明されています。）

---

## Coordinate Spaces（座標系）

FBX ファイルは任意の座標系（軸向きや単位スケール）で保存されている場合があります。  
たとえば、前方／右／上方向の軸や単位長（1.0 の意味）が異なるケースです。

これに対応するため、`<span class="editor-theme-code">ufbx_scene.settings</span>`<span style="white-space: pre-wrap;"> から </span>****軸（axes）****<span style="white-space: pre-wrap;"> と </span>****単位メートル値（unit\_meters）****<span style="white-space: pre-wrap;"> を取得できます。</span>

また、`<span class="editor-theme-code">ufbx_load_opts.target_axes</span>`<span style="white-space: pre-wrap;"> および </span>`<span class="editor-theme-code">ufbx_load_opts.target_unit_meters</span>`<span style="white-space: pre-wrap;"> を設定することで、</span>  
読み込んだシーンを希望の座標系に変換することも可能です。

<span style="white-space: pre-wrap;">変換方法は </span>`<span class="editor-theme-code">ufbx_load_opts.space_conversion</span>`<span style="white-space: pre-wrap;"> によって指定します：</span>

<table id="bkmrk-%E5%AE%9A%E6%95%B0%E5%90%8D%E5%86%85%E5%AE%B9ufbx_space_conv"><colgroup><col></col><col></col></colgroup><tbody><tr><th>定数名

</th><th>内容

</th></tr><tr><td>`<span class="editor-theme-code">UFBX_SPACE_CONVERSION_TRANSFORM_ROOT</span>`

</td><td>ルートノードで空間変換を行う

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

</td><td>各ノードのトランスフォームを補正する

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

</td><td>ジオメトリにスケールを焼き込み、軸変換は ADJUST\_TRANSFORMS と同様に行う

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

ufbx では、`<span class="editor-theme-code">ufbx_load_opts.handedness_conversion_axis</span>`<span style="white-space: pre-wrap;"> を使用して </span>****左右座標系（右手／左手）****<span style="white-space: pre-wrap;"> の変換も可能です。</span>  
通常、FBX は右手座標系が主流なので、右手系を使用する場合は不要です。  
左手座標系でシーンをロードする場合は、ミラー変換が必要になります。

また、カメラ（ローカル +X 向き）やライト（デフォルトではローカル -Y 向き）の軸を修正する機能もあります。  
<span style="white-space: pre-wrap;">これには </span>`<span class="editor-theme-code">ufbx_load_opts.target_camera_axes</span>`<span style="white-space: pre-wrap;"> および </span>`<span class="editor-theme-code">ufbx_load_opts.target_light_axes</span>`<span style="white-space: pre-wrap;"> を使用します。</span>

---

## Coordinate Spaces in Files（ファイル内の座標系）

FBX の座標系やエクスポータの違いは、多くのユーザーを混乱させてきました。  
（例：「FBX scale 100」「FBX scale 0.01」で検索するとよく出てきます。）

これは ufbx にも影響しますが、いくつかの方法で軽減可能です。

- ****Blender****<span style="white-space: pre-wrap;">：通常 Z-up メートル単位で動作しますが、FBX 書き出し時に </span>****Y-up / cm単位（100倍）****<span style="white-space: pre-wrap;"> に変換します。</span>  
    `<span class="editor-theme-code">UFBX_SPACE_CONVERSION_ADJUST_TRANSFORMS</span>`<span style="white-space: pre-wrap;"> を使うと、この100倍スケールを打ち消し、不要なスケーリングを取り除けます。</span>  
    一方、`<span class="editor-theme-code">UFBX_SPACE_CONVERSION_MODIFY_GEOMETRY</span>`<span style="white-space: pre-wrap;"> はジオメトリ自体を0.01倍にスケールして正しい形状を維持しますが、中間ノードにスケール要素が残ります。</span>
- ****Maya****：多くの場合 cm 単位がネイティブです。  
    <span style="white-space: pre-wrap;">こちらでは </span>`<span class="editor-theme-code">UFBX_SPACE_CONVERSION_MODIFY_GEOMETRY</span>`<span style="white-space: pre-wrap;"> の方が適しており、ノードスケールを変更せずにシーンを正しいスケールへ変換できます。</span>

結論として、****すべてのケースで完全に一貫した変換方法は存在しません。****  
ユーザーに変換方法を選択させるオプションを提供するのが望ましいです。

また、軽量ロード（`<span class="editor-theme-code">ufbx_load_opts.ignore_all_content = true</span>`）を使ってシーンを一度読み込み、  
`<span class="editor-theme-code">ufbx_metadata.exporter</span>`<span style="white-space: pre-wrap;"> を確認することで、エクスポータ（Blender / Maya 等）を特定し、</span>  
最適な変換方法を事前設定することも可能です。

> 💡 Blender でエクスポートする場合は、****「Apply Scalings」を “FBX Units Scale” に設定****するのが推奨です。  
> これにより、追加スケールなしのメートル単位（unit\_meters = 1.0）でエクスポートされます。

---

## サンプルコード

```c
// シーンをメートル単位・右手Y-upに変換してロード
ufbx_load_opts opts = { 0 };
opts.target_axes = ufbx_axes_right_handed_y_up;
opts.target_unit_meters = 1.0f;
opts.target_camera_axes = ufbx_axes_right_handed_y_up;
opts.target_light_axes = ufbx_axes_right_handed_y_up;

if (prefer_blender) {
    opts.space_conversion = UFBX_SPACE_CONVERSION_ADJUST_TRANSFORMS;
} else {
    opts.space_conversion = UFBX_SPACE_CONVERSION_MODIFY_GEOMETRY;
}
```

---

## Geometry Transforms（ジオメトリ変換）

<span style="white-space: pre-wrap;">FBX では </span>****ジオメトリ変換（geometry transform）****<span style="white-space: pre-wrap;"> と呼ばれる特殊な変換をサポートしています。</span>  
これはノード直下のメッシュなどにのみ適用され、子ノードには継承されません。  
多くのシーングラフではこの仕組みを直接サポートしていないため、ufbx は代替方法を提供します。

### ジオメトリ変換の利用

<span style="white-space: pre-wrap;">ジオメトリ変換は </span>`<span class="editor-theme-code">ufbx_node.geometry_transform</span>`<span style="white-space: pre-wrap;"> に格納されます。</span>  
また、補助的な行列：

- `<span class="editor-theme-code">ufbx_node.geometry_to_node</span>`
- `<span class="editor-theme-code">ufbx_node.geometry_to_world</span>`

もあり、特に静的メッシュをワールド座標で扱う際に便利です。

### ジオメトリ変換を除去する

非静的シーンでのジオメトリ変換は扱いが難しいため、  
`<span class="editor-theme-code">ufbx_load_opts.geometry_transform_handling</span>`<span style="white-space: pre-wrap;"> によりロード時に削除することも可能です。</span>

<table id="bkmrk-%E5%AE%9A%E6%95%B0%E5%90%8D%E5%86%85%E5%AE%B9ufbx_geometry_t"><colgroup><col></col><col></col></colgroup><tbody><tr><th>定数名

</th><th>内容

</th></tr><tr><td>`<span class="editor-theme-code">UFBX_GEOMETRY_TRANSFORM_HANDLING_HELPER_NODES</span>`

</td><td>補助ノードを挿入して対応（確実だがノード数が増える）

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

</td><td>ジオメトリ変換を頂点データに焼き込み（きれいだが制約あり）

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

</td><td>補助ノードを絶対に作らない（ただし変換誤差が発生する）

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

---

## Inherit Modes（継承モード）

FBX では非標準的な変換継承も可能です。  
<span style="white-space: pre-wrap;">これは </span>`<span class="editor-theme-code">ufbx_node.inherit_mode</span>`<span style="white-space: pre-wrap;"> によって示されます。</span>

<table id="bkmrk-%E3%83%A2%E3%83%BC%E3%83%89%E5%86%85%E5%AE%B9ufbx_inherit_mo"><colgroup><col></col><col></col></colgroup><tbody><tr><th>モード

</th><th>内容

</th></tr><tr><td>`<span class="editor-theme-code">UFBX_INHERIT_MODE_IGNORE_PARENT_SCALE</span>`

</td><td>親のスケールを無視

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

</td><td>スケールと回転を独立して合成

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

ufbx では、ロード時にこれらを標準的なシーングラフへ変換するオプションを用意しています：

<table id="bkmrk-%E5%AE%9A%E6%95%B0%E5%86%85%E5%AE%B9ufbx_inherit_mod"><colgroup><col></col><col></col></colgroup><tbody><tr><th>定数

</th><th>内容

</th></tr><tr><td>`<span class="editor-theme-code">UFBX_INHERIT_MODE_HANDLING_PRESERVE</span>`

</td><td>継承モードをそのまま保持（正確だが複雑）

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

</td><td>補助ノードを追加して対応

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

</td><td>子ノードのスケールを逆補正（できない場合は補助ノード）

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

</td><td>非標準継承をすべて無視（単純だが不正確）

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

---

## Pivots（ピボット）

FBX ノードでは、****回転ピボット****<span style="white-space: pre-wrap;"> と </span>****スケールピボット****<span style="white-space: pre-wrap;"> を個別に設定できます。</span>  
ufbx では、デフォルトでこれらの効果をノードの平行移動へ焼き込みます。

回転ピボットとスケールピボットが同一である場合、  
`<span class="editor-theme-code">ufbx_load_opts.pivot_handling = UFBX_PIVOT_HANDLING_ADJUST_TO_PIVOT</span>`  
を設定することで、ピボットをジオメトリ変換へ変換することも可能です。  
この場合は、`<span class="editor-theme-code">ufbx_load_opts.geometry_transform_handling</span>`<span style="white-space: pre-wrap;"> も併せて指定します（例：</span>`<span class="editor-theme-code">UFBX_GEOMETRY_TRANSFORM_HANDLING_MODIFY_GEOMETRY</span>`）。

---

## その他のプロパティ

ノードには変換以外にも以下のプロパティがあります：

- ****可視性****：`<span class="editor-theme-code">ufbx_node.visible</span>`<span style="white-space: pre-wrap;"> でノードを非表示にできる</span>
- ****マテリアルの上書き****：`<span class="editor-theme-code">ufbx_node.materials[]</span>`<span style="white-space: pre-wrap;"> でインスタンスごとに別マテリアルを適用できる</span>

---

## 備考

<span style="white-space: pre-wrap;">FBX 仕様ではこれらを </span>****“Geometric” transforms（ジオメトリック変換）****<span style="white-space: pre-wrap;"> と呼びますが、</span>  
<span style="white-space: pre-wrap;">ufbx では明確化のため </span>****geometry transforms****<span style="white-space: pre-wrap;"> と呼んでいます。</span>

---

# Meshes（メッシュ） — ufbx ドキュメント日本語訳

## 概要

****Meshes（メッシュ）****（`<span class="editor-theme-code">ufbx_mesh</span>`）は、****ポリゴンジオメトリデータ****<span style="white-space: pre-wrap;"> を保持する要素です。</span>

ufbx では次の用語を使用します：

<table id="bkmrk-%E7%94%A8%E8%AA%9E%E8%AA%AC%E6%98%8Evertex%EF%BC%88%E9%A0%82%E7%82%B9%EF%BC%89%E4%BD%8D%E7%BD%AE%E6%83%85%E5%A0%B1%E3%82%92%E6%8C%81"><colgroup><col></col><col></col></colgroup><tbody><tr><th>用語

</th><th>説明

</th></tr><tr><td>****Vertex（頂点）****

</td><td>位置情報を持つ頂点。3Dモデリングソフトで選択可能な頂点に相当。

</td></tr><tr><td>****Index（インデックス）****

</td><td>頂点にUV・法線・カラーなどの属性を組み合わせたもの。

</td></tr><tr><td>****Face（面）****

</td><td>1枚の平面（三角形・四角形・N-gon）を構成するインデックスの範囲。

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

同じ頂点が複数の面から参照されることがあります。  
<span style="white-space: pre-wrap;">各参照では異なるインデックスを持ち、これにより </span>****同一頂点に異なるUVや法線を設定****<span style="white-space: pre-wrap;"> できます。</span>

---

## メッシュのデータ構造

メッシュデータは各種属性として格納されます：

- `<span class="editor-theme-code">ufbx_mesh.vertex_position</span>`<span style="white-space: pre-wrap;"> — 頂点座標</span>
- `<span class="editor-theme-code">ufbx_mesh.vertex_normal</span>`<span style="white-space: pre-wrap;"> — 頂点法線</span>
- `<span class="editor-theme-code">ufbx_mesh.vertex_uv</span>`<span style="white-space: pre-wrap;"> — 頂点UV座標</span>

<span style="white-space: pre-wrap;">各属性には独自の </span>****インデックス配列****（`<span class="editor-theme-code">ufbx_vertex_attrib.indices[]</span>`<span style="white-space: pre-wrap;">）と </span>****値配列****（`<span class="editor-theme-code">ufbx_vertex_attrib.values[]</span>`）があり、  
インデックス指定で値を取得できます：

```c
data[indices[index]]
```

<span style="white-space: pre-wrap;">あるいはヘルパー関数 </span>`<span class="editor-theme-code">ufbx_get_vertex_vec3()</span>`<span style="white-space: pre-wrap;"> や、</span>  
<span style="white-space: pre-wrap;">C++／Rust の </span>`<span class="editor-theme-code">attrib[index]</span>`<span style="white-space: pre-wrap;"> 構文でもアクセス可能です。</span>

---

## 描画例

以下は仮想的な即時モードポリゴンAPIを使ってメッシュを描画する例です。

```c
void draw_polygons(ufbx_mesh *mesh)
{
    for (ufbx_face face : mesh->faces) {
        begin_polygon();

        // ポリゴンの各コーナーをループ
        for (uint32_t corner = 0; corner < face.num_indices; corner++) {

            // 各コーナーに対応するインデックス
            uint32_t index = face.index_begin + corner;

            // 頂点属性を取得
            ufbx_vec3 position = mesh->vertex_position[index];
            ufbx_vec3 normal   = mesh->vertex_normal[index];
            ufbx_vec2 uv       = mesh->vertex_uv[index];

            polygon_corner(position, normal, uv);
        }

        end_polygon();
    }
}
```

---

## Materials（マテリアル）

1つのFBXメッシュには、****異なる部位に複数のマテリアル****<span style="white-space: pre-wrap;"> が割り当てられる場合があります。</span>  
`<span class="editor-theme-code">ufbx_mesh.face_material[]</span>`<span style="white-space: pre-wrap;"> には、面ごとのマテリアルインデックスが格納されており、</span>  
<span style="white-space: pre-wrap;">これを使って </span>`<span class="editor-theme-code">ufbx_mesh.materials[]</span>`<span style="white-space: pre-wrap;"> にアクセスできます。</span>

ただし、****正確な結果を得るには** `<strong class="editor-theme-bold editor-theme-code">ufbx_node.materials[]</strong>` **を使うのが推奨****です。  
理由は、同じメッシュが異なるマテリアルでインスタンス化されることがあるためです。

ゲームエンジンでは、マテリアル境界ごとにメッシュを分割する必要がある場合があります。  
<span style="white-space: pre-wrap;">ufbx ではこれを容易にするために </span>`<span class="editor-theme-code">ufbx_mesh.material_parts[]</span>`<span style="white-space: pre-wrap;"> を提供しています。</span>  
これには、各マテリアルごとの****面数・三角形数・面リスト****が含まれます。  
マテリアルが存在しない場合でも、便宜上1つのマテリアルパートが存在します。

---

## 例：GPU用フォーマットへの変換

<span style="white-space: pre-wrap;">以下は、メッシュデータを </span>****GPU向けインデックス付きフォーマット****<span style="white-space: pre-wrap;"> に変換する例です。</span>  
使用しているヘルパー関数：

- `<span class="editor-theme-code">ufbx_triangulate_face()</span>`：面を三角形化してインデックス配列を生成
- `<span class="editor-theme-code">ufbx_generate_indices()</span>`：頂点配列を重複排除し、インデックスバッファを生成

```cpp
// GPU向け頂点構造体
// 実際にはよりコンパクトな型を使うべきです。
// `ufbx_real` はデフォルトで64bitです。
struct Vertex {
    ufbx_vec3 position;
    ufbx_vec3 normal;
    ufbx_vec2 uv;
};

void convert_mesh_part(ufbx_mesh *mesh, ufbx_mesh_part *part)
{
    std::vector<Vertex> vertices;
    std::vector<uint32_t> tri_indices;
    tri_indices.resize(mesh->max_face_triangles * 3);

    // このマテリアルを使用している各面を処理
    for (uint32_t face_index : part->face_indices) {
        ufbx_face face = mesh->faces[face_index];

        // 面を三角形化
        uint32_t num_tris = ufbx_triangulate_face(
            tri_indices.data(), tri_indices.size(), mesh, face);

        // 各三角形の頂点を取得
        for (size_t i = 0; i < num_tris * 3; i++) {
            uint32_t index = tri_indices[i];

            Vertex v;
            v.position = mesh->vertex_position[index];
            v.normal   = mesh->vertex_normal[index];
            v.uv       = mesh->vertex_uv[index];
            vertices.push_back(v);
        }
    }

    assert(vertices.size() == part->num_triangles * 3);

    // 頂点ストリームを生成
    ufbx_vertex_stream streams[1] = {
        { vertices.data(), vertices.size(), sizeof(Vertex) },
    };
    std::vector<uint32_t> indices;
    indices.resize(part->num_triangles * 3);

    // 頂点重複を削除し、インデックスバッファを生成
    size_t num_vertices = ufbx_generate_indices(
        streams, 1, indices.data(), indices.size(), nullptr, nullptr);

    vertices.resize(num_vertices);

    create_vertex_buffer(vertices.data(), vertices.size());
    create_index_buffer(indices.data(), indices.size());
}
```

---

## Attributes（属性）

上記の属性に加えて、FBXメッシュには他の属性も存在します。  
<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 class="editor-theme-code">ufbx_mesh.edges[]</span>`<span style="white-space: pre-wrap;"> で2つのインデックス間を定義します。</span>

---

### <span style="white-space: pre-wrap;">頂点（インデックス単位、最大 </span>`<span class="editor-theme-code">ufbx_mesh.num_indices</span>`）

<table id="bkmrk-%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E5%86%85%E5%AE%B9ufbx_mesh.ver"><colgroup><col></col><col></col></colgroup><tbody><tr><th>フィールド

</th><th>内容

</th></tr><tr><td>`<span class="editor-theme-code">ufbx_mesh.vertex_position</span>`

</td><td>頂点座標

</td></tr><tr><td>`<span class="editor-theme-code">ufbx_mesh.vertex_normal</span>`

</td><td>法線ベクトル

</td></tr><tr><td>`<span class="editor-theme-code">ufbx_mesh.vertex_tangent</span>`

</td><td>接線方向（Tangent）UV.x

</td></tr><tr><td>`<span class="editor-theme-code">ufbx_mesh.vertex_bitangent</span>`

</td><td>接線空間UV.y

</td></tr><tr><td>`<span class="editor-theme-code">ufbx_mesh.vertex_uv</span>`

</td><td>UV座標（第1セット）

</td></tr><tr><td>`<span class="editor-theme-code">ufbx_mesh.vertex_color</span>`

</td><td>頂点カラー（第1セット）

</td></tr><tr><td>`<span class="editor-theme-code">ufbx_mesh.vertex_crease</span>`

</td><td>サブディビジョン用クリース値

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

---

### <span style="white-space: pre-wrap;">面（最大 </span>`<span class="editor-theme-code">ufbx_mesh.num_faces</span>`）

<table id="bkmrk-%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E5%86%85%E5%AE%B9ufbx_mesh.fac"><colgroup><col></col><col></col></colgroup><tbody><tr><th>フィールド

</th><th>内容

</th></tr><tr><td>`<span class="editor-theme-code">ufbx_mesh.face_material</span>`

</td><td>面ごとのマテリアル

</td></tr><tr><td>`<span class="editor-theme-code">ufbx_mesh.face_group</span>`

</td><td>ポリゴングループ

</td></tr><tr><td>`<span class="editor-theme-code">ufbx_mesh.face_smoothing</span>`

</td><td>スムーズシェーディングフラグ

</td></tr><tr><td>`<span class="editor-theme-code">ufbx_mesh.face_hole</span>`

</td><td>穴として扱うかどうか

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

---

### <span style="white-space: pre-wrap;">エッジ（最大 </span>`<span class="editor-theme-code">ufbx_mesh.num_edges</span>`）

<table id="bkmrk-%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E5%86%85%E5%AE%B9ufbx_mesh.edg"><colgroup><col></col><col></col></colgroup><tbody><tr><th>フィールド

</th><th>内容

</th></tr><tr><td>`<span class="editor-theme-code">ufbx_mesh.edge_smoothing</span>`

</td><td>法線生成用スムーズフラグ

</td></tr><tr><td>`<span class="editor-theme-code">ufbx_mesh.edge_visibility</span>`

</td><td>編集用のエッジ表示フラグ

</td></tr><tr><td>`<span class="editor-theme-code">ufbx_mesh.edge_crease</span>`

</td><td>サブディビジョン用エッジクリース

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

---

# 🌀 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>

# 🦴 Deformers（デフォーマー）

FBX では、****メッシュ変形（Mesh deformation）****<span style="white-space: pre-wrap;"> は </span>**Deformer**<span style="white-space: pre-wrap;"> を通じて実装されています。</span>  
****ufbx****<span style="white-space: pre-wrap;"> は以下の 3 種類の FBX デフォーマーをサポートしています。</span>

- <span style="white-space: pre-wrap;">🦴 </span>`<span class="editor-theme-code">ufbx_skin_deformer</span>`  
    <span style="white-space: pre-wrap;"> → ボーンに頂点を重み付きで結びつける「スキニング」</span>
- <span style="white-space: pre-wrap;">😶‍🌫️ </span>`<span class="editor-theme-code">ufbx_blend_deformer</span>`  
    <span style="white-space: pre-wrap;"> → ブレンドシェイプ（モーフターゲット）による頂点オフセット</span>
- <span style="white-space: pre-wrap;">💾 </span>`<span class="editor-theme-code">ufbx_cache_deformer</span>`  
    <span style="white-space: pre-wrap;"> → ディスクキャッシュからメッシュデータを置き換えるデフォーマー</span>

これらのデフォーマーはメッシュに接続されています。  
例：`<span class="editor-theme-code">ufbx_mesh.skin_deformers[]</span>`<span style="white-space: pre-wrap;"> や </span>`<span class="editor-theme-code">ufbx_mesh.blend_deformers[]</span>`。  
もし正確な適用順序が必要な場合は、  
`<span class="editor-theme-code">ufbx_mesh.all_deformers[]</span>`<span style="white-space: pre-wrap;"> ですべてのデフォーマーを型なしリストで取得できます。</span>

---

## 🦾 Skin Deformer（スキンデフォーマー）

FBX のスケルトンは、通常のノード（`<span class="editor-theme-code">ufbx_node</span>`）で構成され、  
多くの場合ボーン属性（`<span class="editor-theme-code">ufbx_bone</span>`）を持ちます。  
ボーン属性はスキニングに必須ではありませんが、可視化やスケルトン検出に役立ちます。

### 📐 クラスタ（Cluster）

<span style="white-space: pre-wrap;">ボーンによる影響は </span>****クラスタ (**`<strong class="editor-theme-bold editor-theme-code">ufbx_skin_cluster</strong>`**)****<span style="white-space: pre-wrap;"> で定義されます。</span>  
クラスタはメッシュをボーンに結びつけ、  
`<span class="editor-theme-code">ufbx_skin_cluster.geometry_to_bone</span>`<span style="white-space: pre-wrap;"> は</span>  
メッシュ空間からボーン空間への変換を表します。  
これはいわゆる「逆バインド行列（inverse bind matrix）」です。

<span style="white-space: pre-wrap;">影響を受ける頂点は </span>`<span class="editor-theme-code">ufbx_skin_cluster.vertices[]</span>`<span style="white-space: pre-wrap;"> と</span>  
<span style="white-space: pre-wrap;">対応する </span>`<span class="editor-theme-code">ufbx_skin_cluster.weights[]</span>`<span style="white-space: pre-wrap;"> に格納されています。</span>

---

### 🧮 頂点ごとの重み情報

どのボーンが各頂点に影響するかを解析するのはよくある処理です。  
<span style="white-space: pre-wrap;">そこで </span>**ufbx**<span style="white-space: pre-wrap;"> は便利な簡略アクセスとして：</span>

- `<span class="editor-theme-code">ufbx_skin_deformer.vertices[]</span>`
- `<span class="editor-theme-code">ufbx_skin_deformer.weights[]</span>`

を提供しています。  
これらは****影響度の高い順****にソートされているため、  
もし 4 ～ 8 つのウェイトしか対応しない場合は  
<span style="white-space: pre-wrap;">上位 </span>`<span class="editor-theme-code">N</span>`<span style="white-space: pre-wrap;"> 個を取るだけで十分です。</span>

---

### 💻 C 言語サンプル

```c
#define MAX_WEIGHTS 4

typedef struct Vertex {
    ufbx_vec3 position;
    ufbx_vec3 normal;
    float weights[MAX_WEIGHTS];
    uint32_t bones[MAX_WEIGHTS];
} Vertex;

Vertex get_skinned_vertex(ufbx_mesh *mesh, ufbx_skin_deformer *skin, size_t index)
{
    Vertex v = { 0 };
    v.position = ufbx_get_vertex_vec3(&mesh->vertex_position, index);
    v.normal = ufbx_get_vertex_vec3(&mesh->vertex_normal, index);

    uint32_t vertex = mesh->vertex_indices.data[index];
    ufbx_skin_vertex skin_vertex = skin->vertices.data[vertex];
    size_t num_weights = skin_vertex.num_weights;
    if (num_weights > MAX_WEIGHTS) num_weights = MAX_WEIGHTS;

    float total_weight = 0.0f;
    for (size_t i = 0; i < num_weights; i++) {
        ufbx_skin_weight skin_weight = skin->weights.data[skin_vertex.weight_begin + i];
        v.bones[i] = skin_weight.cluster_index;
        v.weights[i] = (float)skin_weight.weight;
        total_weight += (float)skin_weight.weight;
    }

    // FBX では重みの正規化が保証されていないため再正規化する
    for (size_t i = 0; i < num_weights; i++) {
        v.weights[i] /= total_weight;
    }

    return v;
}
```

---

### 💻 C++ 版

```cpp
#define MAX_WEIGHTS 4

struct Vertex {
    ufbx_vec3 position;
    ufbx_vec3 normal;
    float weights[MAX_WEIGHTS];
    uint32_t bones[MAX_WEIGHTS];
};

Vertex get_skinned_vertex(ufbx_mesh *mesh, ufbx_skin_deformer *skin, size_t index)
{
    Vertex v = { 0 };
    v.position = mesh->vertex_position[index];
    v.normal = mesh->vertex_normal[index];

    uint32_t vertex = mesh->vertex_indices[index];
    ufbx_skin_vertex skin_vertex = skin->vertices[vertex];
    size_t num_weights = skin_vertex.num_weights;
    if (num_weights > MAX_WEIGHTS) num_weights = MAX_WEIGHTS;

    float total_weight = 0.0f;
    for (size_t i = 0; i < num_weights; i++) {
        ufbx_skin_weight skin_weight = skin->weights[skin_vertex.weight_begin + i];
        v.bones[i] = skin_weight.cluster_index;
        v.weights[i] = (float)skin_weight.weight;
        total_weight += (float)skin_weight.weight;
    }

    for (size_t i = 0; i < num_weights; i++) {
        v.weights[i] /= total_weight;
    }

    return v;
}
```

---

### 💻 Rust 版

```rust
const MAX_WEIGHTS: usize = 4;

#[derive(Clone, Copy, Default)]
struct Vertex {
    position: ufbx::Vec3,
    normal: ufbx::Vec3,
    weights: [f32; MAX_WEIGHTS],
    bones: [u32; MAX_WEIGHTS],
}

fn get_skinned_vertex(mesh: &ufbx::Mesh, skin: &ufbx::SkinDeformer, index: usize) -> Vertex {
    let mut v = Vertex{
        position: mesh.vertex_position[index],
        normal: mesh.vertex_normal[index],
        ..Default::default()
    };

    let vertex = mesh.vertex_indices[index] as usize;
    let skin_vertex = skin.vertices[vertex];
    let num_weights = (skin_vertex.num_weights as usize).min(MAX_WEIGHTS);

    let mut total_weight: f32 = 0.0;
    for i in 0..num_weights {
        let skin_weight = skin.weights[skin_vertex.weight_begin as usize + i];
        v.bones[i] = skin_weight.cluster_index;
        v.weights[i] = skin_weight.weight as f32;
        total_weight += skin_weight.weight as f32;
    }

    for i in 0..num_weights {
        v.weights[i] /= total_weight;
    }

    v
}
```

---

## ⚙️ Skinning Modes（スキニングモード）

<span style="white-space: pre-wrap;">FBX は </span>`<span class="editor-theme-code">ufbx_skin_deformer.skinning_method</span>`<span style="white-space: pre-wrap;"> により複数のスキニング方式をサポートします。</span>  
基本的には無視しても問題ありませんが、必要なら以下の通りです。

<table id="bkmrk-%E5%AE%9A%E6%95%B0%E5%86%85%E5%AE%B9ufbx_skinning_me"><colgroup><col></col><col></col></colgroup><tbody><tr><th>定数

</th><th>内容

</th></tr><tr><td>`<span class="editor-theme-code">UFBX_SKINNING_METHOD_RIGID</span>`

</td><td>単一ボーン固定（補間なし）

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

</td><td>一般的な線形ブレンドスキニング

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

</td><td>デュアルクォータニオンスキニング

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

</td><td>線形とデュアルクォータニオンを補間するモード（

`<span class="editor-theme-code">ufbx_skin_vertex.dq_weight</span>`

<span style="white-space: pre-wrap;"> により制御）</span>

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

---

## 🎭 Blend Deformer（ブレンドデフォーマー）

****ブレンドシェイプ（モーフターゲット）****<span style="white-space: pre-wrap;"> は</span>  
****ブレンドチャンネル (**`<strong class="editor-theme-bold editor-theme-code">ufbx_blend_channel</strong>`**)****<span style="white-space: pre-wrap;"> によって制御されます。</span>

FBX 形式では「中間ブレンドキー（in-between keyframes）」をサポートしており、  
`<span class="editor-theme-code">ufbx_blend_channel.keyframes[]</span>`<span style="white-space: pre-wrap;"> にキーが定義されています。</span>

もしそれを扱わない場合は、便利なフィールド：

- `<span class="editor-theme-code">ufbx_blend_channel.target_shape</span>`  
    <span style="white-space: pre-wrap;"> → 最後のキー（ターゲットシェイプ）を直接参照</span>

を使用できます。

各ブレンドシェイプ（`<span class="editor-theme-code">ufbx_blend_shape</span>`）は頂点の部分集合に対してオフセットを持ちます：

- `<span class="editor-theme-code">ufbx_blend_shape.offset_vertices[]</span>`：影響を受ける頂点インデックス
- `<span class="editor-theme-code">ufbx_blend_shape.position_offsets[]</span>`：対応する頂点位置のオフセット
- `<span class="editor-theme-code">ufbx_blend_shape.normal_offsets[]</span>`：法線オフセット（多くの場合は未使用またはゼロ）

また、便利関数として以下も用意されています：

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

---

### 💻 C 例

```c
#define MAX_BLENDS 4

typedef struct Vertex {
    ufbx_vec3 position;
    ufbx_vec3 normal;
    ufbx_vec3 blend_offsets[MAX_BLENDS];
} Vertex;

Vertex get_blend_vertex(ufbx_mesh *mesh, ufbx_blend_deformer *deformer, size_t index)
{
    Vertex v = { 0 };
    v.position = ufbx_get_vertex_vec3(&mesh->vertex_position, index);
    v.normal = ufbx_get_vertex_vec3(&mesh->vertex_normal, index);

    uint32_t vertex = mesh->vertex_indices.data[index];
    size_t num_blends = deformer->channels.count;
    if (num_blends > MAX_BLENDS) num_blends = MAX_BLENDS;

    for (size_t i = 0; i < num_blends; i++) {
        ufbx_blend_channel *channel = deformer->channels.data[i];
        ufbx_blend_shape *shape = channel->target_shape;
        assert(shape);
        v.blend_offsets[i] = ufbx_get_blend_shape_vertex_offset(shape, vertex); 
    }

    return v;
}
```

---

### 💻 C++ 例

```cpp
#define MAX_BLENDS 4

struct Vertex {
    ufbx_vec3 position;
    ufbx_vec3 normal;
    ufbx_vec3 blend_offsets[MAX_BLENDS];
};

Vertex get_blend_vertex(ufbx_mesh *mesh, ufbx_blend_deformer *deformer, size_t index)
{
    Vertex v = { };
    v.position = mesh->vertex_position[index];
    v.normal = mesh->vertex_normal[index];

    uint32_t vertex = mesh->vertex_indices[index];
    size_t num_blends = deformer->channels.count;
    if (num_blends > MAX_BLENDS) num_blends = MAX_BLENDS;

    for (size_t i = 0; i < num_blends; i++) {
        ufbx_blend_channel *channel = deformer->channels[i];
        ufbx_blend_shape *shape = channel->target_shape;
        assert(shape);
        v.blend_offsets[i] = ufbx_get_blend_shape_vertex_offset(shape, vertex); 
    }

    return v;
}
```

---

### 💻 Rust 例

```rust
const MAX_BLENDS: usize = 4;

#[derive(Clone, Copy, Default)]
struct Vertex {
    position: ufbx::Vec3,
    normal: ufbx::Vec3,
    blend_offsets: [ufbx::Vec3; MAX_BLENDS],
}

fn get_blend_vertex(mesh: &ufbx::Mesh, deformer: &ufbx::BlendDeformer, index: usize) -> Vertex {
    let mut v = Vertex{
        position: mesh.vertex_position[index],
        normal: mesh.vertex_normal[index],
        ..Default::default()
    };

    let vertex = mesh.vertex_indices[index] as usize;
    let num_blends = (deformer.channels.len() as usize).min(MAX_BLENDS);
    for i in 0..num_blends {
        let channel = &deformer.channels[i];
        let shape = channel.target_shape.as_ref().expect("no blend shape, broken file");
        v.blend_offsets[i] = shape.get_vertex_offset(vertex); 
    }

    v
}
```

---

<span style="white-space: pre-wrap;">📘 </span>****備考****  
このドキュメントは MIT / Public Domain ライセンスのもとで公開された  
[ufbx (c) 2020 Samuli Raivio](https://ufbx.github.io)<span style="white-space: pre-wrap;"> の内容を翻訳・整形したものです。</span>

# FBX

# 📦 FBX フォーマットの内部構造

このセクションでは、****FBX ファイルフォーマットの内部仕様****<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;"> が FBX フォーマット特有の挙動や癖を</span>  
内部で自動的に処理するよう設計されているためです。

---

## ⚠️ 注意

FBX フォーマットは非常に複雑で、  
****あまり使われないが存在する多くの機能****<span style="white-space: pre-wrap;"> を持っています。</span>  
そのため、FBX ファイルを直接扱う場合は次の点に注意が必要です。

> 💡 新しい FBX ファイルを読み込むたびに、  
> そのファイルが利用している未対応の機能に対応する必要があるかもしれません。

<span style="white-space: pre-wrap;">もし自分自身で </span>****インポータと出力ファイルの両方を管理している****<span style="white-space: pre-wrap;"> 場合は、</span>  
必要な機能だけをサポートすれば十分ですが、  
そうでない場合は広範囲な仕様への対応が求められます。

---

<span style="white-space: pre-wrap;">📘 </span>****補足****  
この内容は MIT / Public Domain ライセンスのもとで公開された  
[ufbx (c) 2020 Samuli Raivio](https://ufbx.github.io)<span style="white-space: pre-wrap;"> のドキュメントを翻訳・整形したものです。</span>

# 🧭 Node Transforms（ノード変換）

FBX のノード変換は、****一連の変換のチェーン****として構成されています。

もし特別な理由がなければ、FBX 固有の変換モデルを直接扱うよりも、  
****ufbx が提供する変換表現****を使用することを強く推奨します。  
<span style="white-space: pre-wrap;">詳細は → </span>[Elements / Nodes / Transforms](/elements/nodes/#transforms)<span style="white-space: pre-wrap;"> を参照してください。</span>

---

## 🔩 基本構造（Transform Properties）

FBX 内でのノード変換は、いくつかの****プロパティ****で構成されています。

<table id="bkmrk-%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E5%90%8D%E6%84%8F%E5%91%B3%22lcl-transla"><colgroup><col></col><col></col></colgroup><tbody><tr><th>プロパティ名

</th><th>意味

</th></tr><tr><td>`<span class="editor-theme-code">"Lcl Translation"</span>`

</td><td>親ノードに対する平行移動

</td></tr><tr><td>`<span class="editor-theme-code">"Lcl Scaling"</span>`

</td><td>親ノードに対する非一様スケール

</td></tr><tr><td>`<span class="editor-theme-code">"Lcl Rotation"</span>`

</td><td>親ノードに対する回転（オイラー角）

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

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

<span style="white-space: pre-wrap;"> のオイラー回転順序（</span>

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

）

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

---

### 🎯 ピボット・オフセット関連

以下のプロパティによって、回転やスケールの中心・ずれが定義されます。

<table id="bkmrk-%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E5%90%8D%E5%86%85%E5%AE%B9%22scalingpivo"><colgroup><col></col><col></col></colgroup><tbody><tr><th>プロパティ名

</th><th>内容

</th></tr><tr><td>`<span class="editor-theme-code">"ScalingPivot"</span>`

</td><td>スケーリングの中心点

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

</td><td>スケール後のオフセット移動

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

</td><td>回転の中心点

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

</td><td>回転後のオフセット移動

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

<span style="white-space: pre-wrap;">さらに </span>`<span class="editor-theme-code">"Lcl Rotation"</span>`<span style="white-space: pre-wrap;"> 以外に、</span>****2種類の補助回転****が存在します：

<table id="bkmrk-%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E5%90%8D%E5%86%85%E5%AE%B9%22prerotation"><colgroup><col></col><col></col></colgroup><tbody><tr><th>プロパティ名

</th><th>内容

</th></tr><tr><td>`<span class="editor-theme-code">"PreRotation"</span>`

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

<span style="white-space: pre-wrap;"> の前に適用される回転（常に XYZ 順）</span>

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

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

<span style="white-space: pre-wrap;"> の後に適用される</span>

****逆回転****

（常に XYZ 順）

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

---

## ⚙️ 変換チェーンの計算例

以下は、****ufbx の内部補正（adjust transform）を考慮しない****  
基本的なノード変換の計算例です。

```cpp
// 手動で `ufbx_node.node_to_parent` を計算
// ※ ufbx固有の調整変換（adjust transform）は考慮しない
Matrix4 get_transform(ufbx_node *node)
{
    ufbx_props *props = &node->props;

    // 主要プロパティを取得（必要に応じてカーブから評価）
    int64_t rotation_order  = ufbx_find_int(props, "RotationOrder", 0);
    Vector3 lcl_translation = ufbx_find_vec3(props, "Lcl Translation", ufbx_zero_vec3);
    Vector3 lcl_scaling     = ufbx_find_vec3(props, "Lcl Scaling", ufbx_zero_vec3);
    Vector3 lcl_rotation    = ufbx_find_vec3(props, "Lcl Rotation", ufbx_zero_vec3);
    Vector3 rotation_pivot  = ufbx_find_vec3(props, "RotationPivot", ufbx_zero_vec3);
    Vector3 scaling_pivot   = ufbx_find_vec3(props, "ScalingPivot", ufbx_zero_vec3);
    Vector3 rotation_offset = ufbx_find_vec3(props, "RotationOffset", ufbx_zero_vec3);
    Vector3 scaling_offset  = ufbx_find_vec3(props, "ScalingOffset", ufbx_zero_vec3);
    Vector3 pre_rotation    = ufbx_find_vec3(props, "PreRotation", ufbx_zero_vec3);
    Vector3 post_rotation   = ufbx_find_vec3(props, "PostRotation", ufbx_zero_vec3);

    // オイラー角 → クォータニオン変換
    Quaternion lcl_quat = Quaternion_euler(lcl_rotation, (EulerOrder)rotation_order);
    Quaternion pre_quat = Quaternion_euler(pre_rotation, EulerOrder_XYZ);
    Quaternion post_quat = Quaternion_euler(post_rotation, EulerOrder_XYZ);

    Matrix4 m = Matrix4_identity;

    // スケール適用（ピボット・オフセット含む）
    m = Matrix4_translate(-scaling_pivot) * m;
    m = Matrix4_scale_nonuniform(lcl_scaling) * m;
    m = Matrix4_translate(scaling_pivot) * m;
    m = Matrix4_translate(scaling_offset) * m;

    // 回転適用（PostRotation は反転）
    m = Matrix4_translate(-rotation_pivot) * m;
    m = Matrix4_rotate(Quaternion_inverse(post_quat)) * m;
    m = Matrix4_rotate(lcl_quat) * m;
    m = Matrix4_rotate(pre_quat) * m;
    m = Matrix4_translate(rotation_pivot) * m;
    m = Matrix4_translate(rotation_offset) * m;

    // 最後に平行移動
    m = Matrix4_translate(lcl_translation) * m;

    return m;
}
```

---

## 🧮 Adjust Transforms（調整変換）

FBX の座標系やピボットの扱いに応じて、  
ufbx は内部でいくつかの「調整変換（adjust transform）」を自動的に付与します。  
これらを考慮しないと、見た目上の座標がずれることがあります。

### 主な adjust transform の対応表

<table id="bkmrk-%E6%A9%9F%E8%83%BD%E5%AF%BE%E5%BF%9C%E3%81%99%E3%82%8B%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89ufbx_spac"><colgroup><col></col><col></col></colgroup><tbody><tr><th>機能

</th><th>対応するフィールド

</th></tr><tr><td>`<span class="editor-theme-code">UFBX_SPACE_CONVERSION_ADJUST_TRANSFORMS</span>`

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

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

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

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

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

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

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

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

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

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

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

</td></tr><tr><td>`<span class="editor-theme-code">ufbx_load_opts.target_camera_axes</span>`

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

</td></tr><tr><td>`<span class="editor-theme-code">ufbx_load_opts.target_light_axes</span>`

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

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

`<span class="editor-theme-code">ufbx_node.has_adjust_transform</span>`<span style="white-space: pre-wrap;"> が </span>`<span class="editor-theme-code">true</span>`<span style="white-space: pre-wrap;"> の場合は、</span>  
ノードが非単位（≠ identity）の調整変換を持っています。  
ただし、常に適用しても安全です。

---

### 💻 Adjust 変換対応版の完全計算例

```cpp
// ufbx固有の adjust transform を考慮した `ufbx_node.node_to_parent` の計算
Matrix4 get_transform(ufbx_node *node)
{
    ufbx_props *props = &node->props;

    // プロパティの取得
    int64_t rotation_order  = ufbx_find_int(props, "RotationOrder", 0);
    Vector3 lcl_translation = ufbx_find_vec3(props, "Lcl Translation", ufbx_zero_vec3);
    Vector3 lcl_scaling     = ufbx_find_vec3(props, "Lcl Scaling", ufbx_zero_vec3);
    Vector3 lcl_rotation    = ufbx_find_vec3(props, "Lcl Rotation", ufbx_zero_vec3);
    Vector3 rotation_pivot  = ufbx_find_vec3(props, "RotationPivot", ufbx_zero_vec3);
    Vector3 scaling_pivot   = ufbx_find_vec3(props, "ScalingPivot", ufbx_zero_vec3);
    Vector3 rotation_offset = ufbx_find_vec3(props, "RotationOffset", ufbx_zero_vec3);
    Vector3 scaling_offset  = ufbx_find_vec3(props, "ScalingOffset", ufbx_zero_vec3);
    Vector3 pre_rotation    = ufbx_find_vec3(props, "PreRotation", ufbx_zero_vec3);
    Vector3 post_rotation   = ufbx_find_vec3(props, "PostRotation", ufbx_zero_vec3);

    // ufbx 特有の調整パラメータ
    Vector3 adjust_pre_translation = node->adjust_pre_translation;
    Quaternion adjust_pre_rotation = node->adjust_pre_rotation;
    Quaternion adjust_post_rotation = node->adjust_post_rotation;
    float adjust_pre_scale = (float)node->adjust_pre_scale;
    float adjust_post_scale = (float)node->adjust_post_scale;
    float adjust_translation_scale = (float)node->adjust_translation_scale;

    // クォータニオン化
    Quaternion lcl_quat = Quaternion_euler(lcl_rotation, (EulerOrder)rotation_order);
    Quaternion pre_quat = Quaternion_euler(pre_rotation, EulerOrder_XYZ);
    Quaternion post_quat = Quaternion_euler(post_rotation, EulerOrder_XYZ);

    Matrix4 m = Matrix4_identity;

    // 後処理（post-adjust）
    m = Matrix4_rotate(adjust_post_rotation) * m;
    m = Matrix4_scale(adjust_post_scale) * m;

    // スケール
    m = Matrix4_translate(-scaling_pivot) * m;
    m = Matrix4_scale_nonuniform(lcl_scaling) * m;
    m = Matrix4_translate(scaling_pivot) * m;
    m = Matrix4_translate(scaling_offset) * m;

    // 回転
    m = Matrix4_translate(-rotation_pivot) * m;
    m = Matrix4_rotate(Quaternion_inverse(post_quat)) * m;
    m = Matrix4_rotate(lcl_quat) * m;
    m = Matrix4_rotate(pre_quat) * m;
    m = Matrix4_translate(rotation_pivot) * m;
    m = Matrix4_translate(rotation_offset) * m;

    // 平行移動
    m = Matrix4_translate(lcl_translation) * m;

    // 前処理（pre-adjust）
    m = Matrix4_translate(adjust_pre_translation) * m;
    m = Matrix4_rotate(adjust_pre_rotation) * m;
    m = Matrix4_scale(adjust_pre_scale) * m;

    // translation のみスケーリング
    m.m03 *= adjust_translation_scale;
    m.m13 *= adjust_translation_scale;
    m.m23 *= adjust_translation_scale;

    return m;
}
```

📘 実際の実装例：  
[`<span class="editor-theme-code">ufbxi_get_transform()</span>`<span style="white-space: pre-wrap;"> on GitHub</span>](https://github.com/ufbx/ufbx/blob/6dd7771ee215c7489a211b7aa259f1056ce14354/ufbx.c#L21497-L21558)

---

## 🧱 Geometric Transforms（ジオメトリ変換）

ジオメトリ変換（**geometry transforms**）は、  
ノードの****子ノードには影響せず、ノード自身の内容（例：メッシュ）だけを変換****します。

<span style="white-space: pre-wrap;">詳細は → </span>[Elements / Nodes / Geometry Transforms](/elements/nodes/#geometry-transforms)

<table id="bkmrk-%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E5%90%8D%E5%86%85%E5%AE%B9%22geometrictr"><colgroup><col></col><col></col></colgroup><tbody><tr><th>プロパティ名

</th><th>内容

</th></tr><tr><td>`<span class="editor-theme-code">"GeometricTranslation"</span>`

</td><td>ノード内コンテンツの平行移動

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

</td><td>ノード内コンテンツのスケール

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

</td><td>ノード内コンテンツの回転（常に XYZ 順）

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

---

### 💻 Geometry Transform の計算例

```cpp
// 手動で `ufbx_node.geometry_to_node` を計算
Matrix4 get_geometry_transform(ufbx_node *node)
{
    ufbx_props *props = &node->props;

    Vector3 geo_translation = ufbx_find_vec3(props, "GeometricTranslation", ufbx_zero_vec3);
    Vector3 geo_scaling     = ufbx_find_vec3(props, "GeometricScaling", ufbx_zero_vec3);
    Vector3 geo_rotation    = ufbx_find_vec3(props, "GeometricRotation", ufbx_zero_vec3);

    Quaternion geo_quat = Quaternion_euler(geo_rotation, EulerOrder_XYZ);

    Matrix4 m = Matrix4_identity;
    m = Matrix4_scale_nonuniform(geo_scaling) * m;
    m = Matrix4_rotate(geo_quat) * m;
    m = Matrix4_translate(geo_translation) * m;

    return m;
}
```

---

<span style="white-space: pre-wrap;">📘 </span>****備考****  
このドキュメントは MIT / Public Domain ライセンスのもとで公開された  
[ufbx (c) 2020 Samuli Raivio](https://ufbx.github.io)<span style="white-space: pre-wrap;"> の内容を翻訳・整形しています。</span>

# Advanced

# ⚙️ Advanced（応用編）

このセクションでは、****ufbx の高度な利用方法や特殊なケース****<span style="white-space: pre-wrap;"> について解説します。</span>  
標準的なモデルの読み込み・描画に加え、より深い制御や拡張を行いたい場合に参照してください。

---

<span style="white-space: pre-wrap;">💡 </span>****この章に含まれるトピック（例）****

<table id="bkmrk-%E9%A0%85%E7%9B%AE%E6%A6%82%E8%A6%81%F0%9F%A7%A9-custom-load-op"><colgroup><col></col><col></col></colgroup><tbody><tr><th>項目

</th><th>概要

</th></tr><tr><td><span style="white-space: pre-wrap;">🧩 </span>

****Custom Load Options****

</td><td>読み込み時に座標系・軸設定・空間変換を指定する方法

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

****Memory Management****

</td><td>外部アロケータや独自メモリ管理の統合

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

****Low-level Access****

</td><td>ファイル内部のノード・プロパティ・カーブへの直接アクセス

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

****Threading / Async Loading****

</td><td>スレッドセーフな利用・非同期読み込みの実装例

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

****Internal Structures****

</td><td>ufbx 内部の構造体設計・評価順序の理解

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

---

<span style="white-space: pre-wrap;">📘 </span>****備考****  
このドキュメントは MIT / Public Domain ライセンスのもとで公開された  
[ufbx (c) 2020 Samuli Raivio](https://ufbx.github.io)<span style="white-space: pre-wrap;"> の内容を翻訳・整形しています。</span>

# 🧩 Build Options（ビルドオプション）

**ufbx**<span style="white-space: pre-wrap;"> のビルドは、主に </span>****プリプロセッサマクロ（**`<strong class="editor-theme-bold editor-theme-code">#define</strong>`**）****<span style="white-space: pre-wrap;"> によってカスタマイズします。</span>

マクロの定義方法は次のいずれかです。

1. コンパイラオプションでグローバルに指定する
2. `<span class="editor-theme-code">"ufbx.h"</span>`<span style="white-space: pre-wrap;"> や </span>`<span class="editor-theme-code">"ufbx.c"</span>`<span style="white-space: pre-wrap;"> をインクルードする前にマクロを定義する</span>
3. または以下を定義して独自設定ファイルを読み込む：

```c
#define UFBX_CONFIG_HEADER "my-config.h"
#define UFBX_CONFIG_SOURCE "my-source-config.h"
```

これにより、`<span class="editor-theme-code">ufbx.h</span>`<span style="white-space: pre-wrap;"> および </span>`<span class="editor-theme-code">ufbx.c</span>`<span style="white-space: pre-wrap;"> 内で指定した設定ファイルが自動的にインクルードされます。</span>

---

## 📘 ヘッダ設定（Header）

<span style="white-space: pre-wrap;">多くの設定マクロは </span>`<span class="editor-theme-code">"ufbx.c"</span>`<span style="white-space: pre-wrap;"> 内だけで有効にすれば十分です。</span>  
ただし、****型やインライン関数に影響を与えるマクロ****<span style="white-space: pre-wrap;"> は </span>`<span class="editor-theme-code">"ufbx.h"</span>`<span style="white-space: pre-wrap;"> にも定義する必要があります。</span>

```c
// アサートを独自実装に置き換える
#define ufbx_assert(cond) my_assert(cond)

// 浮動小数型を double → float に変更
#define UFBX_REAL_IS_FLOAT
```

---

## ⚙️ オプション機能の無効化

**ufbx**<span style="white-space: pre-wrap;"> のサイズを小さくしたい場合、</span>  
特定の機能をマクロで無効化できます。

```c
// メッシュの細分化
#define UFBX_NO_SUBDIVISION

// NURBS のテッセレーション
#define UFBX_NO_TESSELLATION

// ジオメトリキャッシュの読み込み
#define UFBX_NO_GEOMETRY_CACHE

// シーン評価
#define UFBX_NO_SCENE_EVALUATION

// スキン評価
#define UFBX_NO_SKINNING_EVALUATION

// アニメーションベイク
#define UFBX_NO_ANIMATION_BAKING

// 面の三角化
#define UFBX_NO_TRIANGULATION

// インデックス生成
#define UFBX_NO_INDEX_GENERATION

// OBJ 形式の読み込みを無効化
#define UFBX_NO_FORMAT_OBJ
```

---

## 💾 メモリアロケーション（Memory Allocation）

**ufbx**<span style="white-space: pre-wrap;"> は標準の </span>`<span class="editor-theme-code">malloc()</span>`<span style="white-space: pre-wrap;"> / </span>`<span class="editor-theme-code">realloc()</span>`<span style="white-space: pre-wrap;"> / </span>`<span class="editor-theme-code">free()</span>`<span style="white-space: pre-wrap;"> を使用します。</span>  
これを独自アロケータに置き換える方法は3通りあります：

### 方法①：マクロでフックする

```c
#define ufbx_malloc(size) my_alloc(size)
#define ufbx_realloc(ptr, old_size, new_size) my_realloc(ptr, old_size, new_size)
#define ufbx_free(ptr, size) my_free(ptr, size)

#include "ufbx.c"
```

### 方法②：外部関数として定義する

```c
#define UFBX_EXTERNAL_MALLOC

void *ufbx_malloc(size_t size);
void *ufbx_realloc(void *ptr, size_t old_size, size_t new_size);
void ufbx_free(void *ptr, size_t size);
```

### 方法③：アロケータを完全に無効化する

```c
#define UFBX_NO_MALLOC
```

<span style="white-space: pre-wrap;">この場合、ユーザーが </span>`<span class="editor-theme-code">ufbx_allocator</span>`<span style="white-space: pre-wrap;"> を提供しない限り、</span>  
メモリ確保を行う API はすべて失敗します。

---

## 📂 ファイル入出力（File I/O）

<span style="white-space: pre-wrap;">標準の </span>`<span class="editor-theme-code">FILE</span>`<span style="white-space: pre-wrap;"> API を使用して </span>`<span class="editor-theme-code">ufbx_load_file()</span>`<span style="white-space: pre-wrap;"> が動作します。</span>  
独自のファイルI/Oを使いたい場合は、以下の方法で上書き可能です。

### 外部定義で差し替え

```c
#define UFBX_EXTERNAL_STDIO

void *ufbx_stdio_open(const char *path, size_t path_len);
size_t ufbx_stdio_read(void *file, void *data, size_t size);
bool   ufbx_stdio_skip(void *file, size_t size);
uint64_t ufbx_stdio_size(void *file);
void   ufbx_stdio_close(void *file);
```

### 標準I/Oを完全に無効化

```c
#define UFBX_NO_STDIO
```

この場合、`<span class="editor-theme-code">ufbx_load_file()</span>`<span style="white-space: pre-wrap;"> など </span>`<span class="editor-theme-code">FILE</span>`<span style="white-space: pre-wrap;"> に依存する機能は利用できません。</span>  
代わりに、`<span class="editor-theme-code">ufbx_load_opts.open_file_cb</span>`<span style="white-space: pre-wrap;"> によるカスタム読み込みを利用します。</span>

---

## 🧮 数学関数（Math）

**ufbx**<span style="white-space: pre-wrap;"> は </span>`<span class="editor-theme-code"><math.h></span>`<span style="white-space: pre-wrap;"> の一部関数を利用しますが、</span>  
****ビット単位で一致する結果を保証したい場合****や  
****標準ライブラリを使用できない環境****では、  
外部定義で上書きすることができます。

```c
#define UFBX_EXTERNAL_MATH

double ufbx_sqrt(double x);
double ufbx_sin(double x);
double ufbx_cos(double x);
double ufbx_tan(double x);
double ufbx_asin(double x);
double ufbx_acos(double x);
double ufbx_atan(double x);
double ufbx_atan2(double y, double x);
double ufbx_pow(double x, double y);
double ufbx_fmin(double a, double b);
double ufbx_fmax(double a, double b);
double ufbx_fabs(double x);
double ufbx_copysign(double x, double y);
double ufbx_nextafter(double x, double y);
double ufbx_rint(double x);
double ufbx_ceil(double x);
int    ufbx_isnan(double x);
```

これらは自前で定義するか、  
[`<span class="editor-theme-code">extra/ufbx_math.c</span>`](https://github.com/ufbx/ufbx/blob/master/extra/ufbx_math.c)<span style="white-space: pre-wrap;"> を使用可能です。</span>

---

## 🧱 標準ライブラリの除去（C Standard Library）

`<span class="editor-theme-code">UFBX_NO_LIBC</span>`<span style="white-space: pre-wrap;"> を定義すると、</span>  
ほとんどの標準ライブラリ依存を無効化できます。  
これにより組み込み環境などでも利用可能になります。

```c
#define UFBX_NO_LIBC
```

この定義により、デフォルトで以下が暗黙的に有効になります：

- `<span class="editor-theme-code">UFBX_EXTERNAL_MALLOC</span>`
- `<span class="editor-theme-code">UFBX_EXTERNAL_STDIO</span>`
- `<span class="editor-theme-code">UFBX_EXTERNAL_MATH</span>`

標準機能を完全に使わない場合は：

```c
#define UFBX_NO_MALLOC
#define UFBX_NO_STDIO
```

を併用します。

---

### `<span class="editor-theme-code"><string.h></span>`<span style="white-space: pre-wrap;"> 関数の再実装が必要</span>

標準ライブラリを使わない場合、以下の関数を提供する必要があります。  
<span style="white-space: pre-wrap;">（または </span>[`<span class="editor-theme-code">extra/ufbx_libc.c</span>`](https://github.com/ufbx/ufbx/blob/master/extra/ufbx_libc.c)<span style="white-space: pre-wrap;"> を使用）</span>

```c
size_t ufbx_strlen(const char *str);
void *ufbx_memcpy(void *dst, const void *src, size_t count);
void *ufbx_memmove(void *dst, const void *src, size_t count);
void *ufbx_memset(void *dst, int ch, size_t count);
const void *ufbx_memchr(const void *ptr, int value, size_t count);
int ufbx_memcmp(const void *a, const void *b, size_t count);
int ufbx_strcmp(const char *a, const char *b);
int ufbx_strncmp(const char *a, const char *b, size_t count);
```

---

### 📦 最低限必要なヘッダ

以下のヘッダは、ライブラリなしでも通常利用可能です：

```c
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdarg.h>
```

もしこれらすら利用できない環境では：

```c
#define UFBX_NO_LIBC_TYPES
```

<span style="white-space: pre-wrap;">を定義し、自前でこれらの型定義を </span>`<span class="editor-theme-code">"ufbx.h"</span>`<span style="white-space: pre-wrap;"> と </span>`<span class="editor-theme-code">"ufbx.c"</span>`<span style="white-space: pre-wrap;"> の両方に用意する必要があります。</span>

---

<span style="white-space: pre-wrap;">📘 </span>****備考****  
このドキュメントは MIT / Public Domain ライセンスのもとで公開された  
[ufbx (c) 2020 Samuli Raivio](https://ufbx.github.io)<span style="white-space: pre-wrap;"> の内容を翻訳・整形しています。</span>

# Reference