> ## Content Index
> Fetch the complete content index at: https://www.geekjp.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# XMFLOATなのかXMVECTORなのか問題
- URL: https://www.geekjp.com/aboutxmvector/
- Published: 2026-07-23T15:19:55.000Z
- Updated: 2026-08-01T12:19:05.000Z
- Description: XMFLOATなのかXMVECTORなのか問題 XMFLOAT3とXMVECTORは何が違うのか。 調べてまとめてみた。
- Author: 工学じじい
- Tags: ゲームプログラミング, プログラミング

## DirectXMathの使い分けを調べてみた

DirectXMathを使い始めると、最初に迷いやすいのが`XMVECTOR`と`XMFLOAT3`の使い分けです。  
どちらも3次元ベクトルを扱えそうに見えますが、DirectXMathの関数の引数などを見るとどうやらなんかしらの使い分けがありそうです。  
  
公式のドキュメントなどを参照してみると、基本方針は次のとおりの様です。

> **`XMFLOAT3`はデータを保存するための型、`XMVECTOR`は計算するための型として使う。**

クラスや構造体のメンバ変数には`XMFLOAT3`を使い、計算が必要になったら`XMLoadFloat3()`で`XMVECTOR`へ読み込みます。計算が終わったら、`XMStoreFloat3()`で結果を`XMFLOAT3`へ戻します。

```text
XMFLOAT3に保存
    ↓ XMLoadFloat3()
XMVECTORで計算
    ↓ XMStoreFloat3()
XMFLOAT3に保存

```

 そこで、この記事では`XMVECTOR`と`XMFLOAT3`の基本的な違いから、`XMLoadFloat3()`と`XMStoreFloat3()`、ゲーム内での移動計算、`Transform`クラスでの設計例まで順番に説明します。

記事の最後には、公式ドキュメントでよく見かける`FXMVECTOR`、`GXMVECTOR`、`HXMVECTOR`、`CXMVECTOR`、`XM_CALLCONV`についての付録も用意しています。これらはおまけとして調べてみましたので、特に気にせずXMVECTORのシノニムだと思って使って良いと思います（はじめのうちは）。

## この記事でわかること

- `XMVECTOR`と`XMFLOAT3`の違い
- 保存用と計算用を分ける理由
- `XMLoadFloat3()`と`XMStoreFloat3()`の使い方
- ゲームオブジェクトの位置を更新する実装例
- 位置・方向・法線を行列変換するときの違い
- `Transform`クラスのメンバ型と関数設計
- 付録：`FXMVECTOR`系と`XM_CALLCONV`が必要な理由
- 頂点バッファや定数バッファでの使い方

---

## XMVECTORとXMFLOAT3の違い

まずは、それぞれの役割を比較します。

| 項目        | XMVECTOR           | XMFLOAT3                 |
| --------- | ------------------ | ------------------------ |
| 主な用途      | ベクトル計算             | データの保存                   |
| 要素数       | 4要素                | 3要素                      |
| SIMD演算    | DirectXMath関数で利用する | そのままでは利用しない              |
| メンバへのアクセス | 基本的に専用関数を使う        | .x、.y、.zでアクセスできる         |
| クラスのメンバ   | 一時的な計算値向き          | 状態の保持に向く                 |
| 頂点データ     | 通常は使わない            | 位置や法線に使いやすい              |
| ファイル保存    | 扱いにくい              | 扱いやすい                    |
| 関数内の中間計算  | 向いている              | DirectXMath関数を使うにはロードが必要 |

簡単に表現するなら、次のように考えるとわかりやすいでしょう。

> **`XMFLOAT3`は倉庫、`XMVECTOR`は作業台。**

ゲームオブジェクトの位置は`XMFLOAT3`として倉庫に保存しておきます。移動や回転などの計算が必要になったときだけ、`XMVECTOR`という作業台へ持ってきて処理します。  
つまり、ベクトルの３または４要素をまるっと一度に計算する場面では、XMVECTOR使ったほうが、効率いいし速そうだよ。ってことです。

---

## XMVECTORとは

`XMVECTOR`は、DirectXMathライブラリでベクトル演算を行うための中心的な型です。

```cpp
#include <DirectXMath.h>

using namespace DirectX;

XMVECTOR a = XMVectorSet(1.0f, 2.0f, 3.0f, 0.0f);
XMVECTOR b = XMVectorSet(4.0f, 5.0f, 6.0f, 0.0f);

XMVECTOR result = XMVectorAdd(a, b);

```

`XMVECTOR`は、4個の32ビット値をまとめて扱います。

```text
x, y, z, w

```

SSEを使用する環境では`__m128`、ARM NEONを使用する環境では`float32x4_t`など、対象環境に応じたSIMD型として定義されます。

DirectXMathの現在のヘッダーでは、概念的に次のように切り替えられています。

```cpp
// SSEを使用する環境
using XMVECTOR = __m128;

// ARM NEONを使用する環境
using XMVECTOR = float32x4_t;

```

そのため、`XMVECTOR`を普通の構造体だと考えて、常に次のようなアクセスができるとは限りません。

```cpp
// 基本的には、このような直接アクセスを前提にしない
vector.x = 10.0f;

```

要素を取得するときは、DirectXMathのアクセサ関数を使用します。

