Lesson 101 – Primary Shape Introduction This is the first lesson in the Rigid Body chapter of the PhysX SDK. 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. Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 1 1 Initializing the SDK and Creating a Scene In each of the lessons, you need to create an instance of the PhysX SDK to build your simulation. This is done in the function InitNx(). The following block of code is all you need to initialize the PhysX SDK and create a 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(); } From main(), we call InitNx(). InitNx() makes an instance of the physics SDK, gPhysicsSDK, and creates a scene, gScene. This is probably the simplest PhysX application possible. This will compile and run. 2 Setting Parameters for the SDK Now we add parameters to the SDK to flesh out our simulation. // Set the physics parameters gPhysicsSDK->setParameter(NX_SKIN_WIDTH, 0.01); The first parameter is a global physics parameter used by the SDK called skin width. It is an important parameter, basically a “grace-depth” the SDK allows objects to penetrate each other by. For now, we are setting it manually to 0.01 (an absolute depth of 0.01m or 1cm). If we don’t add this line, it will default to 0.025 (0.025m or 2.5cm). Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 2 // 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); 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. 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. // Create the scene NxSceneDesc sceneDesc; sceneDesc.gravity sceneDesc.simType = gDefaultGravity; = NX_SIMULATION_SW; gScene = gPhysicsSDK->createScene(sceneDesc); We start out with a scene descriptor which we feed to the SDK to create our scene. Descriptors are widely used throughout the 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 . 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). Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 3 5 Creating the Actors in the Scene At the end of InitNx(), we add our actors, the box and the plane, to the scene. // 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(); ... } Look at the function 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 Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 4 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. 7 Creating the Box We now create our box. It is a single actor consisting of a single shape. void InitNx() { ... box = CreateBox(); ... } The CreateBox() function is as follows. NxActor* CreateBox() { // Set the box starting height to 3.5m so box starts off falling onto the ground 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 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; Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 5 } 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. 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. 8 Initializing the 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. // HUD globals 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. 9 Updating the Time Next we call UpdateTime(). Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 6 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. 10 Starting the First Frame of the Simulation Finally, we call StartPhysics() to start the first frame of the simulation. Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 7 void InitNx() { ... // Start the first frame of the simulation 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(). 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(). void RenderCallback() { ... if (gScene && !bPause) { GetPhysicsResults(); Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 8 ProcessInputs(); StartPhysics(); } … } … void GetPhysicsResults() { // Get results from gScene->simulate(deltaTime) 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: 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. 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 ... } } Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 9 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. 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. 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)) { Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 10 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. // Force globals NxVec3 gForceVec(0,0,0); NxReal gForceStrength = 20000; bool bForceMode = true; … // Keyboard globals #define MAX_KEYS 256 bool gKeys[MAX_KEYS]; … 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; } … } } } ... void ProcessInputs() { ProcessForceKeys(); ... } Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 11 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 zaxis. 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; } … } } } Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 12 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) { ... } Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 13 // 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 Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 14 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 zaxis, 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() { … Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 15 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(); … Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 16 } ... 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) { Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 17 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: 1. 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(). 2. GetPhysicsResults() Calls NxScene::fetchResults() to retrieve the results of the last frame of simulation. Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 18 3. ProcessInputs() Gets keyboard input from ProcessForceKeys(). Calls NxDebugRenderer::renderData() to draw debug wireframes on the actors. 4. 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. 5. 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(). 6. gDebugRenderer.renderData() Renders wireframes to visualize debug wireframes on the actors such as collision shapes and actor axes. 7. 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 Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 19 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 Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 20 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 Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 21 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’ Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 22 localPose X’ globalPose X World Coordinate System Copyright (c) 2008 NVIDIA Corporation. All rights reserved. http://www.NVIDIA.com 23