目录
- 一、图元装配
- 1.1 坐标系统
- 1.1.1 裁剪
- 1.2 透视分割
- 1.3 视口变换

在上一篇文章【我的OpenGL学习进阶之旅】介绍一下 绘制图元中,我们介绍了如何绘制图元,这篇我们来介绍一下图元装配。
一、图元装配
下图展示了图元装配阶段。通过glDraw***提供的顶点由顶点着色器执行,顶点着色器变化的每个顶点包括描述顶点(x,y,z,w)值的顶点位置。
图元类型和顶点索引确定将被渲染的单独图元。
对于每个单独图元(三角形、直线和点精灵)及其对应的顶点,图元装配阶段执行如下图所示的操作。

在讨论OpenGL ES 中如何光栅化图元之前,我们需要理解OpenGL ES 3.0 中使用的各种坐标系统。这对于更好地理解 OpenGL ES 3.0管线不同阶段中顶点坐标发生的变化是必需的。
1.1 坐标系统
下图展示了顶点通过顶点着色器和图元装配阶段时的坐标系统。

顶点以物体或者本地坐标空间输入到OpenGL ES ,这是最困难用来建模和存储一个对象的坐标空间。
在顶点着色器指向之后,顶点位置被认为是在裁剪坐标空间内。
顶点位置从本地坐标空间(也就是物体坐标)到裁剪坐标空间的变化通过加载执行这一转换的对应矩阵来完成,这些矩阵保存在顶点着色器中定义的对应统一变量中。
在后续的博客再介绍如何将顶点位置从对象变化到裁剪坐标,以及如何在顶点着色器中加载对应的矩阵以执行这一变换。
1.1.1 裁剪
为了避免在可视景体之外处理图元,图元被裁剪到裁剪空间。
执行顶点着色器之后的顶点位置处于裁剪坐标空间内。
裁剪坐标是有(Xc,Yc,Zc,Wc)指定的同类坐标。在裁剪空间(Xc,Yc,Zc,Wc)中定义的顶点坐标根据视景体(又称裁剪体)裁剪。
裁剪体由6个裁剪平面定义,这些平面被称作 近、远、左、右、上、下裁剪平面。如下图所示:
在裁剪坐标中,裁剪体如下:
-Wc<=Xc<=Wc
-Wc<=Yc<=Wc
-Wc<=Zc<=Wc
前面的6项检查根据需要裁剪的图元,有助于确定平面的列表。

裁剪阶段把每个图元裁剪为上图所示的裁剪体。
我们在这里所说的“图元”,是指用
GL_TRIANGLES绘制的单独三角形列表中的每一个三角形,或者一个三角形条带或者扇形中的一个三角形,- 或者用
GL_LINES绘制的单独直线列表中的一条指向,或者一个直线条带或者闭合折线中的一条直线 - 或者点精灵列表中的一个特定点。
对于每种图元类型,执行如下操作:
-
裁剪三角形
- 如果三角形完全在视景体内部,则不执行任何裁剪。
- 如果三角形完全在视景体之外,则该直线被抛弃。
- 如果三角形部分在视景体内,则根据相应的平面裁剪三角形。裁剪操作将生成新的顶点,这些顶点被裁剪到安排为三角扇形的平面。
-
裁剪直线
- 如果直线完全在视景体内部,则不执行任何裁剪。
- 如果直线完全在视景体之外,则该直线被抛弃。
- 如果直线部分在视景体内,则直线被裁剪并生成相应的新顶点。
-
裁剪点精灵
- 如果点位置在近或者远裁剪平面之外,或者如果表示点精灵的正方形在裁剪体之外,裁剪阶段将抛弃点精灵
- 否则,它将不做变化地通过该阶段,点精灵将在其从裁剪体内部移到到外部时裁剪,反之亦然。
在图元根据六个裁剪平面进行裁剪时,顶点坐标经历透视分离,从而称为规范化的设备坐标。
规范化的设备坐标范围是
-1.0 到 1.0
1.2 透视分割
透视分割取得裁剪坐标(Xc,Yc,Zc,Wc)指定的点,并将其投影到屏幕或者视口上。
这个投影通过将(Xc,Yc,Zc) 除以 Wc 进行。执行(Xc/Wc)、(Yc/Wc)、(Zc/Wc)之后,我们得到规范化的设备坐标(Xd,Yd,Zd)。
这些坐标被称为规范化设备坐标,因为它们落在[ -1.0 ... 1.0 ] 区间。
这些规范化的(Xd, Yd)坐标根据视口的大小将被转换为真正的屏幕(或者窗口)坐标。规范化的(Zd)坐标将用glDepthRangf指定的near和far深度值转换为屏幕的Z值。这些转换在视口变化阶段进行。
1.3 视口变换
视口是一个二维矩形窗口区域,是所有OpenGL ES渲染操作最终显示的地方。
视口变换可用如下API调用设置:
void glViewport(GLint x, GLint y, GLsizei w, GLsizei h)
参数说明:
x, y
指定视口的左下角的窗口坐标,以像素表示w,h
指定视口的宽度和高度,以像素表示,这些值必须大于0
从规范化设备坐标(Xd,Yd,Zd)到窗口坐标(Xw,Yw,Zw)的转换用如下变换给出:

在这个变换中,Ox = x + w / 2, Oy = y + h / 2, n和f代表所需的深度范围。
深度范围值n和f可以用如下API调用设置:
void glDepthRangef(GLclampf n, GLclampf f)
参数说明:
n、f指定所需的深度范围。n和f的默认值分别为0.0 和 1.0。 这两个值限于(0.0 ,1.0)区间内。
glDepthRangef 和 glViewport指定的值用于将顶点位置从规范化设备坐标转换为窗口(屏幕)坐标。
初始视口状态被设置为 w = width , h = height ,分别是OpenGL ES 渲染应用程序创建的窗口的宽度和高度。
这个窗口由 eglCreateWindowSurface中指定的EGLNativeWindowType win 参数给出。