跳到主要内容

03-深入理解透视相机和视椎体

刚接触 Three.js 透视相机的视椎体确实是个比较难理解的概念。

这节我们把它可视化的在 3D 场景中展示出来,这样就容易理解了。

代码

不解释代码了

import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

const scene = new THREE.Scene();

const axesHelper = new THREE.AxesHelper(200);
scene.add(axesHelper);

const width = window.innerWidth;
const height = window.innerHeight;

const camera = new THREE.PerspectiveCamera(60, width / height, 1, 1000);
camera.position.set(200, 200, 200);
camera.lookAt(0, 0, 0);

const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height)

function render() {
renderer.render(scene, camera);
requestAnimationFrame(render);
}

render();

document.body.append(renderer.domElement);

const controls = new OrbitControls(camera, renderer.domElement);

开始

要看视椎体的话,我们需要创建另一个相机,用这个相机来观察:

Three.js 提供了一个 CameraHelper 来画视椎体,传入 camera 就行:

image-20250508174022848

我们单独创建一个 PerspectiveCamera,传入 CameraHelper:

image.png

把 AxesHelper 注释掉,不然比较乱。

const camera2 = new THREE.PerspectiveCamera(20, 16 / 9, 100, 300);
const cameraHelper = new THREE.CameraHelper(camera2);
scene.add(cameraHelper);

现在就能看到视椎体了:

image-20250508204506959

这里先顺便说下 OrbitContols 的操作:鼠标左键拖动可以上下左右旋转,鼠标右键拖动可以平移,鼠标滚轮可以缩放。

然后来说回这个视椎体:

image-20250508155719024

THREE.PerspectiveCamera(20, 16 / 9, 100, 300)

第一个参数是角度(fov),第二个参数是宽高比,第三个是近裁截面的距离(near),第四个参数是远裁截面的距离(far)。

这些参数是怎么影响这个视椎体的呢?

dat.gui调试

我们用 dat.gui 来可视化调试下:

import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

image.png

const camera2 = new THREE.PerspectiveCamera(20, 16 / 9, 100, 300);
let cameraHelper = new THREE.CameraHelper(camera2);
scene.add(cameraHelper);

const gui = new GUI();
function onChange() {
camera2.updateProjectionMatrix();
cameraHelper.update();
}
gui.add(camera2, 'fov', [30, 60, 10]).onChange(onChange);
gui.add(camera2, 'aspect', {
'16/9': 16/9,
'4/3': 4/3
}).onChange(onChange);
gui.add(camera2, 'near', 0, 300).onChange(onChange);
gui.add(camera2, 'far', 300, 800).onChange(onChange);

改了参数之后要调用 camera2 的 updateProjectionMatrix 方法来触发 camera 的更新,然后调用 cameraHelper.update 来更新 helper。

自己调节可以看到效果

我们看到的 3D 世界就是这个视椎体的 near 和 far 之间的部分。

在网页上显示的话,宽高比一般都是设置网页的宽高比也就是 window.innerWidth / window.innerHeight

而 near 一般设置 0.1,默认值也是 0.1

具体的参数:https://threejs.org/docs/?q=PerspectiveCamera#api/zh/cameras/PerspectiveCamera

near 默认值 0.1、far 默认值 2000,fov 默认值 50,aspect 默认值是 1

一般这个 aspect 是要改的。

near 设置了比较大,那离摄像机很近的一些物体就被截掉看不到了。

比如下雪的时候,离摄像机特别近的雪花会很大,这时候我们不希望看到特别大的雪花,就把近裁截面距离设置的大一点,把特别近的一些物体裁截掉。

far 就比较容易理解了,如果 far 不够大,那物体会被裁截看不到了。

所以我们经常会修改改 far 的范围,让它包含所有物体。

而 fov 角度影响的是能看的范围的多少,同时也会影响离物体的远近:

image.png

image.png

当你想物体离的远一点,除了调节相机的 position,不妨调小一些 fov 试试。

总结

我们通过 CameraHelper 来把视椎体可视化的画出来,然后用 dat.gui 调节了 fov、aspect、near、far 4 个参数,看了视椎体的变化。

  • fov:影响可视范围角度、离物体远近
  • aspect:可视范围宽高比,一般设置网页宽高比
  • near:近裁截面距离,一般保持默认值 0.1,当你需要截掉一些特别近的物体的时候,把它加大
  • far:远裁截面距离,如果有的物体被裁截掉看不到了,就需要调大 far 把它们包含进来

这就是透视相机的视椎体的 4 个参数,后面会经常用到,需要对它们有透彻的理解。