opengl使用流程文述

opengl使用流程文述
opengl中是通过三个点确定一个面进行着色,总体思路为确定顶点着色器》形成矢量图形》进行栅格化==》最后再通过片元着色器进行上色的过程
1,先用一个view继承自GLSurfaceView 也就是mCameraTexure
2, 在构造方法中用setEGLContextClientVersion(2); 选用2版本,2版本稳定一些
3, opengl的渲染方式,手动和自动两种,自动的话直接在构造方法中调用requestRender();
4, 接着初始化CameraX(此处省略)
5,回调接口onUpdate,渲染在哪里
6,我们要通过实现Preview的OnPreviewOutputUpdateListener接口,从onUpdate的PreviewOutput参数中拿到CameraX的预览图像,我们从output中通过output.getSurfaceTexture()方法拿到surfaceTexure
7, 我们还要通过实现GLSurfaceView.Render接口,并在构造方法中设置setRender监听,一旦设置监听后,他就会回调onSurfaceCreated方法
8,此时需要设置一个int值的texture,可以理解为在GPU所在的地方
9,接着在onSurfaceCreated方法中进行绑定,需用这个mCameraTexture的attachToGLContext(texture)将这个int值传进去,这时就绑定了数据
10,这时候我们给这个mCameraTexture设置setFrameAvailableListener(this)进行渲染,我们需要先实现SurfaceTexture的onFrameAvailableListener这个接口
11,摄像头如果有数据,就会回调onFrameAvailable这个方法
12,这个数据就会在GPU没有在CPU
13, 然后我们在onFrameAvailable中调用requestRender方法进行手动渲染,等于摄像头一有数据,它一回调这个方法我们就会手动渲染一次
14,然后就会回调我们写的这个自定义控件中的onDraw方法,也就是onDrawFrame方法
15,到现在我们的Camera获取的数据还在Texture,还没有到我们的CameraView上,接下来我们需要绑定GPU,确定形状,颜色
16,我们需要通过mCameraTexture的updateTextureImage()方法获取最新的数据,到GPU的内存缓冲区。
17,我们需要进行一层转化,将世界坐标系转换为安卓坐标系,因为在opengl中是三个点确定一个面,确定一个矩形就需要四个点的一个矩阵,前面三个是一个面,后面三个是一个面,两个三角形拼成一个矩形,这个就是VERTEX形状
18,这时候需要进行opengl程序了,我们需要先新建一个文件夹raw,写opengl程序,新建一个Camera_vert.glsl文件,这是一个程序,无论片元程序还是顶点程序都有main函数,这个是片元程序
19,再新建一个Camera_vert.glsl这个是顶点程序,在opengl运行着两个程序,一个是片元程序,一个是顶点程序,顶点的作用是确定形状,这个形状已经在CPU中定义好了,接下来我们需要将CPU中定义好的形状传值过来,所以需要写一个接收变量
20,首先我们要声明一个GPU变量,
attribute vec4 vPosition;
4代表有4个坐标
21,在main方法中对
gl_position = vPosition;
进行赋值,一旦赋值后形状便确认了
22,在这里接收坐标系的是世界坐标系,但是我们需要把它绘制到我们的控件,也就是纹理坐标系中
23,这时我们需要定义纹理坐标系,也是
attribute vec4 vCoord;
24, 接着我们需要定义采样器,将世界坐标系的值传递给纹理坐标系
varying vec2 aCoord;
aCoord = vCoord.xy;
25, 一旦定义varing,它会把我们的顶点坐标系丢到片元坐标系,所以我们在Camera_frag.glsl片元程序中需要声明一个一样的名字,
varying vec2 aCoord;
名字一定要一模一样,它就会传递,不一样的话就不传递了
26,这时我们需要加载这个opengl程序,在Java方法中
String vertexShader = readRawTextFile(context, R.raw.camera_vert);
//返回的String vertexShader是它的路径
27,接下来我们要创建一个程序
//顶点程序
GLES20.glCreatShader(GLES20.GL_VERTEX_SHADER);//片元程序
GLES20.glCreatShader(GLES20.GL_FRAGMENT_SHADER);
顶点程序和片元程序创建大体上是一样的,只有这里参数上有些差别
28, 创建完顶点程序会返回一个int值,这个int值vShader 是程序的地址
29,我们需要关联对应的代码
GLES20.glShaderSource(vShader, vertexShader);
30,接下来编译
//调用这个方法这里GPU会帮你去编译
GLES20.glShaderSource(vShader);
31, 如果编译成功我们需要用一个int[]数组去获取状态
//入参出参对象
int[] status = new int[1];
//获取参数
GLES20.glGetShader(vShader, GLES20.GLCOMPILE_STATUS, status, 0);
//查看配置,是否成功
接下来我们通过status[0]是否等于GLES20.GL_TRUE来判断是否成功
32,然后我们加载片元程序,片元程序和顶点程序流程一样,唯一不同就是两个地址和参数有些不一样
33,两个都执行完成我们需要创建一个总程序
int program = GLES20.glCreatProgram();
它会返回一个int 值program,这个int值对于CPU来说没有意义,但是对GPU却有意义
34,总程序添加两个程序
//加载顶点程序
GLES20.glAttachShader(program, vShader);
//加载片元程序
GLES20.glAttachShader(program, fShader);
这个总程序就相当于一个exe功能
35,最后我们把整个程序激活
GLES20.glLinkProgram(program);
36, 这个时候我们的自定义控件CameraView和我们的Camera的Texture还是没有关系,我们需要将CPU的世界坐标系矩阵,纹理坐标系矩阵传递给GPU
37,需要在Java层用ByteBuffer.allocateDirect,这个方法是通过allocateDirect创建CPU和GPU之间的一个通道
Buffer vertexBuffer = ByteBuffer.allocateDirect(4*2*4).order(Byteorder.nativeOrder()).asFloatBuffer();
这时会返回一个Buffer对象,vertexBuffer,先把他清空
vertexBuffer.clear();
再把坐标点放进去
vertexBuffer.put(VERTEX);
38, 这时我们写一个onDraw方法,传入宽高,每次有数据我们就渲染一次,因此在onDrawFrame中去调用onDraw
39, 在onDraw方法中,需要告诉GPU范围,调用GLES20.glViewport()并传入宽高
40,调用program程序,
GLES20.glUSEProgram(program);
41,定位到GPU的地址
int vPostion = GLES20.glGetAttribLocation(program, "vPostion");
它会返回一个int值vPosition,地址值
42,将CPU的数据传递给GPU
`GLES20.glVertxAttribPointer()`
要传入6个参数,主要要传入的参数是这个vPositon的地址值,和刚才通道的哪个返回值Buffer也就是vetexBuffer,这样就是把vetexBuffer传递到GPU里去了,这个GPU里的vPositon就有值了
43.接下来调用
GLES20.glEnableVertexAttibArray(vPosition);
代表传完了,告诉GPU现在启动这个通道
44,接着传递纹理坐标系,与顶点坐标系一致,开启vCoord变量
GLES20.glEnableVertexAttibArray(vCoord);
45, 这样在GPU中我们两个值都传递了,一个是vPostion,一个是vCoord
46,我们还要在onDraw方法中每次渲染都需要将vertexBuffer与textureBuffer放在0位
47,在onSurfaceCreat中,将CameraView绑定到Texture
mCameraTexture.attachToGLContext(texture);
这样我们的自定义CameraView就与texture绑定了
48, 这时我们需要激活一个图层
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
一共有32个图层,我们随便使用某一个都可以
49,
//绑定一个采样器和摄像头的内容
GLES20.glBindTexture(GLES20.TEXTURE0, texture);
50, 我们需要在片元程序中定义一个采样器
uniform samplerExternalOES vTexture;
51, 在java中先定义一个int值vTexture,接着定位到片元变量
vTexture = GLES20.glGetUniformLocation(program, "vTexture");
52, 接下来我们将vTexture传进去
//告诉摄像机在第几个图层,摄像头和第几个图层进行绑定
GLES20.glUniform1f(vTexure, GL_TEXTURE0);
这个vTexture就拿到片元中的vTexture
53, 在片元程序的main方法中texture2D()
//自带的采样器,图层采样对应的像素值
vec4 rgba = texture2D(vTexture, aCoord);
//我们得到的采样像素就是rgba
54, 我们给gl_FragColor = rgba进行赋值,就可以得到我们摄像头捕获的图像
55,最后在java层通知GPU进行渲染
GLES20.glDrawArrays(GLES20.GL_TRIANGLE, 0, 4);
//第一个参数代表三个顶点
//第二个0
//第三个代表4个坐标值
56,如果想加滤镜,就在gl_FragColor = rgba赋值的时候分别对rgba的r g b a值乘以一定的系数进行转换,形成一定的滤镜效果
比方说相加灰色滤镜
float color = (rgba.r + rgba.g + rgba.b) / 3
gl_FragColor = vec4(color, color, color, rgba.a);
57,想要增加分屏效果,就是通过控制采样点坐标达到分屏的效果
texture2D(vTexture, vec2(aCoord.x, aCoord.y));
59, 如果我们得到CameraX的预览图像时横着的,我们可以在onDrawFrame方法中
float[] mtx = new float[16];
mCameraTexture.getTransformMatrix(mtx);//得到一个纠正的矩阵//通过摄像头捕获这个偏移值传进来
GLES20.glUniformMatix4fv(vMatrix, 1, false, mtx);
在顶点程序中来一个矩阵
uniform mat4 vMatrix;
aCoord = (vMaxtrix * vCoord.xy);
这样就可以得到一个纠正的图像了
PS: 美颜的主要思路
1,其实就是高斯模糊,就是取每个点的平均值放在周围
2,一般取20个点,上,下 ,左,右各4个,然后里三环外三环,三环的图案20个点累加除以20得到平均值,最后将取到的值赋值到这个坐标点,就得到一个高斯模糊的图像
3,再用高反差,就是清晰图减去一张模糊的图片,保留边界的细节
4,调优。分别对r,g,b三种颜色的图层的高反差图乘以一定的调优系数
5,线性叠加,将蓝图的值取出来,保留边界的细节
6,设置一个磨皮的系数,一般是0~1f,再大会模糊
7,然后两个图原图保留的细节,与一个高斯模糊的图相加
6,再对gl_Fragcolor进行赋值
gl_Fragcolor = vec4(r, 1.0);


