Android通过openGL实现视频贴纸功能

Android通过openGL实现视频贴纸功能

GLSL代码

1.vertex代码,文件vertex_filter_stricker.glsl

attribute vec2 inputTextureCoordinate; //纹理坐标
attribute vec4 position;// 顶点坐标
varying   vec2 textureCoordinate;//纹理坐标点变换后输出

void main() {
    gl_Position = position;
    textureCoordinate = inputTextureCoordinate;
}

2.fragment代码,文件fragment_filter_stricker.glsl

//设置精度
precision highp float;
varying highp vec2 textureCoordinate;
uniform sampler2D videoTexture;
uniform sampler2D uImageTexture;
uniform vec4 imageRect;

void main(){
    lowp vec4 c1 = texture2D(videoTexture, textureCoordinate);
    lowp vec2 vCamTextureCoord2 = vec2(textureCoordinate.x, 1.0-textureCoordinate.y);
    if (vCamTextureCoord2.x>imageRect.r && vCamTextureCoord2.x<imageRect.b && vCamTextureCoord2.y>imageRect.g && vCamTextureCoord2.y<imageRect.a)
    {
        vec2 imagexy = vec2((vCamTextureCoord2.x-imageRect.r)/(imageRect.b-imageRect.r), (vCamTextureCoord2.y-imageRect.g)/(imageRect.a-imageRect.g));
        lowp vec4 c2 = texture2D(uImageTexture, imagexy);
        lowp vec4 outputColor = c2+c1*c1.a*(1.0-c2.a);
        outputColor.a = 1.0;
        gl_FragColor = outputColor;
    } else {
        gl_FragColor = c1;
    }
}

Java代码

package com.dong.opencamera.core.filter.impl;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.RectF;
import android.opengl.GLES20;

import com.dong.opencamera.core.filter.IVideoFilter;
import com.dong.opencamera.utils.GLHelper;

import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

/**
 * @author : liaojidong
 * @date : 2020-01-13 15:00
 * @desc :
 */
public class StickerFilter implements IVideoFilter {
    // number of coordinates per vertex in this array
    private static final int COORDS_PER_VERTEX = 3;
    private static final short[] ORDERS = {
            0, 1, 2, // 左下角三角形
            2, 3, 0  // 右上角三角形
    };

    private Context mContext;
    private volatile boolean isInit = false;
    private Bitmap mStickerBitmap;
    private int mProgram;
    private int glImageTextureLoc;
    private int glImageRectLoc;
    private int videoTextureLoc;
    private int uPosLocation;
    private int aTexLocation;

    protected int imageTexture;
    private RectF imageRectF = new RectF();

    private int width;
    private int height;

    public StickerFilter(Context context,
                         Bitmap stickerBitmap) {
        this.mStickerBitmap = stickerBitmap;
        this.mContext = context;
    }

    @Override
    public void onFilterChanged(int surfaceWidth, int surfaceHeight) {
        this.width = surfaceWidth;
        this.height = surfaceHeight;
    }

    private void init() {
        if (isInit) return;

        mProgram = GLHelper.createProgram(mContext,
                "vertex_filter_stricker.glsl",
                "fragment_filter_stricker.glsl");
        // 将程序添加到OpenGL ES环境
        GLES20.glUseProgram(mProgram);

        // 获取顶点着色器的位置的句柄
        uPosLocation = GLES20.glGetAttribLocation(mProgram, "position");
        aTexLocation = GLES20.glGetAttribLocation(mProgram, "inputTextureCoordinate");

        videoTextureLoc = GLES20.glGetUniformLocation(mProgram, "videoTexture");
        glImageRectLoc = GLES20.glGetUniformLocation(mProgram, "imageRect");
        glImageTextureLoc = GLES20.glGetUniformLocation(mProgram, "uImageTexture");

        imageTexture = GLHelper.loadTexture(mContext, mStickerBitmap);


        isInit = true;
    }

    public void setStickerLoc(int x, int y) {
        imageRectF.left = (float) ((x * 1.0) / (width * 1.0));
        imageRectF.right = (float) (imageRectF.left + ((mStickerBitmap.getWidth() * 1.0) / (width * 1.0)));
        imageRectF.top = (float) ((y * 1.0) / (height * 1.0));
        imageRectF.bottom = (float) (imageRectF.top + ((mStickerBitmap.getHeight() * 1.0) / (height * 1.0)));
    }

    @Override
    public void onDraw(int inputTexture,
                       int targetFrameBuffer,
                       FloatBuffer vertexPosBuffer,
                       FloatBuffer texturePosBuffer,
                       ShortBuffer order) {
        init();
        setStickerLoc(100, 100);
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, targetFrameBuffer);
        GLES20.glUseProgram(mProgram);

        // Set the active texture unit to texture unit 0.
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        // Bind the texture to this unit 0.
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTexture);
        // Tell the texture uniform sampler to use this texture in the shader by
        // telling it to read from texture unit 0.
        GLES20.glUniform1i(videoTextureLoc, 0);

        // Set the active texture unit to texture unit 1.
        GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
        // Bind the texture to this unit 1.
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, imageTexture);
        // Tell the texture uniform sampler to use this texture in the shader by
        // telling it to read from texture unit 1.
        GLES20.glUniform1i(glImageTextureLoc, 1);

        // 将数据传递到着色器中
        GLES20.glVertexAttribPointer(uPosLocation, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, vertexPosBuffer);
        GLES20.glVertexAttribPointer(aTexLocation, 2, GLES20.GL_FLOAT, false, 0, texturePosBuffer);

        GLES20.glUniform4f(glImageRectLoc, imageRectF.left, imageRectF.top, imageRectF.right, imageRectF.bottom);

        // 启用顶点位置的句柄
        GLES20.glEnableVertexAttribArray(uPosLocation);
        GLES20.glEnableVertexAttribArray(aTexLocation);

        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
        GLES20.glDrawElements(GLES20.GL_TRIANGLES, ORDERS.length, GLES20.GL_UNSIGNED_SHORT, order);

        GLES20.glFinish();
        GLES20.glDisableVertexAttribArray(uPosLocation);
        GLES20.glDisableVertexAttribArray(aTexLocation);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
        GLES20.glUseProgram(0);
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
    }
}

效果如下图所示:

总结

贴纸的原理本质就是在绘制的时候判断当前位置是应该绘制视频还是应该绘制贴纸。

你可能感兴趣的:(OpenGL,Android)