Jump to content
  • Advertisement
Sign in to follow this  

Zoom to box extents (Zoom to Selection)

This topic is 4035 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello, I am trying to implement a zoom to extents of an axis aligned bounding box function in my 3D model viewer. A zoom to selection function. The parameters are: - min and max points of the box, - 3D vector that is the view direction, - 3D vector that is the "up vector" - view and projection matricies The output would be the distance the camera must be from the center of the box. I have tried a few things but with only partial success. If anyone can please give me some direction it would be much appreciated. BTW I am using DirectX Thanks [Edited by - Fruity on October 3, 2007 10:31:43 AM]

Share this post

Link to post
Share on other sites
One thing I tried was to move the camera to the furthest point in the bounding box from the center of the bounding box along the view vector. I then projected the bounding box points onto this temporary plane. I am hoping to figure out how to scale the camera distance by comparing the projected points to the size of the window, but havent succeeded yet. Anyone have any ideas?

Share this post

Link to post
Share on other sites
Imagine the camera frustum in 3D space along with the bounding box. You want to move the frustum toward the bounding box until they collide. This is as close as they can get before the bounding box goes outside the frustum, meaning part of it is no longer in view.

What you first want to do is extract the right/up/forward vectors for the camera as well as its position from the view matrix. The 'right' vector is the first column, the 'up' vector is the second column, and the 'forward' vector is the third column (only take the first three elements of each column, since the fourth element isn't part of the rotation). The position of the camera can be computed by doing right*(4,1) + up*(4,2) + forward*(4,3), where (4,1), (4,2), and (4,3) are the first three elements of the bottom row. This extraction process works based on the fact that the inverse view matrix directly contains the information we need, and it computes the inverse indirectly using the shortcut here (first transposed for use with DirectX matrices). Finally we need the cotangent of half the FOV for both width and height. Luckily, these values are simply elements (1,1) and (2,2) of the projection matrix, respectively.

Now comes the fun part. We need to compute the horizontal and vertical distance from the forward vector for each point on the bounding box. There are eight points, (max/min, max/min, max/min). These distances can be obtained using dot(up,test_point) - dot(up,camera_position) for the vertical direction and dot(right,test_point) - dot(right,camera_position) for the horizontal direction. This is where the cotangents we extracted from the projection matrix come in. If we know the horizontal/vertical distance of each point, we can multiply those values by their respective cotangents to figure out how far away the camera is going to be from that point (after being projected on the forward vector) when it collides with the frustum.

To find the distance of each point from the camera after being projected on the forward vector, you do dot(forward, test_point - camera_position). You then subtract the value computed above. A positive result tells you that the camera needs to move that many units forward before the frustum collides with the point. A negative values means that you're too close, and that the camera needs to move backward. So after you test all the points, you chose the smallest distance and move that many units forward (if it's negative, then you end up moving backward).

Here's some pseudo-code. It should return the number of units the camera needs to move forward or backward to fit the bounding box:
points[0] = (min.X,min.Y,min.Z)
points[1] = (min.X,min.Y,max.Z)
points[2] = (min.X,max.Y,min.Z)
points[3] = (min.X,max.Y,max.Z)
points[4] = (max.X,min.Y,min.Z)
points[5] = (max.X,min.Y,max.Z)
points[6] = (max.X,max.Y,min.Z)
points[7] = (max.X,max.Y,max.Z)

right = extractRight(viewMatrix);
up = extractUp(viewMatrix);
forward = extractForward(viewMatrix);
camera_position = extractPosition(viewMatrix);

horizontal_cot = projMatrix(1,1);
vertical_cot = projMatrix(2,2);

min_distance_delta = MAX_FLOAT;

for_each(test_point in points)
horizontal_distance = dot(right,test_point) - dot(right,camera_position);
vertical_distance = dot(up,test_point) - dot(up,camera_position);

horizontal_collision_distance = horizontal_distance * horizontal_cot;
vertical_collision_distance = vertical_distance * vertical_cot;

projected_distance = dot(forward,test_point - camera_position);

horizontal_collision_distance_delta = projected_distance - horizontal_collision_distance;
vertical_collision_distance_delta = projected_distance - vertical_collisions_distance;

min_collision_distance_delta = min(horizontal_collision_distance_delta, vertical_collision_distance_delta);

if(min_collision_distance_delta < min_distance_delta)
min_distance_delta = min_collision_distance_delta;

return min_distance_delta;

Share this post

Link to post
Share on other sites
Wow, that is an awesome reply. I appreciate you taking the time to explain it so well.

Thanks :)

Share this post

Link to post
Share on other sites
I have this working now for cases when the forward and up vectors are the same one of the global x, y or z axis, such as the standard views: Forward, Back, Top, Bottom, Left, Right.

However, when the forward and up vectors are not aligned with the x, y or z axis, then I often get points outside the frustum.

For example:

forward = (0, -0.7071067, 0.7071067)
up = (0, 0.7071067, 0.7071067)
right = (1, 0, 0)
min = (-500, -500, -5000)
max = (500, 500, 5000)
cameraPoint = (0, 3570.71387, -3570.71387)

Creates a view where the the max points are inside the frustum but all of the min points are below the bottom plane of the frustum.

I will look into this further, I'll double check that I am not introducing a bug somewhere in my code, but if anyone has any ideas, I'd appreciate it.

Share this post

Link to post
Share on other sites
That's my bad, you need to take the absolute value of the product with the cotangents: abs(horizontal_distance * horizontal_cot) and abs(vertical_distance * vertical_cot).

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!