three.js 场景自适应显示

1,283 阅读2分钟

上代码

function computedFov () {
    const box1 = new THREE.Box3()
    box1.setFromObject(window.smallScene)
    const v1 = box1.min.clone().project(camera)
    const v2 = box1.max.clone().project(camera)

    const maxX = Math.max(Math.abs(v1.x), Math.abs(v2.x))
    // const maxY = Math.max(Math.abs(v1.y), Math.abs(v2.y))
    if (maxX > 1) {
        const scaleRatio = maxX;
        const rad = Math.atan((Math.tan(THREE.MathUtils.degToRad(camera.fov / 2)) * camera.aspect * scaleRatio) / camera.aspect)
        const deg = THREE.MathUtils.radToDeg(rad)
        const fov = deg * 2
        camera.fov = fov
        camera.updateProjectionMatrix()
    }
}

解释

一般3d制作软件,可以导出建议的渲染相机,会给提供相机的position,rotation,fov等信息。但是真实在前端渲染的情况中,浏览器的宽高比千奇百怪,直接使用提供的相机信息可能存在场景渲染不全问题。那保证在几乎所有宽高比都能完整展示场景,大概就是3d自适应了。

思路

可以直接使用提供的position,rotation,也可以是直接使用模型中的相机,和相机动画。根据前端的宽高比信息修改fov达到可以修改视野范围的目的。 fov的定义是垂直方向的视角。 我的思路是根据现有的fov,计算出剪裁空间中,场景包围盒的坐标。如果有大于1的。说明(可能)存在视野外的物体当前看不到,然后根据剪裁空间大于1的坐标为倍率,对fov进行修改。代码如上。 因为原始fov由设计提供,我完全相信原始fov能够包含所有垂直方向模型的范围,所以我在这里只计算了水平方向。如果需要计算垂直方向,计算方法也差不多,去掉宽高比部分就是垂直方向的调整。

反思

因为使用的api是aabb包围盒。所以给的max和min可能并没有物体需要显示,所以这种算法还是粗略的,但还算是简单有效。 这篇文章算是抛砖引玉,如果有大神可以精确算出当前相机位置的最小的fov,请不吝赐教。