The perfect view

Let's say you have a 3d object and you want to move your existing camera so that the object fills your view. I had such a hypothetical situation recently and for some reason it took me several hours of scribbling to figure it out, after which I smacked my head for being so dumb. Hopefully I can save someone out there from a similarly self-induced headache.

First, let's assume that you have a bounding sphere around your object, or in other words, a sphere that tightly and exactly encompasses your object. You know where this bounding sphere is in space, and you also know its radius.

Aside from the sphere, you also have the camera. Your camera has a viewing frustum, which is basically a four sided pyramid with the tip neatly cut off. Here is a simple reference showing the frustum from the side and how we want to fit our sphere in it.



Our eye is at point A. The point at which the eye can start perceiving things is that first vertical solid line, or the frustum's near plane. The sphere is centered at point B, with a radius r. It touches the edge of the frustum at point C (as well as at another point directly opposite which I have not labeled.)

We have the following information about the camera... We know the distance from A to the near plane. We also know the viewing angle of A. Some people keep track of that, in jMonkeyEngine we instead keep track of the offsets of the top, left, bottom and right edges of the near plane (really a rectangle). So we know that the top edge is x units from the center of the near plane, the right edge is y units from the center... etc.

What I want to know is the distance from A to B, but I only had an angle and a single side length. Any geometry student will tell you that you can't construct a triangle without 2 sides and an angle or 2 angles and a side... What to do?

Eventually I realized an important piece of information as illustrated below:



Yes, the fact is we actually know two of the angles. The point at which a circle touches a line or plane is perpendicular to the line from that point to the center of the circle. So, we have a right triangle and problem becomes fairly simple:



sin(theta) = r / AB
or
AB = r / sin(theta)

Where theta is the angle CAB. In jMonkeyEngine you can get this angle with the following pseudo code:

angle = arctan(frustumTop/frustumNear)

Where frustumTop is line st and frustumNear is line At (edit: line As) in the above diagram.

This gets the best fit for the up-down direction. If your screen is taller than wide, you should use frustumRight instead to calculate your angle.

Now that you know how far away the camera should be, grab a vector and set it to your camera direction, then multiply it by the negative distance and add the center of your sphere. Now your camera is in the perfect spot for the "perfect view".

Example code (you can skip computing both if you know that one side will always be bigger):

float angle1 = FastMath.atan(camera.getFrustumTop() / camera.getFrustumNear());
float d1 = sphere.getRadius() / FastMath.sin(angle1);
float angle2 = FastMath.atan(camera.getFrustumRight() / camera.getFrustumNear());
float d2 = sphere.getRadius() / FastMath.sin(angle2);
tempVector.set(camera.getDirection()).multLocal(-(Math.max(d1, d2))).addLocal(sphere.getCenter());
camera.getLocation().set(tempVector);

Photosynth

Dan P., my Italian brother, just sent this link to me. It's one of the TED presentations and it shows off a technology from Microsoft (MSFT) that can scan photos of all different formats (SLR, cell phones, etc.) and arrange them around in a 3d navigable representation of the place they represent. Pretty nifty!

Mad Skills Motocross

jME forum user Tobias of Turborilla Entertainment announced today his upcoming jME powered game, "Mad Skills Motocross." Check out the preview video, it's pretty cool looking already. He apologizes several times for the programmer art, but personally I like it. :)