DirectX9によるテクスチャ描画
概要
DirectX9を使用してテクスチャの描画の方法を説明します。
テクスチャ描画は当然2Dゲームでは必須ですし、3DゲームでもUIなどは2Dで
描画することになるので、3Dゲームを作りたい人でも覚えておくべき内容です。
サンプル
サンプルはここからダウンロードでき、環境については以下の内容となっています。
開発環境
VSのバージョン |
VisualStudio 2019 |
DirectXのバージョン |
DirectX9 |
知っておいたほうがいい知識
このページを読むにあたり、知っておいたほうがいい知識は以下の内容です。
・DirectGrphics基礎
・ポリゴン
・テクスチャ座標
テクスチャ描画の概要
テクスチャの描画はポリゴンを2枚用意して四角を作るところから始まります。
この四角ポリゴンの4頂点に対してテクスチャ座標を指定することで
画像が張り付けられます。
実装の流れ
テクスチャ描画実装の流れは以下の通りです。
準備 |
①.頂点構造をカスタマイズする |
②.テクスチャを読み込む |
描画 |
③.ポリゴンを用意する |
④.頂点情報を登録する |
⑤.使用するテクスチャを登録する |
⑥.描画する |
①.頂点構造をカスタマイズする
ポリゴンを描画するために各頂点には描画座標やテクスチャ座標等の情報が
設定できるようになっています。
この情報を開発側で取捨選択して、自作の頂点構造を作成します。
自作した頂点構造は「CustomVertex(カスタムバーテックス)」と呼ばれています。
設定できる情報
設定できる情報はDirectX側で用意されています。
上記の項目以外の情報をCustomVertexに追加することはできません。
CustomVertexの作成
設定情報項目からポリゴンに必要な情報を選択してCustomVertexを作成します。
作成と書いていますが、実際にやることは構造体の宣言です。
//「頂点座標」「除算数」「テクスチャ座標」を使用することを宣言した構造体
struct CUSTOM_VERTEX
{
// 頂点座標
float x;
float y;
float z;
// 除算数
float rhw;
// テクスチャ座標
float tu;
float tv;
};
これで今回の使用するポリゴン描画用の頂点構造の作成が完了です。
②.テクスチャを読み込む
次は描画で使用するテクスチャを読み込んでゲーム中に使用可能状態にします。
DirectX9では読み込み用の関数がいくつか用意してあり、よく使用される関数は
「D3DXCreateTextureFromFile関数」と「D3DXCreateTextureFromFileEx関数」です。
まずは、D3DXCreateTextureFromFileから説明します。
// テクスチャ読み込み
D3DXCreateTextureFromFile(
g_D3DDevice,
file_name,
&texture_data->TexutreData
);
D3DXCreateTextureFromFileは引数の数も必要最低限になっていて
シンプルで分かりやすい関数です。
次はD3DXCreateTextureFromFileExですが引数の数が多いので気を付けてください。
// テクスチャ読み込み
D3DXCreateTextureFromFileExA(g_D3DDevice,
file_name,
info.Width,
info.Height,
1,
0,
D3DFMT_UNKNOWN,
D3DPOOL_MANAGED,
D3DX_DEFAULT,
D3DX_DEFAULT,
0x0000ff00,
nullptr,
nullptr,
&texture_data->TexutreData);
D3DXCreateTextureFromFileExは引数が多い代わりに様々な設定が可能です。
例えば、読み込むファイルの横幅と縦幅のサイズや抜き色の指定が出来たり、
ミップマップやフィルタリングの設定もできます。
使い分けとしてはD3DXCreateTextureFromFileExで設定できる内容をある程度把握しておき、
それらの設定が必要な時はD3DXCreateTextureFromFileEx、
それ以外はD3DXCreateTextureFromFileを使用すればいいと思います。
読み込みサイズの注意
読み込まれた画像のサイズが二の累乗ではなかった場合、
以下のようにサイズより一回り大きい二の累乗に自動で修正されます。
読み込み前のサイズ |
修正後のサイズ |
500 * 500を読み込む |
512 * 512に修正 |
640 * 200を読み込む |
1024 * 256に修正 |
もし、累乗をされたくない場合はD3DXCreateTextureFromFileExの
第三、第四引数に元のファイルサイズを指定すれば、そのサイズ読み込むことができます。
※サンプルでそちらのコードを書いていますので参考にしてみてください。
解放
読み込まれたテクスチャが不要になった際はどこかのタイミングで
必ずテクスチャの解放を行います。
解放される場所としてよくあるのが各シーンが終了した時やゲーム終了時です。
解放関数としてIDirect3DTexture9に「Release関数」が用意されています。
// テクスチャの解放
g_Texture.m_pTexture->Release();
g_Texture.m_pTexture = nullptr;
解放しないとリークしてしまうので使わなくなったテクスチャは必ず解放してください。
③.ポリゴンを用意する
CustomVertexを宣言し、テクスチャの読み込みが終わったらポリゴンを用意します。
今回はポリゴンで四角形を作り、そこにテクスチャを貼り付けます。
この時に必要な頂点数は四または六頂点です。
なぜ、四か六頂点の二択になっているかというと、四角形を作る場合
ポリゴンの作成方法によって必要とする頂点数が異なるからです。
作成方法 |
必要な頂点数 |
TriangleList(トライアングルリスト) |
六 |
TriangleFan(トライアングルファン) |
四 |
TriangleStrip(トライアングルストリップ) |
四 |
次の項目でこれらの作成方法を一つ一つ説明していきます。
TriangleList(トライアングルリスト)による設定
トライアングルリストによる頂点設定は頂点3つのポリゴンを2つ用意します。
DirectXの約束事として各ポリゴンの頂点設定の順番は左回りで行います。
struct CUSTOM_VERTEX
{
float x, y, z, rhw;
};
CUSTOM_VERTEX TriangleList[] =
{
// 1つ目のポリゴン
{ 0.0f, 0.0f, 0.0f, 1.0f },
{ 100.0f, 0.0f, 0.0f, 1.0f },
{ 0.0f, 100.0f, 0.0f, 1.0f },
// 2つ目のポリゴン
{ 100.0f, 0.0f, 0.0f, 1.0f },
{ 100.0f, 100.0f, 0.0f, 1.0f },
{ 0.0f, 100.0f, 0.0f, 1.0f },
};
TriangleFan(トライアングルファン)による設定
トライアングルファンによる頂点設定は頂点を4つ用意することで
2つポリゴンが作成され、四角形が描画されます。
こちらも頂点は左回りに設定を行います。
どの頂点から始めても問題ありませんが、左上から設定することが多いです。
struct CUSTOM_VERTEX
{
float x, y, z, rhw;
};
CUSTOM_VERTEX TriangleFan[] =
{
// 左上頂点
{ 0.0f, 0.0f, 0.0f, 1.0f },
// 右上頂点
{ 100.0f, 0.0f, 0.0f, 1.0f },
// 右下頂点
{ 100.0f, 100.0f, 0.0f, 1.0f },
// 左下頂点
{ 0.0f, 100.0f, 0.0f, 1.0f },
};
TriangleStrip(トライアングルストリップ)による設定
トライアングルストリップによる頂点設定は頂点を4つ用意することで
2つポリゴンが作成され、四角形が描画されます。
こちらも頂点は左回りに設定を行いますがトライアングルストリップは
まず、1つのポリゴンを設定するために3つの頂点の設定を最初に行います。
そして、3点に新しい頂点を追加することで2つのポリゴンが作成されます。
struct CUSTOM_VERTEX
{
float x, y, z, rhw;
};
CUSTOM_VERTEX TriangleStrip[] =
{
// ポリゴンを作成
// 左上頂点
{ 0.0f, 0.0f, 0.0f, 1.0f },
// 右上頂点
{ 100.0f, 0.0f, 0.0f, 1.0f },
// 左下頂点
{ 0.0f, 100.0f, 0.0f, 1.0f },
// 足りない頂点を追加
// 右下頂点
{ 100.0f, 100.0f, 0.0f, 1.0f },
};
テクスチャ座標の指定
ポリゴンの作成方法が次は各頂点にテクスチャ座標の指定をします。
テクスチャ座標
テクスチャ座標は名前の通り、テクスチャの位置を指定するための座標情報のことです。
座標は縦0.0~1.0、横0.0~1.0で指定します。
これはテクスチャのサイズは128 * 256や512 * 512などバラバラで統一されていません。
このままでは座標指定がやりにくいので指定をしやすいように縦、横のサイズを
最小を0.0、最大1.0として統一しています。
uv
テクスチャ座標ではX軸をu、Y軸をvとすることが一般的で、「UV座標」と呼ばれています。
これは位置座標のXとYと区別するためにベクトルの成分をuとvが使われていると言われており、
様々な参考書やサイトでもテクスチャ座標はuとvで書かれています。
CustomVertexにテクスチャ座標を指定する
テクスチャを頂点に設定するためにはCustomVertexに情報の追加が必要です。
情報はテクスチャ一枚につき「テクスチャ座標のXとY座標」が必要で、
これはどちらもfloat型で指定します。
struct CUSTOM_VERTEX
{
float x, y, z, rhw;
// テクスチャ座標(横)
float tu;
// テクスチャ座標(縦)
float tv;
};
指定例
以下のテクスチャを使用してテクスチャ座標の指定を行いたいと思います。
トライアングルファンで作られた四角形にテクスチャ座標の設定をします。
位置 |
座標(x,y) |
左上 |
0.0, 0.0 |
右上 |
1.0, 0.0 |
右下 |
1.0, 0.5 |
左下 |
0.0, 0.5 |
上の設定は画像の上半分を指定しています。
以下はこの設定部分が書かれたコードで、
CUSTOM_VERTEX配列の各要素の最後の二つがUV値です。
struct CUSTOM_VERTEX
{
float x, y, z, rhw;
// テクスチャ座標(横)
float tu;
// テクスチャ座標(縦)
float tv;
};
CUSTOM_VERTEX TriangleFan[] =
{
// 左上頂点
{ 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f },
// 右上頂点
{ 100.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f },
// 右下頂点
{ 100.0f, 100.0f, 0.0f, 1.0f, 1.0f, 0.5f },
// 左下頂点
{ 0.0f, 100.0f, 0.0f, 1.0f, 0.0f, 0.5f },
};
このコードで作成した頂点情報を使用して描画を行った結果が以下の内容です。
ちゃんとテクスチャの上半分のみを描画できました。
④.頂点情報の登録する
次は描画で使用する頂点情報の登録を行います。
DirectXではポリゴンの描画を行う前にCustomVertexの情報を登録しておく必要があります。
これは、CustomVertexは開発側が用意した独自データなので、
DirectX側は何が使われているか分からないので、情報を上手く使うことができません。
そこで、IDirect3DDevice9の「SetFVF関数」を使用してDirectX側に
CustomVertexで使用している頂点情報に何が含まれているかを伝えます。
// 頂点情報をDirectX側に知らせる
g_D3DDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
上のように論理和「|」を使用して記述すると「座標(除算数あり)」と
「テクスチャ座標」のように複数の情報を同時に登録することができます。
定数でまとめる
通知設定は論理和を使用して一度に書くので一行が長くなります。
そこで、defineなどで定数化してまとめることで使用時の記述を短縮させます。
// 「座標(除算数あり)」と「テクスチャ座標」をまとめる
#define FVF_2D (D3DFVF_XYZRHW | D3DFVF_TEX1)
g_D3DDevice->SetFVF(FVF_2D);
⑤.使用するテクスチャを登録する
次は描画で使用するテクスチャの指定します。
設定にはIDirect3DDevice9の「SetTexture関数」を使用します。
このテクスチャ指定はテクスチャ付きのポリゴンを描画する毎に行います。
一フレームで百回描画する場合は指定処理を百回行うということです。
これは使用するテクスチャが複数あった場合に、間違って意図しないテクスチャが
貼り付けられないようにするためです。
※慣れてきたら毎回しなくてもいい方法を選択しても問題ありませんが、
始めはテクスチャ描画の毎で設定したほうがバグが起こらなくて済みます。
// 使用するテクスチャの設定
g_D3DDevice->SetTexture(0, g_Texture.m_pTexture);
テクスチャステージはマルチテクスチャという、同じポリゴンに複数枚の
テクスチャを貼り付ける手法で使用します。
数字が大きくなるほど後から貼り付けられるようになるので、
一枚しか使用しない場合はゼロ指定で問題ありません。
⑥.描画する
最後にIDirect3DDevice9の「DrawPrimitiveUP関数」を使って描画しますが、
描画はIDirect3DDevice9のBeginSceneとEndSceneの間で行ってください。
// ポリゴン描画
g_D3DDevice->DrawPrimitiveUP(
D3DPT_TRIANGLEFAN, // ポリゴンの作成方法
2, // 描画するポリゴンの数
vertices, // ポリゴンを描画するために使う頂点の配列
sizeof(CustomVertex) // 頂点情報のサイズ
);
これでテクスチャ指定されたポリゴンが描画されます。
テクスチャの描画はこれで終了です。