1. 摄像机和坐标

1.1. 使用视图矩阵

视图矩阵(View Matrix)是一个用于将世界坐标系中的物体转换到摄像机视角的矩阵。它定义了摄像机的位置、方向和朝向,从而决定了场景中物体在摄像机视角下的显示方式。

  • 摄像机向右平移:相当于整个场景中的物体向左平移。
  • 摄像机向上平移:相当于整个场景中的物体向下平移。
  • 摄像机向左旋转:相当于整个场景中的物体向右旋转

1.1.1. 视图矩阵的作用

视图矩阵的主要作用是将场景中的物体从世界坐标系转换到摄像机坐标系。在摄像机坐标系中,摄像机被假设位于原点 (0, 0, 0),并朝向特定方向(通常是 -Z 轴方向)。

1.1.2. 视图矩阵的组成

视图矩阵通常由以下三个部分组成:

摄像机的位置(Position):定义摄像机在世界坐标系中的位置。
摄像机的方向(Orientation):定义摄像机的朝向,包括“前方向”(Forward)、“右方向”(Right)和“上方向”(Up)。
平移和旋转变换:将场景中的物体从世界坐标系转换到以摄像机为中心的坐标系。

1.1.3. 视图矩阵的计算

视图矩阵通常是一个 4x4 矩阵,可以通过以下步骤计算:

定义摄像机的方向向量:

Forward:摄像机的前方向(目标点 - 摄像机位置)。
Right:摄像机的右方向(通过叉积计算)。
Up:摄像机的上方向(通过叉积计算)。
构造旋转矩阵:基于摄像机的方向向量。

添加平移变换:将摄像机的位置应用到矩阵中。

缩放摄像机没有太大意义,因此摄像机的缩放比例为(1, 1, 1)。

1.1.4. 用于创建变换矩阵的函数

以下代码在旋转时,只考虑了Z轴旋转

glm::mat4 buildMatrix(glm::vec3 trans, float rot, glm::vec3 scale)
{
	using glm::mat4;
	mat4 translation = glm::translate(trans);
	mat4 rotation = glm::rotate(rot, glm::vec3(0.0, 0.0, 1.0));
	mat4 scaler = glm::scale(scale);
	return translation * rotation * scaler;
}

1.1.5. 用于创建视图矩阵的函数

glm::mat4 buildViewMatrix(CameraData cam)
{
	using namespace glm;
	return inverse(buildMatrix(cam.position, cam.rotation, vec3(1, 1, 1)));
}

1.2. 视图空间

视图空间是顶点乘以视图矩阵后所处的坐标空间。在视图空间中,坐标系的轴也会改变方向,视图空间完全相对于摄像机。因此原点(0, 0, 0)位于摄像机的位置,Z 轴指向摄像机的前方。

1.3. 裁剪空间

裁剪空间(Clip Space)是图形渲染管线中的一个重要坐标空间,它是顶点经过模型矩阵、视图矩阵和投影矩阵变换后所处的空间。

特点

  • 范围:裁剪空间的坐标范围通常是一个标准化的范围,通常为 [-w, w],其中 w 是齐次坐标的第四个分量。

  • 坐标形式:裁剪空间中的坐标是齐次坐标,表示为 (x, y, z, w)。

  • 作用:裁剪空间用于确定哪些顶点在视锥体内,哪些顶点需要被裁剪掉。
    转换过程
    顶点从模型空间到裁剪空间的转换过程如下:

  • 模型矩阵:将顶点从模型空间转换到世界空间。

  • 视图矩阵:将顶点从世界空间转换到摄像机(视图)空间。

  • 投影矩阵:将顶点从视图空间转换到裁剪空间。

最终的变换公式为:

//顶点着色器中的参考代码如下  
gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * vec4(aPosition, 1.0);

裁剪空间的作用
裁剪空间的主要作用是为后续的裁剪操作和屏幕映射做准备:

  • 裁剪操作:在裁剪空间中,顶点的坐标范围被限制在 [-w, w],超出范围的顶点会被裁剪掉。
  • 归一化设备坐标(NDC):裁剪空间坐标经过透视除法(x/w, y/w, z/w)后,转换为标准化设备坐标(NDC),范围为 [-1, 1]。

一些简单的结论

  1. 只能比较位于同一坐标空间中的两个物体或顶点之间的位置、旋转和缩放关系。
  2. 通过将网格顶点乘以特定矩阵,可以将其从一个坐标空间转换到另一个坐标空间。
  3. 乘以逆矩阵总是与乘以非逆矩阵的结果相反。

1.4. 透视投影

透视投影(Perspective Projection)是一种常见的投影类型,它可以将三维场景映射到二维屏幕上。透视投影的主要特点是,远处的物体比近处的物体看起来更小,形成近大远小的效果。

在上图中,可以看到视锥被定义为近剪裁平面和远剪裁平面之间的一个区域。位于该区域内的物体会被渲染,而位于区域外的物体则会被裁剪掉。可以使用 glm::ortho() 函数创建一个正交投影矩阵,也可以使用 glm::perspective() 函数创建一个透视投影矩阵。

// 版本 2: 三维正交投影矩阵,包含近裁剪面和远裁剪面
template <typename T, qualifier Q>
GLM_FUNC_DECL mat<4, 4, T, Q> ortho(
    T left, T right, T bottom, T top, T zNear, T zFar
);

参数解释

  • left :指定视景体左边界的坐标值。
  • right :指定视景体右边界的坐标值。
  • bottom :指定视景体下边界的坐标值。
  • top :指定视景体上边界的坐标值。
  • zNear (可选):指定近裁剪面的距离,默认值为 -1.0。
  • zFar (可选):指定远裁剪面的距离,默认值为 1.0。

返回值
返回一个 4x4 的正交投影矩阵,类型为 glm::mat4 。

示例代码
当前的视口大小为 768x768,视景体的大小为 1.0x1.0,近裁剪面和远裁剪面的距离分别为 0.0 和 -10.0。

// 创建一个三维正交投影矩阵,包含近裁剪面和远裁剪面
glm::mat4 projectionMatrix = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, 0.0f, -10.0f);

当前的视口大小为 1024x768,视景体的大小为 1.33x1.0,近裁剪面和远裁剪面的距离分别为 0.0 和 -10.0。

// 创建一个三维正交投影矩阵,包含近裁剪面和远裁剪面
glm::mat4 projectionMatrix = glm::ortho(-1.33f, 1.33f, -1.0f, 1.0f, 0.0f, -10.0f);
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