PhysX之旅(一)– NxBoxes的逐行分析

來源:互聯網
上載者:User
PhysX之旅(一)-- NxBoxes的逐行分析

學習新東西免不了走彎路,這個時候能得到指引的話,實在是很幸運的事情。所以我想說:能有SDK真是太好了!

NxBoxes是PhysX的第1個例子,對它進行逐行分析是很有必要的。當我們完完全全瞭解每一行代碼有什麼用的時候,我們也就入門了。

 

 #include <stdio.h>
#include <GL/glut.h>

#include "NxPhysics.h"
#pragma comment(lib, "C:/Program Files/NVIDIA Corporation/NVIDIA PhysX SDK/v2.8.1/SDKs/lib/Win32/PhysXLoader.lib")
#pragma comment(lib, "E:/work/test_bin/extern_library/lib/debug/freeglut.lib")

#define NOMINMAX
#include <windows.h>

//#include "ErrorStream.h"
#include <windows.h>
//#include "PerfRenderer.h"
//#include "Utilities.h"
//#include "SamplesVRDSettings.h"

// Physics
static NxPhysicsSDK* gPhysicsSDK = NULL;    // PhysX介面指標
static NxScene*    gScene = NULL;      // 情境指標
//static PerfRenderer   gPerfRenderer;
/*
渲染前統計用的類
 該類只有2個對外方法:
 bool toggleEnable(); // 顯示/隱藏切換
 void render(const NxProfileData* prof, int width, int height);

關於NxProfileData:
/brief Array of profiling data.
 效能資料數組。
 profileZones points to an array of numZones profile zones.  Zones are sorted such that the parent zones always come before their children. 
 Some zones have multiple parents (code called from multiple places) in which case only the relationship to the first parent is displayed.
 returned by NxScene::readProfileData().

關於ProfileZones
/brief Names for a number of profile zones that should always be available.  Can be used with NxProfileData::getNamedZone()

 <b>Platform:</b>
 /li PC SW: Yes
 /li PPU  : Yes
 /li PS3  : No
 /li XB360: No
enum NxProfileZoneName
 {
 NX_PZ_CLIENT_FRAME,  //!< Clock start is in client thread, just before scene thread was kicked off; clock end is when client calls fetchResults().
 NX_PZ_CPU_SIMULATE,  //!< Maximum time of simulation thread ((Nf)Scene::simulate(NxU32)), over all CPU scenes inside the NxScene.
 NX_PZ_PPU0_SIMULATE, //!< Maximum time of simulation thread over all PPU# scenes inside the NxScene.
 NX_PZ_PPU1_SIMULATE,
 NX_PZ_PPU2_SIMULATE,
 NX_PZ_PPU3_SIMULATE,
 NX_PZ_TOTAL_SIMULATION = 0x10, //!< Clock start is in client thread, just before scene thread was kicked off; clock end is in simulation thread when it finishes.
 };
*/
// Rendering
static NxVec3 gEye(50.0f, 50.0f, 50.0f); // 攝象機位置
static NxVec3 gDir(-0.6f,-0.2f,-0.7f);  // 攝象機方向
static NxVec3 gViewY;           // 攝象機“左平移”的方向
static int  gMouseX = 0;        // 滑鼠當前X座標(abs)
static int  gMouseY = 0;        // 滑鼠當前Y座標(abs)

static bool InitNx() // 該函數負責初始化PhysX
{
 // Initialize PhysicsSDK
 NxPhysicsSDKDesc desc; // 裝置描述符,主要用來指定硬體和情境之間“對資料的共用程度”?
 NxSDKCreateError errorCode = NXCE_NO_ERROR; // 調用NxCreatePhysicsSDK()返回的錯誤資訊
 /*
enum NxSDKCreateError
 {
 NXCE_NO_ERROR       = 0, // 沒錯誤
 NXCE_PHYSX_NOT_FOUND   = 1, // 找不到PhysX庫,未安裝PhysX驅動
 NXCE_WRONG_VERSION    = 2, // SDK版本和Driver版本不匹配
 NXCE_DESCRIPTOR_INVALID  = 3, // 無效的描述符
 NXCE_CONNECTION_ERROR   = 4, // 與裝置通訊出現故障。
 NXCE_RESET_ERROR     = 5, // 未重設(初始化)的裝置
 NXCE_IN_USE_ERROR     = 6, // 裝置正在被其他程式使用
 NXCE_BUNDLE_ERROR     = 7  // 恭喜,你的物理加速卡壞了
 };
*/
 gPhysicsSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION, NULL, /*new ErrorStream()*/NULL, desc, &errorCode); // 建立介面指標。
 if(gPhysicsSDK == NULL) // 如果出錯了,列印出錯誤資訊
 {
  //printf("/nSDK create error (%d - %s)./nUnable to initialize the PhysX SDK, exiting the sample./n/n", errorCode, getNxSDKCreateError(errorCode));
  return false;
 }
 // 可視化遠端偵錯工具的設定...從來沒玩過...
