Создать координаты UV для местности, загруженной картой высот? - PullRequest
0 голосов
/ 10 января 2019

Я создал ландшафт в OpenGL, используя изображение карты высот. Результатом является динамически распределенный массив, который включает все вершины ландшафта (x, y, z) с шагом 3, например: (firstvertexX, firstvertexY, firstvertexZ, secondvertexX, secondvertexY, thirdvertexZ ...).

Я также рассчитал нормали (в аналогичном массиве) и очень плохое приближение предполагаемых UV ландшафта (используя ... нормали) для его рендеринга. Рендеринг не имеет никаких проблем, за исключением того, что как я уже сказал, приближение UV действительно плохое, и текстура отображается в виде «многоугольника» (используя GL_TRIANGLE_STRIPS).

Я хочу уточнить, что я хочу, чтобы ландшафт создавался в OpenGl, а не в любой другой программе, такой как Blender. Поэтому мне нужно как-то указать координату UV для каждой вершины в упомянутом выше массиве, который содержит вершины. Я также хотел бы сказать, что я не ищу идеальное решение для ультрафиолетового излучения (даже если оно каким-то образом есть), а способ приблизительного приближения, чтобы результат был приличным.

Итак, мои вопросы:

  1. Должны ли координаты УФ находиться в диапазоне от 0 до 1, без учета ширины и длины местности или нет?
  2. Должна ли массив координат UV иметь ту же длину, что и массив вершин?
  3. Есть ли какой-нибудь простой алгоритм или способ, которым я мог бы указать UVs ландшафта?

Текстура, которая отображается:

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 Ответ

0 голосов
/ 11 января 2019

Я постараюсь ответить на все ваши вопросы как можно лучше.

1) Нужно ли, чтобы координаты УФ были в диапазоне от 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);

В качестве альтернативы вы можете зафиксировать значения УФ с помощью следующего кода:

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 в массиве через индекс. Но если вы хотите, чтобы все было просто, просто перейдите к 1 к 1 и не беспокойтесь о дубликатах.

Есть ли какой-нибудь простой алгоритм или способ, которым я мог бы указать UVs местность?

Один из простых способов сделать это - просто текстурировать каждый треугольник как часть четырехугольника. Ваш ландшафт должен быть просто сеткой четырехугольников, что означает, что вы можете просто перебирать список вершин, назначая каждый квад в вашей сетке с текстурными координатами, подобными этим:

enter image description here

Еще лучше, если сетка вашей местности имеет размеры 1 по x и z, вы можете просто подключить мировые пространственные координаты вашей сетки к x и z и установить сэмплер текстуры для переноса, предполагая, что ваша сетка не повернута. , Он все равно будет работать, если ваша сетка вращается, но текстура не будет вращаться вместе с ней.

...