LoginSignup
9
9

More than 5 years have passed since last update.

DirectX Tool Kit は、右手座標系

Last updated at Posted at 2014-10-11

見事にハマったのでメモ

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

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

この記事に掲載しているコードおよび実行結果に関して
DXTKにはMS-PL
フォントにはIPAフォントライセンスv1.0を利用しています.

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の色々な機能を使っているかと思ったら、ほんのちょっとだけしか触っていなかった.
ちょっとガッカリ...

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

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)

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 の別名.
    • 環境やお好みに合わせて、読み替えてください.
  • フォントは、前もって、スプライトフォント形式にコンバートする必要があります.

で、これで実行してみた結果がこちら.
render-rh.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

// 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.

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上で動くものだし、
左手座標系使えた方が自然かなぁ、と考え、サンプルも修正.

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

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

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

というお話でした.

まとめ

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

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

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

9
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
9