各処理の作成(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 ); } }
ここで、アクターの描画を行います。
基本的な描画のシナリオは下記の通りです。
- シーンに登録されたアクター数を取得します。
- 登録されているアクターの行列(回転行列、平行移動行列が合成されたもの)を順番に取り出す。
userData
に入ったスケーリング用の係数を取得する。actor->getShapes()
で形状を問い合わせる。- 形状に応じたメッシュの描画。
になります。
具体的には、まず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の面白い機能として、ジョイントがあります。ジョイントは関節のあるモデルの物理を扱うだけでなく、ある程度の力がかかるとジョイントの切断をすることができます。これを工夫してうまく使うと破砕などの表現に使うことが出来ます。破砕は物が壊れる演出効果を高めるのに役立ちます。