广州微型网站建设,wordpress 看板,四川建筑培训考试网,edo网站建设OpenGL ES 索引缓冲区(4)
简述
本节会介绍索引缓冲区#xff0c;索引缓冲区和顶点缓冲区类似#xff0c;也是显存上的一段内存#xff0c;只不过上面的数据用处不同#xff0c;索引缓冲区故名思义里面的数据是用于索引#xff0c;主要作用是用于复用顶点缓冲区里的数据。…OpenGL ES 索引缓冲区(4)
简述
本节会介绍索引缓冲区索引缓冲区和顶点缓冲区类似也是显存上的一段内存只不过上面的数据用处不同索引缓冲区故名思义里面的数据是用于索引主要作用是用于复用顶点缓冲区里的数据。 我们之前说过OpenGL渲染都是渲染三角形如果我们想渲染一个正方形就要通过渲染两个三角形拼接成一个正方形那么这两个三角形有两个顶点是重合的如果没有索引缓冲区两个三角形则需要六个顶点而实际上一个正方形只有四个顶点这里有两个顶点时数据冗余。仅仅一个正方形就有这么多冗余那么一个复杂的游戏场景就会浪费非常多的内存。 下面我们就以渲染一个正方形为例来使用索引缓冲区。
接口使用
索引缓冲区的接口使用方式和顶点缓冲区类似只不过参数不同,这里使用的GL_ELEMENT_ARRAY_BUFFER表示索引缓冲区。
GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, bufferId);
GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER,size,data,type);glDrawElements是用于渲染索引缓冲区第一个和其他DrawCall一样第二个参数是count表示有多少顶点需要渲染第三个参数是索引缓冲区参数类型必须是GLES30.GL_UNSIGNED_SHORT或者GL_UNSIGNED_BYTE第四个参数是offset。
GLES30.glDrawElements(GLES30.GL_TRIANGLES, count, type, offset)不使用索引缓冲区渲染正方形
配置顶点数据
顶点数据如下6个顶点。我我们可以发现第3个和第5个是一样的第2个和第4个是一样的。
private float[] vertexArray new float[] {-0.25f, -0.25f, 0.0f,0.25f, -0.25f, 0.0f,-0.25f, 0.25f, 0.0f,0.25f, -0.25f, 0.0f,-0.25f, 0.25f, 0.0f,0.25f, 0.25f, 0.0f,
};配置着色器
着色器和我们三角形demo的时候基本是一样的通过一个统一变量来控制颜色。
private final String vertexShaderCode attribute vec4 vPosition; void main() { gl_Position vPosition; };private final String fragmentShaderCode precision mediump float; uniform vec4 vColor; void main() { gl_FragColor vColor; };配置顶点缓冲区数据和布局
onSurfaceCreated中填充顶点缓冲区的数据以及加载着色器的逻辑和绘制三角形的时候一样。
public void onSurfaceCreated(GL10 gl, EGLConfig config) {// 清除颜色GLES30.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);// 创建顶点缓冲区int[] idBuffer new int[1];GLES30.glGenBuffers(1, idBuffer, 0);vertexBufferId idBuffer[0];// 顶点缓冲区数据填充FloatBuffer vertexBuffer ByteBuffer.allocateDirect(vertexArray.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();vertexBuffer.put(vertexArray);vertexBuffer.position(0);GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vertexBufferId);GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER,vertexArray.length * 4,vertexBuffer,GLES30.GL_STATIC_DRAW);GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);// shadershaderProgramId initShaderProgram(vertexShaderCode, fragmentShaderCode);
}onDrawFrame方法中其他的基本和绘制三角形的时候一样参数布局其实也是一样的变化的只有glDrawArrays中count变成了6个顶点。
public void onDrawFrame(GL10 gl) {// 清除屏幕GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);// 使能着色器程序GLES30.glUseProgram(shaderProgramId);GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vertexBufferId);int positionLocation GLES30.glGetAttribLocation(shaderProgramId, vPosition);GLES30.glEnableVertexAttribArray(positionLocation);// 告诉GPU顶点缓冲区的布局情况即那些数据的意义是什么。GLES30.glVertexAttribPointer(positionLocation, 3, GLES30.GL_FLOAT, false, 0, 0);// 配置统一变量用于CPU和GPU通信的int colorLocation GLES30.glGetUniformLocation(shaderProgramId, vColor);GLES30.glUniform4f(colorLocation, 1.0f, 1.0f, 1.0f, 1.0f);// 调用DrawCall绘制三角形GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, 6);// 清除配置GLES30.glDisableVertexAttribArray(positionLocation);GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);GLES30.glUseProgram(0);
}效果
渲染图像看起来不是正方形而是长方形是因为OpenGL的坐标比例是按照屏幕显示的比例我们的手机屏幕是长方形的所以按照比例也是长方形的。 使用索引缓冲区
我们前面看到了渲染这个正方形我们使用了6个顶点而其中有2个顶点是重复的我们使用索引缓冲区可以复用顶点。
配置顶点数据
顶点数据如下,indexArray为索引缓冲区的数据必须要short或者byte类型。 这里索引缓冲区就是表示第一个三角形使用的顶点缓冲区中012号顶点第二个三角形使用顶点缓冲区中123号顶点。
private float[] vertexArray new float[] {-0.25f, -0.25f, 0.0f,0.25f, -0.25f, 0.0f,-0.25f, 0.25f, 0.0f,0.25f, 0.25f, 0.0f,
};private short[] indexArray new short[] {0,1,2,1,2,3
};配置顶点缓冲区数据和布局
着色器和之前一样顶点缓冲区配置修改如下除了申请顶点缓冲区之外还申请了索引缓冲区。
public void onSurfaceCreated(GL10 gl, EGLConfig config) {// 清除颜色GLES30.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);// 申请两个缓冲区一个作为顶点缓冲区一个座位索引缓冲区int[] idBuffer new int[2];GLES30.glGenBuffers(2, idBuffer, 0);vertexBufferId idBuffer[0];elementBufferId idBuffer[1];// 顶点缓冲区数据填充FloatBuffer vertexBuffer ByteBuffer.allocateDirect(vertexArray.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();vertexBuffer.put(vertexArray);vertexBuffer.position(0);GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vertexBufferId);GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER,vertexArray.length * 4,vertexBuffer,GLES30.GL_STATIC_DRAW);GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);// 索引缓冲区数据填充类型必须为short/byteShortBuffer indexBuffer ByteBuffer.allocateDirect(indexArray.length * 4).order(ByteOrder.nativeOrder()).asShortBuffer();indexBuffer.put(indexArray);indexBuffer.position(0);GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, elementBufferId);GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER,indexArray.length * 4,indexBuffer,GLES30.GL_STATIC_DRAW);GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, 0);// shadershaderProgramId initShaderProgram(vertexShaderCode, fragmentShaderCode);
}通过GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, elementBufferId)绑定索引缓冲区然后调用glDrawElements来进行绘制。
public void onDrawFrame(GL10 gl) {// 清除屏幕GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);// 使能着色器程序GLES30.glUseProgram(shaderProgramId);GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vertexBufferId);int positionLocation GLES30.glGetAttribLocation(shaderProgramId, vPosition);GLES30.glEnableVertexAttribArray(positionLocation);// 告诉GPU顶点缓冲区的布局情况即那些数据的意义是什么。GLES30.glVertexAttribPointer(positionLocation, 3, GLES30.GL_FLOAT, false, 0, 0);// 配置统一变量用于CPU和GPU通信的int colorLocation GLES30.glGetUniformLocation(shaderProgramId, vColor);GLES30.glUniform4f(colorLocation, 1.0f, 1.0f, 1.0f, 1.0f);// 绑定索引缓冲区GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, elementBufferId);// 调用DrawCall绘制三角形GLES30.glDrawElements(GLES30.GL_TRIANGLES, 6, GLES30.GL_UNSIGNED_SHORT, 0);// 清除配置GLES30.glDisableVertexAttribArray(positionLocation);GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, 0);GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);GLES30.glUseProgram(0);
}效果
和之前一样。
小结
索引缓冲区里面就是存储了一系列索引用于复用顶点缓冲区。 有个问题大家可能会想之前用6个顶点也不过18个数使用了顶点缓冲区后变为12个但是索引缓冲区还有6个好像没有节省多少内存。 但是实际上顶点可能包含了非常多的数据比如我们之前用它来存颜色它还可以存纹理等额外数据实际应用场景一个顶点可能有非常多数据所以复用可节省的内存是非常可观的。