Отражение OpenGL неправильно отображает скайбокс - PullRequest
0 голосов
/ 03 марта 2019

Я пытаюсь изучить отражения на OpenGL без использования метода LearnOpenGL, но я не могу понять, что не так с отражениями.Кажется, что в определенных частях камеры видны искажения и переворачивания.Пока что я просто использую матрицу представления, чтобы просто кодировать.

Вот так выглядит отражение сферы.

Я также пытался использовать куб.Даже когда моя мышь продолжала двигаться вправо, отражение искажалось, а затем отображало изображение, которое присутствовало до деформации.

Отражение куба

Изображение Skybox

Это вершинный шейдер скайбокса

#version 330 core
layout (location = 0) in vec3 aPos;

out vec3 o_pos;

void main()
{
    o_pos = aPos;
    gl_Position = vec4(aPos, 1.0);
}

Это фрагментный шейдер скайбокса.Я передаю матрицу вида непосредственно фрагментному шейдеру.

#version 330 core
out vec4 FragColor;

in vec3 o_pos;

uniform vec3 view_up;
uniform vec3 view_right;
uniform vec3 view_forward;

uniform samplerCube cubeTex;

void main()
{
    vec3 pv = mat3(view_right, view_up, view_forward) * vec3(o_pos.xy, 1.0);
    FragColor = vec4(texture(cubeTex, pv).rgb, 1.0);
}

Это вершинный шейдер объекта

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 normal;

out vec3 o_normal;
out vec3 o_pos;

void main()
{
    o_pos = aPos;
    o_normal = normal;
    gl_Position = vec4(o_pos, 1.0f);
}

Это шейдер фрагмента объекта.Это похоже на шейдер Learnopengl.

#version 330 core
in vec3 o_pos;
in vec3 o_normal;

out vec4 fragColor;

uniform vec3 eye_pos;
uniform samplerCube cubeTex;

void main()
{
    vec3 incident = normalize(o_pos - eye_pos);
    vec3 reflection = reflect(incident, normalize(o_normal));
    fragColor = vec4(texture(cubeTex, reflection).rgb, 1.0);
}

Вот цикл рендеринга

    while (!glfwWindowShouldClose(window))
    {
        // input
        processInput(window);

        // render
        glClearColor(0.9f, 0.8f, 0.5f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // change view using mouse input
        double xpos, ypos;
        glfwGetCursorPos(window, &xpos, &ypos);
        ypos = (ypos/SCR_HEIGHT) * PI * PI * 0.5;
        xpos = (xpos/SCR_WIDTH) * 2 * PI - PI;
        if (ypos < PI/2) ypos = 1.6f;
        if (ypos > 3*PI/2) ypos = 4.7f;
        eye_forward = normalize(glm::vec3{(GLfloat)(cos(ypos) * cos(xpos)),
                                (GLfloat)sin(ypos),
                                (GLfloat)(cos(ypos) * sin(xpos))});
        eye_right = glm::normalize(glm::cross(eye_forward, glm::vec3{0.0, 1.0, 0.0}));
        eye_up = glm::cross(eye_right, eye_forward);

        // draw skybox
        glUseProgram(shaderProgram);
        glUniform1i(u_cubeTex, 0);
        glUniform3fv(u_view_up, 1, (GLfloat*)&eye_up);
        glUniform3fv(u_view_right, 1, (GLfloat*)&eye_right);
        glUniform3fv(u_view_forward, 1, (GLfloat*)&eye_forward);
        glBindVertexArray(vao);
        glDrawArrays(GL_TRIANGLE_STRIP, 0, cube.size());

        // draw UV sphere
        glUseProgram(sphereProgram);
        glUniform1i(u_cubeTex2, 0);
        glUniform3fv(u_eye_pos, 1, (GLfloat*)&eye_forward);
        glBindVertexArray(sphereVAO);
        glDrawArrays(GL_TRIANGLE, 0, sphere.size());

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

1 Ответ

0 голосов
/ 03 марта 2019

eye_pos - это позиция в мировом пространстве.
o_pos - это позиция в пространстве просмотра, пространстве клипа и нормализованном пространстве устройства.Это все то же самое в вашем случае, потому что у вас нет матрицы проекции, и атрибут координаты вершины непосредственно назначается позиции пространства клипа в вершинном шейдере:

 gl_Position = vec4(aPos, 1.0);

В любом случае, не имеет смысла вычислять вектор из положения в мировом пространстве в положение в пространстве вида, как вы это делаете:

 vec3 incident = normalize(o_pos - eye_pos);

Положение глаза в поле зренияпробел (0, 0, 0).Таким образом, вектор вида инцидента в пространстве вида:

vec3 incident = normalize(o_pos - vec3(0.0, 0.0, 0.0));

Этот вектор должен быть преобразован из пространства вида в мировое пространство, что может быть достигнуто с помощью матрицы ориентации вида (mat3(view_right, view_up, view_forward)) втак же, как вы делаете это в фрагментном шейдере скайбокса:

vec3 incident = mat3(view_right, view_up, view_forward) * normalize(o_pos);

Нормальный вектор o_normal также является вектором пространства просмотра.Поэтому его необходимо преобразовать в мировое пространство:

vec3 wordlNormal = mat3(view_right, view_up, view_forward) * normalize(o_normal);

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

#version 330 core

in vec3 o_pos;
in vec3 o_normal;

out vec4 fragColor;

uniform vec3 view_up;
uniform vec3 view_right;
uniform vec3 view_forward;
uniform samplerCube cubeTex;

void main()
{
    mat3 invNormalM      = mat3(view_right, view_up, view_forward);

    vec3 viewIncident    = normalize(o_pos);
    vec3 viewNormal      = normalize(o_normal);
    vec3 worldReflection = invNormalM * reflect(viewIncident, viewNormal);

    fragColor            = vec4(texture(cubeTex, worldReflection).rgb, 1.0);
}

Я передаю матрицу вида непосредственно шейдеру фрагмента.

mat3(view_right, view_up, view_forward) нетматрица вида.Это матрица ориентации камеры.Так что это обратная (нормальная) матрица.

...