天天看點

PhysX實體引擎入門

Hi,大家好,好久沒有寫過東西了.最近在研究實體引擎,在網上搜尋了一下,發現相關的技術文章特别少,于是我心血來潮,決定給有興趣向這方面發展的朋友寫一篇入門教程,希望有所幫助。

如果你是一名超級遊戲愛好者,那想必你會聽說過PPU。要是你不知道什麼是PPU,那也不要緊,但至少你要知道什麼是"實體加速卡"。

Ageia是PhysX實體晶片的開發商,一家名不見經傳的公司,成為敢吃螃蟹的第一人。說不定不久的将來,我們的計算機裡會出現CPU,GPU,PPU三足鼎立的局面,而實體程式設計,也将成為遊戲程式員的必修課程。

一、安裝

在國際上,出名的實體引擎有Havok,Vortex,ODE,Novodex,Takamak等等,其中ode是一個免費開源的實體引擎,而Novodex就是PhysX的前身,被Ageia收購之後,改名為PhysX,是一個可以免費用于非商品用途的引擎。在這裡選用PhysX來作為入門教程,主要是因為,它的幫助比較豐富,而且開發包可以免費獲得。

關于PhysX sdk的安裝.首先要進入http://support.ageia.com下載下傳SDK,網站http://support.ageia.com下載安裝檔案.請注意的是Ageia的SDK隻對注冊使用者開放下載下傳。注冊是免費的,但好像要經過稽核才會開通,不過一般都會通過的。我注冊的時候好像是第二天才收到開通郵件。有兩個安裝檔案是必須下載下傳的System Software.exe和PhysX 2.3.3 SDK Core.exe前一個是底層驅動,後一個是程式核心,最新的SDK是2.4.1,但是隻針對商業客戶開放。對于初學者來說,最好把PhysX 2.3.3 SDK Training Pragrams.exe也一起下載下傳,裡面包含了從初級到進階的一系列教程,對學習這個引擎很有幫助。把所有東西下載下傳下來之後,接着是安裝了,安裝很簡單,一路next下去就可以了,但是為了讓VC中設定友善一點,建設把PhysX 2.3.3 SDK Core.exe的安裝路徑改短一點,例如我的就是安裝在D:PhysX中。

安裝好了之後,後開始對VC編譯環境進行設定。

首先,在Tools→Options→Directories→Inclund Fik中加入以下目錄.

D:PhysXSDKSPhysicsinclude

D:PhysXSDKSFounddationinclude

D:PhysXSDKSPhysXLoaderinclude

然後在…Library Fiks中加入以下目錄:

D:PhysXsdksLIBWin32

以上用到的"D:PhysX"指的是sdk安裝目錄,以你機器中的安裝路徑為準,本教程的示例程式用到了opengl和glut作為渲染引擎,你的計算機如何沒有安裝glut庫,那也請先到www.opengl.org上www.opengl.org下載下傳一個安裝上去。在這裡就不打算深入讨論glut了,沒有基礎的朋友可以先自學一下。

二.、PhysX概述

首先來介紹一下PhysX程式設計的幾個術語以及它們之間的互相聯系。

1.     Scene場景:就像演員表演都需要一個舞台一樣, PhysX的所有實體運動都在這個scene中進行。

2.     Actor角色:在場景中,所有參與運算的實體都是一個角色或許我這樣表達不是很正确,大家慢慢體會吧!

3.     bosy剛體:用來記錄物體之間世界互動的各種系數,如速度,阻尼等.

4.     shape形狀:描述和表達某一角色的外形,PhysX中提供4種基本形狀,盒子,球,膠囊以及平面。

從上面圖可以看到,PhysX程式設計其實很簡單,首先,定義各種不同的角色(actor),然後指定每個角色的形狀(shape)屬性和剛體(body)屬性,最後是把這些角色都加入到場景(scene)空間中去,這樣就可以構造出一個完整的實體世界。下面我将較長的描述程式設計的步驟.

三.程式設計實作

1.建立scene,

NxsceDesc

sceneDesc:

SceneDesc.grauity    =

gDefaultGravity;//指定重力加速度(-9.81f)

SceneDesc.broadphase =

NX_BROADPHASE_COHERENT;            

SceneDesc.collisionDetection= true;     //是否開啟碰撞檢測

Gscene

=gPhysicsSDK→createScene(sceneDesc);

首先我們要建立一個場景的描述(Descriptor),PhysX SDK就利用這個場景描述結構來建立生成一個場景執行個體.

描述(Descriptor)在整個SDK程式設計過程中,會被廣泛地使用。描述其實就是一個資料結構,主要是用來儲存各種在建立實體時所需要的相關資訊。你可以調整描述體中各種參數來達到不同的效果,當然你可以不作任何修改,這樣的話實體在建立時會使用描述體的預設值。

