12.OpenGL ES

OpenGL ES

android中 GLSurfaceView 继承 SurfaceView

GLSurfaceView 中有 GLThread

setEGLContextClientVersion(2);//使用openGLES 2.0上下文
setRenderer(...);//设置渲染回调接口 该方法中实例化GLThread
 /**
 * 刷新方式:
 *     RENDERMODE_WHEN_DIRTY 手动刷新,調用requestRender();
 *     RENDERMODE_CONTINUOUSLY 自動刷新,大概16ms自動回調一次onDraw方法
 */
//注意必须在setRenderer 后面。
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

openGL 渲染管线 顶点->图元装配->光栅化(像素化)

            着色器(顶点着色器和片元着色器)

Android Studio 集成GLSLSupport插件 编辑OpenGL着色器语言(GLSL)时关键字高亮智能提示

openGL着色语言

attribute 属性变量(只在顶点着色器使用)
uniforms 一致变量(片元着色器使用)
varying 易编变量(顶点着色器输出数据到片元着色器)
gl_Position 坐标(x,y,z,w)
samplerExternalOES  图片采样器
samplerExternalOES 相当于rgba 使用texture2D(...)
precision / mediump / float  精度定义

openGL的世界坐标和纹理坐标

static final float COORD[] = {
            -1.0f, -1.0f,
            1.0f, -1.0f,
            -1.0f, 1.0f,
            1.0f, 1.0f,
    };

    static final float TEXTURE_COORD[] = {
            0.0f, 1.0f,
            1.0f, 1.0f,
            0.0f, 0.0f,
            1.0f, 0.0f,
    };
图片.png
  1. onSurfaceCreated

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        //创建OpenGL 纹理 ,把摄像头的数据与这个纹理关联
        textures = new int[1];  //当做能在opengl用的一个图片的ID
        mCameraTexure.attachToGLContext(textures[0]);
        // 当摄像头数据有更新回调 onFrameAvailable
        mCameraTexure.setOnFrameAvailableListener(this);//监听更新时手动调用requestRender()
        screenFilter = new ScreenFilter(cameraView.getContext());
    }
    

    创建和初始化着色器供, 这些过程一般分为7个步骤:

创建顶点着色器对象(glcreateShader);

 向顶点着色器对象中填充着色器程序的源代码(glshaderSource);

 编译顶点着色器(glcompileShander);

创建片元着色器对象(glcreateShader);

 向片元着色器对象中填充着色器程序的源代码(glshaderSource);

 编译片元着色器(glcompileShander);

创建程序对象(glcreateProgram);

 为程序对象分配着色器(glattachShader);

 连接程序对象(gllinkProgram);

 使用程序对象(gluseProgram)
