PhysX3.3.4 snippets—SnippetHelloWorld (2)

    xiaoxiao2021-12-14  19

       在上一篇中提到renderLoop函数实现了基于OpenGL和Glut的程序框架,其中涉及PhysX的最重要的两个函数是initPhysics()和renderCallback()。这一篇我们分析这两个函数,讨论其中涉及的PhysX核心对象和scene->actor->shape的场景结构。本文的内容大量参考官方Guide和API文档,同时它们也是很好的学习工具,文中一些细节的内容可以从这两份文档中获取,因此没有详细解释。

        initPhysics()函数: 初始化顶层对象并创建初始场景的PhysX对象

    首先是两个顶层对象:

    1.       PxFoundation:You need to have an instance of this class to instance the higher level SDKs.  每个应用一般只有一个,最高层成员

    2.       PxPhysics:Abstract singleton factory class used for instancing objects in the Physics SDK   代表SDK的类

              PxCreatePhysics():Creates an instance of the physics SDK.  调用该指令可以注册SDK中的所有代码模块,还有其它函数可以注册部分可选项。

    因此,一般的PhysX初始化代码是

    gFoundation = PxCreateFoundation(PX_PHYSICS_VERSION, gAllocator, gErrorCallback); PxProfileZoneManager* profileZoneManager = &PxProfileZoneManager::createProfileZoneManager(gFoundation); gPhysics = PxCreatePhysics(PX_PHYSICS_VERSION, *gFoundation, PxTolerancesScale(),true,profileZoneManager);其次是PxSceneDesc类型

    PxSceneDesc:Scene descriptor 描述一些场景特性的数据结构, 是PxPhysics的createScene函数的参数。事实上,PhysX中采用了许多作用类似的后缀为Desc的数据结构。

    最后两个函数createStack()和createDynamic()分别创建场景中的box堆和飞出的球。

        renderCallback()函数:渲染

    在讨论渲染之前,我们先要搞清楚PhysX场景的组成。我们采用的是PhysX的API创建场景中的实体,再从这些PhysX对象中获取渲染所需的数据,利用OpenGL进行渲染,才获得了我们最终看到的结果。事实上,换一种说法就是,这里渲染的工作仅仅是让这些PhysX代码实现的物理过程可视化而已,snippets中的许多例子是没有渲染的。

    snippetHelloWorld场景中的对象大致分为三类,从上到下依次为scene类型、actor类型、shape类型。

    PxScene:A scene is a collection of bodies, particle systems and constraints which can interact.  场景

    Actor:PxActor is the base class for the main simulation objects in the physics SDK  actor就是PhysX中的物体,PxActor是所有actor类型的基类,Guide的rigid body一节中有个图描述了这些类型和他们的关系。

    PxShape:Abstract class for collision shapes.  形状,几何,类似的理解...这个类可以提取actor的几何形状,渲染就靠它了。显然,它和碰撞时有关的,不过本例并没有用到。

    它们三者之间通过类似的代码语句建立起彼此的联系,把场景组织起来

    PxShape* shape = gPhysics->createShape(PxBoxGeometry(halfExtent, halfExtent, halfExtent), *gMaterial); PxRigidDynamic* body = gPhysics->createRigidDynamic(t.transform(localTm)); body->attachShape(*shape); gScene->addActor(*body);简单来说,它们三者的关系就是:一个scene里面有许多actor,每个actor的形状由shape来定义。renderCallback函数提取了场景中的所有actor,并调用了renderActors()子函数来对每一个actor关联的所有shape进行渲染,代码如下:

    void renderActors(PxRigidActor** actors, const PxU32 numActors, bool shadows, const PxVec3 & color) { PxShape* shapes[MAX_NUM_ACTOR_SHAPES]; //shape数组 for(PxU32 i=0;i<numActors;i++) //外循环,循环次数等于actor的个数 { const PxU32 nbShapes = actors[i]->getNbShapes(); PX_ASSERT(nbShapes <= MAX_NUM_ACTOR_SHAPES); actors[i]->getShapes(shapes, nbShapes); //获取该actor的shape bool sleeping = actors[i]->isRigidDynamic() ? actors[i]->isRigidDynamic()->isSleeping() : false; //不可或缺的一行,如果actor在sleeping或者actor不是Dynamic类型,那么就把它设为 //sleeping状态,在每个simulation循环中不对它进行处理 for(PxU32 j=0;j<nbShapes;j++) //内循环,循环次数等于shape的个数 { const PxMat44 shapePose(PxShapeExt::getGlobalPose(*shapes[j], *actors[i])); //等于获取OpenGL中的模型变换矩阵 PxGeometryHolder h = shapes[j]->getGeometry(); //获取Geometry if (shapes[j]->getFlags() & PxShapeFlag::eTRIGGER_SHAPE) glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); // render object glPushMatrix(); glMultMatrixf((float*)&shapePose); //gl模型-视图变换 if(sleeping) { PxVec3 darkColor = color * 0.25f; //静止物体(sleeping)用暗色绘制 glColor4f(darkColor.x, darkColor.y, darkColor.z, 1.0f); } else glColor4f(color.x, color.y, color.z, 1.0f); renderGeometry(h); //绘图子函数! glPopMatrix(); glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); if(shadows) //阴影 { const PxVec3 shadowDir(0.0f, -0.7071067f, -0.7071067f); const PxReal shadowMat[]={ 1,0,0,0, -shadowDir.x/shadowDir.y,0,-shadowDir.z/shadowDir.y,0, 0,0,1,0, 0,0,0,1 }; glPushMatrix(); glMultMatrixf(shadowMat); glMultMatrixf((float*)&shapePose); glDisable(GL_LIGHTING); glColor4f(0.1f, 0.2f, 0.3f, 1.0f); renderGeometry(h); glEnable(GL_LIGHTING); glPopMatrix(); } } } }还是一样,如果对这里的OpenGL不够熟悉请参考红宝书。代码不是很难理解,注释也已经很清楚了,再说明两点

    1)       Sleeping对象的不同渲染

    helloWorld将sleeping的actor渲染为了暗色。isSleeping函数实现了这个判断,这里面涉及PhysX的核心概念,simulate该如何理解?

    2)       OpenGL视图变换矩阵的获取

    从shapePose函数和PxMat44等矩阵和向量类型可以看出PhysX与图形渲染的完美兼容。

    为了在OpenGL中绘制不同的shape,snippetRender.cpp中实现了一个 renderGeometry()子函数并在OpenGL的绘图语句位置调用,下一篇我们来详细讨论这里面的内容!

    转载请注明原文地址: https://ju.6miu.com/read-970875.html

    最新回复(0)