一、安裝
在國際上出名的物理引擎有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:/PhysX/SDKS/Physics/include
D:/PhysX/SDKS/Founddation/include
D:/PhysX/SDKS/PhysXLoader/include
然后在…àLibrary Fiks中加入以下目錄:
D:/PhysXdks/LIB/Win32
以 上用到的“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);
創建一個地面角色這可能是角色創建的最簡朴的方法了只用到了四行代碼首先分別創建一個平面形狀描述和角色描述兩個描述都不作任何修改也就是使用它們的默認值.平面的中央位於世界坐標原點(000)處,而法線則是指向y軸的正方向。
第二步把平面描述添加到角色描述中的形狀列表中去,從這里我們也可以看到,一個角色是可以包含多個形狀物體的。
第 三步就是把角色加到場景(scene)中去,也許你會注意到,前面我們所說的一個角色實體必須包括形狀描述和剛體描述,兩大部份,為什么這里只有形狀描 述呢?其實,剛體描述也是存在的,當你沒有為它指定的時候,角色創建時會自動生成一個默認的剛體描述。一個剛體的默認值是這樣的:它不會移動但是會把與它 發生碰撞的物體反彈回去。因為它的質量是無限大的。
4、 創建盒子
前面介紹了如何創建一個地面,這是場景中最簡朴的一個角色了下面我們將要創建一個稍為復雜一點的角色,一個盒子。
Int size=5
NxBodyDesc BodyDesc;
BodyDesc.angularDamping=0.5f;
BodyDesc.linearVelocity=NxUec3(0.0f0.0f0.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.0f1.0f1.0f1.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秒其實最好是使用一些系統時間函數來計算上一次刷屏到現在的時間,這樣會讓物體運動更加逼真。
四.總結
這 是一個PhysX物理引擎的Hello World入門程序為了讓大家更清楚地看到程序總體框架我把程序的功能盡量寫得簡朴。在接下來的一段時間里我會寫一些復雜的相關教程希望各位網友 友持。當然,我也是一邊學一邊寫,難免會出現錯差,假如你們發現我的文章有問題的話,請E-mail:huawenguang@sina.com 告訴知我,也歡迎在這方面有共同愛好的朋友來信交流.
特殊感謝我身邊一個朋友的支持!
五、源代碼
// A minimal Novodex application test.
// 以下代碼,先安裝好PhysX SDK,及按要求配置好路徑之后才能編譯。
// 建義用使用VC2003以上版本,VC6.0在我這里有一個“return”錯誤,把“return”去掉就可以編譯通過。
// 運行的時候假如提示缺少DLL文件,請在/bin/win32 目錄中找到相應的DLL文件把它拷貝到工程文件夾中,
// 或者拷貝到系統systems32/ 文件夾中
// NxBoxes by Pierre Terdiman (01.01.04)
// author: huawenguang@sina.com
#define NOMINMAX
#ifdef WIN32
#include
#include
#include
#elif LINUX
#include
#include
#elif __APPLE__
#include
#include
#elif __CELLOS_LV2__
#include
#endif
#include
// Physics code
#undef random
#include "NxPhysics.h"
//#include "ErrorStream.h"
#pragma comment( lib "PhysXLoader.lib" )
static bool gPause = false;
static NxPhysicsSDK* gPhysicsSDK = NULL;
static NxScene* gScene = NULL;
static NxVec3 gDefaultGravity(0.0f -9.81f 0.0f);
static float gRatio=1.0f;
static void InitNx()
{
// Initialize PhysicsSDK
gPhysicsSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION 0 NULL);
if(!gPhysicsSDK) return;
gPhysicsSDK->setParameter(NX_MIN_SEPARATION_FOR_PENALTY -0.05f);
// Create a scene
NxSceneDesc sceneDesc;
sceneDesc.gravity = gDefaultGravity;
sceneDesc.broadPhase = NX_BROADPHASE_COHERENT;
sceneDesc.collisionDetection = true;
gScene = gPhysicsSDK->createScene(sceneDesc);
NxMaterial * defaultMaterial = gScene->getMaterialFromIndex(0);
defaultMaterial->setRestitution(0.9f);
defaultMaterial->setStaticFriction(0.1f);
defaultMaterial->setDynamicFriction(0.1f);
// Create ground plane
NxPlaneShapeDesc PlaneDesc;
PlaneDesc.d = -5.0f;
NxActorDesc ActorDesc;
ActorDesc.shapes.pushBack(&PlaneDesc);
gScene->createActor(ActorDesc);
//CreateCube(NxVec3(0.020.00.0)5);
// Create body
//////////////////////////////////////////////////////////////
int size = 5;
NxBodyDesc BodyDesc;
BodyDesc.angularDamping = 0.5f;
// BodyDesc.maxAngularVelocity = 10.0f;
BodyDesc.linearVelocity = NxVec3(0.0f0.0f0.0f);
NxBoxShapeDesc BoxDesc;
BoxDesc.dimensions = NxVec3(float(size) float(size) float(size));
NxActorDesc BoxActorDesc;
BoxActorDesc.shapes.pushBack(&BoxDesc);
BoxActorDesc.body = &BodyDesc;
BoxActorDesc.density = 0.10f;
BoxActorDesc.globalPose.t = NxVec3(0.020.00.0);
gScene->createActor(BoxActorDesc)->userData = (void*)size;
}
static void RenderCallback()
{
// Clear buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Setup camera
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0f 1.0 1.0f 10000.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0 5.1 50.0 0.0 0.0 0.0 0.0f 1.0f 0.0f);
gScene->fetchResults(NX_RIGID_BODY_FINISHED);
gScene->simulate(1/60.0f);
gScene->flushStream();
// Keep physics &graphics in sync
int nbActors = gScene->getNbActors();
NxActor** actors = gScene->getActors();
while(nbActors--)
{
NxActor* actor = *actors++;
if(!actor->userData) continue;
glPushMatrix();
float glmat[16];
actor->getGlobalPose().getColumnMajor44(glmat);
glMultMatrixf(glmat);
glColor4f(1.0f 1.0f 1.0f 1.0f);
glutWireCube(float(int(actor->userData))*2.0f);
glPopMatrix();
}
glutSwapBuffers();
}
int main(int argc char** argv)
{
// Initialize Glut
printf("PhysX Hello World!");
glutInit(&argc argv);
glutInitWindowSize(512 512);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
int mainHandle = glutCreateWindow("PhysX Hello World!");
glutSetWindow(mainHandle);
glutDisplayFunc(RenderCallback);
glutIdleFunc(RenderCallback);
// Setup default render states
glClearColor(0.3f 0.4f 0.5f 1.0);
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
// Physics code
InitNx();
// ~Physics code
// Run
glutMainLoop();
if(gPhysicsSDK &&gScene) gPhysicsSDK->releaseScene(*gScene);
gPhysicsSDK->release();
return 0;
}
再分享一下我老師大神的人工智能教程吧。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智能的隊伍中來!https://blog.csdn.net/jiangjunshow