iOS OpenGL ES两种方式绘制图片

移动端的音视频发展已逐渐渗透到各行各业,本人目前所就职的公司业务刚好有触及到这一块,但是目前项目更偏向使用SDK会多一些,小部分业务会使用苹果提供的AVFoundation对视频加以处理。

从网上获悉到有很多播放器都是基于FFMpeg去进行的二次开发,抱着对自己知识边际的扩展的初衷,于是在闲暇之余也去尝试使用FFMpeg对视频文件进行了解码操作,YUV的数据渲染使用的是OpenGL ES,由于之前没有接触过OpenGL ES,于是写此篇文章来记录总结下OpenGL ES的使用步骤

网上有关入门OpenGL ES的文章有很多,此篇就不过多重复,本篇文章侧重于记录在使用OpenGL ES过程中通过两种方式来绘制图片时遇到的一些问题,方便跟我一样对OpenGL ES感兴趣的初学者能够尽快上手,demo链接附在文章末尾处

  • 首先一个比较重要的点就是关于OpenGL ES的坐标系,OpenGL ES存在两种坐标系

1、OpenGL ES 坐标系



OpenGL ES 坐标系的范围是 -1 ~ 1,是一个三维的坐标系,通常用 X、Y、Z 来表示。Z 轴的正方向指向屏幕外。在不考虑 Z 轴的情况下,左下角为 (-1, -1, 0),右上角为 (1, 1, 0)。

2、纹理坐标系



纹理坐标系的范围是 0 ~ 1,是一个二维坐标系,横轴称为 S 轴,纵轴称为 T 轴。在坐标系中,点的横坐标一般用 U 表示,点的纵坐标一般用 V 表示。左下角为 (0, 0),右上角为 (1, 1)。

接下来要提一下着色器的注意点

  • 之前有提到过本文是通过两种不同的方式来绘制图片,这两种不同的方式其实就是两种不同形式的着色器,一种是苹果GLKit提供的着色器GLKBaseEffect,另一种则是使用GLSL语言自定义的着色器。

  • 自定义的着色器会有两个文件,通常后缀名为.vsh.fsh,代表顶点着色器和片元着色器。有些项目中这两个文件的后缀名可能为.glsl,如果同为.glsl的文件,则通过文件内的变量gl_Position和gl_FragColor来区分,包含gl_Position的变量为顶点着色器,包含gl_FragColor的变量为片元着色器

  • 将顶点数据传入到顶点着色器中时,注意传入参数“positon”,这个"position"代表的是顶点着色器文件中申明的变量名,要与其保持一直

GLuint position = glGetAttribLocation(_program, "position");

demo中.vsh文件中声明如下

//顶点坐标
attribute vec4 position;

片元数据的处理同理

GLuint textCoord = glGetAttribLocation(_program, "textCoordinate");

demo中.fsh文件中声明如下

//这个就是刚才从顶点着色器传过来的纹理坐标,注意这里最好直接复制过来,因为一个字母都不许差
varying lowp vec2 varyTextCoord;
  • 在设置顶点坐标时,如果想让图片填充整个窗口,依据OpenGL ES坐标系,其坐标范围为(0 ~ 1),我们只需将每个角的坐标值控制在0或者1即可
GLfloat vertexArr[] = {
        
        1.f,-1.f,0.f,   1.f,0.f,
        -1.f,1.f,0.f,   0.f,1.f,
        -1.f,-1.f,0.f,  0.f,0.f,
        
        1.f,1.f,0.f,    1.f,1.f,
        -1.f,1.f,0.f,   0.f,1.f,
        1.f,-1.f,0.f,   1.f,0.f
        
    };
  • 但是这样加载出来的图片与原始图片比例不符,导致图片严重变形,所以需要根据图片尺寸与窗口尺寸进行适配,适配的结果传入顶点坐标数组中
CGRect realRect = AVMakeRectWithAspectRatioInsideRect(image.size, self.bounds);
    
// 按照图片比例与屏幕比例进行适配
CGFloat widthRatio = realRect.size.width/self.bounds.size.width;
CGFloat heightRatio = realRect.size.height/self.bounds.size.height;
  • OpenGL ES中图元有三个:点,线段,三角形,一般情况下有三种绘制一系列三角形的方式,分别是GL_TRIANGLES、GL_TRIANGLE_STRIP和GL_TRIANGLE_FAN


demo中采用的是GL_TRIANGLES,因为用两个三角形绘制一个矩形,所以顶点坐标数组中传入6个数据,如果是使用GL_TRIANGLE_STRIP或者GL_TRIANGLE_FAN,则只需传入4个数据到顶点坐标数组中

    // GL_TRIANGLE_STRIP
    GLfloat vertexArr[] = {
        -widthRatio, -heightRatio, 0, 0.f, 0.f,  //左下
        widthRatio,  -heightRatio, 0, 1.f, 0.f,  //右下
        -widthRatio, heightRatio,  0, 0.f, 1.f,  //左上
        widthRatio,  heightRatio,  0, 1.f, 1.f   //右上
    };
  • 前文提到过的纹理坐标系,因与UIKit坐标系不一致,所以绘制出来的图片可能会呈现翻转的效果,所以还需要额外做下处理,处理方法可以参考这里

demo地址

参考文章:
https://www.jianshu.com/c/238381ce426d

你可能感兴趣的:(iOS OpenGL ES两种方式绘制图片)