Search code examples
androidopengl-esglslfragment-shadervertex-shader

Apply alpha mask to video in OpenGL


I want to apply an alpha mask to a video. Each frame of the video has color information on top and alpha information at the bottom. Like this:

enter image description here

In my case, i want the white pixels in the alpha image to be transparent in the main image. I have an other texture that fills in those transparent pixels.

I was able to generate the only color images or only alpha images, but not able to apply the alpha on to the image. I am using GLES20 in android.

Here is my code which is giving a black screen:

private val vidVertexShaderCode =
        """
    precision highp float;
    attribute vec3 vertexPosition;
    attribute vec4 uvs;
    varying vec2 varUvs;
    varying vec2 varMaskUvs;
    uniform mat4 texMatrix;
    uniform mat4 mvp;

    void main()
    {
        varUvs = (texMatrix * vec4(uvs.x, uvs.y, 0, 1.0)).xy;
        varMaskUvs = (texMatrix * vec4(uvs.x, uvs.y * 0.5, 0.1, 1.0)).xy;
        gl_Position = mvp * vec4(vertexPosition, 1.0);
    }
    """

private val vidFragmentShaderCode =
        """
    #extension GL_OES_EGL_image_external : require
    precision mediump float;

    varying vec2 varUvs;
    varying vec2 varMaskUvs;
    uniform samplerExternalOES texSampler;

    void main()
    {
        vec2 m_uv  = vec2(varMaskUvs.x, varMaskUvs.y); 
        vec4 mask = texture2D(texSampler, m_uv);  

        vec2 c_uv  = vec2(varUvs.x, varUvs.y * 0.5); 
        vec4 color = texture2D(texSampler, c_uv);  
        gl_FragColor = vec4(color.rgb, color.a * mask.r)
    }
    """

What am i doing wrong?

P.S. I am new to opengl.


Solution

  • Compute the v coordinate of the image (uvs.y * 0.5 + 0.5) and the mask (uvs.y * 0.5) in the vertex shader:

    precision highp float;
    attribute vec3 vertexPosition;
    attribute vec4 uvs;
    varying vec2 varUvs;
    varying vec2 varMaskUvs;
    uniform mat4 texMatrix;
    uniform mat4 mvp;
    
    void main()
    {
        varUvs      = (texMatrix * vec4(uvs.x, uvs.y * 0.5 + 0.5, 0, 1.0)).xy;
        varMaskUvs  = (texMatrix * vec4(uvs.x, uvs.y * 0.5, 0.0, 1.0)).xy;
        gl_Position = mvp * vec4(vertexPosition, 1.0);
    }
    

    You don't need any further transformation in the fragment shader:

    #extension GL_OES_EGL_image_external : require
    precision mediump float;
    
    varying vec2 varUvs;
    varying vec2 varMaskUvs;
    uniform samplerExternalOES texSampler;
    
    void main()
    {
        vec4 mask    = texture2D(texSampler, varMaskUvs);  
        vec4 color   = texture2D(texSampler, varUvs);  
        gl_FragColor = vec4(color.rgb, color.a * mask.r)
    }