Opengl ES系列学习--增加地形

     本节我们在上一节的基础上继续添加地形图功能,我们要分析的目标就是《OpenGL ES应用开发实践指南 Android卷》书中第12章实现的最终的结果,代码下载请点击:Opengl ES Source Code,该Git库中的heightmap Module就是我们本节要分析的目标,先看下本节最终实现的结果。

     可以看到,地形图中有高有低,是用绿色来表示的,最接近底部的颜色最深,最上面的最浅。我们来看一下本节的代码,本节的代码还是在前一节的基础上添加新功能来实现的,所以如果对之前的章节内容有不清楚的地方,请大家先回头搞清楚之前的逻辑:Opengl ES系列学习--用粒子增添趣味Opengl ES系列学习--增加天空盒

     我们还是只看差异的部分,目录结构图如下:

     data包下新增了IndexBuffer、VertexBuffer两个类,这两个类是为了包装顶点缓冲区和索引缓冲区而定义的,先来看VertexBuffer顶点缓冲区。

     顶点缓冲区全称是GL_ARB_vertex_buffer_object,扩展可以提升OpenGL的性能。它提供了顶点数组和显示列表,有效避免了低效实现这些功能。Vertex Buffer Object(VBO) 允许顶点数据储存在高性能显卡上,即服务端的内存中,改善数据传输效率。如果缓冲区对象保存了像素数据,它就被称做Pixel Buffer Object(PBO)。使用顶点数据可以减少函数调用次数及复用共享顶点,然而,顶点数组的缺点是顶点函数及顶点数据在客户端(对于OpenGL来说,显卡为服务端,其它为客户端),每次引用顶点数组时,都必须将顶点数据从客户端(内存)发送到服务端(显卡)。另一方面,显示列表是服务端的函数,它不会再重头传送数据。但是,一旦显示列表被编译了,显示列表中的数据就不能修改了。

     Vertex buffer object (VBO) 为顶点创建创建了一个缓冲区对象。缓冲区对象在服务端的高性能内存中,并提供了相同的函数,引用这些数组,如glVertexPointer()、glNormalPointer()、 glTexCoordPointer()等等。顶点缓冲区内存管理器将缓冲区对象放在储存器中最佳的位置。这依赖了用户输入的模式:“target”模式和“usage”模式。因此,储存管理器可以优化缓冲区,平衡三种内存:system、AGP、video memory。与显示列表不同的是,在顶点缓冲区对象中的数据可以读也可以将它映射到服务端的内存空间中,然后更新它的数据。

     VBO另一个重要的优点是,可以在许多客户端中共享缓冲区对象,就像显示列表和纹理那样。由于VBO在服务端,多个客户端可以通过对应的标识符访问同一个缓冲区。

     明白了VBO的优化,我们来看一下如何使用它,VertexBuffer类的源码如下:

public class VertexBuffer {
    private final int bufferId;
    
    public VertexBuffer(float[] vertexData) {
        // Allocate a buffer.
        final int buffers[] = new int[1];
        glGenBuffers(buffers.length, buffers, 0);
        if (buffers[0] == 0) {
            throw new RuntimeException("Could not create a new vertex buffer object.");
        }
        bufferId = buffers[0];
        
        // Bind to the buffer. 
        glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
        
        // Transfer data to native memory.        
        FloatBuffer vertexArray = ByteBuffer
            .allocateDirect(vertexData.length * BYTES_PER_FLOAT)
            .order(ByteOrder.nativeOrder())
            .asFloatBuffer()
            .put(vertexData);
        vertexArray.position(0);
        
        // Transfer data from native memory to the GPU buffer.              
        glBufferData(GL_ARRAY_BUFFER, vertexArray.capacity() * BYTES_PER_FLOAT,
            vertexArray, GL_STATIC_DRAW);                      
         
        // IMPORTANT: Unbind from the buffer when we're done with it.
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        // We let vertexArray go out of scope, but it won't be released
        // until the next time the garbage collector is run.
    }
        
    public void setVertexAttribPointer(int dataOffset, int attributeLocation,
        int componentCount, int stride) {
        glBindBuffer(GL_ARRAY_BUFFER, bufferId);
        // This call is slightly different than the glVertexAttribPointer we've
        // used in the past: the last parameter is set to dataOffset, to tell OpenGL
        // to begin reading data at this position of the currently bound buffer.
        glVertexAttribPointer(attributeLocation, componentCount, GL_FLOAT, 
            false, stride, dataOffset);
        glEnableVertexAttribArray(attributeLocation);
        glBindBuffer(GL_ARRAY_BUFFER, 0);        
    }     
}

     成员变量只有一个:bufferId,它表示我们向GPU申请创建的顶点缓冲区的ID,构造方法中传入的float[] vertexData参数就表示我们要绘制的顶点数组,当中所有的逻辑就是VBO的使用流程,先调用glGenBuffers向GPU申请一块顶点缓冲区,第二个参数buffers是一个输出参数,表示GPU为我们创建好的VBO的ID,创建成功,则ID值会写入到该数组中;接着调用glBindBuffer以GL_ARRAY_BUFFER类型绑定顶点缓冲区;然后创建FloatBuffer用来存储顶点数据,因为我们要存储的是float类型,所以分配的内存长度需要乘BYTES_PER_FLOAT(4),创建成功并把顶点数据存储进去;然后调用glBufferData给顶点缓冲区填充值,注释也写的很清楚了,最后调用glBindBuffer并传入参数0解绑,这一句必须要有,否则我们其他地方的逻辑可能无法正常工作。glBufferData函数的详细说明如下:

     接着再来看setVertexAttribPointer方法,和之前VertexArray中的该方法的实现不同,我们已经在构造方法中将顶点数值传递到GPU分配的内存中了,所以这里调用glVertexAttribPointer时,最后一个参数不是Buffer类型,我们只需要给API传递stride和offset参数,告诉它从哪里开始取值就可以了。调用流程还是先绑定,再赋值,然后打开顶点属性,最后解绑。看完该类的代码,我们就需要明白顶点缓冲区要如何使用了。

     接着来看IndexBuffer索引缓冲区&#

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

红-旺永福

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值