一、OpenGL在Android中的使用

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);

    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,172评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,346评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,788评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,299评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,409评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,467评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,476评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,262评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,699评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,994评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,167评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,827评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,499评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,149评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,387评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,028评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,055评论 2 352