在本例子中,我們建立一個指定了重力加速以及碰撞檢測算法的場景執行個體。PhysX SDK中提拱了三種碰撞檢測算法提拱給大家選擇.這裡選用的是"broad phase-coheret collison detoction"。

2.給場景(scene)增加實體材質(Materials)

實體材質指的是某一具體物體的表面屬性和碰撞屬性,這些屬性可以确定一個物體和另一個物體發生碰撞時,是如何在該的物體上反彈,滑動或者滾動的。

你可以給場景中的所有物體指定一個相同的預設實體材質。

//建立預設材質

Nxmaterial* defaultMaterial=gscene → getMaterialFromIndex(0);

Default Material→setRestitution(0.9);//還原系數為0的時候沒有還原.

DefaultMaterial→setStaticFriction(0.5);//靜摩擦系數.

DefaultMaterial→setDynamicFricfion(0.5);//動摩擦系數.

以上材質的系數最小值都是0,最大值是1,如果要實作一個物體落在地上會自動彈跳,那就得把還原系數設得大一點。

3.建立地面

在本程式例子中,隻有兩個角色實體,地面和盒子.我們首先來看如何建立地面.

NxPlane shapeDesc planeDesc;

NxActorDesc   actorDesc;

actorDesc.shapes.pushBack(&phane Desc);

gscene→createActor(AcforDesc);

建立一個地面角色,這可能是角色建立的最簡單的方法了,隻用到了四行代碼,首先分别建立一個平面形狀描述和角色描述,兩個描述都不作任何修改,也就是使用它們的預設值.平面的中心位于世界坐标原點(0,0,0)處,而法線則是指向y軸的正方向。

第二步,把平面描述添加到角色描述中的形狀清單中去,從這裡我們也可以看到,一個角色是可以包含多個形狀物體的。

第三步,就是把角色加到場景(scene) 中去,也許你會留意到,前面我們所說的一個角色實體必須包括形狀描述和剛體描述,兩大部份,為什麼這裡隻有形狀描述呢?其實,剛體描述也是存在的,當你沒 有為它指定的時候,角色建立時會自動生成一個預設的剛體描述。一個剛體的預設值是這樣的:它不會移動但是會把與它發生碰撞的物體反彈回去。因為它的品質是 無限大的。

4、                                     建立盒子

前面介紹了如何建立一個地面,這是場景中最簡單的一個角色了,下面我們将要建立一個稍為複雜一點的角色,一個盒子。

Int size=5

NxBodyDesc BodyDesc;

BodyDesc.angularDamping=0.5f;

BodyDesc.linearVelocity=NxUec3(0.0f,0.0f,0.0f)

NxBoxShapeDesc

BoxDesc;

BoxDesc.dinesions=NxUec3(float(size),float(size),float(size));

NxActorDesc BoxActorDesc;

BoxActorDesc.shapes.pushBack(&BosDesc);

BosActorDsec.body=

&BodyDesc;

BoxActorDesc.desity=0.10f;

BoxActorDesc.globalpose.t=NxVec3(0.0.20.0.0.0);

Gscene→createActor(BoxActorDesc)→userData=(viud*)size;

這裡我們建立了一個叫"Box"的場景角我。我們可以看到,盒子角色完整地包含了形狀和剛體兩大部份。和建立平面角色不同的是盒子角色描述中多了"desity","globalpose"兩個分量,分别指的是密度和初始位置,SDK會根據密度和體積來自動計算角色的品質。

"globalpose"指的是在世界位标中的相對位置,值得注意的是:

PhysX中,與坐标尺寸相關的數值,其機關都是"米"(m)。

5.繪制與運動

完成了以上的準備工作之後,接下來便是檢驗成果的最後沖刺了.

Whik(nbActors--)

NxActor*actor=*actors++;

If(!actor->userData) continue;

glpushMatrix();

float glamat[16];

actor->getGlobalPose().getColumnMajor44(glmat);

glColor4f(1.0f,1.0f,1.0f,1.0f);  

glMultMatrix(glmat);

glutWireCube(float(int(actor→userData))*2.0f);

glPopMatrix();

上面是繪制場景的程式,這裡因為不需要繪制地面,是以第一行跳過平面角色,直接繪制盒子.

OK,現在我們可以讓程式運作起來了,在視窗可以看見生成的一個立方體盒子.但是為什麼那個盒子不會落下來,不會運動呢?這是因為我們還沒有加入實時運算函數。在繪制盒子之前加入以下三行:

Gscene→fetchResults(NX_RIGID_BODY_FINFSHED);

gsceng→Simulate(1/60.0f);

gscene→flushstream();

這樣,盒子就會産生自由落體運動,其中simulate(1/60.0)是一個積分函數,用來求位移.這裡用到了固定間隔時間1/60.0秒,其實最好是使用一些系統時間函數,來計算上一次刷屏到現在的時間,這樣會讓物體運動更加逼真。

四.總結

源文檔 <http://popul.jqcq.com/computer/gdev/1153370891.shtml>

繼續閱讀