美文网首页OpenGL ES 3.0
android平台下OpenGLES3.0绘制立方体的几种方式

android平台下OpenGLES3.0绘制立方体的几种方式

作者: Andy周 | 来源:发表于2018-11-09 14:17 被阅读16次

    OpenGL ES 3.0学习实践

    目录

    绘制图元的几个方法

    OpenGL ES中有5个绘制图元的API调用:

    glDrawArrays、gIDrawElements、glDrawRangeHonents、 glDrawArraysInstanced和glDrawElementsInstanced

    glDrawArrays用元素索引为firstfirst+count-1的元素指定的顶点绘制mode指定的图元。

    调用glDrawArrays(GL_TRIANGLES, 0, 6)将绘制两个三角形:一个三角形由元素索引(0, 1, 2)指定,另一个三角形由元素索引(3, 4, 5)指定。
    调用glDrawArrays(GL_TRIANGLE_STRIP,0, 5)将绘制3个三角形:一个由元素索引(0, 1, 2)指定,第二个三角形由元素索引(2, 1, 3)指定,最后一个三角形由元素索引(2, 3, 4)指定。

    基于线段的方式

    基于之前的工程项目,新建LineCubeRenderer.java

    /**
     * @anchor: andy
     * @date: 2018-11-09
     * @description:
     */
    public class LineCubeRenderer implements GLSurfaceView.Renderer {
    
        private final FloatBuffer vertexBuffer;
    
        private int mProgram;
    
        private static final int POSITION_COMPONENT_COUNT = 3;
    
        /**
         * 点的坐标
         */
        private float[] vertexPoints = new float[]{
                0.25f, 0.25f, 0.0f,  //V0
                -0.75f, 0.25f, 0.0f, //V1
                -0.75f, -0.75f, 0.0f, //V2
                0.25f, -0.75f, 0.0f, //V3
    
                0.75f, -0.25f, 0.0f, //V4
                0.75f, 0.75f, 0.0f, //V5
                -0.25f, 0.75f, 0.0f, //V6
                -0.25f, -0.25f, 0.0f, //V7
    
                -0.25f, 0.75f, 0.0f, //V6
                -0.75f, 0.25f, 0.0f, //V1
    
                0.75f, 0.75f, 0.0f, //V5
                0.25f, 0.25f, 0.0f, //V0
    
                -0.25f, -0.25f, 0.0f, //V7
                -0.75f, -0.75f, 0.0f, //V2
    
                0.75f, -0.25f, 0.0f, //V4
                0.25f, -0.75f, 0.0f //V3
        };
    
        public LineCubeRenderer() {
            //分配内存空间,每个浮点型占4字节空间
            vertexBuffer = ByteBuffer.allocateDirect(vertexPoints.length * 4)
                    .order(ByteOrder.nativeOrder())
                    .asFloatBuffer();
            //传入指定的坐标数据
            vertexBuffer.put(vertexPoints);
            vertexBuffer.position(0);
        }
    
        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            //设置背景颜色
            GLES30.glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
            //编译
            final int vertexShaderId = ShaderUtils.compileVertexShader(ResReadUtils.readResource(R.raw.vertex_linecube_shader));
            final int fragmentShaderId = ShaderUtils.compileFragmentShader(ResReadUtils.readResource(R.raw.fragment_linecube_shader));
            //链接程序片段
            mProgram = ShaderUtils.linkProgram(vertexShaderId, fragmentShaderId);
            //使用程序片段
            GLES30.glUseProgram(mProgram);
    
            GLES30.glVertexAttribPointer(0, POSITION_COMPONENT_COUNT, GLES30.GL_FLOAT, false, 0, vertexBuffer);
    
            GLES30.glEnableVertexAttribArray(0);
    
        }
    
        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            GLES30.glViewport(0, 0, width, height);
        }
    
        @Override
        public void onDrawFrame(GL10 gl) {
            GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
    
            //指定线宽
            GLES30.glLineWidth(5);
    
            GLES30.glDrawArrays(GLES30.GL_LINE_LOOP, 0, 4);
    
            GLES30.glDrawArrays(GLES30.GL_LINE_LOOP, 4, 4);
    
            GLES30.glDrawArrays(GLES30.GL_LINES, 8, 8);
    
        }
    }
    

    顶点着色器

    #version 300 es
    layout (location = 0) in vec4 vPosition;
    out vec4 vColor;
    void main() {
         gl_Position  = vPosition;
         gl_PointSize = 10.0;
         vColor = vec4(0.8,0.8,0.8,1.0);
    }
    

    片段着色器

    #version 300 es
    precision mediump float;
    in vec4 vColor;
    out vec4 fragColor;
    void main() {
         fragColor = vColor;
    }
    

    上面的坐标点注释已经很清楚了,可以对照下面这张图来理解对应的坐标

    image

    基于顶点法绘制立方体

    /**
     * @anchor: andy
     * @date: 2018-11-09
     * @description:
     */
    public class ColorCubeRenderer implements GLSurfaceView.Renderer {
    
        private final FloatBuffer vertexBuffer, colorBuffer;
    
        private int mProgram;
    
        private static final int VERTEX_POSITION_SIZE = 3;
    
        private static final int VERTEX_COLOR_SIZE = 4;
    
        /**
         * 点的坐标
         */
        private float[] vertexPoints = new float[]{
                //背面矩形
                0.75f, 0.75f, 0.0f, //V5
                -0.25f, 0.75f, 0.0f, //V6
                -0.25f, -0.25f, 0.0f, //V7
                0.75f, 0.75f, 0.0f, //V5
                -0.25f, -0.25f, 0.0f, //V7
                0.75f, -0.25f, 0.0f, //V4
    
                //左侧矩形
                -0.25f, 0.75f, 0.0f, //V6
                -0.75f, 0.25f, 0.0f, //V1
                -0.75f, -0.75f, 0.0f, //V2
                -0.25f, 0.75f, 0.0f, //V6
                -0.75f, -0.75f, 0.0f, //V2
                -0.25f, -0.25f, 0.0f, //V7
    
                //底部矩形
                0.75f, -0.25f, 0.0f, //V4
                -0.25f, -0.25f, 0.0f, //V7
                -0.75f, -0.75f, 0.0f, //V2
                0.75f, -0.25f, 0.0f, //V4
                -0.75f, -0.75f, 0.0f, //V2
                0.25f, -0.75f, 0.0f, //V3
    
                //正面矩形
                0.25f, 0.25f, 0.0f,  //V0
                -0.75f, 0.25f, 0.0f, //V1
                -0.75f, -0.75f, 0.0f, //V2
                0.25f, 0.25f, 0.0f,  //V0
                -0.75f, -0.75f, 0.0f, //V2
                0.25f, -0.75f, 0.0f, //V3
    
                //右侧矩形
                0.75f, 0.75f, 0.0f, //V5
                0.25f, 0.25f, 0.0f, //V0
                0.25f, -0.75f, 0.0f, //V3
                0.75f, 0.75f, 0.0f, //V5
                0.25f, -0.75f, 0.0f, //V3
                0.75f, -0.25f, 0.0f, //V4
    
                //顶部矩形
                0.75f, 0.75f, 0.0f, //V5
                -0.25f, 0.75f, 0.0f, //V6
                -0.75f, 0.25f, 0.0f, //V1
                0.75f, 0.75f, 0.0f, //V5
                -0.75f, 0.25f, 0.0f, //V1
                0.25f, 0.25f, 0.0f  //V0
        };
    
    
        //立方体的顶点颜色
        private float[] colors = {
                //背面矩形颜色
                1f, 0f, 1f, 1f,
                1f, 0f, 1f, 1f,
                1f, 0f, 1f, 1f,
                1f, 0f, 1f, 1f,
                1f, 0f, 1f, 1f,
                1f, 0f, 1f, 1f,
    
                //左侧矩形颜色
                0f, 1f, 0f, 1f,
                0f, 1f, 0f, 1f,
                0f, 1f, 0f, 1f,
                0f, 1f, 0f, 1f,
                0f, 1f, 0f, 1f,
                0f, 1f, 0f, 1f,
    
                //底部矩形颜色
                1f, 0f, 0.5f, 1f,
                1f, 0f, 0.5f, 1f,
                1f, 0f, 0.5f, 1f,
                1f, 0f, 0.5f, 1f,
                1f, 0f, 0.5f, 1f,
                1f, 0f, 0.5f, 1f,
    
                //正面矩形颜色
                0.2f, 0.3f, 0.2f, 1f,
                0.2f, 0.3f, 0.2f, 1f,
                0.2f, 0.3f, 0.2f, 1f,
                0.2f, 0.3f, 0.2f, 1f,
                0.2f, 0.3f, 0.2f, 1f,
                0.2f, 0.3f, 0.2f, 1f,
    
                //右侧矩形颜色
                0.1f, 0.2f, 0.3f, 1f,
                0.1f, 0.2f, 0.3f, 1f,
                0.1f, 0.2f, 0.3f, 1f,
                0.1f, 0.2f, 0.3f, 1f,
                0.1f, 0.2f, 0.3f, 1f,
                0.1f, 0.2f, 0.3f, 1f,
    
                //顶部矩形颜色
                0.3f, 0.4f, 0.5f, 1f,
                0.3f, 0.4f, 0.5f, 1f,
                0.3f, 0.4f, 0.5f, 1f,
                0.3f, 0.4f, 0.5f, 1f,
                0.3f, 0.4f, 0.5f, 1f,
                0.3f, 0.4f, 0.5f, 1f
        };
    
        public ColorCubeRenderer() {
            //分配内存空间,每个浮点型占4字节空间
            vertexBuffer = ByteBuffer.allocateDirect(vertexPoints.length * 4)
                    .order(ByteOrder.nativeOrder())
                    .asFloatBuffer();
            //传入指定的坐标数据
            vertexBuffer.put(vertexPoints);
            vertexBuffer.position(0);
    
            //分配内存空间,每个浮点型占4字节空间
            colorBuffer = ByteBuffer.allocateDirect(colors.length * 4)
                    .order(ByteOrder.nativeOrder())
                    .asFloatBuffer();
            //传入指定的数据
            colorBuffer.put(colors);
            colorBuffer.position(0);
        }
    
        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            //设置背景颜色
            GLES30.glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
            //编译
            final int vertexShaderId = ShaderUtils.compileVertexShader(ResReadUtils.readResource(R.raw.vertex_colorcube_shader));
            final int fragmentShaderId = ShaderUtils.compileFragmentShader(ResReadUtils.readResource(R.raw.fragment_colorcube_shader));
            //链接程序片段
            mProgram = ShaderUtils.linkProgram(vertexShaderId, fragmentShaderId);
            //使用程序片段
            GLES30.glUseProgram(mProgram);
    
            GLES30.glVertexAttribPointer(0, VERTEX_POSITION_SIZE, GLES30.GL_FLOAT, false, 0, vertexBuffer);
            //启用位置顶点属性
            GLES30.glEnableVertexAttribArray(0);
    
    
            GLES30.glVertexAttribPointer(1, VERTEX_COLOR_SIZE, GLES30.GL_FLOAT, false, 0, colorBuffer);
            //启用颜色顶点属性
            GLES30.glEnableVertexAttribArray(1);
    
        }
    
        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            GLES30.glViewport(0, 0, width, height);
    
        }
    
        @Override
        public void onDrawFrame(GL10 gl) {
            GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
    
            GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, 36);
    
        }
    }
    

    输出显示如下:

    image

    聪明的你一定发现了,其实绘制立方体我们只需要绘制外层的三个面就可以了,去掉顶点位置和颜色属性中的,背面,左侧以及底部相关的属性,只保留最外层的三个可见面,运行试试看,结果也是一样

    基于索引法绘制立方体

    /**
     * @anchor: andy
     * @date: 2018-11-09
     * @description: 基于索引法绘制立方体
     */
    public class IndicesCubeRenderer implements GLSurfaceView.Renderer {
    
        private final FloatBuffer vertexBuffer, colorBuffer;
    
        private final ShortBuffer indicesBuffer;
    
        private int mProgram;
    
        private static final int VERTEX_POSITION_SIZE = 3;
    
        private static final int VERTEX_COLOR_SIZE = 4;
    
        /**
         * 点的坐标
         */
        private float[] vertexPoints = new float[]{
                //正面矩形
                0.25f, 0.25f, 0.0f,  //V0
                -0.75f, 0.25f, 0.0f, //V1
                -0.75f, -0.75f, 0.0f, //V2
                0.25f, -0.75f, 0.0f, //V3
    
                //背面矩形
                0.75f, -0.25f, 0.0f, //V4
                0.75f, 0.75f, 0.0f, //V5
                -0.25f, 0.75f, 0.0f, //V6
                -0.25f, -0.25f, 0.0f //V7
        };
    
        /**
         * 定义索引
         */
        private short[] indices = {
                //背面
                5, 6, 7, 5, 7, 4,
                //左侧
                6, 1, 2, 6, 2, 7,
                //底部
                4, 7, 2, 4, 2, 3,
                //顶面
                5, 6, 7, 5, 7, 4,
                //右侧
                5, 0, 3, 5, 3, 4,
                //正面
                0, 1, 2, 0, 2, 3
        };
    
        //立方体的顶点颜色
        private float[] colors = {
                0.3f, 0.4f, 0.5f, 1f,   //V0
                0.3f, 0.4f, 0.5f, 1f,   //V1
                0.3f, 0.4f, 0.5f, 1f,   //V2
                0.3f, 0.4f, 0.5f, 1f,   //V3
                0.6f, 0.5f, 0.4f, 1f,   //V4
                0.6f, 0.5f, 0.4f, 1f,   //V5
                0.6f, 0.5f, 0.4f, 1f,   //V6
                0.6f, 0.5f, 0.4f, 1f    //V7
        };
    
        public IndicesCubeRenderer() {
            //分配内存空间,每个浮点型占4字节空间
            vertexBuffer = ByteBuffer.allocateDirect(vertexPoints.length * 4)
                    .order(ByteOrder.nativeOrder())
                    .asFloatBuffer();
            //传入指定的坐标数据
            vertexBuffer.put(vertexPoints);
            vertexBuffer.position(0);
    
            //分配内存空间,每个浮点型占4字节空间
            colorBuffer = ByteBuffer.allocateDirect(colors.length * 4)
                    .order(ByteOrder.nativeOrder())
                    .asFloatBuffer();
            //传入指定的数据
            colorBuffer.put(colors);
            colorBuffer.position(0);
    
            //分配内存空间,每个浮点型占4字节空间
            indicesBuffer = ByteBuffer.allocateDirect(indices.length * 4)
                    .order(ByteOrder.nativeOrder())
                    .asShortBuffer();
            //传入指定的数据
            indicesBuffer.put(indices);
            indicesBuffer.position(0);
        }
    
        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            //设置背景颜色
            GLES30.glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
            //编译
            final int vertexShaderId = ShaderUtils.compileVertexShader(ResReadUtils.readResource(R.raw.vertex_colorcube_shader));
            final int fragmentShaderId = ShaderUtils.compileFragmentShader(ResReadUtils.readResource(R.raw.fragment_colorcube_shader));
            //链接程序片段
            mProgram = ShaderUtils.linkProgram(vertexShaderId, fragmentShaderId);
            //使用程序片段
            GLES30.glUseProgram(mProgram);
    
            GLES30.glVertexAttribPointer(0, VERTEX_POSITION_SIZE, GLES30.GL_FLOAT, false, 0, vertexBuffer);
            //启用位置顶点属性
            GLES30.glEnableVertexAttribArray(0);
    
            GLES30.glVertexAttribPointer(1, VERTEX_COLOR_SIZE, GLES30.GL_FLOAT, false, 0, colorBuffer);
            //启用颜色顶点属性
            GLES30.glEnableVertexAttribArray(1);
    
        }
    
        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            GLES30.glViewport(0, 0, width, height);
        }
    
        @Override
        public void onDrawFrame(GL10 gl) {
            GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
    
            GLES30.glDrawElements(GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_SHORT, indicesBuffer);
    
        }
    }
    

    输出如下:

    image

    如果我们采用glDrawArrays的方式,需要给这个立方体指定很多的顶点,而使用glDrawElements方法绘制的时候,我们只需要指定8个顶点即可,因此当涉及到顶点共享的时候,应该尽可能的使用glDrawElements方法完成绘制。

    项目地址:
    https://github.com/byhook/opengles4android

    参考:
    《OpenGL ES 3.0 编程指南第2版》
    《OpenGL ES应用开发实践指南Android卷》

    相关文章

      网友评论

        本文标题:android平台下OpenGLES3.0绘制立方体的几种方式

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