美文网首页
2. OpenGl 渲染 CameraX的数据 + 灰度滤镜

2. OpenGl 渲染 CameraX的数据 + 灰度滤镜

作者: liys_android | 来源:发表于2023-07-04 23:01 被阅读0次
本章实现效果如下:
tutieshi_320x568_8s.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是可以预览了, 但是方向不对, 还变形了, 如下图:
那么问题来了,不同的手机旋转的方向也不一样,怎么办呢?


CameraX横向320.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渲染一个图片+灰度滤镜

相关文章

网友评论

      本文标题:2. OpenGl 渲染 CameraX的数据 + 灰度滤镜

      本文链接:https://www.haomeiwen.com/subject/zsuhudtx.html