Microsoft Visual Studio .NET 2003
 NVIDIA PhysX SDK v2.8.3
 Microsoft DirectX 9.0 SDK (December 2004)

■PhysXをとりあえず使ってみる Prev  Top  Next
関連ページ:PhysX リファレンス

2009/11/25: RenderDataメソッド内でワールド行列を単位行列に設定する

無料レンタルサーバー

まず実行環境です。自分は次の開発環境を使用しています。

 Microsoft Visual Studio .NET 2003
 Microsoft DirectX 9.0 SDK Update (December 2004)
 NVIDIA PhysX SDK v2.8.3

バージョンについては参考程度にとらえてください。まったく同じにする必要はないです。っていうか無理だろう。
「NVIDIA PhysX SDK v2.8.3」が2009年12月現在の最新バージョンです。

開発に使用しているPCのGPUはこれです。

 GeForce Go 7600

このGPUはPhysXに対応していません。実行するとソフトウェアモードで動作します。対応状況はどうなっているんだろう。

ではVisual Studio上で新規でプロジェクトを作成して環境の設定を行います。

●インクルードファイルのパス
 D:\Program Files\NVIDIA Corporation\NVIDIA PhysX SDK\v2.8.3\SDKs\Physics\include
 D:\Program Files\NVIDIA Corporation\NVIDIA PhysX SDK\v2.8.3\SDKs\Foundation\include
 D:\Program Files\NVIDIA Corporation\NVIDIA PhysX SDK\v2.8.3\SDKs\PhysXLoader\include

●ライブラリファイルのパス
 D:\Program Files\NVIDIA Corporation\NVIDIA PhysX SDK\v2.8.3\SDKs\lib\Win32

●追加の依存ファイル
 winmm.lib dxguid.lib d3d9.lib d3dx9.lib PhysXLoader.lib

パスはインストール環境によって変わります。

サンプル1
今回は上の画像のようにボールを自由落下させて地面上でバウンドさせてみます。 つか静止画ではわからんな。まいいや。ポリゴンではなくワイヤーフレームで表示しています。

ではソースを紹介します。 でその前に注意!自分も勉強中で間違ってるところがあるかもしれないのでその辺ご注意を。

あと参照したサイトです。 Shader.jp
しばらくお世話になります。

---PhysX.h---


BOOL InitNxPhysX( NxPhysicsSDK** pPhysicsSDK, NxScene** pScene, DEBUG_RENDERER** pDebugRenderer );

---PhysX.cpp---

//PhysXの初期化
BOOL InitNxPhysX( NxPhysicsSDK** pPhysicsSDK, NxScene** pScene, DEBUG_RENDERER** pDebugRender )
{
   HRESULT hr;
   NxSceneDesc sceneDesc;

   // PhysicsSDKを初期化
   (*pPhysicsSDK) = NxCreatePhysicsSDK( NX_PHYSICS_SDK_VERSION );
   if( (*pPhysicsSDK) == NULL )
   {
      hr = -1;
      goto ERROR_EXIT;
   }

   //2物体が接触するときの衝突判定のための「厚み」を設定
   //正数のときめり込むみたい
   (*pPhysicsSDK)->setParameter( NX_SKIN_WIDTH, 0.0f );

   if( pDebugRender != NULL )
   {
      // デバッガに表示する内容 DebugRender.cppを追加して使用する
      (*pPhysicsSDK)->setParameter(NX_VISUALIZATION_SCALE, 3);          //アクターの3軸の表示上のスケール値
      (*pPhysicsSDK)->setParameter(NX_VISUALIZE_COLLISION_SHAPES, 1);   //衝突判定の対象となってる形状(0で非表示)
      (*pPhysicsSDK)->setParameter(NX_VISUALIZE_ACTOR_AXES, 1);         //アクターの3軸の表示(0で非表示)

      (*pDebugRender) = new DEBUG_RENDERER;
   }

   //重力値を設定
   sceneDesc.gravity   = NxVec3(0.0f, -9.81f, 0.0f);

   //ハードウェアの有無を確認
   NxHWVersion HWVersion = (*pPhysicsSDK)->getHWVersion();
   //対応しているのでフラグをたてる
   if( HWVersion != NX_HW_VERSION_NONE )
      sceneDesc.simType = NX_SIMULATION_HW;

   //NxSceneの作成
   (*pScene) = (*pPhysicsSDK)->createScene(sceneDesc);
   if((*pScene) == NULL) 
   {
      hr = -2;
      goto ERROR_EXIT;
   }

   hr = S_OK;
   return hr;

ERROR_EXIT:
   return hr;
}