```cpp
float x = XMVectorGetX(vector);
float y = XMVectorGetY(vector);
float z = XMVectorGetZ(vector);
float w = XMVectorGetW(vector);

```

値を変更するときも、専用関数を使用できます。

```cpp
vector = XMVectorSetX(vector, 10.0f);
vector = XMVectorSetY(vector, 20.0f);

```

ただし、個々の成分を何度も取り出して計算するのであれば、そもそも`XMVECTOR`を使う意味が薄くなります。`XMVECTOR`は、DirectXMathのベクトル関数を使って、複数の成分をまとめて処理するための型です。

---

## XMFLOAT2・XMFLOAT3・XMFLOAT4とは

`XMFLOAT`系は、浮動小数点数をメモリ上に保存するための構造体です。

代表的な型には、次のものがあります。

```cpp
XMFLOAT2 uv;
XMFLOAT3 position;
XMFLOAT4 color;
XMFLOAT4 quaternion;
XMFLOAT4X4 matrix;

```

`XMFLOAT3`は、実質的に次のような構造です。

```cpp
struct XMFLOAT3
{
    float x;
    float y;
    float z;
};

```

そのため、通常のC++の構造体と同じ感覚で扱えます。

```cpp
XMFLOAT3 position(10.0f, 20.0f, 30.0f);

position.x += 5.0f;
position.y = 0.0f;

```

`XMFLOAT3`が向いている主な用途は次のとおりです。

- ゲームオブジェクトの位置・回転・スケールの保持
- 頂点バッファの位置・法線データ
- ファイルへの保存と読み込み
- エディターやデバッグ画面への表示
- ネットワーク送信用のデータ
- `XMVECTOR`で計算した結果の格納

`XMFLOAT3`は保存しやすく、メンバへ直接アクセスできます。ただし、`XMVectorAdd()`や`XMVector3Normalize()`などの関数へ、そのまま渡すことはできません。

```cpp
XMFLOAT3 position(1.0f, 2.0f, 3.0f);

// XMFLOAT3をそのまま渡すことはできない
// XMVECTOR result = XMVector3Normalize(position);

```

DirectXMathのベクトル関数で計算するときは、`XMVECTOR`へロードします。

---

## XMLoadFloat3とXMStoreFloat3

`XMFLOAT3`と`XMVECTOR`の間では、ロード関数とストア関数を使用します。

### XMFLOAT3からXMVECTORへ読み込む

```cpp
XMFLOAT3 position(1.0f, 2.0f, 3.0f);

XMVECTOR positionVector = XMLoadFloat3(&position);

```

`XMLoadFloat3()`は、`XMFLOAT3`の`x`、`y`、`z`を`XMVECTOR`へ読み込みます。

`XMFLOAT3`には`w`が存在しないため、ロード後の`w`成分は`0.0f`になります。

```text
XMFLOAT3            XMVECTOR
x = 1.0     →       x = 1.0
x = 2.0     →       y = 2.0
z = 3.0     →       z = 3.0
                    w = 0.0

```

### XMVECTORからXMFLOAT3へ保存する

```cpp
XMVECTOR positionVector = XMVectorSet(1.0f, 2.0f, 3.0f, 0.0f);

XMFLOAT3 position;
XMStoreFloat3(&position, positionVector);

```

`XMStoreFloat3()`は、`XMVECTOR`の`x`、`y`、`z`を`XMFLOAT3`へ書き込みます。`w`成分は保存されません。

### 基本的なデータの流れ

```cpp
XMFLOAT3 position(1.0f, 2.0f, 3.0f);
XMFLOAT3 velocity(4.0f, 0.0f, 0.0f);

// 1. 保存用データを計算用の型へロード
XMVECTOR p = XMLoadFloat3(&position);
XMVECTOR v = XMLoadFloat3(&velocity);

// 2. XMVECTORで計算
p = XMVectorAdd(p, v);

// 3. 計算結果を保存用データへストア
XMStoreFloat3(&position, p);

```

これが、DirectXMathを使うときの基本パターンです。

---

## プレイヤーの位置を更新する実装例

ゲーム内で実際に使う形にすると、次のようになります。

```cpp
#include <DirectXMath.h>

class Player
{
private:
    DirectX::XMFLOAT3 position_;
    DirectX::XMFLOAT3 velocity_;

public:
    Player()
        : position_(0.0f, 0.0f, 0.0f),
          velocity_(3.0f, 0.0f, 0.0f)
    {
    }

    void Update(float deltaTime)
    {
        using namespace DirectX;

        XMVECTOR position = XMLoadFloat3(&position_);
        XMVECTOR velocity = XMLoadFloat3(&velocity_);

        // position = velocity * deltaTime + position
        position = XMVectorMultiplyAdd(
            velocity,
            XMVectorReplicate(deltaTime),
            position
        );

        XMStoreFloat3(&position_, position);
    }

    const DirectX::XMFLOAT3& GetPosition() const
    {
        return position_;
    }
};

```

このクラスでは、位置と速度を`XMFLOAT3`で保持しています。

```cpp
DirectX::XMFLOAT3 position_;
DirectX::XMFLOAT3 velocity_;

```

`Update()`内では、計算が必要な間だけ`XMVECTOR`へロードしています。

