美文网首页音视频从入门到放弃
OpenGLES 之 绘制三角形 (一)

OpenGLES 之 绘制三角形 (一)

作者: PuHJ | 来源:发表于2019-07-20 16:36 被阅读0次

    一、OpenGL ES

    OpenGL是一个供运行在Linux、Unix、Mac和Windows的桌面系统使用的跨平台标准的API,OpenGL ES是以手持和嵌入式设备为目标的高级3D图形应用程序编程接口。即OpenGLES是OpenGL的子集,去除了复杂的不常用的功能,专门为PDA等为目标的图形API。

    OpenGLES经常用在对图片、视频、相机、游戏等方面。它是使用了GPU的计算的,从而解放CPU的使用,加速渲染能力。

    二、前言

    作为一门语言的入门,都是从HelloWord学起的。当然OpenGL也不例外,绘制一个三角形应该就是OpenGLES的“HelloWorld”了,但是这个HelloWorld有的复杂,并不像java等语言输入一句话就行了。绘制一个三角形虽然是“HelloWorld”,但是麻雀虽小五脏俱全,工作量和操作步骤却没有变小。

    本文选择的渲染载体为:GLSurfaceView

    简单的介绍下GLSurfaceView,它是继承自SurfaceView,一个双缓冲机制并可在子线程更新的具有两个View体系结构的View,在SurfaceView的基础上增加了对EGL的管理。减少了我们对EGL的操作,简化了步骤。简单说EGL是OpenGLES和底层硬件的过渡层,他抽象了硬件的细节,完成了OpenGLES的跨平台性。

    编写前,先介绍一个概念:图形渲染管线,它是从输入数据开始到绘制到界面的过程。大体步骤,可以参考如下官方给出的步骤。蓝色部分是用户可定制开发的。


    管线操作
    • 顶点着色器:它把一个顶点作为输入。把3D坐标转为标准化设备坐标,同时顶点着色器允许我们对顶点属性进行一些基本处理,如矩阵变换。
    • 图元装配:它将所有的顶点作为输入,将其装配成一个具体的形状。
    • 几何着色器:几何着色器把图元形式的一系列顶点的集合作为输入,通过产生新顶点构造出新的图元来生成其他形状。
    • 光栅化: 图元映射为最终屏幕上相应的像素
    • 片段着色器: 计算一个像素的最终颜色
    • 测试和混合: 根据Z轴选择是否抛弃该点(被遮住),以及对于透明的颜色进行混合。

    三、绘制三角形

    绘制三角形,分为如下几步:

    • 存储顶点数据到ByteBuffer中
    • 编写顶点和片段着色器,并加载相应的着色器(shader)
    • 创建着色器程序,并对顶点和片段着色器进行链接
    • 视口变换操作(glViewport)
    • 传递顶点和颜色数据
    • 绘制物体

    1)、环境准备

    在AndroidManifest中配置OpenGLES版本

    <uses-feature android:glEsVersion="0x00020000" android:required="true" />
    

    并用GLSurfaceView搭建好一个EGL环境,所有的操作在GLSurfaceView.Render的回调中进行。回调开始的时候代表着EGL环境搭建完毕,否则会导致操作失败。

    2)、存储顶点数据到ByteBuffer中

        // 三维的顶点坐标,有方向的
        private static final float triangleCoords[] = {
                -0.5f, 1f, 0.0f,  // bottom right
                -1f, -1f, 0.0f, // bottom left
                0.5f, 1f, 0.0f, // top
        };
    
    
        private static final short indices[] = {
                0,1,2
        };
    
        // 颜色
        private static final  float colors[] = {0.8f, 0.4f, 0.1f, 0f};
    
            // 1、存储顶点坐标
            vertexBuffer = initBuffer(triangleCoords,4);
            ByteBuffer mbb = ByteBuffer.allocateDirect(triangleCoords.length * 4);
            // 数组排列用nativeOrder
            mbb.order(ByteOrder.nativeOrder());
            FloatBuffer floatBuffer = mbb.asFloatBuffer();
            floatBuffer.put(vertexBuffer);
            floatBuffer.flip();
            
            mbb = ByteBuffer.allocateDirect(indices.length * 2);
            // 数组排列用nativeOrder
            mbb.order(ByteOrder.nativeOrder());
            indiceBuffer = mbb.asShortBuffer();
            indiceBuffer.put(indices);
            indiceBuffer.flip();
    

    将顶点坐标存放在ByteBuffer中,供下文传递数据到Shader中。

    3)、编写顶点和片段着色器代码,并加载相应的着色器

    分别编写顶点和片段GLSL代码,Shader是通过输入和输出进行通信的。顶点着色器中用四个元素的向量的属性值传递顶点值,传递到内置的变量gl_Position中。片段着色器是输入颜色的,这里传入的类型是uniform。precision mediump float是代表精度。

        // 顶点着色器code
        private static final String vertexShaderCode =
                "attribute vec4 vPosition;" +
                "void main() {" +
                "  gl_Position = vPosition;" +
                "}";
    
        // 片元着色器code
        private static final String fragmentShaderCode =
                "precision mediump float;" +
                "uniform vec4 vColor;" +
                "void main() {" +
                "    gl_FragColor = vColor;" +
                "}";
    
    加载shader:

    分别创建、加载以及编译着色器代码:

        private int loadShader(int type, String shaderCode) {
            //根据type创建顶点着色器或者片元着色器
            int shader = GLES20.glCreateShader(type);
            //将资源加入到着色器中,并编译
            GLES20.glShaderSource(shader, shaderCode);
            GLES20.glCompileShader(shader);
            return shader;
        }
    
            int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,vertexShaderCode);
            int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentShaderCode);
    

    4)、创建着色器程序,并对顶点和片段着色器进行链接

    顶点和片段着色器只有在链接到着色器程序中,才会起作用。

            //创建一个空的OpenGLES程序
            mProgram = GLES20.glCreateProgram();
            //将顶点着色器加入到程序
            GLES20.glAttachShader(mProgram, vertexShader);
            //将片元着色器加入到程序中
            GLES20.glAttachShader(mProgram, fragmentShader);
            //连接到着色器程序
            GLES20.glLinkProgram(mProgram);
    

    5)、视口变换操作(glViewport)

    // 设置窗口的大小
    GLES20.glViewport(0,0,width,height);
    

    6)、传递顶点和颜色数据

    现在需要将顶点、颜色、顶点索引数据传入到相应的地方,这样才会绘制出想要的形状。

    首先需要获取属性为vPosition的句柄和uniform为vColor的句柄,并根据Attribute和Uniform两种方式传入对应的数据。

            GLES20.glUseProgram(mProgram);
            GLES20.glClearColor(0, 0, 0, 1);
            GLES20.glDisable(GLES20.GL_DEPTH_TEST); // 当我们需要绘制透明图片时,就需要关闭它
            // 填充数据
            //获取顶点着色器的vPosition成员句柄
            mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
            //启用三角形顶点的句柄
            GLES20.glEnableVertexAttribArray(mPositionHandle);
            //准备三角形的坐标数据
            GLES20.glVertexAttribPointer(mPositionHandle, 3,
                    GLES20.GL_FLOAT, false,
                    12, vertexBuffer);
    
            mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
            Log.e(TAG, "onDrawFrame: mPositionHandle="+mPositionHandle+"  mColorHandle="+mColorHandle);
            //设置绘制三角形的颜色
            GLES20.glUniform4fv(mColorHandle, 1, colors, 0);
    

    7)、绘制物体

    通过glDrawElements方法绘制图形,glDrawElements需要使用到索引数组。绘制的API还可以是glDrawArrays,这里不需要明确的设置绘制的顺序,而是通过绘制的模式来决定的。

            //绘制三角形
            GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, 3,GLES20.GL_UNSIGNED_SHORT,indiceBuffer);
    

    四、绘制模式详解

    对于绘制的模式,上面的代码使用的是GLES20.GL_TRIANGLE_STRIP,除此之外还有些其它的模式:、

    • GLES20.GL_POINTS:绘制点精灵模式
    • GLES20.GL_LINES:对于n各定点,会绘制(v0、v1)、(v2、v3)、(v4、v5)、(vn-2、vn-1)条线段
    • GLES20.GL_LINE_LOOP:对于n各定点,会绘制(v0、v1)、(v1、v2)、(v2、v3)、(vn-2、vn-1)条线
    • GLES20.GL_LINE_STRIP:对于n各定点,会绘制(v0、v1)、(v1、v2)、(v2、v3)、(vn-2、vn-1)、(vn-1、v0)条线,这绘制的会多了个首位相连的线段。
    • GLES20.GL_TRIANGLES:同GL_LINES,它是不重复的使用顶点
    • GLES20.GL_TRIANGLE_STRIP :绘制一系列相互连接的三角形,对于5个顶点,它绘制的是(v0,v1,v2)、(v2,v1,v3)、(v2,v3,v4)
    • GLES20.GL_TRIANGLE_FAN: 绘制一系列相互连接的三角形,对于5个顶点,它绘制的是(v0,v1,v2)、(v0,v2,v3)、(v0,v3,v4)

    五、参考

    LearnOpenGL-CN
    Jhuster的专栏

    上例代码下载

    相关文章

      网友评论

        本文标题:OpenGLES 之 绘制三角形 (一)

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