glm :: rotate приводит к выпуклости текстуры - PullRequest
2 голосов
/ 17 июня 2019

Я реализую небольшую программу просмотра изображений, способную поворачивать изображение и увеличивать / уменьшать его. Я делаю это нарочно, используя OpenGL и GLM для самостоятельных занятий. Пока все работает отлично, единственная проблема, которая возникла, это то, что изображение сильно сжимается, когда я поворачиваю его. Это происходит, особенно когда ширина и высота изображения сильно различаются. Кажется, что после поворота на 90 градусов текстура защемляется до тех пор, пока не уместится, что приводит к искажению изображения. Понимаю ли я что-то не так в том, как здесь происходит вращение? Насколько я понял, это просто умножение координат многоугольника на матрицу вращения. Но тогда я не понимаю, почему это привело бы к такому выпуклости текстуры.

Я пытался поиграть с перспективой и даже зашел так далеко, чтобы настроить вымышленную камеру, используя glm::lookAt(), но пока безуспешно.

Реализация вершинного шейдера:

const GLchar* vertexSource = R"glsl(
#version 150 core
in vec2 position;
in vec3 color;
in vec2 texcoord;

out vec3 Color;
out vec2 Texcoord;

uniform mat4 model;
void main()
{
    Color = color;
    Texcoord = texcoord;
    gl_Position = model *  vec4(position, 0.0, 1.0);
}
)glsl";

Реализация ротации:

//...
model = glm::mat4(1.0f);
//Get the transformation into the shader
uniTrans = glGetUniformLocation(shaderProgram, "model");
//...
else if(windowEvent.key.code == sf::Keyboard::Left){
                        degree = 5;
                        model = glm::rotate(model, glm::radians(degree), glm::vec3(0.0f, 0.0f, 1.0f));
                        glUniformMatrix4fv(uniTrans, 1, GL_FALSE, glm::value_ptr(model));
                    }
                    else if(windowEvent.key.code == sf::Keyboard::Right){
                        degree = -5;
                        model = glm::rotate(model, glm::radians(degree), glm::vec3(0.0f, 0.0f, 1.0f));
                        glUniformMatrix4fv(uniTrans, 1, GL_FALSE, glm::value_ptr(model));
                    }
//...

Реализация массива вершин (существуют факторы, чтобы текстура не заполняла все окно. Они создаются таким образом, что граница всегда будет 200 пикселей):

//...
 GLfloat vertices[] = {
        //Position                //Color          //Texcoords
        facX*(-1.0f), facY*( 1.0f), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, //top-left
        facX*( 1.0f), facY*( 1.0f), 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, //top-right
        facX*( 1.0f), facY*(-1.0f), 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, //bottom-right
        facX*(-1.0f), facY*(-1.0f), 1.0f, 1.0f, 1.0f, 0.0f, 1.0f //bottom-left
    };
//...

Настройка текстур:

GLuint tex;
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.getX(), image.getY(), 0, GL_BGRA, GL_UNSIGNED_BYTE, (const GLvoid*)data);
    //Defining how to proceed if the texture is smaller than the space
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
    //Specify Border Color
    float color[] = {1.0f, 0.0f, 0.0f, 1.0f};
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
    //Set up filter for up and downscaling of the texture (linear smooth, nearest would give pixelised result)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

Чтобы описать возникающую проблему более наглядно, когда я поворачиваю изображение с шириной! = Высота на 90 градусов, «новой» высотой будет старая ширина. Однако происходит то, что высота остается неизменной, что, конечно, приводит к выпуклому изображению. У кого-нибудь есть представление о том, что я делаю неправильно?

1 Ответ

3 голосов
/ 17 июня 2019

Это происходит, особенно когда ширина и высота изображения сильно различаются

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

Матрица проекции преобразует все данные вершин из координат вида в координаты клипа.Координаты клипа преобразуются в нормализованные координаты устройства (NDC) ( Перспективное деление ).
Нормализованные координаты устройства находятся в диапазоне от (-1, -1, -1) до (1, 1, 1) и образуют идеальный объем куба.
В случае ортогональной проекции координаты пространства глаза линейно отображаются в NDC.
Если область просмотра является прямоугольной, это необходимо учитывать путем сопоставления координат.

Добавьте матрицу проекции в вершинный шейдер:

const GLchar* vertexSource = R"glsl(
#version 150 core
in vec2 position;
in vec3 color;
in vec2 texcoord;

out vec3 Color;
out vec2 Texcoord;

uniform mat4 projection;
uniform mat4 model;
void main()
{
    Color = color;
    Texcoord = texcoord;
    gl_Position = projection * model * vec4(position, 0.0, 1.0);
}

Установите матрицу ортографической проекции с помощью ortho(), которая «масштабирует» геометрию в соответствии с соотношением сторон и задает матрицу с равномерным:

uniProjection = glGetUniformLocation(shaderProgram, "projection");
int widht  = ...; // width of the viewport (window)
int height = ...; // height of the viewport (window)
float aspect = (float)width / height; 

glm::mat4 project = glm::ortho(-aspect, aspect, -1.0f, 1.0f, -1.0f, 1.0f);
glUniformMatrix4fv(uniProjection, 1, GL_FALSE, glm::value_ptr(project ));

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

...