```cpp
XMVECTOR position = XMLoadFloat3(&position_);
XMVECTOR velocity = XMLoadFloat3(&velocity_);

```

計算が終わったら、位置だけをメンバ変数へ戻します。

```cpp
XMStoreFloat3(&position_, position);

```

このように、**長期間保持するデータと、一時的な計算データを分ける**のが基本です。

---

## ロードとストアは計算の前後にまとめる

次のコードは動作しますが、ロードとストアを何度も繰り返しています。

```cpp
XMVECTOR position = XMLoadFloat3(&position_);
position = XMVectorAdd(position, XMLoadFloat3(&velocity_));
XMStoreFloat3(&position_, position);

position = XMLoadFloat3(&position_);
position = XMVectorAdd(position, XMLoadFloat3(&acceleration_));
XMStoreFloat3(&position_, position);

```

できるだけ、計算の最初に必要な値をロードし、計算が完了してからまとめてストアします。

```cpp
XMVECTOR position = XMLoadFloat3(&position_);
XMVECTOR velocity = XMLoadFloat3(&velocity_);
XMVECTOR acceleration = XMLoadFloat3(&acceleration_);

position = XMVectorAdd(position, velocity);
position = XMVectorAdd(position, acceleration);

XMStoreFloat3(&position_, position);

```

`XMVECTOR`は、レジスタ上で連続した計算を行いやすいように設計されています。途中で何度もメモリへ戻すより、必要な計算をまとめてから結果を保存する方が、コードの意図も明確になります。

ただし、ロードとストアを1回でも行ったら遅い、という意味ではありません。最適化では、実際の処理時間をReleaseビルドで計測することが重要です。

---

## XMVECTORのw成分は何に使うのか

`XMVECTOR`は、3次元ベクトルを扱う場合でも`x`、`y`、`z`、`w`の4成分を持ちます。

```cpp
XMVECTOR value = XMVectorSet(x, y, z, w);

```

一般的な同次座標では、位置と方向を次のように表します。

| 用途      | x  | y  | z  | w |
| ------- | -- | -- | -- | - |
| 位置      | px | py | pz | 1 |
| 方向      | dx | dy | dz | 0 |
| 色       | r  | g  | b  | a |
| クォータニオン | x  | y  | z  | w |

ただし、DirectXMathの関数によっては、入力された`w`をそのまま使わず、関数側で位置または方向として扱います。

### 位置を変換するXMVector3TransformCoord

```cpp
XMVECTOR worldPosition =
    XMVector3TransformCoord(localPosition, worldMatrix);

```

`XMVector3TransformCoord()`は入力の`w`成分を無視し、`w = 1.0f`として変換します。そのため、行列の平行移動成分の影響を受けます。

返されるベクトルは、結果が`w = 1.0f`になるように射影除算されます。

### 方向や法線を変換するXMVector3TransformNormal

```cpp
XMVECTOR worldDirection =
    XMVector3TransformNormal(localDirection, worldMatrix);

```

`XMVector3TransformNormal()`は、方向ベクトルや法線ベクトルを変換するときに使います。平行移動成分は計算に含まれません。

したがって、用途によって使い分けます。

```text
頂点の位置    → XMVector3TransformCoord
移動方向      → XMVector3TransformNormal
法線ベクトル  → XMVector3TransformNormal

```

なお、非一様スケールを含む行列で法線を正しく変換する場合は、ワールド行列そのものではなく、逆転置行列を使用する必要があります。

---

## Transformクラスではどう設計するか

ゲームエンジンの`Transform`クラスでは、位置・回転・スケールを長期間保持します。

そのため、メンバ変数には`XMFLOAT3`を使用する設計が扱いやすいでしょう。

```cpp
#pragma once

#include <DirectXMath.h>

class Transform
{
private:
    DirectX::XMFLOAT3 position_;
    DirectX::XMFLOAT3 rotation_;
    DirectX::XMFLOAT3 scale_;

public:
    Transform()
        : position_(0.0f, 0.0f, 0.0f),
          rotation_(0.0f, 0.0f, 0.0f),
          scale_(1.0f, 1.0f, 1.0f)
    {
    }

    const DirectX::XMFLOAT3& GetPosition() const
    {
        return position_;
    }

    DirectX::XMVECTOR GetPositionVector() const
    {
        return DirectX::XMLoadFloat3(&position_);
    }

    void SetPosition(float x, float y, float z)
    {
        position_ = DirectX::XMFLOAT3(x, y, z);
    }

    DirectX::XMMATRIX GetWorldMatrix() const
    {
        using namespace DirectX;

        const XMMATRIX scale = XMMatrixScalingFromVector(
            XMLoadFloat3(&scale_)
        );

        const XMMATRIX rotation = XMMatrixRotationRollPitchYawFromVector(
            XMLoadFloat3(&rotation_)
        );

        const XMMATRIX translation = XMMatrixTranslationFromVector(
            XMLoadFloat3(&position_)
        );

        return scale * rotation * translation;
    }
};

```

この設計では、用途に応じて2種類の取得方法を用意しています。

```cpp
// 保存データとして参照したい
const XMFLOAT3& GetPosition() const;

// DirectXMathで計算したい
XMVECTOR GetPositionVector() const;

```