//#if SAMPLES_USE_VRD
// // 設定Visual Remote Debugger的IP和port。(在SampleCommonCode/SamplesVRDSettings.h檔案中定義)
// if (gPhysicsSDK->getFoundationSDK().getRemoteDebugger())
//  gPhysicsSDK->getFoundationSDK().getRemoteDebugger()->connect(SAMPLES_VRD_HOST, SAMPLES_VRD_PORT, SAMPLES_VRD_EVENTMASK);
//#endif

 // 設定變數,皮膚厚度為0.05,實際結果就是角色的碰撞幾何體被縮小了0.05。
 gPhysicsSDK->setParameter(NX_SKIN_WIDTH, 0.05f);

 // Create a scene
 NxSceneDesc sceneDesc; // 聲明一個情境描述符
 sceneDesc.gravity    = NxVec3(0.0f, -9.81f, 0.0f); // 設定重力加速度
 gScene = gPhysicsSDK->createScene(sceneDesc);     // 使用剛才的情境描述符來建立情境
 if(gScene == NULL)                  // 錯誤處理
 {
  printf("/nError: Unable to create a PhysX scene, exiting the sample./n/n");
  return false;
 }

 // Set default material // 設定材質
 // 總是存在一個預設材質(index = 0),該材質也不能被釋放,調用releaseMaterial(defaultMaterial)將沒有任何效果
 NxMaterial* defaultMaterial = gScene->getMaterialFromIndex(0);
 defaultMaterial->setRestitution(0.0f);    // 設定還原係數
 defaultMaterial->setStaticFriction(0.5f);   // 設定靜摩擦係數
 defaultMaterial->setDynamicFriction(0.5f);  // 設定動摩擦係數

 // Create ground plane // 建立一個片,作為地板
 NxPlaneShapeDesc planeDesc;       // 很明顯,片描述符
 NxActorDesc actorDesc;         // 角色描述符
 actorDesc.shapes.pushBack(&planeDesc); // 將片描述符添加到角色描述符中
 gScene->createActor(actorDesc);     // 建立角色

 return true;
}

// 該函數做清理工作
static void ExitNx()
{
 if(gPhysicsSDK != NULL)
 {
  if(gScene != NULL) gPhysicsSDK->releaseScene(*gScene); // 釋放情境
  gScene = NULL;
  NxReleasePhysicsSDK(gPhysicsSDK);            // 釋放PhysX
  gPhysicsSDK = NULL;
 }
}

// 建立一個cube
static void CreateCube(const NxVec3& pos, int size=2, const NxVec3* initialVelocity=NULL)
{
 if(gScene == NULL) return;

 // Create body // 建立剛體
 NxBodyDesc bodyDesc;                       // 剛體描述符
 bodyDesc.angularDamping = 0.5f;                  // 旋轉衰減
 if(initialVelocity) bodyDesc.linearVelocity = *initialVelocity;  // (沿著某個方向的)速度

 NxBoxShapeDesc boxDesc;                        // 盒子描述符
 boxDesc.dimensions = NxVec3((float)size, (float)size, (float)size);  // 設定盒子的體積

 NxActorDesc actorDesc;        // 角色描述符
 actorDesc.shapes.pushBack(&boxDesc); // 將盒子描述符添加到角色描述符中
 actorDesc.body   = &bodyDesc;   // 設定剛體描述符
 actorDesc.density  = 10.0f;     // 設定密度
 actorDesc.globalPose.t  = pos;    // 設定物體當前座標(全局座標系)
 gScene->createActor(actorDesc)->userData = (void*)size_t(size); // 建立角色
 //printf("Total: %d actors/n", gScene->getNbActors());
}

// 建立大方塊
static void CreateCubeFromEye(int size)
{
 NxVec3 t = gEye;  // 點
 NxVec3 vel = gDir; // 方向
 vel.normalize();  // 歸一化
 vel*=200.0f;    // 該方向上的速度(200個單位向量)
 CreateCube(t, size, &vel); // 建立方塊
}

// 建立金字塔
static void CreateStack(int size)
{
 const float cubeSize = 2.0f;
 const float spacing = -2.0f*gPhysicsSDK->getParameter(NX_SKIN_WIDTH); // 縮放產生的尺寸減少的值。
 // 只要知道“皮膚厚度”代表的意義之後,以下的代碼不過是為了讓這些方塊緊密排列的演算法而已。
 NxVec3 pos(0.0f, cubeSize, 0.0f);
 float offset = -size * (cubeSize * 2.0f + spacing) * 0.5f;
 while(size)
 {
  for(int i=0;i<size;i++)
  {
   pos.x = offset + (float)i * (cubeSize * 2.0f + spacing);
   CreateCube(pos, (int)cubeSize);
  }

  offset += cubeSize;
  pos.y += (cubeSize * 2.0f + spacing);
  size--;
 }
}

// 建立棍子
static void CreateTower(int size)
{
 const float cubeSize = 2.0f;
 const float spacing = 0.01f;
 NxVec3 pos(0.0f, cubeSize, 0.0f);
 while(size)
 {
  CreateCube(pos, (int)cubeSize);
  pos.y += (cubeSize * 2.0f + spacing);
  size--;
 }
}

// 鍵盤迴調函數
static void KeyboardCallback(unsigned char key, int x, int y)
{
 switch(key)
 {
  case 27: // ESC的ASCII碼為27
   exit(0);
   break;
  case '0': 
   //gPerfRenderer.toggleEnable();
   break;
  case ' ': 
   CreateCube(NxVec3(0.0f, 20.0f, 0.0f),1); // 在 (0,20,0)的位置建立 大小為1,速度為0的方塊
   break;
  case 's':
  case 'S':
   CreateStack(10);
   break;
  case 'b': 
  case 'B': 
   CreateStack(30);
   break;
  case 't':
  case 'T':
   CreateTower(30);
   break;
  case 'w':
  case 'W':
   CreateCubeFromEye(8);
   break;
  case 'q':
  case 'Q':
   {
    NxActor** actors = gScene->getActors();
    if(gScene->getNbActors() > 1){
     gScene->releaseActor(*actors[gScene->getNbActors()-1]);
    }
   }
   break;  
  case GLUT_KEY_UP: case '8': gEye += gDir*2.0f; break;
  case GLUT_KEY_DOWN: case '2': gEye -= gDir*2.0f; break;
  case GLUT_KEY_LEFT: case '4': gEye -= gViewY*2.0f; break;
  case GLUT_KEY_RIGHT: case '6': gEye += gViewY*2.0f; break;
 }
}

// 鍵盤迴調函數
static void ArrowKeyCallback(int key, int x, int y)
{
 KeyboardCallback(key,x,y);
}

// 滑鼠回呼函數
static void MouseCallback(int button, int state, int x, int y)
{
 gMouseX = x;
 gMouseY = y;
}

// 運動回呼函數?
static void MotionCallback(int x, int y)
{
 int dx = gMouseX - x;
 int dy = gMouseY - y;
 
 gDir.normalize();
 gViewY.cross(gDir, NxVec3(0,1,0));

 NxQuat qx(NxPiF32 * dx * 20/ 180.0f, NxVec3(0,1,0));
 qx.rotate(gDir);
 NxQuat qy(NxPiF32 * dy * 20/ 180.0f, gViewY);
 qy.rotate(gDir);

 gMouseX = x;
 gMouseY = y;
}

