美文网首页
一、OpenGL在Android中的使用

一、OpenGL在Android中的使用

作者: 石器时代小古董 | 来源:发表于2019-10-04 21:06 被阅读0次

    OpenGL 的概念
    OpenGL API
    OpenGL 专题
    [Android OpenGL](https://www.jianshu.com/p/92d02ac80611

    一、什么是 OpenGL

    图形领域的标准。它是一套描述了如何绘制2D和3D图像的API。它与硬件无关。是一个跨平台操作 GPU 的 API。可以想象成是一种CS架构,客户端通过调用 OpenGL 的 API 发起一个渲染的请求,请求传送给图形硬件厂商提供的 OpenGL 服务

    在 OpenGl 中都是由三个顶点组成的平面

    需要自己写顶点着色器和片元着色器的功能

    二、GPU 概念

    GPU 是是图形处理器,它无法单独工作,必须由 CPU 进行控制调用才能工作。它有许多的计算单元。

    三、OpenGL 中的一些概念

    着色器是使用 GLSL 所编写的一段小程序。

    顶点着色器:它是运行在GPU上的小程序,用于渲染图形顶点的OpenGL ES 图形代码

    片元着色器:负责呈现面的颜色<BR>

    四、在 Android 中使用 OpenGL

    android 中提供了 GLSurface 和 GLRender 。GLSurface 负责展示 GLRender 负责真正的渲染

    [图片上传失败...(image-312d4c-1570195439422)]

    五、示例代码

    1.集成 GLSurfaceView

    setEGLContextClientVersion 调用该方法设定使用的 OpenGL ES 的版本

    给 GLSurfaceView 传递一个 Renderer 用来真正的渲染

    public class GLView extends GLSurfaceView {
        public GLView(Context context) {
            super(context);
        }
    
        public GLView(Context context, AttributeSet attrs) {
            super(context, attrs);
            setEGLContextClientVersion(2);
            setRenderer(new GLRender(this));
        }
    }
    
    

    2.Render

    API 作用
    onSurfaceCreate 当surface创建完毕
    onSurfaceChange 当surface改变时
    onDrawFrame 系统调用次方法重回Surface

    1.Render 是真正调用 OpenGL 做渲染的地方

    2.Surface 创建的时候构造 OpenGL 的着色器

    3.在onDrawFrame 之前要清空一下,并且调用 OpenGL 绘制

    class GLRender implements GLSurfaceView.Renderer {
        protected View mView;
        private Triangle mGLObject;
    
        public GLRender(GLView glView) {
            this.mView = glView;
    
        }
    
        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            GLES20.glClearColor(0, 0, 0, 0);
            mGLObject = new Triangle();
        }
    
        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            mGLObject.onSurfaceChanged(gl, width, height);
        }
    
        @Override
        public void onDrawFrame(GL10 gl) {
            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT|GLES20.GL_DEPTH_BUFFER_BIT);
            mGLObject.onDrawFrame(gl);
        }
    }
    
    

    3.Triangle
    绘制一个三角形的核心代码

    1. 转换数据结构,因为 Java 使用的是大端字节序,而 OpenGL 使用的是小端字节序,需要通过 ByteBuffer转换
    1. 创建一个顶点着色器
    1. 创建一个片元着色器
    1. 将顶点着色器和片元着色器交给 OpenGL 生成可执行的程序。
    1. 绘制一个图形时,首先需要使用 OpenGL 的程序
    1. 获取顶点着色器某个字段的句柄,将我们的Java数据赋值给这个句柄。
    1. OpenGL 有相机和投影的概念,这里可以见参考文章。绘制的图像时需要调整相机的视角
    /**
     * 使用 OpenGL 绘制的图形
     * 原理 http://www.twinklingstar.cn/2015/1532/introduce-to-opengl/
     * https://blog.csdn.net/qq_32175491/article/details/79091647
     * https://blog.csdn.net/ylbs110/article/details/52074826
     * Matrix https://blog.csdn.net/kkae8643150/article/details/52805738
     * 顶点着色器:把一个单独的顶点作为输入。顶点着色器的目的是把3D点转换成另一种3D点
     * 片段着色器: 计算一个像素最终的颜色
     */
    public class Triangle {
        int mProgram;
        // 绘制的数据  3d 坐标点
        static float triangleCoords[] = {
                0.5f, 0.5f, 0.0f,
                -0.5f, -0.5f, 0.0f,
                0.5f, -0.5f, 0.0f,
        };
        private FloatBuffer vertexBuffer;
        // 定点着色器的 gl 语言代码  我们输入的数据会替代这个 vPosition
        // 顶点着色器是运行在 GPU 上的小代码
        // 这里乘以一个矩阵得到一个等腰三角形
        // https://www.jianshu.com/p/1c23ce604e4e vec4 包含4个浮点数的矢量  mat 代表 Matrix
        // attribute 该值传递给顶点着色器
        // uniform
        private final String vertextShaderCode = "attribute vec4 vPosition;" +
                "uniform mat4 vMatrix;\n" +
                "void main(){" +
                "gl_Position=vMatrix*vPosition;" +
                "}";
        // 片元着色器的代码
        private final String fragmentShaderCode = "precision mediump float;\n" +
                "uniform  vec4 vColor;\n" +
                "void main(){\n" +
                "gl_FragColor=vColor;\t\n" +
                "}";
        private float[] mViewMatrix = new float[16];
        private float[] mProjectMatrix = new float[16];
        private float[] mMVPMatrix = new float[16];
        // RGB Alpha
        float color[] = {1.0f, 1.0f, 1.0f, 1.0f};
    
        public void onSurfaceChanged(GL10 gl, int width, int height) {
    
            //        固定的写法
            //        //计算宽高比
            float ratio = (float) width / height;
            //   在哪个地方 最后将 mProjectMatrix 矩阵的值赋值给 mMVPMatrix
            Matrix.frustumM(mProjectMatrix, 0, -ratio, ratio, -1, 1, 3, 120);
            // 设置观察视角
            Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 7,//摄像机的坐标
                    0f, 0f, 0f,//目标物的中心坐标
                    0f, 1f, 0f);//相机方向
            //计算变换矩阵
            Matrix.multiplyMM(mMVPMatrix, 0, mProjectMatrix, 0, mViewMatrix, 0);
        }
    
        /**
         * 注意这里着色器的代码执行是很费时的,所以让它只执行一次。
         */
        public Triangle() {
            // 转换数据结构 因为 Java 端使用的是大端字节序,而 OpenGL 使用的小端字节序,所以需要通过 ByteBuffer 去转换。
            // 公式就是 传入数据的长度*数据的字节数
            // float 是 4 个字节
            ByteBuffer byteBuffer = ByteBuffer.allocateDirect(triangleCoords.length * 4);
            // 数据分配的顺序
            byteBuffer.order(ByteOrder.nativeOrder());
            vertexBuffer = byteBuffer.asFloatBuffer();
            // 把数据交给这个native buffer
            vertexBuffer.put(triangleCoords);
            // 设置这块 Buffer 的位置
            vertexBuffer.position(0);
            // 创建定点着色器
            int shader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
            // 设置定点着色器的代码
            GLES20.glShaderSource(shader, vertextShaderCode);
            // 编译定点着色器
            GLES20.glCompileShader(shader);
            /**
             * 创建片元着色器
             */
            int fragmentShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
            GLES20.glShaderSource(fragmentShader, fragmentShaderCode);
            GLES20.glCompileShader(fragmentShader);
    
            /**
             * 将片元着色器和顶点着色器放到统一的OpenGL程序去管理
             */
            mProgram = GLES20.glCreateProgram();
            // 将顶点着色器和片元着色器交给 OpenGL 的程序
            GLES20.glAttachShader(mProgram, shader);
            GLES20.glAttachShader(mProgram, fragmentShader);
            // 创建 OpenGL ES 的可执行程序
            GLES20.glLinkProgram(mProgram);
        }
    
        public void onDrawFrame(GL10 gl) {
            // 将程序添加到 OpenGL ES 的环境中
            GLES20.glUseProgram(mProgram);
            // 获取顶点着色器的位置的句柄
            int matrixHandler = GLES20.glGetUniformLocation(mProgram, "vMatrix");
            // 将 mMVPatrix 传递个 GPU 替代 vMatrix
            GLES20.glUniformMatrix4fv(matrixHandler, 1, false, mMVPMatrix, 0);
    
            int mPositionsHandler = GLES20.glGetAttribLocation(mProgram, "vPosition");
            /**
             * 必须调用这句话 数据才能被 GPU 访问
             * 因为数据虽然传递到了 GPU 但是GPU仍然不能看到,这里是可以让 GPU 正常访问这块数据
             */
            GLES20.glEnableVertexAttribArray(mPositionsHandler);
            // 3*4 --- 3 表示一个顶点的3个坐标 4代表字节 传递数据
            GLES20.glVertexAttribPointer(mPositionsHandler, 3, GLES20.GL_FLOAT, false, 3 * 4, vertexBuffer);
            // uniform location 代表声明为 uniform 的某个变量
            int mColorHandler = GLES20.glGetUniformLocation(mProgram, "vColor");
            // 将color数据传递给 GPU 替换 vColor字段 指定的是GPU渲染的形状的颜色
            GLES20.glUniform4fv(mColorHandler, 1, color, 0);
            // 真正的渲染,绘制一个三角形,
            GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
            // 解绑数据,让GPU可以去处理其他工作
            GLES20.glDisableVertexAttribArray(mPositionsHandler);
    
        }
    }
    
    

    相关文章

      网友评论

          本文标题:一、OpenGL在Android中的使用

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