LearnOpenGL笔记: 2025年8月13日
任何位于近平面前方的坐标都会被裁剪,同样,位于远平面后方的坐标也会被裁剪。我们通常的做法是,在我们自己确定的坐标范围(或空间)内指定坐标,然后在顶点着色器中将这些坐标变换为标准化设备坐标(NDC)。为了将顶点坐标从视图空间转换到裁剪空间,我们定义了一个所谓的投影矩阵,它指定了一个坐标范围,所有超出这个范围的坐标都不会被映射到 -1.0 和 1.0 之间,因此会被裁剪掉。正交投影矩阵会直接将坐标映射
我们通常的做法是,在我们自己确定的坐标范围(或空间)内指定坐标,然后在顶点着色器中将这些坐标变换为标准化设备坐标(NDC)。这些NDC随后被传递给光栅化器,以将它们转换为屏幕上的2D坐标/像素。
将它们变换到几个中间坐标系的好处是,某些操作/计算在特定的坐标系中会更容易执行,这一点很快就会变得明显。
1.全局图景
为了将坐标从一个空间变换到下一个坐标空间,我们将使用几个变换矩阵,其中最重要的是模型矩阵、视图矩阵和投影矩阵。
我们的顶点坐标首先以局部坐标的形式存在于局部空间中,然后进一步处理为世界坐标、视图坐标、裁剪坐标,最终变成屏幕坐标。

