美文网首页
视频录制——2.加上实时美颜

视频录制——2.加上实时美颜

作者: 猫侠 | 来源:发表于2017-09-28 13:31 被阅读0次

    要加上实时美颜,就要编写texture -> 帧缓冲区的过程。

    texture -> 帧缓冲区的过程是用OpenGL绘图。
    OpenGL是一台管理渲染管线的状态机。
    渲染管线有一个出口,一个入口。
    入口可以指向一个texture,出口可以指向帧缓冲区或一个FBO。
    帧缓冲区是显存中特殊的一块,储存经渲染管线加工后得到的二维像素数据,它对应的FBO索引为0。

    几个步骤:

    1. 输出 -> cameraFrameBuffer,覆盖为(0,0,0,0)
      输入 -> 摄像头纹理
      用cameraProgram绘制 -> 顶点经过Matrix调整,cameraTexture为摄像头纹理
    2. 输出 -> gaussFrameBuffer,覆盖为(0,0,0,0)
      输入 -> cameraTexture
      用gaussProgram绘制 -> 顶点位置不变、gaussTexture为磨皮后的摄像头纹理
    3. 输出 -> 帧缓冲区 ,覆盖为(0,0,0,0)
      输入 -> cameraTexture、gaussTexture、smoothTexture
      用smoothProgram绘制 -> 帧缓冲区为美白后的二维像素数据

    *每次glDrawArrays前,都要先把输出的FBO覆盖为(0,0,0,0)。
    *如果一个texture绑定到一个FBO,那么对FBO的写入操作会影响texture。这被用来进行render to texture。

    常用的GL接口:

    // 创建n个纹理,索引用textures装载返回
    public static native void glGenTextures(int n, java.nio.IntBuffer textures);
    
    // 创建n个FBO,索引用framebuffers装载返回
    public static native void glGenFramebuffers(int n, java.nio.IntBuffer framebuffers);
    
    // 把入口指向索引为texture的texture,texture的类型为target;特别地,当texture= 0时不使用纹理
    public static native void glBindTexture(int target, int texture);
    
    // 把出口指向索引为framebuffer的FBO,FBO的类型为target;特别地,当framebuffer = 0时指向帧缓冲区
    public static native void glBindFramebuffer(int target, int framebuffer);
    
    // 用bitmap填充texture
    // target:texture的类型
    // level:质量等级
    // internalformat:图像格式
    // type:数据格式
    // border:边框宽度
    public static void texImage2D(int target, int level, int internalformat, Bitmap bitmap, int type, int border)
    
    // 把texture绑定到FBO
    // target:texture的类型
    // attachment:FBO的接入点
    // textarget:texture的索引
    // level:质量等级
    public static native void glFramebufferTexture2D(int target, int attachment, int textarget, int texture, int level);
    
    // 设置用来覆盖出口指向的FBO或帧缓冲区的RGBA值(还没有覆盖)
    public static native void glClearColor(float red, float green, float blue, float alpha);
    
    // 用上一个接口设置的RGBA值来覆盖出口指向的FBO或帧缓冲区(覆盖了);
    // mask指明覆盖哪一层,如GLES20.GL_COLOR_BUFFER_BIT覆盖颜色层
    public static native void glClear(int mask);
    
    // 设置视口位置及尺寸
    public static native void glViewport(int x, int y, int width, int height);
    
    // 开始绘制
    // mode:以怎样的行为绘制
    // first:起始处偏移量
    // count:顶点数量
    public static native void glDrawArrays(int mode, int first, int count);
    

    *注意:所有“创建”的行为只是在OpenGL的命名空间中创建了一个名字(索引),只有在绑定后才真正为texture或FBO分配空间

    关于GLSL

    磨皮和美白的算法要用GLSL写Shader程序,记录一下常用的GLSL和载入方法

    // attribute修饰符表示由APP传来的顶点数据,只用于vertex
    attribute vec2 position;
    attribute vec2 inputTextureCoordinate;
    
    // uniform修饰符表示由APP传来的常量,可用于vertex和fragment
    uniform float texelWidthOffset;
    uniform float texelHeightOffset;
    
    // varying修饰符表示由vertex初始化,供fragment使用的值
    varying vec2 blurCoordinates[3];
    
    void main() {
        // gl_Position是内建变量,表示顶点的输出位置
        gl_Position = vec4(position.xy,0,1);
        vec2 singleStepOffset = vec2(texelWidthOffset, texelHeightOffset);
        blurCoordinates[0] = inputTextureCoordinate.xy;
        blurCoordinates[1] = inputTextureCoordinate.xy + singleStepOffset * optimizedGaussianOffsets[0];
        blurCoordinates[2] = inputTextureCoordinate.xy - singleStepOffset * optimizedGaussianOffsets[1];
    }
    
    String s = (上面那一段代码);
    // 创建一个Shader,返回它的索引
    int shader = GLES20.glCreateShader(GL_VERTEX_SHADER);
    // 把源码绑定到这个Shader
    GLES20.glShaderSource(shader, s);
    // 编译源码
    GLES20.glCompileShader(shader);
    // 查看是否编译成功
    // compiled装载是否成功,GL_TRUE或GL_FALSE
    GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
    // 如果编译失败,删除Shader
    if(compiled[0] == GL_FALSE) {
        GLES20.glDeleteShader(shader);
        shader = 0;
    }elase {  // 如果编译成功
        // 创建一个Program
        int program= GLES20.glCreateProgram();
        // 把shader加入Program
        GLES20.glAttachShader(program, shader);
        // 释放shader资源
        GLES20.glDeleteShader(vertexShader );
        // 链接程序
        GLES20.glLinkProgram(program);
        // 获取program的链接情况
        GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
        // 若链接失败则删除program
        if (linkStatus[0] == GL_FALSE) {
            GLES20.glDeleteProgram(program);
            program = 0;
        } else {    // 如果链接成功
            // 使用program
            GLES20.glUseProgram(program);
            // 获取变量名的id,location是shader程序中声明为attribute的变量名
            int id = GLES20.glGetAttribLocation(program, location);
            // 允许shader从VBO读取这个变量的值
            GLES20.glEnableVertexAttribArray(id);
            // 设置索引为0的VBO为传输媒介,即APP向这个VBO写入数据,shader从这个VBO读取数据
            GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
            // 设置向VBO写入的数据,注意只有在调用glDrawArrays时才真正写入
            // size:变量的属性的数量,比如vec2类型的变量num = 2,vec3类型的变量num = 3
            // type:变量的属性的类型
            // normalized:如果写入的不是type类型的数据,是否要归一化
            // stride:每个数据的间隔
            // arrayBuffer:写入的数据
            GLES20.glVertexAttribPointer(id, size, type, normalized, stride, arrayBuffer);
        }
    }
    

    相关文章

      网友评论

          本文标题:视频录制——2.加上实时美颜

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