OpenGLES添加水印

版权声明:本文为卫伟学习总结文章,转载请注明出处!
原理:把文字变成图片,用多纹理渲染的方式来添加。其他图片水印直接是多纹理渲染即可。即添加水印=多个纹理绘制在同一个surface上。
理解了添加水印的原理,不管是视频水印还是图片水印都是很简单的了,只是使用的纹理不一样而已。如果是绘制文字水印的话,则需要将文字生成图片,然后将图片使用纹理绘制即可。
那么怎样将多个纹理添加到同一个surface上?
简单示例代码:

public class WlEncodecRender implements WLEGLSurfaceView.WlGLRender {

private Context context;
//顶点坐标
private float[] vertexData = { // in counterclockwise order:
        -1f, -1f, 0.0f, // bottom left
        1f, -1f, 0.0f,// bottom right
        -1f, 1f, 0.0f,// top left
        1f, 1f,0.0f,// top right

        0f, 0f, 0f, // 水印预留位置
        0f, 0f, 0f,
        0f, 0f, 0f,
        0f, 0f, 0f
};

// 纹理坐标 对应顶点坐标  与之映射
private float[] fragmentData = {
        0f, 1f, 0.0f, // bottom left
        1f, 1f, 0.0f, // bottom right
        0f, 0f, 0.0f, // top left
        1f, 0f, 0.0f, // top right
};

// 位置
private FloatBuffer vertexBuffer;
// 纹理
private FloatBuffer fragmentBuffer;

private int program;
private int vPosition;
// 纹理位置
private int fPosition;
// 纹理 默认第0个位置 可以不获取
private int textureid;

// vbo id
private int vboId;

private int fboTextureId;

private Bitmap bitmap;
private int waterTextureId;

private int bitmapTextureid;


public WlEncodecRender(Context context, int textureid) {
    this.context = context;
    this.textureid = textureid;

    initWater(); 

    vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)
            .order(ByteOrder.nativeOrder())
            .asFloatBuffer()
            .put(vertexData);
    vertexBuffer.position(0);

    fragmentBuffer = ByteBuffer.allocateDirect(fragmentData.length * 4)
            .order(ByteOrder.nativeOrder())
            .asFloatBuffer()
            .put(fragmentData);
    fragmentBuffer.position(0);

}

private void initWater() {
    bitmap = WlShaderUtil.createTextImage("我是水印",40,"#fff000","#00000000",0);

    // 设置位置 根据需求自己配置
    float r = 1.0f * bitmap.getWidth() / bitmap.getHeight();
    float w = r * 0.1f;
    vertexData[12] = 0.8f - w;
    vertexData[13] = -0.8f;
    vertexData[14] = 0;

    vertexData[15] = 0.8f;
    vertexData[16] = -0.8f;
    vertexData[17] = 0;

    vertexData[18] = 0.8f - w;
    vertexData[19] = -0.7f;
    vertexData[20] = 0;

    vertexData[21] = 0.8f;
    vertexData[22] = -0.7f;
    vertexData[23] = 0;
}

@Override
public void onSurfaceCreated() {
    // 启用透明
    GLES20.glEnable(GLES20.GL_BLEND);
    GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA,GLES20.GL_ONE_MINUS_SRC_ALPHA);
    String vertexSource = WlShaderUtil.getRawResource(context, R.raw.vertex_shader_screen);
    String fragmentSource = WlShaderUtil.getRawResource(context, R.raw.fragment_shader_screen);

    program = WlShaderUtil.createProgram(vertexSource, fragmentSource);

    vPosition = GLES20.glGetAttribLocation(program, "v_Position");
    fPosition = GLES20.glGetAttribLocation(program, "f_Position");

    // 创建vbo
    createVBO();

    //创建水印纹理
    bitmapTextureid =  createWaterTextureId();
}

/**
 * 创建vbo
 */
private void createVBO() {
    //1. 创建VBO
    int [] vbos = new int[1];
    GLES20.glGenBuffers(1, vbos, 0);
    vboId = vbos[0];
    //2. 绑定VBO
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboId);
    //3. 分配VBO需要的缓存大小
    GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertexData.length * 4 + fragmentData.length * 4, null, GLES20. GL_STATIC_DRAW);
    //4. 为VBO设置顶点数据的值
    GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, 0, vertexData.length * 4, vertexBuffer);
    GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, vertexData.length * 4, fragmentData.length * 4, fragmentBuffer);
    //5. 解绑VBO
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
}

