首页 > 解决方案 > 为加载了高度图的地形创建 UV 坐标?

问题描述

我使用高度图图像在 OpenGL 中创建了一个地形。结果是一个动态分配的数组,其中包括地形的所有顶点 (x,y,z),步长为 3,如下所示:(firstvertexX,firstvertexY,firstvertexZ,secondvertexX,secondvertexY,thirdvertexZ...)。

为了渲染它,我还计算了法线(在类似的数组中)和假定的地形 UV 的极差近似值(使用...法线)。渲染完全没有问题,除了我说的UV 近似值非常糟糕,并且渲染的纹理在其中具有“多边形”感觉(使用GL_TRIANGLE_STRIPS)。

我想澄清一下,我希望在 OpenGl 中创建地形,而不是在 Blender 等任何其他程序中创建。所以我必须以某种方式为上面提到的数组中包含顶点的每个顶点指定一个 UV 坐标。我还想说,我不是在寻找完美的紫外线解决方案(即使以某种方式存在),而是一种粗略近似以使结果良好的方法。

所以我的问题是:

  1. UV坐标是否需要在0到1的范围内,不考虑地形的宽度和长度?
  2. UV坐标数组是否需要与顶点数组的长度相同?
  3. 是否有任何简单的算法或方法可以指定地形的 UV?

渲染的纹理:

渲染图像

实际图片来自网络:

实际图像

指定创建数组的代码:

for (i = 0; i < terrainGridLength - 1 ; i++) { //z
     for (j = 0; j < terrainGridWidth; j++) { //x

      TerrainVertices[k] =  startW + j + xOffset;
      TerrainVertices[k + 1] =  20 * terrainHeights[(i + 1)*terrainGridWidth + (j)]  + yOffset;
      TerrainVertices[k + 2] =  startL - (i + 1) + zOffset;
      k = k + 3;


      TerrainVertices[k] =  startW +  j +xOffset;
      TerrainVertices[k + 1] = 20 * terrainHeights[(i)*terrainGridWidth + j] +yOffset;
      TerrainVertices[k + 2] =  startL - i  + zOffset;
      k = k + 3;


      float x = RandomFloat(0.16, 0.96);
      TerrainUVs[d] = x* (terrainNormals[ 3*((i+1 )*terrainGridWidth + j)]);
      TerrainUVs[d + 1] = terrainNormals[3* ((i+1 )*terrainGridWidth + j) + 2 ];

      x = RandomFloat(0.21, 0.46);
      TerrainUVs[d+2] = x*(terrainNormals[ 3*((i+1 )*terrainGridWidth + j) +1]);
      d = d + 3;


      x = RandomFloat(0.3, 0.49);
      TerrainUVs[d] = x*(terrainNormals[3* ((i  )*terrainGridWidth + j) ]);
      TerrainUVs[d + 1] = terrainNormals[ 3*((i  )*terrainGridWidth + j)+2 ];

      x = RandomFloat(0.4, 0.85);
      TerrainUVs[d + 2] = x*(terrainNormals[3* ((i )*terrainGridWidth + j) +1]);

      d = d + 3;
    }
}

标签: c++openglterrain

解决方案


我会尽我所能解决你所有的问题。

1)UV坐标是否需要在0到1的范围内,不考虑地形的宽度和长度?

UV 坐标通常在 0 到 1 的空间中,但是如果您传入的 UV 不是 0 到 1,那么处理 UV 的方式将取决于您如何设置 OpenGL 来处理这种情况。

您可以使用以下代码告诉纹理采样器将坐标视为包装:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

或者,您可以使用以下代码限制 UV 值:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

在此处查看有关纹理采样器的更多信息: https ://www.khronos.org/opengl/wiki/Sampler_Object

UV坐标数组是否需要与顶点数组的长度相同?

一般来说,是的。在对某些几何体进行纹理化时,您通常需要为每个顶点至少一个 UV,因此您应该拥有与顶点相同数量的 UVS。但是,如果您将多个纹理应用于几何体,您可能会拥有更多纹理,或者如果您通过其他方式对几何体进行纹理化,例如使用您编写的不需要 UVS 的片段着色器,您可能会拥有更少的纹理。如果您的 UVS 被索引,您也可以拥有更少,即当共享相同 UV 的顶点每个通过索引引用数组中的相同 UV 时。但是,如果您想保持简单,只需一对一,不要担心重复。

是否有任何简单的算法或方法可以指定地形的 UV?

一种简单的方法就是将每个三角形纹理化为四边形的一部分。您的地形应该只是一个四边形网格,这意味着您可以遍历顶点列表,为网格中的每个四边形分配纹理坐标,如下所示:

在此处输入图像描述

更好的是,如果您的地形网格在 x 和 z 上的大小为 1,您可以在 x 和 z 上插入您的网格的世界空间坐标,并将您的纹理采样器设置为环绕,假设您的网格没有旋转。如果您的网格旋转,它仍然可以工作,但纹理不会随之旋转。


推荐阅读