Filtro base de cámara Android OpenGL ES 3.0

1. Efectos de filtro de rejilla dinámica

1.1 Sombreador de vértices
#version 300 es
layout(location = 0) in vec3 attr_position;
layout(location = 1) in vec2 attr_uv;

uniform mat4   uni_mat;
out vec2   v_texcoord;

void main(void)
{
    v_texcoord = attr_uv;
    gl_Position = uni_mat* vec4(attr_position,1.0);
}

La matriz MVP entrante y las coordenadas del material.

1.2 Sombreadores de fragmentos
#version 300 es
precision mediump float;
//precision highp float;

uniform sampler2D uni_textureY;
uniform sampler2D uni_textureU;
uniform sampler2D uni_textureV;

in vec2 v_texcoord;
out vec4 fragColor;

uniform float u_offset;//偏移量
uniform vec2 texSize;//纹理尺寸

vec4 YuvToRgb(vec2 uv){
    vec3 yuv;
    vec3 rgb;
    yuv.x = texture(uni_textureY, uv).r;
    yuv.y = texture(uni_textureU, uv).r - 0.5;
    yuv.z = texture(uni_textureV, uv).r - 0.5;
    rgb = mat3( 1,1,1, 0,-0.39465,2.03211,1.13983,-0.58060,0) * yuv;
    return vec4(rgb, 1);
}


void main(void)
{
    vec2 imgTexCoord = v_texcoord * texSize;//将纹理坐标系转换为图片坐标系
    float sideLength = texSize.y / 6.0;//网格的边长
    float maxOffset = 0.15 * sideLength;//设置网格线宽度的最大值
    float x = mod(imgTexCoord.x, floor(sideLength));
    float y = mod(imgTexCoord.y, floor(sideLength));

    float offset = u_offset * maxOffset;

    if(offset <= x
    && x <= sideLength - offset
    && offset <= y
    && y <= sideLength - offset)
    {
        fragColor = YuvToRgb(v_texcoord);
    }
    else
    {
        fragColor = vec4(1.0, 1.0, 1.0, 1.0);
    }
}

YuvToRgb: Esto se usa para convertir datos yuv en rgb para renderizar en la pantalla

La cuadrícula dinámica divide principalmente la textura en múltiples cuadrículas y luego cambia dinámicamente el ancho de la cuadrícula de acuerdo con un desplazamiento.

mod: devuelve x – y * piso (x / y), es decir, % de cálculo de módulo

piso: devuelve el valor entero más grande menor o igual a x

Antes del cálculo, es necesario convertir el sistema de coordenadas de la textura al sistema de coordenadas de la imagen para garantizar que la cuadrícula no se estire.

2. Efectos de pantalla dividida

2.1 Sombreador de vértices
#version 300 es
layout(location = 0) in vec3 attr_position;
layout(location = 1) in vec2 attr_uv;

uniform mat4   uni_mat;
out vec2   v_texcoord;

void main(void)
{
    v_texcoord = attr_uv;
    gl_Position = uni_mat* vec4(attr_position,1.0);
}

Esta pieza es principalmente datos y materiales de vértices, por lo que es igual a la anterior.

2.2 Sombreadores de fragmentos
#version 300 es
precision mediump float;
//precision highp float;

uniform sampler2D uni_textureY;
uniform sampler2D uni_textureU;
uniform sampler2D uni_textureV;

in vec2 v_texcoord;
out vec4 fragColor;

vec4 YuvToRgb(vec2 uv){
    vec3 yuv;
    vec3 rgb;
    yuv.x = texture(uni_textureY, uv).r;
    yuv.y = texture(uni_textureU, uv).r - 0.5;
    yuv.z = texture(uni_textureV, uv).r - 0.5;
    rgb = mat3( 1,1,1, 0,-0.39465,2.03211,1.13983,-0.58060,0) * yuv;
    return vec4(rgb, 1);
}


void main(void)
{

    /*四分屏  效果正常*/
    vec2 newTexCoord = v_texcoord;
    if(newTexCoord.x < 0.5)
    {
        newTexCoord.x = newTexCoord.x * 2.0;
    }
    else
    {
        newTexCoord.x = (newTexCoord.x - 0.5) * 2.0;
    }

    if(newTexCoord.y < 0.5)
    {
        newTexCoord.y = newTexCoord.y * 2.0;
    }
    else
    {
        newTexCoord.y = (newTexCoord.y - 0.5) * 2.0;
    }

    fragColor = YuvToRgb(newTexCoord);
}

El principio del filtro de pantalla dividida es reducir (reducir) la textura completa en múltiples áreas específicas, de modo que la imagen completa se pueda mostrar varias veces en múltiples áreas.

3. Efecto círculo escalado

3.1 Sombreador de vértices
#version 300 es
layout(location = 0) in vec3 attr_position;
layout(location = 1) in vec2 attr_uv;

uniform mat4   uni_mat;
out vec2   v_texcoord;

void main(void)
{
    v_texcoord = attr_uv;
    gl_Position = uni_mat* vec4(attr_position,1.0);
}

Esta pieza es principalmente datos y materiales de vértices, por lo que es igual a la anterior.

3.2 Sombreadores de fragmentos
#version 300 es
precision mediump float;
//precision highp float;

uniform sampler2D uni_textureY;
uniform sampler2D uni_textureU;
uniform sampler2D uni_textureV;

in vec2 v_texcoord;
out vec4 fragColor;

uniform float u_offset;//偏移量
uniform vec2 texSize;//纹理尺寸

