今回は、三角錐を回してみます。
次のソースを、ダウンロードしてください。
今回も、draw.cpp を書き換えただけです。
今回は、頂点を変更します。といっても、さらに簡単になっていて、3次元座標と、頂点色だけです。
struct CUSTOMVERTEX
{
FLOAT x, y, z; // 位置
DWORD color; // 色
};
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE)
さらに、トライアングルファンを使ってみます。原点と、xy面、yz面及び、zx面の 1.0 の頂点にある三角形3つを表示します。
CUSTOMVERTEX vertices[] =
{
// x, y, z, color
{ 0.0f, 0.0f, 0.0f, D3DCOLOR_RGBA(0xff, 0xff, 0xff, 0xff), },
{ 1.0f, 0.0f, 0.0f, D3DCOLOR_RGBA(0xff, 0x00, 0x00, 0xff), },
{ 0.0f, 1.0f, 0.0f, D3DCOLOR_RGBA(0x00, 0xff, 0x00, 0xff), },
{ 0.0f, 0.0f, 1.0f, D3DCOLOR_RGBA(0x00, 0x00, 0xff, 0xff), },
{ 1.0f, 0.0f, 0.0f, D3DCOLOR_RGBA(0xff, 0x00, 0x00, 0xff), },
};
色は、(x,y,z)=(1,0,0) が赤、(0,1,0) が緑、(0,0,1) が青です。
今回は、いつもの頂点定義に加え、SetRenderState で、レンダリングするときの設定をしています。
もちろん、通常の描画で行ってもいいのですが、変更が起きないし、SetRenderState は重いらしいので、ここで設定します。
HRESULT InitRender(LPDIRECT3DDEVICE8 lpD3DDEV)
{
CUSTOMVERTEX vertices[] =
{
// x, y, z, color
{ 0.0f, 0.0f, 0.0f, D3DCOLOR_RGBA(0xff, 0xff, 0xff, 0xff), },
{ 1.0f, 0.0f, 0.0f, D3DCOLOR_RGBA(0xff, 0x00, 0x00, 0xff), },
{ 0.0f, 1.0f, 0.0f, D3DCOLOR_RGBA(0x00, 0xff, 0x00, 0xff), },
{ 0.0f, 0.0f, 1.0f, D3DCOLOR_RGBA(0x00, 0x00, 0xff, 0xff), },
{ 1.0f, 0.0f, 0.0f, D3DCOLOR_RGBA(0xff, 0x00, 0x00, 0xff), },
};
HRESULT hr;
hr = lpD3DDEV->CreateVertexBuffer( 5*sizeof(CUSTOMVERTEX),0,
D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &pVB);
if(FAILED(hr)) return E_FAIL;
VOID* pVertices;
hr = pVB->Lock( 0, sizeof(vertices), (BYTE**)&pVertices, 0);
if(FAILED(hr)) return E_FAIL;
memcpy( pVertices, vertices, sizeof(vertices) );
pVB->Unlock();
lpD3DDEV->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
lpD3DDEV->SetRenderState(D3DRS_LIGHTING, FALSE);
return S_OK;
}
D3DRS_CULLMODE は、ポリゴンを表裏のあるものかどうかの設定をします。
D3DCULL_NONE にすると、表裏の概念がありません。
D3DCULL_CW 等に設定すると、裏を向いた時は、表示をしなくなります。
D3DRS_LIGHTING は、ライトの設定です。ここでは、ライトを当てないようにします。
ライトの計算は、基本的に重いので、なるべく使わないように心がけるべきだと思います。
ここが、今回、一番ごちゃごちゃしています。
void Render(LPDIRECT3DDEVICE8 lpD3DDEV)
{
// ローカル、ワールド座標系の変換
D3DXMATRIX mWorld, mRotX, mRotY, mTrans;
D3DXMatrixTranslation(&mTrans, 0,0,0);
float time = (float)timeGetTime();
D3DXMatrixRotationY(&mRotY, time/600.0f);
D3DXMatrixRotationX(&mRotX, 0.0f);
mWorld = mRotX * mRotY * mTrans;
lpD3DDEV->SetTransform(D3DTS_WORLD, &mWorld);
// ワールド、ビュー座標系の変換
D3DXMATRIX mView, mProj;
D3DXMatrixLookAtLH(&mView
,&D3DXVECTOR3(0,3.0f,5.0f) // カメラ位置
,&D3DXVECTOR3(0,0,0) // カメラの注目点
,&D3DXVECTOR3(0,1,0) // 上の向き
);
lpD3DDEV->SetTransform(D3DTS_VIEW, &mView);
// ビュー、スクリーン座標系の変換
D3DXMatrixPerspectiveFovLH(&mProj
,60.0f*PI/180.0f // 視野角
,1.0f // アスペクト比
,0.01f // 最近接距離
,100.0f // 最遠方距離
);
lpD3DDEV->SetTransform(D3DTS_PROJECTION, &mProj);
// ポリゴンの描画
lpD3DDEV->SetStreamSource( 0, pVB, sizeof(CUSTOMVERTEX) );
lpD3DDEV->SetVertexShader( D3DFVF_CUSTOMVERTEX );
lpD3DDEV->DrawPrimitive( D3DPT_TRIANGLEFAN, 0, 3 );
}
さて、3つのマトリックスを設定する必要があります。
最初は、ローカル-ワールドマトリックスです。
このマトリックスは、ポリゴンの3次元空間での位置を設定します。
mTrans は、位置を指定します。今回は、(0,0,0) なので、原点にポリゴン(の基準位置)はあります。
mRotX, mRotY は、それぞれ、X 軸、Y 軸周りのポリゴンの回転です。
今回は、timeGetTime() で時間を調べて、Y 軸周りに回るようにしてみました。
Y 軸周りの回転は、コマの様にくるくる回ります。
次にワールド-ビューマトリックスです。
これは、カメラの位置です。
今回は、(0,3,5)にカメラをおきます。原点より少し手前上です。
これ以外に、カメラが見ている点を設定します(ポリゴンを見るように原点(ポリゴンの位置)を指定しました)。
また、上の方向を指定します。今回は、Y軸の方向にしました。
ここを変更すると、酔っ払ったアングルができますが、ほとんどこの設定でいいでしょう。
そして、ビュー-スクリーンマトリックスです。
これは、カメラの性能です。
最初の引数で、視野角を設定します。パノラマなどの特殊な効果をするときは、ここを変更します。
アスペクト比は、ピクセルの形です。まぁ、今のディスプレイなら、1.0でしょう
(PS 等のコンシューマ機では、320 x 448 の解像度を使う場合があり、このときには、0.5になったりします)。
最近接(最遠方)距離は、手前と、後方がどのくらいまで見えるかで、ポリゴンの大きさから適当に決めます。
今回は、単位をmと見立て、ポリゴンの大きさが、1m x 1m x 1m とすると、1cm から、100m ぐらいの範囲には、
ほぼ収まるだろうと思ったので、この数字にしました。
以上が、各マトリックスの設定です。
この処理は難しく見えますが、定型処理なので、一度作ったらほとんど変更しません。
こんなもんなんだと思ってもらってぜんぜんかまいません。
ただ、
mWorld * mView * mProj;
の行列を使うと一気にポリゴンのデータから、ディスプレイのスクリーン座標が計算できることは、 覚えておいたほうがいいと思います。SetTransform で複雑な設定をしているように感じるかもしれませんが、 実際には行列の掛け算しかしません。
最後に、トライアングルストリップで、扇形にポリゴンを3枚表示します。
後片付けは、いつものように、使ったものを開放するだけです。
void CleanRender()
{
RELEASE(pVB);
}
どうでしょうか?これで、とりあえず3次元ポリゴンが表示できます。
理論は、他の本、ページに譲るとして、使って慣れてしまうのがいいと思います。
プロの?ゲーム開発の場でも、各行列がどうなっているのかぜんぜん知らない人もいます。
でも使えてしまうのです。
ようは、設定している変数の意味がわかっているかどうかです。
個人的には、ここで深く考えるよりも、この先にあるもっと面白いことにチャレンジしろって感じです。
でも、ちゃんとした本などで数式もマスターすべきですよ。