dynamic物理引擎简单教程

Newton物理引擎没有函数说明,没有教程文档,只有几个demo程序,看完这些demo后,整理了一下,方便以后查阅

首先跟踪一下,牛顿引擎的运行过程:

全局函数NewtonUpdate (g_world, (1.0f / DEMO_PHYSICS_FPS));这个函数内部调用了g_world.UpdatePhysics(dgFloat32 timestep)然后,这个函数又调用了:dgWorld::Update(dgFloat32 timestep)退出的时候要:NewtonDestroyAllBodies (g_world); 销毁世界中的所有bodyNewtonDestroy (g_world); 销毁牛顿世界使用流程:设置内存分配和释放函数。NewtonSetMemorySystem (AllocMemory, FreeMemory);void* AllocMemory (int sizeInBytes){return malloc (sizeInBytes);}void FreeMemory (void *ptr, int sizeInBytes){free (ptr);

}

创建牛顿世界:

NewtonWorld* g_world = NewtonCreate ();设置在那个平台使用牛顿物理引擎NewtonSetPlatformArchitecture (g_world, 0); 这个表示在X86平台使用。设置牛顿世界的大小:dVector minSize (-500.0f, -500.0f, -500.0f);dVector maxSize ( 500.0f, 500.0f, 500.0f);NewtonSetWorldSize (g_world, &minSize[0], &maxSize[0]); 如果需要开启可视牛顿调试器:void* g_newtonDebugger = NewtonDebuggerCreateServer ();设置牛顿求解模型:NewtonSetSolverModel (g_world, 1); 创建牛顿场景:…………………接下来就进入渲染循环里面了:做一些输入控制处理,现在还具体没有调用引擎的函数。驱动牛顿引擎干活:NewtonUpdate (g_world, (1.0f / DEMO_PHYSICS_FPS));如果打开了牛顿可视调试器:NewtonDebuggerServe (g_newtonDebugger, g_world);看看怎么创建一个body:在创建场景的时候添加牛顿的body,一个body需要一个shap:NewtonBody* Body;NewtonCollision* shape;1 分析一下shap是怎么创建的:shap是一个形状,比如盒子,球等。比如创建盒子:dMatrix offset (GetIdentityMatrix());offset.m_posit = origin; //盒子的中心点// 下面这个函数返回NewtonCollision* shap;shap的ID不知是不是固定的,我看到box的id是0.return NewtonCreateBox (world, size.m_x, size.m_y, size.m_z, shapeId, &offset[0][0]);2 shap有了之后就可以创建body了:1 Body = NewtonCreateBody (world, shap);2 NewtonBodySetDestructorCallback (Body, DestroyBodyCallback);设置body的销毁函数销毁函数可能主要用于释放内存吧,3 NewtonBodySetUserData (Body, ent); //设置自定义用户数据,自定义的Entity* 4 NewtonBodySetMatrix(const NewtonBody* const bodyPtr, const dFloat* const matrixPtr)设置body的位置和方向矩阵,就是用一个矩阵表示就行了。5 下面需要body的质量的重心位置,以及惯性矩阵inertia matrix(质量矩阵)。Newton中有一个函数可以根据一个shap来计算得到这两个东西:void NewtonConvexCollisionCalculateInertialMatrix(const NewtonCollision* convexCollision,dFloat* const inertia, dFloat* const origin)第二和第三个参数都是dVector* 其实。NewtonConvexCollisionCalculateInertialMatrix (shap, &inertia[0], &origin[0]);6 设置质量矩阵: mass是质量,float类型NewtonBodySetMassMatrix (body, mass, mass * inertia.m_x, mass * inertia.m_y, mass * inertia.m_z);7 设置刚体原点:NewtonBodySetCentreOfMass (body, &origin[0]);8 设置力和转矩回调函数:NewtonBodySetForceAndTorqueCallback (body, ApplyForceAndTorqueCallback);void ApplyForceAndTorqueCallback (const NewtonBody* body, dFloat timestep, int threadIndex){dFloat Ixx;dFloat Iyy;dFloat Izz;dFloat mass;// for this tutorial the only external force in the GravityNewtonBodyGetMassMatrix (body, &mass, &Ixx, &Iyy, &Izz);dVector gravityForce (0.0f, mass * GRAVITY, 0.0f, 1.0f);NewtonBodySetForce(body, &gravityForce[0]); 设置一个外力}8 设置方位变化的回调函数:NewtonBodySetTransformCallback (body, SetTransformCallback);void SetTransformCallback (const NewtonBody* body, const dFloat* matrix, int threadIndex){//在这个函数里,你可以设置自定义的Entity的方位//通过传进来的matrix可以得到位置,,//可以通过一个函数得到旋转dQuaternion rotation;//NewtonBodyGetRotation(body, &rotation.m_q0);Entity* ent;ent = (Entity*) NewtonBodyGetUserData(body);ent->m_prevPosition = ent->m_curPosition;ent->m_prevRotation = ent->m_curRotation;if (ent->m_curRotation.DotProduct (rotation) < 0.0f) {ent->m_prevRotation.Scale(-1.0f);ent->m_curPosition = posit;ent->m_curRotation = rotation;}3 最后还要调用一下这个函数:NewtonReleaseCollision (world, shape); 这是由于NewtonCollision对象是索引计数对象其他shape的创建方法:创建一个与实体网格形状相同的shape:第三个参数是单个顶点占的字节数,这里面的shapId也是0。NewtonCreateConvexHull(world, ent->m_vertexCount, ent->m_vertex, 3 * sizeof (dFloat), 0.1f, shapeId, NULL);下面看看怎么创建joint:joint是物体之间的一种连接关系,比如铰链连接,等,所以要有两个body。1 对第一个物体,单它的body创建好后,创建Joint:NewtonUserJoint* frownyHinge;frownyHinge = CreateCustomJoint6DOF (&matrix[0][0], &matrix[0][0], frownyBody, NULL);看看这个函数的声明: NewtonUserJoint *CreateCustomJoint6DOF (const dFloat* pinsAndPivotChildFrame, const dFloat* pinsAndPivotParentFrame, const NewtonBody* child, const NewtonBody* parent);2 设置Joint的一些限制:第二三个参数都是dvector类型。CustomJoint6DOF_SetLinearLimits (frownyHinge, &minLinearLimits[0], &maxLinearLimits[0]);CustomJoint6DOF_SetAngularLimits (frownyHinge, &minAngulaLimits[0], &maxAngulaLimits[0]);3 设置前面的body与另外一个body通过Hinge Joint相连。NewtonUserJoint* smillyFrownyHinge;NewtonUserJoint *CreateCustomHinge (const dFloat* pinsAndPivotChildFrame, const NewtonBody* child,const NewtonBody* parent);smillyFrownyHinge = CreateCustomHinge (&matrix[0][0], smillyBody, frownyBody);HingeEnableLimits (smillyFrownyHinge, 1);HingeSetLimits (smillyFrownyHinge, -0.5f * 3.1416f, 0.5f * 3.1416f);//第二三个函数分别表示最小角度和最大角度这样两个body通过hinge Joint相连了。Kinematic control joint这是另外一种Joint:可以自己控制它的运动路径NewtonUserJoint* g_pathFollow;g_pathFollow = CreateCustomKinematicController (frownyBody, &matrix.m_posit[0]);CustomKinematicControllerSetPickMode (g_pathFollow, 1);CustomKinematicControllerSetMaxAngularFriction (g_pathFollow, 200.0f);CustomKinematicControllerSetMaxLinearFriction (g_pathFollow, 1000.0f);CustomSetUserData(g_pathFollow, path);CustomSetDestructorCallback(g_pathFollow, FollowPath::Destroy);CustomSetSubmitContraintCallback (g_pathFollow, FollowPath::EvaluatePath);如何使用材质:1 首先要创建材质:g_floorMaterial = NewtonMaterialCreateGroupID (world);g_woodMaterial = NewtonMaterialCreateGroupID (world);g_metalMaterial = NewtonMaterialCreateGroupID (world);2 定义材质碰撞后产生的效果NewtonMaterialSetCollisionCallback (world, g_woodMaterial, g_floorMaterial, &woodOnFloor, NULL, GenericContactProcess);回调函数的形式是这样的:static void GenericContactProcess (const NewtonJoint* contactJoint, dFloat timestep, int threadIndex)在这个回调函数里面得到下面的知识:有一种joint叫做contact joint,通过这个joint连接起来的body可能有多个,可以获得第一个body:NewtonBody* const body0 = NewtonJointGetBody0(contactJoint);可以枚举所有这种contactjoint的所有contact:void* contact = NewtonContactJointGetFirstContact (contactJoint);//获得第一个contact = NewtonContactJointGetNextContact (contactJoint, contact);//获得下一个通过contact可以获得接触的材质句柄。NewtonMaterial* material = NewtonContactGetMaterial (contact); //这个函数 只能在这个回调函数里面调用。获得接触的法线方向上的速度,如果是负数就表示是回弹。float contactNormalSpeed = NewtonMaterialGetContactNormalSpeed (material);获得接触的位置和法线方向: NewtonMaterialGetContactPositionAndNormal (material, body0, &contactPosit[0], &normal[0]);获得材质对的用户数据:NewtonMaterialGetMaterialPairUserData (material);contact joint–contact–material–接触位置,法线,接触速度,用户数据。contact joint–接触的body。3 给body赋予材质:NewtonBodySetMaterialGroupID (floorBody, g_floorMaterial);下面分析一下tree collision这种shape:1 创建tree shape:NewtonCollision* collision = NewtonCreateTreeCollision(world,0);2 添加面到tree collision里面:1 开始添加:NewtonTreeCollisionBeginBuild (collision);2 遍历所有Entity的subEntity,把subEntity里面的所有面加入到tree collisionNewtonTreeCollisionAddFace(collision, 3, &face[0].m_x, sizeof (dVector), shapeIdArray[i]);3 结束添加:NewtonTreeCollisionEndBuild (collision, 1);3 注册一个回调函数,在一条射线与这个tree collisioin的面相交的时候,会被调用。NewtonTreeCollisionSetUserRayCastCallback(collision, UserMeshCollisionCallback);static dFloat UserMeshCollisionCallback (const NewtonBody* const body, const NewtonCollision* const collisionTree, dFloat interception, dFloat* normal, int faceId, void* usedData){return 1.0f;}下面分析下HeightFieldCollision这种shape:顾名思义这个东西是从一张高度图文件创建这种shape的。NewtonCollision* NewtonCreateHeightFieldCollision(指定宽度,高度,高度数据,属性等)设置射线与这个collision相交时调用的回调函数NewtonHeightFieldSetUserRayCastCallback().还要根据高度值创建地形网格。2 获取collision的相关信息:NewtonCollisionInfoRecord collisionInfo;memset (&collisionInfo, 0, sizeof (NewtonCollisionInfoRecord));NewtonCollisionGetInfo (collision, &collisionInfo);可以自己查看这个结构体的定义。可以将多个shape合并成一个复合shape:NewtonCreateCompoundCollision (world, ent->m_subMeshCount, shapedArray, 0);第二个参数是shape的数量,第三个参数是shape的数组,第四个参数是shapeID。还可以从多个凹网格创建一个复合shape:NewtonCollision* NewtonCreateCompoundCollisionFromMesh (const NewtonWorld* const newtonWorld,const NewtonMesh* const convexAproximation, dFloat hullTolerance, int shapeID, int subShapeID)创建出来的是与凹网格尽可能逼近的凸网格shape,然后再由这些shape组成复合网格。下面分析一下鼠标拾取物体扔来扔去是怎么实现的:首先获取鼠标光标坐标,转换到3D空间中,沿着光标点做一条垂线到3D空间求出这条射线与那个物体相交,记下这个物体。NewtonWorldRayCast()由这个函数实现。然后给拾取到的body创建定制joint:// Create PickBody JointbodyPickController = CreateCustomKinematicController (pickedBody, &p[0]);设置pickable模式为0:CustomKinematicControllerSetPickMode (bodyPickController, 0);设置各种摩擦系数:CustomKinematicControllerSetMaxAngularFriction (bodyPickController, 10.0f);CustomKinematicControllerSetMaxLinearFriction (bodyPickController, MAX_FRICTION_LINEAR_ACCELERATION);设置joint的目标位置:CustomKinematicControllerSetTargetPosit (bodyPickController, &p[0]);当不需要joint的时候销毁它:CustomDestroyJoint (bodyPickController);

快乐要懂得分享,才能加倍的快乐

dynamic物理引擎简单教程

相关文章:

你感兴趣的文章:

标签云: