以游戏Trigger Rally为例谈WebGL地形渲染

      在本系列中,我将介绍WebGL游戏《Trigger Rally》中使用的地形渲染技术。

  一个难题

  在电脑图像和游戏中高效沉浸大面积、精细的地图是一个难题。

  
  terrain3(from gamasutra)

  使用WebGL(网页图形库)却可以使这个难题变得容易。WebGL是浏览器的OpenGL(开放图形语言),允许用户使用GPU的性能,但有一些限制。更重要的是,在本地应用中用 JavaScript处理CPU端的数据更慢。把数据转移到GPU,比在本地应用中要求更多的安全性检查,以保证网络用户安全。然而,一旦数据到GPU,绘制就非常快了。

  
  gpu-good-cpu-bad(from gamasutra)

  最大化GPU工作和最小化CPU工作的好办法是,在启动时把静态数据(顶点、指数和纹理)载入到GPU,然后在运行时用尽量少的调用渲染它。

  但仅靠静态数据是很难做出漂亮的地形的,因为镜头通常会很接近地面,而在屏幕上看,最近处和最远处的地面之间的精细度差异会很明显。

  另外,在给定的GPU交互率下,能够绘制的三角形的数量是有限的。三角形数量的多少取决于应用或游戏运行的系统,但通常不可能在整个平面上大面积地、精细地渲染。

  因为三角形数量有限,我们必须找出最佳的三角形分配方案。所以,在接近镜头时我们以低细节均匀分布,因为于玩家不可能欣赏到更远处的细节。

  
  terrain-diagram1(from gamasutra)

  注意,近处的视线(粉红部分)表面积比远处的视线(蓝色部分)的更大。理想情况下,我们会让接近镜头的地方比远离镜头的地方有更多三角形,以平均二者。


  terrain-diagram2(from gamasutra)

  但对于移动的视点和纯静态的顶点数据,这个方法并不太管用。

  
  terrain-diagram3(from gamasutra)

  如果你乐意做些CPU上的工作,那么你可以根据当前的视点,使用多种算法中的一种来调整地形的细节程度(LOD)。各个算法都以各自的方式平衡CPU的工作和GPU的工作。

  解决方案:Geoclipmapping

  我们如何用纯静态顶点数据达到可调节的LOD?Geoclipmapping和顶点纹理就是答案。

  我们不是编码顶点数据中的高度信息,而是把它留在单独的纹理里。这样,我们的顶点数据可以用中央更高的分辨率和从源头开始的递减的分辨率环编码简单的网格模型。

 
  terrain-diagram4(from gamasutra)

  在运行时,我们把这个网格模型放在当前视点之下,然后从顶点着色器的高地纹理地图中取样本。

  事实上要做的事不止这些,所以在本系列的下一篇文章中,我将继续详细geoclipmapping的运作原理和执行方法。再之后,我将讨论多分辨率heightmapping和表面着色。

  环形

  Geoclipmap渲染使用一系列的方格“环绕”顶点,每个环都是此前环形的两倍,空间分辨率也是如此分布。这就形成了所有距离间的地形几乎一致的屏幕空间分辨率。位居最中央 (最高分辨率)的环拥有其中心填充,成为一个简单的三角方格:

  以方格模式自我重复的几何形有一个良好的属性:我们不会让用户看到任何可视变化(除了移动的边缘),就可以通过准确的方格数量对其进行转换:

  
  diagram5(from gamasutra)

  我们可以运用这一属性移动几何体,令其接近摄像机之下,但不要让它的移动看起来过于明显。

  每个环都有自己的方格大小,由于转换距离取决于几何大小,所以我们得分别移动这些环。因此就要让顶点着色器知道顶点属于哪个图层,这样才好让它正确变体。

  所以我们需要的顶点属性就是:

  *X轴位置

  *Y轴位置

  *图层属性

  
  vertex attributes(from gamasutra)

  在《Trigger Rally》中,我们使用的是[X,Y,X]向量,并将图像索引编程为Z,这样我们的原几何图的环形就会堆叠起来。

  填充空隙

  每个环都用不同的比例绘制,它们还使用多个比例进行转变。这里就有一个问题:当一个环形转变了,而其旁边的环形却没有转变,那么这就会产生一个空隙。

  
  diagram8(from gamasutra)

  修复这个空隙的一个方法就是使用额外几何形,即所谓的skirt扩大环形边缘。skirt是由许多更小的碎片集合而成,使用大量的小顶点缓冲器和谨慎的CPU逻辑,但这并非我们想要 的结果。

  所在在部署《Trigger Rally》的地形时,我花了数个小时试图找到一种无缝而完全静态的skirt设计方法,但却无果而终。

  之后我在去年的WebGL Camp Europe现场见到了Florian B?sch,他建议我将环形做得更大一点,然后让它们重叠。

  现在,富有经验的图像程序员肯定会说“不行!你不能重叠几何图形!这太浪费了,并且你会看到糟糕的深度冲突问题!”不过除了有一点透支之外,这种方法还算是一种很棒的 解决方案,因为几何形匹配非常妥当。

  变体

  在这些环形的边缘之前,我们为几何形分配一个分辨率,令其紧挨着仅有其一半分辨率的几何形。我们必须在每个环形的边缘引进一个转换区域,仅几何形逐渐移动或从高分辨率 向低分辨率变体,这样当你到达环形边缘时,它就会与其相邻的环形完美匹配。

  
  diagram6(from gamasutra)

  以下就是每个顶点要与另一个环形相匹配时所需移动的方式:

  
  diagram7(from gamasutra)

  我们要在顶点着色器中执行这种转换。最简单的方法莫过于将变体方向矢量作为顶点数据格式的一部分,但Florian对此却有更好的建议,即使用模运算!

  让我们列出这些数据看看如何执行:

  顶点坐标 0 1 2 3 4

  MOD 2 0 1 0 1 0

  MOD 4 0 1 2 3 0

  变体矢量 0 -1 0 1 0

  我们可以使用这个GLSL代码,从面点位置来计算变体矢量:

  vec2 morphVector = mod(position.xy, 2.0) * (mod(position.xy, 4.0) – 2.0);

  这不需要任何额外的顶点属性!

  这次我们要看看地形高地数据是如何储存和处理的。

  《Trigger Rally》的地形高地数据主要资源,形成山地的整体形状,是瑞士阿尔卑斯山地图的真实卫星数据。

  
  terrain4(from gamasutra)

  我写了一个工具把这个数据转化为无缝的1024×1024的16位图像。低8位储存在红色通道里,高8位存在绿色通道里。如下图所示:

 
  nice-boosted(from gamasutra)

  在载入时,游戏把这个图像转化为单通道的32们浮动纹理,然后把赛车跑道曲线(每一条路道的曲线都是不一样的)绘制到这个图像中。

  以角秒的速度取样高地数据,以21米对应阿尔卑斯山纬度30米。我把这些数值除以大约3,以缩小游戏中的高山,所以主高地地图的各个象素其实是7.5米x10.8米。

  这样的分辨率对于高山是不错的,对于跑道只是刚好,而对于顺畅的驾驶和近景图像,就不太够了。

  平滑

  第一件要做的事就是修改高地地图。对于图像,线性过滤通常足够平滑了,但对于我们几何体,我们确实需要更高的连续性。这里有几个不同的办法,但我只采用三次厄密特条样 函数插值法。

  我们得到的结果如下:

  
  terrain7(from gamasutra)

  添加细节

  现在我们必须添加更高分辨率的细节,使地形更加有趣和真实。为此,我使用512×512的8位地图,其中高地储存在蓝色通道中,高地导数(游戏邦注:一个变量随某个变量变化时 的速度或变化率)存在红色和绿色通道中。

  
  detail(from gamasutra)

  以每个顶点1象素,最高的地形分辨率,取样这个细节地图,然后添加到主要高地上,使地图更加生动。

  
  terrain8(fro

2021欧洲杯赛事2021欧洲杯赛事2021欧洲杯赛事2元彩票网2元彩票网

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注