I have a CubeGeometry which the camera is looking at, and I want the camera to zoom so that the cube is entirely visible, but no larger.
My initial attempt was to convert the cube verticies to the camera coordinate system,
function toScreenXY(position, camera) {
var pos = position.clone();
var projScreenMat = new THREE.Matrix4();
projScreenMat.multiply(camera.projectionMatrix, camera.matrixWorldInverse);
projScreenMat.multiplyVector3( pos );
return pos;
}
function ScaleInView() {
camera.fov = 0.0;
for (var i=0; i<8; i++) {
proj2d = toScreenXY(cube.geometry.vertices[i],camera);
angle = 57.296 * Math.max(Math.atan(proj2d.x/proj2d.z), Math.atan(proj2d.y/proj2d.z));
camera.fov = Math.max(camera.fov,angle);
}
camera.updateProjectionMatrix();
}
I thought this would work, but sometimes it’s too small, and other times too large (depending on the position of the camera).
I also need to do this for Orthographic Camera.
Edit:
I know how to do this when the cube is facing the camera, I’m looking for a way to do it when the camera is moved to some arbitrary (r, theta, phi) position (spherical polar coordinates; r is actually constant for my purposes).
Multiplying by camera.matrixWorldInverse gives a vector in the camera’s coordinates, but importantly does not apply perspective.
We can then find the smallest angle that will fit all the box corners in the scene. arctan(D.x / D.z) gives the angle BCD where B is what the camera is looking at, C is the camera’s position, and D the position of an object that you want to be visible in the camera coordinates.
In my case, the following ensures that the the cube boundbox is fully visible.