在 three.js 中实现聚焦某个物体,或整体内容自适应屏幕,在自身项目测试问题不大,但特殊情况估计还需要调整。
原理
在 three.js 中,控制视图的缩放、平移主要是通过控制镜头的参数和位置来实现。
计算物体的 max bounding box,从而计算出相关的相机参数,比如 top/bottom/left/right/center 等信息。
镜头类型
- 正交相机:正交相机的成像原理比较简单
- 透视相机:需要考虑视角,相对正交而言复杂些
正交相机实现
- 求得物体的的 BoundingBox,得到 viewport 的相关信息(top/bottom/left/right/center)
- 设置相机的 top/bottom/left/right 为 viewport 的值
- 设置相机的 zoom 为 1
- 镜头 lookAt(center)
- 将相机的位置平移到 center 处即可
- 如果应用了 controls,设置 controls.target 为 center
透视相机实现
- 同正交相机一样,计算得到 viewport 信息
- 由于透视相机不存在 top/bottom 等参数,大致有两种实现方式,一种是改变 fov 值,一种是改变相机的位置
- 调整 fov(frame of view) 会改变视角的效果,感觉不是很好,排除(虽然社区也有人这样做)
- 设置 zoom 值为 1
- 通过 top 值,结合 fov 值计算出 distance
- 镜头 lookAt(center)
- 相机位置平移到 center,distance 作为 z 值
- 如果应用了 controls,设置 controls.target 为 center
相机扩展
23D 切换:当相机的视线轴和场景的平面垂直时,使用平行投影,这样给人的感觉就是 2D 视图,所以需要根据透视的视锥体计算出平行投影的视景体
function fromPerspectiveToOrthographic() {
const distance = this.cameraP.position.distanceTo(this.controls.target);
const h = Math.tan(this.camera.fov / 2 * DEG2RAG) * distance;
const r = h * this.cameraP.aspect;
this.cameraO.zoom = 1;
this.cameraO.top = h;
this.cameraO.bottom = -h;
this.cameraO.left = -r;
this.cameraO.right = r;
this.cameraO.updateProjectionMatrix();
}
function fromOrthographicToPerspective() {
const zoom = this.cameraO.zoom;
const distance = this.controls.target.distanceTo(this.cameraP.position);
const eyeDirection = this.cameraP.position.clone().sub(this.controls.target).normalize();
this.cameraP.position.copy(this.controls.target.clone().add(eyeDirection.multiplyScalar(distance / zoom)));
this.cameraP.updateProjectionMatrix();
}