本章实现效果如下:
![](https://img.haomeiwen.com/i13519092/69957b2dba66c1d2.gif)
使用CameraX
引入CameraX
//app/build.gradle下引入CameraX
implementation "androidx.camera:camera-core:1.0.0-alpha05"
implementation "androidx.camera:camera-camera2:1.0.0-alpha05"
//添加camera权限, android6.0以上动态申请
<uses-permission android:name="android.permission.CAMERA" />
可能很多人用CameraX预览都是在xml布局使用:
<androidx.camera.view.PreviewView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
其实还有另一种用法:CameraX会把数据传到一个纹理中,用OpenGl把这个纹理绑定到采样器上, 然后进行渲染.
一. 关键步骤如下:
1. CameraX的使用封装
外部调用这个方法,第二个参数back回调表示:我已经准备好了, 并返回一个"SurfaceTexture纹理对象",但是这个纹理是不能直接用来赋值的, 因为它并不是GPU中真正的纹理, 而是我们CPU中的对象,我们需要通过这个对象去GPU创建真正的纹理.
object CameraHelper {
fun cameraX(lifecycleOwner: LifecycleOwner, back: (SurfaceTexture)->Unit){
// 预览配置
val previewConfig = PreviewConfig.Builder()
.setTargetResolution(Size(1080, 720))
.setLensFacing(CameraX.LensFacing.BACK) //前置或者后置摄像头
.build()
val preview = Preview(previewConfig)
preview.setOnPreviewOutputUpdateListener {
back(it.surfaceTexture)
}
//预览绑定生命周期
CameraX.bindToLifecycle(lifecycleOwner, preview)
}
}
2. SurfaceTexture,创建纹理ID
由上一节可知, 要操作GPU,必须要在OpenGL线程(EGL环境), 所以需要吧SurfaceTexture和GL线程 关联起来,然后创建一个纹理, 纹理的句柄textureId的值,由我们指定, 通常是0和1这种.
//cameraTexture就是CmaeraX返回的SurfaceTexture对象
cameraTexture?.attachToGLContext(textureId) //GL线程中调用
3. OpenGl什么时候更新数据?设置监听
回调时, 证明CameraX已经把数据准备好了, 可以更新到纹理上
cameraTexture?.setOnFrameAvailableListener {
glSurfaceView.requestRender();
}
4. 通知CameraX,把数据输出到纹理上
cameraTexture?.updateTexImage();
//后续参考第一节,把纹理,纹理单元,采样器绑定, 渲染即可
5. 片元着色器换成了samplerExternalOES
//相当于导包
#extension GL_OES_EGL_image_external : require
varying vec2 tCoordinate; //纹理坐标
uniform samplerExternalOES vTexture; //摄像头采样器
void main(){
//gl_FragColor = texture2D(vTexture, tCoordinate);
vec4 rgba = texture2D(vTexture,aCoord);
float value = (rgba.r+rgba.g+rgba.b)/3.0;
gl_FragColor = vec4(value, value, value, rgba.a);
}
经过以上步骤,Camera是可以预览了, 但是方向不对, 还变形了, 如下图:
那么问题来了,不同的手机旋转的方向也不一样,怎么办呢?
![](https://img.haomeiwen.com/i13519092/f25954aa8d7bbb00.jpg)
6. 纠正预览的方向
SurfaceTexture提供了一个纠错的4X4的矩阵mtx:
新坐标=mtx*原坐标
代码如下:
cameraTexture?.getTransformMatrix(mtx);
//给vMatrix赋值, tMatrixHandle为顶点着色器中vMatrix变量的句柄
GLES20.glUniformMatrix4fv(tMatrixHandle, 1, false, mtx, 0);
顶点着色器
precision mediump float;
attribute vec4 vPosition;//顶点坐标
attribute vec4 vCoordinate; //纹理的坐标
uniform mat4 vMatrix; //纠正的矩阵
varying vec2 tCoordinate; //传递给片元
void main(){
gl_Position = vPosition;
tCoordinate = (vMatrix*vCoordinate).xy;
}
注意:
顶点坐标: 手机中心为原点,上和右为正
纹理坐标:左下角原为原点,上和右为正
// --------------------------顶点转buf-----------------------------
vPositionBuffer = GLApp.coordinate2Buf(
floatArrayOf(
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f
)
)
vCoordinateBuffer = GLApp.coordinate2Buf(
floatArrayOf(
//左下角原点
0.0f, 0.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f
)
)
工具类看第一节:OpenGl渲染一个图片+灰度滤镜
网友评论