1.局部空间
局部空间是您的物体本地的坐标空间,也就是您的物体开始时所在的地方。
2.世界空间
我们希望为每个物体定义一个位置,将它们放置在一个更大的世界中。世界空间中的坐标正如其名字所表示的那样:所有顶点相对于一个(游戏)世界的坐标。这是您希望将物体变换到的坐标空间,使得它们都分散在各个地方(最好以现实的方式)。您物体的坐标从局部空间变换到世界空间;这通过模型矩阵来完成。
3.视图空间
视图空间是人们通常所说的OpenGL的“相机”(有时也被称为相机空间或眼睛空间)。视图空间是将世界空间坐标转换为位于用户视野前方的坐标的产物。
4.裁剪空间
在每个顶点着色器运行结束时,OpenGL期望坐标值在特定范围内,任何超出该范围的坐标都会被裁剪掉。被裁剪的坐标会被丢弃,因此剩下的坐标最终会成为屏幕上可见的片段。
为了将顶点坐标从视图空间转换到裁剪空间,我们定义了一个所谓的投影矩阵,它指定了一个坐标范围,所有超出这个范围的坐标都不会被映射到 -1.0 和 1.0 之间,因此会被裁剪掉。
请注意,如果一个图元(例如一个三角形)只有部分超出了裁剪体积,OpenGL会将这个三角形重建为一个或多个三角形,以使其适合在裁剪范围内。
投影矩阵创建的这个视图盒子被称为视锥体(frustum),任何最终落在这个视锥体内的坐标都会出现在用户的屏幕上。将指定范围内的坐标转换为可以轻松映射到二维视图空间坐标的标准化设备坐标(NDC)的整个过程被称为投影。
当所有顶点被转换到裁剪空间后,会执行一个最终操作,称为透视除法。我们用位置向量的齐次坐标 w 分量来分别除以位置向量的 x 、 y 和 z 分量;透视除法是将四维裁剪空间坐标转换为三维标准化设备坐标的关键步骤。
(1) 正交投影
正交投影矩阵定义了一个类似立方体的视锥体盒子,这个盒子确定了裁剪空间,其中任何超出这个盒子的顶点都会被裁剪掉。在创建正交投影矩阵时,我们会指定可见视锥体的宽度、高度和长度:
视锥体定义了可见的坐标范围,并通过宽度、高度以及近平面和远平面来指定。任何位于近平面前方的坐标都会被裁剪,同样,位于远平面后方的坐标也会被裁剪。正交投影的视锥体会直接将视锥体内的所有坐标映射到标准化设备坐标(NDC),而不会产生任何特殊的副作用,因为它不会影响变换后向量的 w 分量;如果 w 分量始终保持为 1.0,那么透视除法不会改变坐标值。
为了创建一个正交投影矩阵,我们使用GLM库中内置的函数glm::ortho:
glm::ortho(0.0f, 800.0f, 0.0f, 600.0f, 0.1f, 100.0f);
前两个参数指定了视锥体的左侧和右侧坐标,第三和第四个参数指定了视锥体的底部和顶部。通过这4个点,我们定义了近平面和远平面的大小,而第五和第六个参数则定义了近平面和远平面之间的距离。这个特定的投影矩阵会将所有位于这些x、y和z范围值之间的坐标转换为标准化设备坐标。
正交投影矩阵会直接将坐标映射到二维平面上,也就是你的屏幕,但在现实中,直接投影会产生不真实的结果,因为这种投影没有考虑透视效果。而透视投影矩阵正是用来解决这个问题的。
在 OpenGL(以及大多数 3D 图形系统)里,“透视”确实是指近大远小的效果。换句话说,就是模拟人眼或相机在真实世界中的视觉规律:离观察者近的物体看起来大,远的物体看起来小。
(2) 透视投影
正如你所看到的,由于透视的原因,这些线条似乎在足够远的距离上汇聚到一点。这正是透视投影试图模仿的效果,它通过使用透视投影矩阵来实现。投影矩阵将给定的视锥体范围映射到裁剪空间,同时也以一种方式操纵每个顶点坐标的w值,使得顶点坐标离观察者越远,这个w分量就变得越大。一旦坐标被转换到裁剪空间,它们的范围是-w到w(超出这个范围的坐标会被裁剪)。OpenGL要求可见坐标最终在顶点着色器输出时落在-1.0到1.0的范围内,因此一旦坐标进入裁剪空间,透视除法就会应用于裁剪空间坐标:
每个顶点坐标的分量都会被其w分量除,使得顶点离观察者越远,顶点坐标就越小。这也是w分量很重要的另一个原因,因为它帮助我们实现透视投影。得到的结果坐标就位于标准化设备空间中。
在GLM中,可以如下创建一个透视投影矩阵:
glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)width/(float)height, 0.1f, 100.0f);
glm::perspective 函数的作用是再次创建一个较大的视锥体,定义了可见空间。任何超出视锥体范围的物体都不会进入裁剪空间体积,因此会被裁剪掉。透视视锥体可以被想象成一个形状不规则的盒子,其中盒子内的每个坐标都会被映射到裁剪空间中的一个点。透视视锥体的图像如下所示:
它的第一个参数定义了视野角度(field of view,简称FOV),用于设置视图空间的大小。为了获得更接近现实的视图效果,通常将其设置为45度,但如果你想要类似《毁灭战士》风格的效果,可以将其设置为更高的值。
第二个参数设置宽高比(aspect ratio),是通过将视口(viewport)的宽度除以其高度来计算的。
第三个和第四个参数分别设置了视锥体的近平面和远平面。我们通常将近平面距离设置为0.1,远平面距离设置为100.0。所有位于近平面和远平面之间且在视锥体内的顶点都会被渲染。
每当你的透视矩阵中的近平面值设置得过高(比如10.0)时,OpenGL会裁剪掉所有靠近相机的坐标(0.0到10.0之间的部分)。这可能会导致一种你在视频游戏中可能见过的视觉效果,当你不自然地靠近某些物体时,你会看到物体穿模。
由于正交投影不使用透视投影,远处的物体看起来不会变小,这会产生一种奇怪的视觉效果。因此,正交投影主要用于二维渲染以及一些建筑或工程应用,因为在这些场景中,我们不希望顶点被透视效果扭曲,下面就是2种投影的对比:
5.将所有整合起来
我们为上述提到的每个步骤创建一个变换矩阵:模型矩阵、视图矩阵和投影矩阵。然后,顶点坐标按照以下方式被转换为裁剪坐标:
裁剪坐标 = 投影矩阵 * 视图矩阵 * 模型矩阵 * 顶点坐标
这个过程可以总结为:
• 模型矩阵:将局部坐标(模型坐标)转换为世界坐标。
• 视图矩阵:将世界坐标转换为视图坐标(相机坐标)。
• 投影矩阵:将视图坐标转换为裁剪坐标。
• 透视除法:将裁剪坐标转换为标准化设备坐标(NDC)。
最终,裁剪坐标经过透视除法后,会映射到屏幕坐标上,从而在屏幕上渲染出可见的片段。
请注意矩阵乘法的顺序是反过来的(记住我们需要从右到左阅读矩阵乘法)。然后,得到的顶点应该被赋值给顶点着色器中的gl_Position,OpenGL 将会自动执行透视除法和裁剪操作。
更多推荐


所有评论(0)