// 渲染回呼函數
// 當把上一貞的結果提交到渲染隊列進行渲染的時候,CPU就空閑了,這個時候再
static void RenderCallback()
{
 static DWORD elapsedTime = 0;

 if(gScene == NULL) return;
 
 // Start simulation (non blocking)
 if( elapsedTime!= 0 )
 {
  elapsedTime = ::GetTickCount() - elapsedTime;
 }
 gScene->simulate( elapsedTime *0.001f ); // 進行類比,所有的物理相關的計算都由該函數處理了。

#pragma region OpenGL相關
 // Clear buffers
 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

 // Setup projection matrix
 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();
 gluPerspective(60.0f, (float)glutGet(GLUT_WINDOW_WIDTH)/(float)glutGet(GLUT_WINDOW_HEIGHT), 1.0f, 10000.0f);
 gluLookAt(gEye.x, gEye.y, gEye.z, gEye.x + gDir.x, gEye.y + gDir.y, gEye.z + gDir.z, 0.0f, 1.0f, 0.0f);

 // Setup modelview matrix
 glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();

 // Render all actors
 int nbActors = gScene->getNbActors();   // 獲得角色總數
 NxActor** actors = gScene->getActors();  // 獲得角色隊列指標
 while(nbActors--)             // 不渲染地板,因為可以從代碼的編寫上來保證第1個一定是地板,所以這裡不做檢測
 {
  NxActor* actor = *actors++;       // 做迭代
  if(!actor->userData) continue;     // 如果角色的“使用者自訂資料”指標非空,也不渲染它

  // 渲染角色
  // Render actor
  glPushMatrix();
  float glMat[16];
  actor->getGlobalPose().getColumnMajor44(glMat);
  glMultMatrixf(glMat);
  glColor4f(1.0f, 1.0f, 1.0f, 1.0f);         // 設定顏色
  glutSolidCube(float(size_t(actor->userData))*2.0f); // 進行渲染
  glPopMatrix();

  // Render shadow
  glPushMatrix();
  const static float shadowMat[]={ 1,0,0,0, 0,0,0,0, 0,0,1,0, 0,0,0,1 };
  glMultMatrixf(shadowMat);
  glMultMatrixf(glMat);
  glDisable(GL_LIGHTING);
  glColor4f(0.1f, 0.2f, 0.3f, 1.0f);
  glutSolidCube(float(size_t(actor->userData))*2.0f);
  glEnable(GL_LIGHTING);
  glPopMatrix();
 }
#pragma endregion OpenGL相關

 // Fetch simulation results
 gScene->flushStream();
 gScene->fetchResults(NX_RIGID_BODY_FINISHED, true);
 elapsedTime = ::GetTickCount();
 
 // Print profile results (if enabled)
 //gPerfRenderer.render(gScene->readProfileData(true), glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT));

 glutSwapBuffers();
}

static void ReshapeCallback(int width, int height)
{
 glViewport(0, 0, width, height);
}

static void IdleCallback()
{
 glutPostRedisplay();
}

int main(int argc, char** argv)
{
 // Initialize glut
 printf("Use the arrow keys or 2, 4, 6 and 8 to move the camera./n");
 printf("Use the mouse to rotate the camera./n");
 printf("Press the keys w, t, s, b and space to create various things./n");
 printf("Press q to destroy the last thing created./n");
 printf("Press 0 to toggle the frame rate display./n");
 glutInit(&argc, argv);
 glutInitWindowSize(512, 512);
 glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH);
 int mainHandle = glutCreateWindow("SampleBoxes");
 glutSetWindow(mainHandle);
 glutDisplayFunc(RenderCallback);
 glutReshapeFunc(ReshapeCallback);
 glutIdleFunc(IdleCallback);
 glutKeyboardFunc(KeyboardCallback);
 glutSpecialFunc(ArrowKeyCallback);
 glutMouseFunc(MouseCallback);
 glutMotionFunc(MotionCallback);
 MotionCallback(0,0);
 atexit(ExitNx);

 // Setup default render states
 glClearColor(0.3f, 0.4f, 0.5f, 1.0);
 glEnable(GL_DEPTH_TEST);
 glEnable(GL_COLOR_MATERIAL);

 // Setup lighting
 glEnable(GL_LIGHTING);
 float ambientColor[] = { 0.0f, 0.1f, 0.2f, 0.0f };
 float diffuseColor[] = { 1.0f, 1.0f, 1.0f, 0.0f };  
 float specularColor[] = { 0.0f, 0.0f, 0.0f, 0.0f };  
 float position[]  = { 100.0f, 100.0f, 400.0f, 1.0f };  
 glLightfv(GL_LIGHT0, GL_AMBIENT, ambientColor);
 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseColor);
 glLightfv(GL_LIGHT0, GL_SPECULAR, specularColor);
 glLightfv(GL_LIGHT0, GL_POSITION, position);
 glEnable(GL_LIGHT0);

 // Initialize physics scene and start the application main loop if scene was created
 if (InitNx())
  glutMainLoop();

 return 0;
}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.