/**
- fbo纹理id
*/
private int fboTextureId;
/**
- fbo id
*/
private int fboId;
/**
- vbo id
*/
private int vboId;
/**
- 顶点着色器代码路径
*/
private String vertexFilename;
/**
- 片元着色器代码路径
*/
private String fragFilename;
/**
- 尺寸
*/
private int width;
private int height;
/**
- 是否绑定Fbo
*/
private boolean isBindFbo = false;
/**
- 着色器顶点坐标位置
*/
private int aPosLocation;
/**
- 着色器纹理坐标位置
*/
private int aCoordinateLocation;
/**
- 着色器纹理位置
*/
private int uSamplerLocation;
/**
- 是否执行了onCreate
*/
private boolean isCreate = false;
/**
- 是否执行了onChange
*/
private boolean isChange = false;
public BaseRender(Context context) {
this(context, “render/base/base/vertex.frag”, “render/base/base/frag.frag”);
}
public BaseRender(Context context, String vertexFilename, String fragFilename) {
this.context = context;
this.vertexFilename = vertexFilename;
this.fragFilename = fragFilename;
}
@Override
public void onCreate() {
if (isCreate) {
return;
}
onCreatePre();
onClearColor();
onInitBlend();
onInitVertexBuffer();
onInitCoordinateBuffer();
onInitVbo();
onInitProgram();
onCreateAfter();
isCreate = true;
}
@Override
public void onChange(int width, int height) {
if (isChange) {
return;
}
onChangePre();
setWidth(width);
setHeight(height);
onViewport();
onInitFbo();
onChangeAfter();
isChange = true;
}
@Override
public void onDraw(int textureId) {
if (!onReadyToDraw()) {
return;
}
onDrawPre();
onClear();
onUseProgram();
onInitLocation();
onBindFbo();
onBindVbo();
onActiveTexture(textureId);
onEnableVertexAttributeArray();
onSetVertexData();
onSetCoordinateData();
onSetOtherData();
onDraw();
onDisableVertexAttributeArray();
onUnBind();
onDrawAfter();
}
@Override
public void onRelease() {
onDeleteProgram(program);
onDeleteShader(vertexShader);
onDeleteShader(fragShader);
onDeleteTexture(textureId);
onDeleteTexture(fboTextureId);
onDeleteFbo(fboId);
onDeleteVbo(vboId);
}
/**
- 创建之前
*/
public void onCreatePre() {
}
/**
- 设置背景颜色
*/
public void onClearColor() {
GLES20.glClearColor(0, 0, 0, 1);
}
/**
- 是否启用混色
*/
public boolean onEnableBlend() {
return false;
}
/**
- 初始化混色
*/
private void onInitBlend() {
if (!onEnableBlend()) {
return;
}
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
}
/**
- 初始化顶点坐标
*/
public void onInitVertexBuffer() {
vertexBuffer = OpenGLESUtils.getSquareVertexBuffer();
}
/**
- 初始化纹理坐标
*/
public void onInitCoordinateBuffer() {
if (isBindFbo) {
coordinateBuffer = OpenGLESUtils.getSquareCoordinateReverseBuffer();
} else {
coordinateBuffer = OpenGLESUtils.getSquareCoordinateBuffer();
}
}
/**
- 初始化Vbo
*/
public void onInitVbo() {
vboId = OpenGLESUtils.getVbo(vertexBuffer, coordinateBuffer);
}
/**
- 初始化Program
*/
public void onInitProgram() {
String vertexShaderCode = OpenGLESUtils.getShaderCode(context, vertexFilename);
String fragShaderCode = OpenGLESUtils.getShaderCode(context, fragFilename);
vertexShader = OpenGLESUtils.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
fragShader = OpenGLESUtils.loadShader(GLES20.GL_FRAGMENT_SHADER, fragShaderCode);
program = OpenGLESUtils.linkProgram(vertexShader, fragShader);
}
/**
- 创建之后
*/
public void onCreateAfter() {
}
/**
- 设置尺寸之前
*/
public void onChangePre() {
}
/**
- 设置窗口尺寸
*/
public void onViewport() {
GLES20.glViewport(0, 0, width, height);
}
/**
- 初始化Fbo
*/
public void onInitFbo() {
if (!isBindFbo) {
return;
}
int[] fboData = OpenGLESUtils.getFbo(width, height);
fboId = fboData[0];
fboTextureId = fboData[1];
}
/**
- 设置尺寸之后
*/
public void onChangeAfter() {
}
/**
- 绘制之前的准备
*/
public boolean onReadyToDraw() {
return true;
}
/**
- 绘制之前
*/
public void onDrawPre() {
}
/**
- 清屏
*/
public void onClear() {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
}
/**
- 使用Program
*/
public void onUseProgram() {
GLES20.glUseProgram(program);
}
/**
- 初始化着色器各个位置
*/
public void onInitLocation() {
aPosLocation = GLES20.glGetAttribLocation(program, “aPos”);
aCoordinateLocation = GLES20.glGetAttribLocation(program, “aCoordinate”);
uSamplerLocation = GLES20.glGetUniformLocation(program, “uSampler”);
}
/**
- 绑定Fbo
*/
public void onBindFbo() {
if (!isBindFbo) {
return;
}
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
GLES20.GL_TEXTURE_2D, fboTextureId, 0);
GLES20.glViewport(0, 0, width, height);
}
/**
- 绑定Vbo
*/
public void onBindVbo() {
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboId);
}
/**
- 激活并绑定纹理
*/
public void onActiveTexture(int textureId) {
this.textureId = textureId;
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
GLES20.glUniform1i(uSamplerLocation, 0);
}
/**
- 启用顶点坐标
*/
public void onEnableVertexAttributeArray() {
GLES20.glEnableVertexAttribArray(aPosLocation);
GLES20.glEnableVertexAttribArray(aCoordinateLocation);
}
/**
- 设置顶点坐标
*/
public void onSetVertexData() {
GLES20.glVertexAttribPointer(aPosLocation, vertexSize, GLES20.GL_FLOAT, false, vertexStride, 0);
}
/**
- 设置纹理坐标
*/
public void onSetCoordinateData() {
GLES20.glVertexAttribPointer(aCoordinateLocation, coordinateSize, GLES20.GL_FLOAT, false, coordinateStride, vertexBuffer.limit() * 4);
}
/**
- 设置其他数据
*/
public void onSetOtherData() {
}
/**
- 绘制
*/
public void onDraw() {
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount);
}
/**
- 禁用顶点坐标
*/
public void onDisableVertexAttributeArray() {
GLES20.glDisableVertexAttribArray(aPosLocation);
GLES20.glDisableVertexAttribArray(aCoordinateLocation);
}
/**
- 解除绑定
*/
public void onUnBind() {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
}
/**
- 绘制之后
*/
public void onDrawAfter() {
}
/**
- 删除Program
*/
public void onDeleteProgram(int program) {
GLES20.glDeleteProgram(program);
}
/**
- 删除Shader
*/
public void onDeleteShader(int shader) {
GLES20.glDeleteShader(shader);
}
/**
- 删除纹理
*/
public void onDeleteTexture(int textureId) {
GLES20.glDeleteTextures(1, new int[]{textureId}, 0);
}
/**
- 删除Fbo
*/
public void onDeleteFbo(int fboId) {
GLES20.glDeleteFramebuffers(1, new int[]{fboId}, 0);
}
/**
- 删除Vbo
*/
public void onDeleteVbo(int vboId) {
GLES20.glDeleteBuffers(1, new int[]{vboId}, 0);
}
public Context getContext() {
return context;
}
public void setContext(Context context) {
this.context = context;
}
public FloatBuffer getVertexBuffer() {
return vertexBuffer;
}
public void setVertexBuffer(FloatBuffer vertexBuffer) {
this.vertexBuffer = vertexBuffer;
}
public FloatBuffer getCoordinateBuffer() {
return coordinateBuffer;
}
public void setCoordinateBuffer(FloatBuffer coordinateBuffer) {
this.coordinateBuffer = coordinateBuffer;
}
public int getVertexSize() {
return vertexSize;
}
public void setVertexSize(int vertexSize) {
this.vertexSize = vertexSize;
}
public int getCoordinateSize() {
return coordinateSize;
}
public void setCoordinateSize(int coordinateSize) {
this.coordinateSize = coordinateSize;
}
public int getVertexStride() {
return vertexStride;
}
public void setVertexStride(int vertexStride) {
this.vertexStride = vertexStride;
}
public int getCoordinateStride() {
return coordinateStride;
}
public void setCoordinateStride(int coordinateStride) {
this.coordinateStride = coordinateStride;
}
public int getVertexCount() {
return vertexCount;
}
public void setVertexCount(int vertexCount) {
this.vertexCount = vertexCount;
}
public int getCoordinateCount() {
return coordinateCount;
}
public void setCoordinateCount(int coordinateCount) {
this.coordinateCount = coordinateCount;
}
public int getProgram() {
return program;
}
public void setProgram(int program) {
this.program = program;
}
public int getFboTextureId() {
return fboTextureId;
}
public void setFboTextureId(int fboTextureId) {
this.fboTextureId = fboTextureId;
}
public int getFboId() {
return fboId;
}
public void setFboId(int fboId) {
this.fboId = fboId;
}
public int getVboId() {
return vboId;
}
public void setVboId(int vboId) {
this.vboId = vboId;
}
public String getVertexFilename() {
return vertexFilename;
}
public void setVertexFilename(String vertexFilename) {
this.vertexFilename = vertexFilename;
}
public String getFragFilename() {
return fragFilename;
}
public void setFragFilename(String fragFilename) {
this.fragFilename = fragFilename;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public boolean isBindFbo() {
return isBindFbo;
}
public void setBindFbo(boolean bindFbo) {
isBindFbo = bindFbo;
}
public int getPosLocation() {
return aPosLocation;
}
public void setPosLocation(int aPosLocation) {
this.aPosLocation = aPosLocation;
}
public int getCoordinateLocation() {
return aCoordinateLocation;
}
public void setCoordinateLocation(int aCoordinateLocation) {
this.aCoordinateLocation = aCoordinateLocation;
}
public int getSamplerLocation() {
return uSamplerLocation;
}
public void setSamplerLocation(int uSamplerLocation) {
this.uSamplerLocation = uSamplerLocation;
}
public boolean isCreate() {
return isCreate;
}
public void setCreate(boolean create) {
isCreate = create;
}
public boolean isChange() {
return isChange;
}
public void setChange(boolean change) {
isChange = change;
}
public BaseRenderBean getRenderBean() {
return renderBean;
}
public void setRenderBean(BaseRenderBean renderBean) {
this.renderBean = renderBean;
}
public void updateRenderBean(BaseRenderBean renderBean) {
setRenderBean(renderBean);
}
}
代码有点长,但是里面尽可能地考虑到了渲染和扩展的需求
顶点着色器 vertex.frag
attribute vec4 aPos;
attribute vec2 aCoordinate;
varying vec2 vCoordinate;
void main(){
vCoordinate = aCoordinate;
gl_Position = aPos;
}
片元着色器 frag.frag
precision mediump float;
uniform sampler2D uSampler;
varying vec2 vCoordinate;
void main(){
gl_FragColor = texture2D(uSampler, vCoordinate);
}
注意到,里面有用到一个工具类OpenGLESUtils和实体类BaseRenderBean具体就不贴出来了,可以到Github
上查看
四、BaseOesRender
注意到,BaseRender
里面绑定的纹理是2D纹理
,而如果想实现相机预览,则需要使用Oes纹理
,所以需要创建一个BaseOesRender
为相机做渲染
package com.yk.media.opengles.render.base;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import com.yk.media.utils.OpenGLESUtils;
public class BaseOesRender extends BaseRender {
/**
- oes纹理id
*/
private int oesTextureId;
/**
- 顶点变换矩阵位置
*/
private int uMatrixLocation;
/**
- 纹理变换矩阵位置
*/
private int uOesMatrixLocation;
/**
- oes尺寸
*/
private int oesW = -1;
private int oesH = -1;
/**
- 顶点变换矩阵
*/
private float[] mMVPMatrix = new float[16];
/**
- 纹理变换矩阵
*/
private float[] mOesMatrix = {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
/**
- 是否准备好绘制
*/
private boolean isReadyToDraw = false;
/**
- SurfaceTexture
*/
private SurfaceTexture surfaceTexture;
/**
- SurfaceTexture回调
*/
private OnSurfaceTextureListener onSurfaceTextureListener;
public BaseOesRender(Context context) {
super(context, “render/base/oes/vertex.frag”, “render/base/oes/frag.frag”);
setBindFbo(true);
oesTextureId = OpenGLESUtils.getOesTexture();
}
@Override
public void onInitCoordinateBuffer() {
setCoordinateBuffer(OpenGLESUtils.getSquareCoordinateBuffer());
}
@Override
public boolean onReadyToDraw() {
if (!isReadyToDraw) {
if (onSurfaceTextureListener != null) {
if (surfaceTexture != null) {
surfaceTexture.release();
surfaceTexture = null;
}
surfaceTexture = new SurfaceTexture(oesTextureId);
onSurfaceTextureListener.onSurfaceTexture(surfaceTexture);
isReadyToDraw = true;
} else if (surfaceTexture != null) {
surfaceTexture.attachToGLContext(oesTextureId);
isReadyToDraw = true;
} else {
return false;
}
}
return oesW != -1 && oesH != -1;
}
@Override
public void onDrawPre() {
super.onDrawPre();
mMVPMatrix = OpenGLESUtils.getMatrix(getWidth(), getHeight(), oesW, oesH);
surfaceTexture.updateTexImage();
float[] oesMatrix = new float[16];
surfaceTexture.getTransformMatrix(oesMatrix);
if (!OpenGLESUtils.isIdentityM(oesMatrix)) {
mOesMatrix = oesMatrix;
}
}
@Override
public void onInitLocation() {
super.onInitLocation();
uMatrixLocation = GLES20.glGetUniformLocation(getProgram(), “uMatrix”);
uOesMatrixLocation = GLES20.glGetUniformLocation(getProgram(), “uOesMatrix”);
}
@Override
public void onActiveTexture(int textureId) {
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId);
GLES20.glUniform1i(getSamplerLocation(), 0);
}
@Override
public void onSetOtherData() {
super.onSetOtherData();
GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, mMVPMatrix, 0);
GLES20.glUniformMatrix4fv(uOesMatrixLocation, 1, false, mOesMatrix, 0);
}
@Override
public void onRelease() {
super.onRelease();
onDeleteTexture(oesTextureId);
}
/**
- 绘制
*/
public void onDrawSelf() {
super.onDraw(oesTextureId);
}
/**
- 设置oes尺寸
*/
public void setOesSize(int width, int height) {
oesW = width;
oesH = height;
}
/**
- 设置SurfaceTexture
*/
public void setSurfaceTexture(SurfaceTexture surfaceTexture) {
this.surfaceTexture = surfaceTexture;
isReadyToDraw = false;
}
/**
- 设置SurfaceTexture回调
*/
public void setOnSurfaceTextureListener(OnSurfaceTextureListener onSurfaceTextureListener) {
this.onSurfaceTextureListener = onSurfaceTextureListener;
isReadyToDraw = false;
}
}
顶点着色器 vertex.frag
attribute vec4 aPos;
attribute vec4 aCoordinate;
uniform mat4 uMatrix;
uniform mat4 uOesMatrix;
varying vec2 vCoordinate;
void main(){
vCoordinate = (uOesMatrix * aCoordinate).xy;
gl_Position = uMatrix * aPos;
}
片元着色器 frag.frag
#extension GL_OES_EGL_image_external:require
precision mediump float;
uniform samplerExternalOES uSampler;
varying vec2 vCoordinate;
void main(){
gl_FragColor = texture2D(uSampler, vCoordinate);
}
BaseOesRender
是继承BaseRender
的
加入了一些变量
oesW
和oesH
用于计算矩阵
mMVPMatrix
通过width、height、oesW、oesH
计算的矩阵
mOesMatrix
通过SurfaceTexture
获取的矩阵
isReadyToDraw
是否准备好渲染
重写了一些方法
onInitCoordinateBuffer
BaseOesRender
需要绑定FBO
,所有纹理坐标需要设置好,不然会出现倒立
onReadyToDraw
此处做一些SurfaceTexture
绑定纹理和回调
onDrawPre
此处做矩阵相关的计算
onInitLocation
获取矩阵的Location
onActiveTexture
前面有说到,预览相机使用的是SurfaceTexture
,所有需要修改绑定为Oes纹理
onSetOtherData
此处传入矩阵的数据
onRelease
此处做一些释放资源的工作
OnSurfaceTextureListener
public interface OnSurfaceTextureListener {
/**
- SurfaceTexture回调
*/
void onSurfaceTexture(SurfaceTexture surfaceTexture);
}
onDrawSelf
public void onDrawSelf() {
super.onDraw(oesTextureId);
}
因为oesTextureId
是内部创建的,故渲染的话,直接调用super.onDraw(oesTextureId)
,方便外部调用
五、OesRender
前面有说过,EGLTextureView
的setRenderer
只能调用一次,故才会创建BaseRender
,现在来创建Renderer
调度者
public class OesRender implements Renderer {
private Context context;
/**
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
因为oesTextureId
是内部创建的,故渲染的话,直接调用super.onDraw(oesTextureId)
,方便外部调用
五、OesRender
前面有说过,EGLTextureView
的setRenderer
只能调用一次,故才会创建BaseRender
,现在来创建Renderer
调度者
public class OesRender implements Renderer {
private Context context;
/**
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-7YOXvBmK-1715328700265)]
[外链图片转存中…(img-sbgV6qiJ-1715328700268)]
[外链图片转存中…(img-5ogQ6Qf4-1715328700269)]
[外链图片转存中…(img-AKSQ5jFL-1715328700270)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!