基本概念
cone:锥体。
frustum: 截头锥体。也就是截掉头部的截体。如下图:
field of view(FOV): 视野,表示可视范围 。常用角度来表示。
Viewing frustum: 视锥体。视锥体只是截头锥体在透视相机系统中的具体表达。three.js中的视锥体又特指底面为四边形的截头锥体。锥体顶点被视作相机位置。如下图所示:
使用方法
在three.js中,构建函数THREE.PerspectiveCamera,就是用来定义透视投影相机(Perspective Camera)的视锥体的。视锥体是空间物体的容器,物体位于视锥体内的部分才可能会显示出来,位于视锥体外的部分则会被剪切掉。
PerspectiveCamera的用法如下:
const camera = THREE.PerspectiveCamera(fov, aspect, near, far)
- fov 垂直方向(y轴方向)的可视角度
- aspect 实际窗口的纵横比,为保证物体不出现比例上的变形,一般设置为容器的width/height
- near 相机与近平面的距离
- far 相机与远平面的距离
只有这几个参数的话,PerspectiveCamera就只是定义了一个形状。只有形状,没有位置,又怎么能知道某个物体是否在这个形状内呢?
其实,在three.js的坐标系(也称全球坐标系)中,所有三维物体,包括上面定义的camera
,都被设置了一个默认位置的:(0, 0, 0),即原点。全球坐标系示意如下图:
视锥体在坐标系中的位置,示意如下:
如果不改变各个物体的默认位置,camera
就会位于物体的内部,其定义的视锥体如果也正好在物体的外面的话,那就不会有任何的投影,屏幕会是一片空白。
所以,为了完整地投影三维物体,我们可以通过调整camera
的位置或者视锥体的参数(fov/aspect/near/far),来确保三维物体位于视锥体的内部。
代码示例
下面举例说明。
最好结合这个完整示例代码来看。
首先,定义一个位于原点,尺寸为(1,1,1)的立方体。
const scene = new THREE.Scene();
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
定义一个z轴位于5的相机(立方体的z轴最大值为0.5)
const camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
0.1,
10
);
camera.position.set(0, 0, 5);
可以看到立方体完整投影,效果如下图。其中小正方形为立方体背面投影,大正方形为正面投影。近大远小。
调整相机位置,将其移到立方体后方
camera.position.set(0, 0, -0.5)
屏幕为空。
再调整相机方位置,让其只能看到立方体的背面,但看不到前方
camera.position.set(0, 0, 0.4);
效果如下图:
总结
PerspectiveCamer
定义了被称为视锥体的三维虚拟容器,位于其内部的物体会保留,位于外部的被剪切掉。留下的部分,和坐标系一起投影到二维平面如浏览器canvas中,就是我们看到的最终效果。