Finally, my problem has been solved!
1. The key was to move the camera within a loop, adjusting the zoom to the desired direction each time, and creating a new frustum with the camera's matrix in every iteration.
2. By checking for intersections between spheres and the frustum planes, it was possible to detect when part of an object goes outside the frustum, signaling the need to stop the loop and return the camera to its previous position.
This technique can be applied to any object, not just spheres, as every object has a boundingSphere that can be computed (although the precision may vary).
Moreover, this method also proved effective when zooming out, requiring adjustments to ensure no negative distances exist from any plane to the objects in view.
For zooming out on r72 version, here’s the code snippet:
var finished = false;
var camLookingAt = /* calculate */ ;
while( !finished ){
var toDirection = camera.position.clone().sub(camLookingAt.clone());
toDirection.setLength(vec.length() - 1); // decrease length for zooming out
camera.position.set(toDirection.x, toDirection.y, toDirection.z);
camera.updateMatrix(); // update camera's local matrix
camera.updateMatrixWorld(); // update camera's world matrix
var frustum = new THREE.Frustum();
frustum.setFromMatrix(new THREE.Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse));
for (var j = frustum.planes.length - 1; j >= 0; j--) {
var p = frustum.planes[j];
for (var i = myMeshSpheres.length - 1; i >= 0; i--) {
var sphere = new THREE.Sphere(myMeshSpheres[0].position.clone(), myMeshSpheres[0].radius);
if(p.distanceToSphere(sphere) < 1){ // 'negative' signifies portion outside
finished = true;
}
}
}