DirectX 8.1 入門:AppWizard


~新しい機能をとりあえず使ってみた~




■はじめに

DirectX 8.1 が公開されました。
仮にもチュートリアルページ?試さないわけにはいきません。
今回は新しい機能の一つである AppWizard にチャレンジです。

くそ~、一度 DirectX をアンインストールしないと GeForce3 の HAL が有効にならなかったぞ!!
なんだこりゃ~

さて、今回のソースは、次のものです。

今回は、DirectX が作ったものをそのまま載せています。

sample.cppユーザーが触るであろうファイル。
sample.hsample.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リソース管理。

あと、いつもの様に、実行ファイルと、プロジェクトファイル、それにアイコンファイルが入っています。
多くの気にしなくて良いファイルがあります。
見ておくほうがいいと思いますが、知らなくてもプログラムはできます。
暇を見てが解読しておきましょう。

■AppWizard の手順く

では、手順を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 が何かがわかるので、初心者がなれるのにはいいと思います。

自分が使うかといえば・・・・
ちゃんとしたサンプルを作るときには使うかもしれません。




もどる

imagire@gmail.com