Android OpenGL ES基本用法(6),VBO


目录


VBO

Vertex Buffer Object 顶点缓存对象
不使用VBO时,我们每次绘制( glDrawArrays )图形时都是从本地内存处获取顶点数据然后传输给OpenGL来绘制,使用VBO,我们就能把顶点数据缓存到GPU的显存中,直接从显存中获取数据,这样就能提升绘制的效率。

创建VBO

1、创建VBO
GLES20.glGenBuffers(1, vbos, 0);

2、绑定VBO
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbos[0]);

3、分配VBO需要的缓存大小
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertex.length * 4,null, GLES20. GL_STATIC_DRAW);

4、为VBO设置顶点数据的值
GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, 0, vertexData.length * 4, vertexBuffer);

5、解绑VBO
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);

使用VBO

1、绑定VBO
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbos[0]);

2、设置顶点数据
GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 8, 0);

3、解绑VBO
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);

在上一篇的基础上

package com.example.opengl.eglpic;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLUtils;

import com.example.opengl.R;
import com.example.opengl.egl.MyGlSurfaceView;
import com.example.opengl.egl.ShaderUtil;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

public class PicRender implements MyGlSurfaceView.EGLRender {
     

    private Context context;

    //顶点坐标
    private float[] vertexData = {
     
            -1f, -1f,
            1f, -1f,
            -1f, 1f,
            1f, 1f
    };
    private FloatBuffer vertexBuffer;

    //纹理坐标
    private float[] fragmentData = {
     
            0f, 1f,
            1f, 1f,
            0f, 0f,
            1f, 0f
    };
    private FloatBuffer fragmentBuffer;

    //生成的shader程序
    private int program;
    //顶点坐标
    private int vPosition;
    //纹理坐标
    private int fPosition;
    //纹理的id
    private int textureId;

    private int sampler;

    //vbo
    private int vboId;

    public PicRender(Context context) {
     
        this.context = context;


        vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)//4个字节
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(vertexData);
        vertexBuffer.position(0);

        fragmentBuffer = ByteBuffer.allocateDirect(fragmentData.length * 4)//4个字节
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(fragmentData);
        fragmentBuffer.position(0);
    }

    /**
     * OpenGl
     */
    @Override
    public void onSurfaceCreated() {
     
        //读取shader的源码
        String vertexSource = ShaderUtil.readRawTxt(context, R.raw.vertex_shader);
        String fragmentSource = ShaderUtil.readRawTxt(context, R.raw.fragment_shader);

        //创建shader程序
        program = ShaderUtil.createProgram(vertexSource, fragmentSource);

        vPosition = GLES20.glGetAttribLocation(program, "v_Position");
        fPosition = GLES20.glGetAttribLocation(program, "f_Position");
        sampler = GLES20.glGetUniformLocation(program, "sTexture");

        int[] vbos = new int[1];
        //创建vbo,生成一个,偏移量为0
        GLES20.glGenBuffers(1, vbos, 0);
        vboId = vbos[0];
        //绑定vbo
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboId);
        //分配VBO需要的缓存大小,data=null是只需要申请空间,暂时不赋值
        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertexData.length * 4 + fragmentData.length * 4, null, GLES20.GL_STATIC_DRAW);
        //为VBO设置顶点数据的值
        GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, 0, vertexData.length * 4, vertexBuffer);
        GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, vertexData.length * 4, fragmentData.length * 4, fragmentBuffer);
        //解绑vbo
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);

        int[] textureIds = new int[1];
        GLES20.glGenTextures(1, textureIds, 0);
        textureId = textureIds[0];
        //绑定
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
        //激活第0个
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        //绑定sampler和0
        GLES20.glUniform1i(sampler, 0);
        //设置环绕方式
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
        //设置过滤
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);

        //得到图片
        Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.photo);
        //图片绑定到纹理
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

        //回收
        bitmap.recycle();
        bitmap = null;
        //解绑
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
    }

    @Override
    public void onSurfaceChanged(int width, int height) {
     
        GLES20.glViewport(0, 0, width, height);
    }

    @Override
    public void onDrawFrame() {
     
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        GLES20.glClearColor(1f, 0f, 0f, 1f);

        //使用shader程序
        GLES20.glUseProgram(program);

        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);

        //使用vbo,绑定,在顶点和纹理赋值之前
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboId);

        //顶点赋值
        GLES20.glEnableVertexAttribArray(vPosition);
//        GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 8, vertexBuffer);
        //从vbo中取数据
        GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 8, 0);


        //纹理赋值
        GLES20.glEnableVertexAttribArray(fPosition);
//        GLES20.glVertexAttribPointer(fPosition, 2, GLES20.GL_FLOAT, false, 8, fragmentBuffer);
        //从vbo中取数据
        GLES20.glVertexAttribPointer(fPosition, 2, GLES20.GL_FLOAT, false, 8, vertexData.length * 4);


        //从0开始绘制4个点
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

        //解绑
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);

        //解绑vbo
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
    }
}

你可能感兴趣的:(OpenGL)