Search code examples
c++openglglm-math

How to calculate the required scale of a rectangle to fit the screen


I want to fit my rectangle to the screen size with regards to the camera position.

This is the VBO data for the rectangle.

width = 50.0f;
height = 50.0f;
verticesRect = {
        // Positions        // Normal Coords          // Texture Coords
        width,  height, 0.0f,    0.0 , 0.0, 1.0 ,     1.0f, 0.0f,   // Top Right
        width, -height, 0.0f,    0.0 , 0.0, 1.0 ,     1.0f, 1.0f,   // Bottom Right
       -width, -height, 0.0f,    0.0 , 0.0, 1.0 ,     0.0f, 1.0f,   // Bottom Left
       -width, height, 0.0f,    0.0 , 0.0, 1.0 ,     0.0f, 0.0f    // Top Left 
    };

The Matrix for Projection.

 float angle = 45.0f;
    glm::mat4 projection = glm::perspective(glm::radians(angle), (float)1920.0 / (float)1080.0, 0.1, 1000.0);

The Matrix for View

glm::vec3 Position( 0.0 , 0.0 , 500.0);
glm::vec3 Front( 0.0 , 0.0 , 0.0);
glm::vec3 Up( 0.0 , 1.0 , 0.0);
glm::mat4 view = glm::lookAt(Position, Front , Up);

The Matrix for rectangle object is

glm::model = PositionMarix * RotationMatrix * ScalingMatrix;

How can i calculate what the scaling of the object should be so that it fits itself to the screen size

The rectangle object can translate in z position so as camera can also move in z Position.


Solution

  • At perspective projection, the projected size on the viewport depends on the distance to the camera (depth).

    aspect = width / height
    
    height_vp = depth * 2 * atan(fov_y / 2)
    width_vp  = height_vp * aspect
    

    In your case the object is drawn around (0, 0, 0) and the distance of the camera to the origin is 500. The filed of view (fov_y) is glm::radians(angle).
    With the above formula you can project a rectangle with the bottom left (-1, -1) and the top right (1, 1) exactly on the viewport. Since the bottom left of your rectangle is (-50, -50) and the top right is (50, 50) you have to divide by this scale.
    Hence the scale is:

    float scale_x = 500.0f * 2.0f * atan(glm::radians(angle) / 2.0f);
    float scale_y = scale_x * 1920.0f / 1080.0f;
    
    glm::mat4 ScalingMatrix = glm::scale(glm::mat4(1.0f), 
        glm::vec3(scale_x / 50.0f, scale_y / 50.0f, 1.0f));