今回は、三角錐を回してみます。
次のソースを、ダウンロードしてください。
今回も、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次元ポリゴンが表示できます。
理論は、他の本、ページに譲るとして、使って慣れてしまうのがいいと思います。
プロの?ゲーム開発の場でも、各行列がどうなっているのかぜんぜん知らない人もいます。
でも使えてしまうのです。
ようは、設定している変数の意味がわかっているかどうかです。
個人的には、ここで深く考えるよりも、この先にあるもっと面白いことにチャレンジしろって感じです。
でも、ちゃんとした本などで数式もマスターすべきですよ。