これはPhysXの初期化関数です。 NxPhysicsSDKとかNxSceneはPhysXの標準クラスです。NxPhysicsSDKはまあIDirect3D9、NxSceneはIDirect3DDevice9みたいなものと考えていいと思います。 DEBUG_RENDERERは自作のクラスです。なにやってるかはあとで解説します。

NxCreatePhysicsSDK関数について。引数にNX_PHYSICS_SDK_VERSIONを渡しています。これを渡すと、開発時に使用するのPhysX SDKのバージョンと実行時のDLLのバージョンが一致しているかをチェックできます。 バージョンが定義されているNxVersionNumber.hのメジャーバージョンを変更して検証したところ、どうも上位互換性はなく、完全に一致していないと関数がNULLを返すようです。 となると配布時にはDLLも一緒に配布する必要があると思います。DirectXと違ってWindowsに標準でインストールされていませんしね。まあDLLを配布して問題ないかどうかは必ずNVIDIAサイトにて確認してください。

---DebugRenderer.h---


class DEBUG_RENDERER
{
private:
   // DebugRenderer用頂点フォーマット
   typedef struct _DEBUG_RENDER_VERTEX
   {
      D3DXVECTOR3 vPos;
      DWORD color;
   }DEBUG_RENDER_VERTEX;

   DWORD m_FVF;
   DEBUG_RENDER_VERTEX* m_DebugRenderVertex;

public:
   DEBUG_RENDERER();
   ~DEBUG_RENDERER();

   //頂点データをPhysXから取得
   void RenderData( const LPDIRECT3DDEVICE9 pd3dDevice, const NxDebugRenderable* data );

private:
   //描画処理
   void RenderBuffer( const LPDIRECT3DDEVICE9 pd3dDevice, const DEBUG_RENDER_VERTEX *pVertex, const D3DPRIMITIVETYPE Type, const int VertexCount );
};

---DebugRenderer.cpp---

DEBUG_RENDERER::DEBUG_RENDERER()
{
   m_DebugRenderVertex = NULL;
   m_FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;
}

DEBUG_RENDERER::~DEBUG_RENDERER()
{
}

//描画処理
void DEBUG_RENDERER::RenderBuffer( const LPDIRECT3DDEVICE9 pd3dDevice, const DEBUG_RENDER_VERTEX *pVertex, const D3DPRIMITIVETYPE Type, const int VertexCount )
{
   //現在のレンダーステートの設定を退避

   DWORD RStateLightingBK;
   pd3dDevice->GetRenderState( D3DRS_LIGHTING, &RStateLightingBK );
   //ライティングを無効
   pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
   
   DWORD RStateCullModeBK;
   pd3dDevice->GetRenderState( D3DRS_CULLMODE, &RStateCullModeBK );
   //両面レンダリング
   pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );

   IDirect3DBaseTexture9* ppTexBK = NULL;
   pd3dDevice->GetTexture( 0, &ppTexBK );
   //テクスチャーを無効にする
   pd3dDevice->SetTexture( 0, NULL );

   DWORD FVFBK;
   pd3dDevice->GetFVF( &FVFBK );
   pd3dDevice->SetFVF( m_FVF );

   //描画
   pd3dDevice->DrawPrimitiveUP( Type, VertexCount , pVertex, sizeof(DEBUG_RENDER_VERTEX) );

   //戻す
   pd3dDevice->SetRenderState( D3DRS_LIGHTING, RStateLightingBK );
   pd3dDevice->SetRenderState( D3DRS_CULLMODE, RStateCullModeBK );
   pd3dDevice->SetTexture( 0, ppTexBK );
   pd3dDevice->SetFVF( FVFBK );
}

