c++openglglm-mathperspectivecameraorthographic

Switching from perspective to orthogonal keeping the same view size of model and zooming


I have fov angle = 60, width = 640 and height = 480 of window, near = 0.01 and far = 100 planes and I get projection matrix using glm::perspective()

glm::perspective(glm::radians(fov),
                              width / height,
                              zNear,
                              zFar);

It works well.

Then I want to change projection type to orthogonal, but I don't knhow how to compute input parameters of glm::ortho() properly. I've tried many ways, but problem is after switching to orthographic projection size of model object become another.

Let I have a cube with center in (0.5, 0.5, 0.5) and length size 1, and camera with mEye in (0.5, 0.5, 3), mTarget in (0.5, 0.5, 0.5) and mUp (0, 1, 0). View matrix is glm::lookAt(mEye, mTarget, mUp) With perspective projection it works well. With glm::ortho(-width, width, -height, height, zNear, zFar) my cube became a small pixel in the center of window. Also I've tried implement this variant How to switch between Perspective and Orthographic cameras keeping size of desired object but result is (almost) same as before.

So, first question is how to compute ortho parameters for saving original view size of object/position of camera?

Also, zooming with

auto distance = glm::length(mTarget - mEye)
mEye = mTarget - glm::normalize(mTarget - mEye) * distance;

have no effect with ortho. Thus second question is how to implement zooming in case of ortho projection?

P.s. I assume I understand ortho correctly. Proportions of model doesn't depends on depth, but nevertheless I still can decide where camera is for setting size of model properly and using zoom. Also I assume it is simple and trivial task, for example, when developing a 3D-viewer/editor/etc. Correct me if it is not.


Solution

  • how to compute ortho parameters for saving original view size of object/position of camera?

    At orthographic projection the 3 dimensional scene is parallel projection to the 2 dimensional viewport.
    This means that the objects, which are projected on the viewport always have the same size, independent of their depth (distance to the camera).

    The perspective projection describes the mapping from 3D points in the world as they are seen from of a pinhole camera, to 2D points of the viewport.
    This means an object which is projected on the viewport becomes smaller, by its depth.

    If you switch form perspective to orthographic projection only the objects in 1 plane, which is planar (parallel) to the viepwort, and keeps its depth. Note, a plane is 2 dimensional and has no "depth". This cause that a 3 dimensional object never can "look" the same, when the projection is switched. But a 2 dimensional billboard can keep it's size.

    The ration of depth an size at perspective projection is linear and can be calculated. It depends on the field of view angle only:

    float ratio_size_per_depth = atan(glm::radians(fov / 2.0f) * 2.0f;
    

    If you want to set up an orthographic projection, which keeps the size for a certain distance (depth) then you have to define the depth first:

    e.g. Distance to the target point:

    auto distance = glm::length(mTarget - mEye);
    

    the projection can be set up like this:

    float aspect = width / height
    float size_y = ratio_size_per_depth * distance;
    float size_x = ratio_size_per_depth * distance * aspect;
    
    glm::mat4 orthProject = glm::ortho(-size_x, size_x, -size_y, size_y, 0.0f, 2.0f*distance);
    

    how to implement zooming in case of ortho projection?

    Scale the XY components of the orthographic projection:

    glm::mat4 orthProject = glm::ortho(-size_x, size_x, -size_y, size_y, 0.0f, 2.0f*distance);
    
    float orthScale = 2.0f;
    orthProject = glm::scale(orthProject, glm::vec3(orthScale, orthScale, 1.0f));
    

    Set a value for orthScale which is > 1.0 for zoom in and a value which is < 1.0 for zoom out.