4
\$\begingroup\$

In most game engines (Unity, UE4) if we select a model and press F, the camera moves and focuses to the selected model. I want to implement that for my models.

I have a perspective camera and world space bounding box of the model.

How do I calculate the appropriate distance to view the entire model in the camera?

\$\endgroup\$

1 Answer 1

6
\$\begingroup\$

Take every point (vertex), project them into screen space (basically multiply them with the projection * view * model matrix).

After you got this, take every point and get the 2 with the biggest x difference and repeat the same for y. This way you get the bounding box of these points.

Now, you'll also need 2 things: the aspect ratio of the camera, and the vertical FOV.

Take the bounding box, multiply it's height by the aspect ratio, and check if it is bigger or smaller than the width. If it's bigger, then we need to take the height into consideration when we position our camera, if it's smaller, we need to take the width into consideration.

Now we need the vertical FOV (and some trigonometry). If you need to place your camera based on the vertical, then you simply use the following formula (height is the bounding box height, FOV is the FOV):

dist := height / 2 / tan(FOV / 2)

If you need to base it off of the width, then you need to do a slight modification (width is the width of the bounding box, aspect is the aspect ratio):

dist := width / 2 / tan(FOV * aspect / 2)

(Every angle is in radian BTW)

Now, you now how far you need to place the camera.

Now, if you need the distance based on width, then let the 2 farthest points on the horizontal axis be A and B. If you need the height version, then let the farthest points on the vertical axis be A and B (Doesn't matter which one's which).

Now, A and B form a line (marked with AB). Get this line's center ((A + B) / 2), let this be M. Now the last part. Take the direction vector (it should be normalized), negate it, multiply it with dist you got earlier, add it to M and done, you have the position of the camera.

Because many people don't understand math, and because I'm a nice guy, here's this in pseudo-code:

func find_pos(mat4 proj_view_model, float aspect, float FOV, vec3[] points, vec3 camera_direction) {
    vec4[] projected_points
    foreach (vec3 pos in points) do
        push(projected_points, proj_view_model * vec4(pos, 1))
    end

    vec4 A1, B1, A2, B2

    float width, height

    for (i = 0 .. length(projected_points) - 1) do
        for (j = i .. length(projected_points)) do
           float new_width := abs(projected_points[i].x - projected_points[j].x)
           float new_height := abs(projected_points[i].y - projected_points[j].y)

           if (new_width > width) then
               A1 := projected_points[i]
               B1 := projected_points[j]
               width := new_width
           end
           if (new_height > height) then
               A2 := projected_points[i]
               B2 := projected_points[j]
               height := new_height
           end
        end
    end

    vec4 A, B

    float dist
    if (height * aspect > width) then
        dist := height / 2 / tan(FOV / 2)
        A := A1
        B := B1
    else
        dist := widh / 2 / tan(FOV * aspect / 2)
        A := A2
        B := B2
    end

    vec3 center := vec3((A + B) / 2)
    vec3 camera_pos = center - camera_direction * dist
    return camera_pos
}

This function is very fast if you're wondering, the biggest drawback is getting the 2 farthest points. If you know any other algorithms, feel free to use that.

If you find any errors in my logic, post a comment below.

\$\endgroup\$
4
  • \$\begingroup\$ I didn't get. have u any c++ or C# code ? \$\endgroup\$
    – UPO33
    Jan 27, 2017 at 14:48
  • \$\begingroup\$ @UPO33 What don't you get? No, I don't have either of those, you should learn to read pseudo code \$\endgroup\$
    – Bálint
    Jan 27, 2017 at 16:06
  • \$\begingroup\$ projected_points. I wrote the following code but it gives wrong result paste2.org/vIapFY4C \$\endgroup\$
    – UPO33
    Jan 27, 2017 at 17:46
  • \$\begingroup\$ @UPO33 I made a very small error, at the beginning i should go from 0 instead of 1. If the problem stays after this fix, then could you explain how's it not working? \$\endgroup\$
    – Bálint
    Jan 27, 2017 at 19:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .