游戏中的 3D 地图渲染

3D maps rendering in games

我对 3D 游戏(即魔兽世界)中的地图以及程序员如何渲染它们有一些疑问:

  1. 是否可以通过某种技术 "smooth" 山脉的边缘,或者唯一可能的解决方案是在高度图中使用更多顶点?

    我是否认为他们为此使用了某种技术,因为他们只为每座山渲染了相当数量的顶点?我错了吗?

  2. 看看这张图片:


    (来源:gamona.de

    关于如何渲染这种场景的一些问题:

    1. 我听说 open-world 像 WoW 这样的游戏使用高度图进行地形渲染,他们怎么知道在哪里绘制所有其他东西? (树木、房屋、栅栏、水等)。
    2. 他们如何渲染地下区域? (山里面有一座巨大的城堡)
    3. 请注意,每个凹凸使用大约 2 个纹理来显示(雪和岩石)。他们用来知道何时对每个纹理进行采样的算法可能是什么?它看起来并不依赖于法线。 (我认为他们甚至不会为他们的地形生成法线。)
    4. 看起来他们也没有为 horizon 使用天空盒。可能是什么技术?
    5. 你能说出你注意到我可以探索的其他有趣技术吗?

我目前正在学习 OpenGL,但我也标记了 DirectX,因为这些问题并不是 API 具体的。

暴雪建模师使用 Autodesk's 3ds max 创建模型。如果您研究该软件包的功能和技术,您将了解它们是如何实现其效果的。请注意,景观模型使用非均匀 b 样条 (NURB) 使它们具有圆润的外观。

除了 Tyler Durdens 的回答之外,我还想谈谈您的几点看法。

  1. 他们可能开发了自己的编辑器,并将其导出并传递给渲染器。因此开发人员可以进入并在点放置一棵树,然后渲染器知道在该点绘制树模型。或者他们按照以下方式做一些事情:http://mollyrocket.com/casey/stream_0017.html,其中他们 "fill" 有东西的空白区域,如草(如本例所示)、树木等

  2. 他们渲染外部区域的方式相同 :p

  3. 可以通过 link dari posted 作为对您 post 的回复来实现这种效果,或者像您提到的那样覆盖高度图中的一些纹理。

  4. 我不太确定天空盒。

  5. 看看一些 links posted,你肯定可以花大量时间研究 :)

很难从你的高度图上分辨出来(主要是因为你上面没有任何光照)但我想说这几乎可以肯定,在你的例子中他们使用的是比你更高分辨率的基础高度图是。

现在不像其他一些张贴者所说的那样,景观在 3D 建模包中建模的可能性很小。他们也不太可能使用 B 样条曲线来渲染景观。

使用更高分辨率高度图的最大问题是内存需求。为此有多种不同的解决方案,"optimise" 将高度图数据存储在内存中。近处的风景不需要远方的风景那么多细节。

渲染大量高度详细的景观几何图形的真正好技术是 geometry clipmaps. It's quite complicated though. Another scheme I have used to great success in the past is Geo-Mipmapping。它非常简单而且非常快。如果您将三线性过滤技术应用于 Geo-mipmap,它也会产生出色的结果。为这样的景观编写异步块加载器以提供巨大景观的良好流式传输性能也相当简单。

无论如何我会回答你的其他问题。

  1. 正如 hbdavehb 所建议的,他们将有一个加载景观的编辑器,然后他们可以在地图上放置项目(以及,很可能,编辑景观)。模型将在 3DS Max 或 Maya 中创建,然后加载到编辑器中进行放置。

  2. 它们是用其他形式的渲染器渲染的。通常是 portal renderer or maybe a BSP renderer.

  3. 此技术称为 texture splatting

  4. 在我看来就像一个天空盒。我猜它可能是天空盒上的动态渲染。

  5. 名单很大。但我建议研究各种图像映射技术,例如 bump mapping (Especially normal mapping), cube mapping, Parallax mapping, Displacement mapping. Then there would be the lighting techniques such as global illumination, the Phong illumination (not the same as Phong shading), bidirectional reflectance distribution functions and precomputed radiance transfer. That's only scratching the surface. I highly recommend having a good read around. Computer Graphics: Principles and Practice by Foley et al. is an excellent book on rendering. The GPU Gems series is very good too. For a history of 3D rendering techniques and, in my opinion, still a very useful book its worth looking at Michael Abrash's Black Book

祝你好运!

我发现平滑地形的最简单方法是,在转换为浮动后,对顶点应用 convolution 过滤器。这是一种来自图像处理的技术,但也可以很好地处理来自 8 位高度图的数据。

这是我几年前使用的 C++ 源代码。

void CGround::CHeightmap::_SmoothTerrain(int passes)
{
   float* NewHeightData;

   while (passes--)
   {
       // Note: m_Size.X and m_Size.Y should be equal and power-of-two values 
       NewHeightData = new float[m_Size.X * m_Size.Y];

       for (int x = 0; x < m_Size.X; x++)
       {
          for (int y = 0; y < m_Size.Y; y++)
          {
              int adjacentSections = 0;
              float sectionsTotal = 0.0f;

              if ((x - 1) > 0) // Check to left
              {
                 sectionsTotal += m_Heights[(x - 1)*m_Size.Y + y];
                 adjacentSections++;

                 if ((y - 1) > 0) // Check up and to the left
                 {
                    sectionsTotal += m_Heights[(x - 1)*m_Size.Y + y - 1];
                    adjacentSections++;
                 }

                 if ((y + 1) < m_Size.Y) // Check down and to the left
                 {
                    sectionsTotal += m_Heights[(x - 1)*m_Size.Y + y + 1];
                    adjacentSections++;
                 }
              }

              if ((x + 1) < m_Size.X) // Check to right
              {
                 sectionsTotal += m_Heights[(x + 1)*m_Size.Y + y];
                 adjacentSections++;

                 if ((y - 1) > 0) // Check up and to the right
                 {
                     sectionsTotal += m_Heights[(x + 1) * m_Size.Y + y - 1];
                     adjacentSections++;
                 }

                 if ((y + 1) < m_Size.Y) // Check down and to the right
                 {
                     sectionsTotal += m_Heights[(x + 1)*m_Size.Y + y + 1];
                     adjacentSections++;
                 }
              }

              if ((y - 1) > 0) // Check above
              {
                 sectionsTotal += m_Heights[x*m_Size.Y + y - 1];
                 adjacentSections++;
              }

              if ((y + 1) < m_Size.Y) // Check below
              {
                 sectionsTotal += m_Heights[x*m_Size.Y + y + 1];
                 adjacentSections++;
              }

              NewHeightData[x*m_Size.Y + y] = (m_Heights[x*m_Size.Y + y] + (sectionsTotal / adjacentSections)) * 0.5f;
           }
       }
       delete m_Heights;
       m_Heights = NewHeightData;
   }
}

增加 passes 的值以获得更多平滑度。

分别回答您的 1)。他们有一个对象列表,只需将它们放在高度图的顶部。

2) - 以不同的方式。地下城通常是规则的网格。

3) 您可以使用不同解释的法线、高度、附加纹理数据或以上的任意组合