Search code examples
c++cameravulkanglm-mathorthographic

Behaviour of (glm::) orthographic camera in Vulkan app


I have a 3d application in Vulkan, where a simple 3d model is being rendered. Usually, I use perspective projection with glm, like so:

// Vulkan-trick because GLM was written for OpenGL, and Vulkan uses
// a right-handed coordinate system instead. Without this correction,
// geometry will be y-inverted in screen space, and the coordinate space
// will be left-handed. Described at:
// https://matthewwellings.com/blog/the-new-vulkan-coordinate-system/
glm::mat4 correction(
        glm::vec4(1.0f,  0.0f, 0.0f, 0.0f),
        glm::vec4(0.0f, -1.0f, 0.0f, 0.0f),
        glm::vec4(0.0f,  0.0f, 0.5f, 0.0f),
        glm::vec4(0.0f,  0.0f, 0.5f, 1.0f));

camera->projectionMatrix = correction * glm::perspectiveFov(fov, w, h, near, far);

This works fine.

So, trying now with orthographic projection instead:

float aspect = h / w; // window height/width in pixels
camera->projectionMatrix = correction * glm::ortho(-1.0f, 1.0f, -aspect, aspect, near, far);

The 3d model still renders, even though it's bigger than before, so I'm probably making mistake(s) in how I create the orthographic projection matrix.

But the problem is that the camera cannot move forwards/backwards in the scene now, which is something that worked fine with perspective projection. The underlying setup looks liks this:

// called every frame if up arrow key is pressed
void camera_move_forward(Camera* camera, float distance)
{
    camera->position += camera->front * distance;
}

// called every frame
static void update(Camera* camera)
{
    const glm::quat& q = camera->orientation;
    camera->viewMatrix = glm::translate(glm::mat4_cast(q), camera->position);

    camera->front = glm::rotate(glm::conjugate(q), glm::vec3(0.0f, 0.0f, 1.0f));
    camera->up = glm::rotate(glm::conjugate(q), glm::vec3(0.0f, 1.0f, 0.0f));
    camera->right = glm::normalize(glm::cross(-camera->up, camera->front));
}

The observable behaviour is that camera_move_forward does not change the size of the 3d object on-screen. But I can, however, see that the near/far planes work correctly as the model starts getting "cut" if I hold up/down arrow keys for an extended period of time.

How is this usually done? I have not used orthographic projection before.


Solution

  • This post provides a great answer. In short, it is working as designed. The 3D scene is projected to 2D in a parallel manner, so moving the camera position won't change the size of the object since the extents of the object are always going to appear to be the same distance apart. Hence, "parallel". In order to "zoom" in or out on the object, you'll have to change the ortho extents or modify your transform stack in some other way.