DirectX 8.1 が公開されました。
仮にもチュートリアルページ?試さないわけにはいきません。
今回は新しい機能の一つである AppWizard にチャレンジです。
くそ~、一度 DirectX をアンインストールしないと GeForce3 の HAL が有効にならなかったぞ!!
なんだこりゃ~
さて、今回のソースは、次のものです。
今回は、DirectX が作ったものをそのまま載せています。
sample.cpp | ユーザーが触るであろうファイル。 |
sample.h | sample.cpp のヘッダー。 |
d3dapp.h | 気にするな。 |
d3dapp.cpp | 気にするな。 |
d3dfile.h | 気にするな。 |
d3dfile.cpp | 気にするな。 |
d3dfont.h | 気にするな。 |
d3dfont.cpp | 気にするな。 |
d3dutil.cpp | 気にするな。 |
d3dutil.cpp | 気にするな。 |
dxutil.h | 気にするな。 |
dxutil.cpp | 気にするな。 |
d3dres.h | リソース管理。 |
resource.h | リソース管理。 |
あと、いつもの様に、実行ファイルと、プロジェクトファイル、それにアイコンファイルが入っています。
多くの気にしなくて良いファイルがあります。
見ておくほうがいいと思いますが、知らなくてもプログラムはできます。
暇を見てが解読しておきましょう。
では、手順を1から説明します。
VC++ を立ち上げてください。
新規作成を選択します。
新規作成ダイアログだ出ます。
『DirectX AppWizard』を選択して、プロジェクト名に適当な名前を入れます。
まぁ、MFCなんか使わないので、Single document window を選択して、Direct??? のうち、使うものを選択します(普通に表示するだけなら、Direct3Dだけで十分です)。
次に自動的に表示してくれるオブジェクトを選択します。
最初は Teapot(茶瓶)から初めて、慣れたら何もない Blank にするのがいいでしょう。
これで、終了です。
実行すると、コンパイルしてくれて、ティーポットが表示されます。
FPS 表示もあっていたせりつくせりです。
では、ソースファイルの中身はどうなっているのでしょうか?
ここでは、d3d??? の名前がついていない sample.cpp の中身を見てみましょう。
ほとんどが、CMyD3DApplication のメソッドになっています。
初期化は、HRESULT CMyD3DApplication::InitDeviceObjects() です。
//----------------------------------------------------------------------------- // Name: InitDeviceObjects() // Desc: Initialize scene objects. //----------------------------------------------------------------------------- HRESULT CMyD3DApplication::InitDeviceObjects() { // TODO: create device objects HRESULT hr; // Init the font (フォントの初期化) m_pFont->InitDeviceObjects( m_pd3dDevice ); // Create a teapot mesh using D3DX (ティーポットの初期化) if( FAILED( hr = D3DXCreateTeapot( m_pd3dDevice, &m_pD3DXMesh, NULL ) ) ) return DXTRACE_ERR_NOMSGBOX( "D3DXCreateTeapot", hr ); return S_OK; }
フォントと、ティーポットのそれぞれの初期化をしています。
それ以外にも自分でオブジェクトを追加していくときは、ここに記述します。
また、レンダリング状態等の設定をする CMyD3DApplication::RestoreDeviceObjects() が、最初に呼ばれます。
//----------------------------------------------------------------------------- // Name: RestoreDeviceObjects() // Desc: Restores scene objects. //----------------------------------------------------------------------------- HRESULT CMyD3DApplication::RestoreDeviceObjects() { // TODO: setup render states // Setup a material D3DMATERIAL8 mtrl; D3DUtil_InitMaterial( mtrl, 1.0f, 0.0f, 0.0f ); m_pd3dDevice->SetMaterial( &mtrl ); // Set up the textures(頂点色がついたテクスチャー) m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); // Set miscellaneous render states(バッファなどの設定) m_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE, FALSE ); m_pd3dDevice->SetRenderState( D3DRS_SPECULARENABLE, FALSE ); m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE ); m_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x000F0F0F ); // Set the world matrix(ワールド行列の設定) D3DXMATRIX matIdentity; D3DXMatrixIdentity( &matIdentity ); m_pd3dDevice->SetTransform( D3DTS_WORLD, &matIdentity ); // Set up our view matrix. A view matrix can be defined given an eye point, // a point to lookat, and a direction for which way is up. Here, we set the // eye five units back along the z-axis and up three units, look at the // origin, and define "up" to be in the y-direction.(ビュー行列の設定) D3DXMATRIX matView; D3DXVECTOR3 vFromPt = D3DXVECTOR3( 0.0f, 0.0f, -5.0f ); D3DXVECTOR3 vLookatPt = D3DXVECTOR3( 0.0f, 0.0f, 0.0f ); D3DXVECTOR3 vUpVec = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); D3DXMatrixLookAtLH( &matView, &vFromPt, &vLookatPt, &vUpVec ); m_pd3dDevice->SetTransform( D3DTS_VIEW, &matView ); // Set the projection matrix(射影行列の設定) D3DXMATRIX matProj; FLOAT fAspect = ((FLOAT)m_d3dsdBackBuffer.Width) / m_d3dsdBackBuffer.Height; D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, fAspect, 1.0f, 100.0f ); m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj ); // Set up lighting states(光源の設定) D3DLIGHT8 light; D3DUtil_InitLight( light, D3DLIGHT_DIRECTIONAL, -1.0f, -1.0f, 2.0f ); m_pd3dDevice->SetLight( 0, &light ); m_pd3dDevice->LightEnable( 0, TRUE ); m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE ); // Restore the font(フォントのほうの設定) m_pFont->RestoreDeviceObjects(); return S_OK; }
深度バッファや、テクスチャーステートの設定に、各種変換行列を設定します。
値が変わらないものは、ここで設定するといいと思います。
描画部分は CMyD3DApplication::Render() です。
実際には、いつもと同じように BeginScene() と EndScene() の間で描画します(その部分を黄色で塗りました)。
//----------------------------------------------------------------------------- // Name: Render() // Desc: Called once per frame, the call is the entry point for 3d // rendering. This function sets up render states, clears the // viewport, and renders the scene. //----------------------------------------------------------------------------- HRESULT CMyD3DApplication::Render() { // Clear the viewport m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 0x000000ff, 1.0f, 0L ); // Begin the scene(描画開始) if( SUCCEEDED( m_pd3dDevice->BeginScene() ) ) { // TODO: render world // Render the teapot mesh(ティーポットの描画) m_pD3DXMesh->DrawSubset(0); // Render stats and help text(HELPの文字描画) RenderText(); // End the scene.(描画終わり) m_pd3dDevice->EndScene(); } return S_OK; }
なお、キーが押されたことによる変更は CMyD3DApplication::FrameMove() で行われます(実際のキーのチェックはUpdateInput()です)。
//----------------------------------------------------------------------------- // Name: FrameMove() // Desc: Called once per frame, the call is the entry point for animating // the scene. //----------------------------------------------------------------------------- HRESULT CMyD3DApplication::FrameMove() { // TODO: update world(全体の更新) // Update user input state(キー入力を調べる) UpdateInput( &m_UserInput ); // Update the world state according to user input(入力を見て、ワールド行列を変更する) D3DXMATRIX matWorld; D3DXMATRIX matRotY; D3DXMATRIX matRotX; if( m_UserInput.bRotateLeft && !m_UserInput.bRotateRight ) m_fWorldRotY += m_fElapsedTime; else if( m_UserInput.bRotateRight && !m_UserInput.bRotateLeft ) m_fWorldRotY -= m_fElapsedTime; if( m_UserInput.bRotateUp && !m_UserInput.bRotateDown ) m_fWorldRotX += m_fElapsedTime; else if( m_UserInput.bRotateDown && !m_UserInput.bRotateUp ) m_fWorldRotX -= m_fElapsedTime; D3DXMatrixRotationX( &matRotX, m_fWorldRotX ); D3DXMatrixRotationY( &matRotY, m_fWorldRotY ); D3DXMatrixMultiply( &matWorld, &matRotX, &matRotY ); m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld ); return S_OK; }
bRotateLeft 等をみて、回転角度を追加したりしています。
基本的には、ワールド行列を変更するだけです。
余分な負荷をかけないために、最小の更新にとどめているのだと思います。
後は、後始末です。CMyD3DApplication::DeleteDeviceObjects() で行います。
//----------------------------------------------------------------------------- // Name: DeleteDeviceObjects() // Desc: Called when the app is exiting, or the device is being changed, // this function deletes any device dependent objects. //----------------------------------------------------------------------------- HRESULT CMyD3DApplication::DeleteDeviceObjects() { // TODO: Cleanup any objects created in InitDeviceObjects()(InitDeviceObjects()で作成したオブジェクトを開放する) m_pFont->DeleteDeviceObjects(); SAFE_RELEASE( m_pD3DXMesh ); return S_OK; }
自分でオブジェクトを追加したときは、ここで削除します。
DirectX 8.1 で追加された機能の一つの AppWizard を試してみました。
d3dapp.cpp 等を使うので、ファイルが多くなるので全てを把握するのは大変ですが、
Microsoft のお墨付きの処理なので、確実な処理かもしれません。
サンプルをいじれば DirectX が何かがわかるので、初心者がなれるのにはいいと思います。
自分が使うかといえば・・・・
ちゃんとしたサンプルを作るときには使うかもしれません。