Irrlicht学习备忘录——7 Collision

7 Collision

官方代码($sdk)\examples\07.Collision

Irrlicht学习备忘录——7 Collision_第1张图片

这个例子是教使用irr的碰撞检测系统。我自己设计游戏引擎时,曾经花了大量时间在这部分上,每天都在推导数学物理公式和研究算法,看怎么把它们用到自己的引擎中。第一次看到这个例子,我非常兴奋,irr已经有了这部分,不需要自己再在这上面费力气了。事实上,我错了,irr的这部分功能同样很弱小,只够山寨学生时代的经典——CS。他里面的碰撞检测主要是包围盒碰撞和射线跟三角形的碰撞,物理方面的东西几乎没有,就只有一个简单的模拟重力。用上只能保证自己做的运动模型不会穿墙而过,会从高处往下落下,能找到射线方向上的第一个三角形面在什么物体上。再复杂的东西,如碰撞之后的反弹这些力学的东西,一概没有。不管怎么说,irr引擎还是很强大了,它的确能够用来做比较简单的3D游戏了。下面就具体看看irr的碰撞检测的主要功能怎么用。

这个例子其实是在官方例子02.Quake3Map的基础上添加出来的。

首先用枚举类型,定义了三个ID常量,ID_IsNotPickable= 0,IDFlag_IsPickable = 1 << 0,IDFlag_IsHighlightable = 1 <<1用来区别能否鼠标拾取和高光显示。它们是用在例子中射线对三角形面的碰撞检测中。

然后在第二例中的Quake3地形模型建立后,创建了一个三角形选择器,并把它设置为地形模型使用的三角形选择器。注意,三角形选择器是irr碰撞检测的核心,irr的所有碰撞检测都是基于它的,没有它,就没有碰撞了。创建三角形选择器的方法在irr场景管理器里,主要有createTriangleSelectorcreateTriangleSelectorFromBoundingBoxcreateOctreeTriangleSelector createTerrainTriangleSelector几个三角形选择器,当然不够用的话,irr允许自己做扩展。这么多三角形选择器的创建方法,怎么知道什么时候该使用什么方法创建呢?从数量上看的确有点晕,其实并不复杂,它们基本是跟创建的场景节点类型是配套的,从方法的名称和参数上看,就基本知道自己该选哪一个了。createTriangleSelector从名字看,似乎是万能的,看参数应该能体会到它主要是用来给动画场景节点配套使用的,或者自己要用不同于场景节点的mesh做为碰撞检测依据时使用的;createTriangleSelectorFromBoundingBox这个一看名字就很简单,使用包围盒作为碰撞检测的三角形选择器,这样可以大幅减少测试碰撞的三角形数;createOctreeTriangleSelector创建八叉树三角形选择器,这明摆着跟八叉树场景节点有关,用它做与八叉树节点配套,肯定跟八叉树场景节点一样有优化的效果;createTerrainTriangleSelector创建一个地形三角形选择器,这个跟后面官方例子中使用的irr地形生成器生成的地形配套使用。创建好三角形选择器后,使用场景节点的setTriangleSelector方法,就可以将三角形选择器设为场景节点所使用的三角形检测器。例子中用相似的方法,为四个不同的动画模型场景节点也设置了三角形选择器。

三角形选择器设置好后,就可以使用irr的碰撞检测功能了。irr将碰撞检测功能封装成一个碰撞管理器ISceneCollisionManager,它属于场景管理器的一部分,通过场景管理器的getSceneCollisionManager方法,就能获得碰撞管理器。例子中为了简单,同时能够实时看到碰撞检测效果,将碰撞管理器的使用代码全放到了帧循环中。鼠标拾取时,其实就是用碰撞管理器检查从屏幕中心到鼠标指向的位置的射线与三角形面是否相交。因此首先得计算出射线的方程。代码如下:

定义一个射线结构

core::line3d<f32>ray;

将摄像机的位置设为射线的起点

ray.start= camera->getPosition();

将摄像机的镜头对准方向前方1000的位置设为射线的终点,这样射线就准备好了。

ray.end= ray.start + (camera->getTarget() - ray.start).normalize() *1000.0f;

使用碰撞管理器的getSceneNodeAndCollisionPointFromRay(射线,交点,相交的三角形,检测掩码,检测的根场景节点)方法,得到返回的相交的场景节点。这里的检测掩码设置为非0后,将只对场景节点ID与掩码位相符的节点进行射线的碰撞检测。 找到鼠标拾取的场景节点后,将该节点的材质光照属性设为不启用光照,这时就成高亮显示该场景节点了,同时更改节点ID

物体之间的碰撞检测,例子中将它用到了摄像机节点上。通过场景管理器createCollisionResponseAnimator创建了一个以前例子中说过的场景节点运动器,这个函数的第一个参数指定了用于碰撞检测的三角形选择器;第二参数是与第一个参数发生碰撞的场景节点,第三个参数是设置发生碰撞的场景节点的大小,它是一个椭球状包围体;第四个参数是重力各方向的大小;最后一个参数是发生碰撞的场景节点在椭球包围体中的偏移量,默认的时候是在椭球体的中心,设置这个偏移量可以模拟摄像机在身体的位置。这个运动器创建好后,把它添加到摄像机场景节点,移动镜头时就自动产生运动物体与其它物体的碰撞反应。

本例中只设置了摄像机与地形的碰撞,因此移动摄像机时,只会与场景中的地面墙壁等发生碰撞,而对4个游戏人物直接穿过。

例子中绘制了一个红点代替被隐藏的鼠标指针,效果跟《生化危机4》瞄准到目标后显示的哪个红点一样。这个红点其实是创建了一个告示板场景节点IBillboardSceneNode,它是一个2d效果的场景节点,用来显示一张纹理,不管怎么旋转总是面向用户的,不会随距离远近发生透视现象。自己再用IVideoDriver的绘制一条红线,就可以完美山寨《生化危机4》瞄准线了,当描到目标就把IBillboardSceneNode设为显示,没描到目标就关闭。

要想使irr产生更复杂的物理效果,如车撞击到一个锥筒,锥筒会自己飞出去,飞行方向、距离等与车的速度方向、撞击部位有关。就得自己动手写相关的代码或者找个物理引擎来计算每一帧后物体的位置,旋转角度等数据来重新设置场景节点。光靠irr的碰撞管理器和运动器是做不到这么复杂效果。


你可能感兴趣的:(游戏,游戏引擎,游戏编程,3D引擎,Irrlicht)