OpenGL ES:学习总结

学习阶段(一):OpenGL es基础的学习

理论:

  1. OpenGL es渲染流程
  2. 着色器的编写
  3. 图元的绘制
  4. VAO、VBO、EBO
  5. 纹理的绘制
  6. 矩阵变换
  7. 滤镜原理、卷积核

实践:

  1. 基本形状的绘制(三角形、正方形、正方体、圆)
  2. 纹理的绘制(绘制图片到图元、混合纹理绘制)
  3. 矩阵的变换(缩放、平移、旋转、MVP矩阵)
  4. 图像加滤镜效果(黑白、放大、四格)

问题:

  1. 绘制纹理遇见了大小比例不一被拉伸的现象,这种情况可以使用投影矩阵解决,用正交投影把坐标归一化。
  2. OOM问题,起初将bitmap作为来源生成相应的纹理,即使用完之后显式地调用了recycle回收资源,但是这个过程放在了onDrawFrame渲染回调里面,每次都会生成一份新的纹理,而渲染频率又很高,可能bitmap都来不及回收,从而导致OOM,
    并且纹理使用后也需要释放掉。
  3. OpenGL渲染的纹理图像时候,出现了倒置的情况,因为纹理坐标系的原点在左下角,而Android的屏幕坐标系在左上角,所以需要翻转一下。

总结:
经过这一轮基础的学习,也基本对OpenGL有一些了解,OpenGL的流程如下图所示。我们对OpenGL的操作只需要关注顶点数据、纹理数据以及着色器程序的编写即可,并且OpenGL的操作需要在一定的上下文环境中执行,不过GLSurfaceView已经帮我们初始化好了上下文环境,我们只需在它提供中的回调函数中进行OpenGL的操作即可,当然这样灵活性可能缺失,有的时候还需要自己去初始化上下文环境。
在编码的时候要注意一些细节上的问题也要注意资源的回收,避免发生内存泄漏,进而导致oom。

而实现滤镜的效果,也只是对片段着色器进行相关的编程,对某个像素或坐标进行变换,影响其片段的着色,从而达成目的。滤镜的不同点在于片段着色器的不同,因此可以封装一个BaseFilter,提供一个接口用于获取子类的片段着色器,具体滤镜只需提供特定的片段着色器即可。BaseFilter中持有向外提供滤镜的初始化以及绘制接口和设置纹理来源接口即可。

一些注意点

学习阶段(二):综合应用

理论:

  1. Camera1、Camera2 API的使用
  2. 使用TexutureView、SurfaceView、GLSurfaceView进行相机数据预览
  3. OES纹理、FBO、离屏渲染、EGL环境创建
  4. MediaCodec、MediaExtractor、AudioTrack的使用
  5. 音视频基础理论:采样率、声道、采样格式、音视频格式等

实践:

  1. 相机预览添加滤镜效果

    想到如下俩种实现方案:

    a) 使用TextureView用于相机预览,TextureView表面再盖上一层GLSurfaceView用与OpenGL ES的渲染输出,从TextureView中获取每一帧的Bitmap交给OpenGL ES渲染到GLSurfaceView上。
    问题:预览一段时间后OOM,原因是没有释放渲染过的纹理,当渲染新的bitmap的时候释放上一帧的纹理即可。

    b) 从OpenGL ES中生成一个纹理对象,以纹理ID new一个SurfaceTexture回调给外部的相机作为预览的输出,作为OpenGL ES的纹理输入渲染到GLSurfaceView上。

    问题:

    1. 绘制出来的图像方向不对的问题,需要将纹理坐标顺时针旋转90°才能解决,但是这样处理肯定是不行的。
      猜想:
      1).可能是相机预览的问题?(否决,如果这样的话,a方案也会有问题)
      2).OES纹理导致的问题?OES纹理坐标系和普通2D坐标系不同?(可能yuv格式向rgb格式转换的时候发生的)
      解决方案:是在OpenGL中矩阵变换顺时针旋转90度即可。(原因尚未搞明白)

    2. 切换滤镜会黑屏一会。
      原因:切换滤镜生成了新的纹理,返回了新的SurfaceTexture给 Camera重新设置预览,从而导致黑屏。
      解决方案:使用新滤镜时复用老滤镜的TextureId和SurfaceTexture,以及从老滤镜中继承相应的滤镜参数配置,从而可实现无缝切换。

  2. 视频硬解码渲染

    实现一个视频播放器,使用MediaCodec将视频解码后交给OpenGL处理然后渲染到GLSurfaceView上。MediaCodec的输出Surface需要从BaseFilter回调提供SurfaceTexture生成,同时监听SurfaceTexture的帧,可用的时候即渲染当前帧到GLSurfaceView。因此,BaseFilter需要拓展对外提供SurfaceTexture回调和设置渲染监听。

总结:

  1. 相机的预览加滤镜,开始最容易想到的的确是a方案,实现以后不免也容易想到,但是性能不好。而b方案这种实现,是不能使用2D纹理的,从camera拿到的数据是yuv格式的从而需要拓展类中的OES 纹理来将yuv转化为OpenGL能渲染的rgb格式。而之前实现的BaseFilter类是不兼容OES纹理的,因此需要对此进行拓展,对外提供选择渲染纹理的类型。
  2. 视频硬解码渲染,音频和视频的解码流程差不多,只是解码输出一个给OpenGL es处理,一个给AudioTrack进行播放而已。上层的API已经封装的很好了,因此更应该关注一下其内部的实现,诸如inputBuffer和outputBuffer 的实现以及其他的一些原理。

之后的学习计划

内容:
1. 滤镜类(BaseFilter)的进一步优化和封装。
2. 完善播放器的功能(进度条、暂停、音量、水印、视频导出、视频倒放等)
3. 离屏渲染的实际应用

全部评论

相关推荐

点赞 评论 收藏
转发
点赞 2 评论
分享
牛客网
牛客企业服务