AGEIA PhysX SDK 是一个实体动力学模拟与碰撞检测的开发包,可以简单的应用到工程当中。
实体动力学组件可以使你模拟现实的物体运动。用物理观念例如骨架,位置,速率,加速度,冲量,力,旋转运动,能量,摩擦,脉冲,碰撞,限制 等等,该引擎给你一个组件包,使用它可以创建各种类型的机械的设备。
这个文档将覆盖 所有的 特征和用法,学术上的挑战自然的问题 ,假装你有物理学的知识。如果没有建议你需要一本好书来扩充你的物理学知识之后继续学习。
需要下载SDK在官网。
这个SDK用标准C++的接口。本地SDK 是一个层级类结构。每一个类包含函数都可以被调用者通过接口使用。这个接口是典型的c++虚类,另外有一些其他形式的函数出口可以使用。
编码规范:
每一个接口的类定义了设置了方法。下面是代码规范表:
·所有的类定义都在 头文件。
·类的开头大写。
·接口类(所有用户可用)标题头上有“Nx”。
·方法和变量开始使用小写开头。
·参数可接受的,使用了*语法,成功后之后返回指针。
·参数不可接受,可以会产生错误使系统崩溃。
·用功能会返回功能函数
数据类型:
为了提供方便的调用规则,SDK定义了特殊的类型,定义在 /NxSimpleTypes.h.中。
SDK的类NxVec3, NxMat33, NxMat34, 和 NxQuat 代表3-vector, 3x3 matrix, 3x4 matrix, 四元数。他们是一般用来配置使用单精度浮点数点量。这些类型用户可以使用并且在SDK中找到。
数学类也提供非常多的选择类型和格式和变换方法。这些方法将使用inline进行编译,你可能添加你自己的符号自定义给这些类,除非你想重新编译SDK给你的数学类。
单元:
SDK不需要使用一些特殊的现实物体单元。然而,把物体放到渲染管线,定义这些这是很重要的。SDK使用单元数去测量三种类型的基本数,质量,长度,和时间。你可以定义这些数量给很多单元只要你希望这样做。单元量的表示根据各自的基本单元。例如。速率总是距离除以时间,所以在我们的事件里这就是长度除以表。(作者注:很好理解 长度就是距离,时间就是秒)。其他例如取得单元的力,脉冲。。。
SDK使用单精度浮点为默认,这是很重要的保持物体一系类相对的属性保持高精度。
数学函数包括NxMath, NxVec3, NxQuat, NxMat33, NxMat34, and some floating point unit control functions and macros 在 NxFPU.h 中定义。
NxMath类包含了很多标准c中的函数 如sin fabs 还有很多的常量 如:PI
NxVec3是一个3单元的向量。NxMat33是3乘3的矩阵。
NxQuat是一个四元数,用于快速旋转。(大名鼎鼎的四元数旋转)
NxMat34是用于转换的,如物体的平移和旋转。
线性变化可以像 H = [R, t],这里的R是一个旋转矩阵,t是一个向量。
把p变成p'可以这样表示。
p’ = H p = R p + t
两个变换 A= [aR at] and B = [bR bt]如下:
A B = [aR bR aR bt + at]
矩阵的元素存储对用户来说是透明的,但是也许会收回使用 get方法获得,如果你需要。左右手原则sdk不关心,尽管坐标是右手的,简单的方式是发送矩阵给openGL
NxMat34 m;//PhysX matrix
float glmat[16];//OpenGL matrix
m.getColumnMajor44(glmat);//copy to glmat
glMultMatrixf(glmat);//send to OpenGL
SDK定义了设置了形状类提供了简单的函数。
NxBounds3 - Axis Aligned Bounding Box (AABB)
NxBox - Oriented Bounding Box (OBB)
NxCapsule - Capsule (Line segment with a distance)
NxPlane - Parametric Plane
NxRay - Infinite Ray/Line
NxSegment - Finite Ray/Line (i.e., has two end points)
NxSphere - Sphere, Point, and Radius
一切都从一个简单的Dome开始,他存放在/SampleBoxes/src/NxBoxes.cpp.
使用SDK需要 包含 用户相关的资源文件头。
#include "NxPhysics.h"
如果你的程序用户需要使用windows.h包换到你的sdk,你必须定义一个宏min和max,下面是一个通用的c++方式在SDK。
#define NOMINMAX
#include <windows.h>
开始SDK跟着声明:
gPhysicsSDK=NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION,
&myAllocator,
&myOutputStream);
if(!gPhysicsSDK)Error("Wrong SDK DLL version?");
第一个参数就是版本号在SDK头文件中定义,这个关系到你将使用的版本类的dll包含。如果错误会返回NULL。
第二个参数是取空间给object,错误会返回NULL。
的三个参数是输出流物体。
现在成功,你已经获取一个接口指针。
如果你完成了SDK的使用 需要释放他。
gPhysicsSDK->release();
不仅可以有一个实体接口,当然使用一个要释放一次(用c++习惯了,这个忘不了)。
接口类的实例不是使用new来实例化,因为他们是纯虚类。实例化的第一个类是NxPhysicsSDK,他将返回 NxPhysicsSDK函数。
很多SDK接口包含创建方法指针将返回其他类型的实例,这些方法是创建SDK工具,为了避开过度的长参数列表和返回帮助,错误检测,SDK使用描述类去pass创建的参数。这个表述是临时变量仅仅存在在创建的时间,你可以申请一个堆变量。下面你将创建一个场景例子,将使用描述符号:
NxSceneDesc sceneDesc;
这个场景描述符(其实就是一个结构体,翻译起来别扭。。。)将会有很多的默认值,但是不能满足所有的需要,所以还需要定义一些参数;
sceneDesc.gravity.set(0,-9.8f,0);//重力设置
创建一个SDK的object(实例),参数 场景描述符创建方法:
gScene = gPhysicsSDK->createScene(sceneDesc);
if (!gScene) Error("Can't create scene!");
//这个函数如果错误将返回fail。
当然创建了,不想要了就要release;
gPhysicsSDK->releaseScene(*gScene);
gScene = 0; //the object is now deleted,
//so don't use the pointer anymore!
Up Casting是一个转换操作获取一个类的参数或是子类的参数给一个超类的参数。
SDK2.1.2之前,不支持接口继承,因为没有主,但是这已经过去了,现在可以使用C++创建继途径去隐式的选派子类型到超类。
Down Casting与Up Casting相反。
//this is still the sphere object created above.
NxShape * shape = shapePointers[0];
//get back the sphere pointer
NxSphereShape * sphere = shape->isSphere();
//try to get a box shape pointer:
NxBoxShape * p = shape->isBox();
//failure! here p will be set to 0.
现在安装了SDK,下面将定义内存管理,这非常重要!。这个机制在PC开发中很烂,但是必须这样做,囧。任何一个方法让用户监视SDK的内存,这是一个很重要的方面。
SDK将使用机器的内存,像C的malloc realloc free,你需要定义一个获取 NxUserAllocator,和定义所有这些纯虚类的方法。这些方法是基本的C runtime malloc realloc free,直到你试图访问他们为止,下面由一个实例,SDK没有质量保障和特殊的花样,允许你去做真实的专门的分配,很多的cases,SDK将奉陪一个内存Chunk,起始阶段,当时的内部管理块为了 内部分配的需要。
分配你定义在开始初始化 NxCreatePhysicsSDK() 时开始,之后你创建SDK,这里没有方法去remove分配器。
Example:
class MyAllocator : public NxUserAllocator
{
public:
void * malloc(NxU32 size)
{
return ::malloc(size);
}
void * mallocDEBUG(NxU32 size,const char *fileName, int line)
{
return ::_malloc_dbg(size,_NORMAL_BLOCK, fileName, line);
}
void * realloc(void * memory, NxU32 size)
{
return ::realloc(memory,size);
}
void free(void * memory)
{
::free(memory);
}
} myAllocator;
gPhysicsSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION, &myAllocator, 0);
线程:
用户应该保证分配器的线程安全。。。
调试机制是预计在SDK中潜在的问题给用户的虚拟方法,而不是仅仅的文本的错误信息。这非常有用对于很多问题,空间排序等等,例如,一个车将不滚,如果这个轮子的轴线的错误方向,可以设置轴线到一个合法的范围这样不会发出错误消息,这个问题可能不会立即给用户明显的感觉。
SDK可以帮助快速认识问题,用几行代码进行设置。因为SDK不能知道也不关系你用了什么API,渲染几何体和其他什么
...
//Do this after advancing the simulation.
const NxDebugRenderable *dbgRenderable=gScene->getDebugRenderable();
renderData(dbgRenderable);
...
void renderData(const NxDebugRenderable& data) const
{
glLineWidth(1.0f);
// Render points
{
NxU32 NbPoints = data.getNbPoints();
const NxDebugPoint* Points = data.getPoints();
glBegin(GL_POINTS);
while(NbPoints--)
{
setupColor(Points->color);
glVertex3fv(&Points->p.x);
Points++;
}
glEnd();
}
// Render lines
{
NxU32 NbLines = data.getNbLines();
const NxDebugLine* Lines = data.getLines();
glBegin(GL_LINES);
while(NbLines--)
{
setupColor(Lines->color);
glVertex3fv(&Lines->p0.x);
glVertex3fv(&Lines->p1.x);
Lines++;
}
glEnd();
}
// Render triangles
{
NxU32 NbTris = data.getNbTriangles();
const NxDebugTriangle* Triangles = data.getTriangles();
glBegin(GL_TRIANGLES);
while(NbTris--)
{
setupColor(Triangles->color);
glVertex3fv(&Triangles->p0.x);
glVertex3fv(&Triangles->p1.x);
glVertex3fv(&Triangles->p2.x);
Triangles++;
}
glEnd();
}
}
void setupColor(NxU32 color) const
{
NxF32 Blue= NxF32((color)&0xff)/255.0f;
NxF32 Green= NxF32((color>>8)&0xff)/255.0f;
NxF32 Red= NxF32((color>>16)&0xff)/255.0f;
glColor3f(Red, Green, Blue);
}
假设OpenGL矩阵是已经设置的 几何渲染了将会变换到世界空间中(世界坐标系)。
下面我们需要SDK使用我们的的draw代码去 显示什么东西。假设我们的物体是移动在一个奇怪的路上,可能惯性张量可能设置错误,你界定最好是SDKdraw说有的 惯性和张量在当前的屏幕,打开现实的非零的大小。
NxReal myScale = 1.0f;
physicsSdk->setParameter( NX_VISUALIZATION_SCALE, myScale);
这个scale参数 箭头和向量可以 可见。这个大小靠你来设置在你的场景中。最好的bind他用一些按键或GUI slider,你可以控制这些变化。这样更好看。
Ok,现在开启你希望关心的选项。在这个案例 mass axes使我们关心的,所以设置他。
physicsSdk->setParameter( NX_VISUALIZE_BODY_MASS_AXES, 1.0f);
这个方法改变显示的物体,如果是这样的话,就错了。