开始功能是所有例子的共同点,分享在SampleBase工程里。打开PhysXSample.cpp文件并导航到onInit函数,在这里初始化了PhysX.
这一例子用一个头文件包含了整个PhysX API。你也可以有选择性的只囊括一些你需要的头文件。但PxPhysicsAPI.h包含了所有,可以帮助你更快的开始:
#include "PxPhysicsAPI.h"
首先,创建一个PxFoundation 物体:
static PxDefaultErrorCallback gDefaultErrorCallback;
static PxDefaultAllocator gDefaultAllocatorCallback;
mFoundation = PxCreateFoundation(PX_PHYSICS_VERSION, gDefaultAllocatorCallback, gDefaultErrorCallback);
if(!mFoundation)
fatalError("PxCreateFoundation failed!");
创建每一个physX模块都需要一个PxFoundation实例。需要的参数包括版本号,分配回调和错误回调。PX_PHYSICS_VERSION参数是一个宏定义,用来检测头文件和相应的SDKdll的版本不匹配。通常,分配回调和错误回调的定义都是固定的,但physX提供了默认了的定义,这也使得开始搭建变得非常容易:
1、在16字节对齐的平台中或是有分配器对齐的特定平台代码,默认的分配器简化为malloc() and free()两个函数。
2、默认的错误流输出错误信息。这条信息会伴随着错误代码PxErrorCode::eABORT信号(一个不可恢复的错误),默认的定义将会循环,并且每一秒都会输出信息。
更多关于分配器和错误回调的信息可以在The PhysX API中查询。样本代码支持先进的内存分配器,这一分配器用轨道分配器代替默认的,但我们在这儿忽略了很多细节。
一个可选的管理器可以开启PhysX可视化调试器(更多信息可查看ProfileZoneManager and ProfileZone章节)。(据说是用来做性能分析的)
mProfileZoneManager = &PxProfileZoneManager::createProfileZoneManager(mFoundation);
if(!mProfileZoneManager)
fatalError("PxProfileZoneManager::createProfileZoneManager failed!");
现在让我们来创建最高级别的物理体:
bool recordMemoryAllocations = true;
mPhysics = PxCreatePhysics(PX_PHYSICS_VERSION, *mFoundation,
PxTolerancesScale(), recordMemoryAllocations, mProfileZoneManager );
if(!mPhysics)
fatalError("PxCreatePhysics failed!");
又一次用到了版本号PxTolerancesScale这一参数。使得在不同尺度下修改内容变得容易,而且也简化了这一类型的默认物体。recordMemoryAllocations这一参数具体到是否执行内存分析。
Cooking库
PhysX cooking库提供了一些可用来创建、转换和序列化大量数据的方法。开发工程时,你可能希望通过链接cooking库在运行时处理这样的数据。另外,你也可以提前处理这些数据以便在需要的时候将其加载到内存。初始化cooking库的方法如下:
mCooking = PxCreateCooking(PX_PHYSICS_VERSION, *mFoundation, PxCookingParams());
if (!mCooking)
fatalError("PxCreateCooking failed!");
通过配置不同的PxCookingParams参数以针对不同的平台,也可使用非默认的容忍量或是创建可选择的输出。
cooking库通过一个流接口产生数据。在实例程序中,流的定义在PxToolkit库中,从文件或是内存中读写。
extensions库
extensions库包含了许多方法,也许对一大类用户非常有用,但对于某些用户他们忽略这一类库,可能由于代码大小原因、或是避免使用特定的子系统,例如那些涉及网路的部分。初始化extensions库需要有物理体:
if (!PxInitExtensions(*mPhysics))
fatalError("PxInitExtensions failed!");
可选的SDK组件
把PhysX作为静态库链接到内存受约束的平台时,尽可能的避免链接一些不常用的PhysX features来节约内存。通常可选的features包括:
- 关节
- 高度域
- 统一高度域
- 布料
- 粒子
如果你的工程需要用到这些功能中的某个,推荐使用PxCreateBasePhysics代替PxCreatePhysics,接下来就可以手工注册你所需要的组件。下面这个例子注册了除统一高度域之外的所有可选项。
physx::PxPhysics* customCreatePhysics(physx::PxU32 version,
physx::PxFoundation& foundation,
const physx::PxTolerancesScale& scale,
bool trackOutstandingAllocations,
physx::PxProfileZoneManager* profileZoneManager)
{
physx::PxPhysics* physics = PxCreateBasePhysics(version, foundation, scale,
trackOutstandingAllocations, profileZoneManager);
if(!physics)
return NULL;
PxRegisterArticulations(*physics);
PxRegisterHeightFields(*physics);
return physics;
}
在3.3版本中,我们引入了支持统一高度场的碰撞检测。这一方法共享了介于蒙面和高度场之间的碰撞检测代码,例如作为蒙面创造的等效地形的高度场,这个方法促进了应用程序中蒙面和高度场的混合使用。在两种方法中的碰撞行为没有明显差异。为了启用这种方法,你必须用动态注册的方式予以证明:
PxRegisterUnifiedHeightFields(*physics);
应该执行这种动态注册而不是引起:
PxRegisterHeightFields(*physics);
当我们依赖链接器剔除无用代码后,可以把PhysX作为静态库动态注册仅可以节省内存。
关闭
为了处理任何PhysX物体,可以调用它的release()方法。这将销毁这一物体,以及所涵盖的所有物体。这一精确的行为依附于被释放的物体,也涉及到相关的细节指导。为了关闭整个物理系统,可以在物理体上简单地调用release()方法,这将清除所有的物理体:
mPhysics->release();
也不要忘记释放foundation物体,但这要在所有物理体均被释放之后执行:
mFoundation->release();
Windows延迟加载
PhysX.dll和PhysXCooking.dll在PhysXCommondll的基础上使用了延迟加载标签。PhysX.dll和PhysXCooking.dll能够让用户同时延时加载。如果需要加载一个PhysXCommon.dll 有不同的文件名而不是使用默认的,很可能使用PxDelayLoadHook回调指定一个名字。
class SampleDelayLoadHook: public PxDelayLoadHook
{
virtual const char* getPhysXCommonDEBUGDllName() const { return "PhysX3CommonDEBUG_x64_Test.dll"; }
virtual const char* getPhysXCommonCHECKEDDllName() const { return "PhysX3CommonCHECKED_x64_Test.dll"; }
virtual const char* getPhysXCommonPROFILEDllName() const { return "PhysX3CommonPROFILE_x64_Test.dll"; }
virtual const char* getPhysXCommonDllName() const { return "PhysX3Common_x64_Test.dll"; }
} gDelayLoadHook;
// Now the hook must be set for PhysX and PhysXCooking.
PxSetPhysXCookingDelayLoadHook(&gDelayLoadHook);
PxSetPhysXDelayLoadHook(&gDelayLoadHook);
// PhysX3Common..._x64_Test.dll can be now loaded and used by the application