c++openglorthographic

Rotate camera around z axis by 45 degrees works but not around x axis


I'm trying to setup an orthographic camera in C++ and I have some problems getting the rotation correctly.

When I try to rotate the camera around the z axis by 45 degrees, everything works as expected (model is defined from -0.5f to 0.5f).

enter image description here

However, when trying to rotate around x axis, the angle gets really amplified (i.e. rotation around 1 radian makes it almost disappear).

enter image description here

Here is the related code:

int main(int argc, char** argv)
{
    sdl2::Context context;

    sdl2::Window window("myWindow", 800, 600);
    sdl2::GLContext glContext(window);
    
    //make the shader
    Shader shader("shaders/quad.vert", "shaders/quad.frag");

    Quad quad;

    //create a orthographic projection
    glm::mat4 projection = glm::ortho(0.0f, 800.0f, 0.0f, 600.0f);
    auto zAxis = glm::vec3(0.0f, 0.0f, 1.0f);

    glUseProgram(shader.getID());
    auto projectionLoc = glGetUniformLocation(shader.getID(), "projection");
    glUniformMatrix4fv(projectionLoc, 1, false, glm::value_ptr(projection));

    auto viewLoc = glGetUniformLocation(shader.getID(), "view");
    auto viewTransform = glm::mat4(1.0f);

    auto zRot = glm::quat(glm::vec3(glm::radians(1.0f), glm::radians(0.0f), glm::radians(0.0f)));
    viewTransform *= glm::toMat4(zRot);

    glUniformMatrix4fv(viewLoc, 1, true, glm::value_ptr(viewTransform));

    bool quit = false;
    SDL_Event e;
    while (!quit)
    {
        while (SDL_PollEvent(&e) != 0)
        {
            if (e.type == SDL_QUIT)
            {
                quit = true;
            }
        }
        glClear(GL_COLOR_BUFFER_BIT);
        quad.render(shader);
        SDL_GL_SwapWindow(window());
    }
    
    
    
    SDL_Delay(3000);
    return 0;
}

#version 430 core
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 uv;

uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;

void main()
{
    gl_Position = projection * view * model * vec4(pos, 1.0);
}

Quad::Quad() :
    _position(0, 0, 0)
{
    glCreateBuffers(1, &_vbo);
    glCreateVertexArrays(1, &_vao);
    glGenBuffers(1, &_ebo);

    float vertices[] = {
     0.5f,  0.5f, 0.0f,  // top right
     0.5f, -0.5f, 0.0f,  // bottom right
    -0.5f, -0.5f, 0.0f,  // bottom left
    -0.5f,  0.5f, 0.0f   // top left 
    };

    uint32_t indices[] = {
        0, 1, 3,
        1, 2, 3
    };
    
    glBindVertexArray(_vao);
    glBindBuffer(GL_ARRAY_BUFFER, _vbo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ebo);

    glEnableVertexAttribArray(0);

    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
}

Quad::~Quad()
{
    glDeleteVertexArrays(1, &_vao);
    glDeleteBuffers(1, &_vbo);
}

void Quad::render(const Shader& shader)
{
    glBindVertexArray(_vao);
    glUseProgram(shader.getID());

    auto modelView = glm::mat4(1.0f);
    //modelView = glm::translate(modelView, glm::vec3(400.0f, 300.0f, 0.0f));
    modelView = glm::scale(modelView, glm::vec3(400.0f, 400.0f, 1.0f));
    //modelView = glm::scale(modelView, glm::vec3(800, 600, 0));
    auto modelLoc = glGetUniformLocation(shader.getID(), "model");
    auto viewLoc = glGetUniformLocation(shader.getID(), "view");
    auto projectionLoc = glGetUniformLocation(shader.getID(), "projection");
    glUniformMatrix4fv(modelLoc, 1, false, glm::value_ptr(modelView));
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}

Solution

  • When you rotate a round the x or y axis, then the objects is clipped by the near and far plane of the Orthographic projection. By default near is -1.0 and far is 1.0. Increase the distance to the near and far plane (see glm::ortho). For instance:

    glm::mat4 projection = glm::ortho(0.0f, 800.0f, 0.0f, 600.0f);

    glm::mat4 projection = glm::ortho(0.0f, 800.0f, 0.0f, 600.0f, -500.0f, 500.0f);