//頂点データをPhysXから取得
void DEBUG_RENDERER::RenderData( const LPDIRECT3DDEVICE9 pd3dDevice, const NxDebugRenderable* data )
{
   //頂点の座標を更新することで移動させているようなのでワールド行列は単位行列にする
   D3DXMATRIX matWorld;
   D3DXMatrixIdentity( &matWorld );
   pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );

   SafeDelete( m_DebugRenderVertex );

   if( data == NULL || pd3dDevice == NULL )
      goto ERROR_EXIT;

   DWORD dwCount;

   //*******************************************************************************************
   //点描画
   //*******************************************************************************************

   //頂点数を取得
   unsigned int NbPoints = data->getNbPoints();
   if(NbPoints)
   {
      //頂点数ぶんの領域確保
      m_DebugRenderVertex = new DEBUG_RENDER_VERTEX[NbPoints];
      if( m_DebugRenderVertex == NULL )
         goto ERROR_EXIT;

      //頂点データを取得
      const NxDebugPoint* Points = data->getPoints();

      dwCount = 0;

      //全頂点の情報をDirect3Dの描画用の構造体にコピー
      while(NbPoints--)
      {
         m_DebugRenderVertex[dwCount].vPos  = D3DXVECTOR3( Points->p.x, Points->p.y, Points->p.z );
         m_DebugRenderVertex[dwCount].color = (DWORD)Points->color;
         dwCount++;
         Points++;
      }
      
      //描画処理へ
      RenderBuffer( pd3dDevice, m_DebugRenderVertex, D3DPT_POINTLIST, data->getNbPoints() );

      SafeDelete( m_DebugRenderVertex );
   }

   //*******************************************************************************************
   //辺描画
   //*******************************************************************************************

   //辺数を取得
   unsigned int NbLines = data->getNbLines();
   if(NbLines)
   {
      //辺数ぶんの領域確保
      m_DebugRenderVertex = new DEBUG_RENDER_VERTEX[NbLines * 2];
      if( m_DebugRenderVertex == NULL )
         goto ERROR_EXIT;

      //辺データを取得
      const NxDebugLine* Lines = data->getLines();

      dwCount = 0;

      //全辺の情報をDirect3Dの描画用の構造体にコピー
      while(NbLines--)
      {
         m_DebugRenderVertex[dwCount].vPos  = D3DXVECTOR3( Lines->p0.x, Lines->p0.y, Lines->p0.z );
         m_DebugRenderVertex[dwCount].color = (DWORD)Lines->color;
         dwCount++;

         m_DebugRenderVertex[dwCount].vPos  = D3DXVECTOR3( Lines->p1.x, Lines->p1.y, Lines->p1.z );
         m_DebugRenderVertex[dwCount].color = (DWORD)Lines->color;
         dwCount++;

         Lines++;
      }
      
      //描画処理へ
      RenderBuffer( pd3dDevice, m_DebugRenderVertex, D3DPT_LINELIST, data->getNbLines() );

      SafeDelete( m_DebugRenderVertex );
   }

   //*******************************************************************************************
   //△ポリゴン描画
   //*******************************************************************************************

   //△ポリゴン数を取得
   unsigned int NbTriangles = data->getNbTriangles();
   if(NbTriangles)
   {
      //△ポリゴン数ぶんの領域確保
      m_DebugRenderVertex = new DEBUG_RENDER_VERTEX[NbTriangles * 3];
      if( m_DebugRenderVertex == NULL )
         goto ERROR_EXIT;

      //△ポリゴンデータを取得
      const NxDebugTriangle* Triangles = data->getTriangles();

      dwCount = 0;

      //全△ポリゴンの情報をDirect3Dの描画用の構造体にコピー
      while(NbTriangles--)
      {
         m_DebugRenderVertex[dwCount].vPos  = D3DXVECTOR3( Triangles->p0.x, Triangles->p0.y, Triangles->p0.z );
         m_DebugRenderVertex[dwCount].color = (DWORD)Triangles->color;
         dwCount++;

         m_DebugRenderVertex[dwCount].vPos  = D3DXVECTOR3( Triangles->p1.x, Triangles->p1.y, Triangles->p1.z );
         m_DebugRenderVertex[dwCount].color = (DWORD)Triangles->color;
         dwCount++;

         m_DebugRenderVertex[dwCount].vPos  = D3DXVECTOR3( Triangles->p2.x, Triangles->p2.y, Triangles->p2.z );
         m_DebugRenderVertex[dwCount].color = (DWORD)Triangles->color;
         dwCount++;

         Triangles++;
      }
      
      //描画処理へ
      RenderBuffer( pd3dDevice, m_DebugRenderVertex, D3DPT_TRIANGLELIST, data->getNbTriangles() );

      SafeDelete( m_DebugRenderVertex );
   }

   return;

