КОНТЕКСТ:
Я пытаюсь создать в openGL естественную сцену с открытым миром. Массив terrainVertices
длины 3*NUM_OF_VERTICES
содержит данные вершин для ландшафта, которые представляют собой карту высот, генерируемую шумом. Каждая вершина имеет x,y,z
координаты, и на основе значения y
определенному цвету присваивается вершина, что обеспечивает несколько плавный переход между глубокими водами и горными вершинами.
ПРОБЛЕМА:
Озера образуются, когда окрестность вершин имеет значение y, такое что y<0
. Раскраска выполняется должным образом, однако результат нереалистичен. Это похоже на голубую яму:
Я решил решить эту проблему, создав слой вершин, которые появляются над озером, имеют y=0
и светло-синий цвет с низким значением альфа, создавая иллюзию поверхности, под которой лежит фактическое озеро.
Массив terrainVertices
индексируется массивом элементов elements[NUM_OF_ELEMENTS]
. Я перебираю массив элементов и пытаюсь найти триплеты индексов, которые соответствуют вершинам с y<0
. Я собираю каждый триплет, который соответствует этому условию, в векторе, затем создаю новый объект массива вершин с теми же данными вершин, что и у ландшафта, но с новым буферным объектом элемента, который я только что описал. У «подводных» вершин значение y заменено на 0
, чтобы прилипать к поверхности озера.
Вот код, который я использовал для этого:
std::vector<GLuint> waterElementsV;
//iterating over every triangle
for (int i = 0; i < NUM_OF_ELEMENTS / 3; i++) {
//accessing each vertex based on its index from the element array
//checking if its height is lower than zero
//elements[3*i+0, +1, +2] represents the indices for a triangle
//terrainVertices[index + 1] represents the height of the vertex
if (terrainVertices[3 * (elements[3 * i]) + 1] < 0 &&
terrainVertices[3 * (elements[3 * i + 1]) + 1] < 0 &&
terrainVertices[3 * (elements[3 * i + 2]) + 1] < 0) {
//since its a valid triangle, add its indices in the elements array.
waterElementsV.push_back(elements[3 * i]);
waterElementsV.push_back(elements[3 * i + 1]);
waterElementsV.push_back(elements[3 * i + 2]);
}
}
//iterating through the terrain vertices, and setting
//each appropriate vertex's y value to water surface level y = 0
for (unsigned int i = 0; i < waterElementsV.size(); i++) {
currentIndex = waterElementsV[i];
terrainVertices[3 * currentIndex + 1] = 0;
}
//get the vector's underlying array
waterElements = waterElementsV.data();
glGenVertexArrays(1, &waterVAO);
glBindVertexArray(waterVAO);
glGenBuffers(1, &waterVerticesVBO);
glBindBuffer(GL_ARRAY_BUFFER, waterVerticesVBO);
glBufferData(GL_ARRAY_BUFFER, NUM_OF_VERTICES, terrainVertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
glGenBuffers(1, &waterEBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, waterEBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(waterElements), waterElements, GL_STATIC_DRAW);
Шейдеры очень просты, так как мне нужно только назначить позицию и цвет. Матрицы проекции мировоззрения не используются, потому что каждый объект рисуется относительно местности в любом случае.
Вершинный шейдер:
#version 330 core
layout (location = 0) in vec3 pos;
void main()
{
gl_Position = vec4(pos, 1.0);
}
Фрагмент шейдера:
#version 330 core
out vec4 fragColor;
void main()
{
fragColor = vec4(0, 0, 0, 1);
}
Результат точно такой же, как на картинке выше. Я размышлял о том, что происходит, но, похоже, не могу понять ... Обратите внимание, что озера расположены в случайных местах и не обязательно соседствуют друг с другом.
Любая помощь или советы с благодарностью:)