С моим рендером воды у меня возникла проблема, когда в зависимости от положения и ориентации камеры в игре присутствует эффект "мерцания" на местности.В основном, серое наложение «мерцает» на местности, но затем исчезает.Это повторяется при изменении положения / ориентации камеры.
В частности, это происходит только на определенных «островках» местности и вблизи той части местности, которая пересекает четырехугольник воды.
Итак, чтобыпроиллюстрируем проблему:
Вода без мерцания
Вода с мерцанием;В нижней правой части изображения на небольшом острове, который выступает из основного острова, имеется небольшое серое наложение.
Кроме того, вот анимированный .gif, демонстрирующий проблему:
В заключение, это мерцание не происходит, скажем, для большого телаландшафта в фоновом режиме.
Может кто-нибудь сообщить мне, какие дополнительные детали мне нужно предоставить, а также указать мне правильное направление относительно проблемы и возможного решения?
Спасибозаранее!
Ниже приведен мой процесс отображения отражения в квадрате воды:
Сначала я создал один буферный объект кадра при запуске программы: Создание объекта Framebuffer:
// FBO objct
unsigned int framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// generate texture
unsigned int texColorBuffer;
glGenTextures(1, &texColorBuffer);
glBindTexture(GL_TEXTURE_2D, texColorBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024, 768, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
// attach it to currently bound framebuffer object
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texColorBuffer, 0);
unsigned int rbo;
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 1024, 768);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
Я создал один водный квад:
// real_offsets needed for instancing
std::vector<glm::vec2> real_offsets;
real_offsets.push_back(glm::vec2(650, 450));
glm::mat4 waterQuad = glm::mat4(1.0f);
waterQuad = translate(waterQuad, vec3(0, 480.0, 0));
waterQuad = scale(waterQuad, vec3(100, 1, 100));
objects.push_back(std::shared_ptr <Object>(new Object("waterpane_very_low.obj", waterQuad, real_offsets, true, false
, glm::vec3(0.0, 0.5, 1.0))));
Затем в основном игровом цикле я использовал объект буфера кадров, чтобы сохранить снимок сцены: Основной игровой цикл:
do {
glEnable(GL_CLIP_DISTANCE0);
// Use frame buffer object
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Draw scene with no water quad to FBO
// [...]
// Disable frame buffer object
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Save frame buffer object texture to texture unit 0 to use later
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texColorBuffer);
glDisable(GL_CLIP_DISTANCE0);
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Draw whole scene, including water quad as normal
// [...]
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
} while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS && glfwWindowShouldClose(window) == 0);
В шейдере моего обычного объекта я включил плоскость обрезки, чтобы управлять тем, что рисуется на текстуру отражения: NormalObjects.vertexshader:
const vec4 plane = vec4(0,1,0,-480);
gl_ClipDistance[0] = dot( M * vec4(vertex,1), plane);
gl_Position = MVP * vec4(vertex,1);
В моем water.vertexshader я выполнилнеобходимые вычисления для преобразования локальной вершины: water.vertexshader:
// MVP_offset = P * V * M_offset, where M_offset depends on a vector of vecs2 passed in containing instancing offsets
clipSpace = MVP_offset * vec4(vertex,1.0);
gl_Position = MVP_offset * vec4(vertex,1.0); // instanced vertex
Затем в моем water.fragmentshader я применил затенение Blinn-Phong, сэмплировал текстуру отражения и проецировал ее: water.fragmentshader:
// Sampler variable
uniform sampler2D waterTexture;
// Projectively map the reflection texture
vec2 clipProj = (clipSpace.xy / clipSpace.w) / 2.0 + 0.5;
clipProj.y *= -1.0f; // flip texture around
// waterTexture was assigned texture unit 0
vec4 finalVec = vec4(texture(waterTexture, clipProj).rgb, 1.0);
vec4 finalVec2 = finalVec * vec4(ambientComponent() + diffuseComponent(modelNormal,lightVec) + specularComponent(modelNormal, lightVec), 1.0);
FragColor = finalVec2;