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 が何かがわかるので、初心者がなれるのにはいいと思います。
自分が使うかといえば・・・・
ちゃんとしたサンプルを作るときには使うかもしれません。