斜视角图形引擎的设计(上)

经过好几个月的理论准备, 云风决定自己写一个第三人称斜向固定视角的图象引擎. 一边写一边将我在实践中学习到的知识和经验奉献给和我有着相同目标的朋友;-) 希望我们的游戏产业能尽快跟上世界.

我将要设计的东西称作"第三人称斜向固定视角"(以下简称"斜视角"),想必大家能够 想象出将是个什么样子. 在《创世纪》,《仙剑奇侠传》里都使用了这个视角, 并取得了成功. 而它们使用的那种图形引擎在英文中叫做 Isometric Tile Engine. Tile 直译是砖块的意思,就是指游戏中的场景和人物都是以一个个砖块为单位 描述的. 目前的许多 RPG, SLG 游戏都是这样. 就直观的视觉效果来说又分两种, 按一般玩家的说法, 90 度视角的和斜45度视角的. Isometric 形式就是通常 提到的斜 45 度视角, Isometric 这个词,有等轴(晶体),等容,等积的意思, 如果你玩过《超时空英雄传说》,或是《X-COM I/II》这类战棋游戏, 见过游戏里面框住人物的光标,就会感到 Isometric 这个词用的是多么准确;-) 因为这个词强调的是等轴, 所以 Isometric 并没有说明视角一定是 45 度的 (关于视角的选择,下文将有详细论述); 另一种 90 度的形式, 国外称之为 Rectangular Tile Engine, Rectangular 就是直角的意思了. 这种直角砖块的处理给程序的实现带来许多好处, 最大莫过于遮挡的计算了, 在计算机 CPU/ 显卡速度还很慢的年代, 甚至是 RPG 唯一的表现手段, 对于目前有的游戏还采取这种形式, 我感到不可理解, 难道是程序员功力不够? 无论美工多么厉害, 90 度的平面世界的表现力和真实感是远不能满足现在的玩家的.

这里,没有使用 Isometric 或是 Tile 这些名词,是因为我所构想的表现形式是不同的, 除了外观上采用和 Isometric 相同的斜视角, 在内部数据结构,和实现方法, 绘制顺序,遮挡计算等方面都将超出传统. 将使用的是无大小限制,角度限制, 的物体及无规则的场景, 而其中人物运动的方向也是任意的, 这些好象更接近 3D 一些, 但我的目的是避免和多边形,贴图,等打交道,在中档次的计算机上有个 理想的效率,而腾出更多的 CPU 时间去完成更复杂耗时的 AI 处理,和产生图象特效. btw, 我想这种设计英文可以称作 "Leaning View",请问有没有专业一点的译法?

云风的工作刚刚开始, 写这个系列文章和引擎的开发基本同步, 而且是没有什么 实践经验, 所以错误在所难免, 文章可能也会反复修改甚至将以前的东西 全部推倒重来. 其中所有的观点,算法属于云风个人的看法, 欢迎批评指正, 可别动不动就说我在误人子弟哟 ;-)

OK. 废话少说, 让我们开始迈开第一步.

视角的选择和坐标变换


斜视角图象的处理, 在程序设计上的一大难点在于它的世界中坐标反映在2D屏幕上需要做一些变换.45 度视角的 Tile (3470字节) Isometric Tile 游戏中的 X 轴一般是从左上指向右下, 沿 35 度角左右的方向(如果是 45 度视角的话), 每个 Tile 的底面在屏幕上看起来就象菱形,整个 Tile 是一个六面体 (见右图). x 轴和 y 轴成 90 度. 32:15 的 Tile (1468字节) 这是个不错的角度, 但在设计 Isometric Tile 的时候, 更好的角度是 26 度 (arc tan 0.5), 对应的视角是 30 度. 看起来更扁一些, 32:15 的 Tile 设计随处可见(如左图), 因为 32 对计算机处理来说可是个很方便的数值.(所谓视角, 这里指视线和水平面的夹角, 特别的, 游戏中大多采用的都是俯视的视角, 如果你需要将坐标轴同水平线的角度转换为视角,可以将其取 tg,再来次 arc sin) 在 Isometric Tile Engine 的设计中, 使用什么角度的视角并不重要, 程序代码基本相同,只对于美工是不同的. 但是经过这几天的思考, 我发现斜视角(非 Tile) 的引擎设计中如果能采用比较合适的角度, 引擎的速度将有很大的提高, 这个最合适的角度就是 37 度 (arc tan 0.75) 视角大约 48 度. 在这个角度下, 游戏中的 X, Y 轴, 和屏幕上 X,Y 轴的转换关系正好为勾三股四弦五的关系, 这在我们需要的大量坐标转换的工作中提供了加速运算的可能 ;-) 游戏中的 X 轴上一个单位,相当于屏幕 X 的 0.8 个单位, Y 的 0.6 个单位的变化. 游戏中的 Y 轴上一个单位,相当于屏幕 X 的 -0.8 个单位, Y 的 0.6 个单位的变化. 就是说我们的 Sprite 在游戏中移动 aX+bY, 在屏幕上就移动了 0.8(a-b)X+0.6(a+b)Y

坐标转换示意图 (2781字节) 现在让我们来看看屏幕, 假如我们选择 640x480 的分辨率. Aha, 640:480=4:3 就有这么好的事 ;) 那么在游戏坐标系中的一条水平线正好是屏幕的对角线, 这使得判断游戏世界中的一个坐标点是否在屏幕区域内变的很简单 ;-) 请看左图, 外菱形框是游戏世界中的一矩形部分,中间的矩形框表示屏幕区域. 我们的屏幕坐标从左上角的 (0,0) 到右下角的 (639,479) 为了好说明问题, 将游戏世界的坐标原点也定在屏幕的左上角, ok, 现在来算一下屏幕四个角对应的游戏世界的坐标. 由于屏幕对角线长 800, 那么右上角的坐标是 (400,-400); 左下角是 (400,400); 右下角是 (800,0). 决定一个点是否在屏幕内的根据是 0≤X+Y≤800, 就这么简单.

最后谈谈引擎设计时的优化, 我们在坐标变换时, 使用最多的运算是除5. 而除法指令是最慢的, 有没有办法优化呢? 针对我们的作用数值并不是很大的情况这个运算可以达到最快的速度. 即用 *205/1024 代替 /5 而 205=(1+5*8)*5 , 386 以上的 CPU 计算 *5 *8 等都可以利用 LEA 指令, 非常的快. 右移 10 位就可以代替 /1024, 这个不用我多说了吧 ;-) 当然现在的 C 语言编译器将优化选项开到最大时, 会自动帮你做优化, 不用你写内嵌汇编的. 如果实在是想自己写,大概是这么几行:

        mov edx,eax              ; eax 里是被除数 a
        lea eax,[edx+4*edx]      ; eax = 5*a
        lea eax,[edx+8*eax]      ; eax = a+8*eax = 41*a
        lea eax,[eax+4*eax]      ; eax = 5*eax = 205*a
        sar eax,10               ; eax = 205*a/1024

注意:如果用 C 语言写, 最好写将 /1024 直接写成 >>10, 虽然 /1024 会被优化成右移操作, 但除法是有四舍五入的, 所以编译器在优化时,将多考虑些东西,而多几条指令.

担心计算的精度吗? 大可不必, 205/1024=0.200195 就是说, 一个点有 0.000195 的误差, 这样,即使积累到 800 个点 (屏幕的对角线,就是最长的线啦) 也才 0.17 点的误差, 而屏幕上的坐标是整数的,所以没有影响. 你可以很容易的验证, 就算使用 1280x1024 的分辨率也是没有问题. <script language=javascript src="../gbook.js"></script>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值