由于国内资料很少,所以有些冲动将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