Personally, the demo with the clothes being ripped apart sold me (clothes start ripping after 1:23 into the video below):
http://www.youtube.com/watch?v=fXkSxph75_I
yet another one with clothes:
http://www.youtube.com/watch?v=dviWZcphcIQ
I haven't seen any other physics API able to rip clothes!
(source: http://devsupport.ageia.com/ics/support ... tionID=243)
Lesson 001: Quick Start Integration Guide
Introduction
This is a Quick Start Guide to integrating PhysX into your game. It contains a basic PhysX shell that highlights the key components to a quick-start PhysX integration. It will help you avoid some of the common initial developer pitfalls with integration.
1 Basic PhysX Shell
2 Make your Physics Loop Asynchronous
3 Use a Fixed Timestep
4 Turn on Debug Rendering
5 Put your User Callbacks and Inputs in ProcessInputs()
6 Adjust your Physics Parameters to Scale
7 Render your Physics Objects
1 Basic PhysX Shell
The following is a basic PhysX shell with an asynchronous physics loop, fixed timestep, debug rendering turned on, callbacks in ProcessInputs() after NxScene::fetchResults() and before NxScene::gScene->simulate(), physics parameters adjusted to scale, and objects drawn in sync with their physical data. We will analyze this basic loop in the next sections to explain where each item of interest is and how it works. For reference, this shell is built on an OpenGL implementation.
Code: Select all
NxPhysicsSDK* gPhysicsSDK = NULL;
NxScene* gScene = NULL;
void RenderCallback()
{
. . .
// Update physics objects
if (gScene)
{
GetPhysicsResults();
ProcessInputs();
StartPhysics();
}
// Render physics objects
SetupCamera();
RenderActors();
. . .
}
void GetPhysicsResults()
{
// Get results from gScene->simulate(deltaTime)
while (!gScene->fetchResults(NX_RIGID_BODY_FINISHED, false));
}
void ProcessInputs()
{
// Put user callbacks here
// Show debug wireframes
if (bDebugWireframeMode)
{
if (gScene) gDebugRenderer.renderData(*gScene->getDebugRenderable());
}
}
void StartPhysics()
{
// Update the time step
NxReal deltaTime = 1.0f/60.0f;
// Start collision and dynamics for delta time since the last frame
gScene->simulate(deltaTime);
gScene->flushStream();
}
void InitNx()
{
// Create the physics SDK
gPhysicsSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION);
if (!gPhysicsSDK) return;
// Set the debug visualization parameters
gPhysicsSDK->setParameter(NX_VISUALIZATION_SCALE, 1);
gPhysicsSDK->setParameter(NX_VISUALIZE_COLLISION_SHAPES, 1);
gPhysicsSDK->setParameter(NX_VISUALIZE_ACTOR_AXES, 1);
// Set scale dependent parameters
NxReal scale = 1.0f; // scale is meters per PhysX units
gPhysicsSDK->setParameter(NX_SKIN_WIDTH, 0.05*(1/scale));
gPhysicsSDK->setParameter(NX_DEFAULT_SLEEP_LIN_VEL_SQUARED, 0.15*0.15*(1/scale)*(1/scale));
gPhysicsSDK->setParameter(NX_BOUNCE_THRESHOLD, -2*(1/ scale));
gPhysicsSDK->setParameter(NX_VISUALIZATION_SCALE, 0.5*(1/ scale));
// Initialize the physics loop
if (gScene) StartPhysics();
}
void DebugRenderer::renderData(const NxDebugRenderable& data) const
{
. . .
}
To take full advantage of multi-threading, make your physics loop asynchronous. Set up your physics loop like this in your render callback.
Code: Select all
void RenderCallback()
{
GetPhysicsResults();
ProcessInputs();
StartPhysics();
}
Code: Select all
void ProcessInputs()
{
// Put user callbacks here
// Show debug wireframes
if (bDebugWireframeMode)
{
if (gScene) gDebugRenderer.renderData(*gScene->getDebugRenderable());
}
}
When starting out, make sure to use a fixed time step for your physics loop. You can synchronize your physics update with your graphics update later, this will get you up and running right away.
Code: Select all
void StartPhysics()
{
// Update the time step
NxReal deltaTime = 1.0f/60.0f; // Start collision and dynamics for delta time since the last frame
gScene->simulate(deltaTime);
gScene->flushStream();
}
Set up debug rendering immediately so you can visualize the PhysX objects you create. You will need to create a debug renderer object:
Code: Select all
class DebugRenderer
{
public:
void renderData(const NxDebugRenderable& data) const;
};
Code: Select all
void InitNx()
{
// Create the physics SDK
gPhysicsSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION);
if (!gPhysicsSDK) return;
. . .
// Set the debug visualization parameters
gPhysicsSDK->setParameter(NX_VISUALIZATION_SCALE, 1);
gPhysicsSDK->setParameter(NX_VISUALIZE_COLLISION_SHAPES, 1);
gPhysicsSDK->setParameter(NX_VISUALIZE_ACTOR_AXES, 1);
. . .
}
Code: Select all
void ProcessInputs()
{
// Put user callbacks and inputs here
// Show debug wireframes
if (bDebugWireframeMode)
{
if (gScene) gDebugRenderer.renderData(*gScene->getDebugRenderable());
}
}
The debug renderer object needs to be passed to the SDK in the ProcessInputs() function in between GetPhysicsResults() (NxScene::fetchResults()) and StartPhysics() (NxScene::simulate()).
Any other user callbacks or user inputs to the scene you need to do here, as input to the scene is locked out in the rest of the code.
Code: Select all
void RenderCallback()
{
GetPhysicsResults();
ProcessInputs();
StartPhysics();
}
void ProcessInputs()
{
// Put user callbacks and inputs here
// Show debug wireframes
if (bDebugWireframeMode)
{
if (gScene) gDebugRenderer.renderData(*gScene->getDebugRenderable());
}
}
One of the most common problems encountered by developers is the issue of scale. There are five parameters PhysX uses that have absolute scale: min separation for penalty, sleep linear velocity, bounce threshold, and visualization scale.
You will want to adjust these so they make sense within the scale of your game world. If your object scale is scale meters / PhysX unit, you will want to set these like this
Code: Select all
NxReal scale = 1.0f; // scale is meters per PhysX units
gPhysicsSDK->setParameter(NX_SKIN_WIDTH, 0.05*(1/ scale));
gPhysicsSDK->setParameter(NX_DEFAULT_SLEEP_LIN_VEL_SQUARED, 0.15*0.15*(1/ scale)*(1/ scale));
gPhysicsSDK->setParameter(NX_BOUNCE_THRESHOLD, -2*(1/ scale));
gPhysicsSDK->setParameter(NX_VISUALIZATION_SCALE, 0.5*(1/ scale));
You should now be able to see your objects via debug rendering. Now you want to use your own rendering routines to draw them. The following SetupCamera() and RenderActors() functions cycles through PhysX actors and renders their shapes using OpenGL. This example only renders sphere shapes.
Code: Select all
void RenderCallback()
{
…
// Render your physics objects
SetupCamera();
RenderActors();
}
float gCameraAspectRatio = 1.0f;
NxVec3 gCameraPos(0,5,-15);
NxVec3 gCameraForward(0,0,1);
void SetupCamera()
{
// Setup camera
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0f, gCameraAspectRatio, 1.0f, 10000.0f);
gluLookAt(gCameraPos.x,gCameraPos.y,gCameraPos.z,gCameraPos.x + gCameraForward.x, gCameraPos.y + gCameraForward.y, gCameraPos.z + gCameraForward.z, 0.0f, 1.0f, 0.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void RenderActors()
{
// Render all the actors in the scene
int nbActors = gScene->getNbActors();
NxActor** actors = gScene->getActors();
while (nbActors--)
{
NxActor* actor = *actors++;
DrawActor(actor);
}
}
void DrawActor(NxActor* actor)
{
NxShape** shapes = actor->getShapes();
NxU32 nShapes = actor->getNbShapes();
nShapes = actor->getNbShapes();
while (nShapes--)
{
DrawShape(shapes[nShapes]);
}
}
void DrawShape(NxShape* shape)
{
switch(shape->getType())
{
. . .
case NX_SHAPE_SPHERE:
DrawSphere(shape);
break;
. . .
}
}
int dispListSphere;
void InitShapeDisplayLists()
{
// SPHERE DISPLAY LIST
dispListSphere = glGenLists(1);
glNewList(dispListSphere, GL_COMPILE);
GLUquadricObj * quadObj = gluNewQuadric ();
gluQuadricDrawStyle (quadObj, GLU_FILL);
gluQuadricNormals (quadObj, GLU_SMOOTH);
gluQuadricOrientation(quadObj,GLU_OUTSIDE);
gluSphere (quadObj, 1.0f, 9, 7); //unit sphere
glEndList();
gluDeleteQuadric(quadObj);
}
void DrawSphere(NxShape *sphere)
{
NxMat34 pose = sphere->getGlobalPose();
glPushMatrix();
SetupGLMatrix(pose.t, pose.M);
NxReal r = sphere->isSphere()->getRadius();
glScaled(r,r,r);
glCallList(dispListSphere);
glPopMatrix();
}
void SetupGLMatrix(const NxVec3& pos, const NxMat33& orient)
{
float glmat[16]; //4x4 column major matrix for OpenGL.
orient.getColumnMajorStride4(&(glmat[0]));
pos.get(&(glmat[12]));
//clear the elements we don't need:
glmat[3] = glmat[7] = glmat[11] = 0.0f;
glmat[15] = 1.0f;
glMultMatrixf(&(glmat[0]));
}
8 Conclusion
This has been a Quick-Start guide to PhysX.
If you have any questions or comments about this guide, please click "Discuss Topic" to the right of this article.