跳到主要内容
3D Playground
Three.js 核心第 13 / 13 节

相机:透视、正交与视锥

进阶WebGL

相机定义一个“可见空间”

相机看到的范围是一个封闭的体积,叫视锥体(frustum)。只有在视锥体内的东西会被画出来。CameraHelper 能把它画成线框,示例左半屏用另一台“观察者相机”从远处看这台相机,右半屏显示它实际看到的画面。

PerspectiveCamera:透视

new PerspectiveCamera(fov, aspect, near, far)

  • fov:垂直视野角度(度)。小 fov 像长焦镜头,画面压缩;大 fov 像广角,边缘拉伸。
  • aspect:宽高比,应等于画布(或视口)的宽 / 高。
  • 视锥体是一个被截掉尖端的金字塔,所以远处的物体看起来更小——这就是透视。

OrthographicCamera:正交

new OrthographicCamera(left, right, top, bottom, near, far)

  • 用世界单位定义一个长方体视野,远近物体大小相同,平行线保持平行。
  • 常用于 2D 游戏、CAD、等距视角(isometric)、阴影相机和 UI。
  • 为了不变形,(right - left) / (top - bottom) 应等于视口宽高比,示例在 resize 时一起更新。

near 与 far

小于 near 或大于 far 的部分会被裁掉。把 near 拉大,你会看到离相机近的柱子被“切开”;把 far 拉小,远处的柱子会消失。不要为了“保险”把 near 设得极小(如 0.0001)、far 设得极大:深度缓冲的精度主要集中在近处,比例太悬殊会导致远处表面互相闪烁(z-fighting)。

修改后记得更新

改了 fov、aspect、near、far、zoom 或正交的边界之后,必须调用 camera.updateProjectionMatrix(),否则投影矩阵还是旧的。CameraHelper 也需要 helper.update() 才会跟着变化。

一张画布,两个视口

分屏用的是 renderer.setViewport 和 renderer.setScissor(开启 setScissorTest(true)),在同一画布的不同矩形区域里各渲染一次。注意坐标原点在左下角。渲染右半屏时,我们隐藏了 CameraHelper,否则相机会“看见”自己的视锥线。

切换 perspective / orthographic,看右半屏的柱子阵列:透视下汇聚于远方,正交下保持平行。

核心 API

THREE.PerspectiveCameraTHREE.OrthographicCameracamera.updateProjectionMatrixTHREE.CameraHelpercamera.zoomrenderer.setViewportrenderer.setScissorrenderer.setScissorTest

动手试试

  1. 1把 near 调到 6,观察右半屏里靠近相机的柱子如何被切开。
  2. 2在 updateCameras 里删掉 persp.updateProjectionMatrix(),再拖动 fov,看看会发生什么。
  3. 3把 fov 调到 15 并让相机后退(改 orbit 半径),模拟长焦镜头的“压缩感”。
  4. 4把正交相机放到正上方 (0, 10, 0) 往下看,做一个俯视小地图。
运行中