この形なら、ゲームロジック側では保存用の`XMFLOAT3`として位置を確認でき、数学処理側では`GetPositionVector()`から計算用の`XMVECTOR`を取得できます。

`XMVECTOR`を直接受け取る自作関数の書き方は、記事末尾の付録で説明します。

---

## 頂点バッファではXMFLOATを使う

頂点データは、連続したメモリ上に大量に並べてGPUへ送ります。

そのため、通常は`XMVECTOR`ではなく`XMFLOAT`系を使用します。

```cpp
struct Vertex
{
    DirectX::XMFLOAT3 position;
    DirectX::XMFLOAT3 normal;
    DirectX::XMFLOAT2 uv;
};

```

頂点データの位置をCPU側で変換するときは、ロード・計算・ストアを行います。

```cpp
void TransformVertex(
    Vertex& vertex,
    const DirectX::XMMATRIX& matrix
) noexcept
{
    using namespace DirectX;

    XMVECTOR position = XMLoadFloat3(&vertex.position);
    position = XMVector3TransformCoord(position, matrix);
    XMStoreFloat3(&vertex.position, position);

    XMVECTOR normal = XMLoadFloat3(&vertex.normal);
    normal = XMVector3TransformNormal(normal, matrix);
    normal = XMVector3Normalize(normal);
    XMStoreFloat3(&vertex.normal, normal);
}

```

実際の描画では、毎フレーム全頂点をCPUで変換するより、頂点シェーダーで変換する設計が一般的です。この例は、`XMFLOAT3`と`XMVECTOR`の役割を示すためのものです。

---

## 定数バッファではC++側とHLSL側の配置を合わせる

定数バッファへ値を送るときも、保存用の構造体には`XMFLOAT4`や`XMFLOAT4X4`を使用できます。

```cpp
struct SceneConstantBuffer
{
    DirectX::XMFLOAT4X4 world;
    DirectX::XMFLOAT4 color;
    DirectX::XMFLOAT3 lightDirection;
    float padding;
};

```

行列は`XMMATRIX`で計算し、`XMFLOAT4X4`へ保存します。

```cpp
DirectX::XMMATRIX world = transform.GetWorldMatrix();

SceneConstantBuffer buffer{};
DirectX::XMStoreFloat4x4(
    &buffer.world,
    DirectX::XMMatrixTranspose(world)
);

```

HLSLの定数バッファでは、変数が16バイト境界をまたがないように配置されます。そのため、C++側の構造体とHLSL側の`cbuffer`で、サイズと並びを対応させる必要があります。

```hlsl
cbuffer SceneConstantBuffer : register(b0)
{
    float4x4 world;
    float4 color;
    float3 lightDirection;
    float padding;
};

```

`XMFLOAT3`の直後に`float`を置く形はよく使われますが、常に機械的に`padding`を追加すればよいわけではありません。HLSL側の変数順序とパッキング規則を確認し、C++側と一致させます。

---

## XMFLOAT3Aとは

DirectXMathには、`XMFLOAT3`を16バイト境界へアラインした`XMFLOAT3A`もあります。

```cpp
DirectX::XMFLOAT3A alignedPosition;

```

`XMFLOAT3A`のロードとストアには、対応する関数を使用します。

```cpp
DirectX::XMVECTOR position =
    DirectX::XMLoadFloat3A(&alignedPosition);

DirectX::XMStoreFloat3A(
    &alignedPosition,
    position
);

```

対応関係は次のとおりです。

| 保存型       | ロード             | ストア              |
| --------- | --------------- | ---------------- |
| XMFLOAT3  | XMLoadFloat3()  | XMStoreFloat3()  |
| XMFLOAT3A | XMLoadFloat3A() | XMStoreFloat3A() |
| XMFLOAT4  | XMLoadFloat4()  | XMStoreFloat4()  |
| XMFLOAT4A | XMLoadFloat4A() | XMStoreFloat4A() |

アライン済みの型を使えば常に速くなるとは限りません。データサイズ、配列の配置、キャッシュ効率、コンパイラの最適化なども関係します。

また、アライン済み型をSTLコンテナで使用する場合は、必要なアラインメントが維持されるかを確認する必要があります。

通常のゲームオブジェクトの位置を保持するだけなら、まずは`XMFLOAT3`で十分です。実際にボトルネックが確認できた部分で、アライン済み型やデータ配置を検討する方が安全です。

---

## よくある間違い

### XMVECTORを常にクラスのメンバにする

`XMVECTOR`をメンバ変数にすること自体が禁止されているわけではありません。

ただし、次の用途では`XMFLOAT3`の方が扱いやすいことが多いです。

- ファイルへ保存する
- GUIへ表示する
- 頂点配列へ格納する
- 構造体をコピーする
- 個別成分を編集する
- C++とHLSLのデータ配置を合わせる

特別な理由がなければ、ゲームオブジェクトの状態は`XMFLOAT`系で保持し、計算中だけ`XMVECTOR`を使う形から始めるとよいでしょう。

### XMFLOAT3を成分ごとに計算し続ける

```cpp
position.x += velocity.x * deltaTime;
position.y += velocity.y * deltaTime;
position.z += velocity.z * deltaTime;

```

このコードが間違いというわけではありません。単純な処理なら十分に読みやすく、コンパイラが最適化する可能性もあります。

