UVマッピング
概要
UVマッピングとはテクスチャマッピングの1種で、 3Dモデル等のポリゴンの各頂点にテクスチャのUV値の指定を行い、 その指定されたUV値からテクスチャをポリゴンにマッピングして描画します。 このUVマッピングを使用して「UVアニメーション」「UVスクロール」といった ゲームでよく使用される手法を使うことができます。
UV座標軸
UV座標軸は左上を原点とした縦、横の2直線が交差する座標軸で、 横方向をU軸、縦方向をV軸と呼んでいます。 そのため、UV座標軸で設定したテクスチャ座標のことを 「UV値」や「UV座標」と呼びます。
UVの範囲
下の画像のように1枚のテクスチャのUV値は 縦横ともに全て「0.0~1.0」の範囲とされています。
ピクセル座標からUV座標変換
3Dモデルの場合は各頂点にマッピングするUV値はMaya等のモデルツールが 行ってくれますが、2Dゲームの統合画像の一部分をマッピングしたい場合など、 UV値の計算を開発者側でしなくてはいけない事もあります。 その際にピクセル単位の座標であるテクセル座標からUV座標に変換が必要です。 以下はその変換の計算式です。 例として以下の画像の一番左のキャラクターのみ四角形ポリゴンに UVマッピングするための各頂点のUV値をテクセル座標から変換してみます。
UVアニメーション
UVアニメーションはUVマッピングする矩形を一定フレーム毎に変更する手法です。 この手法を使用することで、キャラクターやエフェクトのアニメーションを表現できます。
ループ
アニメーションのループはアニメーションが最後に到達した際に そのままにせずに先頭や途中の矩形に戻すことで可能です。
実装方法
アニメーションの実装にはアニメーションの矩形情報などのデータ側と それを使用する再生側の実装が必要となります。
データ側
データ側は「矩形情報」「矩形切り替え時間」「次の矩形に関する情報」が 必要なので、それが保存できる構造体やクラスを用意します。struct UVAnimationRect { // 矩形に必要な情報 float m_TexturePosX; //!< テクスチャ座標X float m_TexturePosY; //!< テクスチャ座標Y float m_RectWidth; //!< 矩形横幅 float m_RectHeight; //!< 矩形縦幅 TextureList m_TextureId; //!< 対象のテクスチャID // アニメーションに必要な情報 int m_ChangeFrame; //!< 切り替えフレーム intt m_NextRectId; //!< 次のアニメーションID };
用意したデータ構造を使用して「待機」や「移動」など、 各アニメーション単位のデータを用意します。// 待機アニメーション UVAnimationRect CharacterIdleAnimations[] = { { 0.0f, 0.0f, 128.0f, 128.0f, TextureList::CharacterTex, 5, 1 }, { 128.0f, 0.0f, 128.0f, 128.0f, TextureList::CharacterTex, 5, 2) }, { 256.0f, 0.0f, 128.0f, 128.0f, TextureList::CharacterTex, 5, 3) }, { 374.0f, 0.0f, 128.0f, 128.0f, TextureList::CharacterTex, 5, 0) }, }; // 移動アニメーション UVAnimationRect CharacterRunAnimations[] = { { 0.0f, 128.0f, 128.0f, 128.0f, TextureList::CharacterTex, 5, 1 }, { 128.0f, 128.0f, 128.0f, 128.0f, TextureList::CharacterTex, 5, 2 }, { 256.0f, 128.0f, 128.0f, 128.0f, TextureList::CharacterTex, 5, 3 }, { 374.0f, 128.0f, 128.0f, 128.0f, TextureList::CharacterTex, 5, 4 }, { 0.0f, 256.0f, 128.0f, 128.0f, TextureList::CharacterTex, 5, 0 }, };
この各アニメーション情報をまとめておき、そのまとめた内容をもとにして enumなどの定数を用意すると管理が楽になります。// アニメーションリスト enum AnimationIds { CharacterIdleAnimation, //!< キャラクター待機 CharacterRunAnimation, //!< キャラクター移動 MaxAnimationIds, }; // アニメーションリスト UVAnimationRect* AnimationsList[] = { CharacterIdleAnimations, CharacterRunAnimations, };
再生側
再生は必要な情報は「再生中のアニメーション、矩形、時間」です。
この情報をPlayerやEnemyなどの様々なオブジェクトが使用することになるので、
汎用的に使えるようにしておいた方が楽です。
今回は再生用の構造体と再生実行関数で実装しています。
// アニメーション再生用構造体
struct AnimationPlayer
{
AnimationIds m_AnimationId; //!< アニメーションID
UVAnimationRect* m_Animations; //!< アニメーション矩形情報
int m_Frame; //!< フレーム数
int m_CurrentId; //!< m_Animationsのインデックス
};
bool UpdateAnimation(AnimationPlayer* player)
{
bool is_finish = false;
player->m_Frame++;
if (player->m_Frame >= player->m_Animations[player->m_CurrentId].m_ChangeFrame)
{
player->m_Frame = 0;
if (player->m_Animations[player->m_CurrentId].m_NextAnimationId != -1)
{
player->m_CurrentId = player->m_Animations[player->m_CurrentId].m_NextAnimationId;
}
else
{
// アニメーション終了
is_finish = true;
}
}
return is_finish;
}
UVスクロール
UVスクロールは設定されているUV座標に対しの加算または減算を行い 画像がスクロールしているようにみせる方法です。
UVスクロールの種類
UVスクロールには種類がいくつかあり、その種類によって0.0~1.0の範囲を 越えた際の描画の内容が変わります。 スクロールの種類は「ラップ」「ミラー」「クランプ」「ボーダー」があります。 ※サンプルではDirectX9を使用しているので、設定の説明もDirectX9で行っています。
設定方法
DirectXでの設定はIDirect3DDeviceのSetSamplerStateを使用します。
内容 | Samplerの設定を行う | |
---|---|---|
戻り値 | 初期化の成否(HRESULT)が返る | |
引数の型 | 説明 | |
DWORD Stage | サンプラステージ | |
D3DTEXTURESTAGESTATETYPE Type | サンプラステートの設定 pValueの影響がU軸やV軸などの設定が可能 |
|
DWORD pValue | ラッピングモードの種類 |
ラップ
ラップはUV座標が0.0~1.0の範囲を超えた場合、 範囲を超えた領域はテクスチャを繰り返し描画します。 SetSamplerStateの設定では「D3DTADDRESS_WRAP」を設定します。
ミラー
ミラーはUV座標が0.0~1.0の範囲を超えた場合、 上下または左右反転したテクスチャで範囲を超えた領域の描画を行います。 SetSamplerStateの設定では「D3DTADDRESS_MIRROR」を設定します。
クランプ
クランプはUV座標が0.0~1.0の範囲を超えた場合、 終端の色情報を使用して範囲を超えた領域の描画を行います。 SetSamplerStateの設定では「D3DTADDRESS_CLAMP」を設定します。
ボーダー
ボーダーはUV座標が0.0~1.0の範囲を超えた場合、 特定の色で範囲を超えた領域の描画を行います。 ボーダーのみSetSamplerStateの設定は2つ必要になります。 まず通常と同様に「D3DTADDRESS_BORDER」を設定します。 次にSetSamplerState(0, D3DSAMP_BORDERCOLOR, 領域を埋めたい色)で 描画で使用する色を決めます。