译者: 神杀中龙 邵小宁 microsoftxiao@163.com 翻译的烂请见谅 原著 《Focus on 3D Terrain Programming》 Woohoo!你现在将要学习地形编程的核心部分了,它们是由难以置信的复杂算法。实际上,那是谎话。本章我将解释三个算法,因为它们的简单和高效所以选择了它们。And , for once in this book, 下面的列表是本章将要讲述的内容: n
解释持续层次细节的意思 n
geomipmapping的背后理论 n
实现geomipmapping的方法 为了简单那,
我打破了议程的三个部分。不管这些细节,本章将相当长。然而,不要让本章的长度吓到你。The content will be presented, as always, in a fun and simple manner. 注意,虽然我改变了一点学习风格。第5,6,7将集中在算法的解释上相比前几章将使用伪码表示。在以后几章,我将为你提供一些演示并且给出我的实现,但是实现是简单的,并且you should use them only in conjunction with the tex. With that said, 我们开始吧。 CLOD Terrain 101 在本书你已经听说了术语 Continuous Level of Detail(CLOD) 持续层次细节很久了,但是现在到了我告诉你实际情况的时候了。CLOD算法, in one sentence, 是一个动态多边形网格,通过增加额外的三角形来得到更多细节。这是个简单的陈述,但是读完本节你将了解更多关于CLOD的东西,并且知道本章结束。不要烦恼现在还不理解CLOD。 Why Bother with CLOD Terrain? CLOD地形为什么麻烦? CLOD算法需要更多的研究,难于编码,平均比brute force实现占用更多的CPU周期。在你脑中,为什么CLOD算法麻烦?它真的简单吗: 为了创建更真实,更多细节,更重要,更快的地形碎片。 More Detail Is Added Where More Detail Is Needed CLOD的基本思想是添加更多的细节(更多三角形)是必须的。举例来说,如果我们有一个相当光滑的地形片(看图5.1),我们将想要一个平均更少些的地形(如图5.2)。然而,不是所有更多细节的算法都很糟糕。Geomipmapping可以似的三角形不是很分散但又拥有更多细节,但是Rottger的四叉树算法(在第六章,攀登四叉树)来做。因此,话说CLOD, 总体上,添加了更多细节到区域上,但并不总是这样,但是大部分是这样的,我彻底的把你搞晕了? Cull Like You’ve Never Culled Before! 另外实际的CLOD基础算法是它们允许比brute force方法拣选更多的多边形。这意味着这些多边形发送给API但却看不见。举例来说,我们通过geomipmapping实现一系列的地形碎片。如果碎片不可见,我们排除潜在的289个被渲染的顶点(一个17x17的顶点碎片)in one fell swoop. 大量的顶点不会被加载到显卡里,而是被CPU裁剪了。使用简单的方法,我们满足GPU和CPU两者,让你的主板同时高兴。 Not Everything Is Happy In the Land of CLOD Terrain 在CLOD地形大陆不是任何事物都是愉快的 虽尽管使用CLOD地形算法有一些缺点,Oddly enough, 世界帮助我们写下了这一段在 Game Developer Magazine里。 主要确定是包括每帧更新多边形网格。 当大部分这些算法还不是很流行时(geomipmapping, Rottger’s quadtree algorithm, and ROAM)被设计。这是因为该算法想要将更多的工作量放置在CPU里而且发送了一点必要的信息到了GPU。从此一直,然而,这些东西有了一丁点的变化。现在我们需要把焦点放在GPU比CPU更多些。 Wrapping Up Your Introduction to CLOD Terrain 封装你的初级CLOD地形 明显的,如果geomipmapping, 四叉树,ROAM算法过时了,你将不会再读到它们了。 这意味着某人,某地(heck, 甚至我)哪出了一些优化的,在今天的地形渲染也是最重要的优化。随即,我将解除前面胡说的关于geomipmapping的东西。 Geomipmapping Theory for the Semi-CLOD Impaired Geomipmapping, 是Willerm H. de Boer开发,一个友好的GPU CLOD算法。它也是转变到CLOD大陆最完美的简单算法。那么我们继续前进,你也许想要查阅实际geomipmapping白皮书,我放在 CD-ROM里希望给你提供方便。(它的名字叫 /geomipmapping.pdf算法白皮书。) Simply the Basics 简单的基础 如果你熟悉mipmapping的纹理化概念,那么geomipmapping似乎是很浅显的对你来说。概念同样,除了处理纹理被取代,我们处理地形片上的顶点。推动geomipmapping概念的是你有一个地形片集合。为了解释它,我有大小为5的顶点作为一片(5x5的片)。5x5的片将有一系列的等级细节,第0级是最详细的,这样,第2级是较详细的。 看图5.3如果你需要可视化解释每个各种等级的话。在图中,黑色顶点没有被发送到渲染API, 但是白色被发送到了。 如果查阅了Willern de Boer的geomipmapping的白皮书,你也许注意到图5.3和白皮书里展示的一点不同。原因是我做的改变了一点为了更清晰,但是现在,just know that I did it for a reason. 到了我们讨论更多geomipmapping的时候了。我前面已经给介绍了些基础,但是现在到了你知道所有东西的时候了…. 好,几乎所有东西。我也许会保留些信息。 [译者注: Mip Mapping (Mip贴图) 这项纹理贴图的技术,是依据不同精度的要求,而使用不同版本的材质图样进行贴图。例如:当物体移近使用者时,程序会在物体表面贴上较精细、清晰度较高的材质图案,于是让物体呈现出更高层、更加真实的效果;而当物体远离使用者时,程序就会贴上较单纯、清晰度较低的材质图样,进而提升图形处理的整体效率。LOD(细节水平)是协调纹理像素和实际像素之间关系的一个标准。一般用于中、低档显卡中。 注意 Mip-Mapping和三线性过滤有区别。] [ 译者注 MipMapping 和三线性区别 Mip-Mapping
我第一次看到Mip-mapping技术是在游戏QUAKE里,而现在这种技术早已是随处可见了。这种技术是由Williams在1983年发明的,“Mip”这个名称起源于“multum in parvo”,大概就是在一小块地方有很多东西的意思。
具体说来,Mip-Mapping的思想就是构建一套纹理,总共需要大约1.3倍的内存。其中,每块子纹理是通过对父纹理过滤而得到,它的长和宽都是其父纹理的1/2,其面积为父纹理的1/4。接下来,在应用的时候,你根据距离选取最合适的一块来进行映射,实践证明,这种技术虽然简单,但对提高纹理映射的质量确实非常有效。
通过Mip-Mapping,可以为较小的多边形映射上面积较小的纹理,这对减少纹理的扰动大有好处。举个例子,你有一块256x256大小的纹理,当它开始向远离观察者的方向开始移动时,你会看到它开始闪烁和颤动。这种现象的出现是因为我们把一大块纹理映射到一个很小的区域而引起的。你可能在上一帧时,画的是纹理中(50,20)处的像素,到了下一帧,却画的是纹理中(60,30)处的像素。如果这两个像素相差很大,你就会观察到前面所说的现象了。总的来说,这种剧烈的纹理座标的变化,会损害图像的品质,并且影响CACHE的效率,而Mip-Mapping无疑是解决这个问题的好办法。
Tri-linear Interpolation
在介绍了双线性插值和Mip-Mapping以后,该来讲讲三线性插值了。其实三线性插值也很简单,它就是前两种技术的结合。它在对Mip-Mapping的每块纹理做双线性插值的同时,还要对Mip-Mapping中相邻的两块纹理按距离再做一次插值。既算出较大的一块纹理上的某点双线性插值像素值和较小的一块纹理上的某点双线性插值像素值,再按目标同两块纹理的距离做一次类似的插值。
使用三线性插值,可以消除Mip-Mapping里纹理切换(既上一帧时用的是某个大小的一块纹理,而下一帧时又换了一块的情况)时的突然变化,从而可以提供很平畅的高质图像输出。
同前两种技术相比,三线性插值的运算量非常大,目前只能依靠硬件来实现。 原文链接: http://www.chinagcn.com/blog/?43/viewspace-702 ] 正如我前面说的,geomipmapping与纹理的MipMapping类似除了我们使用陆地片来替代纹理片。我们需要怎么做呢,从3D空间用户的出发点(摄影机眼睛的位置), 使所有的片的大部分细节都围绕者摄影机因为这些片是用户看得见的。 At a certain distance way, 我们将片切换到低的细节上。而更远的距离,我将切换到甚至更低的细节。图5.4是可视化解释。 如图所示,这些片是摄影机位置处的细节层次(LOD)为0,以为这这些片是最高等级的细节。这些片一旦拉远,细节将调整到1,是第二高的细节。如果距离摄影机更远的话,片将降低到等级2,是图中最低的细节。 Triangle Arrangement Made Easy 前面,你也许注意到5.3排列出的三角形不同于我提供给你的geomipmapping paper中的排列。这种情况你不需要立刻访问白皮书,看图5.5看,论文的建议三角形这么排列。 这个排列也许像更好的想法,and it is for the most part. (警告: I’m going to get slightly sidetracked right here.)三角形带如果你计划使用顶点缓冲渲染片的话,这是我给你的建议。然而,因为使用顶点缓冲区进行渲染辉高度依赖API,我选择使用直接渲染模式因为它更容易转换到其他API语法。使用顶点缓冲区渲染对地形实现来说更高速因为它的函数当你发送每个顶点,纹理坐标,颜色等到API时是单独的。另外,大部分图形卡更喜欢每个顶点信息被发送到顶点缓冲的形式。最后,我推荐你使用顶点缓冲区渲染地形。你将获得极大的速度,完成这个是相当有价值的。如果你喜欢看一个Direct3D顶点缓冲区实现geomipmapping-esque的例子,可以看“Simplified Terrain Using Interlocking Tiles”在 Game Programming Gems, 卷2里。 总之,该回到前面的话题了。如图5.3是我们将要渲染好的排列好的片。这个排列对我们来说是非常有益的:它允许我们更容易的跳过被渲染的顶点当我们需要时,which is quite often. 接着下一个话题。 Hacks and Cracks, But Mostly Just Cracks 砍,爆裂,砍,更多爆裂 常常当你处理CLOD地形算法时,你必须处理裂缝的问题。裂缝出现,在geomipmapping出现这种情况,当高细节挨着低细节时(看图5.6)。 正如你看到的图,片左边比右边细节高。我们的问题位于点A和B。问题是当A点比B细节高时,这意味着左边的精确度高于A点,但是右边的片刚刚是从那个高度平均过来的位于高度之下。这个破裂的东西也许不像个大问题,但是图5.7所示,展示了我的geomipmapping 实现没有裂缝吗? 这不是一个平滑的地形,是吧?这是所有洞穴的景色。我们来解决它! Crack-Proofing Your Geomipmapping Engine 你的Geomipmapping引擎裂缝实验 裂缝穿透你的geomipmapping地形是比听着来的容易。你添加些有意的东西(that would be me)解释这个概念给你,整个处理过程是容易的… 好,好像是容易的。 我有两个可能的解决裂缝问题的方法。一个方法是在低细节地方添加顶点片以至于这个片区域将达到和高细节区同样的细节等级。这个解决方法是丑陋的,可是,它意味着我们必须对片进行重排列(添加其他的三角形扇)。 另外的方法是从更多细节片内删掉顶点。这个方法更有效一些。看图5.8看删掉顶点多么容易解决裂缝。 Where Art Thou Crack? 你在哪里裂缝了? 你知道怎么导致裂缝和怎样解决它们。真正的问题是: 你如何确定它们?基本上,当你当前渲染片,你需要测试片周围(看图5.9)看是否有低细节。如果它们是,你知道你需要忽略一些顶点了。 测试每个片不困难。你将需要实现一系列的简单的if-else语句。(Pseudo-code如下). If LeftPath.LOD is less than CurrentPath.LOD RenderLeftVertex = true; Else RenderLeftVertex = false; If RightPath.LOD is less than CurrentPath.LOD RenderRightVertex = true Else RenderRightVertex = false; If UpperPath.LOD is less than CurrentPath.LOD RenderUpperVertex = true; Else RenderUpperVertex = false; If LowerPath.LOD is less than CurrentPath.LOD RenderLowerVertex = true; Else RenderLowerVertex = false; 看多么简单啊?之后测试,渲染你的三角形扇,你跳过粗糙片的方向顶点。例如,右边片是低级等级的,那么你的当前片是高等级细节(行列翻倍被渲染), 那么你仅仅想要跳过这些顶点到远处的片(看图5.10)。 警告: 注意你省略的仅仅是必须的顶点。否则,你将结束整个片而不意味着省略。例如,图5.10, 片由多行多列组成的三角形扇。你不想省略右边的顶点;你仅仅想省略右边的顶点在最右列。 这是你简单的geomipmapping理论!现在到我们实现我们学过所有东西的时候了。 Implementing Geomipmapping for the Very Slightly CLOD Impaired 实现Geomipmapping CLOD 你了解了geomiapping背后的基础,但是现在我们需要实现它。这将使你的大脑负担太重。做完它将是最难的部分,照常,我们将每次做一步。来点咖啡,锁好你的们,然后来点好听的音乐! Path It Up 拼凑 由于geomipmapping是由一系列碎片组成的,大概可以从一个好的想法出发,创建一个patch数据结构。这个结构不需要包含太多信息,而且我们至少需要包含,最好。实际上,这将是从本书里你见过的最小的结构。不要太习惯漂亮的大小! 所有的patch结构真的只需要两个变量。一个变量将记录当前细节等级,另一个变量存储从patch到摄影机的位置的距离。保持头脑正常!整个patch数据结构。在这里,代码: struct SGEOMM_PATTH { float m_fDistance; int m_iLOD; }; 它也许是微笑结构,但是记住: 大东西将由小东西组成。虽然小,我们将经常使用它,所以确认你已经花了几小时记住它的成员。 Creating the Basic Geomipmapping Implementation 创建基本的Geomimapping实现 Yeah, 两个成员的数据结构不要哭哭啼啼的。现在我们将开始geomipmapping引擎的重负荷工作——geomimapping类。开始,我们需要获得我们的patch信息指针,我们将动态的分配一些指针在我们的demo内。继续,我们需要计算出patch大小(顶点数)和地形的边需要多少个patchs。 警告 geomipmmaping实现是基于2的N次方+1个像素块高度图。这意味着你不能使用midpoint displacement不规则高度图产生高度图。所有你的高度图只能使用fault formation产生。 |