とりあえずポリゴンを表示できたが、まだ動かすことができない。
ポリゴン自体が動けば当然表示される結果は変わるが、カメラが動いても同様に結果は変化する。
そのあたりをやっていこう。
現状ではQuad::Draw関数の先頭でビュー行列とプロジェクション行列を作成しているが、これはカメラに関することなので処理を分けよう。基本的にカメラは1シーンに1つなので、クラスではなくnamespaceにまとめていく。(マリオカートの2人プレイみたいに画面を分割する場合は複数のカメラが必要だが…その時のことはその時考えよう)
さて、戦車ゲームや3Dパックマンを作った時にカメラに対してどんなことをしたか思い出してみよう。「カメラの位置(視点)」と「カメラが見る位置(焦点)」を決めたはずだ。ということは、その2つを入れる変数と、入れるための関数が必要なのは言うまでもない。
そして、Quad::Drawに書いた処理を見ると「ビュー行列」と「プロジェクション行列」を作ってシェーダーに渡しているわけだから、それを入れる変数と、入れるための関数が必要。
あとは最初の準備(カメラの初期位置を入れたり)する関数と、カメラの位置とかが変わった時にビュー行列を計算する関数が必要なので――
<Camera.h>
#pragma once
#include "Direct3D.h"
#include <DirectXMath.h>
using namespace DirectX;
//-----------------------------------------------------------
//カメラ
//-----------------------------------------------------------
namespace Camera
{
//初期化(プロジェクション行列作成)
void Initialize();
//更新(ビュー行列作成)
void Update();
//視点(カメラの位置)を設定
void SetPosition(XMVECTOR position);
//焦点(見る位置)を設定
void SetTarget(XMVECTOR target);
//ビュー行列を取得
XMMATRIX GetViewMatrix();
//プロジェクション行列を取得
XMMATRIX GetProjectionMatrix();
};
<Camera.cpp>
#include "Camera.h"
//変数
XMVECTOR position_; //カメラの位置(視点)
XMVECTOR target_; //見る位置(焦点)
XMMATRIX viewMatrix_; //ビュー行列
XMMATRIX projMatrix_; //プロジェクション行列
//初期化
void Camera::Initialize()
{
}
//更新
void Camera::Update()
{
}
//位置を設定
void Camera::SetPosition(XMVECTOR position)
{
}
//焦点を設定
void Camera::SetTarget(XMVECTOR target)
{
}
//ビュー行列を取得
XMMATRIX Camera::GetViewMatrix()
{
}
//プロジェクション行列を取得
XMMATRIX Camera::GetProjectionMatrix()
{
}
とりあえずこんな感じ。
ここではまず、視点と焦点の初期値を入れておく。特にカメラの設定をしなかったときはこの値が使われる。
void Camera::Initialize()
{
position_ = XMVectorSet(0, 3, -10, 0); //カメラの位置
target_ = XMVectorSet(0, 0, 0, 0); //カメラの焦点
}
そして、プロジェクション行列は後から変わることがないのでここで作ってしまおう。
(※カメラをズームさせたりしたい場合は、この処理はUpdateに書かなきゃない)
//プロジェクション行列
projMatrix_ = XMMatrixPerspectiveFovLH(XM_PIDIV4, (FLOAT)800 / (FLOAT)600, 0.1f, 100.0f);
}
この関数の引数は前から順番に
画角(視野角):XM_PIが3.14ラジアン=180度。DIV4は÷4なのでXM_PIDIV4は45度を表す定数。
アスペクト比:ウィンドウの縦横の比率。今数字を直接書いちゃってダサいので、後で何とかしたい。
ニア(近)クリッピング面までの距離:カメラからこの値より近いものは映らない。
ファー(遠)クリッピング面までの距離:カメラからこの値より遠いものは映らない。
視点と焦点はいつ変わるかわからないので、ビュー行列はここで作成しておく。
(※今後、カメラ固定のゲームしか作らないのであればInitializeでやった方が無駄がなくていい)
void Camera::Update()
{
//ビュー行列の作成
viewMatrix_ = XMMatrixLookAtLH(position_, target_, XMVectorSet(0, 1, 0, 0));
}
この関数の引数は前から順番に
カメラの位置(視点)
見る位置(焦点)
上方向ベクトル(もしカメラを傾けたいなら、これも変数にする必要あり)
残りの4つはただのセッターとゲッターなので、今更説明することは無い。
最低限のカメラの機能はできたので、Main.cppから初期化と更新処理を呼び出す。
初期化はDirect3Dの準備ができた後、更新は描画の前がいいだろう。
当然Camera.cppのインクルードが必要になる。
Quad::Drawの最初でビュー行列とプロジェクション行列を作っていたが、それは削除。
代わりにCameraのゲッターを使って両行列を取得しシェーダーに渡す。
void Quad::Draw()
{
//コンスタントバッファに渡す情報
(ここの処理は消す)
D3D11_MAPPED_SUBRESOURCE pdata;
CONSTANT_BUFFER cb;
cb.matWVP = XMMatrixTranspose(Camera::GetViewMatrix() * Camera::GetProjectionMatrix());
Direct3D::pContext->Map(pConstantBuffer_, 0, D3D11_MAP_WRITE_DISCARD, 0, &pdata); // GPUからのリソースアクセスを一時止める
今まで通り表示されることを確認しよう。
あとはこれに任意のワールド行列(移動・回転・拡縮)が使えるようになればいいわけだ。
Quad::Draw関数の引数としてワールド行列を受け取って、ビュー・プロジェクション行列にかけてやれば良い。
void Quad::Draw(XMMATRIX& worldMatrix)
{
//コンスタントバッファに渡す情報
D3D11_MAPPED_SUBRESOURCE pdata;
CONSTANT_BUFFER cb;
cb.matWVP = XMMatrixTranspose(worldMatrix * Camera::GetViewMatrix() * Camera::GetProjectionMatrix());
あとは、WinMainから適当な行列を渡してやれば、その通りに変形する。
//メッセージなし
else
{
//ゲームの処理
Camera::Update();
Direct3D::BeginDraw();
//描画処理
XMMATRIX mat = XMMatrixRotationY(XMConvertToRadians(45));
quad.Draw(mat);