PhysX3.3.4 snippets—SnippetHelloWorld (2)

   在上一篇中提到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.  场景

ActorPxActor 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的绘图语句位置调用,下一篇我们来详细讨论这里面的内容!



  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值