PhysX3学习笔记2

时间:2022-02-26 05:39:28

今日由于选修了雷哥的物理学,所以不得不学有余力。好在现在为网路时代,共享心得的热心者有许多,所以学习起来总有参照

虽然资料并非全新,但是依旧免去了后辈的许多烦恼。


英文原文请戳我

本文参照 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,呼出属性界面

PhysX3学习笔记2

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;
如果遇到一些不明白的函数和类库可以参照下面的链接

NVIDIA PhysX API QAO

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的空框架。打开之后就能看见夜空(一片黑= =)

不要泄气PhysX3学习笔记2添加几何体的教程陆续会来的

我是妖哲,希望教程对你有所帮助。

源代码移步github