今日由于选修了雷哥的物理学,所以不得不学有余力。好在现在为网路时代,共享心得的热心者有许多,所以学习起来总有参照
虽然资料并非全新,但是依旧免去了后辈的许多烦恼。
本文参照 Tasos Papazoglou Chalikias于2013,2,24发表的Getting started on PhysX3.2.1&OpenGL一文。
PhysX,nVidia的一款物理引擎,被应用在多款游戏中,UDK(虚幻引擎)便采用了其解决方案。鉴于之后从事游戏制作会与
UnReal打交道,那么部署服务器的时候势必会使用到PhysX。在这里选用physx物理引擎+openGL可视化渲染的方案。
注:下文将创建一个空的PhysX sample。
1.下载PhysX SDK(截止目前官方最新为3.3.2)
2.新建一个Visual C++的新工程,按下Alt+F7,呼出属性界面
3.配置SDK与工程的路径连接
修改可执行目录(binary),包含目录(Include),库目录(Lib),源目录(Src)
$(SDK_Path)Bin\win32;$(ExecutablePath) <pre name="code" class="plain">$(SDK_Path)Include;$(IncludePath) <pre name="code" class="plain">$(SDK_Path)Lib\win32;$(LibraryPath) <pre name="code" class="plain">$(SDK_Path)Source;$(SourcePath)4.由于需要使用到OpenGL,所以要下载glut等常用工具。 glut等配置在隔壁放映室
5.俗话说的好,磨刀不误砍柴工,在正式敲击代码之前,我们尚需申明一下我们的类库。
#include <stdio.h> #include <iostream> #include <vector> #include <GL\glut.h> #include <PxPhysicsAPI.h> #include <extensions\PxExtensionsAPI.h> #include <extensions\PxDefaultErrorCallback.h> #include <extensions\PxDefaultAllocator.h> #include <extensions\PxDefaultSimulationFilterShader.h> #include <extensions\PxDefaultCpuDispatcher.h> #include <extensions\PxShapeExt.h> #include <extensions\PxSimpleFactory.h> #include <foundation\PxFoundation.h> #pragma comment(lib, "PhysX3_x86.lib") #pragma comment(lib, "PhysX3Common_x86.lib") #pragma comment(lib, "PhysX3Extensions.lib") #pragma comment(lib, "PxTask.lib") using namespace physx; using namespace std;如果遇到一些不明白的函数和类库可以参照下面的链接
7.接下来就是正式的coding阶段
我们先需要一些全局变量
int start_time = 0,total_frames = 0; float fps =0; const int WINDOW_WIDTH = 800,WINDOW_HEIGHT =600; PxScene *gloable_scene = NULL; PxReal myTimestep = 1.0/60.0f;
开始时间,总帧数和fps用于计算fps帧数。
窗口宽高
timestep设置了迭代时间
有了这些变量我们就能够开始初始化PhysX了
void InitPx() { PxFoundation *foundation = PxCreateFoundation(PX_PHYSICS_VERSION,gAllocator,gErrorcallback); PxDirector = PxCreatePhysics(PX_PHYSICS_VERSION,*foudation,PxTolerancesScale() ); PxInitExtensions(*PxDirector); //创建场景 PxSceneDesc sceneDesc(PxDirector->getToleranceScale()); sceneDesc.gravity = PxVec(0.0f,-9.8f,0.0f); if(!sceneDesc.cpuDispatcher) { PxDefaultCpuDispatcher *mCpuDispatcher = PxDefaultCpuDispatcherCreate(1); sceneDesc.cpuDispatcher = mCpuDispatcher; } if(sceneDesc.filterShader) { sceneDesc.filterShader = gFilterShader; } gScene = PxDirector->createScene(sceneDesc); }每一个Px模块都需要一个可用的基础(PxFoundation实例)。
需要的参数是 版本ID (PX_PHYSICS_VERSION),一个分配回调(gAllocator),一个错误回调(gErrorcallback),这两个参数需要你自己预先创建。
然后我们创建一个*的PxPhysic对象(PxDirector),需要版本ID,基础对象,以及一个PxToleranceScale()函数。
PxTolerance参数使得在不同尺寸创作内容的时候更加便捷,并且PhysX依旧像预期的效果一样。
但是为了快速开始我们传入了这个类型的默认对象。你也可以设置一个参数 recordMemoryAllocations 来开启内存性能分析。
同样的,设置mProfileZoneManager 参数可以开启PhysX可视化调试器性能分析。PhysX Visual Debugger下载
接下来,我们初始化扩展库。它包含了许多对使用者有用的函数,但是一些使用者可能更乐意在他们的应用中
忽略掉代码大小的原因或者避免使用某些子系统,例如和网络相关的。初始化扩展库需要有PxPhysics对象。
现在创建这个场景。PxScene对象是物理世界中具现化对象。创建场景需要在PxSceneDesc中指定一系列的不变 的参数。
我们先获取toleranceScale并且可以设定场景的性质。在示例代码中,我们设定了scene的重力场,一个Vec3。
之后我们创建了一个cpuDispatcher。Cpu调度员是SDK用来连接程序线程池的抽象类。一般般来说,一整个应用会有一个CpuDispatcher,除非这儿的确需要更多的线程池。在括号里的数值设定了使用CPU线程的数量(代码中为1)。如果你想包括CUDA的话,你也可以建立一个GPU调度员。
CUDA(compute unified devicearchitecture)是NVIDIA推出的通用运行计算架构。传送门
同样我们需要创建滤波着色器。
准备齐全所有的东西之后就可以根据场景描述来建立场景了(当然你得用*对象PxDirector去调用)
Ps:
不知道怎么写代码的看这里,是需要你自己预先创建的几个值。
static PxPhysics* PxDirector = NULL; static PxDefaultErrorCallback gErrorcallback; static PxDefaultAllocator gAllocator; static PxSimulationFilterShader gFilterShader = PxDefaultSimulationFilterShader;
其他的一些功能函数
我们需要一些函数来管理时间迭代和PhysX的注销。
void StepPx() { gScene->simulate(myTimeStep); while(!gScene->fetchResults()) { //做一些你想做的事情嘿嘿 } } void onRender() { total_frames++; int current = glutGet(GLUT_ELAPSED_TIME); if((current-start_time)>1000) { float elapsedTime =current-start_time; fps = ((tot *1000.0f)/elapsedTime); start_time =current; total_frames =0; } if(gScene) { StepPx(); } glClearColor(0.1,0.1,0.1); glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glSwapBuffers(); } void Idle() { glutPostRedisplay(); } void onShutdown() { gScene->release(); PxDirector->relea(); }stepPx用simulate()设置了场景时间,simulate通过预定义的时间间隔(也就是我们的myTimeStep)来移动场景中的所有物体。
这可能是众多处理仿真进行时间办法中最简单的一个。
onRender函数计算了帧率,并且调用了stepPx,当然调用了glut清除buffers。
onShutDown 中我们调用了每一个Px物体的release函数,这会销毁这些对象,以及他们的子对象。
为了完全地注销physics,我们还调用了*PxPhysics对象的release函数,这将把所有的物理对象清除。最后我们也消除了foundation对象,当然这得在其他所有PhysX模组释放之后。
ps:这里需要注意,销毁函数要严格按照顺序,可以尝试一下,如果在场景之前预先调用了PxPhysics对象PxDirector的销毁函数,
在其他模组销毁之前将foundation销毁,会导致访问出错,不信你试一下不咯?
Main函数
void main(int argc,char **argv) { atexit(onShutdown); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(WINDOW_WIDTH,WINDOW_HEIGHT); glutCreateWindow("PxTest"); glutDisplayFunc(onRender); glutIdleFunc(Idle); InitPx(); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glutMainLoop(); }喜闻乐见的计算机图形学必备技巧,openGL基础代码。
最后不要忘记把PhysX3_x86.dll和P3Common_x86.dll复制到你的 PxTest.vcxproj路径下,不然你会打不开的。虽然你可以丢在System32里面=-=但是我还是建议扔到解决方案路径下........
好了,以上就是一个PhysX的空框架。打开之后就能看见夜空(一片黑= =)
不要泄气添加几何体的教程陆续会来的
我是妖哲,希望教程对你有所帮助。