//着色器程序准备
public static int loadProgram(String vSource, String fSource) {
    /**
     * 顶点着色器
     */
    int vShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
    //加载着色器代码
    GLES20.glShaderSource(vShader, vSource);
    //编译(配置)
    GLES20.glCompileShader(vShader);

    //查看配置 是否成功
    int[] status = new int[1];
    GLES20.glGetShaderiv(vShader, GLES20.GL_COMPILE_STATUS, status, 0);
    if (status[0] != GLES20.GL_TRUE) {
        //失败
        throw new IllegalStateException("load vertex shader:" + GLES20.glGetShaderInfoLog
                (vShader));
    }

    /**
     *  片元着色器
     *  流程和上面一样
     */
    int fShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
    //加载着色器代码
    GLES20.glShaderSource(fShader, fSource);
    //编译(配置)
    GLES20.glCompileShader(fShader);

    //查看配置 是否成功
    GLES20.glGetShaderiv(fShader, GLES20.GL_COMPILE_STATUS, status, 0);
    if (status[0] != GLES20.GL_TRUE) {
        //失败
        throw new IllegalStateException("load fragment shader:" + GLES20.glGetShaderInfoLog
                (vShader));
    }


    /**
     * 创建着色器程序
     */
    int program = GLES20.glCreateProgram();
    //绑定顶点和片元
    GLES20.glAttachShader(program, vShader);
    GLES20.glAttachShader(program, fShader);
    //链接着色器程序
    GLES20.glLinkProgram(program);


    //获得状态
    GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, status, 0);
    if (status[0] != GLES20.GL_TRUE) {
        throw new IllegalStateException("link program:" + GLES20.glGetProgramInfoLog(program));
    }
    GLES20.glDeleteShader(vShader);
    GLES20.glDeleteShader(fShader);
    return program;
}
  1. onSurfaceChanged设置宽高

  2. onDrawFrame

    @Override
    public void onDrawFrame(GL10 gl) {
        //todo 更新纹理
        mCameraTexure.updateTexImage();//拿到最新的图像数据
        mCameraTexure.getTransformMatrix(mtx);
        screenFilter.setTransformMatrix(mtx);
        screenFilter.onDraw(textures[0]);
    }
    
    public int onDraw(int texture, FilterChain filterChain) {
            FilterContext filterContext = filterChain.filterContext;
            //设置绘制区域
            GLES20.glViewport(0, 0, filterContext.width, filterContext.height);
    
    
            GLES20.glUseProgram(program);
    
            vertexBuffer.position(0);
            // 4、归一化 normalized  [-1,1] . 把[2,2]转换为[-1,1]
            GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 0, vertexBuffer);
            //CPU传数据到GPU,默认情况下着色器无法读取到这个数据。 需要我们启用一下才可以读取
            GLES20.glEnableVertexAttribArray(vPosition);
    
    
            textureBuffer.position(0);
            // 4、归一化 normalized  [-1,1] . 把[2,2]转换为[-1,1]
            GLES20.glVertexAttribPointer(vCoord, 2, GLES20.GL_FLOAT, false, 0, textureBuffer);
            //CPU传数据到GPU,默认情况下着色器无法读取到这个数据。 需要我们启用一下才可以读取
            GLES20.glEnableVertexAttribArray(vCoord);
    
    
            //相当于激活一个用来显示图片的画框
            GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
            // 0: 图层ID  GL_TEXTURE0
            // GL_TEXTURE1 , 1
            GLES20.glUniform1i(vTexture, 0);
    
            beforeDraw();
            //通知画画,
            GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
    
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
    
            return texture;
    }
    

    openGL ES离屏渲染 FBO(Frame Buffer Object)帧缓存对象

    public void createFrame(int width, int height) {
            releaseFrame();
            //創建FBO
            /**
             * 1、创建FBO + FBO中的纹理
             */
            frameBuffer = new int[1];
            frameTextures = new int[1];
            GLES20.glGenFramebuffers(1, frameBuffer, 0);
            OpenGLUtils.glGenTextures(frameTextures);
    
            /**
             * 2、fbo与纹理关联
             */
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameTextures[0]);
            GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE,
                    null);
            //纹理关联 fbo
            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffer[0]);  //綁定FBO
            GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D,
                    frameTextures[0],
                    0);
    
            /**
             * 3、解除绑定
             */
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
    
        }
    

EGL库 管理窗口 将Surface和EGLSurface绑定

图片.png

openGL是在GLThread子线程 同样需要搭建一个EGL环境在子线程

1.创建Display获取显示窗口

EGLDisplay mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
EGL14.eglinitialize(...);//初始化

2.配置属性选项

EGL.eglChooseConfig(...)

3.创建EGL上下文

EGL14.eglCreateWindowSurface(...)

5.绘制

//先绑定当前线程的显示屏diplay
EGL14.eglMakeCurrent(EGLDisplay, EGLSurface, EGLSurface, EGLContext);
//EGLSurface是双缓冲模式
EGLExt.eglPresentationTimeANDROID(EGLDisplay,EGLSurface,时间戳);
EGL14.eglSwapBuffers(EGLDisplay,EGLSurface);

实现功能一 、调整快慢帧

//只需要调整bufferInfo参数中的时间戳
Muxer.writeSampleData(track,encodeData,bufferInfo);
//改变时间的速率
bufferInfo.presentationTimeUs = bufferInfo.presentationTimeUs/speed;

实现功能二、识别脸部 使用Seetaface FaceLandmarker

图像局部缩放 
图片.png

实现功能三、图像遮罩物

openGL图像混合
GLES20.gleEnable(GLES20.GL_BLEND);
GLES20.GLBlendFunc(GLES20.GLONE,GLES20.GL_ONE_MINUS_SRC_ALPHA);
//GL_ONE采用源颜色的alpha值作为因子
//GL_ONE_MINUS_SRC_ALPHA表示用1.0减去源颜色的aplha作为因子
利用GLES20.glViewPort(x,y,width,heigh)或openGL中转换世界坐标系

GLUtils.textImage2D(...)将Bitmap图片绑定openGL中

实现功能四、美颜

1.模糊效果(水平方向和垂直方向)设计11*11算子

2.高反差保留 边缘化  高反差=原图-模糊图

3.保留边缘细节不被模糊掉

4.磨皮调整

实现功能五、闪烁 以中心点(0.5,0.5)向四周扩散

实现功能六、分配 以屏幕0.25~0.75绘制(大于0.5则减去0.25,否则加上0.25)

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

推荐阅读更多精彩内容