Microsoft Visual Studio .NET 2003 NVIDIA PhysX SDK v2.8.3 Microsoft DirectX 9.0 SDK (December 2004) |
■PhysXをとりあえず使ってみる | Prev Top Next |
関連ページ:PhysX リファレンス |
|
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
では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; }この関数は衝突判定で使用するコリジョン用オブジェクトの大きさなどを確認するために画面上にワイヤーフレームを表示するためのものです。ソース元は次の場所にあります。
---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モデルを表示させてみたいと思います。