Программа игры OpenGL 4.6 - Отражение воды - Проблема мерцания - PullRequest
0 голосов
/ 04 января 2019

С моим рендером воды у меня возникла проблема, когда в зависимости от положения и ориентации камеры в игре присутствует эффект "мерцания" на местности.В основном, серое наложение «мерцает» на местности, но затем исчезает.Это повторяется при изменении положения / ориентации камеры.

В частности, это происходит только на определенных «островках» местности и вблизи той части местности, которая пересекает четырехугольник воды.

Итак, чтобыпроиллюстрируем проблему:

Вода без мерцания

enter image description here

Вода с мерцанием;В нижней правой части изображения на небольшом острове, который выступает из основного острова, имеется небольшое серое наложение.

enter image description here

Кроме того, вот анимированный .gif, демонстрирующий проблему:

enter image description here

В заключение, это мерцание не происходит, скажем, для большого телаландшафта в фоновом режиме.

Может кто-нибудь сообщить мне, какие дополнительные детали мне нужно предоставить, а также указать мне правильное направление относительно проблемы и возможного решения?

Спасибозаранее!


Ниже приведен мой процесс отображения отражения в квадрате воды:

Сначала я создал один буферный объект кадра при запуске программы: Создание объекта 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...