一、简介
在 OpenGL ES 2.0 中,使用 glDrawArrays
和 glDrawElements
两个接口绘制图元。
在 OpenGL ES 3.0 中,又新增了 glDrawRangeElements
、glDrawElementsInstanced
和 glDrawArraysInstanced
三个接口用于绘制图元。
二、函数介绍
1. glDrawArrays
/**
* @param mode 渲染的图元模式,有:GL_POINTS、GL_LINES、GL_LINE_LOOP、GL_LINE_STRIP、GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN
* @param first 起始位置
* @param count 顶点数量
*/
void glDrawArrays(GLenum mode, GLint first, GLsizei count);
2. glDrawElements
/**
* @param mode 渲染的图元模式,有:GL_POINTS、GL_LINES、GL_LINE_LOOP、GL_LINE_STRIP、GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN
* @param count 顶点数量
* @param type 元素类型,有:GL_UNSIGNED_BYTE、GL_UNSIGNED_SHORT、GL_UNSIGNED_INT
* @param indices 元素索引数组
*/
void glDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices);
3. 区别
首先,这两个函数的作用都是从一个数据数组中提取数据,然后渲染图元。
区别在于:glDrawArrays
是直接绘制真实的顶点数据,而 glDrawElements
是按照指定的索引顺序取出真实数据再绘制。
于是对于顶点存在共享的场景时,使用 glDrawElements
对于重复的顶点数据只需要传输一份数据,绘制时通过索引反复的获取其值,最终降低内存占用和内存带宽需求。
三、图元介绍
上面我们知道,渲染的时候需要指定一个渲染的图元模式,下面我们就详细介绍一下这些图元和图元模式。
1. 点精灵
对应的模式为 GL_POINTS,即在每个顶点位置绘制一个点。OpenGL ES 中绘制的点实则是一个方块,顶点位置是方块的中心点,边长在顶点着色器中由内建变量 gl_PointSize
指定。
点的尺寸大小范围可以通过如下方式获取:
GLfloat pointSizeRange[2];
glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
如果我们想自定义点的外形,通常可以使用纹理。一个使用纹理的片段着色器示例如下:
#version 300 es
precision mediump float;
uniform sampler2D u_TextureUnit;
layout(location = 0) out vec4 outColor;
void main() {
outColor = texture2D(u_TextureUnit, gl_PointCoord);
}
这样我们在外面给 u_TextureUnit
指定纹理的 id 即可,关于纹理的相关使用后续文章再介绍。
还有上例中我们使用到了一个内建变量 gl_PointCoord
,它只在绘制点精灵时可以使用,描述了这个点内部的坐标空间,其左上角为 (0, 0),右下角为 (1, 1)。
2. 直线
对应的模式为 GL_LINES、GL_LINE_LOOP、GL_LINE_STRIP,用指定的顶点绘制相应的线段。
如图,假设指定的顶点坐标为 (v0, v1, v2, v3),那么
- GL_LINES 模式下,将绘制 (v0, v1) 和 (v2, v3) 这两条线段
- GL_LINE_STRIP 模式下,将绘制 (v0, v1)、(v1, v2) 和 (v2, v3) 三条线段
- GL_LINE_LOOP 模式下,将绘制 (v0, v1)、(v1, v2)、(v2, v3) 和 (v3, v0) 四条线段
线段的宽度使用如下 API 指定:
/**
* @param width 线宽,以像素数表示,默认的宽度为 1.0
*/
void glLineWidth(GLFloat width);
指定的线宽将被 OpenGL 记住,直到由应用程序更新。
支持的线宽范围可以通过如下方式获取:
GLfloat lineWidthRange[2];
glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, lineWidthRange);
3. 三角形
对应的模式为 GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN。三角形图元可谓是最常使用的了。
如图,假设指定的顶点坐标为上图所示,那么
- GL_TRIANGLES 模式下,将绘制 (v0, v1, v2) 和 (v3, v4, v5) 这两个三角形。
- GL_TRIANGLE_STRIP 模式下,将绘制 (v0, v1, v2)、(v2, v1, v3) (注意顺序)和 (v2, v3, v4) 三个三角形。
- GL_TRIANGLE_FAN 模式下,将绘制 (v0, v1, v2)、(v0, v2, v3) 和 (v0, v3, v4) 三个三角形。
四、3.0 新增的绘制接口介绍
最开始说到在 OpenGL ES 3.0 中新增了几个绘制图元的接口,接下来对其简单了解一下。
1. glDrawRangeElements
/**
* @param mode 渲染的图元模式,有:GL_POINTS、GL_LINES、GL_LINE_LOOP、GL_LINE_STRIP、GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN
* @param start 起始索引位置
* @param end 结束索引位置
* @param count 顶点数量
* @param type 元素类型,有:GL_UNSIGNED_BYTE、GL_UNSIGNED_SHORT、GL_UNSIGNED_INT
* @param indices 元素索引数组
*/
void glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);
相比于 glDrawElements
接口,它新增了 start
,end
两个参数,用来指定使用的数据数组的起始和结束位置。其余区别不大。
2. glDrawElementsInstanced 和 glDrawArraysInstanced
当需要绘制大量相似对象时(例如颜色、大小存在不同),以往我们只能向 OpenGL ES 引擎发送许多 API 调用。但是使用几何形状实例化,可以用一次 API 调用多次渲染具有不同属性的同一对象,大大降低 API 调用的 CPU 处理开销。
简单的说,如果我们想做一次批量的渲染,就可以使用 glDrawElementsInstanced
或 glDrawArraysInstanced
。
函数定义:
/**
* @param mode 渲染的图元模式,有:GL_POINTS、GL_LINES、GL_LINE_LOOP、GL_LINE_STRIP、GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN
* @param first 起始位置
* @param count 顶点数量
* @param instancecount 绘制的图元实例数量
*/
void glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
/**
* @param mode 渲染的图元模式,有:GL_POINTS、GL_LINES、GL_LINE_LOOP、GL_LINE_STRIP、GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN
* @param count 顶点数量
* @param type 元素类型,有:GL_UNSIGNED_BYTE、GL_UNSIGNED_SHORT、GL_UNSIGNED_INT
* @param indices 元素索引的指针
* @param instancecount 绘制的图元实例数量
*/
void glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount);
相比于 glDrawArrays
和 glDrawElements
,它多出了一个 instancecount
参数,表示我们需要绘制的图元数量。例如我们想要一次批量绘制 100 个相似的图元,这个值对应就传 100。
关于多实例绘制想要详细了解的,可以参考其它博客:
博客链接:
https://www.jianshu.com/p/71b7149d9dc1
https://www.cnblogs.com/xin-lover/p/9147905.html