As you pointed out, using the existing THREE.OrbitControls and changing the target does not work, since the camera will not look perpendicular in the bounding box.
I tried different things, with pretty bad results, but here is my job.
In every solution I tried, I always had to calculate (in any order):
- camera position
- camera direction .
In any case, the camera should revolve around something. So, all my decisions are more or less based on THREE.OrbitControls , which acts like, say, the "current state of rotation" and processes all the DOM event events for me.
Looking for the nearest point on AABB
The idea is this:
- The camera rotates
- the nearest point on the AABB from the camera is the place where the camera should look (direction);
- a certain distance d is used to push the camera out of this point (position).
There are 2 cases:
The border

angle

Tested on this (very complex) violin . It is still necessary to fix the upper and lower surfaces, though (feature rotation).
Limited Ratings
This is the idea you described in the question:
- Create the bounding volume that the camera should follow;
- raycast camera position on this BV;
- the new camera position is the intersection point ;
- The new direction of the camera is the normal intersected surface.
I tried it with the geometry of a split block with rounded borders and corners so that the camera rotates at angles.

Given the smoothness of the surface, the result could be very convenient. Unfortunately, the camera abruptly changes direction when the normal of intersection changes, causing unpleasant bumps in motion.
See this (complicated again) violin .
To fix this, we can linearly interpolate the normal along the triangle, but this requires that the normals be calculated in such a way that each normal of the vertex is the average of the normals of the faces to which this vertex belongs.

Please note that this solution is quite heavy (raycasting a lot of faces) and may require some pre-processing to create a BV.
Changing the basics of classic orbit controls
This is not exactly what you are looking for, but it is also suitable for long objects and, frankly, the less complicated decision I made.
The idea is to modify the basis on which the classic THREE.OrbitControls , so that the position changes, but the direction remains the same, for example:

I did this with a special version: THREE.BasisOrbitControls . Take a look at this script .
var basis = new THREE.Matrix4(); basis.makeScale(2.0, 3.0, 4.0); // my object is very long and a bit tall var controls = new THREE.BasisOrbitControl(camera, basis, renderer.domElement);
Note that the resulting camera movement is described by an ellipsoid .
Hope this helps, I'm really interested in a clean solution.