OpenGL ES
android中 GLSurfaceView 继承 SurfaceView
GLSurfaceView 中有 GLThread
setEGLContextClientVersion(2);//使用openGLES 2.0上下文
setRenderer(...);//设置渲染回调接口 该方法中实例化GLThread
/**
* 刷新方式:
* RENDERMODE_WHEN_DIRTY 手动刷新,調用requestRender();
* RENDERMODE_CONTINUOUSLY 自動刷新,大概16ms自動回調一次onDraw方法
*/
//注意必须在setRenderer 后面。
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
openGL 渲染管线 顶点->图元装配->光栅化(像素化)
着色器(顶点着色器和片元着色器)
Android Studio 集成GLSLSupport插件 编辑OpenGL着色器语言(GLSL)时关键字高亮智能提示
openGL着色语言
attribute 属性变量(只在顶点着色器使用)
uniforms 一致变量(片元着色器使用)
varying 易编变量(顶点着色器输出数据到片元着色器)
gl_Position 坐标(x,y,z,w)
samplerExternalOES 图片采样器
samplerExternalOES 相当于rgba 使用texture2D(...)
precision / mediump / float 精度定义
openGL的世界坐标和纹理坐标
static final float COORD[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
};
static final float TEXTURE_COORD[] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
};
图片.png
-
onSurfaceCreated
@Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { //创建OpenGL 纹理 ,把摄像头的数据与这个纹理关联 textures = new int[1]; //当做能在opengl用的一个图片的ID mCameraTexure.attachToGLContext(textures[0]); // 当摄像头数据有更新回调 onFrameAvailable mCameraTexure.setOnFrameAvailableListener(this);//监听更新时手动调用requestRender() screenFilter = new ScreenFilter(cameraView.getContext()); }
创建和初始化着色器供, 这些过程一般分为7个步骤:
创建顶点着色器对象(glcreateShader);
向顶点着色器对象中填充着色器程序的源代码(glshaderSource);
编译顶点着色器(glcompileShander);
创建片元着色器对象(glcreateShader);
向片元着色器对象中填充着色器程序的源代码(glshaderSource);
编译片元着色器(glcompileShander);
创建程序对象(glcreateProgram);
为程序对象分配着色器(glattachShader);
连接程序对象(gllinkProgram);
使用程序对象(gluseProgram)
//着色器程序准备
public static int loadProgram(String vSource, String fSource) {
/**
* 顶点着色器
*/
int vShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
//加载着色器代码
GLES20.glShaderSource(vShader, vSource);
//编译(配置)
GLES20.glCompileShader(vShader);
//查看配置 是否成功
int[] status = new int[1];
GLES20.glGetShaderiv(vShader, GLES20.GL_COMPILE_STATUS, status, 0);
if (status[0] != GLES20.GL_TRUE) {
//失败
throw new IllegalStateException("load vertex shader:" + GLES20.glGetShaderInfoLog
(vShader));
}
/**
* 片元着色器
* 流程和上面一样
*/
int fShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
//加载着色器代码
GLES20.glShaderSource(fShader, fSource);
//编译(配置)
GLES20.glCompileShader(fShader);
//查看配置 是否成功
GLES20.glGetShaderiv(fShader, GLES20.GL_COMPILE_STATUS, status, 0);
if (status[0] != GLES20.GL_TRUE) {
//失败
throw new IllegalStateException("load fragment shader:" + GLES20.glGetShaderInfoLog
(vShader));
}
/**
* 创建着色器程序
*/
int program = GLES20.glCreateProgram();
//绑定顶点和片元
GLES20.glAttachShader(program, vShader);
GLES20.glAttachShader(program, fShader);
//链接着色器程序
GLES20.glLinkProgram(program);
//获得状态
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, status, 0);
if (status[0] != GLES20.GL_TRUE) {
throw new IllegalStateException("link program:" + GLES20.glGetProgramInfoLog(program));
}
GLES20.glDeleteShader(vShader);
GLES20.glDeleteShader(fShader);
return program;
}
onSurfaceChanged设置宽高
-
onDrawFrame
@Override public void onDrawFrame(GL10 gl) { //todo 更新纹理 mCameraTexure.updateTexImage();//拿到最新的图像数据 mCameraTexure.getTransformMatrix(mtx); screenFilter.setTransformMatrix(mtx); screenFilter.onDraw(textures[0]); }
public int onDraw(int texture, FilterChain filterChain) { FilterContext filterContext = filterChain.filterContext; //设置绘制区域 GLES20.glViewport(0, 0, filterContext.width, filterContext.height); GLES20.glUseProgram(program); vertexBuffer.position(0); // 4、归一化 normalized [-1,1] . 把[2,2]转换为[-1,1] GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 0, vertexBuffer); //CPU传数据到GPU,默认情况下着色器无法读取到这个数据。 需要我们启用一下才可以读取 GLES20.glEnableVertexAttribArray(vPosition); textureBuffer.position(0); // 4、归一化 normalized [-1,1] . 把[2,2]转换为[-1,1] GLES20.glVertexAttribPointer(vCoord, 2, GLES20.GL_FLOAT, false, 0, textureBuffer); //CPU传数据到GPU,默认情况下着色器无法读取到这个数据。 需要我们启用一下才可以读取 GLES20.glEnableVertexAttribArray(vCoord); //相当于激活一个用来显示图片的画框 GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture); // 0: 图层ID GL_TEXTURE0 // GL_TEXTURE1 , 1 GLES20.glUniform1i(vTexture, 0); beforeDraw(); //通知画画, GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); return texture; }
openGL ES离屏渲染 FBO(Frame Buffer Object)帧缓存对象
public void createFrame(int width, int height) { releaseFrame(); //創建FBO /** * 1、创建FBO + FBO中的纹理 */ frameBuffer = new int[1]; frameTextures = new int[1]; GLES20.glGenFramebuffers(1, frameBuffer, 0); OpenGLUtils.glGenTextures(frameTextures); /** * 2、fbo与纹理关联 */ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameTextures[0]); GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null); //纹理关联 fbo GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffer[0]); //綁定FBO GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, frameTextures[0], 0); /** * 3、解除绑定 */ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); }
EGL库 管理窗口 将Surface和EGLSurface绑定
图片.png
openGL是在GLThread子线程 同样需要搭建一个EGL环境在子线程
1.创建Display获取显示窗口
EGLDisplay mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
EGL14.eglinitialize(...);//初始化
2.配置属性选项
EGL.eglChooseConfig(...)
3.创建EGL上下文
EGL14.eglCreateWindowSurface(...)
5.绘制
//先绑定当前线程的显示屏diplay
EGL14.eglMakeCurrent(EGLDisplay, EGLSurface, EGLSurface, EGLContext);
//EGLSurface是双缓冲模式
EGLExt.eglPresentationTimeANDROID(EGLDisplay,EGLSurface,时间戳);
EGL14.eglSwapBuffers(EGLDisplay,EGLSurface);
实现功能一 、调整快慢帧
//只需要调整bufferInfo参数中的时间戳
Muxer.writeSampleData(track,encodeData,bufferInfo);
//改变时间的速率
bufferInfo.presentationTimeUs = bufferInfo.presentationTimeUs/speed;
实现功能二、识别脸部 使用Seetaface FaceLandmarker
图像局部缩放
图片.png
实现功能三、图像遮罩物
openGL图像混合
GLES20.gleEnable(GLES20.GL_BLEND);
GLES20.GLBlendFunc(GLES20.GLONE,GLES20.GL_ONE_MINUS_SRC_ALPHA);
//GL_ONE采用源颜色的alpha值作为因子
//GL_ONE_MINUS_SRC_ALPHA表示用1.0减去源颜色的aplha作为因子
利用GLES20.glViewPort(x,y,width,heigh)或openGL中转换世界坐标系
GLUtils.textImage2D(...)将Bitmap图片绑定openGL中
实现功能四、美颜
1.模糊效果(水平方向和垂直方向)设计11*11算子
2.高反差保留 边缘化 高反差=原图-模糊图
3.保留边缘细节不被模糊掉
4.磨皮调整
实现功能五、闪烁 以中心点(0.5,0.5)向四周扩散
实现功能六、分配 以屏幕0.25~0.75绘制(大于0.5则减去0.25,否则加上0.25)