图元装配和光栅化

2021年11月21日 8点热度 0条评论

在顶点着色器处理图元顶点之后进入图元装配阶段。这一阶段,执行裁剪、透视分割和Viewport变换操作。

光栅化是将图元转换为一组二维片元的过程。片元由片元着色器处理,代表可以在屏幕上绘制的像素。

一、图元

图标是一组表示顶点位置的顶点描述,是可以用OpenGLES 中的glDrawArrays、glDrawElements、glDrawRangeElements、GLDrawArraysInstanced 和glDrawElementsInstanced 命令绘制的几何形状对象。

OpenGLES 可以绘制的图元:点、线、三角形

三角形图元

代表着描述3D应用程序渲染的几何形状对象时最常用的方法。OpenGLES支持的三角形图元有 GL_TRIANGLES、GL_TRIANGLES_STRIP、GL_TRINAGLES_FAN。类型示意图如下:

三角形图元几种类型

GL_TRIANGLES 绘制一系列单独的三角形,共绘制 n/3 个三角形

GL_TRIANGLES_STRIP 绘制一系列相互连接的三角形,共n - 2 个三角形

GL_TRIANGLES_FAN 绘制一系列项链的三角形,共绘制 n - 2 个三角形

直线图元

OpenGLES 支持的直线图元有GL_LINES、GL_LINE_STRIP 和 GL_LINELOOP, 类型示意图如下:

直线图元几种类型

GL_LINES 绘制一系列不相连的直线,共绘制 n/2 根直线

GL_LINE_STRIP 绘制一系列相连的直线,共绘制 n - 1 跟直线

GL_LINE_LOOP 绘制一系列相连的封闭直线,共绘制 n 条直线。

直线宽度用 glLineWidth(GLfloat width) 指定

void glLineWidth(GLfloat width)

参数说明:

width : 指定线宽,以像素表示,默认宽度为1.0

查询线宽支持范围可以用如下命令查询:

GLfloat lineWidthRange[2];

glGetFoatv(GL_ALIASED_WIDTH_RANGE, lineWidthRange);

点图元

支持的点图元是GL_POINTS。点图元对指定的每个顶点绘制。通常用于粒子系统效果当作点而非正方形绘制,从而实现高效渲染。点图元是指定位置和半径的屏幕对齐的正方形。位置表示正方形的中心,半径用于计算正方形的4个坐标。

gl_PointSize 是用于顶点着色器中输出点半径的内建变量。

查询半径支持非平滑尺寸范围的限制,可以入以下命令:

GLfloat pointSizeRange[2];

glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);

OpenGLES 窗口原点(0, 0) 表示左下方,而点图元的坐标原点则表示左上方。

gl_PointCoord 是只能在渲染图元为点图元时用于片元着色器的内建变量,用mediump 精度限定符限定的vec2 变量,范围是 0~1

绘制一个带有纹理的点图元的片元着色器程序:

#version 300 es

precision mediump float;

uniform sampler2D s_texSprite;

layout(location = 0) out vec4 outColor;

void main() {

outColor = texture(s_texSprite, gl_PointCoord);

}

二、绘制图元

void glDrawArrays(GLenum mode, GLint first,  GLsizei count)

参数说明

mode : 指定要渲染的图元,GL_POINTS、GL_LINES、GL_LINE_STRIP、GL_LINE_LOOP、GL_TRIANGLES、GL_TRIANGLES_STRIP、GL_TRIANGLE_FAN

first : 指定启用的顶点数组中的起始顶点索引

count : 指定要绘制的顶点数量

备注:使用glDrawArrays 绘制多面体,共享的点必须重复计算。因此,使用glDrawArrays 绘制立方体需要的是24个或36个顶点,而不是8个顶点。

void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)

void glDrawElements(GLenum mode. GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices)

参数说明:

mode : 指定要渲染的图元

start : 指定indices 中的最小数组索引

end : 指定indices 中的最大数组索引

count : 指定要绘制的索引数量

type : 指定indices 中保存的元素索引类型,GL_UNSIGNED_BYTE、GL_UNSIGNED_SHORT、GL_UNSIGNED_INT

indices : 指向元素索引存储位置的指针

glDrawArrays 和 glDrawElements 区别

glDrawArrays :传输或指定的数据是真实数据,则绘制时效率更高,但比较吃内存/显存。图形较少/图形很多相同,则更节省空间

glDrawElements : 指定的是索引,更节省内存/显存。图形多且形状不相同时优先考虑。

图元重启

使用图元重启可以在一次绘图调用中渲染多个不相连的图元(如三角形/条形带),能够降低绘图API调用的开销。图元重启的另一种方法时生成退化三角形,但方法不够简洁。

可以通过在索引列表中插入一个特殊索引来重启一个用于索引绘图调用的图元实现。

这个特殊索引时该索引类型的最大可能索引,GL_UNSIGNED_BYTE为255,GL_UNSIGNED_SHORT为65535

启用和禁用图元重启:

// 启用图元

glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);

// 绘制图元

// 禁用图元

glDisable(GL_PRIMITIVE_RESTART_FIXED_INDEX);

驱动顶点

如果没有限定符,那么顶点着色器的输出值在图元中使用线性插值。但是使用平面着色时没有发生插值。因为没有发生插值,所以片元着色器中只有一个顶点值可用。对于给定的图元实例,驱动顶点确定使用顶点着色器的哪个顶点输出,因为只能使用一个顶点。

驱动顶点选择规则如下:

GL_POINTS         i

GL_LINES            2i

GL_LINE_LOOP   如果 i < n, 为 i + 1,i = n,为1

GL_LINE_STRIP   i + 1

GL_TRIANGLES   3i

GL_TRIANGLES_STRIP i + 2

GL_TRIANGLES_FAN    i + 2

几何形状实例化

几何形状实例化可以用一次API调用多次渲染具有不同属性的一个对象。这一功能在渲染大量类似对象时很有用,几何图形实例化降低了想OpenGLES 引擎发送许多 API 调用的CPU处理开销。

void glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount);

void glDrawElementsInstanced(GLenum mode, GLsizei num, GLenum type, const GLvoid *indices, GLsizei instanceCount);

访问每个实例数据的方法:

1、使用 glVertexAttribDivisor

void glVer