vec4 YuvToRgb(vec2 uv){
    vec3 yuv;
    vec3 rgb;
    yuv.x = texture(uni_textureY, uv).r;
    yuv.y = texture(uni_textureU, uv).r - 0.5;
    yuv.z = texture(uni_textureV, uv).r - 0.5;
    rgb = mat3( 1,1,1, 0,-0.39465,2.03211,1.13983,-0.58060,0) * yuv;
    return vec4(rgb, 1);
}



void main(void)
{
    vec2 imgTex = v_texcoord * texSize;//将纹理坐标系转换为图片坐标系
    float r = (u_offset + 0.2 ) * texSize.x;   //0.2 表示圆圈的默认大小
    if(distance(imgTex, vec2(texSize.x / 2.0, texSize.y / 2.0)) < r)
    {
        fragColor = YuvToRgb(v_texcoord);
    }
    else
    {
        fragColor = vec4(1.0, 1.0, 1.0, 1.0);
    }

}

4. Parte del programa de renderizado

void MSDynamicGridLine::UpdateYUVData(MSYUVData_Frame *yuvFrame) {
    if(yuvFrame == nullptr ){
        return;
    }

    if(m_nVideoH != yuvFrame->height || m_nVideoW != yuvFrame->width){

        if(nullptr != m_pBufYuv420p)
        {
            free(m_pBufYuv420p);
            m_pBufYuv420p=nullptr;
        }
    }


    m_nVideoW =  yuvFrame->width;
    m_nVideoH = yuvFrame->height;

    m_yFrameLength = yuvFrame->luma.length;
    m_uFrameLength = yuvFrame->chromaB.length;
    m_vFrameLength = yuvFrame->chromaR.length;


    //申请内存存一帧yuv图像数据,其大小为分辨率的1.5倍
    int nLen = m_yFrameLength + m_uFrameLength +m_vFrameLength;

    if(nullptr == m_pBufYuv420p)
    {
        m_pBufYuv420p = ( unsigned char*) malloc(nLen);
    }

    memcpy(m_pBufYuv420p,yuvFrame->luma.dataBuffer,m_yFrameLength);
    memcpy(m_pBufYuv420p+m_yFrameLength,yuvFrame->chromaB.dataBuffer,m_uFrameLength);
    memcpy(m_pBufYuv420p+m_yFrameLength +m_uFrameLength,yuvFrame->chromaR.dataBuffer,m_vFrameLength);

    m_bUpdateData =true;
}

Este método se usa para actualizar los datos YUV. Dado que los datos provienen de la cámara y no son un hilo con opengl, deben copiarse a través del uso compartido de la memoria.

void MSDynamicGridLine::Render(MSGLCamera *pCamera) {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    if(m_bUpdateData == false){
        return;
    }

    static MSVertex triangleVert[] = {
            {-1, 1,  1,     0,0},
            {-1, -1,  1,    0,1},
            {1,  1,  1,     1,0},
            {1,  -1,  1,    1,1},
    };


    glm::mat4x4  objectMat = glm::mat4x4(1.0);
    glm::mat4x4  objectTransMat = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -5));
    objectMat = objectMat * objectTransMat;

    objectMat = pCamera->projectionMatrix * pCamera->viewMatrix * objectMat ;


    m_pOpenGLShader->Bind();

    m_pOpenGLShader->SetUniformValue("uni_mat",objectMat);


    m_pOpenGLShader->EnableAttributeArray("attr_position");
    m_pOpenGLShader->SetAttributeBuffer("attr_position",GL_FLOAT,triangleVert,3,sizeof(MSVertex));

    m_pOpenGLShader->EnableAttributeArray("attr_uv");
    m_pOpenGLShader->SetAttributeBuffer("attr_uv",GL_FLOAT,&triangleVert[0].u,2,sizeof(MSVertex));

    m_PeriodicFrameIndex++;
    float progress = GetFrameProgress();
    m_pOpenGLShader->SetUniformValue("u_offset",0.2f * progress);

    LOGD("m_nVideoW is %d,progress is %f",m_nVideoW,progress);

    if (m_nVideoW>0){
        m_pOpenGLShader->SetUniformValue("texSize",glm::vec2(m_nVideoW,m_nVideoH));
    }else{
        m_pOpenGLShader->SetUniformValue("texSize",glm::vec2(720,1280));
    }


    m_pOpenGLShader->SetUniformValue("uni_textureY",0);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, m_textures[0]);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_nVideoW, m_nVideoH, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_pBufYuv420p);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    m_pOpenGLShader->SetUniformValue("uni_textureU",1);
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, m_textures[1]);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,m_nVideoW/2, m_nVideoH/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, (char*)(m_pBufYuv420p+m_yFrameLength));
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    m_pOpenGLShader->SetUniformValue("uni_textureV",2);
    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, m_textures[2]);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_nVideoW/2, m_nVideoH/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, (char*)(m_pBufYuv420p+m_yFrameLength+m_uFrameLength));
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    glBindTexture(GL_TEXTURE_2D, 0);
    m_pOpenGLShader->DisableAttributeArray("attr_position");
    m_pOpenGLShader->DisableAttributeArray("attr_uv");

    m_pOpenGLShader->Release();

    return;
}
  • Pasar parámetros al sombreador: matriz mvp, vértice, desplazamiento, etc.
  • Genere tres texturas para transportar los datos de los tres componentes de yuv
  • Luego dibuja glDrawArrays

Supongo que te gusta

Origin blog.csdn.net/u014078003/article/details/127992769
Recomendado
Clasificación