見事にハマったのでメモ
追々記:
深度テスト関係なしに、図形作成時にも左手座標系である指定をする必要がありました.
追記:
しまった. ライセンス明記するの忘れていた.
この記事に掲載しているコードおよび実行結果に関して
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の色々な機能を使っているかと思ったら、ほんのちょっとだけしか触っていなかった.
ちょっとガッカリ...
仕方がないので、ドキュメント見ながら簡単なサンプル作ってみました。
//--------------------------------------------------------------------------------------
/// @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)
//--------------------------------------------------------------------------------------
/// @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 の別名.
- 環境やお好みに合わせて、読み替えてください.
- フォントは、前もって、スプライトフォント形式にコンバートする必要があります.
というわけで、タイトル回収.
何も考えず左手座標を想定した向きで書いてみたら、
カメラが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上で動くものだし、
左手座標系使えた方が自然かなぁ、と考え、サンプルも修正.
// ...
// ビュー行列(カメラの制御).
// 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);
// ...
無事、意図した方向を向いてくれるように.
ただし、深度テストがうまく動作していないようなので、修正が必要そうですね.
深度テストがおかしい問題は、基本図形作成時にオプションで右手座標系を無効にしました.
デフォルト引数遠すぎてめんどくせぇ.
というお話でした.
まとめ
DirectXTKは思った以上に簡単なので、
DirectX9.0cから未だ移行できない人も、乗り換えてみるにはいいかも.
- ※ただし
- DirectXで動かす前提なのに、XNAの置き換えを狙っているためか、所々めんどくさく感じる
- 諦めて右手座標系使ったほうが楽かもしれねぇ
- 例外をところかまわず投げてくる
- しかも、どこで例外投げるか分からん
- そもそもAPI一覧がドキュメントとして用意されていないはどういうことだよ...
- DirectXで動かす前提なのに、XNAの置き換えを狙っているためか、所々めんどくさく感じる
なんて不満点も感じているので、悩ましいところ.
英語力高めて、公式の Discussion に文句書き込みたいなぁ.