ただし、正規化、内積、外積、行列変換、クォータニオン回転などを行う場合は、DirectXMathの関数を使用した方が処理を統一できます。

### 位置と法線へ同じ変換関数を使う

位置には`XMVector3TransformCoord()`、方向や法線には`XMVector3TransformNormal()`を使用します。

ただし、法線については非一様スケールを含む場合に逆転置行列が必要です。

---

## 判断に迷ったときの使い分け

### XMFLOAT系を使う場面

- クラスや構造体のメンバとして保存する
- 頂点データへ格納する
- ファイルへ保存する
- エディターで編集する
- C++とHLSLの構造体を対応させる
- ベクトルの成分へ直接アクセスする

### XMVECTORを使う場面

- ベクトルの加算・減算・乗算を行う
- 正規化する
- 内積・外積を求める
- 行列で座標変換する
- クォータニオンで回転する
- 関数内で一時的な計算結果を保持する

## 最終的なデータフロー

DirectXMathを使うときは、次の流れを基本にすると整理しやすくなります。

```text
1. XMFLOAT3で状態を保持する
        ↓
2. XMLoadFloat3()でXMVECTORへロードする
        ↓
3. DirectXMathの関数で計算する
        ↓
4. XMStoreFloat3()でXMFLOAT3へ戻す

```

この「保存 → ロード → 計算 → ストア」が、この記事で最も重要な基本形です。

自作関数で`XMVECTOR`を受け取るときの書き方は、記事末尾の付録で説明します。

---

## まとめ

`XMVECTOR`と`XMFLOAT3`は、どちらか一方だけを選ぶものではありません。

それぞれの役割を分けて、一緒に使用します。

> **保存は`XMFLOAT`、計算は`XMVECTOR`。**

基本となる役割は、次の2つです。

```text
保存用：XMFLOAT2 / XMFLOAT3 / XMFLOAT4
計算用：XMVECTOR

```

- メンバ変数や頂点データでは`XMFLOAT`系を使う
- 計算するときだけ`XMVECTOR`へロードする
- 計算結果は`XMFLOAT`系へストアして保存する

まずは、この流れを理解すればDirectXMathを使い始められます。

公式ドキュメントに出てくる`FXMVECTOR`系は、通常のベクトル計算とは別の「関数の受け渡し方」の話です。必要になった段階で、後半の付録を参照してください。

---

## FAQ

### XMVECTORとXMFLOAT3は、どちらの方が速いですか？

単純に型だけで比較するものではありません。`XMFLOAT3`は保存用、`XMVECTOR`はDirectXMathによる計算用です。計算内容、メモリアクセス、コンパイラ最適化、データ配置によって性能は変わります。

### XMVECTORをクラスのメンバ変数にしてはいけませんか？

禁止ではありません。ただし、保存、ファイル入出力、デバッグ表示、頂点データなどでは`XMFLOAT3`の方が扱いやすいため、一般的な`Transform`では`XMFLOAT3`を保持して計算時にロードする設計がわかりやすいでしょう。

### 公式ドキュメントのFXMVECTORには何を渡せばよいですか？

普通の`XMVECTOR`をそのまま渡します。`FXMVECTOR`型の変数を別に作ったり、変換したりする必要はありません。`FXMVECTOR`系は、主に関数を定義する側で使用する引数用の型エイリアスです。詳しい理由と使い分けは、次の付録で説明します。

### XMLoadFloat3でw成分はどうなりますか？

`XMLoadFloat3()`で読み込んだ`XMVECTOR`の`w`成分は`0.0f`になります。ただし、`XMVector3TransformCoord()`は入力の`w`を無視し、`1.0f`として位置変換を行います。

---

## 付録：FXMVECTOR・GXMVECTOR・HXMVECTOR・CXMVECTORとは

ここからは、DirectXMathの公式ドキュメントやヘッダーファイルを読んだときに登場する、少し高度な引数型について説明します。

通常のベクトル計算だけを行う場合は、ここまでの内容を理解していれば十分です。

### 最初に結論：関数を使う側はXMVECTORを渡せばよい

公式ドキュメントでは、関数の引数が`FXMVECTOR`になっていることがあります。

```cpp
XMVECTOR XM_CALLCONV XMVector3Normalize(
    FXMVECTOR V
) noexcept;

```

これを見ると、`FXMVECTOR`型の変数を作らなければならないように見えます。

しかし、関数を呼び出す側が用意するのは、普通の`XMVECTOR`です。

```cpp
using namespace DirectX;

XMVECTOR direction =
    XMVectorSet(1.0f, 2.0f, 3.0f, 0.0f);

XMVECTOR normalized =
    XMVector3Normalize(direction);

```

変換処理は必要ありません。

```text
関数を呼び出す側：XMVECTORを渡す
関数を定義する側：FXMVECTORなどで受け取る

```

`FXMVECTOR`、`GXMVECTOR`、`HXMVECTOR`、`CXMVECTOR`は、位置・方向・法線・色などを表す型ではありません。

すべて、関数が`XMVECTOR`を受け取るときに使用する型エイリアスです。

### 普通のC++ではコンパイラに任せるのではないか

ここで、次の疑問が出てきます。

