行列を用いた移動

復習:演算を用いたポリゴンの移動

ポリゴンを上下左右に移動させるには、ポリゴンの各頂点座標にそれぞれ移動させたい値を加えればよい。
例えば、頂点A、B、C、Dで構成されるポリゴンを右方向に10ピクセル移動させたいなら、ポリゴンの各頂点のx座標に対して次の演算を行えばよい。

頂点AのX座標 = 頂点AのX座標 + 10.0f
頂点BのX座標 = 頂点BのX座標 + 10.0f
頂点CのX座標 = 頂点CのX座標 + 10.0f
頂点DのX座標 = 頂点DのX座標 + 10.0f

各頂点のX,Y座標にそれぞれ移動量を加えるのは面倒なので、移動処理を行う関数(Move関数)を用意し、その関数を使って簡単に移動処理が行えるようにした(6章1を参照)。
先の例の場合、Move()関数を使って次のようにプログラムできる。

Move(VertexDataTbl1, 10.0f, 0.0f);

行列による移動

上記で行ったように、各頂点ごとに演算をして移動先の座標を求める方法以外に、行列(マトリックス)を用いて頂点座標を求める方法がある。
ポリゴンを移動させるだけなら演算で移動先の座標を簡単に求めることができるが、行列を使えば移動、拡大/縮小、回転が1回の乗算だけで行うことができる
この授業では2Dゲームの製作を目標にしているため、行列を使わなくても特に支障はない。しかし、3Dゲームの製作には欠かすことのできない技術であるため、ここでは行列を使ってポリゴンを移動させる方法を紹介する。2Dで行列の移動が使えれば、3Dゲームの授業についていくことができるだろう。

行列については数学の授業で詳しく行うので、ここでは簡単な紹介だけにしておく。
頂点A(0,0,0)をX方向に10移動させると、頂点A’は(10,0,0)になる。この演算を行列で行うには、頂点行列に移動量行列を乗算すればよい
それぞれの行列は4行4列で表すと決まっており、次のように表現される。

これをプログラムで表すと、次のようになる。

1.変数の宣言

// 行列の定義
D3DXMATRIX PosMatrix;  // 頂点行列
D3DXMATRIX MoveMatrix; // 移動量行列

《POINT》

2.行列に値を設定

// 行列の初期化
D3DXMatrixIdentity(&PosMatrix);  // 単位行列生成
D3DXMatrixIdentity(&MoveMatrix); // 単位行列生成
// 移動量行列に移動量を設定
MoveMatrix._41 = 10.0f; // X移動量
MoveMatrix._42 = 0.0f; // Y移動量
MoveMatrix._43 = 0.0f; // Z移動量

《POINT》

3.移動処理(MyChara.v[0〜3]に、現在のポリゴンの座標がセットされているものとする)

// 移動処理
int i;
for ( i=0 ; i < 4 ; i++ ) {
    PosMatrix._41 = MyChara.v[i].x; // 頂点行列に現在のポリゴンのX座標をセット
    PosMatrix *= MoveMatrix;        // 頂点行列に移動量を加算
    MyChara.v[i].x = PosMatrix._41; // 演算結果をポリゴンのX座標に格納
}

《POINT》

D3DXMatrixTranslation関数による移動

上記のやり方では、行列への座標/移動量のセットは、行列に値を直接代入している。例えば四角形ポリゴンのX,Y座標を同時に移動させる場合、次のようなプログラムになる。

// 移動量のセット
MoveMatrix._41 = X方向の移動量;
MoveMatrix._42 = Y方向の移動量;

// 移動処理
int i;
for ( i=0 ; i < 4 ; i++ ) {
    // 頂点情報のセット
    PosMatrix._41 = MyChara.v[i].x;
    PosMatrix._42 = MyChara.v[i].y;
    // 演算
    PosMatrix *= MoveMatrix;
    // 結果を戻す
    MyChara.v[i].x = PosMatrix._41;
    MyChara.v[i].y = PosMatrix._42;
}

これは、D3DXMatrixTranslation関数を使って次のように簡略化できる。

// 移動量のセット
D3DXMatrixTranslation(&MoveMatrix, X方向の移動量, Y方向の移動量, Z方向の移動量);

// 移動処理
int i;
for ( i=0 ; i < 4 ; i++ ) {
    // 頂点情報のセット
    D3DXMatrixTranslation(&PosMatrix, MyChara.v[i].x, MyChara.v[i].y, MyChara.v[i].z);
    // 演算
    PosMatrix *= MoveMatrix;
    // 結果を戻す
    MyChara.v[i].x = PosMatrix._41;
    MyChara.v[i].y = PosMatrix._42;
}

実際のプログラム

D3DXMatrixTranslation関数によって、行列への値の代入が簡単に行えることがわかった。しかし、2Dゲームの場合は四角形ポリゴンを扱うため、1つのポリゴンを移動させるのに4回のループを行わなければならない。よって、実際のプログラムでは、これらの処理も関数化し、Move関数と同じ感覚で利用できるようにするべきである。
行列による移動処理を行う関数を次のように作成する。NKC_Public.cppに作成するのがよいだろう。

MoveMatrix()関数の作成

//----------------------------------------------------------------------------------------
// 関数名 : MoveMatrix()
// 機能概要: 各頂点に対し、行列を使用して与えられた移動量を加算する
//----------------------------------------------------------------------------------------
void MoveMatrix(LPTLVERTEX v, float x, float y, float z)
{
    D3DXMATRIX PosMatrix, MoveMatrix;
    int i;

    // 行列の初期化(単位行列生成)
    D3DXMatrixIdentity(&PosMatrix);
    D3DXMatrixIdentity(&MoveMatrix);

    // 移動量設定
    D3DXMatrixTranslation(&MoveMatrix, x, y, z);

    // 移動処理
    for ( i=0 ; i<4 ; i++ ) {
        // 現在の頂点座標を格納
        D3DXMatrixTranslation(&PosMatrix, v[i].x, v[i].y, v[i].z);
        // 演算
        PosMatrix *= MoveMatrix;
        // 結果を戻す
        v[i].x = PosMatrix._41;
        v[i].y = PosMatrix._42;
        v[i].z = PosMatrix._43;
    }

}

《POINT》

MoveMatrix()関数の使用

MoveMatrix()関数を作成したら、Move()関数を使っているところを次のように変更してみる。

Move(MyChara.v, MyChara.MoveX, MyChara.MoveY);
↓
MoveMatrix(MyChara.v, MyChara.MoveX, MyChara.MoveY, 0.0f);

《POINT》

※任意のプログラムに上記修正を行い、MoveMatrix()関数を使用しても同じようにキャラクタが移動できることを確認すること。



NEXT(拡大・縮小)