内容简介:大家好,这是我的今天给大家介绍这段代码大家应该很熟悉了,它的作用就是将顶点数据指定给
大家好,这是我的 OpenGL ES
高级进阶系列文章,在我的 github
上有一个与本系列文章对应的项目,欢迎关注,链接: github.com/kenneycode/…
今天给大家介绍 VBO(Vertex Buffer Object)
和 IBO(Index Buffer Object)
,让我们先从一段代码开始,逐步介绍它们:
// 将三角形顶点数据放入buffer中 // Put the triangle vertex data into the vertexDataBuffer vertexDataBuffer = ByteBuffer.allocateDirect(vertexData.size * java.lang.Float.SIZE / 8) .order(ByteOrder.nativeOrder()) .asFloatBuffer() vertexDataBuffer.put(vertexData) vertexDataBuffer.position(0) // 启动对应位置的参数,这里直接使用LOCATION_ATTRIBUTE_POSITION,而无需像OpenGL 2.0那样需要先获取参数的location // Enable the parameter of the location. Here we can simply use LOCATION_ATTRIBUTE_POSITION, while in OpenGL 2.0 we have to query the location of the parameter GLES30.glEnableVertexAttribArray(LOCATION_ATTRIBUTE_POSITION) // 指定a_position所使用的顶点数据 // Specify the data of a_position GLES30.glVertexAttribPointer(LOCATION_ATTRIBUTE_POSITION, VERTEX_COMPONENT_COUNT, GLES30.GL_FLOAT, false, 0, vertexDataBuffer) 复制代码
这段代码大家应该很熟悉了,它的作用就是将顶点数据指定给 vertex shader
中的 attribute
变量,这里有个细节之前没提到过,就是 glVertexAttribPointer()
这个方法指定了顶点数据,但它不会将顶点数据一直存储在显存中,而我们渲染的时候,所有要访问的数据必需在显存中,因此,每次渲染时, OpenGL
会有一个将这些顶点数据从内存复制到显存的操作,这样会带来一些问题:
-
一个是因此每次渲染都要复制一次,因此内存中的顶点数据要一直留着,不然复制的时候就没有数据来复制了。
-
另一个是如果顶点数据量大的时候,每次渲染都做这样的一次复制,性能上会有问题,我们的例子中,顶点算是非常少的,那什么时候顶点会多呢?例如做一些形变效果时,往往会划分网格,一般来说划分得越多,效果越细腻,这时顶点就会很多,另外,在做3D渲染时,通常顶点也很多,单个3D模型甚至可以有上万个顶点。
那有什么办法来避免复制?这时就要用到 VBO
,它可以和顶点数据绑定,绑定后的顶点数据是一直存储在显存中的,当需要用这些顶点数据的时候,直接绑定这个 VBO
就行了,不会有复制过程。
那 IBO
又是什么呢?它和 VBO
作用很类似, VBO
是为了避免顶点数据的复制, IBO
是则是为了避免顶点索引数据的复制,什么是顶点索引呢?我们先来看一份顶点数据:
// 三角形顶点数据 // The vertex data of a triangle private val vertexData = floatArrayOf( -1f, -1f, // 左下角 -1f, 1f, // 左上角 1f, 1f, // 右上角 -1f, -1f, // 左下角 1f, 1f, // 右上角 1f, -1f // 右下角 ) 复制代码
这是一份很普通的顶点数据,在我们的教程中多次用到过,它用2个三角形组成了一个矩形,对应用 GL_TRIANGLES
的绘制模式进行渲染(绘制模式可参考我的一篇文章 《Android OpenGL ES 2.0 手把手教学(5)- 绘制模式》 ),我们可以很容易地看到,这6个顶点是有重复的,一个矩形只需要4个顶点就行了,有些点是不同三角形之间共用的,那么如何让不同三角形之间共用?这就要用到顶点索引,它能让我们用索引的方法告诉 OpenGL
我们的顶点,而不是每个点都用坐标的方式给出,这样可以减少我们的顶点数据量,这在面片数量较大时很有用。
那么下面我们来看看具体如何使用 VBO
和 IBO
,先来看看顶点数据和顶点索引数据:
// 三角形顶点、纹理数据 // The vertex data and texture coordinate data of triangles private val vertexData = floatArrayOf( -1f, -1f, 0f, 1f, // x, y, u, v -1f, 1f, 0f, 0f, 1f, 1f, 1f, 0f, 1f, -1f, 1f, 1f ) 复制代码
这里我们将顶点和纹理坐标组合越来,这也是配合 VBO
和 IBO
的常规优化用法,它的好处让顶点和纹理坐标在存储上靠近,利于 OpenGL
取数据,提高性能,特别是在3D渲染时,数据一般都是这样组织的。
接下来用 glGenBuffers
创建 VBO
和 IBO
:
// 创建VBO和IBO // Create VBO and IBO val buffers = IntArray(2) GLES30.glGenBuffers(buffers.size, buffers, 0) vbo = buffers[0] ibo = buffers[1] 复制代码
我们可以看到,在创建的时候其实并没有 VBO
和 IBO
的区别,都是叫 buffer
,它们是在真正用的时候才能体现出区别。
下面将顶点的纹理数据加载到 VBO
中:
// 将顶点数据载入VBO // Load vertex data into VBO val vertexDataBuffer = ByteBuffer.allocateDirect(vertexData.size * java.lang.Float.SIZE / 8) .order(ByteOrder.nativeOrder()) .asFloatBuffer() vertexDataBuffer.put(vertexData) vertexDataBuffer.position(0) GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo) GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, vertexDataBuffer.capacity() * java.lang.Float.SIZE / 8, vertexDataBuffer, GLES30.GL_STATIC_DRAW) GLES30.glEnableVertexAttribArray(LOCATION_ATTRIBUTE_POSITION) GLES30.glEnableVertexAttribArray(LOCATION_ATTRIBUTE_TEXTURE_COORDINATE) GLES30.glVertexAttribPointer(LOCATION_ATTRIBUTE_POSITION, 2, GLES30.GL_FLOAT, false, 16, 0) GLES30.glVertexAttribPointer(LOCATION_ATTRIBUTE_TEXTURE_COORDINATE, 2, GLES30.GL_FLOAT, false, 16, 8) 复制代码
主要的关键点是先用 glBindBuffer
绑定我们在操作的 buffer
,这一点和操作 texture
和 frame buffer
时很像,操作前都先绑定。接着用 glBufferData
给它喂数据,这里最后一个参数用于提示 OpenGL
以便于它做一些优化,例如这里我们传了 GL_STATIC_DRAW
,即我们的数据是不会变的,还有一些其它的可以设置,如 GL_DYNAMIC_DRAW
则提示 OpenGL
这个 buffer
的数据是会变的。
在 glVertexAttribPointer
指定顶点和纹理数据时,我们不再像之前那样,直接把数据的传进来,因为这时我们的数据已经在 VBO
中了,这里不需要再传,这里重点关注最后两个参数,倒数第二个参数是指定 stride
,即 OpenGL
去取一份数据时的跨度,这里因为我们把顶点和纹理数据组合在了一起,因此一份数据是2个顶点和2个纹理坐标,即4个 float
,16个字节。倒数第一个参数是指定这个数据在一份数据中的开始位置,因为我们在一份数据中是先放顶点再放纹理坐标,因此对于顶点,开始位置是0,对于纹理坐标,开始位置是第8个字节。
这样我们就设置好了 VBO
和 IBO
,在渲染的时候,直接绑定 VBO
和 IBO
就可以使用对应的顶点和纹理数据了:
override fun onDrawFrame(gl: GL10?) { // 设置清屏颜色 // Set the color which the screen will be cleared to GLES30.glClearColor(0.9f, 0.9f, 0.9f, 1f) // 清屏 // Clear the screen GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT) // 设置视口,这里设置为整个GLSurfaceView区域 // Set the viewport to the full GLSurfaceView GLES30.glViewport(0, 0, glSurfaceViewWidth, glSurfaceViewHeight) // 设置好状态,准备渲染 // Set the status before rendering GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo) GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, ibo) GLES30.glActiveTexture(GLES30.GL_TEXTURE0) GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, imageTexture) // 调用draw方法用TRIANGLES的方式执行渲染,顶点数量为3个 // Call the draw method with GL_TRIANGLES to render 3 vertices GLES30.glDrawElements(GLES30.GL_TRIANGLES, indexData.size, GLES30.GL_UNSIGNED_INT, 0) } 复制代码
来看看效果,就是渲染出一张图来,从效果上看不出什么区别哈:
代码在我 github
的 OpenGLESPro
项目中,本文对应的是 SampleVBOAndIBO
,项目链接: github.com/kenneycode/…
感谢阅读!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
jQuery基础教程 (第4版)
[美] Jonathan Chaffer、[美] Karl Swedberg / 李松峰 / 人民邮电出版社 / 2013-10 / 59.00
本书由jQuery API网站维护者亲自撰写,第一版自2008上市以来,一版再版,累计重印14次,是国内首屈一指的jQuery经典著作! 作为最新升级版,本书涵盖jQuery 1.10.x和jQuery 2.0.x。本书前6章以通俗易懂的方式讲解了jQuery的核心组件,包括jQuery的选择符、事件、动画、DOM操作、Ajax支持等。第7章和第8章介绍了jQuery UI、jQuery M......一起来看看 《jQuery基础教程 (第4版)》 这本书的介绍吧!