opengl es和opengl,opengl和opengl es的区别
前言主要介绍什么是VBO/VAO,为什么需要使用它,以及如何使用VBO和VAO。
VBO VBO是什么
o(顶点缓冲对象):顶点缓冲对象。它是在显卡的存储空间中开辟的一个区域,在显卡的存储空间中开辟的一个区域用来存储顶点的各种属性信息。如顶点坐标、纹理坐标、顶点颜色等数据。渲染时,直接从显式VBO获取数据,无需与CPU交换数据。
为什么你需要用VBO?
将顶点数据保存在内存中。在调用glDrawArrays或glDrawElements等绘图方法之前,需要调用相应的方法将数据送入显存,导致I/O开销大,性能差。如果使用顶点缓冲对象来存储顶点数据,就不需要在每次绘制之前将顶点数据复制到显存中,而是在初始化顶点缓冲对象时将顶点数据发送到显存中一次,每次绘制都直接使用显存中的数据,这样可以大大提高绘制性能。
如何使用VBO
使用函数glGenBuffers和一个缓冲区ID生成一个VBO对象:unsigned int VBO;
glGenBuffers(1,VBO);函数glBindBuffer用于绑定顶点缓冲对象,缓冲类型为GL_ARRAY_BUFFER。OpenGL有很多类型的缓冲对象,顶点缓冲对象的缓冲类型是GL _ array _ buffer。
glBindBuffer(GL_ARRAY_BUFFER,VBO);使用函数glBufferData将定义的顶点数据复制到缓冲内存://vertices表示顶点数组。
glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL _ STATIC _ DRAW);GlBufferData是一个专门用于将用户定义的数据复制到当前绑定缓冲区的函数。它的第一个参数是目标缓冲区的类型,其中VBO代表yes GL_ARRAY_BUFFER。第二个参数指定传输数据的大小(以字节为单位)。只需用一个简单的sizeof计算顶点数据大小。第三个参数是我们想要发送的实际数据。第四个参数指定我们希望图形卡如何管理给定的数据。它有三种形式:
GL_STATIC_DRAW:数据不会或几乎不会改变。
GL_DYNAMIC_DRAW:数据会有很大变化。
GL_STREAM_DRAW:每次绘制时数据都会发生变化。
位置数据一般不会改变,每次调用渲染都会保持不变,所以它的使用类型一般是GL_STATIC_DRAW。如果一个缓冲区中的数据会经常变化,那么使用的类型就是GL_DYNAMIC_DRAW或者GL_STREAM_DRAW,保证显卡把数据放在可以高速写入的内存部分。
使用glDeleteBuffers函数后,删除缓冲区。今天我们以之前画四边形的练习为例,用VBO画四边形:在Opengl ES中画四边形。
我们的目标是灵活运用Opengl绘制一个蓝色的四边形。
这里就不多说普通画图了。可以看看后续的代码,或者回顾一下之前的四边形绘制的文章。在这里,我主要介绍一下VBO的两种绘画方法:
首先,它们使用相同的顶点着色器和片段着色器,两者都是:
//顶点着色器
静态常量char *ver=#version 300 es\n
在vec4 aColor中;\n
在vec4位置;\n
out vec4 vColor\n
void main() {\n
vColor=aColor\n
gl _ Position=aPosition\n
};
//片段着色器
静态常量char *fragment=#version 300 es\n
精密中间浮动;\n
在vec4 vColor中;\n
out vec4 fragColor\n
void main() {\n
fragColor=vColor\n
};顶点坐标和颜色值坐标是分开的(数组结构)。首先看顶点数据和颜色数据:
//用画两个三角形的形式组成一个矩形(三角带)
//第一、二、三点构成三角形,第二、三、四点构成三角形。
const static GLfloat顶点[]={
0.5f,-0.5f,//右下方
0.5f,0.5f,//右上
-0.5f,-0.5f,//左下方
-0.5f,0.5f,//左上
};
//vbo颜色
const static GL float COLOR _ ICES[]={
0.0f,0.0f,1.0f,1.0f
0.0f,0.0f,1.0f,1.0f
0.0f,0.0f,1.0f,1.0f
0.0f,0.0f,1.0f,1.0f
};O vb数据和绑定:
//vbo
glGenBuffers(3,vbo);
glBindBuffer(GL_ARRAY_BUFFER,vbo[0]);
glBufferData(GL_ARRAY_BUFFER,sizeof(VERTICES),VERTICES,GL _ STATIC _ DRAW);
//颜色
glBindBuffer(GL_ARRAY_BUFFER,vbo[1]);
glBufferData(GL_ARRAY_BUFFER,sizeof(COLOR_ICES),COLOR_ICES,GL _ STATIC _ DRAW);主要图纸代码:
//使用VBO绘制,顶点与颜色分开
//glBindBuffer(GL_ARRAY_BUFFER,vbo[0]);
//glvertexattributepointer(position handle,2,GL_FLOAT,GL_FALSE,0,(void *)0);
////启用顶点数据
//glEnableVertexAttribArray(position handle);
//
//glBindBuffer(GL_ARRAY_BUFFER,vbo[1]);
//glvertexattributepointer(color handle,4,GL_FLOAT,GL_FALSE,0,(void *)0);
////启用颜色顶点数据
//glEnableVertexAttribArray(color handle);
////取消绑定
//glBindBuffer(GL_ARRAY_BUFFER,0);顶点的坐标和颜色值的坐标结合的方式(结构数组)顶点数据和颜色数据混合混淆;
const static GL float VERTICES _ AND _ COLOR[]={
0.5f,-0.5f,//右下方
//颜色
0.0f,0.0f,1.0f,1.0f
0.5f,0.5f,//右上
//颜色
0.0f,0.0f,1.0f,1.0f
-0.5f,-0.5f,//左下方
//颜色
0.0f,0.0f,1.0f,1.0f
-0.5f,0.5f,//左上
//颜色
0.0f,0.0f,1.0f,1.0f
};O vbdata绑定:
//vbo
glGenBuffers(3,vbo);
glBindBuffer(GL_ARRAY_BUFFER,vbo[0]);
glBufferData(GL_ARRAY_BUFFER,sizeof(VERTICES),VERTICES,GL _ STATIC _ DRAW);
//颜色
glBindBuffer(GL_ARRAY_BUFFER,vbo[1]);
glBufferData(GL_ARRAY_BUFFER,sizeof(COLOR_ICES),COLOR_ICES,GL _ STATIC _ DRAW);
//顶点混色,先顶点坐标,再颜色坐标。
glBindBuffer(GL_ARRAY_BUFFER,vbo[2]);
glBufferData(GL_ARRAY_BUFFER,sizeof(VERTICES_AND_COLOR),VERTICES_AND_COLOR
,GL _ STATIC _ DRAW);主要图纸代码:
//VBO绘制顶点坐标和颜色坐标
//glBindBuffer(GL_ARRAY_BUFFER,vbo[2]);
////跨步,每个顶点坐标由6个数据点分隔,数据类型为float。
//glvertexattributepointer(position handle,2,GL_FLOAT,GL_FALSE,6 * sizeof(float),(void *)0);
////启用顶点数据
//glEnableVertexAttribArray(position handle);
////步幅步长每个颜色坐标由6个数据点分隔。数据类型为float,颜色坐标索引从2开始。
//glvertexattributepointer(color handle,4,GL_FLOAT,GL_FALSE,6 * sizeof(float),(void *)(2 * sizeof(FLOAT)));
////启用颜色顶点数据
//glEnableVertexAttribArray(color handle);
////取消绑定
//glBindBuffer(GL_ARRAY_BUFFER,0);他们的运行结果都是成功的画出了一个蓝色的四边形:
在性能方面,我们使用了多种不同的组合来绘制四边形,包括将顶点坐标和颜色坐标分别写在两个不同的数组中,或者将顶点坐标和颜色坐标写在同一个数组中,然后通过控制stride和offset (*pointer)的参数进行绘制。这两种方法哪个性能更好?
其中,将不同数组中的各种顶点坐标分开的写入方法成为数组结构,而将各种顶点坐标组合成一个数组的写入方法也称为结构化数组。在《OPENGL ES 3.0编程指南》这本书里,作者指出结构化数组的写性能更好。
大多数情况下,答案是结构数组。
原因是可以顺序读取每个顶点的属性数据,这最有可能造成高效的内存访问模式。
VAO VAO是什么
o(顶点数组对象):顶点数组对象。
注意:VAO是OpenGL ES 3.0之后推出的新功能,所以在使用VAO之前需要确定OpenGL ES的版本是否在3.0之后。
顶点数组对象可以像顶点缓冲区对象一样绑定,任何后续的顶点属性调用都将存储在这个VAO中。这样做的好处是,在配置顶点属性指针时,只需要执行那些调用一次,然后在绘制对象时只需要绑定相应的VAO。这使得在不同的顶点数据和属性配置之间切换非常简单,只需绑定不同的vao。刚刚设置的所有状态都将存储在VAO中。
顶点数组对象存储以下内容:
对GlenVertexattribarray和glEnableVertexAttribArray的调用。配置由glVertexAttribPointer设置的顶点属性。通过glVertexAttribPointer调用与顶点属性关联的顶点缓冲区对象。在上面VBO的介绍中,我们知道每次绘制都需要频繁绑定和解除绑定VBO,并且每次绘制都需要在渲染前拿出VBO的数据进行赋值。当数据量很大时,重复这些操作会很繁琐。这个过程可以被VAO简化,所以VAO可以简单理解为VBO的管理者,避免了画框时对VBO的人工操纵,VAO也不能单独使用。
它需要和VBO一起使用。
对于GPU来说,VBO就是一堆数据,但是如何解析和使用这堆数据,需要glEnableVertexAttribArray等相关函数在每次绘制的时候告诉GPU,所以VAO的作用就是简化这个过程。只需要在初始化时将这些解析逻辑与VAO绑定一次。
然后每次画图只需要绑定对应的VAO,而不是每次都绑定VBO,然后告诉GPU如何解析相关数据。可以说是一次性能优化。
如何使用VAO
首先,调用函数glGenVertexArrays来生成无符号int VAO;
glGenVertexArrays(1,VAO);调用函数glBindVertexArray绑定vaogbindvertexarray(VAO);
//管理VBO,让VAO记住VBO的数据是如何解析和使用的。
glBindBuffer(GL_ARRAY_BUFFER,VBO);
glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL _ STATIC _ DRAW);
//3.设置顶点属性指针
glvertexattributepointer(0,3,GL_FLOAT,GL_FALSE,3 * sizeof(float),(void *)0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);然后在绘图时使用函数glBindVertexArray(VAO)。
退出时,通过函数glDeleteVertexArrays删除VAOglDeleteVertexArrays的主绑定代码:
//VAO
glGenVertexArrays(1,vao);
glBindVertexArray(vao);
//VAO与VBO联系在一起
glBindBuffer(GL_ARRAY_BUFFER,vbo[2]);
//跨步,每个顶点坐标用6个数据点隔开,数据类型为float。
glvertexattributepointer(position handle,2,GL_FLOAT,GL_FALSE,6 * sizeof(float),(void *)0);
//启用顶点数据
glEnableVertexAttribArray(position handle);
//步幅步长每个颜色坐标由6个数据点分隔,数据类型为float,颜色坐标索引从2开始。
glvertexattributepointer(color handle,4,GL_FLOAT,GL_FALSE,6 * sizeof(float),(void *)(2 * sizeof(FLOAT)));
//启用颜色顶点数据
glEnableVertexAttribArray(color handle);
//解除绑定
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindVertexArray(0);使用的主要图纸代码:
//VBO和VAO被画在一起。
//使用vao
glBindVertexArray(vao);
//4个顶点绘制两个三角形形成一个矩形
glDrawArrays(GL_TRIANGLE_STRIP,0,4);
glUseProgram(0);
//vao解除绑定
glBindVertexArray(vao);以下是完整的代码:
VBOVAOOpengl.h
静态常数int NUM _ VBO=3;
VBOVAOOpengl类:public BaseOpengl{
公共:
VBOVAOOpengl();
virtual ~ VBOVAOOpengl();
虚拟void onDraw();
私人:
闪烁位置句柄{-1 };
闪烁color handle {-1 };
Glu int vbo[NUM _ VBO];
Glu int vao { 0 };
};VBOVAOOpengl.cpp
//顶点着色器
静态常量char *ver=#version 300 es\n
在vec4 aColor中;\n
在vec4位置;\n
out vec4 vColor\n
void main() {\n
vColor=aColor\n
gl _ Position=aPosition\n
};
//片段着色器
静态常量char *fragment=#version 300 es\n
精密中间浮动;\n
在vec4 vColor中;\n
out vec4 fragColor\n
void main() {\n
fragColor=vColor\n
};
//用画两个三角形的形式组成一个矩形(三角带)
//第一、二、三点构成三角形,第二、三、四点构成三角形。
const static GLfloat顶点[]={
0.5f,-0.5f,//右下方
0.5f,0.5f,//右上
-0.5f,-0.5f,//左下方
-0.5f,0.5f,//左上
};
const static GL float VERTICES _ AND _ COLOR[]={
0.5f,-0.5f,//右下方
//颜色
0.0f,0.0f,1.0f,1.0f
0.5f,0.5f,//右上
//颜色
0.0f,0.0f,1.0f,1.0f
-0.5f,-0.5f,//左下方
//颜色
0.0f,0.0f,1.0f,1.0f
-0.5f,0.5f,//左上
//颜色
0.0f,0.0f,1.0f,1.0f
};
//rgba
//const static GL float COLOR _ ICES[]={
//0.0f,0.0f,1.0f,1.0f
//};
//vbo颜色
const static GL float COLOR _ ICES[]={
0.0f,0.0f,1.0f,1.0f
0.0f,0.0f,1.0f,1.0f
0.0f,0.0f,1.0f,1.0f
0.0f,0.0f,1.0f,1.0f
};
VBOVAOOpengl:VBOVAOOpengl() {
initGlProgram(ver,fragment);
position handle=glgetattributelocation(程序,一个位置);
color handle=glgetattributelocation(program, aColor );
//vbo
glGenBuffers(3,vbo);
glBindBuffer(GL_ARRAY_BUFFER,vbo[0]);
glBufferData(GL_ARRAY_BUFFER,sizeof(VERTICES),VERTICES,GL _ STATIC _ DRAW);
//颜色
glBindBuffer(GL_ARRAY_BUFFER,vbo[1]);
glBufferData(GL_ARRAY_BUFFER,sizeof(COLOR_ICES),COLOR_ICES,GL _ STATIC _ DRAW);
//顶点与颜色混合,先顶点坐标,再颜色坐标
glBindBuffer(GL_ARRAY_BUFFER,vbo[2]);
glBufferData(GL_ARRAY_BUFFER,sizeof(VERTICES_AND_COLOR),VERTICES_AND_COLOR
,GL _ STATIC _ DRAW);
glBindBuffer(GL_ARRAY_BUFFER,0);
//VAO
glGenVertexArrays(1,vao);
glBindVertexArray(vao);
//VAO与电压关联
glBindBuffer(GL_ARRAY_BUFFER,vbo[2]);
//步幅步长每个顶点坐标之间相隔6个数据点,数据类型是漂浮物
glvertexattributepointer(位置句柄,2,GL_FLOAT,GL_FALSE,6 * sizeof(float),(void *)0);
//启用顶点数据
glEnableVertexAttribArray(位置句柄);
//步幅步长每个颜色坐标之间相隔6个数据点,数据类型是浮动,颜色坐标索引从2开始
glvertexattributepointer(颜色句柄,4,GL_FLOAT,GL_FALSE,6 * sizeof(float),(void *)(2 * sizeof(FLOAT)));
//启用颜色顶点数据
glEnableVertexAttribArray(彩色手柄);
//解除绑定
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindVertexArray(0);
LOGD(’程序:%d ,程序);
LOGD(’位置句柄:%d ,位置句柄);
LOGD(colorHandle:%d ,颜色句柄);
}
void VBOVAOOpengl:onDraw() {
//清屏
glClearColor(0.0f,1.0f,0.0f,1.0f);
GL清零(GL _ COLOR _ BUFFER _ BIT);
葡萄糖程序(程序);
//普通方式绘制
///**
//*大小几个数字表示一个点,显示是两个数字表示一个点
//*正常化是否需要归一化,不用,这里已经归一化了
//*步幅步长,连续顶点之间的间隔,如果顶点直接是连续的,也可填0
//*/
//glvertexattributepointer(位置句柄,2,GL_FLOAT,GL_FALSE,0,顶点);
////启用顶点数据
//glEnableVertexAttribArray(位置句柄);
//
////这个不需要glEnableVertexAttribArray
//glvertexattrib 4 Fv(颜色句柄,COLOR _ ICES);
//############################################# 分割线#################################
//使用电压的方式绘制,顶点与颜色分开
///**
//glBindBuffer(GL_ARRAY_BUFFER,vbo[0]);
//glvertexattributepointer(位置句柄,2,GL_FLOAT,GL_FALSE,0,(void *)0);
////启用顶点数据
//glEnableVertexAttribArray(位置句柄);
//
//glBindBuffer(GL_ARRAY_BUFFER,vbo[1]);
//glvertexattributepointer(颜色句柄,4,GL_FLOAT,GL_FALSE,0,(void *)0);
////启用颜色顶点数据
//glEnableVertexAttribArray(颜色句柄);
////解除绑定
//glBindBuffer(GL_ARRAY_BUFFER,0);
//############################################# 分割线#################################
//VBO绘制顶点坐标与颜色坐标一起
//glBindBuffer(GL_ARRAY_BUFFER,vbo[2]);
////步幅步长每个顶点坐标之间相隔6个数据点,数据类型是漂浮物
//glvertexattributepointer(位置句柄,2,GL_FLOAT,GL_FALSE,6 * sizeof(float),(void *)0);
////启用顶点数据
//glEnableVertexAttribArray(位置句柄);
////步幅步长每个颜色坐标之间相隔6个数据点,数据类型是浮动,颜色坐标索引从2开始
//glvertexattributepointer(颜色句柄,4,GL_FLOAT,GL_FALSE,6 * sizeof(float),(void *)(2 * sizeof(FLOAT)));
////启用颜色顶点数据
//glEnableVertexAttribArray(颜色句柄);
////解除绑定
//glBindBuffer(GL_ARRAY_BUFFER,0);
//############################################# 分割线#################################
//VBO与顶点数组对象配合绘制
//使用顶点数组对象
glBindVertexArray(vao);
//4个顶点绘制两个三角形形成一个矩形
glDrawArrays(GL_TRIANGLE_STRIP,0,4);
glUseProgram(0);
//vao解除绑定
glBindVertexArray(vao);
//禁用顶点
glDisableVertexAttribArray(position handle);
if(nullptr!=eglHelper){
egl helper-swap buffers();
}
}
VBOVAOOpengl:~ VBOVAOOpengl()no except {
glDeleteBuffers(NUM_VBO,vbo);
glDeleteVertexArrays(1,vao);
}之前的注释Opengl ES的EGL环境Opengl ES的构建着色器
Opengl ES的三角形绘制
Opengl ES的四边形绘制
Opengl ES的纹理映射
关注我,共同进步,生活不止编码!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。