> 普通の構造体を関数へ渡すとき、レジスタを使うかメモリを使うかはコンパイラが決める。XMVECTORだけ、なぜ特別な型を使う必要があるのか。

この疑問はもっともです。

実際に、**どのレジスタを使うか、あるいはメモリを使うかという最終的な判断は、DirectXMathでもコンパイラが行います。**

`FXMVECTOR`は、「この値を必ず特定のレジスタへ入れろ」と命令する型ではありません。

DirectXMathが切り替えたいのは、その一つ前の段階にある、次の違いです。

```cpp
// XMVECTORそのものを値として受け取る
void Function(XMVECTOR value);

```

```cpp
// 元のXMVECTORを参照して受け取る
void Function(const XMVECTOR& value);

```

値渡しと参照渡しは、C++の関数宣言として別物です。

たとえるなら、次の違いです。

```text
値渡し  ：荷物そのものを渡す
参照渡し：荷物が置かれている場所を渡す

```

コンパイラは、「荷物をどの車に載せるか」に相当するレジスタやメモリの使い方は判断できます。

しかし、プログラマーが「荷物そのものを渡す」と宣言したのに、コンパイラが勝手に「荷物の置き場所だけを渡す」方式へ変更することはできません。呼び出す側と受け取る側が、同じ方法を前提にしていなければならないためです。

つまり、コンパイラが自由に決められるのは、**宣言された値渡し・参照渡しと、その環境の呼び出し規約を守った範囲内**です。

### なぜXMFLOAT4では同じことを意識しないのか

`XMFLOAT4`は、4個の`float`をメモリへ保存するための通常の構造体です。

```cpp
struct XMFLOAT4
{
    float x;
    float y;
    float z;
    float w;
};

```

次のような関数を書いた場合、引数を実際にどのレジスタやメモリで渡すかは、通常のC++の呼び出し規約に従ってコンパイラが決めます。

```cpp
void Function(
    XMFLOAT4 a,
    XMFLOAT4 b,
    XMFLOAT4 c
);

```

一方、`XMVECTOR`は単なる保存用構造体ではありません。

x86・x64環境では`__m128`、ARM環境ではNEONのベクトル型などに対応する、SIMD計算用の型です。

```text
XMFLOAT4：メモリへ保存するための普通の構造体
XMVECTOR：SIMD演算で使用するための特殊なベクトル型

```

`XMFLOAT4`を関数へ渡した場合、関数内でSIMD計算をするには、最終的に`XMVECTOR`へロードする必要があります。

```cpp
XMFLOAT4 value;
XMVECTOR vector = XMLoadFloat4(&value);

```

DirectXMathの関数は、最初から`XMVECTOR`を受け取り、そのままSIMD演算へ使用するように作られています。

そのためDirectXMathでは、一般的な構造体よりも、**XMVECTORを関数の境界でどう受け取るか**が性能へ影響しやすくなります。

### DirectXMathが解決したい本当の問題

`XMVECTOR`に適した受け取り方は、すべての環境で同じではありません。

環境によっては、`XMVECTOR`を値として受け取ることで、ベクトルレジスタを使った受け渡しができます。

```cpp
const XMVECTOR value

```

別の環境や引数位置では、参照として受け取った方が、その環境の呼び出し規約に適しています。

```cpp
const XMVECTOR& value

```

この違いには、次のような条件が関係します。

- x86、x64、ARM、ARM64の違い
- 32ビットと64ビットの違い
- 使用するコンパイラ
- `__fastcall`や`__vectorcall`などの呼び出し規約
- その関数が受け取る`XMVECTOR`の数と位置

DirectXMathは、Windowsの複数のCPU環境で同じヘッダーファイルを利用できる、移植可能なSIMDライブラリとして作られています。

もし型エイリアスがなければ、関数定義を環境ごとに書き分ける必要があります。

```cpp
#if VALUE_PASS_IS_BETTER

XMVECTOR Function(const XMVECTOR value);

#else

XMVECTOR Function(const XMVECTOR& value);

#endif

```

これを一つの書き方へまとめるために、DirectXMathは`FXMVECTOR`などの名前を用意しています。

```cpp
XMVECTOR XM_CALLCONV Function(
    FXMVECTOR value
) noexcept;

```

`FXMVECTOR`の実体は、環境に応じて概念的に次のどちらかへ切り替わります。

```cpp
typedef const XMVECTOR FXMVECTOR;

```

または、

```cpp
typedef const XMVECTOR& FXMVECTOR;

```

つまり`FXMVECTOR`は、レジスタを直接指定するための型ではありません。

> `XMVECTOR`を値として受け取るか、参照として受け取るかというプラットフォーム差を隠すための型

と考えると理解しやすいでしょう。

その宣言を基に、実際にどのレジスタやメモリを使うかをコンパイラが決定します。

### なぜFX・GX・HX・CXの4種類があるのか

値渡しが適している範囲は、環境や呼び出し規約だけでなく、その関数に何個目の`XMVECTOR`として渡されるかによっても変わります。

その違いを一つの`FXMVECTOR`だけでは表せないため、DirectXMathでは4種類のエイリアスを用意しています。

| XMVECTOR入力引数としての順番 | 使用する型     |
| ------------------ | --------- |
| 1～3番目              | FXMVECTOR |
| 4番目                | GXMVECTOR |
| 5～6番目              | HXMVECTOR |
| 7番目以降              | CXMVECTOR |

