【OpenGL ES】关于VBO(Vertex Buffer Object)的一些坑——解析一些关于glBuffer的函数

最近在写毕设的时候用到OpenGL ES中的VBO,由于对一些接口用到的变量不了解被坑得很惨,在此记录一下防止以后再被坑。

本文为大便一箩筐的原创内容,转载请注明出处,谢谢:http://www.cnblogs.com/dbylk/p/4492306.html 

 


 

使用VBO的好处在此就不多说了,在Java中操作VBO绘图涉及到的OpenGL接口主要有以下几个:

1. void glGenBuffers(int n, int[] buffers, int offset)

向OpenGL ES申请开辟新的VBO,并通过buffers数组获取VBO handle,handle的类型为整型。

int n      申请的VBO个数

int[] buffers  用于存储VBO handle的数组

int offset    buffers数组的偏移量,即从buffers的第offset个位置开始存储handle

注意需要满足 n + offset <= buffers.length

 

2. void glBindBuffer(int target, int buffer)

通过handle绑定指定的VBO,同一时间只能绑定一个同类型的VBO,只有当前被绑定的VBO才会被用户操作。通过绑定handle为0的VBO,可以取消对所有同类型VBO的绑定。

int target    指定绑定的VBO类型,具体类型有GL_ARRAY_BUFFER(用于为顶点数组传值)和GL_ELEMENT_ARRAY_BUFFER(用于为索引数组传值)

int buffer    指定绑定的VBO handle

 

3. void glBufferData(int target, int size, Buffer data, int usage)

将数据传递给当前绑定的VBO。

int target    指定VBO类型,同上

int size      指定VBO的大小,单位为byte

Buffer data   指定需要传递的数据

int usage    指定VBO的存储方式,例如GL_STATIC_DRAW或GL_DYNAMIC_DRAW

 

4. void glVertexAttribPointer(int indx, int size, int type, boolean normalized, int stride, int offset)

将VBO中的数据传递给顶点数组。

int indx           指定Shader属性的顶点数组handle

int size        指定该属性的顶点数组大小,单位为数组元素的类型

int type         指定该属性的顶点数组元素类型,如GL_FLOAT和GL_UNSIGNED_BYTE

boolean normalize  指定传递给该属性顶点数组的数据是否需要归一化(转化为单位向量)

int stride       指定该属性的顶点数据在VBO中的跃度,即每个顶点所占的数据长度,单位为byte

int offset       指定该属性在VBO中起始位置的偏移量,单位为byte

 

5. void glDrawArrays(int mode, int first, int count)

直接使用顶点数组绘制图元。

int mode    指定绘图的模式,如GL_TRIANGLES和GL_TRIANGLE_STRIP

int first     指定从第几个顶点开始绘制

int count    指定绘制几个顶点

本人博客地址,防止无脑抄袭,影响阅读见谅:http://www.cnblogs.com/dbylk

 

6. void glDrawElements(int mode, int count, int type, int offset)

使用索引数组绘制图元。

int mode    指定绘图的模式,如GL_TRIANGLES和GL_TRIANGLE_STRIP

int count    指定绘制几个顶点

int type      指定索引数组的数据类型,如GL_UNSIGNED_SHORT和GL_UNSIGNED_INT

int offset      指定索引数组起始位置的偏移量,单位为byte 

 

通过下面的简单实例中可以了解这些方法在实际操作中如何使用:

// Author DaBianYiLuoKuang.
// http://www.cnblogs.com/dbylk/

public void onDrawFrame(GL10 gl) {
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        
    // 设置旋转矩阵的函数,在此可以忽略
    setRotationView(0);
        
    // 获取Position属性的location
    int positionHandle = GLES20.glGetAttribLocation(programHandle, "Position");
    // 获取SourceColor属性的location
    int colorHandle = GLES20.glGetAttribLocation(programHandle, "SourceColor");

    // 激活两个属性的数组
    GLES20.glEnableVertexAttribArray(positionHandle);
    GLES20.glEnableVertexAttribArray(colorHandle);

    // 每个顶点的跃度,即一个顶点占有的数据类型个数
    int stride = 6;
    // 顶点数据数组,6个float组成一个顶点,前2个float为位置坐标,后4个float为颜色RGBA
    float[] data = {
        -0.5f, -0.5f,        1f, 1f, 1f, 1f,
         0.5f, -0.5f,        1f, 1f, 1f, 1f,
           0f,    1f,        1f, 1f, 1f, 1f
    };
        
    // 将顶点数组封装进Buffer中
    // 值得注意的一点是通过Buffer.wrap()方法生成的Buffer无法在OpenGL ES中使用,必须通过如下方法创建Buffer
    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(data.length * 4);
    // OpenGL ES中使用的数据为小端字节序(低位字节在前,高位字节在后),而Java的Buffer默认使用大端字节序(高位字节在前,低位字节在后)存储数据,所以在此需要通过下面的方法进行转换
    byteBuffer.order(ByteOrder.nativeOrder());
    // 将ByteBuffer转换为FloatBuffer
    FloatBuffer floatBuffer = byteBuffer.asFloatBuffer();
    // 将data中的数据放入FloatBuffer中
    floatBuffer.put(data);
    // 重新定义Buffer的起点和终点,等价于同时使用postion(0)方法和limit(data.length)方法
    floatBuffer.flip();
        
    // 用于获取VBO handle的临时变量
    int[] temp = new int[1];
    // 向OpenGL申请新的VBO,将handle存于temp中
    GLES20.glGenBuffers(1, temp, 0);
    // 从temp中取出VBO handle
    vertexBufferHandle = temp[0];
    // 绑定刚刚申请到的VBO
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBufferHandle);
    // 将FLoatBuffer中的数据传递给OpenGL ES
    GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, floatBuffer.limit() * 4, floatBuffer, GLES20.GL_STATIC_DRAW);

    // 将VBO中的数据传递给shader中的顶点数组
    GLES20.glVertexAttribPointer(positionHandle, 2, GLES20.GL_FLOAT, false, stride * 4, 0);
    GLES20.glVertexAttribPointer(colorHandle,    4, GLES20.GL_FLOAT, false, stride * 4, 2 * 4);

    // 绘制三角形
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);

    // 取消buffer的绑定
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
    
    // 反激活顶点数组
    GLES20.glDisableVertexAttribArray(positionSlot);
    GLES20.glDisableVertexAttribArray(colorSlot);
} 

 

关于注释中提到的大端字节序和小端字节序,具体可以查阅下篇博文:

http://www.cnblogs.com/xiehy/archive/2010/11/25/1887779.html

 

posted @ 2015-05-10 15:27  大便一箩筐  阅读(8241)  评论(0编辑  收藏  举报