PhysX官方教程lession101
由于國內資料很少,所以有些沖動將PhysX原教程給翻譯了,今天只做了一部分希望大家能夠認同
Lesson 1-1 – 主要形狀
介紹
In this lesson, you will create an instance of the SDK, create a scene, create four actors (a ground plane, a capsule, a sphere and a box), simulate the other three actors on the plane actor, and apply global forces to the box by keyboard action during the simulation.
這是我們學習PhysX SDK 剛體的第一課。這里,你會學會創建一個PhysX的實例,一個場景,和4個角色Actor(一個地面,一個膠囊,一個球體和一個立方體(盒子))模擬其中三個角色Actor放在地面上,并且通過使用鍵盤動作來產生一些力量控制這些角色。
1 Initializing the SDK and Creating a Scene初始化SDK并且創建一個場景
在每個課程中,你都需要創建一個PhysX SDK的實例來構建你虛擬的物理世界。 這些都通過一個叫做InitNx()的方法來實現 。以下這些未完成的代碼是提供給你來初始化PhysX SDK 并且創建一個場景scene的。
#include "Lesson101.h"
// Physics SDK globals
NxPhysicsSDK* gPhysicsSDK = NULL;
NxScene* gScene = NULL;
NxVec3 gDefaultGravity(0,-9.8,0);
void InitNx()
{
// Create the physics SDK
gPhysicsSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION);
if (!gPhysicsSDK) return;
// Create the scene
NxSceneDesc sceneDesc;
sceneDesc.gravity = gDefaultGravity;
gScene = gPhysicsSDK->createScene(sceneDesc);
}
void main(int argc, char** argv)
{
InitNx();
}
從 main()函數開始, 我們調用了InitNx()函數。 InitNx() makes an instance of the physics SDK InitNx()函數創建了Physics SDK的實例, 對應指針名字叫做gPhysicsSDK,并且創建了一個場景scene , 對應指針名gScene. 這大概是可以作到的最簡單的PhysX 應用了。同樣這段代碼也能正常編譯和運行。
2 Setting Parameters for the SDK設置SDK的屬性
Now we add parameters to the SDK to flesh out our simulation.
現在我們來給SDK填充一些屬性來豐富我們的虛擬世界。
//設置SDK的屬性
gPhysicsSDK->setParameter(NX_SKIN_WIDTH, 0.01);
第一個設置的SDK的全局屬性被稱為皮膚寬度skin width 。這是一個很重要的屬性, basically a “grace-depth” the SDK allows objects to penetrate each other by基本上一個 “grace-depth”SDK允許里面的物體相互穿透。 For now, we are setting it manually to 0.01 (an absolute depth of 0.01m or 1cm)因為現在,我們手動地設置它為0.01(一個0.01米或1厘米絕對深度). If we don’t add this line, it will default to 0.025 (0.025m or 2.5cm).如果我們不寫這一行代碼,它會采用默認值0.025(0.025米或2.5厘米)。
// 設置一些調試可見的屬性
gPhysicsSDK->setParameter(NX_VISUALIZATION_SCALE, 1);
gPhysicsSDK->setParameter(NX_VISUALIZE_COLLISION_SHAPES, 1);
gPhysicsSDK->setParameter(NX_VISUALIZE_ACTOR_AXES, 1);
These are debug visualization parameters we are setting for the simulation設置這些調試可見的屬性是為了實現我們需要的物理模擬效果,. We are saying when we switch to Debug Wireframe Mode, we want debug vectors to be 1 meter in length and we want to see all the collision shapes in the scene and the global poses of all the actors. 我們設置縮放比例為1m:1m,并且我們想在場景中看到所有的碰撞形狀,而且所有的角色都使用同一個朝向。亂七八糟的什么邊框激活模式,反正和上面圖形里面的白色條紋有關了。求高手翻譯。
3 Creating the Scene創建場景
We have adjusted all the parameters we want to the SDK and added a default material for objects to be constructed from. Now we create the scene. 我們已經調整好了所有我們想要的SDK的屬性,并且給所有的物體增加了一個默認的材質,現在我們來創建場景吧。
// 創建場景
NxSceneDesc sceneDesc;
sceneDesc.gravity = gDefaultGravity;
sceneDesc.simType = NX_SIMULATION_SW;
gScene = gPhysicsSDK->createScene(sceneDesc);
We start out with a scene descriptor which we feed to the SDK to create our scene. 我們創建了一個場景描述符(sceneDesc),然后依賴剛才我們定義好的SDK通過這個描述符來創建場景Descriptors are widely used throughout the SDK,這個描述符將被廣泛的應用于SDK的各個位置. They are structures that contain all the information you want your object to be created with他們包含了所有我們想要創造的物體的構造信息. You can adjust the descriptor to taste or leave it alone and the object will be created with the descriptor’s default settings.你可以調整這個描述符去嘗試使用或者不使用這個描述符來創建你物體。
In the above case, we want to create a software scene with the gravity vector provided. To create a software scene, set the simulation type to NX_SIMULATION_SW .
在上面的例子中,我們想要創建一個有重力方向的場景,就需要把simType設置為 NX_SIMULATION_SW。
4 Adding Materials to the Scene給場景增加一個默認材質
You want to give the scene a default physical material that everything will be made of. A material defines the collision and surface properties of the object the material is assigned to, that is, how the object will bounce, slide, and roll off other objects.
我們想在這個場景中創建的任何物體都具備一個默認的材質,一個材質可以定義這個物體的碰撞表面屬性。就是,可以會怎樣發生反彈,怎樣滑動,怎樣滾過其他的物體。
// Create the default material創建一個默認的材質
NxMaterial* defaultMaterial = gScene->getMaterialFromIndex(0);
defaultMaterial->setRestitution(0.5);
defaultMaterial->setStaticFriction(0.5);
defaultMaterial->setDynamicFriction(0.5);
This says all objects in the scene are made of a substance with average bounciness (restitution of 0.5) and average resting and sliding friction (static friction of 0.5 and dynamic friction of 0.5).
這里聲明了在這個場景中的所有物體均具有0.5的還原系數(彈性阻尼),0.5的動摩擦系數和靜摩擦系數。
5 Creating the Actors in the Scene在場景中創建角色Actor
At the end of InitNx(), we add our actors, the box and the plane, to the scene.
在InitNx()函數的末尾,我們把我們的角色添加進場景中,他們是一個盒子和一個面板。
// Actor globals全局角色
NxActor* groundPlane = NULL;
NxActor* box = NULL;
…
void InitNx()
{
…
// Create the objects in the scene
groundPlane = CreateGroundPlane();
gSelectedActor = CreateBox();
CreateSphere();
CreateCapsule();
…
}
6 Creating the Ground Plane創建地面面板
We will be using a ground plane in most of our simulations and we add it here.
我們將在這里添加一個很多模擬將用到的地面面板。
void InitNx()
{
...
groundPlane = CreateGroundPlane();
...
}
來看函數CreateGroundPlane().
NxActor* CreateGroundPlane()
{
// Create a plane with default descriptor
NxPlaneShapeDesc planeDesc;
NxActorDesc actorDesc;
actorDesc.shapes.pushBack(&planeDesc);
return gScene->createActor(actorDesc);
}
This is probably the simplest actor creation function. The ground plane actor is initialized with an actor descriptor. The actor descriptor is initialized with the default plane descriptor, so the ground plane passes through the origin (0,0,0) with normal along the positive y-axis (0,1,0). The plane has no rigid body assigned to it, so it is a static actor: it will not move and will push dynamic objects away from it as if it had infinite mass.
這可能是最簡單的角色創建函數了,這個地面面板角色通過一個actor的描述符初始化,而這個actor的描述符又通過一個默認的plane描述符初始化,因此這個地面面板會穿過原點(0,0,0)并且法線方向始終指向 y軸(0,1,0)。這個面板沒有注冊對應的剛體,所以它默認為一個靜態角色:既它不能移動,而且能夠將所有的動態物體推離自己,無限廣闊就像真實世界的地面一樣。
7 Creating the Box創建盒子
We now create our box. It is a single actor consisting of a single shape.
現在我們來創建我們的立方體,一個由單一的簡單圖形構成的單一的角色。
void InitNx()
{
...
box = CreateBox();
...
}
以下為CreateBox() 函數的內容:
NxActor* CreateBox()
{
// Set the box starting height to 3.5m so box starts off falling onto the ground賦值一個real型的數據startHeight =3.5米
NxReal boxStartHeight = 3.5;
// Add a single-shape actor to the scene在場景中添加一個簡單圖形的角色
NxActorDesc actorDesc;
NxBodyDesc bodyDesc;
// The actor has one shape, a box, 1m on a side這個角色有一個圖形,一個立方體,棱長為1
NxBoxShapeDesc boxDesc;
boxDesc.dimensions.set(0.5,0.5,0.5);
actorDesc.shapes.pushBack(&boxDesc);
actorDesc.body = &bodyDesc;
actorDesc.density = 10.0f;
actorDesc.globalPose.t = NxVec3(0,boxStartHeight,0);
assert(actorDesc.isValid());
NxActor *pActor = gScene->createActor(actorDesc);
assert(pActor);
// //create actor with no shapes創建一個沒有圖形的角色
//NxShape* const *shape = pActor->getShapes();
//NxBoxShape *boxShape = shape[0]->isBox();
//assert(boxShape);
//pActor->releaseShape(*boxShape);
return pActor;
}
We are creating an actor in the scene called “box”. To create the actor we need to pass an actor descriptor defining the actor to NxScene::createActor(). We give actorDesc a single shape descriptor, boxDesc. boxDesc describes a box that is one meter on a side. We set its dimensions using half the length, width, and height of the box with boxDesc.dimensions.set(0.5, 0.5, 0.5). Then we attach a body to the actor, bodyDesc, give the actor a density of 10, and set its global position to (0,boxStartHeight,0), meaning the center of the box will be at boxStartHeight = 3.5 meters above the ground at the beginning of the simulation.
我們在場景中創建了一個叫做“box”的角色,創建這個角色的方法Scene::createActor()需要通過一個角色描述符來定義角色信息。我們給這個角色描述符actorDesc一個簡單形狀描述符,boxDesc。boxDesc描述了一個棱長為1米的立方體,然后我們使用boxDesc.dimensions.set(0.5,0.5,0.5)方法使這個立方體的尺寸定制為0.5倍的長寬高。然后我們將一個體綁定到這個actor上,bodyDesc,設置角色密度為10/米立方,并且定義這個角色的全局位置為(0,boxStartHeight,0),意味著當程序開始運行時,這個立方體的中心點會處于高為3.5米的空中。
Our actor consists of a single shape, a box 1m on a side, centered at (0, boxStartHeight,0), and having a density 10. When we call NxScene::createActor(), the rigid body we attached to the actor, bodyDesc, will be computed given the box shape and density we have constructed the actor with.
我們的角色由一個簡單的形狀構成,一個棱長為1米的立方體,中心點位于(0,3.5 ,0)的位置上,并且密度為10,當我們調用這個NxSceneActor()時,這個剛體bodyDesc被綁定到這個角色上,將會計算出我們所構造出的這個立方體的形狀以及密度。
8 Initializing the HUD初始化HUD
We create a heads-up-display object that displays whether or not the scene is running in hardware, whether or not the scene is paused, as well as additional information as needed by the tutorial.
這里我們將創建一個前臺展示系統來展示我們所運行在PhysX中的角色。(這段我瞎翻譯的不要當真)
若有高手請幫忙翻譯。不勝感激
// HUD globals全局的HUD
HUD hud;
…
// Simulation globals
…
bool bHardwareScene = false;
bool bPause = false;
…
void InitNx()
{
…
// Initialize HUD
bHardwareScene = (gScene->getSimType() == NX_SIMULATION_HW);
hud.Update(bHardwareScene, bPause, "");
…
}
The HUD class and its member variables and functions are defined in HUD.cpp and HUD.h.
這個HUD類以及它的成員變量和方法被定義在HUD.cpp和HUD.h中。
9 Updating the Time更新時間流
Next we call UpdateTime().
接下來我們調用UpdateTime()函數
UpdateTime.h
NxReal UpdateTime()
{
NxReal deltaTime;
#ifndef LINUX
static __int64 gTime,gLastTime;
__int64 freq;
QueryPerformanceCounter((LARGE_INTEGER *)&gTime); // Get current count
QueryPerformanceFrequency((LARGE_INTEGER *)&freq); // Get processor freq
deltaTime = (double)(gTime - gLastTime)/(double)freq;
gLastTime = gTime;
#else
struct timeval tv;
static struct timeval lasttv = { 0 , 0 };
if (lasttv.tv_usec == 0 && lasttv.tv_sec == 0)
gettimeofday(&lasttv, NULL);
gettimeofday(&tv, NULL);
deltaTime = (tv.tv_usec - lasttv.tv_usec)/1000000.f
+ (tv.tv_sec - lasttv.tv_sec);
lasttv = tv;
#endif
return deltaTime;
}
Lesson101.h
void InitNx()
{
...
// Get the current time
UpdateTime();
...
}
This sets gTime to the current time. Every frame we call UpdateTime() to get deltaTime, the amount of time that has passed since we last rendered the scene and therefore the amount of time we need to advance the simulation to render the current scene.
這里設置gTime來控制時間流,每一禎我們都調用UpdateTime()方法來獲取deltaTime——從我們最后一次渲染場景到現在的時間到當前時間的時間段,因此這個我們需要在當前渲染的活動場景中增加這個加上這個時間段。
10 Starting the First Frame of the Simulation開始模擬第一禎
Finally, we call StartPhysics() to start the first frame of the simulation.
最后,我們來調用StartPhysics()方法來啟動這個模擬程序的第一禎。
void InitNx()
{
...
// Start the first frame of the simulation啟動,若存在場景則調用StartPhysics()
if (gScene) StartPhysics();
}
…
void StartPhysics()
{
// Update the time step更新時間
gDeltaTime = UpdateTime();
// Start collision and dynamics for delta time since the last frame從最后一禎的時間開始模擬這個時間段的物理碰撞和破壞。
gScene->simulate(gDeltaTime);
gScene->flushStream();
}
11 Getting the Results of the Simulation獲取模擬的結果集
We have initialized the SDK and created our scene with InitNx(). Now we call glutMainLoop() from main().
我們已經初始化了SDK并且使用InitNx()創建了場景,現在讓我們來從Main調用glutMainLoop()
int main(int argc, char** argv)
{
PrintControls();
InitGlut(argc, argv);
InitNx();
glutMainLoop();
ReleaseNx();
return 0;
}
The program will stay in glutMainLoop() until the user ends the simulation. After a scene is rendered, the RenderCallback() callback function gets called where we set up the next scene. At the beginning of RenderCallback(), we call NxScene::fetchResults() from GetPhysicsResults() to get the results of our physics simulation since our last call to NxScene::simulate() from StartPhysics().
這個程序將一直處于glutMainLoop()這個循環函數中,直到用戶終止這個模擬。當一個場景渲染完畢后,我們需要渲染動態場景的下一個狀況,RenderCallback()回調函數獲取調用。在RenderCallback()方法前端,我們調用GetPhysicsResult()函數,使用Scene::fetchResults獲取結果集。處理輸入流后再繼續進行物理模擬(這個大長句讓我頭上星光閃閃了,以自己的理解翻譯了,肯定不是原意,求高手)
void RenderCallback()
{
...
if (gScene && !bPause)//如果存在場景,且沒有處于暫停狀態
{
GetPhysicsResults();//獲取物理模擬結果集
ProcessInputs();//處理輸入
StartPhysics();//開始物理模擬
}
…
}
…
void GetPhysicsResults()
{
// Get results from gScene->simulate(deltaTime)通過gScene->simulate(delta Time)方法來獲取結果集。
while (!gScene->fetchResults(NX_RIGID_BODY_FINISHED, false));
}
We call NxScene::fetchResults(NX_RIGID_BODY_FINISHED, false) to close out the simulation started on the last call to NxScene::simulate(). The “NX_RIGID_BODY_FINISHED” parameter specifies that we want to close out the simulation of rigid bodies for this time step. The “false” parameter specifies that the call is non-blocking. We will not block waiting for the rigid body simulation to finish. If we put “true” here, instead:
我們使用NxScene::fetchResults(NX_RIGID_BODY_FINISHED,false)來處理從最后一次調用 NxScene::simulate() 的模擬。如果這里我們不等待所有剛體物理模擬完成,在這里我們選擇“true”,代碼應替換為:
void GetPhysicsResults()
{
// Get results from gScene->simulate(deltaTime)
gScene->fetchResults(NX_RIGID_BODY_FINISHED, true);
}
...the NxScene::fetchResults() call will not return at all until the simulation is finished. With our call, we continually query to see if the simulation is finished and don't break out of the loop until the funciton returns true. We could use this space to execute additional code in case the physics for the frame is not yet finished.
除非所有的模擬完成,NxScene::fetchResults()不會返回任何內容。程序會不斷的查詢這個模擬過程是否完成,并且一直等待這個應答為“true”時才跳出循環。我們可以用這段禎空閑時間來執行一些附加的代碼(不影響PhysX主循環的情況下)。
void GetPhysicsResults()
{
// Get results from gScene->simulate(deltaTime)
while (!gScene->fetchResults(NX_RIGID_BODY_FINISHED, false))
{
// Execute additional code here for rendering, AI, etc., 在這里執行附加代碼,可以用于渲染,或者人工智能,或者其它
// while waiting for the rigid body simulation to finish在這個循環等待這段時間的物理運算結束。
...
}
}
12 Processing Inputs to the Simulation處理輸入數據
We then call ProcessInputs() to collect all physics inputs to the new scene and set up any callbacks for the new scene. Here we apply forces to the box, set the position of the box, and set up callbacks, namely the user debug renderer, for the next simulation step.
接下來我們調用ProcessInputs()來收集所有服務于新場景(應為場景新狀態)的物理輸入數據和任何回調數據。在這里我們設置了一個作用于box的力,設置box的位置,和組織回調內容,即用戶的調試渲染器,為下一個模擬步驟準備。
void RenderCallback()
{
...
if (gScene && !bPause)
{
GetPhysicsResults();
ProcessInputs();
StartPhysics();
}
…
}
...
void ProcessInputs()
{
ProcessForceKeys();
// Show debug wireframes
if (bDebugWireframeMode)
{
if (gScene) gDebugRenderer.renderData(*gScene->getDebugRenderable());
}
}
1. Selecting Actors選擇角色
Press ‘r’ to call SelectNextActor to select other actor. The selected actor is rendered in wireframe mode. The actor with NX_TRIGGER_ENABLE flag and static actor can’t be selected.
按下‘r’鍵來調用SelectNextActor()選擇下一個角色。這個被選擇的角色會被渲染成邊框激活模式。擁有觸發器可用(NX _TRIGGER_ENABLE)標示的角色和靜態的角色(例如GroundPlane) 不會被選擇到。
void SelectNextActor()
{
NxU32 nbActors = gScene->getNbActors();
NxActor** actors = gScene->getActors();
for(NxU32 i = 0; i < nbActors; i++)
{
if (actors[i] == gSelectedActor)
{
NxU32 j = 1;
gSelectedActor = actors[(i+j)%nbActors];
while (!IsSelectable(gSelectedActor))
{
j++;
gSelectedActor = actors[(i+j)%nbActors];
}
break;
}
}
}
2. Applying Forces to the Actors對選擇的角色施加作用力
Our first call is to ProcessForceKeys(), where we call ApplyForceToActor() on our actor.
我們第一次調用ProcessForceKeys(),哪里我們對actor調用ApplyForceToActor()函數。
// Force globals全局作用力變量
NxVec3 gForceVec(0,0,0);//方向
NxReal gForceStrength = 20000;//力量
bool bForceMode = true;//???
…
// Keyboard globals鍵盤全局編號
#define MAX_KEYS 256
bool gKeys[MAX_KEYS];//256的鍵盤誒。其實是ASIC碼了
…
void ProcessForceKeys()
{
// Process force keys處理鍵盤鍵
for (int i = 0; i < MAX_KEYS; i++)
{
if (!gKeys[i]) { continue; }
switch (i)
{
…
// Force controls控制
…
case 'j': {gForceVec = ApplyForceToActor(gSelectedActor, NxVec3(1,0,0), gForceStrength); break; }//如果為j碼時,給gSelectedActor一個方向為(1,0,0),大小為20000牛的 作用力,執行完成后跳出循環。
…
}
}
}
...
void ProcessInputs()
{
ProcessForceKeys();
...
}
ApplyForceToActor() calls NxActor::addForce() to add forces to the box through keyboard input.
NxVec3 ApplyForceToActor(NxActor* actor, const NxVec3& forceDir, const NxReal forceStrength)
{
NxVec3 forceVec = forceStrength*forceDir*gDeltaTime;
actor->addForce(forceVec);
return forceVec;
}
Every time we hit “j”, we call box->addForce(NxVec3(gForceStrength,0,0)) and a force of gForceStrength = 20000 is applied continuously to the box at its center along the positive x-axis each frame. Note, when running the simulation, you start out facing down the positive z-axis of the scene marked in blue. The positive y-axis is in green going up and the positive x-axis is in red going to the left. All axes in the SDK are set up and rendered in this manner. “j” now imparts a force that pushes the box to the left. The force is shown as a yellow arrow. Note using the “umijkl” buttons, the force is constant, applied at the center of the box, and always faces along the global x, y, or z-axis.
每當我們點擊‘j’,我們都調用box->addForce(NxVec3(gFoceStrength,0,0))方法,即每一禎都會有一個沿x軸正方向大小為20000牛的作用力持續作用在這個立方體上,時間應該是gDeltaTime,即禎與禎的間隔時間。(功效還是很大的1秒可以產生20000焦耳的能量吧2W瓦。。。)。注釋:。。。
今天先翻譯到此,要下班了。明天把最困難的第一章翻譯完,然后把這段時間的學習筆記奉上,包括Ogre,Havok以及PhysX。
3. Resetting the Position of the Actors
Next we call NxActor::setGlobalPosition() to set the position of the box in ProcessKeys().
// Keyboard globals
#define MAX_KEYS 256
bool gKeys[MAX_KEYS];
…
void ProcessKeys()
{
// Process keys
for (int i = 0; i < MAX_KEYS; i++)
{
if (!gKeys[i]) { continue; }
switch (i)
{
…
// Return box to (0,5,0)
case 't': { gSelectedActor->setGlobalPosition(NxVec3(0,5,0)); break; }
…
}
}
}
Every time we hit “t”, we call NxActor::setGlobalPosition(NxVec3(0,5,0)) on our box actor. This places the actor at a position 5 units above the origin.
As with adding forces, we need to do this in between the NxScene::fetchResults() call in GetPhysicsResults() and the NxScene::simulate() call in StartPhysics()). It is an input to the physics scene which we need to perform while the scene is not being calculated by the hardware.
4. Debugging the Objects
After processing possible calls to add forces to and set the position of the box, we call the following code.
void ProcessInputs()
{
…
// Show debug wireframes
if (bDebugWireframeMode)
{
if (gScene) gDebugRenderer.renderData(*gScene->getDebugRenderable());
}
}
Hitting “b” in the demo toggles these wireframes on and off. The call gDebugRenderer.renderData() renders wireframes in the scene that we set up to visualize in InitNx() in order to see the collision shapes and actor axes in the scene. You can see the DebugRenderer::renderData() function in DebugRenderer.cpp.
void DebugRenderer::renderData(const NxDebugRenderable& data) const
{
glLineWidth(1.0f);
glPushMatrix();
glDisable(GL_LIGHTING);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Render points
NxU32 NbPoints = data.getNbPoints();
if(NbPoints)
{
...
}
// Render lines
NxU32 NbLines = data.getNbLines();
if(NbLines)
{
...
}
// Render triangles
NxU32 NbTris = data.getNbTriangles();
if(NbTris)
{
...
}
// Reset the color
glColor3f(1,1,1);
glEnable(GL_LIGHTING);
glPopMatrix();
}
Note that drawing these debug wireframes is for debug mode only. The drawing is not optimal because it is not done in parallel with the physics simulation, i.e., the physics simulation is idle when you do the debug rendering.
For more information on the Debug Renderer, see “Lesson 301: Debug Renderer”.
13 Starting the Simulation
Finally, we call StartPhysics() to start the next frame of the simulation.
void RenderCallback()
{
...
if (gScene && !bPause)
{
...
StartPhysics();
}
…
}
...
void StartPhysics()
{
// Update the time step
gDeltaTime = UpdateTime();
// Start collision and dynamics for delta time since the last frame
gScene->simulate(gDeltaTime);
gScene->flushStream();
}
StartPhysics() calls UpdateTime(), which gets deltaTime, the time step since the last scene. We call NxScene::simulate(deltaTime) and NxScene::flushStream() to run the simulation for the time step.
NxScene::simulate() is point of entry to the PhysX physics solver and the heart of the simulation. The SDK simulates the scene we have constructed for deltaTime. All computation for the simulation takes place on the hardware and gets retrieved by the next call to NxScene::fetchResults() which we call from GetPhysicsResults().
14 Drawing the Objects
After we call GetPhysicsResults(), ProcessInputs(), and StartPhysics()in RenderCallback(), we draw the objects in the scene from gCameraPos (0,5,-15) facing gCameraForward (0,0,1), so 5 meters above and 15 meters behind the origin along the z-axis, and facing the origin along positive z. We draw the actors and their shadows on the ground plane with the following code.
void RenderActors(bool shadows)
{
// Render all the actors in the scene
NxU32 nbActors = gScene->getNbActors();
NxActor** actors = gScene->getActors();
while (nbActors--)
{
NxActor* actor = *actors++;
DrawActor(actor);
// Handle shadows
if (shadows)
{
DrawActorShadow(actor);
}
}
}
void RenderCallback()
{
…
RenderActors(bShadows);
…
}
DrawActor() and DrawActorShadow() loop through all the shapes in the actor, drawing each shape and its shadow. The code for drawing the different types of shapes is in DrawShapes.cpp. You can look at it, but it’s not important for the lesson right now, just know this is where the actors get drawn.
15 Drawing the Forces
The force that gets applied to the box is returned to gForceVec. In RenderCallback(), we call DrawForce() to draw an arrow representing the force applied to the box.
void ProcessForceKeys ()
{
// Process force keys
for (int i = 0; i < MAX_KEYS; i++)
{
if (!gKeys[i]) { continue; }
switch (i)
{
…
// Force controls
case 'i': {gForceVec = ApplyForceToActor(gSelectedActor, NxVec3(0,0,1), gForceStrength); break; }
case 'k': {gForceVec = ApplyForceToActor(gSelectedActor, NxVec3(0,0,-1), gForceStrength); break; }
case 'j': {gForceVec = ApplyForceToActor(gSelectedActor, NxVec3(1,0,0), gForceStrength); break; }
case 'l': {gForceVec = ApplyForceToActor(gSelectedActor, NxVec3(-1,0,0), gForceStrength); break; }
case 'u': {gForceVec = ApplyForceToActor(gSelectedActor,NxVec3(0,1,0), gForceStrength); break; }
case 'm': {gForceVec = ApplyForceToActor(gSelectedActor,NxVec3(0,-1,0), gForceStrength); break; }
}
}
}
...
void ProcessInputs()
{
ProcessForceKeys();
…
}
...
void DrawForce(NxActor* actor, NxVec3& forceVec, const NxVec3& color)
{
// Draw only if the force is large enough
NxReal force = forceVec.magnitude();
if (force < 0.1f) return;
forceVec = 3*forceVec/force;
NxVec3 pos = actor->getCMassGlobalPosition();
DrawArrow(pos, pos + forceVec, color);
}
...
void RenderCallback()
{
...
if (gScene && !bPause)
{
...
ProcessInputs();
...
}
...
DrawForce(box, gForceVec, NxVec3(1,1,0));
gForceVec = NxVec3(0,0,0);
…
}
This code draws a yellow arrow originating from the center of mass of the box and extending 3 meters in the direction of the axis-aligned force.
16 Resetting the Scene and Shutting Down
Run the simulation for a while and hit F10. You will notice the box appears back in its starting position, falling to the ground as before. Hitting F10 resets the scene, calling ResetNx() which calls ReleaseNx() to shut down the SDK and then InitNx() to start it up again.
// Physics SDK globals
NxPhysicsSDK* gPhysicsSDK = NULL;
NxScene* gScene = NULL;
…
void SpecialCallback(int key, int x, int y)
{
switch (key)
{
// Reset PhysX
case GLUT_KEY_F10: ResetNx(); return;
}
}
void ReleaseNx()
{
if (gScene)
{
GetPhysicsResults(); // Make sure to fetchResults() before shutting down
gPhysicsSDK->releaseScene(*gScene);
}
if (gPhysicsSDK) gPhysicsSDK->release();
}
void ResetNx()
{
ReleaseNx();
InitNx();
}
ReleaseNx() calls GetPhysicsResults() which calls NxScene::fetchResults(), which waits for the card to finish processing the scene. It then calls NxPhysicsSDK::releaseScene() which deletes all the objects in the scene and then deletes the scene itself. It then calls NxPhysicsSDK::release() which shuts down the SDK.
ReleaseNx() is also called after glutMainLoop() to shut down the SDK before exiting.
17 Major Application Functions
The major functions of interest in the application are:
RenderCallback()
Calls GetPhysicsResults(), ProcessInputs(), and StartPhysics() each frame to simulate the scene. Places the camera with SetupCamera(). Draws the actors in the scene with RenderActors(). Draws the user supplied force to objects in the scene with DrawForce().
GetPhysicsResults()
Calls NxScene::fetchResults() to retrieve the results of the last frame of simulation.
ProcessInputs()
Gets keyboard input from ProcessForceKeys(). Calls NxDebugRenderer::renderData() to draw debug wireframes on the actors.
StartPhysics()
Calls UpdateTime() to get gDeltaTime, the time since the last frame of the scene was rendered. Calls NxScene::simulate(gDeltaTime) and NxScene::flushStream() to run the simulation for gDeltaTime.
InitNx()
Initializes the PhysX SDK with NxCreatePhysicsSDK(). Adds simulation-wide parameters with NxPhysicsSDK::setParameter(). Adds new materials to the SDK by calling NxScene::getMaterialFromIndex() and adjusting the material properties using NxMaterial::setRestitution(), ::setStaticFriction(), and ::setDynamicFriction(). Creates the scene with NxPhysicsSDK::createScene(). Constructs the actors in the scene with CreateGroundPlane() and CreateBox(), both of which call NxScene::createActor(). Sets the current time with UpdateTime(). Begins the simulation with StartPhysics().
gDebugRenderer.renderData()
Renders wireframes to visualize debug wireframes on the actors such as collision shapes and actor axes.
ReleaseNx()
Calls GetPhysicsResults() to close out the simulation. Calls NxPhysicsSDK::releaseScene() to shut down the scene and NxPhysicsSDK::release() to shut down the SDK.
18 Conclusion and Playing Around
You have completed a basic application using the PhysX SDK. Congratulations! You have taken your first step into a larger world. Experiment as much as you can with your creation. Use the “umijkl” keys to push the box around the plane and use the “qzwasd” keys to follow it around with the camera.
There is a lot of information in this lesson and it is fairly comprehensive as it covers an entire working application with everything from initializing the SDK, initializing the scene, creating an actor, applying forces to the actor through keyboard inputs, drawing the actor, running the simulation, drawing forces applied to the actor, and drawing debug wireframes for the objects. Don’t panic if there are some things you don’t understand right now. Everything will become more apparent with practice as you continue to use the SDK.
In future lessons, we will use the same framework as this lesson and introduce one or two new features per lesson until we have covered all the features in the SDK.
19 Related Classes, Functions, and Parameters
NxCreatePhysicsSDK()
NxPhysicsSDK
createScene()
setParameter()
visualize()
releaseScene()
release()
NxMaterial
setRestitution()
setStaticFriction()
setDynamicFriction()
NxSceneDesc
gravity
simType
NxScene
getMaterialFromIndex()
createActor()
simulate()
flushStream()
fetchResults()
NxPlaneShapeDesc
NxBoxShapeDesc
Dimensions
NxSphereShapeDesc
radius
NxCapsuleShapeDesc
radius
height
NxBodyDesc
NxActorDesc
shapes
body
density
globalPose
NxActor
setGlobalPosition()
getCMassGlobalPosition()
addForce()
NxDebugRenderable
getNbPoints()
getPoints()
getNbLines()
getLines()
getNbTriangles()
getTriangles()
NxDebugPoint
color
p
NxDebugLine
color
p0
p1
NxDebugTriangle
color
p0
p1
p2
NxParameter
NX_SKIN_WIDTH
NX_VISUALIZE_COLLISION_SHAPES
NX_VISUALIZE_ACTOR_AXES
NxSimulationStatus
NX_RIGID_BODY_FINISHED
21 Relationship between localPose and globalPose
In CreateBox, CreateSphere and CreateCapsule functions, there are two variables: localPose and globalPose need to be noted. See the following snippet:
NxCapsuleShapeDesc capsuleDesc;
capsuleDesc.radius = 0.55f;
capsuleDesc.height = 0.75f;
capsuleDesc.localPose.t = NxVec3(0, 0, 0);
//Rotate capsule shape
NxQuat quat(45, NxVec3(0, 0, 1));
NxMat33 m33(quat);
capsuleDesc.localPose.M = m33;
actorDesc.shapes.pushBack(&capsuleDesc);
actorDesc.body = &bodyDesc;
actorDesc.density = 10.0f;
actorDesc.globalPose.t =NxVec3(6.0f,capsuleStartHeight,0);
Here, globalPose is the coordinate in world coordinate System; localPose is the coordinate based on globalPose. See the below illustration:
Y Y’
Z
Z’
localPose
X’
globalPose
X World Coordinate System
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/sine199/archive/2009/11/26/4879937.aspx
再分享一下我老師大神的人工智能教程吧。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智能的隊伍中來!https://blog.csdn.net/jiangjunshow
總結
以上是生活随笔為你收集整理的PhysX官方教程lession101的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SEO工具,站长必备
- 下一篇: PHP 类的构造方法 __constru