/**
 * 创建水印纹理
 */
private int createWaterTextureId() {
    int[] textureIds = new int[1];
    // 创建纹理
    GLES20.glGenTextures(1,textureIds,0);
    waterTextureId = textureIds[0];
    // 绑定纹理
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, waterTextureId);
    //环绕(超出纹理坐标范围)  (s==x t==y GL_REPEAT 重复)
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
    //过滤(纹理像素映射到坐标点)  (缩小、放大:GL_LINEAR线性)
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);

    ByteBuffer bitmapBuffer = ByteBuffer.allocate(bitmap.getHeight() * bitmap.getWidth() * 4);//RGBA
    bitmap.copyPixelsToBuffer(bitmapBuffer);
    //将bitmapBuffer位置移动到初始位置
    bitmapBuffer.flip();

    //设置内存大小绑定内存地址
    GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, bitmap.getWidth(), bitmap.getHeight(),
            0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, bitmapBuffer);

    //解绑纹理
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,0);
    return textureIds[0];
}

@Override
public void onSurfaceChanged(int width, int height) {
    GLES20.glViewport(0, 0, width, height);
}

@Override
public void onDrawFrame() {
    // 清空颜色
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    // 设置北京颜色
    GLES20.glClearColor(1f,0f, 0f, 1f);

    //使用程序
    GLES20.glUseProgram(program);

    // 设置纹理
    // 绑定渲染纹理  默认是第0个位置
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureid);

    GLES20.glEnableVertexAttribArray(vPosition);
    GLES20.glEnableVertexAttribArray(fPosition);

    // 使用VBO设置纹理和顶点值
    useVboSetVertext();

    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);


    //bitmap
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,bitmapTextureid);

    GLES20.glEnableVertexAttribArray(vPosition);
    GLES20.glVertexAttribPointer(vPosition,2,GLES20.GL_FLOAT,false,12,
            48);
    GLES20.glEnableVertexAttribArray(fPosition);
    GLES20.glVertexAttribPointer(fPosition, 2, GLES20.GL_FLOAT, false, 12,
            vertexData.length * 4);

    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);

}

/**
 * 使用vbo设置顶点位置
 */
private void useVboSetVertext() {
    //1. 绑定VBO
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboId);
    //2. 设置顶点数据
    GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 8,
            0);
    GLES20.glVertexAttribPointer(fPosition, 2, GLES20.GL_FLOAT, false, 8,
            vertexData.length * 4);
    //3. 解绑VBO
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
}

ShaderUtil.java

/**
 * 根据文字创建图片
 */
public static Bitmap createTextImage(String text, int textSize, String textColor, String bgColor, int padding) {
    Paint paint = new Paint();
    paint.setColor(Color.parseColor(textColor));
    paint.setTextSize(textSize);
    paint.setStyle(Paint.Style.FILL);
    paint.setAntiAlias(true);

    float width = paint.measureText(text,0,text.length());

    float top = paint.getFontMetrics().top;
    float bottom = paint.getFontMetrics().bottom;

    Bitmap bm = Bitmap.createBitmap((int) (width + padding * 2), (int) ((bottom - top) + padding * 2), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bm);

    canvas.drawColor(Color.parseColor(bgColor));
    canvas.drawText(text, padding, - top + padding, paint);
    return bm;
}

public static int loadBitmapTexture(Bitmap bitmap) {
    int[] textureIds = new int[1];
    GLES20.glGenTextures(1,textureIds,0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textureIds[0]);

    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);

    ByteBuffer bitmapBuffer = ByteBuffer.allocate(bitmap.getHeight() * bitmap.getWidth() * 4);
    bitmap.copyPixelsToBuffer(bitmapBuffer);
    bitmapBuffer.flip();

    GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, bitmap.getWidth(),
            bitmap.getHeight(), 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, bitmapBuffer);
    return textureIds[0];
}

在当前GL_TEXTURE_2D纹理绘制之后在glBindTexture绑定水印的纹理绘制即可。需要注意的几个点:

    1. 需要开启透明,不然没有透明效果。
//启用透明
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, 
GLES20.GL_ONE_MINUS_SRC_ALPHA);
    1. 如果是使用fbo来离屏渲染OES纹理添加水印,需要在开个fbo来使用2D绘制OES的纹理和添加水印,然后另外用一个Render来绘制fbo纹理,即:fbo里面OES和2d不能混用,不然不会起作用。
    1. 使用VBO需要注意点的位置。

你可能感兴趣的:(OpenGLES添加水印)