mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-01-13 22:30:37 +08:00
RP
@aREversez https://linux.cn/article-14945-1.html 辛苦了,这篇虽然一定曲高和寡,但是确实非常有价值。
This commit is contained in:
parent
3c07d536b5
commit
74a5290a91
@ -4,12 +4,14 @@
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "aREversez"
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-14945-1.html"
|
||||
|
||||
在《毁灭战士》中应用二叉空间分割(BSP)是何等天才之举?
|
||||
======
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202208/19/161257n99vkniexsjdehvh.jpg)
|
||||
|
||||
1993 年,游戏开发公司 id Software 发行了一款第一人称射击游戏 《<ruby>毁灭战士<rt>DOOM</rt></ruby>》,游戏一经发行迅速爆火。在今天看来,《毁灭战士》可谓有史以来最具影响力的游戏之一。
|
||||
|
||||
《毁灭战士》发行之后的第十年(2003 年),记者 <ruby>大卫·库什纳<rt>David Kushner</rt></ruby> 出版了一本关于 id Software 的书,书名为《<ruby>Doom 启示录<rt>Masters of Doom</rt></ruby>》,后被奉为记录毁灭战士创作史的典范读物。几年前我曾读过这本书,如今内容已记得不太真切了,但是书中有一个关于 id Software 首席程序员 <ruby>约翰·卡马克<rt>John Carmack</rt></ruby> 的故事,我印象特别深刻。这里只对故事做粗略描述(具体情节请往下阅读)。实际上,早在《毁灭战士》开发前期,卡马克就发现自己为这款游戏编写的 3D 渲染器在渲染某些关卡时慢得像爬一样。对于《毁灭战士》这一对动感和速度有着相当高要求的射击游戏来说,这是一个非常严重的问题。意识到了这一问题的严重性,卡马克需要一个更加有效的渲染算法,于是他开始阅读相关论文。最后,他实现了一种叫做“<ruby>二叉空间分割<rt>binary space partitioning</rt></ruby>(BSP)”的技术,极大地提升了《毁灭战士》游戏引擎的运行速度,而这项技术此前从未用于电子游戏当中。
|
||||
@ -44,13 +46,13 @@ BSP 树是计算机图形领域最具挑战性难题的解决方案之一。举
|
||||
|
||||
对于强调物体的渲染器来说,可以使用 Z 缓冲区来解决 VSD 问题,比较简单。每次将物体投射到屏幕上时,需要对每个用于绘制的像素点进行检查。如果你想绘制出的物体的部分和已经绘制在目标像素点上的物体相比更加靠近玩家,可以将其覆盖。否则,必须保持像素不变。尽管办法很简单,但是 Z 缓冲区对内存的要求较高,而且渲染器可能仍然要花费大量的 CPU 资源来投射玩家永远不会看到的水平几何体。
|
||||
|
||||
在 20 世纪 90 年代,使用 Z 缓冲区的方法还存在着其他缺陷:IBM 兼容个人电脑(PC)搭载的是一种叫 VGA 的显示适配器系统,在这类电脑上,将图像写入帧缓冲区的成本非常之高。因此,在只会以后被覆盖的像素上绘制花费的时间拖慢了渲染器的性能。
|
||||
在 20 世纪 90 年代,使用 Z 缓冲区的方法还存在着其他缺陷:IBM 兼容机(PC)搭载的是一种叫 VGA 的显示适配器系统,在这类电脑上,将图像写入帧缓冲区的成本非常之高。因此,在只会以后被覆盖的像素上绘制花费的时间拖慢了渲染器的性能。
|
||||
|
||||
考虑到将图像写入帧缓冲区的成本非常之高,理想的渲染器需要首先绘制离玩家最近的物体,接着是比较近的物体,以此类推,直到屏幕上每个像素点都写入了信息。这时,渲染器会停止运行,大幅缩短远处不可见物体的渲染时间。这种由近及远对物体进行排序的方法也可以解决 VSD 问题。那么问题又来了:什么才是玩家可以看到的?
|
||||
|
||||
最初,卡马克打算依靠《毁灭战士》的关卡布局来解决 VSD 问题。首先用渲染器绘制出玩家目前所在房间的墙壁,之后玩家冲进隔壁房间,再绘制出隔壁房间的墙壁。由于每个房间互不遮挡,这一办法也能解决 VSD 问题。而互相遮挡的房间可以分割成若干互不遮挡的“区域”。在 YouTube 上的一个 [视频][2] 中,Bisqwit 展示了自己制作出来的使用了相同算法的渲染器。可以看到,如果以超慢的速度运行,便能一睹渲染的具体过程。这一算法同样运用到了《毁灭公爵 3D 版》当中,这款游戏在 《毁灭战士》 推出三年之后发行,当时 CPU 的性能也更加强大了。1993 年,尽管在硬件上已经可以运行游戏了,但是使用这一算法的《毁灭战士》渲染器在复杂的层级结构上依旧表现吃力,尤其是在房间分割出来的各部分相互嵌套的情况下。不巧的是,这类层级结构正是构造环形楼梯等物体的唯一办法。沿着环形楼梯走下去,直到走入已经绘制好的区域,由于这其中涉及多次循环下降运动,导致游戏引擎的运行速度大幅降低。
|
||||
|
||||
在 id Software 团队意识到《毁灭战士》游戏引擎的速度可能过慢时,公司还面临着其他任务:将《德军总部 3D 版》移植到超级任天堂游戏机(简称“超任”)上。那时,超任的性能比 IBM 兼容个人电脑还要差。结果表明,尽管光线投射渲染器非常简单,但是想要在超任上快速运行是不可能的。于是,卡马克着手研究更为高效的算法。事实上,也正是为了顺利将《德军总部》移植到超任,卡马克首次研究了二叉空间分割技术,并将其付诸应用。由于《德军总部 3D 版》的墙壁与坐标轴平齐,所以二叉空间分割技术应用起来也比较简单直接;但是《毁灭战士》的情况则比较复杂。不过,卡马克发现,二叉空间分割树同样可以用来解决《毁灭战士》速度过慢的问题。
|
||||
在 id Software 团队意识到《毁灭战士》游戏引擎的速度可能过慢时,公司还面临着其他任务:将《德军总部 3D 版》移植到超级任天堂游戏机(简称“超任”)上。那时,超任的性能比 IBM 兼容机还要差。结果表明,尽管光线投射渲染器非常简单,但是想要在超任上快速运行是不可能的。于是,卡马克着手研究更为高效的算法。事实上,也正是为了顺利将《德军总部》移植到超任,卡马克首次研究了二叉空间分割技术,并将其付诸应用。由于《德军总部 3D 版》的墙壁与坐标轴平齐,所以二叉空间分割技术应用起来也比较简单直接;但是《毁灭战士》的情况则比较复杂。不过,卡马克发现,二叉空间分割树同样可以用来解决《毁灭战士》速度过慢的问题。
|
||||
|
||||
### 二叉空间分割
|
||||
|
||||
@ -102,7 +104,7 @@ BSP 树是计算机图形领域最具挑战性难题的解决方案之一。举
|
||||
|
||||
实际上,“将 BSP 树引入《毁灭战士》”意味着将 BSP 树生成器引入《毁灭战士》的关卡编辑器中。当完成一个《毁灭战士》的关卡的制作时,BSP 树就会在关卡几何图形的基础上生成。根据程序员 <ruby>法比安·桑格勒德<rt>Fabien Sanglard</rt></ruby> 的说法,在原版《毁灭战士》中,一个关卡的 BSP 树生成时间需要 8 秒,全部关卡合计共需 11 分钟 [^5]。之所以生成时间较长,部分原因在于卡马克所用的 BSP 生成算法,该算法尝试使用各种启发式方法找出 “高质量” BSP 树。在运行时,8 秒的延时可能让人无法接受;但是离线等 8 秒,时间并不算长,尤其是考虑到 BSP 树提升了渲染器的性能。为每个关卡生成的 BSP 树将在游戏启动时作为关卡数据载入。
|
||||
|
||||
卡马克对 1980 年论文中提出的 BSP 树算法进行了改造,因为在《毁灭战士》开始运行时,当前关卡的 BSP 树就会读取到内存中,渲染器通过 BSP 树由前向后绘制物体,而非由后向前进行绘制。福克斯三人在那篇论文中演示了 BSP 树可用于执行由后向前的画家算法,但是画家算法会造成许多重复的绘制任务,对于 IBM 兼容个人电脑来说负担较大。因此,《毁灭战士》的渲染器换了个方向,首先绘制距离玩家较近的图形,之后再绘制离玩家较远的。这种反向排序很容易通过 BSP 树来实现,因为你可以在树的每个节点都进行反向遍历。为了避免绘制出来的远处图形遮挡到近处的图形,《毁灭战士》的渲染器使用了一种隐式 Z 缓冲区,这种缓冲区不仅具备普通 Z 缓冲区的优势,而且对内存的要求也较低。这种 Z 缓冲区有两组数组,一组记录水平方向的遮挡关系,另两组记录自屏幕顶部和底部的垂直方向的遮挡关系。《毁灭战士》的渲染器就算不使用实际的 Z 缓冲区也无伤大雅,因为从技术上来看它并不是真正的 3D 游戏。BSP 树数据结构的成本虽然不高,但却能够起作用,其原因在于《毁灭战士》不会发生以下问题:水平方向的遮挡数组能够发挥作用,是因为该游戏中没有倾斜的墙体;垂直方向的遮挡数组能够发挥作用,是因为该游戏不存在有着一上一下两扇窗户的墙体。
|
||||
卡马克对 1980 年论文中提出的 BSP 树算法进行了改造,因为在《毁灭战士》开始运行时,当前关卡的 BSP 树就会读取到内存中,渲染器通过 BSP 树由前向后绘制物体,而非由后向前进行绘制。福克斯三人在那篇论文中演示了 BSP 树可用于执行由后向前的画家算法,但是画家算法会造成许多重复的绘制任务,对于 IBM 兼容机来说负担较大。因此,《毁灭战士》的渲染器换了个方向,首先绘制距离玩家较近的图形,之后再绘制离玩家较远的。这种反向排序很容易通过 BSP 树来实现,因为你可以在树的每个节点都进行反向遍历。为了避免绘制出来的远处图形遮挡到近处的图形,《毁灭战士》的渲染器使用了一种隐式 Z 缓冲区,这种缓冲区不仅具备普通 Z 缓冲区的优势,而且对内存的要求也较低。这种 Z 缓冲区有两组数组,一组记录水平方向的遮挡关系,另两组记录自屏幕顶部和底部的垂直方向的遮挡关系。《毁灭战士》的渲染器就算不使用实际的 Z 缓冲区也无伤大雅,因为从技术上来看它并不是真正的 3D 游戏。BSP 树数据结构的成本虽然不高,但却能够起作用,其原因在于《毁灭战士》不会发生以下问题:水平方向的遮挡数组能够发挥作用,是因为该游戏中没有倾斜的墙体;垂直方向的遮挡数组能够发挥作用,是因为该游戏不存在有着一上一下两扇窗户的墙体。
|
||||
|
||||
剩下比较棘手的问题是如何将《毁灭战士》中处于运动中的角色融入到借助 BSP 树绘制的静止的关卡几何图形中。该游戏中的敌人不可能纳入 BSP 树之中,因为他们会移动,而 BSP 树只对静止的几何形状起作用。所以渲染器首先绘制静止的关卡几何图形,同时与另一个内存使用效率较高的数据结构协作,记录屏幕上分割出来用于绘制的区域。之后,渲染器按照由后往前的顺序绘制敌人,并消除被屏幕上的区域遮挡住的敌人。这一过程与使用 BSP 树进行渲染相比,效果稍差一些。但是由于关卡中能看到的敌人的数量少于几何图形的数量,所以速度并不是一个严重的问题。
|
||||
|
||||
@ -112,7 +114,7 @@ BSP 树是计算机图形领域最具挑战性难题的解决方案之一。举
|
||||
|
||||
这些“片面之词”忽视了 BSP 树的发展历史。当美国空军研究人员开始意识到场景分割可能会加快渲染任务的时候,他们就对提升 _实时_ 渲染的速度产生了兴趣,毕竟他们当时试图创建一个飞行模拟器。1980 年,同样的案例再次出现在了福克斯等人的论文中,他们探讨了 BSP 树如何应用于飞行模拟器中,帮助飞行员进行训练:飞行员用它来反复练习将飞机降至同一空港。由于空港的地形不会发生改变,BSP 树只需生成一次,即可一劳永逸。很明显,他们考虑的是实时模拟。在论文的引言部分,福克斯等人还谈到实时图形系统必须在至少 1/30 秒内生成一张图像,由此激励了他们的研究。
|
||||
|
||||
因此,卡马克不是第一个想到在实时图形模拟中应用 BSP 树的人。诚然,设想与付诸实践是两码事。但是即使在实施的过程中,卡马克受到的帮助与指导可比人们想象的要多得多。至少是到这篇文章写成之时,BSP 树的 [维基百科词条][13] 页面显示,卡马克参考了 1991 年 <ruby>陈<rt>Chen</rt></ruby> 和 <ruby>戈登<rt>Gordon</rt></ruby> 的一篇论文,以及 1990 年的一本教材《计算机图形学:原理及实践》。尽管该页面并未提供引用信息,但这可能是真的。陈和戈登的论文介绍了运用 BSP 树由前向后的渲染方法,这种方法与《毁灭战士》中用到的方法基本一致,还包括了我称之为“隐式 Z 缓冲区”的数据结构,可用于防止远处的图形在绘制时遮挡近处的图形。《计算机图形学:原理及实践》详细介绍了 BSP 树,以及一些构建并展示 BSP 树的伪代码(非常感谢我大学的图书馆,让我能够一睹这本教材 1990 年的版本)。因为这本书是计算机图形学的经典之作,所以卡马克很可能也有一本。
|
||||
因此,卡马克不是第一个想到在实时图形模拟中应用 BSP 树的人。诚然,设想与付诸实践是两码事。但是即使在实施的过程中,卡马克受到的帮助与指导可比人们想象的要多得多。至少是到这篇文章写成之时,BSP 树的 [维基百科词条][13] 页面显示,卡马克参考了 1991 年 <ruby>陈<rt>Chen</rt></ruby> 和 <ruby>戈登<rt>Gordon</rt></ruby> 的一篇论文,以及 1990 年的一本教材《计算机图形学:原理及实践》。尽管该页面并未提供引用信息,但可信度没什么问题。陈和戈登的论文介绍了运用 BSP 树由前向后的渲染方法,这种方法与《毁灭战士》中用到的方法基本一致,还包括了我称之为“隐式 Z 缓冲区”的数据结构,可用于防止远处的图形在绘制时遮挡近处的图形。《计算机图形学:原理及实践》详细介绍了 BSP 树,以及一些构建并展示 BSP 树的伪代码(非常感谢我大学的图书馆,让我能够一睹这本教材 1990 年的版本)。因为这本书是计算机图形学的经典之作,所以卡马克很可能也有一本。
|
||||
|
||||
然而,卡马克发现自己遇到一个新问题:如何让第一人称射击游戏在一台 CPU 甚至都无法进行浮点操作的电脑上运行呢?通过调查研究,他证明了 BSP 树的数据结构非常适用于实时电子游戏渲染。尽管 BSP 树早已提出,而且到了卡马克的时代,相关理论已经非常成熟了,但我始终认为,卡马克的做法可谓惊人之壮举。也许,得到人们称誉的应该是整个《毁灭战士》的游戏引擎,它的确非常精致。我在前文也提及过,但是桑格勒德的《<ruby>游戏引擎黑皮书:毁灭战士<rt>Game Engine Black Book: DOOM</rt></ruby>》 很好地讲解了这款游戏引擎的非凡之处,以及这些优势相互契合之法。要明白,VSD 问题只是卡马克在编写《毁灭战士》游戏引擎时需要解决的诸多问题之一。不得不说,面对不为大多数程序员所知的复杂的数据结构,卡马克能够查阅相关文献,将其付诸实践,仅此一点就足以说明其技术之精湛、匠心之独到。
|
||||
|
Loading…
Reference in New Issue
Block a user