Three.js - 正交相机

IT技术 javascript 3d three.js
2021-02-09 17:48:57

我正在开发一个显示一些 3D 模型的应用程序。我们加载模型,创建网格,将它们添加到场景中……标准程序。添加最后一个网格后,我们计算边界框以移动相机并覆盖所有场景,使用总几何的大小和视口的大小进行数学计算。

    if (bounds.bx / bounds.by < camera.aspect) {
        /* Vertical max */
        r = bounds.by / (2 * Math.tan(Math.PI / 8));
    } else {
        /* Horizontal max */
        hFOV = 2 * Math.atan(Math.tan(Math.PI / 8) * camera.aspect);
        r = bounds.bx / (2 * Math.tan((hFOV / 2)));
    }

bounds是一个包含边界框宽度和高度的对象。经过这个计算,我们移动相机(加上一点比例,只是为了美观,我们希望在几何体和屏幕边框之间留出一点空间:))并渲染

    camera.position.z = r * 1.05;

到目前为止,这已实现并运行正常。这是通过 PerspectiveCamera 完成的。现在我们想改变它并使用 OrthographicCamera ......结果是一团糟。模型太小,我们失去了轨迹球控件的鼠标滚轮缩放,并且移动相机的算法不再起作用。另外我不明白相机构造函数的参数......这些宽度和高度是用于几何图形还是视口?

3个回答

在 Three.js 中实例化正交相机的模式是:

var camera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, near, far );

其中widthheight是以世界空间单位测量的相机长方体形截锥体的宽度和高度

nearfar到截锥体的近平面和远平面世界空间距离。双方nearfar应大于零。

为防止失真,您通常希望正交相机 ( width / height) 的纵横比与渲染画布的纵横比相匹配。(见下面的*注)

不幸的是,three.js 示例中的许多示例都将window.innerWidthwindow.innerHeight作为参数传递给此构造函数。仅当正交摄影机用于渲染纹理,或者正交场景的世界单位以像素为单位时,这样做才有意义。


*注意:实际上,相机纵横比应该与渲染器视口的纵横比相匹配。视口可以是画布的子区域。如果不直接使用 设置渲染器的视口renderer.setViewport(),则视口将与画布大小相同,因此具有与画布相同的纵横比。

三.js r.73

我明白,但是......我怎样才能在 Z 轴上移动相机,就像我在透视模式下使用上面的代码所做的那样?
2021-03-16 17:48:57
@AlvinfromDiaspar 是的,它应该,但不一定是。
2021-03-25 17:48:57
向前或向后移动相机不会改变正交投影。
2021-03-26 17:48:57
现在我明白了。那么,一定要使用camera.setZoom吗?我在这里有点困惑,因为构造函数中使用的宽度和高度似乎不会改变渲染窗口的大小。例如,我使用 (1600, 1200) 作为 w/h,和 (16, 12) 结果是相同的。
2021-04-06 17:48:57
@expiredninja 场景会显得拉长。
2021-04-11 17:48:57

供将来参考: 更新的视频

var w = container.clientWidth;
var h = container.clientHeight;
var viewSize = h;
var aspectRatio = w / h;

_viewport = {
    viewSize: viewSize,
    aspectRatio: aspectRatio,
    left: (-aspectRatio * viewSize) / 2,
    right: (aspectRatio * viewSize) / 2,
    top: viewSize / 2,
    bottom: -viewSize / 2,
    near: -100,
    far: 100
}

_camera = new THREE.OrthographicCamera ( 
    _viewport.left, 
    _viewport.right, 
    _viewport.top, 
    _viewport.bottom, 
    _viewport.near, 
    _viewport.far 
);

在我的特定情况下,我的世界单位是像素。因此,我使用container.clientWidthandcontainer.clientHeight作为宽度和高度。你可能不想这样做。

哦,我明白了,哈哈。感谢您的解释
2021-03-13 17:48:57
@Matteo 您似乎有根本的误解,但这不是讨论它的合适场所。如果您无法通过实验自行解决,请重新发布。负近平面将渲染相机后面的对象。
2021-03-14 17:48:57
添加了新的视频链接
2021-03-28 17:48:57
1. 正交相机参数采用世界单位。你的世界单位是像素吗?2. 另外,不管你过去看到过什么——或者在视频中——近平面应该是正的,所以平截头体在相机前面。
2021-04-01 17:48:57
+1的视频链接,-1的代码(对不起!),具体是:var viewSize = h;不是viewSize应该完全依赖于大小(世界coords)使用场景中的对象。
2021-04-08 17:48:57
            camera.top = (.95*camera.top);
            camera.bottom = (.95*camera.bottom);
            camera.left = (.95*camera.left);
            camera.right = (.95*camera.right);