覚え方は次のとおりです。

```text
1～3番目  ：F
4番目     ：G
5～6番目  ：H
7番目以降：C

```

これらはベクトルの意味を表しているわけではありません。

```text
FXMVECTOR = 位置用
GXMVECTOR = 方向用
HXMVECTOR = 法線用
CXMVECTOR = 色用

```

という分類ではありません。

呼び出し側が渡す変数は、すべて普通の`XMVECTOR`です。

```cpp
XMVECTOR v1;
XMVECTOR v2;
XMVECTOR v3;
XMVECTOR v4;
XMVECTOR v5;
XMVECTOR v6;
XMVECTOR v7;

XMVECTOR result = Calculate(
    v1, v2, v3, v4, v5, v6, v7
);

```

関数を定義する側だけが、次のようにエイリアスを使い分けます。

```cpp
XMVECTOR XM_CALLCONV Calculate(
    FXMVECTOR v1,
    FXMVECTOR v2,
    FXMVECTOR v3,
    GXMVECTOR v4,
    HXMVECTOR v5,
    HXMVECTOR v6,
    CXMVECTOR v7
) noexcept;

```

### 数えるのは関数全体の何番目ではない

数えるのは、関数全体の引数番号ではありません。

**入力として受け取る`XMVECTOR`が何個目か**を数えます。

```cpp
XMVECTOR XM_CALLCONV MovePosition(
    float deltaTime,
    FXMVECTOR position,
    float speed,
    FXMVECTOR direction
) noexcept;

```

この例では、`position`は関数全体では2番目の引数です。しかし、`XMVECTOR`入力としては1番目なので`FXMVECTOR`です。

`direction`は関数全体では4番目ですが、`XMVECTOR`入力としては2番目なので、同じく`FXMVECTOR`です。

```text
1個目のXMVECTOR入力：position  → FXMVECTOR
2個目のXMVECTOR入力：direction → FXMVECTOR

```

`float`、`int`、`bool`などは数えません。

4個目の`XMVECTOR`入力だけが`GXMVECTOR`になります。

```cpp
XMVECTOR XM_CALLCONV SampleFunction(
    float time,
    FXMVECTOR a,
    int mode,
    FXMVECTOR b,
    FXMVECTOR c,
    bool enabled,
    GXMVECTOR d
) noexcept;

```

`d`は関数全体では7番目ですが、`XMVECTOR`入力としては4番目なので`GXMVECTOR`です。

### 出力引数は数えない

計算結果を書き込むための`XMVECTOR*`や`XMVECTOR&`は、入力引数の数に含めません。

たとえば、`XMVectorSinCos()`は次のような宣言です。

```cpp
void XM_CALLCONV XMVectorSinCos(
    XMVECTOR* pSin,
    XMVECTOR* pCos,
    FXMVECTOR V
) noexcept;

```

`pSin`と`pCos`は、計算結果を書き込む出力先です。

入力として渡される`XMVECTOR`は`V`だけなので、`V`は1個目として`FXMVECTOR`になります。

```text
XMVECTOR* pSin：出力なので数えない
XMVECTOR* pCos：出力なので数えない
FXMVECTOR V    ：1個目のXMVECTOR入力

```

### XM\_CALLCONVとは

`FXMVECTOR`系のエイリアスは、値渡しと参照渡しの違いを環境に合わせて切り替えます。

一方、`XM_CALLCONV`は、関数全体の呼び出し規約を環境に合わせて切り替えるマクロです。

```cpp
XMVECTOR XM_CALLCONV MovePosition(
    FXMVECTOR position,
    FXMVECTOR velocity,
    float deltaTime
) noexcept;

```

現在のDirectXMathでは、環境に応じて`__vectorcall`、`__fastcall`、または何も付けない形などへ切り替わります。

```text
FXMVECTOR系：各XMVECTOR引数をどの型で受け取るか
XM_CALLCONV：関数全体をどの呼び出し規約で呼ぶか

```

DirectXMathと同じ形式で自作関数を定義する場合は、基本的にセットで使用します。

#### ヘッダーファイル

```cpp
DirectX::XMVECTOR XM_CALLCONV MovePosition(
    DirectX::FXMVECTOR position,
    DirectX::FXMVECTOR velocity,
    float deltaTime
) noexcept;

```

#### CPPファイル

```cpp
DirectX::XMVECTOR XM_CALLCONV MovePosition(
    DirectX::FXMVECTOR position,
    DirectX::FXMVECTOR velocity,
    float deltaTime
) noexcept
{
    return DirectX::XMVectorMultiplyAdd(
        velocity,
        DirectX::XMVectorReplicate(deltaTime),
        position
    );
}

```

宣言と定義の両方で、同じ`XM_CALLCONV`を使用します。

なお、既存のDirectXMath関数を呼び出すだけなら、利用者が`XM_CALLCONV`を書く必要はありません。

### コンストラクタだけ規則が異なる

C++のコンストラクタでは、通常の関数と同じ規則をそのまま使いません。

DirectXMathの公式ガイドでは、コンストラクタに`GXMVECTOR`と`HXMVECTOR`を使用しないことが推奨されています。

