美文网首页移动开发干货店
《OpenGL从入门到放弃04》画一个长方形

《OpenGL从入门到放弃04》画一个长方形

作者: 蓝师傅_Android | 来源:发表于2019-04-25 22:39 被阅读152次

    之前文章:

    《OpenGL从入门到放弃01 》一些基本概念
    《OpenGL从入门到放弃02 》GLSurfaceView和Renderer
    《OpenGL从入门到放弃03 》相机和视图

    上一篇已经介绍了使用相机和视图,解决三角形位置问题,这一篇我们在三角形的基础上修改,画一个长方形。

    一、修改顶点

    static float triangleCoords[] = {
               -1f, 0.5f, 0.0f, // top left
               -1f, -0.5f, 0.0f, // bottom left
                1f, 0.5f, 0.0f,  // top right
                1f, -0.5f, 0.0f  // bottom right
        };
    

    长方形4个顶点,没毛病。

    二、绘制

    方法1,顶点法
            GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount);
    

    GLES20 .GL_TRIANGLE_STRIP 不清楚?等下会介绍。

    方法2,索引法

    增加索引代码,并且要转换成 ShortBuffer

    //用索引表示两个三角形,012和123
        static short index[]={
                0,1,2,1,2,3
        };
    //索引数据要在OpenGL中使用必须转换
      indexBuffer = GLUtil.shortArray2ShortBuffer(index);
    
      //索引法绘制,也就是一个正方形
      GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP,index.length, GLES20.GL_UNSIGNED_SHORT,indexBuffer);
    
    

    两种方法绘制的结果是一样的


    说明:

    GLES20.glDrawArrays 的第一个参数表示绘制方式,第二个参数表示偏移量,第三个参数表示顶点个数。
    绘制方式有:

    int GL_POINTS       //将传入的顶点坐标作为单独的点绘制
    int GL_LINES        //将传入的坐标作为单独线条绘制,ABCDEFG六个顶点,绘制AB、CD、EF三条线
    int GL_LINE_STRIP   //将传入的顶点作为折线绘制,ABCD四个顶点,绘制AB、BC、CD三条线
    int GL_LINE_LOOP    //将传入的顶点作为闭合折线绘制,ABCD四个顶点,绘制AB、BC、CD、DA四条线。
    int GL_TRIANGLES    //将传入的顶点作为单独的三角形绘制,ABCDEF绘制ABC,DEF两个三角形
    int GL_TRIANGLE_FAN    //将传入的顶点作为扇面绘制,ABCDEF绘制ABC、ACD、ADE、AEF四个三角形
    int GL_TRIANGLE_STRIP   //将传入的顶点作为三角条带绘制,ABCDEF绘制ABC,BCD,CDE,DEF四个三角形
    

    GLES20.glDrawElements 称之为索引法,是根据索引序列,在顶点序列中找到对应的顶点,并根据绘制的方式,组成相应的图元进行绘制。

    顶点法拥有的绘制方式,索引法也都有。相对于顶点法在复杂图形的绘制中无法避免大量顶点重复的情况,索引法可以相对顶点法减少很多重复顶点占用的空间。


    完整代码如下

    /**
     * 正方形
     * 在三角形基础修改
     */
    public class Square {
    
        // 顶点着色器的脚本
        String vertexShaderCode =
                "uniform mat4 uMVPMatrix;" +         //接收传入的转换矩阵
                        " attribute vec4 vPosition;" +      //接收传入的顶点
                        " void main() {" +
                        "  gl_Position = uMVPMatrix * vPosition;" +  //矩阵变换计算之后的位置
                        " }";
    
        // 片元着色器的脚本
        String fragmentShaderCode =
                " precision mediump float;" +  // 声明float类型的精度为中等(精度越高越耗资源)
                        " uniform vec4 vColor;" +       // 接收传入的颜色
                        " void main() {" +
                        "     gl_FragColor = vColor;" +  // 给此片元的填充色
                        " }";
    
        private FloatBuffer vertexBuffer;  //顶点坐标数据要转化成FloatBuffer格式
        private ShortBuffer indexBuffer; //所引法需要
    
    
        // 数组中每3个值作为一个坐标点
        static final int COORDS_PER_VERTEX = 3;
        //正方形坐标数组
        static float triangleCoords[] = {
               -1f, 0.5f, 0.0f, // top left
               -1f, -0.5f, 0.0f, // bottom left
                1f, 0.5f, 0.0f,  // top right
                1f, -0.5f, 0.0f  // bottom right
        };
    
        //用索引表示两个三角形,012和123
        static short index[]={
                0,1,2,1,2,3
        };
    
        //顶点个数,计算得出
        private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
        //一个顶点有3个float,一个float是4个字节,所以一个顶点要12字节
        private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per mVertex
    
        //三角形的颜色数组,rgba
        private float[] mColor = {
                0.0f, 1.0f, 0.0f, 1.0f,
        };
    
        //当前绘制的顶点位置句柄
        private int vPositionHandle;
        //片元着色器颜色句柄
        private int vColorHandle;
        //变换矩阵句柄
        private int mMVPMatrixHandle;
        //这个可以理解为一个OpenGL程序句柄
        private final int mProgram;
    
        //变换矩阵,提供set方法
        private float[] mvpMatrix = new float[16];
        public void setMvpMatrix(float[] mvpMatrix) {
            this.mvpMatrix = mvpMatrix;
        }
    
    
        public Square() {
            /** 1、数据转换,顶点坐标数据float类型转换成OpenGL格式FloatBuffer,int和short同理*/
            vertexBuffer = GLUtil.floatArray2FloatBuffer(triangleCoords);
            indexBuffer = GLUtil.shortArray2ShortBuffer(index);
    
            /** 2、加载编译顶点着色器和片元着色器*/
            int vertexShader = GLUtil.loadShader(GLES20.GL_VERTEX_SHADER,
                    vertexShaderCode);
            int fragmentShader = GLUtil.loadShader(GLES20.GL_FRAGMENT_SHADER,
                    fragmentShaderCode);
    
            /** 3、创建空的OpenGL ES程序,并把着色器添加进去*/
            mProgram = GLES20.glCreateProgram();
    
            // 添加顶点着色器到程序中
            GLES20.glAttachShader(mProgram, vertexShader);
    
            // 添加片段着色器到程序中
            GLES20.glAttachShader(mProgram, fragmentShader);
    
            /** 4、链接程序*/
            GLES20.glLinkProgram(mProgram);
    
        }
    
    
        public void draw() {
    
            // 将程序添加到OpenGL ES环境
            GLES20.glUseProgram(mProgram);
    
            /***1.获取句柄*/
            // 获取顶点着色器的位置的句柄(这里可以理解为当前绘制的顶点位置)
            vPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
            // 获取片段着色器的vColor句柄
            vColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
            // 获取变换矩阵的句柄
            mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
    
            /**2.设置数据*/
            // 启用顶点属性,最后对应禁用
            GLES20.glEnableVertexAttribArray(vPositionHandle);
    
            //准备三角形坐标数据
            GLES20.glVertexAttribPointer(vPositionHandle, COORDS_PER_VERTEX,
                    GLES20.GL_FLOAT, false,
                    vertexStride, vertexBuffer);
            // 设置绘制三角形的颜色,给vColor 这个变量赋值
            GLES20.glUniform4fv(vColorHandle, 1, mColor, 0);
            // 将投影和视图转换传递给着色器,可以理解为给uMVPMatrix这个变量赋值为mvpMatrix
            GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
    
            /** 3.绘制正方形,4个顶点, GL_TRIANGLE_STRIP的方式绘制连续的三角形*/
            GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount);
    //        索引法绘制两个三角形,也就是一个正方形
    //        GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP,index.length, GLES20.GL_UNSIGNED_SHORT,indexBuffer);
    
            // 禁用顶点数组
            GLES20.glDisableVertexAttribArray(vPositionHandle);
        }
    }
    
    

    好了,长方形的绘制很简单,本质上就是画两个三角形,其它复杂的图形也是如此,由多个简单的图形组成。

    下一篇介绍一下着色器语言,然后就开始比较有意思的纹理和图片处理,敬请期待吧~

    相关文章

      网友评论

        本文标题:《OpenGL从入门到放弃04》画一个长方形

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