Origin
zhuanlan.zhihu.com
Tags
简悦
项目
收藏夹
创建时间
收藏类型
Cubox 深度链接
更新时间
原链接
描述
00 背景
我们将描述在《使命召唤》中如何创作和渲染大规模地形。系统受到了 2015 年 GDC 上展示的早期工作的启发,并在此基础上进行了建设。将讨论如何将虚拟化的概念扩展到了地形纹理之外。还将讨论如何使系统从低端移动设备扩展到高端 PC。
现在《使命召唤》中使用的地形技术最初是由 Treyarch 的 JT Hooker 和他的团队在多年前实施的。
- 在他 2021 年的 GDC 演讲中,名为 “Boots on the Ground”,JT 展示了《使命召唤冷战》时的超级地形技术。
- JT 详细介绍了超级地形的创作过程。
- 本文不会详细讨论超级地形技术的各个方面,特别是任何关于创作的内容。你可能需要参考当时的演讲了解更多内容
01 地形
超级地形实际上是一系列地形表面的集合。
- 每个紫色矩形都是一个地形表面。每个红色部分都是一个兴趣点,它有自己的地形表面。
- 有如此多的地形表面的一个原因是,可以在同一地图上进行并行开发。
- 另一个原因是可以有不同数量的细节。
地形表面有几个限制。
- 它们不能被缩放或旋转。它们也必须是正方形。这使得代码更简单和更快。
- 红色的地形看起来被旋转和非正方形。这是通过使用切割体积来实现的,这是稍后会介绍的。
地形技术大量使用四叉树。
- 每个地形表面都有一个四叉树。
- 在每个节点,存储顶点和索引缓冲区,这些缓冲区必须在节点可以被渲染之前加载。
- 不需要渲染的节点,不会加载任何顶点或索引数据。
地形表面包含一个高度图和一个四叉树。在四叉树的每个节点,都有一个地形块。在最低级别,地形块使用程序生成的顶点,所有顶点都放置在一个规则的网格上。在分支处,通过一个网格简化器处理我们的网格。网格简化器为每个顶点输出两个浮点数,一个 X 和一个 Y。Z 通过采样高度图来重建。这使得能够以较少的顶点保留大量的细节。视觉质量上有所提升,在性能上也有所提升,因为 GPU 更喜欢大的三角形而不是小的三角形。
地形块也引用了它们的低分辨率网格。当摄像机远离网格时,顶点会向它们的低分辨率对应部分插值。当摄像机足够远离网格,并且所有顶点都已经塌陷到低分辨率网格时,我们切换到低分辨率网格。
这里所说得最低级别应该是 LOD0,见图,近处是规则的网格,远处是低分辨率网格。
在创作地形时,艺术家们通常会使用剪切体积来标记他们不想要地形的世界区域。
低分辨率的远景地形可以为另一个更密集的地形(可玩区域)腾出空间。它也被用来在地面上打洞以形成洞穴,或者在地形上放置建筑物。剪切体积被烘焙成每个地形一个剪切纹理图。剪切纹理图非常节省内存。它每个顶点只需要 1 位。单个字节编码 8 个顶点的可见状态。
02 材质
地形表面由称之为地形层的材质集合构成。
典型的地形层可以是草地、沙地、土地等。在最初实现地形技术时,每个地形层都使用了一个 alpha 遮罩。只支持 32 个地形层,但由于所有这些 alpha 遮罩都需要加载,所以仍然占用了大量的内存。这也意味着着色器的成本是不可预测的。大多数像素可能只使用了 1 层,但没有什么能阻止所有 32 层都被用来给单个像素着色。除此之外,32 的限制太低,需要增加这个数值。
在《黑色行动:冷战》中,Treyarch 用他们创新的技术替换了层遮罩,这种技术被他们称为每顶点一种材质(One Material Per Vertex,简称 OMPV)。OMPV 使用一个索引图,每个像素持有一个字节,以及一个颜色图,每个像素持有一个 RGB 值。有了 OMPV,层遮罩就消失了,而且由于颜色是 BC1 压缩的,显著的节省了内存。在每个像素处,索引图记录最突出的层。颜色图实际上是一个颜色色调,意味着要被那一层使用。
使用 OMPV,为了给这里的纹素 T 着色,着色器代码会收集四个周围顶点的索引和颜色。
我们计算一个 alpha 值,定义每个顶点的贡献。纹素 T 离顶点越近,该顶点的 alpha 值就越大。
每个顶点的索引指向一个地形层。由于每个顶点可能引用同一层,我们可以通过求和他们的 alpha 值来加速处理重复的层。如果所有顶点恰好都引用同一层,这实际上是常见的情况,我们不需要对同一材质进行 4 次采样,只需采样一次。
由于 JT 在他的 GDC 演讲中详细解释的不明确的条件,我们将 alpha 乘以 2 并限制在 0 到 1 的范围内。
然后我们使用艺术家创作的揭示图来混合所有层,以便他们可以控制混合过程。并非所有的层都是相同的。层按照他们的索引排序,索引最低的层是主层,永远不会被混合。它的 alpha 值始终为 1。
然而,OMPV 也有其自身的问题。第一个问题和像素化外观有关。
在这里的右上图像中可以清楚地看到。
为了解决这个问题,使用全局的 256x256 扭曲图来扭曲 UVs,如这里所示。艺术家可以控制每级的扭曲幅度和频率。这是一个全局的设置,在采样索引和颜色图之前,UVs 就已经被扭曲了。
不仅在 OMPV 中存在,当地形层在地图的大片区域中使用时,平铺伪像会变得明显。
解决这个问题的方法是使用一种称之为 “平铺隐藏” 的技术。在每个顶点,根据该顶点的世界位置计算一个随机旋转。这个旋转是一个整数,在 0 到 15 的范围内,解释为弧度中的角度。平铺隐藏在隐藏平铺伪像方面非常有效,但由于增加了旋转,无法再合并重复的地形层,除非它们恰好有相同的随机旋转。在顶部的图片中,由于大多数顶点都会引用草地材质,所以给一个像素着色通常只需要采样一次草地材质。但在进行平铺隐藏后,由于 4 个顶点可能具有不同的旋转,给一个像素着色将需要采样 4 次草地材质,每次使用不同的 UVs。尽管如此,视觉质量的提高仍然是非常值得的。
在地图的大片区域上使用相同的纹理的另一个问题是,从远处看,最高 mip 的所有细节最终都会塌陷为单一的颜色。
解决这个问题的方法称为 Vista UVs。使用 Vista UVs,计算一组第二 UVs,这组 UVs 很简单,就是原始的 UVs 集,除了缩小一些,以放大被采样的纹理。再次采样反照率和法线来计算宏观贡献。使用相机距离在常规贡献和宏观贡献之间进行插值,以计算最终贡献。在某些类型的内容,如岩石,Vista UVs 在从远处观看内容时能够创造出有趣的细节。
OMPV 的另一个问题是从一种材质过渡到另一种材质时的尖锐过渡。这里展示了从泥土过渡到沙子时会发生什么。
迄今为止使用的解决方案是让艺术家手动制作过渡材料。这种方法效果很好,但是它是一个人工密集的过程。由于每个过渡都是一套全新的纹理,它给我们的纹理流系统增加了压力,并消耗了宝贵的内存。
目前正在实施一个解决这个问题的方案,称之为多层地形材质或简称 MLTM。多层地形材质需要 2 个输入地形材质,以及一个用于混合这两种材质的阈值。目标材质的揭示图被用来完成混合。
本质上,这就像在 Photoshop 中制作过渡,但是没有内存成本。所有这些都是在运行时完成的。这确实增加了着色器的成本,但由于过渡材质只在过渡期间使用,所以这是可以接受的。
03 虚拟贴图
虚拟纹理是一种在运行时模拟非常大的纹理的过程。
虚拟纹理的工作方式类似于虚拟内存模拟一台拥有比实际更多物理内存的计算机,可以用来模拟一种比其他方式可能更大的纹理。这种模拟的关键是两种纹理:首先,物理纹理,它包含了非常大的纹理的页面。页面是模拟纹理或其 mips 的一个小的方形部分。页面通常是 256x256 像素,但它可以是你想要的任何大小。其次,有一种间接纹理,它包含了足够的信息来重定向 GPU 去采样存储在物理纹理中的纹理数据。间接纹理的一个像素将指向物理纹理中的一个页面。例如,一个 4K4K 的物理纹理的 256x256 页面乘以一个 2K2K 的间接纹理可以用来模拟一个 512K*512K 的纹理。
虚拟纹理通常被称为程序化虚拟纹理,因为模拟的纹理是材质和其他绘图原语的程序化组合的结果。在这个演示中,省略了程序化这个词,但重要的是要记住,模拟的纹理是一个复杂混合过程的结果,并不存在于磁盘上。
虚拟纹理非常擅长模拟由于其大小而无法适应 GPU 的大纹理。然而,它们仍然太小,无法模拟巨大的纹理。例如,前一张幻灯片中的 512K 乘以 512K 的虚拟纹理,只能覆盖大约 0.3 乘以 0.3 英里的区域,分辨率为每英寸 25 像素。
对于更大的虚拟纹理,育碧的 Ka Chen 在他的 2015 年 GDC 演讲中提出了自适应虚拟纹理。从现在开始,将自适应虚拟纹理简称为 AVT。AVT 可以模拟最多 24 个 mips 的纹理。在每英寸 25 像素的分辨率下,这足以覆盖 10.6 乘以 10.6 英里的区域。在核心,世界被切割成大约 210 乘以 210 英尺的区域。每个区域由一个虚拟图像管理,本质上是一个常规的虚拟纹理。那个虚拟图像的大小是动态的。它随着相机距离的变化而变化。这就是为什么它被称为自适应虚拟纹理。
一个虚拟图像最多有 16 个 mips。有了 16 个 mips,我们可以以每英寸 25 像素的分辨率覆盖 210 乘以 210 英尺的区域。只有相机周围的区域被激活。最多只支持 255 个区域。还有一个默认区域覆盖了整个世界。默认区域总是使用一个 16 个 mips 的虚拟图像。
在这三张截图中,可以看到虚拟图像被创建。屏幕左上角的正方形是间接纹理的表示。它只有 512 乘以 512 像素。浅绿色的默认区域占据了左上角。虚拟图像从那个间接纹理中为自己分配空间。同样的颜色方案用于给地形着色,这样就可以看到哪个区域控制了地形的哪个区域。当接近一个区域时,你可以看到它的虚拟图像变得更大。当离开一个区域时,它的虚拟图像会缩小。
虚拟图像四叉树比普通四叉树更复杂,因为它跟踪 GPU 可用的页面。当扩展四叉树的一个分支时,一些子节点可能没有自己的页面。因此,它们必须指向父页面。这在这张图片中得到了说明。
例如,在深度 1 处,根页面的子节点被扩展,因为必须创建棕色的子节点,给它一个页面。其他 3 个子节点简单地引用父页面。每一帧,页面可能变得可以供 GPU 使用,或者相反,页面可能变得不可用。当一个新页面被合成时,四叉树在下一帧才更新。这是因为我们不能冒险告诉 GPU 在页面被合成时开始使用它。当一个页面没有被请求时,它会在缓存中老化。它从四叉树中移除,但我们保证页面至少在 3 帧内不会被回收。这足以确保 GPU 不会使用正在被回收的页面。
CPU 版本的四叉树对于 GPU 来说过于复杂,无法直接使用。因此,我们将四叉树烘焙在一个间接纹理中。每一帧,游戏都会计算前一帧四叉树和当前帧四叉树之间的差异。这些差异被转化为命令,然后由一个计算着色器处理,这个计算着色器会更新间接纹理。这张图片展示了从 GPU 的角度看 CPU 四叉树是什么样的。
当摄像机靠近一个区域时,游戏可能会决定需要添加一个新的 mip。它首先从主间接纹理中分配一个更大的子间接纹理。然后,它使用与更新帧间间接纹理相同的过程来填充它。当摄像机远离时,反向的过程就会发生。也就是说,mips 会从间接纹理中移除。
间接纹素是一个 32 位的值,提供物理页面的坐标。它还指定了页面的 mip 级别和四叉树的宽度。所有这些信息都是从扇区 UVs 转换到物理页面 UVs 所必需的。这里的代码片段展示了如何将扇区 UVs 转换为物理页面 UVs。
我们有工具可以帮助在游戏中调试和可视化间接纹理。地形上的每个方块只是将 32 位间接像素解释为反照率颜色。通常,这些会被物理页面填充。
地形在预处理和不透明处理期间都会被渲染。在预处理期间,地形会写入深度缓冲区和为超级地形保留的模板位。我们还将几何法线写入一个 gbuffer。在不透明处理期间,地形使用全屏四边形进行延迟渲染。所有设置了模板位的像素,都会从虚拟纹理中采样以着色当前像素。
虚拟纹理的一个核心方面是它由 GPU 驱动。在不透明处理期间,当它为每个像素着色时,它也会计算如果可用的话,它希望使用的物理页面。这个信息被存储在一个反馈缓冲区中,反馈缓冲区在 3 帧后由 CPU 读回。它的分辨率是 240x136 像素,但我们正在研究在低端硬件上使用更小分辨率的反馈缓冲区。出于性能原因,没有线程同步。
在不透明处理期间,每个地形像素都会将一个 32 位值写入反馈缓冲区。它会写入它希望使用的虚拟纹理的 mip 等级,像素的扇区 ID,以及它希望使用的间接纹理四叉树节点的四叉树坐标。反馈缓冲区最困难的部分是 mip 等级。它是通过查看 UV 梯度来计算的。这段代码片段说明了我们做了什么。
一旦 GPU 完成对反馈缓冲区的写入,CPU 就会读取它。考虑到反馈缓冲区的分辨率是 240x136,这意味着我们处理大约 32000 个值。首先,计算所有唯一值的数量。然后,将子节点的计数传播到它们的父节点。这是为了确保如果子节点的命中次数不够,希望父节点的命中次数会足够。然后按照受欢迎程度进行排序。我们希望最多被请求的页面首先被合成。
对扇区的根页面进行偏置,这样如果一个扇区在任何程度上都是可见的,那么至少有 1 个页面对应那个扇区。也根据相机的速度对高分辨率页面进行偏置,高速移动时有些页面是不值得合成的。
考虑到反馈缓冲区是由不同步的线程更新的,它可能会有噪声。通过使用一个阈值来解决这个问题,低于这个阈值的页面不会去合成。有时,接近阈值的页面在一帧中可能超过阈值,在下一帧中可能低于阈值。所以,我们会救回已经可见的页面,以避免视觉上的错误。
我们也永远不会请求超过缓存中总页面数的 1/3,以避免抖动。
尽管已经描述了所有的情况,但是仍然有可能偶尔看到低分辨率的虚拟纹理 (VT)。例如,如果你将相机面向一个方向,然后将其转向侧面,以便它用屏幕上请求的内容填充缓存,如果相机然后快速 180 度旋转查看其后面的内容,那么新页面添加到缓存中需要几帧的时间。这可能相当明显。
解决方案是选择每个扇区最近的中等分辨率页面,并将其添加到请求页面的列表中。我们经常做相机传送,或者非常快速的相机转换,例如从玩家选择装备的天空转换到玩家实际出生的地面。游戏总是被告知相机将要传送到哪里,这样我们就可以为目标位置流式传输适当的内容。AVT 也借此创建中等分辨率的页面。
虚拟纹理本质上是一个缓存。通常,你只想用最新的数据填充缓存。如果 VT 想要合成一个页面,需要确保在页面被合成之前,所有需要的 mips 都已经加载。不幸的是,在有慢存储设备的硬件上,加载所需的 mips 可能需要几秒钟的时间。这可能导致相机实际上超过了 VT,整个地形看起来像 PS1 游戏的错误。我们发现,最好在请求页面时立即进行合成,但将其标记为低分辨率。15 帧后,如果它还没有完全准备好,假设有带宽,再次对其进行合成。延迟被加倍到 30 帧,再次对其进行合成。一直这样做,直到页面被标记为准备好,最后一次对其进行合成。
每一帧,只合成有限数量的页面。在低端移动硬件上,这个数字永远不会超过 4 个页面,但在高端 PC 上,这个数字可以达到每帧 20 个页面。不在缓存中的热门页面首先被合成。如果还有剩余空间,会重新合成可能存在的任何低分辨率页面。低分辨率页面是优先排序的,因此首先重新合成最需要的页面。所有页面都有一个年龄。被请求的页面其年龄被重置为 0。没有被请求的页面看到他们的年龄增加。至少 3 帧没有被请求的页面可以被回收。总是先回收最老的页面。
04 Decal
贴花在渲染超级地形时起着关键作用。
有 3 种类型的贴花。地形贴花是自上而下的矩形正交投影。曲线贴花是自上而下的正交投影,但遵循贝塞尔曲线。体积贴花不仅限于自上而下的投影。它们也适用于任何类型的地理形状,包括地形。
第一张截图显示的是仅有地形层,没有贴花的世界看起来是什么样子。在第二张截图中,渲染了地形层和地形贴花。在第三张截图中,渲染了地形层和曲线贴花。如你所见,使用曲线贴花来制作道路。最后一张截图显示的是所有元素结合在一起的样子。
05 流式加载
负责从磁盘加载资源的游戏系统为流式加载器,这通常取决于摄像机的位置。例如,流式加载器负责加载所需的图像 mips,以全分辨率渲染场景。还将加载网格细节级别,声音,动画和各种其他类型的数据。
超级地形使用了大量从磁盘流式传输的数据。网格数据,如顶点和索引缓冲区,作为摄像机距离的函数进行流式传输。贴花存储在四叉树中,也进行流式传输。根据当前的摄像机位置,游戏计算应该加载的地形层和贴花的图像 mips。当有请求进来合成页面时,游戏检查是否加载了适当的 mips。如果它们没有被加载,会提高它们的优先级,以便尽快进行流式传输。如果有任何缺失的 mips,仍然会合成页面,但将其标记为低分辨率。如果缺少关键数据,如缺少贴花树节点,将该页面标记为未准备好(用缺少绘图基元的页面进行渲染,会导致不好的视觉效果)。如果没有缺失的部分,将页面标记为已准备好。
06 合成
地形组合使用了 3 个称为 ScratchBuffer 的 GBuffer。第一个保存了反照率(albedo)。第二个保存了法线(normal)。第三个保存了金属度(metalness)、遮挡(occlusion)和光泽度(gloss)。在合成页面时,一次写入所有 3 个 Buffer。ScratchBuffer 是未压缩的渲染目标,因此在内存使用方面可能相当昂贵。
首先使用计算着色器渲染地形层。然后使用顶点和像素着色器渲染样条贴花。接着也使用顶点和像素着色器渲染地形贴花。最后,使用计算着色器渲染体积贴花。贴花可以相互排序,但例如体积贴花不能在地形贴花之前渲染。
在将组合的 Scratch 页面复制到物理纹理之前,需要对它们进行压缩。这是通过编写的计算着色器完成的。在移动设备上,使用 ASTC 压缩,在所有其他平台上使用 BC 压缩。在除移动设备外的所有平台上,数据可以被压缩为 2 个 BC3 纹理或 3 个 BC1 纹理。请注意,这是我们在视觉质量上看到最大损失的阶段。
物理纹理有 2 个 mip。这是双线性纹理插值所必需的。物理页面有 4 像素的边界。这是 8X 各向异性过滤工作所必需的。请注意,这意味着每页只使用 248 乘以 248 像素。
BC3 物理纹理有 8 个通道可以使用。第一个纹理编码反照率和金属度,而第二个编码法线、遮挡和光泽度。X 分量进入绿色通道,而 Y 分量进入 alpha 通道。
在 BC1 模式下,有 9 个通道可以使用。第一个纹理编码反照率。第二个纹理编码光泽度、法线的 x 分量和遮挡。而第三个纹理编码金属度和法线的 Y 分量。还有 1 个通道可以用于想要的任何东西。
法线分量被编码在绿色通道中,因为绿色通道有 6 位,而其他通道只有 5 位。尽管理论上 2 个 BC3 模式应该能带来更好的视觉质量,但从未能看出区别。BC1 模式将内存减少了三分之一,并增加了 1 个通道,这很好。
在启用了 GPU 曲面细分和位移的平台上,也使用虚拟纹理来存储位移。位移物理页面是 32 乘以 32,有 1 个 mip,并且有 1 像素的边界,因为它只用于位移顶点,而这些顶点的密度明显小于像素密度。另外,它是 BC4 压缩的,所以内存成本相当小。请注意,位移不影响碰撞,这意味着它们不能太大,否则将开始引起明显的问题。
由于我们的地形技术在各种设备上运行,AVT 可以调整以适应平台,为此有 5 个质量设置:
- 在非常低的设置中,物理纹理只有 13 乘以 13 的页面。间接纹理是 512 乘以 512。
- 在低设置中,物理纹理是 16 乘以 16 的页面。间接纹理也是 512 乘以 512。
- 在中等设置中,物理纹理是 22 乘以 22 的页面。间接纹理仍然是 512 乘以 512。
- 在高设置中,物理纹理是 30 乘以 30 的页面。间接纹理是 1024 乘以 1024。
- 在超高设置中,物理纹理是 42 乘以 42 的页面。间接纹理是 1024 乘以 1024。
mip 链的顶部 6 级的 VT 页面是离线烘焙的。通常,这些页面非常昂贵,因为它们覆盖了地图的大部分区域。通过离线烘焙,显著减少了 GPU 压力,也可以大幅提高视觉质量。在这里,你可以看到只使用离线烘焙页面渲染的世界。
对于接近相机的任何东西来说,它显然分辨率太低,但在远处,离线烘焙页面是 GPU 希望使用的。尽管这些图像需要被流式传输,但它最终节省了内存,因为不需要为足够远离的地形表面流式传输地形层和贴花。这节省了内存并减少了流媒体压力。
在使用 3 BC1 模式时,有 9 个通道可用。由于 AVT 通常只使用 8 个通道,这意味着我们还有 1 个通道可以用来做其他事情。到目前为止,已经为这个通道找到了 4 种不同的用途。散射通常用于雪上,使雪看起来更像真实的雪。热力通道用于夜视和热视觉。有了自发光通道,可以在地面上放置余烬。闪烁通道用于沙子或雪,使它们闪闪发光。启用一个特性是在地图级别完成的。一次只能支持一个特性。
07 高度图
当每个地形表面都有自己的高度图时,知道超级地形上任何点的高度真的很难做到。如果使用单一的高度图覆盖整个超级地形,这就变得非常简单。我们称之为统一高度图或简称 UHM,因为所有的高度图都合并成了一个图。有了 UHM,实现裙边成为可能,这是艺术家们长期以来一直在寻求的。
典型的 UHM 将消耗 32MB 的内存,但如果它是 128MB 或更多,艺术家们会更高兴,因为这意味着它有更高的定义。在某些平台上,32MB 的内存是很大的。通过虚拟化 UHM,显著减少了其内存占用。称之为虚拟高度图或简称 VHM。
VHM 有 144 页,每页是 64x64,不包括 2 像素的边框。这意味着缓存略小于 1.3MB。它还使用了一个间接表,类似于 VT 使用的间接纹理,只不过它只是一个缓冡区。对于我们最大的地图,它只有 8KB 大小。VHM 的页面按照它们到相机的距离进行优先级排序。总是填满缓存。在缓存中的页面有一个滞后性,使它们更难被驱逐。
在这个地图的渲染中,你可以看到地形 Tile 的分辨率。绿色 Tile 的分辨率最高,其次是蓝色,紫色,然后是青色。
早期,我们评估了多种上采样技术,希望我们可以将整个 VHM 保持在内存中,但是进行压缩。结果发现仍然需要进行流处理,但这仍然是有趣的研究。所有这些研究都是使用从美国地质调查网站下载的高度图进行的。
在这张图和接下来的图中,P 是父纹素,代码需要预测 4 个子纹素的高度。P 是 A、B、C 和 D 的高度的平均值。总是先重构所有的 A,然后是 B,接着是 C,最后是 D。最简单的图像上采样技术是假设子高度与父高度相同。这是我们的 C0 预测器。现在我们知道了 A、B 和 C 的值,我们可以对 D 做一些稍微复杂一点的事情。这种简单的上采样技术将内存减少到源的 60%。
C0 上采样 + 改进了之前的技术,它利用 A 来重构 B,然后利用 A 和 B 来重构 C。不过,通过这样做只获得了微不足道的 1% 的提升。
C1 上采样利用邻居,将内存使用量减少到源数据的 43%。这是如何重构 A 的方法。
对于 B,只是简单地取相邻的 A 的平均值。
对于 C,取相邻的 A 和 B 的平均值。
对于 D,取 A、B 和 C 的平均值。因为 C 离 D 纹素更远,应该使用较低的贡献权重,但是实现现在还没有做到这一点。
我们还实现了 C2 预测器,它们本质上就像 C1 预测器,只不过它们观察的是更远的邻居,以便重构一个 C2 连续曲线,而不仅仅是一条直线。这些在 USGS 地图上工作得相当好,但是在游戏中使用的高度图上并没有提供那么多的收益。我们还评估了一个简单的神经网络,尽管它比最好的 C2 预测器做得更好,但它太昂贵了。最后,使用梯度下降来优化一个 5x5 的核。然而,它并没有比 Neville 增量预测器好多少,而今天正在使用的就是 Neville 增量预测器,因为它不需要任何训练。
预测器的目的是预测各个纹素处的高度值。但是,需要重构的高度是无损的。所以,在错误流中保存预测值和真实值之间的差值。那个错误流往往相当稀疏,所以使用简单的压缩技术就能很好地压缩。到目前为止,所有的结果都包括了这种压缩。
使用 Neville 增量,解压一个 68x68 的页面在 PS4 上需要大约 1ms。我们肯定会重新评估这个问题,可能会切换到只使用 C1 预测器,因为它在我们的数据上的表现接近于 Neville 增量,并且应该会便宜很多。
使用 UHM 或 VHM,现在可以实现裙边。裙边允许网格与地形无缝融合。裙边同时包含两个部分:首先,顶点的高度被改变以使其匹配地形的高度。艺术家控制在多大的上下范围内进行形态变化。其次,在对网格进行着色时,可以根据像素离地形的距离从虚拟纹理中采样。在下面的图片中,可以看到岩石与地形无缝融合。
杂乱的物体也利用了裙边技术。在上面的图片中,顶点变形和颜色混合被禁用。你可以看到草实际上是漂浮在地形之上的。当启用顶点变形时,草叶会贴合到地形上。
如草等杂物可以进行颜色调整,使其与下面的地形无缝融合。在颜色调整时使用较低分辨率的 VT,以获得平均颜色。可以计算每个杂物实例、每个顶点或每个像素的颜色调整。这取决于内容创作者的判断。
与杂物着色相关的是网格着色。通过按照特定规则采样非常低分辨率的 VT,可以使相同的网格看起来独特并更好地适应其环境。
右边的悬崖使用非常低分辨率的 VT 作为颜色调整,使其看起来独特。
09 统一表面
目前正在研究称之为 “统一地形表面” 的新技术。不再使用多个地形表面,而是使用一个覆盖整个世界的地形表面。它解决了以前遇到的一个烦人的问题,即当两个具有不同顶点密度的地形表面相邻时。这会在地面上产生裂缝,艺术家通常不得不放置网格来隐藏它们。使用 UTS,这已经不再是问题。与统一地形表面一起,还实现了一个统一的索引和颜色映射。
10 虚拟化
在统一过程之后,可以进行虚拟化过程。虚拟化统一地图可以减少它们的内存占用。
索引图不能被插值,因为每个值都是地形层索引,使用点采样来生成低分辨率的 mips,由于索引地图的一个像素只能与颜色地图的对应像素一起工作,也对颜色图进行点采样。最后,索引和颜色图的分辨率必须匹配。这再次是因为索引图的一个像素只能与颜色图的对应像素一起工作。虚拟索引地目前是 16 位,但我们计划将其减少到 10 位。虚拟颜色地图是 BC1 压缩的。
除了虚拟化索引和颜色地图,我们还虚拟化了剪切图。剪切图非常简单,因为每个像素只有 1 位。样本要么被剪切,要么不被剪切。绝大多数页面都是白色的,我们有一些黑色的页面,还有一些页面有剪切和非剪切像素的混合。虚拟剪切图使用了一个间接表,就像其他虚拟图一样。对于黑白页面,简单地使用一个特殊的索引来表示黑色或白色。只把那些有剪切和非剪切像素混合的页面放入缓存。由于最多只能有 254 个这样的页面,这意味着虚拟剪切图的最坏情况下的内存成本是 150KB。数据如此之小,甚至都不需要进行下采样。在大地图上,间接表的内存成本只有微不足道的 4KB。
Vista UVs 非常擅长使地形层在相机近处和远处都看起来很好。问题在于它依赖于相机距离。当相机远离表面时,会在宏观细节中加入 alpha,并在微观细节中减少 alpha。这样做的原因是,从远处看,宏观贡献看起来很好,但从近处看,它会显得像素化。对于虚拟纹理来说,使用相机距离是有问题的,因为 VT 没有相机的概念。必须通过将 mip 级别转换为相机距离来进行伪造。例如,mip 0 意味着从最大距离约 5 英尺的地方看到。Mip 1 将这个距离加倍,而 mip 2 再次加倍。这在 VT 页面的 mip 链中创建了一个不连续性,因为现在,两个相邻的 mips 实际上会有稍微不同的数据。实际上,已经能够在很多地方使这个工作,但我们仍在探索解决这个问题的方法。
11 其它 & 未来
对于冰,我们通常使用一种便宜的视差映射技术,这种技术在模拟深度方面做得很好。然而,我们的地形技术并不支持视差映射,但我们没有理由不支持。
我们目前正在添加第四个 BC1 纹理。这将为我们提供另外 3 个可玩的通道,总共有 4 个可选通道。散射和闪烁通常用于雪上。目前,可以选择其中一个,但不能同时拥有两者。同样,视差通常用于冰,因此在雪层级上也会用到。有了第四个 BC1 纹理,可以同时拥有散射、闪烁和视差。
我们正在尝试使用程序化贴花,这种贴花的内存成本为零。它们可以用来为原本平淡无奇的地形层添加细节。
虚拟纹理是一个静态缓存,但我们相信可以有一定量的动态性。一个很好的例子就是在雪地或沙地上的脚印。所有的技术都已经存在,可以自动重新计算虚拟纹理区域。只需要尝试一下,看看效果如何。
我们最近增加了触发大规模事件的能力,以戏剧性地改变我们地图的某些区域。当涉及到地形时,希望地理位置会受到影响。举个例子,一架飞机在地面上坠毁。使用虚拟化地图,实现这一点既简单又便宜,因为只需要更新受影响的页面。 > 本文由简悦 SimpRead 转码