相机一直是我的心病,花了几周的时间学习了下opengl se。并利用opengl来实现android平台下的实时预览。,真的硬着头皮啃 网上的大神的代码,没有什么注解,确实有点苦逼,闲话不说了现在做好笔记 ,方便回顾。
相机的预览
首先回到相机的预览,我们知道camera2,利用surfacetexture 可以在非预览情况下获得相机的数据,,然后利用与surfacetexture同一个texture利用GLsurfaceView中利用opengl来渲染出来。
1、写一个camera的工具,方便用来打开相机,抛出接口,就是setSurfacetexture(),set后打开相机,相机预览的数据就会进入 surfacetexture。这里的surfacetexture的创建是 由glsurfaceview中创建的texture 来创建,这样相机和opengl公用一个texture
。
2、利用mSurfaceTexture.updateTexImage()
来更新texture的纹理,然后利用GLsurfaceview在onDrawFrame()绘制出texture
,这样我们才能看见相机的数据。
3、编写定点着色器和片着色器,opengl将texture绘制在屏幕上需要这2点。这里丢出最简单的着色器:
顶点着色器
attribute vec4 vPosition;
uniform mat4 vMatrix;
attribute vec2 inputTextureCoordinate;
varying vec2 textureCoordinate;
void main()
{
gl_Position = vPosition*vMatrix;
textureCoordinate = inputTextureCoordinate;
}
片着色器
#extension GL_OES_EGL_image_external : require
precision mediump float;
varying vec2 textureCoordinate;
//uniform sampler2D vTexture;
uniform samplerExternalOES vTexture;
void main()
{
gl_FragColor = texture2D( vTexture, textureCoordinate );
}
这里需要注意的是,相机的texture必须为samplerExternalOES
而sampler2D
是二维纹理,后续离屏渲染的时候会用到。
在opengl中,为了和着色器交互,
attribute
传入顶点着色器的顶点,texture的映射关系
uniform
来传入普通的,数组、整数等关系。
当然还有一些着色器语法这里就不一一详述了。后续的滤镜美颜,大多图像处理的算法也是在着色器里面来编写的。
java层找到着色器的部分代码:
vPositionLocation = glGetAttribLocation(program , "vPosition");
vTextureCoordinateLocation = glGetAttribLocation(program , "inputTextureCoordinate");
vTextureLocation = GLES20.glGetUniformLocation(program, "vTexture");
vMatrixLocation = GLES20.glGetUniformLocation(program, "vMatrix");
然后传入相应的数据:
// 传入矩阵、 顶点和texture的floatbuffer
GLES20.glUniformMatrix4fv(vMatrixLocation, 1, false, pointsMatrix, 0);
GLES20.glVertexAttribPointer(vPositionLocation, 2, GLES20.GL_FLOAT, false, 8, vPositionBuffer);
GLES20.glVertexAttribPointer(vTextureCoordinateLocation, 2, GLES20.GL_FLOAT, false,
8,vTextureCoordinateBuffer );
当然,手机有前后摄像头,前后摄像头获得的数据,旋转角度、和纹理的左右相反等问题,可以根据相机id判断通过 顶点的旋转矩阵pointsMatrix
和 纹理映射矩阵vTextureCoordinateBuffer
来解决。
glsurfaceview
绘制坐标
2d下,glsurfaceview绘制到屏幕的坐标是归一化到- 1到1
samplerExternalOES
的纹理坐标
如果纹理本来是正的,则只需要按照一样的映射关系传入到着色器就可以了。如果想旋转90度,则通过Matrix,当然也可以通过 改变纹理映射点的对应关系,如顶点着色器(-1,-1),而 texture对应点为(1,1),其他的对应点也顺时针对应时,则最终显示的图片就会旋转90度。
当然都可以通过matrix来处理,其中经常用的纹理绕中间位置对称互换,如:
public void flipY(){
float[] c = MatrixUtils.getOriginalMatrix();
MatrixUtils.flip(c,false,true);
setPointsMatrix(c);
}
4,创建program,链接着色器,绘制即可。