c++ - 为加载高度图的地形创建 UV 坐标?

标签 c++ opengl terrain

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

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

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

所以我的问题是:

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

渲染的纹理:

Renderedimage

来自网络的实际图像:

Actual image

指定数组创建的代码:

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;
    }
}

最佳答案

我会尽力回答您的所有问题。

1) Do the UV coordinates need to range from 0 to 1, with no consideration of the terrain's width and length or not?

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

Does the UV coordinate array need to be the same length as the vertices array?

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

Is there any simple algorithm or way that i could specify the UVs of the terrain?

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

enter image description here

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

关于c++ - 为加载高度图的地形创建 UV 坐标?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54136126/

相关文章:

c++ - 旋转模型 'compas correct' 时出现问题

c# - 我如何计算在体素游戏中应该首先加载哪些 block ?

javascript - 如何从Three.js中给出X和Y的网格表面获取高程值(Z坐标)?

c++ - 我如何在我的代码中同时支持 Unicode 和多字节字符集?

c++ - 使用 std::search 查找多次出现的模式

java - 在类的构造函数中找出实例化对象

opengl - OpenGL : Error moving object using keyboard

c++ - 在 directx 应用程序中,找到已知位置的 z(地形)

c++ - C++ 中的调试宏

c++ - 重载的按位或运算符 ('|' ) 是否具有明确定义的评估顺序?