SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

物理エンジンを使ってDirect3Dアプリケーションをつくる

Direct3DアプリケーションにAGEIA PhysXエンジンを導入する

  • X ポスト
  • このエントリーをはてなブックマークに追加

各処理の作成(2/2)

描画

描画処理
void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice,
    double fTime, float fElapsedTime, void* pUserContext )
{
    HRESULT hr;
    D3DXMATRIXA16 mWorld, matActor, matS;
    D3DXMATRIXA16 mView;
    D3DXMATRIXA16 mProj;
    D3DXMATRIXA16 mWorldViewProjection;
    float d3dMat[16];    // アクターから受け取る行列のための配列
    UINT iPass = 0;

    // If the settings dialog is being shown, then
    // render it instead of rendering the app's scene
    if( g_SettingsDlg.IsActive() )
    {
        g_SettingsDlg.OnRender( fElapsedTime );
        return;
    }

    // アクター数の取得
    int numActors = g_iActor = g_pScene->getNbActors();
    NxActor** actors = g_pScene->getActors(); // アクターの取得

    // Clear the render target and the zbuffer
    V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
        D3DCOLOR_ARGB(0, 45, 50, 170), 1.0f, 0) );

    // Render the scene
    if( SUCCEEDED( pd3dDevice->BeginScene() ) )
    {
        // Get the projection & view matrix from the camera class
        mWorld = *g_Camera.GetWorldMatrix();
        mProj = *g_Camera.GetProjMatrix();
        mView = *g_Camera.GetViewMatrix();

        mWorldViewProjection = mWorld * mView * mProj;

        // Update the effect's variables. Instead of using strings,
        // it would be more efficient to cache a handle 
        // to the parameter by calling
        // ID3DXEffect::GetParameterByName
        V( g_pEffect->SetFloat( "g_fTime", (float)fTime ) );
    V( g_pEffect->SetVector( "g_MaterialAmbientColor",
        &D3DXVECTOR4(0.4f, 0.4f,0.4f,0.4f) ) );

    while(numActors--)
    {
        // 現在のアクターの行列を取得
        NxActor* actor = *actors++;
        actor->getGlobalPose().getColumnMajor44( d3dMat );
        memcpy(&matActor, d3dMat, sizeof(D3DXMATRIXA16));

        if( !actor->userData )
            continue;

        D3DXMatrixScaling( &matS,
            float(int(actor->userData))*1.0f,
            float(int(actor->userData))*1.0f,
            float(int(actor->userData))*1.0f);

        mWorldViewProjection = matS * matActor * mView * mProj;

        // アクターの描画
            V( g_pEffect->SetMatrix( "g_mWorldViewProjection",
                &mWorldViewProjection ) );
            V( g_pEffect->SetMatrix( "g_mWorld", &matActor ) );

        V( g_pEffect->Begin( &iPass, 0 ));
        V( g_pEffect->BeginPass( 0 ) );

        // バウンディングボリュームの形状に合わせて
        // 描画するメッシュを変える
        NxShape* shape = *actor->getShapes();
        switch(shape->getType())
        {
        case NX_SHAPE_BOX:
            V( g_pEffect->SetVector("g_MaterialDiffuseColor",
                &D3DXVECTOR4(0.45,0.15,0.0,1)));        
            g_pEffect->CommitChanges();
            hr = g_pMeshBox->Render( pd3dDevice );
            break;
        case NX_SHAPE_SPHERE:
            V( g_pEffect->SetVector("g_MaterialDiffuseColor",
                &D3DXVECTOR4(0.6,0.6,0.6,1)));
            g_pEffect->CommitChanges();
            hr = g_pMeshSphere->Render( pd3dDevice );
            break;
        }

        V( g_pEffect->EndPass() );
        V( g_pEffect->End() );
    }

    // 地面の描画
    D3DXMatrixTranslation( &mWorld, 0, 0, 0);
    mWorldViewProjection = mWorld * mView * mProj;
    V( g_pEffect->SetMatrix( "g_mWorldViewProjection",
        &mWorldViewProjection ) );
        V( g_pEffect->SetMatrix( "g_mWorld", &mWorld ) );

    V( g_pEffect->Begin( &iPass, 0 ));
    V( g_pEffect->BeginPass( 0 ) );

    V( g_pEffect->SetVector("g_MaterialDiffuseColor",
        &D3DXVECTOR4(.8,.8,.8,1)));
    g_pEffect->CommitChanges();
    g_pMeshGround->Render( pd3dDevice );

    V( g_pEffect->EndPass() );
    V( g_pEffect->End() );

        // These events are to help PIX identify what the code is doing
        DXUT_BeginPerfEvent( DXUT_PERFEVENTCOLOR, L"HUD / Stats" );
        RenderText();
        V( g_HUD.OnRender( fElapsedTime ) );
        V( g_SampleUI.OnRender( fElapsedTime ) );
        DXUT_EndPerfEvent();

        V( pd3dDevice->EndScene() );
    }

    // 物理演算を進める
    if( g_pScene && !g_bPause )
    {
        g_pScene->flushStream();
        g_pScene->fetchResults( NX_RIGID_BODY_FINISHED, true );
    }
}

 ここで、アクターの描画を行います。

 基本的な描画のシナリオは下記の通りです。

  1. シーンに登録されたアクター数を取得します。
  2. 登録されているアクターの行列(回転行列、平行移動行列が合成されたもの)を順番に取り出す。
  3. userDataに入ったスケーリング用の係数を取得する。
  4. actor->getShapes()で形状を問い合わせる。
  5. 形状に応じたメッシュの描画。

 になります。

 具体的には、まずg_pScene->getNbActors()でアクター数を取得します。続いてg_pScene->getActors()で登録されたアクターのポインタを取得します。これをwhileで順番に呼びだしていきます。そしてactor->getGlobalPose().getColumnMajor44()で行列を取得します。actor->getShapes()で形状が呼び出せるので、それによって描画するメッシュを切り替えます。

 最後に、flushStream()のところでPhysX側にシミュレーションの演算のステップを進ませます。

終了処理

終了処理
VOID CleanupPhysX()
{
    // PhysX関連
        if( g_pPhysicsSDK && g_pScene )
            g_pPhysicsSDK->releaseScene( *g_pScene );
    if(g_pPhysicsSDK)
        g_pPhysicsSDK->release();
}

 ここではPhysXの終了処理を行っています。

 まずは、確保したシーンの解放を行い。最後にSDKクラスの解放処理を行います。

おわりに

 今回の記事では、PhysX SDKの導入と球やボックスの扱いを説明しました。PhysX SDKで扱える衝突形状はこのほかにもカプセルや凸形状、トライアングルメッシュ(三角形の集合体)など今回扱ったものより複雑なものもありますので、プログラムで必要とする衝突判定の精度とパフォーマンスに応じて必要なものを使うといいと思います。

 その他のPhysX SDKの面白い機能として、ジョイントがあります。ジョイントは関節のあるモデルの物理を扱うだけでなく、ある程度の力がかかるとジョイントの切断をすることができます。これを工夫してうまく使うと破砕などの表現に使うことが出来ます。破砕は物が壊れる演出効果を高めるのに役立ちます。

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

高橋 誠史(タカハシ マサフミ)

僻地の大学院生です。GPUプログラミングとそのニュースを集めたサイトShader.jpを開いています。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/719 2006/11/29 00:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング