DirectX Tool Kit は、右手座標系

見事にハマったのでメモ

追々記：
深度テスト関係なしに、図形作成時にも左手座標系である指定をする必要がありました.

追記:
しまった. ライセンス明記するの忘れていた.

この記事に掲載しているコードおよび実行結果に関して
[DXTKにはMS-PL](http://directxtk.codeplex.com/license)、
[フォントにはIPAフォントライセンスv1.0](http://ipafont.ipa.go.jp/ipa_font_license_v1.html)を利用しています.

## DirectX Tool Kit とは
>http://go.microsoft.com/fwlink/?LinkId=248929
>**Project Description**
>The DirectX Tool Kit (aka DirectXTK) is a collection of helper classes for writing DirectX 11.x code in C++.

**要するにDirectX11世代のC++用ゲームフレームワーク.**

MS公式がD3DXの代わりに使ってね とアナウンスしています.
http://msdn.microsoft.com/en-us/library/windows/desktop/ee663275(v=vs.85).aspx

## サンプル書いてみた
DirectXTKのサンプルにWin32 Simple Sample とやらがあるので、覗いてみる
http://directxtk.codeplex.com/wikipage?title=Samples&referringTitle=Documentation

~~っておい、全然シンプルじゃねーだろ！~~
まぁゲームのひな形ってこんなもんだよね、うん(´・ω・｀)

でも、このサンプルでDirectXTKの色々な機能を使っているかと思ったら、ほんのちょっとだけしか触っていなかった.
ちょっとガッカリ...

仕方がないので、ドキュメント見ながら簡単なサンプル作ってみました。

```cpp:sample_scene.cpp
//--------------------------------------------------------------------------------------
/// @file    sample_scene.h
/// @brief   サンプルシーン.
//--------------------------------------------------------------------------------------
#pragma once
#if !defined(SAMPLE_SCENE_H)
#define SAMPLE_SCENE_H

#include "StdAfx.h"
#include "scene/renderable_scene.h"

namespace DirectX {
    class GeometricPrimitive;
    class SpriteBatch;
    class SpriteFont;
}

//--------------------------------------------------
/// @brief   サンプルシーン.
//--------------------------------------------------
class sample_scene final : public renderable_scene {
public:
    /// @brief コンストラクタ.
    sample_scene(d3d_device_ptr device, d3d_context_ptr context);

    /// @brief デストラクタ.
    virtual ~sample_scene();

    /// @brief 初期化処理.
    virtual void initialize() override;

    /// @brief 終了処理.
    virtual void finalize() override;

    /// @brief 更新処理.
    virtual void update() override;

    /// @brief 描画処理.
    virtual void render() override;

private:
    std::unique_ptr<DirectX::GeometricPrimitive>    m_tea_pod;
    std::unique_ptr<DirectX::GeometricPrimitive>    m_torus;
    std::unique_ptr<DirectX::SpriteBatch>           m_sprite_batch;
    std::unique_ptr<DirectX::SpriteFont>            m_sprite_font;
};

#endif // !defined(SAMPLE_SCENE_H)

```
```cpp:sample_scene.cpp
//--------------------------------------------------------------------------------------
/// @file   base/win32_application.cpp
/// @brief  サンプルシーン.
/// DXTKを使って色々描画する.\n
/// シェーダは、DXTKのデフォルトのものを利用している.
//--------------------------------------------------------------------------------------
#include "StdAfx.h"
#include "scene/sample/sample_scene.h"

//--------------------------------------------------
namespace {
    using namespace DirectX;
    using namespace DirectX::SimpleMath;

    // ---------------
    // 行列計算(面倒なので固定値).
    // ---------------

    // シェイプの位置.
    //   ティーポッド： 右を向かせて、左側手前に.
    //   トーラス    ： Y軸/Z軸周りに45°だけ回転し、右奥の方向に.
    const Matrix teapod_matrix =
        Matrix::CreateWorld(Vector3(-1.0F, 0.0F, -1.0F), Vector3(1.0F, 0.0F, 0.0F), Vector3(0.0F, 1.0F, 0.0F));

    const Matrix torus_matrix =
        Matrix::CreateFromYawPitchRoll(0.0F, XM_PIDIV4, XM_PIDIV4) *
        Matrix::CreateTranslation(1.0F, 0.0F, 1.0F);

    // ビュー行列(カメラの制御).
    // NOTE: ※注意1
    const Vector3   eye     = Vector3(0.0F, 3.0F, -6.0F);
    const Vector3   target  = Vector3(0.0F, 0.0F, 0.0F);
    const Vector3   up      = Vector3(0.0F, 1.0F, 0.0F);
    const Matrix    view    = Matrix::CreateLookAt(eye, target, up);

    // プロジェクション行列(投影の制御).
    // NOTE: ※注意2
    const Matrix projection = Matrix::CreatePerspectiveFieldOfView(XM_PIDIV4, 480.0F / 640.0F, 0.01f, 100.0f);

    // ---------------
    // テキスト描画用.
    // ---------------
    const wchar_t* font_name = L"../data/font/ipa_gothic_16.spritefont_test";
    const wchar_t* text      = L"Hello, world!";
    const Vector2  text_pos  = Vecotr2(100.0F, 100.0F);
}


sample_scene::sample_scene(d3d_device_ptr device, d3d_context_ptr context)
    : renderable_scene(device, context)
    , m_tea_pod()
    , m_torus()
    , m_sprite_batch()
    , m_sprite_font()
{}


sample_scene::~sample_scene() {
}


void sample_scene::initialize() {
    ASSERT(m_d3d_device_context);

    // シェイプの構築.
    m_tea_pod = GeometricPrimitive::CreateTeapot(m_d3d_device_context.Get());
    m_torus   = GeometricPrimitive::CreateTorus(m_d3d_device_context.Get());

    // フォントの構築.
    m_sprite_batch = std::make_unique<SpriteBatch>(m_d3d_device_context.Get());
    m_sprite_font  = std::make_unique<SpriteFont>(m_d3d_device.Get(), font_name);
}


void sample_scene::finalize() {
    m_tea_pod.reset();
    m_torus.reset();
    m_sprite_batch.reset();
    m_sprite_font.reset();
}


void sample_scene::update() {
    // FIXME: フレームレートの制御が必要.
}


void sample_scene::render() {

    // シェイプの描画.
    m_tea_pod->Draw(teapod_matrix, view, projection, Colors::Goldenrod);
    m_torus->Draw(torus_matrix, view, projection, Colors::Gray, nullptr, true);

    // スプライト・フォントの描画.
    m_sprite_batch->Begin();
    m_sprite_font->DrawString(
        m_sprite_batch.get(), text, text_pos, Colors::Black);
    m_sprite_batch->End();
}

```
* 前提：DirectXの初期化や、Window作る過程、メッセージループなどは自分で作ってください.
* 色々粗が目立ちますが、DXTKの使い方という観点では本筋ではないのでガン無視.
* d3d_device_ptr や d3d_context_ptr は、Microsoft::WRL::ComPtr<T> の別名.
    * 環境やお好みに合わせて、読み替えてください.
* フォントは、前もって、スプライトフォント形式にコンバートする必要があります.

で、これで実行してみた結果がこちら.
![render-rh.png](https://qiita-image-store.s3.amazonaws.com/0/49330/9a3f9d6d-a043-3485-ed26-f8dac20779a7.png)

というわけで、タイトル回収.

何も考えず左手座標を想定した向きで書いてみたら、
カメラがZ軸で正反対の位置になり、
(右手座標系を、180度Y軸回転した状態となり)
結果X軸が逆方向に...

## そもそもなんで右手座標系？
ちゃんとドキュメントに書いてありました.
少し長めの引用です.
http://directxtk.codeplex.com/wikipage?title=SimpleMath&referringTitle=DirectXTK

>**Coordinate Systems**
>
>Because SimpleMath Is intended to look a lot like like XNA Game Studio's math library, it uses right-handed coordinates by convention for the following Matrix methods:
>
>* CreatePerspectiveFieldOfView
>* CreatePerspective
>* CreatePerspectiveOffCenter
>* CreateOrthographic
>* CreateOrthographicOffCenter
>* CreateLookAt
>
>If you want to use left-handed coordinates, use the DirectXMath methods directly. For example
>
>```cpp
>// Here's a RH example
>Vector3 eye, target, up;
>...
>Matrix mView = Matrix::CreateLookAt( eye, target, up );
>
>// Here' is a LH example of same thing which relies on
>// Vector3 and Matrix conversion operators
>Vector3 eye, target, up;
>...
>Matrix mView = XMMatrixLookAtLH( eye, target, up ); 
>```
>
>With the methods Matrix::CreateBillboard and Matrix::CreateConstrainedBillboard the handedness is inherent in the default vectors for cameraForward, and objectForward which are right-handed. You can make them behave left-handed by providing appropriate vectors.
>
>```cpp
>Vector3 objectPosition, cameraPosition, rotateAxis;
>
>Matrix mView = Matrix::CreateBillboard( objectPosition, cameraPosition, Vector3::Up, Vector3::Backward );
>
>Matrix mView = Matrix::CreateConstrainedBillboard( objectPosition, cameraPosition, rotateAxis, Vector3::Backward, Vector3::Backward );
>```

要するに、 **DirectXTKの数学関数は、XNA風(右手座標系)に使えることを目指したため、**
デフォルトが右手座標系になっていると.
なので左手座標系使いたい場合は、XMMatrix～なり、「前方」の向きを「後方」に変えろとのこと.

このライブラリはあくまでDirectX上で動くものだし、
左手座標系使えた方が自然かなぁ、と考え、サンプルも修正.

```cpp:sample_scene.cpp
// ...

    // ビュー行列(カメラの制御).
    //   SimpleMath::Matrix::CreateLookAt() は右手座標系のため、注意.
    const Vector3   eye     = Vector3(0.0F, 3.0F, -6.0F);
    const Vector3   target  = Vector3(0.0F, 0.0F, 0.0F);
    const Vector3   up      = Vector3(0.0F, 1.0F, 0.0F);
    const Matrix    view    = XMMatrixLookAtLH(eye, target, up);

    // プロジェクション行列(投影の制御).
    //   SimpleMath::Matrix::CreatePerspectiveFieldOfView() は右手座標系のため、注意.
    const Matrix projection = XMMatrixPerspectiveFovLH(XM_PIDIV4, 480.0F / 640.0F, 0.01f, 100.0f);

// ...

void sample_scene::initialize() {
    ASSERT(m_d3d_device_context);

    // シェイプの構築.
    m_tea_pod = GeometricPrimitive::CreateTeapot(m_d3d_device_context.Get(), 1.0F, 8, false);
    m_torus   = GeometricPrimitive::CreateTorus(m_d3d_device_context.Get(), 1.0F, 0.3F, 32, false);
// ...

```
![render-lh.png](https://qiita-image-store.s3.amazonaws.com/0/49330/bf8e5101-d6bb-3cbe-fead-8e62884cc5da.png)

無事、意図した方向を向いてくれるように.

~~ただし、深度テストがうまく動作していないようなので、修正が必要そうですね.~~
深度テストがおかしい問題は、基本図形作成時にオプションで右手座標系を無効にしました.
デフォルト引数遠すぎてめんどくせぇ.

というお話でした.

##まとめ
DirectXTKは思った以上に簡単なので、
DirectX9.0cから未だ移行できない人も、乗り換えてみるにはいいかも.

* ※ただし
    * DirectXで動かす前提なのに、XNAの置き換えを狙っているためか、所々めんどくさく感じる
        * 諦めて右手座標系使ったほうが楽かもしれねぇ
    * 例外をところかまわず投げてくる
        * しかも、どこで例外投げるか分からん
    * そもそもAPI一覧がドキュメントとして用意されていないはどういうことだよ...

なんて不満点も感じているので、悩ましいところ.
英語力高めて、公式の Discussion に文句書き込みたいなぁ.