想象一个场景,场景中有很多的物体排列在不同的位置。我们拿个相机从不同角度拍摄这个场景,相机拍到的就是最终渲染在屏幕上的内容。OpenGL 中并没有相机的概念,需要我们自己完成。相机也被称为眼,从哪个角度去拍或从哪个角度去看。
在深入之前,我们先来看下是怎么在代码中使用的。
const camera = new Camera()
camera.position.x = 0.5
camera.position.y = 0.5
camera.position.z = 0.5
// 设置相机的位置
camera.lookAt([0, 0, 0])
// 设置相机看向原点
const matLoc = gl.getUniformLocation(program, 'uMat')
gl.uniformMatrix4fv(matLoc, false, camera.viewMatrix)
// 获取和设置 uniform
gl_Position = uMat * aPos;
// 在顶点着色器中将顶点乘上这个矩阵
要用相机去拍摄一个场景,我们需要知道相机的位置和相机拍摄的目标。上面代码中首先创建了一个相机实例,然后设置相机的位置,并让相机看向原点。camera.viewMatrix
就是根据相机的位置和看向方向生成的矩阵,我们只需要将这个矩阵应用在物体上,最终渲染出来的画面就是相机拍下来的画面。
如果场景中的物体和相机一起移动,例如向前移动 10 米,那么相机拍摄出来的画面和移动前还是一样的。在 OpenGL 中有个惯例,就是将相机位置固定在原点,并且朝着 -Z 方向看。为了将相机移动到惯例位置,我们需要两个步骤。
1.将相机移动到原点
2.旋转相机,让它看向 -Z 位置。
![](https://i-blog.csdnimg.cn/blog_migrate/114b2c32f0f5859d5c3d5f477221fdbb.png)
视图矩阵
上方的 camera.viewMatrix
矩阵一般称为视图矩阵,它可以让场景中的物体对相机做逆变换,向相机相反的位置移动和旋转。上面有提到场景中的物体和相机一起移动和旋转,那么相机拍摄的画面和移动前拍摄的画面是一样的。相机向前移动,那么场景中的物体就要向后移动,物体要和相机的变换相反。
第一步将相机移动到原点很简单,变换中有讲过,矩阵最右边那一列,就是平移的量。我们这里设置负的相机位置,这样就可以将相机移动到原点了。
[1, 0, 0, -Px,0, 1, 0, -Py,0, 0, 1, -Pz,0, 0, 0, 1
]
第二步旋转相机,让它看向 -Z 位置,也就是要将相机的坐标轴和全局的坐标轴对齐。我们需要先求出相机它自己的坐标轴,如下图所示。
![](https://i-blog.csdnimg.cn/blog_migrate/c8cb64e5271d253125cb18634812c31d.png)
相机的坐标系还是右手坐标系,看向 -Z 方向。
我们可以通过相机的位置减去目标的位置并归一化得到相机坐标轴中的 Z 轴,我们不需要坐标轴的长度只要它的方向,所以将它归一化为单位矢量。
这里会用到矢量的各种计算,如果对矢量不太了解,可以回顾下矢量<