代码改变世界

OpenGL笔记(四) 关键API及VAO、VBO、EBO、FBO等名词解释

2018-08-11 14:29  Shdjgrwjdbd  阅读(1532)  评论(0)    收藏  举报

一、一些重要的

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

顶点法绘制:使用顶点数组方式绘制图形。第一个参数是绘制方式,第二个是顶点数组的起点,第三个是从顶点数组读取的个数。

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

索引法绘制:绘制模式,绘制的顶点数,索引的数据格式,索引的数据buffer

 

二、几个重要的名词

顶点缓冲对象:Vertex Buffer Object,VBO
图元索引缓冲对象:Element Buffer Object,EBO

    VBO和EBO实际上是同一类Buffer按照用途不同的称呼。OpenGLES2.0编程中,用于绘制的顶点数组数据首先保存在CPU内存中,在调用glDrawArrays或者glDrawElements等进行绘制时,需要将顶点数组数据从CPU内存拷贝到显存。

    但是,每次绘制都进行内存拷贝是不必要的,VBO和EBO的作用是在显存中提前开辟好一块内存,用于缓存顶点数据或者图元索引数据,从而避免每次绘制时CPU和GPU之间的内存拷贝,有效提升渲染性能,降低内存带宽和功耗。

    OpenGLES3.0支持两类缓冲区对象:顶点数组缓冲区对象图元索引缓冲区对象

    GL_ARRAY_BUFFER标志指定的缓冲区对象用于保存顶点数组;

    GL_ELEMENT_ARRAY_BUFFER标志指定的缓冲区对象用于保存图元索引数组;

顶点数组对象:Vertex Array Object,VAO

    VAO是指顶点数组对象,作用是管理VBO或EBO,减少glBindBuffer/glEnableVertexAttribArray/glVertexAttribPointer等调用操作,高效地实现在顶点数组配置之间切换。

    FBO(离屏渲染)本身不能用于渲染,只有添加了纹理或者渲染缓冲区后才能作为渲染目标。窗口系统的帧缓冲区渲染只有当纹理尺寸小于或等于帧缓冲区才有效。而FBO可以让渲染操作不用再渲染到屏幕上,而是渲染到离屏buffer中,然后可以使用glReadPixels等方法将渲染后的图像数据读出来,从而实现在后代用GPU对图像进行处理。

 

    通常深度可以理解为z坐标,它代表一个像素在空间中和你的距离,如果离你远就可能被别的像素遮挡,你就看不到它了,它会被丢弃,以节省资源。

    核心模式(Core)与立即渲染模式(Immediate mode,也就是固定渲染管线,基本废弃)

    标准化设备坐标(Normalized Device Coordinates, NDC)

    一旦你的顶点坐标已经在顶点着色器中处理过,它们就应该是标准化设备坐标了,标准化设备坐标是一个x、y和z值在-1.0到1.0的一小段空间。任何落在范围外的坐标都会被丢弃/裁剪,不会显示在你的屏幕上。与通常的屏幕坐标不同,y轴正方向为向上,(0, 0)坐标是这个图像的中心,而不是左上角。

    在真实的程序里输入数据通常都不是标准化设备坐标,所以我们首先必须先把它们转换至OpenGL的可视区域内。

 

三、Texture相关

void glGenTextures( GLsizei n,GLuint * textures)

n:生成纹理的数量

textures:存储纹理索引的首指针

GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture)

激活当前活动纹理单元,texture一般为GL_TEXTURE0,GL_TEXTURE1等

void glBindTexture(GLenum target, GLuint texture )

target: GL_TEXTURE_2D

texture:texture的索引

void glAttachShader(GLuint program, GLuint shader);

将一个着色器对象绑定到一个程序对象

GLint glGetUniformLocation(GLuint shaderID, const GLchar* varName);

返回一个有符号的整数,代表在shaderID指定的着色器中由varName命名的变量的位置。在一个着色器进行编译和连接之后,我们必须在着色器中寻找uniform的位置

void glUniform1f(GLint location, GLfloat v0);

设置标量和向量的统一值,1代表1个参数,f代表float,以此类推。

void glUniform1fv(GLint location, GLuint count, GLfloat* v);

接受一个指针,count值代表每个含有x个分量的数组中有多少个元素。使用范例:

GLfloat vColor[4]={1.0f, 1.0f, 1.0f, 1.0f};

glUniform4fv(iColorLocation, 1, vColor);

如果vColor是多维数组的话,count就是多维。

glUniformMatrix2fv(GLint location, GLuint count, GLboolean transpose, const GLfloat *m);

设置统一矩阵

void glReadPixels(GLint x, GLint y, GLSizei width, GLSizei height, GLenum format, GLenum type, const void *pixels);

x,y值指定为矩形左下角的窗口坐标

void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLunum format, GLenum type, void* data);

载入纹理

void glTexSubImage2D(GLenum target, GLint level, GLint xOffset, GLint yOffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *data);

在时间敏感的场合比如游戏或模拟应用中,重复加载新纹理可能会成为性能瓶颈。如果我们不再需要某个已加载的纹理,它可以被全部替换,也可以被替换掉一部分。替换一个纹理图像常常比直接使用glTexImage重新加载一个新纹理快得多。

GLboolean glIsTexture(GLint texture);

判断纹理是否有效

void glVertexAttributePointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer);

指定了渲染时索引值为index的顶点属性数组的数据格式和位置,示例:

 

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
  • 第一个参数指定我们要配置的顶点属性。还记得我们在顶点着色器中使用layout(location = 0)定义了position顶点属性的位置值(Location)吗?它可以把顶点属性的位置值设置为0。因为我们希望把数据传递到这一个顶点属性中,所以这里我们传入0
  • 第二个参数指定顶点属性的大小。顶点属性是一个vec3,它由3个值组成,所以大小是3。
  • 第三个参数指定数据的类型,这里是GL_FLOAT(GLSL中vec*都是由浮点数值组成的)。
  • 下个参数定义我们是否希望数据被标准化(Normalize)。如果我们设置为GL_TRUE,所有数据都会被映射到0(对于有符号型signed数据是-1)到1之间。我们把它设置为GL_FALSE
  • 第五个参数叫做步长(Stride),它告诉我们在连续的顶点属性组之间的间隔。由于下个组位置数据在3个float之后,我们把步长设置为3 * sizeof(float)。要注意的是由于我们知道这个数组是紧密排列的(在两个顶点属性之间没有空隙)我们也可以设置为0来让OpenGL决定具体步长是多少(只有当数值是紧密排列时才可用)。一旦我们有更多的顶点属性,我们就必须更小心地定义每个顶点属性之间的间隔,我们在后面会看到更多的例子(译注: 这个参数的意思简单说就是从这个属性第二次出现的地方到整个数组0位置之间有多少字节)。
  • 最后一个参数的类型是void*,所以需要我们进行这个奇怪的强制类型转换。它表示位置数据在缓冲中起始位置的偏移量(Offset)。由于位置数据在数组的开头,所以这里是0。我们会在后面详细解释这个参数。
void glEnableVertexAttribArray(GLuint index)

出于性能考虑,所有VertexShader中的属性(Attribute)变量都是关闭的,意味着数据在Shader中是不可见的,哪怕数据已经上传至GPU,由glEnableVertexAttribArray启用后,才可以在VertexShader中访问顶点属性。glVertexAttribPointer只是建立了CPU和GPU之间的逻辑连接,从而数据上传至GPU,但数据是否可用取决于有没有调用glEnableVertexAttribArray.