正如您所指出的,使用现有的 THREE.OrbitControls 并修改 target 不起作用,因为相机不会垂直地看边界框。
我尝试了不同的方法,结果很糟糕,但这是我的工作。
在我尝试的每个解决方案中,我总是必须计算(以任何顺序):
- 相机的位置;
- 相机的方向。
无论如何,相机必须围绕某物旋转。所以,我所有的解决方案或多或少都基于THREE.OrbitControls,它充当,比如说,“当前的旋转状态”,并为我处理所有的 DOM 事件。
查看 AABB 上最近的点
思路如下:
- 相机旋转;
- AABB 上的距离相机最近的点是相机应注视的位置(方向);
- 一定距离d用于将相机推离该点(位置)。
有两种情况:
边界
角落
在this (very tricky) fiddle 上测试。仍然需要修复顶面和底面(旋转奇点)。
在边界体积上投射光线
这是您在问题中描述的想法:
- 创建相机应遵循的包围体;
- 在此 BV 上对摄像机位置进行射线投射;
- 相机的新位置是交点;
- 相机的新方向是相交面的法线。
我尝试使用带有圆形边框和角的细分框几何体,以便相机以角度旋转。
考虑到表面的光滑度,结果可能非常方便。不幸的是,当交叉路口的法线发生变化时,相机会急剧改变方向,从而在运动中造成令人不快的颠簸。
见this (tricky again) fiddle。
为了解决这个问题,我们可以沿三角形线性插值法线,但这需要以这样一种方式计算法线,即顶点的每个法线都是该顶点所属面的法线的平均值。
请注意,此解决方案非常繁重(对很多面进行射线投射),并且可能需要一些预处理来创建 BV。
改变经典轨道控制的基础
这不是您要寻找的,但它也适用于长对象,老实说,这是我提出的不太棘手的解决方案。
想法是修改经典THREE.OrbitControls操作的基础,使得位置改变但方向保持不变,如下所示:
我用一个定制的版本来做到这一点:THREE.BasisOrbitControls。看看this fiddle。
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);
请注意,相机的最终运动由椭球体描述。
希望这会有所帮助,我也对干净的解决方案很感兴趣。