美文网首页OpenGL ES
附录(6)使用顶点缓存区绘制

附录(6)使用顶点缓存区绘制

作者: 大旺旺的弟弟小旺旺 | 来源:发表于2021-06-27 10:34 被阅读0次

    顶点缓存区在第六章已经说过,这里整理一个案例。还是最简单的代码,绘制一个三角形。这案例继承附录5中的基类。

    不使用顶点缓存区

    /**
     * 三角形
     */
    public class Triangle extends BaseGameScreen {
        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;" +
                        "}";
    
        static final int COORDS_PER_VERTEX = 3;
        private FloatBuffer vertexBuffer;
        static float triangleCoords[] = {
                0.5f,  0.5f, 0.0f, // top
                -0.5f, -0.5f, 0.0f, // bottom left
                0.5f, -0.5f, 0.0f  // bottom right
        };
    
        //顶点个数
        private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
        //顶点之间的偏移量
        private final int vertexStride = COORDS_PER_VERTEX * 4; // 每个顶点四个字节
        //设置颜色,依次为红绿蓝和透明通道
        float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
        private int mPositionHandle;
        private int mColorHandle;
        float d = 0.01F;
        public Triangle(){
    
        }
    
        public void create(){
            ByteBuffer bb = ByteBuffer.allocateDirect(
                    triangleCoords.length * 4);
            bb.order(ByteOrder.nativeOrder());
            vertexBuffer = bb.asFloatBuffer();
            vertexBuffer.put(triangleCoords);
            vertexBuffer.position(0);
    
            int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,vertexShaderCode);
            int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentShaderCode);
            mProgram = GLES20.glCreateProgram();
            GLES20.glAttachShader(mProgram,vertexShader);
            GLES20.glAttachShader(mProgram,fragmentShader);
            GLES20.glLinkProgram(mProgram);
            //程序加入到环境里面
            GLES20.glUseProgram(mProgram);
    //        检查是否有效
            GLES20.glValidateProgram(mProgram);
            mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
            mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
        }
    
    
        @Override
        public void surfaceChange(int width, int height) {
            GLES20.glViewport(0,0,width,height);
        }
    
        @Override
        public void dispose() {
    
        }
    
    
        @Override
        public void render() {
            //获取位置句柄   属性句柄
    
            GLES20.glEnableVertexAttribArray(mPositionHandle);
            //准备三角形的坐标数据
            GLES20.glVertexAttribPointer(
                    mPositionHandle,
                    COORDS_PER_VERTEX,
                    GLES20.GL_FLOAT,
                    false,
                    vertexStride,
                    vertexBuffer);
            //获取片元着色器的vColor成员的句柄
    
            color[1] = color[1]-d;
            if (color[1]<=0||color[1]>=1){
                d=-d;
            }
            //设置绘制三角形的颜色
            GLES20.glUniform4fv(mColorHandle, 1, color, 0);
            //绘制三角形
            GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
            //禁止顶点数组的句柄
            GLES20.glDisableVertexAttribArray(mPositionHandle);
        }
    
    }
    

    使用顶点缓存区

    package com.example.myapplication.learn.shape;
    
    import android.opengl.GLES20;
    
    import com.example.myapplication.MainActivity;
    import com.example.myapplication.learn.shape.base.BaseGameScreen;
    
    import java.nio.ByteBuffer;
    import java.nio.ByteOrder;
    import java.nio.FloatBuffer;
    import java.nio.IntBuffer;
    
    /**
     * 三角形
     */
    public class TriangleBuffer extends BaseGameScreen {
        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;" +
                        "}";
    
        static final int COORDS_PER_VERTEX = 3;
        private FloatBuffer vertexBuffer;
        static float triangleCoords[] = {
                0.5f,  0.5f, 0.0f, // top
                -0.5f, -0.5f, 0.0f, // bottom left
                0.5f, -0.5f, 0.0f  // bottom right
        };
    
        //顶点个数
        private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
        //顶点之间的偏移量
        private final int vertexStride = COORDS_PER_VERTEX * 4; // 每个顶点四个字节
        //设置颜色,依次为红绿蓝和透明通道
        float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
        private int mPositionHandle;
        private int mColorHandle;
        float d = 0.01F;
        public TriangleBuffer(MainActivity activity){
    
        }
    
        public void create(){
            ByteBuffer bb = ByteBuffer.allocateDirect(
                    triangleCoords.length * 4);
            bb.order(ByteOrder.nativeOrder());
            vertexBuffer = bb.asFloatBuffer();
            vertexBuffer.put(triangleCoords);
            vertexBuffer.position(0);
    
            createVBO();
    
            int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,vertexShaderCode);
            int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentShaderCode);
            mProgram = GLES20.glCreateProgram();
            GLES20.glAttachShader(mProgram,vertexShader);
            GLES20.glAttachShader(mProgram,fragmentShader);
            GLES20.glLinkProgram(mProgram);
            //程序加入到环境里面
            GLES20.glUseProgram(mProgram);
    //        检查是否有效
            GLES20.glValidateProgram(mProgram);
            //得到活跃的unifor
            int arr[] = new int[1];
            int arr1[] = new int[1];
            int arr2[] = new int[1];
            int arr3[] = new int[1];
            byte arr4[] = new byte[10];
            GLES20.glGetProgramiv(mProgram,GLES20.GL_ACTIVE_UNIFORMS,arr,0);
            GLES20.glGetActiveUniform(
                    mProgram,
                    1,
                    1,
                    arr1,
                    1,
                    arr2,
                    1,
                    arr3,
                    1,
                    arr4,
                    0
                    );
            mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
            mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
        }
    
    
        @Override
        public void surfaceChange(int width, int height) {
            GLES20.glViewport(0,0,width,height);
        }
    
        @Override
        public void dispose() {
    
        }
    
    
        @Override
        public void render() {
            //获取位置句柄   属性句柄
    
            GLES20.glEnableVertexAttribArray(mPositionHandle);
            //准备三角形的坐标数据
            useVboDraw();
    //        GLES20.glVertexAttribPointer(
    //                mPositionHandle,
    //                COORDS_PER_VERTEX,
    //                GLES20.GL_FLOAT,
    //                false,
    //                vertexStride,
    //                vertexBuffer);
            //获取片元着色器的vColor成员的句柄
    
            color[1] = color[1]-d;
            if (color[1]<=0||color[1]>=1){
                d=-d;
            }
            //设置绘制三角形的颜色
            GLES20.glUniform4fv(mColorHandle, 1, color, 0);
            //绘制三角形
            GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
            //禁止顶点数组的句柄
            GLES20.glDisableVertexAttribArray(mPositionHandle);
        }
    
        int vboId = 0;
        private void createVBO() {
            //1. 创建VBO
            int[] vbos = new int[1];
            GLES20.glGenBuffers(vbos.length, vbos, 0);
            vboId = vbos[0];
            //2. 绑定VBO
            GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboId);
            //3. 分配VBO需要的缓存大小
            GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER,
                    triangleCoords.length * 4 +
                            triangleCoords.length * 4,
                    null, GLES20.GL_STATIC_DRAW);
            //4. 为VBO设置顶点数据的值
            GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER,
                    0,
                    triangleCoords.length * 4,
                    vertexBuffer);
    //        GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, vertexData.length * 4, textureData.length * 4, textureBuffer);
            //5. 解绑VBO
            GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
        }
    
        private void useVboDraw() {
            //1. 绑定VBO
            GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboId);
            //2. 设置顶点数据
            GLES20.glVertexAttribPointer(
                    mPositionHandle,
                    COORDS_PER_VERTEX,
                    GLES20.GL_FLOAT,
                    false,
                    vertexStride,
                    0);
    
            //3. 解绑VBO
            GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
        }
    }
    
    

    区别在哪里,只有两个地方,第一个创建缓存区放入数据,第二个是使用缓存区。

       private void createVBO() {
            //1. 创建VBO
            int[] vbos = new int[1];
            GLES20.glGenBuffers(vbos.length, vbos, 0);
            vboId = vbos[0];
            //2. 绑定VBO
            GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboId);
            //3. 分配VBO需要的缓存大小
            GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER,
                    triangleCoords.length * 4 +
                            triangleCoords.length * 4,
                    null, GLES20.GL_STATIC_DRAW);
            //4. 为VBO设置顶点数据的值
            GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER,
                    0,
                    triangleCoords.length * 4,
                    vertexBuffer);
    //        GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, vertexData.length * 4, textureData.length * 4, textureBuffer);
            //5. 解绑VBO
            GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
        }
    

    第二个是使用

       private void useVboDraw() {
            //1. 绑定VBO
            GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboId);
            //2. 设置顶点数据
            GLES20.glVertexAttribPointer(
                    mPositionHandle,
                    COORDS_PER_VERTEX,
                    GLES20.GL_FLOAT,
                    false,
                    vertexStride,
                    0);
    
            //3. 解绑VBO
            GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
        }
    

    创建部分,不需要做任何修改, 只需要加入创建代码即可,使用部分,需要删除之前顶点的指定方式,换成这个调用方法即可。

    相关文章

      网友评论

        本文标题:附录(6)使用顶点缓存区绘制

        本文链接:https://www.haomeiwen.com/subject/qytxultx.html