基于八叉树的拾取算法在游戏中的应用

时间:2023-02-13 20:30:49
时间: 2014-02-12 来源:论文在线

  摘  要:八叉树结构在游戏的场景渲染中应用十分广泛,本文针对该结构大幅度优化运算效率的特点,将其作了适当改进,使其用于鼠标拾取技术,取得了不错的效果。在要求对鼠标点击做出快速响应的游戏中,尤其是实时射击游戏中,该算法有一定的参考与使用价值。

  关键词:拾取,DirectX sdk,包围盒,八叉树

  1.  引 言

  3D交互图形应用程序中,常常要用鼠标去选择图形,其实现机制基于鼠标拾取算法。拾取操作指当我们在屏幕上用鼠标点击某个图元应用程序能返回该图元的一个标志和某些相关信息[1]。有图形程序设计经验的人都知道,有这些信息就表示我们有了对该图元的控制权,我们可以删除,可以编辑,可以任意对待该图元。

  “拾取”适用于所有种类的游戏和3D程序。例如,玩家通过用鼠标点击来影响3D世界中的不同对象,玩家可能点击向敌人射击,或点击拾取物品。好的程序会适当做出反应,程序需要知道哪个对象被选取(是敌人还是物品),以及选取目标在3D空间中的位置(开枪会击中哪?或玩家将要移动到哪去拾取物品?)。拾取回答了我们这些问题。

  判断一条射线是否穿过了场景中的多边形产生的运算量可能会很大。一个最简单的检测法就是用球形来近似地表示物体或物体的一部分,然后再通过连立射线与球面方程,通过观察方程的解的情况来判断是否相交[2] [3]。但在游戏中的大多数物体是方的,为了保证游戏的真实性,我们最好用方盒来代替球体。如下图所示:

基于八叉树的拾取算法在游戏中的应用

  很显然,当我们用鼠标点选包围体(红点处表示鼠标)时,包围盒的真实性远优于包围球。

  那么,我们如何判断鼠标选取了场景中的物体呢?在三维世界里,一个点的位置是经过多次的矩阵变换才最终显示到屏幕上的[4],其变换流程如下图所示:

基于八叉树的拾取算法在游戏中的应用

  因此我们在得到鼠标屏幕坐标后要把它转化为世界坐标,生成拾取射线,然后用这条射线与三维场景中的所有图元判断是否相交,来判断鼠标是否拾取到场景中的物体。可以看出,拾取算法主要有两步:

  1.计算拾取射线

  2.循环判断射线与三角形图元是否相交

  Directsdk中也为我们提供了一个方法来判断拾取问题:D3DXIntersect。该方法通过计算拾取射线与所有的三角形图元的交点是否存在来判断鼠标是否选取物体。但是一个三维物体是由成千上万个三角形组成的(例如图一中的卡通人物就是由1982个三角形组成)。如果依次判断与场景中的所有三角形相交无疑是一件耗费资源的事情,基于以上原因,文章下面给出了一个可以较为快速的判断拾取问题的算法。

  2.  基于八叉树的拾取算法

  八叉树广泛应用于3D游戏的场景渲染,其原理是把一个大的场景以树型结构不断拆分成多个小的场景,然后遍历每个场景节点,以确定要渲染的图元,大大提高了渲染的效率[5]。我们发现,在经过适当改进后,这种方法用于拾取技术也有很好的效果。本文所介绍的算法就是基于这种结构的,算法内容如下:

  2.1拆分节点,构造八叉树

  首先,八叉树把一个网格模型的包围盒看作一个大的根节点,然后不断分拆此节点,直到满足要求为止。其中,不包含三角形图元的节点将被去掉。最后就会得到一个树型结构,每个节点最多有8个子节点,且每个叶节点都包含三角形图元。如下图所示:

基于八叉树的拾取算法在游戏中的应用

基于八叉树的拾取算法在游戏中的应用

  另外,我们需要设置一个条件作为拆分完毕的依据。在这里,这个条件可以是每个节点所含三角形图元的个数。假如令该值为30,则分拆到每个节点中的三角形个数低于30时自动停止。其中每个节点的结构为:

基于八叉树的拾取算法在游戏中的应用

  typedef struct{

  float XPos,

  float YPos,

  float ZPos}Point; //节点的中心坐标

  flaot Size; //节点的边长

  unsigned long FaceNum; //包含的三角形数

  unsigned long *Index //存储所包含的三角形的索引

  sNode *Node[8]; //存储8个子节点的指针

  按照下面步骤构造8叉树:

  1.载入待检测网格(Mesh)的包围盒作为根节点

  2.判断当前节点是否满足预设条件(例如:包含三角形数<30)

  满足:结束  不满足:跳到步骤3

  3.把不满足步骤2 的节点拆分为8个子节点,判断各子节点是否包含三角形图元。不包含:删除该子节点  包含  :把该节点加入到树形结构中,并且转到步骤2。

  2.2计算拾取射线

  射线的方程可以表示为P(t)=Orgin+t*Dir。其中Orgin为射线出发点(通常为摄像机在世界坐标中的位置),Dir为射线方向。我们定义在世界坐标系中,Dir为向量P-Orign(P为屏幕上的鼠标坐标点转化为世界坐标之后的结果)。如下图所示:

基于八叉树的拾取算法在游戏中的应用

  如何把平面坐标P转化为世界坐标的问题实际上就是对图2中的坐标变换求逆变换的过程。许多文献中对于拾取射线的生成算法有比较详细的描述[6],在此不再介绍。

  2.3相交性判断

  在有了8叉树和拾取射线之后,我们就可以进行相交性判断了。流程如下:

基于八叉树的拾取算法在游戏中的应用

  该过程依次检测拾取射线与每个节点中的所有三角形是否相交,如果相交则不再进行检测,立即返回。

  3.  结论

  本文给出了一个鼠标拾取的新算法,与Direct SDK 提供的D3DXIntersect函数不同,该算法并不是用射线与所有三角形图元作相交性判断,而是一旦发现有三角形与射线相交后立即返回,大大节省了检测时间。另外,该算法利用了树形结构的便利性,避免了对无用节点的检测。而且在判断速度提高的同时算法的精度也没有下降,解决了以往拾取算法中精度与速度不能兼顾的问题。因此本文提出的算法在一些对拾取速度与精度要求较高的场合中(例如射击类游戏)有一定的实用价值。

  参考文献

  [1].姚继权, 李晓豁  计算机图形学人机交互中三维拾取方法的研究  工程设计学报2006

  [2].王玉增,  顾英妮  基于DirectX SDK 开发平台的碰撞检测  工程图学学报2006

  [3]. 王志强  洪嘉振  杨  辉  碰撞检测问题研究综述  软件学报1999

  [4]. 尚晶晶Direct3D游戏开发技术详解ISBN:7-115-14309-9

  [5]. Jim Adams 著,黄际州,刘刚 译DirectX 角色扮演游戏编程ISBN:7-5624-3542-1

  [6]. Frank Luna  Introduction to 3D Game Programming with DirectX 9.0   ISBN:1556229135