美文网首页
OpenGL ES 扫盲

OpenGL ES 扫盲

作者: 毛先森 | 来源:发表于2020-09-02 15:42 被阅读0次

    前言

    OpenSL 是处理音频的底层开源库, OpenGL 则是处理图像相关的库,而对于移动端 Cpu/内存资源比较吃紧的特性,OpenGL 将部分不那么重要的 Api 进行精简,推出了 OpenGL ES ,相当于一个 mini 版本

    从 2014 年以来,OpenGL ES 经历多个版本迭代,现在已经迭代到 3.x 版本

    image.png

    如何在 Android 上使用

    首先它对应了专门的控件 GLSurfaceView,我们用 Opengl ES 可以直接绘制的图形有点、线、三角形,其他图像怎么办呢? -- 用三角形拼接

    • 构建 OpenGL ES 环境
        // AndroidManifest 文件中声明
    
        <uses-feature android:glEsVersion="0x00020000" android:required="true" />
    
    
    • 使用 GLSurfaceView
    • 构建渲染程序

    ByteBuffer 是什么

    缓冲区是一段定长的存储空间,用于加速频繁的 I/O 操作,其实就是临时存储数据,直接与信道(Channel)打交道,写入数据到信道或者从信道读取。

    • ByteBuffer 的使用方法
    1. allocate(int capacity):从堆空间中分配一个容量大小为capacity的byte数组作为缓冲区的byte数据存储器
    2. allocateDirect(int capacity):通过操作系统来创建内存块用作缓冲区,而不在JVM堆栈中
    3. wrap(byte[] array):这个缓冲区的数据会存放在byte数组中
    4. wrap(byte[] array,int offset, int length):在上一个方法的基础上可以指定偏移量和长度

    实践:使用 OpenGL 绘制 2D 三角形

    OpenGL ES 是直接作用于硬件,所以有较高的性能优势,但是需要特定的语言来实现,比如在绘制三角形中,我们需要自己手写 shader (着色器),Opsl ES 2.0 以后需要自己实现了,在 1.x 版本都是系统的工作,提高了开发难度

    • 定义三角形
    • 定义顶点着色器、片源着色器
    • 绘制
    
    /**
     * 用于 OpenGL 绘制的三角形
     * @author : kai.mao
     * @date :  2020/9/2
     */
    public class GLTriangle {
    
        private final int mProgram;
    
        // 为顶点创建一个浮点型缓冲区
        private FloatBuffer vertexBuffer;
        private static final int VERTEX_COUNT = 3;
        //用于存取attribute修饰的变量的位置编号
        private int mPositionHandle;
        //用于存取uniform修饰的变量的位置编号
        private int mColorHandle;
    
        private final int vertexCount = triangleCoords.length / VERTEX_COUNT;
        // 4 bytes per vertex
        private final int vertexStride = VERTEX_COUNT * 4;
    
    
    
        static float triangleCoords[] = {
                // top 屏幕顶端中心点
                0.0f, 1.0f, 1.0f,
                // bottom left 屏幕底部左下角
                -1.0f, -1.0f, 0.0f,
                // bottom right 屏幕底部右下角
                1.0f, -1.0f, 0.0f
                //以上坐标z都为0 创建一个平面的三角形
        };
    
    
        // Set color with red, green, blue and alpha (opacity) values
        private float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };
    
        public GLTriangle(){
            ByteBuffer byteBuffer = ByteBuffer.allocateDirect(triangleCoords.length * 4);
            byteBuffer.order(ByteOrder.nativeOrder());
            vertexBuffer = byteBuffer.asFloatBuffer();
            vertexBuffer.put(triangleCoords);
            vertexBuffer.position(0);
    
            // 加载顶点着色器
            int vertexShader = TriangleRender.loadShader(GLES20.GL_VERTEX_SHADER,vertexShaderCode);
            // 加载片元着色器
            int frameShader = TriangleRender.loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentShaderCode);
            // 创建 gl 程序
            mProgram = GLES20.glCreateProgram();
            GLES20.glAttachShader(mProgram, vertexShader);
            GLES20.glAttachShader(mProgram, frameShader);
            // 链接程序
            GLES20.glLinkProgram(mProgram);
        }
    
        /**
         * 顶点着色器代码
         * attribute变量(属性变量)只能用于顶点着色器中
         * uniforms变量(一致变量)用来将数据值从应用程其序传递到顶点着色器或者片元着色器。 。
         * varying变量(易变变量)是从顶点着色器传递到片元着色器的数据变量。
         * gl_Position (必须)为内建变量,表示变换后点的空间位置。
         */
        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;" + // 颜色值传给 gl_FragColor内建变量,完成片元的着色
                        "}";
    
    
    
        public void draw(){
            // 使用 GL 程序
            GLES20.glUseProgram(mProgram);
            mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
            GLES20.glVertexAttribPointer(mPositionHandle, VERTEX_COUNT,
                    GLES20.GL_FLOAT, false,
                    vertexStride, vertexBuffer);
            GLES20.glEnableVertexAttribArray(mPositionHandle);
            mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
            GLES20.glUniform4fv(mColorHandle, 1, color, 0);
            GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
            GLES20.glDisableVertexAttribArray(mPositionHandle);
        }
    
    }
    
    
    
    /**
     * @author : kai.mao
     * @date :  2020/9/2
     */
    public class TriangleRender implements GLSurfaceView.Renderer {
    
        GLTriangle glTriangle;
    
    
        public TriangleRender() {
        }
    
        @Override
        public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
            glTriangle = new GLTriangle();
        }
    
        @Override
        public void onSurfaceChanged(GL10 gl10, int width, int height) {
            GLES20.glViewport(0, 0, width, height);
    
        }
    
        @Override
        public void onDrawFrame(GL10 gl10) {
            //清空颜色
            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    
            glTriangle.draw();
        }
    
        /**
         * 加载并编译着色器代码
         * 渲染器类型type={GLES20.GL_VERTEX_SHADER, GLES20.GL_FRAGMENT_SHADER}
         * 渲染器代码 GLSL
         */
        public static int loadShader(int type, String shaderCode){
    
            int shader = GLES20.glCreateShader(type);
            //加载shader代码 glShaderSource 和 glCompileShader
            GLES20.glShaderSource(shader, shaderCode);
            GLES20.glCompileShader(shader);
            return shader;
        }
    
    }
    
    

    PS

    • 三角形的顶点顺序以逆时针排列,叫做 “卷曲顺序”,原因统一使用卷曲顺序有利于 OpenGL 的优化,可以减少绘制那些无法被看到的图形
    • OpenGL 的坐标系和 Android 坐标系不一样,Android 中的坐标系顶点位于屏幕左上角,而 OpenGL 世界坐标系位于屏幕中心位置
    image.png
    • OpenGL 程序需要使用 Java + GLSL 两种语言编写

    相关链接

    相关文章

      网友评论

          本文标题:OpenGL ES 扫盲

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