ERROR_EXIT:

   return;
}

この関数は衝突判定で使用するコリジョン用オブジェクトの大きさなどを確認するために画面上にワイヤーフレームを表示するためのものです。ソース元は次の場所にあります。
D:\Program Files\NVIDIA Corporation\NVIDIA PhysX SDK\v2.8.3\Samples\SampleCommonCode\src\DebugRenderer.cpp
パスはインストール環境によって異なります。 前にも言いましたがこのソースはOpenGL用ですのでそのままDirectXで使用できません。そのためDirectX用に修正しています。

---main.cpp---


//Direct3D
static LPDIRECT3D9           m_pdirect3d9    = NULL;
static LPDIRECT3DDEVICE9     m_pd3dDevice    = NULL;
static D3DPRESENT_PARAMETERS m_d3dParameters;

//PhysX
static NxPhysicsSDK*         m_pNxPhysicsSDK = NULL;
static NxScene*              m_pNxScene      = NULL;

// PhysXデバッグ用クラス
static DEBUG_RENDERER*       m_pDebugRenderer = NULL;

static UINT nWidth = 1024;       //ウィンドウの横幅
static UINT nHeight = 768;       //ウィンドウの縦幅

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE /*hPrevInstance*/,
                     LPSTR     /*lpCmpLine*/,
                     INT       /*nCmdShow*/)
{
   HRESULT hr;
   MSG msg;
   ZeroMemory( &msg, sizeof(MSG) );
   HWND hWnd = NULL;
   BOOL Windowed = TRUE;
   TCHAR* AppName = _T("PhysX Tutrial 01");

   //****************************************************************************
   // ウィンドウ作成
   //****************************************************************************

   // 省略。。。

   //****************************************************************************
   // Direct3Dの初期化
   //****************************************************************************

   // 省略。。。

   //****************************************************************************
   // PhysXの初期化
   //****************************************************************************

   hr = InitNxPhysX( &m_pNxPhysicsSDK, &m_pNxScene, &m_pDebugRenderer );
   if( FAILED( hr ) )
   {
      ::DestroyWindow( hWnd );
      return 0;
   }

   NxActorDesc actorDesc;

   //****************************************************************************
   // 静的な衝突判定用オブジェクトを作成する
   //****************************************************************************

   // 初期化
   actorDesc.setToDefault();

   // 地面のアクターを作成する
   NxPlaneShapeDesc planeDesc;
   // 初期化
   planeDesc.setToDefault();
   // 原点からの距離
   // この値と法線ベクトル(別にあるメンバ変数)により地面の位置が決定される
   planeDesc.d = -5.0f;

   actorDesc.shapes.pushBack(&planeDesc);

   // 摩擦関連
   NxMaterial * defaultMaterial = m_pNxScene->getMaterialFromIndex(0);
   // 反発係数(球をバウンドさせる)
   defaultMaterial->setRestitution(0.5f);

   // シーンに対して、指定のアクターを追加
   m_pNxScene->createActor(actorDesc);

   //****************************************************************************
   // 動的な衝突判定用オブジェクトを作成する
   //****************************************************************************

   // 初期化
   actorDesc.setToDefault();

   // 球体のアクターを作成する
   NxSphereShapeDesc sphereDesc;
   // 初期化
   sphereDesc.setToDefault();
   // 球の半径を指定
   sphereDesc.radius = 2.0f;

   // この辺で動的な設定をする
   NxBodyDesc bodyDesc;
   // 初期化
   bodyDesc.setToDefault();
   // 回転による減衰係数
   bodyDesc.angularDamping = 0.5f;

   // 球をアクターに追加
   actorDesc.shapes.pushBack(&sphereDesc);
   // ここで動的情報を指定
   actorDesc.body          = &bodyDesc;
   // 質量密度
   actorDesc.density         = 0.01f;
   // ワールド空間上の位置
   actorDesc.globalPose.t  = NxVec3(0.5f, 20.0f, 30.0f);

   // シーンに対して、指定のアクターを追加
   m_pNxScene->createActor(actorDesc);

   ::ShowWindow(hWnd, SW_SHOW);
   ::UpdateWindow(hWnd);

   //****************************************************************************
   // メッセージループ
   //****************************************************************************

   do
   { 
      if( ::PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )
      {
         ::TranslateMessage(&msg); 
         ::DispatchMessage(&msg); 
      }
      else
      {
         if( MainLoop(hWnd) == FALSE )
            ::DestroyWindow( hWnd );
      }
   }while( msg.message != WM_QUIT );

   ::UnregisterClass( AppName, hInstance );

   return msg.wParam;
}

LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, UINT wParam, LONG lParam )
{
   switch (msg)
   {
   case WM_KEYUP:
      if( wParam == VK_ESCAPE )
         ::DestroyWindow( hWnd );
      break;

   // 終了処理
   case WM_DESTROY:
      //PhysX
      SafeDelete( m_pDebugRenderer );
      if( m_pNxPhysicsSDK != NULL )
      {
         if( m_pNxScene != NULL )
            m_pNxPhysicsSDK->releaseScene( *m_pNxScene );
         m_pNxScene = NULL;

         NxReleasePhysicsSDK( m_pNxPhysicsSDK );
         m_pNxPhysicsSDK = NULL;
      }

      //Direct3D
      SafeRelease( m_pd3dDevice );
      SafeRelease( m_pdirect3d9 );
      ::PostQuitMessage(0);
      break;

   default:
      return ::DefWindowProc( hWnd, msg, wParam, lParam );
   }

   return 0L;
}

BOOL MainLoop( HWND hWnd )
{   
   D3DXMATRIX matWVP, matWorld, matView, matProj;

   //ワールド行列
   D3DXMatrixIdentity( &matWorld );
   m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );

   //ビュー行列
   D3DXMatrixTranslation( &matView, 0.0f, 0.0f, 0.0f );
   m_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );

   //遠近射影行列
   //クリップ面はアプリケーションごとに調整すること
   D3DXMatrixPerspectiveFovLH( &matProj,
                               D3DX_PI/4.0f,
                               4.0f / 3.0f,
                               0.01f, 150.0f );
   m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );

   if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
   {
      m_pd3dDevice->Clear( 0L, 
                           NULL, 
                           D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
                           0x0,
                           1.0f,
                           0L );

      //****************************************************************************
      // デバッグ用のワイヤーフレームを描画
      //****************************************************************************

      if(m_pDebugRenderer)
         m_pDebugRenderer->RenderData( m_pd3dDevice, m_pNxScene->getDebugRenderable() );

      m_pd3dDevice->EndScene();

      // 1FPSの時間を指定
      // 遅延が発生した場合を考慮しないとだめだろう
      m_pNxScene->simulate( 1.0f / 60.0f );

      //よくわからんが下記の2関数をコールして実際に時間を進めるらしい
      m_pNxScene->flushStream();
      m_pNxScene->fetchResults( NX_RIGID_BODY_FINISHED, true );
   }

   m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

   return TRUE;
}

今回はコリジョン判定用オブジェクトの表示をやりました。次は実際の3Dモデルを表示させてみたいと思います。


Prev  Top  Next
inserted by FC2 system