Android通过openGL实现视频贴纸功能
16lz
2021-12-04
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); }}
效果如下图所示:
总结
贴纸的原理本质就是在绘制的时候判断当前位置是应该绘制视频还是应该绘制贴纸。
更多相关文章
- Android(安卓)中OpenGL的使用
- Android(安卓)API开发之OpenGL开发之Android(安卓)OpenGL之使用G
- Android(安卓)音视频开发(五) : OpenGL ES API,了解 OpenGL 开发
- [置顶] 一步一步学android OpenGL ES2.0编程(2)
- Android(安卓)OpenGL例子学习
- OpenGL ES for Android(安卓)绘制线
- openGL 简单demo
- PHP算法练习八:判断给定的三个数是否能构成直角三角形
- 关键路径(C语言)