在3D游戏中,碰撞检测算得上是最复杂也是最影响游戏效果的环节了,这里简单介绍一下如何在OGRE引擎里实现简单的碰撞检测。

话不多说,先贴代码:

bool EdenCollisionManager::Collide()
{
bool collide=false;
m_KeyObject=*(m_ResearchObject.begin());  // m_Keyobjects是待检测的物体(游戏角色)
Ogre::AxisAlignedBox AABB = m_KeyObject->getWorldBoundingBox(true);  // 获取包围盒
m_AABBSceneQuery->setBox(AABB);  // 以包围盒建立场景查询
m_AABBSceneQuery->setQueryMask(ENTITY_QUERY_MASK); // 设置查询标识
Ogre::SceneQueryResult& results = m_AABBSceneQuery->execute();  // 获取查询结果
Ogre::SceneQueryResultMovableList::iterator iter = results.movables.begin();
if(results.movables.empty())
return false;
else
{
for(;iter!=results.movables.end();iter++)
{
if((*iter)->getMovableType()==“Entity”)
{
if(m_KeyObject->getName()==(*iter)->getName())
continue;
else
{
collide=true;
break;
}
}
}
return collide;
}
}
OK,对OGRE熟悉一点的人一眼就可以看出来,这里采用的是基于包围盒的碰撞检测方法,什么是基于包围盒的碰撞检测呢?简单点说,就是用一个立方体的盒子把物体装起来,然后用这个盒子里代替原先的物体,在场景中进行检测,按照一定的策略(比如距离)判断两两物体间是否碰撞。
包围盒法虽然简单快速,但是准确性却不太高,而且有很大的局限性。因为是采用立方体的包围盒,盒子的范围比原先的物体大,所以会造成一定的误差(特别是在物体形状不规则的情况下),这个误差随着“盒子”的体积紧包物体表面而无限接近真实结果,所以为了减少这个误差,配合着场景物体的形状,我们可以用球体、圆柱体等来代替包围盒,所有这些替代,都是为了减少误差,是碰撞检测更加精确。可以说,包围盒法检测结果的准确性依赖于包围盒的选择,包围盒的体积愈接近3D物体,结果越精确,但是在游戏中,一个场景中往往有各种大小、各种形状的物体,所以我们的包围盒往往只能折中选择。

上面的代码只是在OGRE引擎里实现碰撞检测的演示代码,下面具体讲讲包围盒法碰撞检测的算法:
包围盒法碰撞一般是使用球体或圆柱体的范围包围每个Object或测试一定范围内的碰撞。假设我们有两个Object A和B,两个Object分别被一个半径为ra,rb的球体包围,半径ra,rb来检测。我们可以简单的检测AB间的距离是否小于ra+rb,小于,则碰撞;反之则没有。
碰撞检测还有很多其他的方法,比如射线法等,甚至还有三角面级别的精确碰撞检测,这里不再详述,以后再做介绍。
优化问题
最后简单提一下碰撞检测的优化问题。
举一个简单的例子,假设一个场景中有1000个对象(object,子弹等等)。现在假设我们要对这1000个obejcts进行碰撞检测,考虑到每两个物体之间我们都要计算一次,那么总共会有1000×1000 = 1000000的计算量,这个计算量是很恐怖的,因此我们不得不对碰撞问题进行一些优化,这里介绍一下空间分割方法。

还是这个场景,但是我们现在把利用BSP树(二叉树)对场景里的object进行管理,并且将所有的object划分成一组一组,每一组50个object,共有1000 / 50 = 20组。很显然,现在我们只需要在每一组的objects里进行检测就可以了,所以现在的计算量是50 * 50 * 20 = 50000。计算量只有原来的5%!可见使用BSP树进行场景管理对我们游戏性能的提高有多大帮助了!

暂无相关产品

3则回应给“OGRE里如何实现碰撞检测”

  1. 雨碎江南说道:

    学习了…尤其是空间分割方法对我启发很大.

    [回复]

  2. zclmoon说道:

    学习了。支持。

    [回复]

  3. 溪风说道:

    学习了,楼主,很精辟!

    [回复]

发表评论