斜视角图形引擎的设计

物体的绘制及遮挡运算

[上篇:动态地表的实现][下篇:复杂的精灵控制]


较之平面引擎的设计,难点之一恐怕要属物体间的遮挡关系的处理. 通常,有两种方法来处理物体间的遮挡关系:画家算法和Z-Buffer. Z-Buffer 多用于 3D Engine 中, 由于 3D Engine 里图象是矢量构成, 容易得到每点的 Z 值,根据 Z 值,查询 Z 缓冲,就可以知道是否应该绘制. 如果是像斜视角引擎这样的假 3D 中,则可以将物体做成 3D 面片, 同样适用; 而画家算法, 就是先确定物体的先后次序,然后按从后向前的次序,依次绘制.

两种方法各有优缺点, 但都必须注意的是, 物体的整体结构必须是凸多边形, 因为无论是哪种方法, 物体实际都是作为一个平面处理(除非将其按 3D 格式存放) 本身都为一次绘成, 凹的多边形容易造成物体间没有固定的前后关系,产生相互遮挡的结果. 比如半圆形的墙,和有门梁的门,在遇到这些情况时,应当将多边形切成几个凸多变形的块, 分别处理.如图,是一个半圆形的墙和一个矩形物体,从物体的底面来看(图 1-1),墙是个凹多边形, 在 3D 的视图上, 墙就和六面体发生了相互遮挡的现象(图 1-2). 这时, 不能简单的先画六面体, 或是先画墙,来得到正确的图像. 所以我们应该将墙分成两块凸多边形(图 1-3) 图中灰色部分是透明属性, 但不得放置其它物体或精灵. 如果想将墙描述的更细致, 可以再将其分割成更多的块.带有门梁的门同样是这样,我们必须将门的梁和它的两侧墙分开, 才能正确的处理精灵通过门时的图象.

多边形底面 (1288字节) 3D多边形 (1694字节) 分割多边形 (1383字节)
图 1-1
图 1-2
图 1-3

在基于 Tile 的引擎中,决定各个 Tile 的绘画先后次序是很容易的,所以根本谈不上用什么 Z-Buffer. 按照游戏中的坐标依次去画各个 Tile 就不会出错.从屏幕上看就是从右上到左下,从左上到右下. 还可以经过一个简单的坐标换算,按从左至右,从上至下等次序绘制.关于这部分的算法,有许多文章中已经提到, 在此不表.再来看看非 Tile 的引擎,将采用不规则的多边形, 不规则的角度放置.使用 Z-Buffer 是个解决途径, 不过我仍旧希望采用画家算法,这样可以减少描述物体时的数据复杂度,而且物体是固定的, 预先算好其前后关系完全可行. 这样我们需要找到一个好的算法, 不光用于游戏设计时的预运算, 还要用来决定下一步,精灵的穿插其中.

最初的设想是采用 BSP 树进行空间分割, 但这毕竟是一个 2D 的引擎, 视角固定, 没有必要去对平面进行细致的分割,使用 BSP 树无谓的增加了程序和数据的复杂度. (假如要将引擎设计成像《地下城守护者》那样可以随意转动视角的话,我会毫不犹豫的采用 BSP 树, 除非引擎设计成基于 Tile 的) 在没有想到更好的方法前,先使用如下方案:

3D视图及地面掩图 (4525字节) 首先假设所有的物体(包括精灵) 底面都是不重叠的 (门梁这样可以和精灵重叠的特例将于下文讨论), 我们在制作物体的位图时, 应当同时制作它的底面掩图(图 2-1). 对屏幕内物体的位置排序, 基本操作就是判断任两个物体的前后次序. 如果两个物体底面的剪裁矩形不相关(图 2-2), (不相关指不存在一条垂直线能穿过两个矩形)认为它们之间无前后关系, 具体的绘制顺序由其它物体的相对位置决定.(图 2-3) 参与位置排序时,相互比较结果为相等,如果相关(图2-4)则取垂直方向并集部分的区域, 其内,两个物体的掩图必定有明显的前后关系 (任一条垂直线上,两物体的底面掩图点的前后关系保持一致). 如果有的物体可以和精灵重叠, 那么, 我们认为它处于整个平面的上方. 即当重叠的时候, 精灵永远被之覆盖. 典型的例子是门粱(图 2-5), 如果重叠时,精灵在物体的上方, 我们就认为它是地表,而不做物体处理. 从这里可以看出, 这个 Engine 将是纯 2D 的世界, 精灵永远在同一层运动, 为了达到某些 3D 的视角效果, 我们可以采取一些美工上的技巧, 在地图中加入梯子等物, 在地图的构建上仍是 2D 的, 而当精灵通过梯子时,做相应的特殊处理 (显示爬梯子的动作), 这样从玩家的感觉上,游戏世界就变的有层次了. 这些特殊物体便可和门梁 之类同做特殊处理(在地图上标明), 不必每次判断精灵和物体间是否重叠.

底面剪裁矩形分离 (2430字节) 绘制次序的间接确定 (2832字节) 底面剪裁相交 (2861字节) 门的特殊处理 (3390字节)
图 2-2
图 2-3
图 2-4
图 2-5