最初の3個を`FXMVECTOR`、4個目以降を`CXMVECTOR`にします。

```cpp
class VectorCollection
{
public:
    VectorCollection(
        DirectX::FXMVECTOR v1,
        DirectX::FXMVECTOR v2,
        DirectX::FXMVECTOR v3,
        DirectX::CXMVECTOR v4,
        DirectX::CXMVECTOR v5
    );
};

```

通常の関数は次の並びです。

```text
F, F, F, G, H, H, C, C, ...

```

コンストラクタでは次の並びになります。

```text
F, F, F, C, C, C, C, ...

```

また、コンストラクタには`XM_CALLCONV`を付けないことが推奨されています。

### 戻り値はXMVECTORでよい

`FXMVECTOR`系は、入力引数を受け取るための型です。

戻り値には通常の`XMVECTOR`を使用します。

```cpp
DirectX::XMVECTOR XM_CALLCONV GetForwardVector(
    DirectX::FXMVECTOR rotationQuaternion
) noexcept
{
    const DirectX::XMVECTOR baseForward =
        DirectX::XMVectorSet(
            0.0f,
            0.0f,
            1.0f,
            0.0f
        );

    return DirectX::XMVector3Rotate(
        baseForward,
        rotationQuaternion
    );
}

```

### 自作関数では必ず使わなければならないのか

既存のDirectXMath関数を呼び出すだけなら、`FXMVECTOR`系を自分で書く場面はありません。

また、自分のアプリケーション内部だけで使う単純な関数なら、通常のC++として次のように書くこともできます。

```cpp
XMVECTOR NormalizeVector(XMVECTOR value);

```

```cpp
XMVECTOR NormalizeVector(const XMVECTOR& value);

```

これらが直ちに間違いになるわけではありません。

ただし、DirectXMathと同じように、複数のWindowsプラットフォームや呼び出し規約へ対応しながら、`XMVECTOR`の受け渡しを最適化した形式にしたい場合は、`FXMVECTOR`系と`XM_CALLCONV`を使用します。

つまり、利用者側では次のように判断できます。

```text
DirectXMath関数を呼ぶだけ
    → 普通のXMVECTORを渡す

簡単な自作関数を作る
    → 通常のC++の引数でも書ける

DirectXMathと同じ移植性・呼び出し規約を採用する
    → FXMVECTOR系 + XM_CALLCONVを使う

```

### XMMATRIXにも同じ考え方がある

行列にも、関数引数用の型エイリアスがあります。

```cpp
FXMMATRIX
CXMMATRIX

```

これらも、行列の意味を表す別の型ではありません。`XMMATRIX`を関数が受け取るときの環境差を隠すための型です。

ただし、`FXMMATRIX`の細かい規則は、周囲にあるベクトル引数や浮動小数点引数の数にも影響されます。

行列の引数規則まで必要になった場合は、公式の関数宣言を参考にするか、別の記事として扱った方が整理しやすいでしょう。

### 付録のまとめ

`FXMVECTOR`系について、利用者側で最初に覚えることは次の3点です。

1. 公式ドキュメントに`FXMVECTOR`と書かれていても、呼び出す側は普通の`XMVECTOR`を渡す
2. `FXMVECTOR`系は、値渡しと参照渡しのプラットフォーム差を隠すための型エイリアスである
3. DirectXMathと同じ形式の自作関数では、`FXMVECTOR`系と`XM_CALLCONV`を組み合わせる

```text
XMVECTOR
    実際のベクトルデータ

FXMVECTOR / GXMVECTOR / HXMVECTOR / CXMVECTOR
    関数がXMVECTORを受け取るための型エイリアス

XM_CALLCONV
    関数全体の呼び出し規約を選ぶマクロ

```

細かい順番は、次のとおりです。

```text
1～3個目のXMVECTOR入力：FXMVECTOR
4個目                  ：GXMVECTOR
5～6個目               ：HXMVECTOR
7個目以降              ：CXMVECTOR

```

ただし、コンストラクタでは最初の3個を`FXMVECTOR`、4個目以降を`CXMVECTOR`とし、`XM_CALLCONV`は付けません。

---

## 参考資料

- [Microsoft Learn: Library Internals](https://learn.microsoft.com/en-us/windows/win32/dxmath/pg-xnamath-internals?ref=geekjp.com)
- [Microsoft Learn: XMVector3TransformCoord](https://learn.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-xmvector3transformcoord?ref=geekjp.com)
- [Microsoft Learn: DirectXMath 3D vector transformation functions](https://learn.microsoft.com/en-us/windows/win32/dxmath/ovw-xnamath-reference-functions-vector3-transformation?ref=geekjp.com)
- [Microsoft Learn: XMStoreFloat3](https://learn.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-xmstorefloat3?ref=geekjp.com)
- [Microsoft Learn: XMFLOAT3A](https://learn.microsoft.com/en-us/windows/win32/api/directxmath/ns-directxmath-xmfloat3a?ref=geekjp.com)
- [Microsoft Learn: Packing rules for constant variables](https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules?ref=geekjp.com)
- [Microsoft DirectXMath: DirectXMath.h](https://github.com/microsoft/DirectXMath/blob/main/Inc/DirectXMath.h?ref=geekjp.com)