当前位置: 首页 > 编程日记 > 正文

教你实现GPUImage【OpenGL渲染原理】

一、前言

本篇主要讲解GPUImage底层是如何渲染的,GPUImage底层使用的是OPENGL,操控GPU来实现屏幕展示

由于网上OpenGL实战资料特别少,官方文档对一些方法也是解释不清楚,避免广大同学再次爬坑,本篇讲解了不少OpenGL的知识,并且还讲解了花了大量时间解决bug的注意点,曾经因为对glDrawArrays这个方法不熟悉,遇上Bug,晚上熬到凌晨四点都没解决,还是第二天中午解决的。

如果喜欢我的文章,可以关注我微博:袁峥Seemygo

二、GPUImageVideoCamera

  • 可以捕获采集的视频数据
  • 关键是捕获到一帧一帧视频数据如何展示?
  • 通过这个方法可以获取采集的视频数据

  • 采集视频注意点:要设置采集竖屏,否则获取的数据是横屏
  • 通过AVCaptureConnection就可以设置

三、自定义OpenGLView渲染视频

  • 暴露一个接口,获取采集到的帧数据,然后把帧数据传递给渲染View,展示出来

四、利用OpenGL渲染帧数据并显示

  • 导入头文件#import ,GLKit.h底层使用了OpenGLES,导入它,相当于自动导入了OpenGLES
  • 步骤
    • 01-自定义图层类型
    • 02-初始化CAEAGLLayer图层属性
    • 03-创建EAGLContext
    • 04-创建渲染缓冲区
    • 05-创建帧缓冲区
    • 06-创建着色器
    • 07-创建着色器程序
    • 08-创建纹理对象
    • 09-YUV转RGB绘制纹理
    • 10-渲染缓冲区到屏幕
    • 11-清理内存

01-自定义图层类型

  • 为什么要自定义图层类型CAEAGLLayer? CAEAGLLayer是OpenGL专门用来渲染的图层,使用OpenGL必须使用这个图层

02-初始化CAEAGLLayer图层属性

  • 1.不透明度(opaque)=YES,CALayer默认是透明的,透明性能不好,最好设置为不透明.
  • 2.设置绘图属性
    • kEAGLDrawablePropertyRetainedBacking :NO (告诉CoreAnimation不要试图保留任何以前绘制的图像留作以后重用)
    • kEAGLDrawablePropertyColorFormat :kEAGLColorFormatRGBA8 (告诉CoreAnimation用8位来保存RGBA的值)
  • 其实设置不设置都无所谓,默认也是这个值,只不过GPUImage设置了

03-创建EAGLContext

  • 需要将它设置为当前context,所有的OpenGL ES渲染默认渲染到当前上下文
  • EAGLContext管理所有使用OpenGL ES进行描绘的状态,命令以及资源信息,要绘制东西,必须要有上下文,跟图形上下文类似。
  • 当你创建一个EAGLContext,你要声明你要用哪个version的API。这里,我们选择OpenGL ES 2.0

04-创建渲染缓冲区

  • 有了上下文,openGL还需要在一块buffer进行描绘,这块buffer就是RenderBuffer
  • OpenGLES 总共有三大不同用途的color buffer,depth buffer 和 stencil buffer.
  • 最基本的是color buffer,创建它就好了
函数glGenRenderbuffers

  • 它是为renderbuffer(渲染缓存)申请一个id(名字),创建渲染缓存
  • 参数n表示申请生成renderbuffer的个数
  • 参数renderbuffers返回分配给renderbuffer(渲染缓存)的id
    。 注意:返回的id不会为0,id 0 是OpenGL ES保留的,我们也不能使用id 为0的renderbuffer(渲染缓存)。
函数glBindRenderbuffer

  • 告诉OpenGL:我在后面引用GL_RENDERBUFFER的地方,其实是引用_colorRenderBuffer
  • 参数target必须为GL_RENDERBUFFER
  • 参数renderbuffer就是使用glGenRenderbuffers生成的id
    。 当指定id的renderbuffer第一次被设置为当前renderbuffer时,会初始化该 renderbuffer对象,其初始值为:

函数renderbufferStorage

  • 把渲染缓存(renderbuffer)绑定到渲染图层(CAEAGLLayer)上,并为它分配一个共享内存。
  • 参数target,为哪个renderbuffer分配存储空间
  • 参数drawable,绑定在哪个渲染图层,会根据渲染图层里的绘图属性生成共享内存。

实战代码

05-创建帧缓冲区

  • 它相当于buffer(color, depth, stencil)的管理者,三大buffer可以附加到一个framebuffer上
  • 本质是把framebuffer内容渲染到屏幕
函数glFramebufferRenderbuffer

  • 该函数是将相关buffer()三大buffer之一)attach到framebuffer上,就会自动把渲染缓存的内容填充到帧缓存,在由帧缓存渲染到屏幕
  • 参数target,哪个帧缓存
  • 参数attachment是指定renderbuffer被装配到那个装配点上,其值是GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT中的一个,分别对应 color,depth和 stencil三大buffer。
  • renderbuffertarget:哪个渲染缓存
  • renderbuffer渲染缓存id

06-创建着色器

着色器
  • 什么是着色器? 通常用来处理纹理对象,并且把处理好的纹理对象渲染到帧缓存上,从而显示到屏幕上。
  • 提取纹理信息,可以处理顶点坐标空间转换,纹理色彩度调整(滤镜效果)等操作。
  • 着色器分为顶点着色器,片段着色器
    • 顶点着色器用来确定图形形状
    • 片段着色器用来确定图形渲染颜色
  • 步骤: 1.编辑着色器代码 2.创建着色器 3.编译着色器
  • 只要创建一次,可以在一开始的时候创建
着色器代码

实战代码

07-创建着色器程序

  • 步骤: 1.创建程序 2.贴上顶点和片段着色器 3.绑定attribute属性 4.连接程序 5.绑定uniform属性 6.运行程序
  • 注意点:第3步和第5步,绑定属性,必须有顺序,否则绑定不成功,造成黑屏

08-创建纹理对象

纹理

  • 采集的是一张一张的图片,可以把图片转换为OpenGL中的纹理, 然后再把纹理画到OpenGL的上下文中
  • 什么是纹理?一个纹理其实就是一幅图像。
  • 纹理映射,我们可以把这幅图像的整体或部分贴到我们先前用顶点勾画出的物体上去.
  • 比如绘制一面砖墙,就可以用一幅真实的砖墙图像或照片作为纹理贴到一个矩形上,这样,一面逼真的砖墙就画好了。如果不用纹理映射的方法,则墙上的每一块砖都必须作为一个独立的多边形来画。另外,纹理映射能够保证在变换多边形时,多边形上的纹理图案也随之变化。
  • 纹理映射是一个相当复杂的过程,基本步骤如下:
    • 1)激活纹理单元、2)创建纹理 、3)绑定纹理 、4)设置滤波
  • 注意:纹理映射只能在RGBA方式下执行
函数glTexParameter

  • 控制滤波,滤波就是去除没用的信息,保留有用的信息
  • 一般来说,纹理图像为正方形或长方形。但当它映射到一个多边形或曲面上并变换到屏幕坐标时,纹理的单个纹素很少对应于屏幕图像上的像素。根据所用变换和所用纹理映射,屏幕上单个象素可以对应于一个纹素的一小部分(即放大)或一大批纹素(即缩小)
  • 固定写法

函数glPixelStorei

  • 设置像素存储方式
  • pname:像素存储方式名
  • 一种是GL_PACK_ALIGNMENT,用于将像素数据打包,一般用于压缩。
  • 另一种是GL_UNPACK_ALIGNMENT,用于将像素数据解包,一般生成纹理对象,就需要用到解包.
  • param:用于指定存储器中每个像素行有多少个字节对齐。这个数值一般是1、2、4或8,
    一般填1,一个像素对应一个字节;
函数CVOpenGLESTextureCacheCreateTextureFromImage

  • 根据图片生成纹理
  • 参数allocator kCFAllocatorDefault,默认分配内存
  • 参数textureCache 纹理缓存
  • 参数sourceImage 图片
  • 参数textureAttributes NULL
  • 参数target , GL_TEXTURE_2D(创建2维纹理对象)
  • 参数internalFormat GL_LUMINANCE,亮度格式
  • 参数width 图片宽
  • 参数height 图片高
  • 参数format GL_LUMINANCE 亮度格式
  • 参数type 图片类型 GL_UNSIGNED_BYTE
  • 参数planeIndex 0,切面角标,表示第0个切面
  • 参数textureOut 输出的纹理对象
      实战代码

      09-YUV转RGB绘制纹理

      • 纹理映射只能在RGBA方式下执行
      • 而采集的是YUV,所以需要把YUV 转换 为 RGBA,
      • 本质其实就是改下矩阵结构
      • 注意点(熬夜凌晨的bug):glDrawArrays如果要绘制着色器上的点和片段,必须和着色器赋值代码放在一个代码块中,否则找不到绘制的信息,就绘制不上去,造成屏幕黑屏
      • 之前是把glDrawArrays和YUV转RGB方法分开,就一直黑屏.
      函数glUniform1i

      • 指定着色器中亮度纹理对应哪一层纹理单元
      • 参数location:着色器中纹理坐标
      • 参数x:指定那一层纹理
      函数glEnableVertexAttribArray

      • 开启顶点属性数组,只有开启顶点属性,才能给顶点属性信息赋值
      函数glVertexAttribPointer

      • 设置顶点着色器属性,描述属性的基本信息
      • 参数indx:属性ID,给哪个属性描述信息
      • 参数size:顶点属性由几个值组成,这个值必须位1,2,3或4;
      • 参数type:表示属性的数据类型
      • 参数normalized:GL_FALSE表示不要将数据类型标准化
      • 参数stride 表示数组中每个元素的长度;
      • 参数ptr 表示数组的首地址
      函数glBindAttribLocation

      • 给属性绑定ID,通过ID获取属性,方便以后使用
      • 参数program 程序
      • 参数index 属性ID
      • 参数name 属性名称
      函数glDrawArrays

      • 作用:使用当前激活的顶点着色器的顶点数据和片段着色器数据来绘制基本图形
      • mode:绘制方式 一般使用GL_TRIANGLE_STRIP,三角形绘制法
      • first:从数组中哪个顶点开始绘制,一般为0
      • count:数组中顶点数量,在定义顶点着色器的时候,就定义过了,比如vec4,表示4个顶点
      • 注意点,如果要绘制着色器上的点和片段,必须和着色器赋值代码放在一个代码块中,否则找不到绘制的信息,就绘制不上去,造成屏幕黑屏。
      实战代码

      10-渲染缓冲区到屏幕

      • 注意点:必须设置窗口尺寸glViewport
      • 注意点:渲染代码必须调用[EAGLContext setCurrentContext:_context]
      • 原因:因为是多线程,每一个线程都有一个上下文,只要在一个上下文绘制就好,设置线程的上下文为我们自己的上下文,就能绘制在一起了,否则会黑屏.
      • 注意点:每次创建纹理前,先把之前的纹理引用清空[self cleanUpTextures],否则卡顿
        函数glViewport

      • 设置OpenGL渲染窗口的尺寸大小,一般跟图层尺寸一样.
      • 注意:在我们绘制之前还有一件重要的事情要做,我们必须告诉OpenGL渲染窗口的尺寸大小
          方法presentRenderbuffer

          • 是将指定renderbuffer呈现在屏幕上
          实战代码

          11-清理内存

          • 注意:只要有Ref结尾的,都需要自己手动管理,清空
          函数glClearColor

          • 设置一个RGB颜色和透明度,接下来会用这个颜色涂满全屏.
          函数glClear

          • 用来指定要用清屏颜色来清除由mask指定的buffer,mask可以是 GL_COLOR_BUFFER_BIT,GL_DEPTH_BUFFER_BIT和GL_STENCIL_BUFFER_BIT的自由组合。
          • 在这里我们只使用到 color buffer,所以清除的就是 clolor buffer。

          GPUImage工作原理

          • GPUImage最关键在于GPUImageFramebuffer这个类,这个类会保存当前处理好的图片信息。
          • GPUImage是通过一个链条处理图片,每个链条通过target连接,每个target处理完图片后,会生成一个GPUImageFramebuffer对象,并且把图片信息保存到GPUImageFramebuffer。
          • 这样比如targetA处理好,要处理targetB,就会先取出targetA的图片,然后targetB在targetA的图片基础上在进行处理.

      相关文章:

      构建之法阅读笔记02

      在这次的阅读过程中我了解到了如何给别人提意见,给我最大的启发是乔布斯对其下属提意见的小故事,当其下属把iphone的图标都设计成了矩形的时候,乔布斯建议他把图标设计成带圆角的正方形,而其下属一开始却并没有接受乔的意见&#…

      Windows Server 2008 R2 配置笔记,密码设置为任意长度,远程桌面终端连接数的设置...

      图片显示不完全时,可在新标签页打开。 Windows Server 2008 R2 配置{ 安装企业版(Enterprise Editon),因为企业版功能全面,并且比数据中心版更容易配置{ 各版本功能概述在版本概览页面。详细参数对比在版本概览页面右边有链接&…

      html5图片灰度显示,HTML5 组件Canvas实现图像灰度化

      HTML5发布已经有很长一段时间了,一直以来从来没有仔细的看过,过年刚来随便看看发现HTML5中的Canvas组件功能是如此的强大,不怪很多牛人预言Flash已死,死不死不是我要关心的,我关心的Canvas可以很轻松在网页中实现简单相…

      SqlParameter参数方式操作数据库(存储过程)

      访问数据库: View Code using System; using System.Data; using System.Configuration; using System.Linq; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using Syst…

      视频编解码之理论概述 和即时通信

      前言 即时通讯应用中的实时音视频技术,几乎是IM开发中的最后一道高墙。原因在于:实时音视频技术 音视频处理技术 网络传输技术 的横向技术应用集合体,而公共互联网不是为了实时通信设计的。有关实时音视频开发时的技术难题请参见《音视频云…

      图论:关于二分图的总结(转载)

      二分图是这样一个图,它的顶点可以分类两个集合X和Y,所有的边关联在两个顶点中,恰好一个属于集合X,另一个属于集合Y。 最大匹配:图中包含边数最多的匹配称为图的最大匹配。 完美匹配:…

      动态加载的html没有js效果,JS利用html5实现loadding动态加载效果代码实例

      51前端window.οnlοadfunction(){var Loading function (canvas, options) {this.canvas document.getElementById(canvas);this.options options;};Loading.prototype{constructor: Loading,show: function(){var canvas this.canvas,begin this.options.begin,old thi…

      iOS 自动布局框架 – Masonry 详解

      来源:伯乐在线 - 刘小壮 如有好文章投稿,请点击 → 这里了解详情 如需转载,发送「转载」二字查看说明 目前iOS开发中大多数页面都已经开始使用Interface Builder的方式进行UI开发了,但是在一些变化比较复杂的页面,还是…

      GDC2016 Epic Games【Bullet Train】 新风格的VR-FPS的制作方法

      追求“舒适”和“快感”的VR游戏设计方法http://game.watch.impress.co.jp/docs/news/20160318_749016.html【Bullet Train】演讲的状况在游戏的创造历史上,有那种决定性的创新,以及高完成度的作品,对于FPS风格来说,【DOOM】就是这…

      例4-1和例4-2和例4-3

      public class ComputerCircleArea{ public static void main(String args[]){ double radius; double area; radius163.16; area3.14*radius*radius; System.out.printf("半径是%5.3f的圆的面积:\n%5.3f\n",radius,area); }} class Circle{ double radius; doubl…

      html中的两种标记,如何在html选项标记中实现两种不同的对齐?

      下面是一个单空间js解决方案,与scott everden的jquery示例一起使用。我只在firefox中测试过,但这应该足够开始了。javascriptvar MIN_SPACES_BETWEEN_VALS 3;function mkOption(left, right, total){var str left;var spaces total - left.length - right.length;for(x 0;x…

      html标签(2)--有序列表与无序列表

      有一些内容形式&#xff0c;用div来实现非常麻烦&#xff0c;也不适合 例如一些表格形式 无序列表 ul 代表列表 li 代表列表中的项 list-style 控制列表的样式 有序列表 ol 代表列表 li 代表列表中的项 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN…

      Swift3实现的绘制股票K线库, FastImageCache提升图片的加载和渲染速度,Chameleon颜色框架

      代码1:用Swift3实现的绘制股票K线库 for iOS & macOS代码地址&#xff1a;网页链接代码2:FastImageCache是Path团队开发的一个开源库&#xff0c;用于提升图片的加载和渲染速度&#xff0c;让基于图片的列表滑动起来更顺畅。代码地址&#xff1a;网页链接代码3&#xff1a;…

      传智播客还收费 兄弟会都是免费的

      【传智播客还收费 兄弟会都是免费的 兄弟连兄弟会it开发培训 www.itxdh.net 企鹅群&#xff1a;499956522 高端人才培养就到【兄弟连兄弟会it开发培训】纯免费的高端IT人才培养】 传智播客&#xff0c;一个多么具有戏剧性的词眼&#xff0c;以前张孝祥老师建校的初衷就是为了让…

      用计算机的英语造句process,process的用法总结大全

      process的意思n. 过程,工序,做事方法,工艺流程vt. 加工,处理,审阅,审核vi. 列队行进adj. 经过特殊加工(或处理)的变形&#xff1a;过去式: processed&#xff1b; 现在分词&#xff1a;processing&#xff1b; 过去分词&#xff1a;processed&#xff1b;process用法process可以…

      iOS进阶之页面性能优化

      作者: hi_xgb 地址: http://www.jianshu.com/p/1b5cbf155b31 前言 在软件开发领域里经常能听到这样一句话&#xff0c;“过早的优化是万恶之源”&#xff0c;不要过早优化或者过度优化。我认为在编码过程中时刻注意性能影响是有必要的&#xff0c;但凡事都有个度&#xff0c;不…

      LabelMe图像数据集下载

      Download MATLAB Toolbox for the LabelMe Image Database 利用Matlab Toolbox工具箱下载图像库 一、下载Matlab Toolbox工具箱 1. Github repository We maintain the latest version of the toolbox on github. To pull the latest version, make sure that "git" …

      win8计算机管理没有用户组,Win8右键计算机管理提示“该文件没有与之关联的程序”怎么办?...

      最近有Win8用户反映&#xff0c;右键计算机管理的时候&#xff0c;出现提示“该文件没有与之关联的程序来执行该操作”&#xff0c;这让用户非常苦恼。那么&#xff0c;Win8右键计算机管理提示“该文件没有与之关联的程序”怎么办呢&#xff1f;下面&#xff0c;我们就一起往下…

      Objective-C 自动生成文档工具:appledoc

      来源&#xff1a;iOS_小松哥 www.jianshu.com/p/fd4d8d6b6177 如有好文章投稿&#xff0c;请点击 → 这里了解详情 由于最近琐事比较多&#xff0c;所以好久没有写文章了。今天我们聊一聊Objective-C自动生成文档。 做项目的人多了&#xff0c;就需要文档了。手工写文档是一件…

      linux命令--提升

      查看系统进程&#xff1a;top 查看磁盘空间&#xff1a; df -h 查询系统负载: uptime , 以下显示输入uptime的信息&#xff1a; 04:03:58 up 10 days, 13:19, 1 user, load average: 0.54, 0.40, 0.20 1.当前时间 04:03:58 2.系统已运行的时间 10 days, 13:19 3.前在线用户…

      git 从远程主服务器当中创建新分支

      现有版本; h20, h28&#xff0c;h26,i8 h28&#xff0c;h26,i8是从H20下面创建的。 需求: 从H28下面创建新分支继续开发。 思路&#xff1a; 所有代码均是放置到H20上仓库当中&#xff0c;首先下载H20完整仓库&#xff0c;也就是.git文件夹当中内容&#xff0c;其本质是一个ZIP…

      涉密计算机用户账号设置审批表,北京邮电大学涉密计算机配置审批表.PDF

      北京邮电大学涉密计算机配置审批表北京邮电大学涉密计算机配置审批表使用部门 品牌型号涉密计算机类型 ?台式机 ?便携机 资产编号用途 ?科研 ?办公 ?其他 配置日期硬盘序列号中央处理器硬盘容量CPU基本配置 内 存显示器品牌型号MAC 地址操作系统版本 操作系统安装时间放置…

      Oracle 正则表达式

      ORACLE中的支持正则表达式的函数主要有下面四个&#xff1a;1&#xff0c;REGEXP_LIKE &#xff1a;与LIKE的功能相似2&#xff0c;REGEXP_INSTR &#xff1a;与INSTR的功能相似3&#xff0c;REGEXP_SUBSTR &#xff1a;与SUBSTR的功能相似4&#xff0c;REGEXP_REPLACE &#x…

      制作 Swift 和 Objective-C Mixed 的 Pod

      来源&#xff1a;南栀倾寒 www.jianshu.com/p/c7623c31d77b 如有好文章投稿&#xff0c;请点击 → 这里了解详情 知识背景 What is CocoaPods&#xff08;https://guides.cocoapods.org/using/getting-started.html&#xff09; What did CocoaPods do&#xff1f;&#x…

      SearchRequestBuilder常用方法说明

      SearchRequestBuilder常用方法说明 (1) setIndices(String... indices)&#xff1a;上文中描述过&#xff0c;参数可为一个或多个字符串&#xff0c;表示要进行检索的index&#xff1b;(2) setTypes(String... types)&#xff1a;参数可为一个或多个字符串&#xff0c;表示要进…

      计算机知识课后反思,计算机硬件和软件知识课后反思

      计算机硬件和软件知识课后反思《计算机系统组成》—计算机硬件和软件知识一课是七年级信息技术中《信息技术基础》里的知识。在学习这之前&#xff0c;学生虽然都使用过计算机&#xff0c;但对于计算机的系统组成、主机内的硬件知识基本知之甚少。但是对这些知识学生又充满了好…

      iOS超全开源框架、项目和学习资料汇总:UI篇

      2017-01-30 iOS巍 CocoaChina原文 上下拉刷新控件 1. MJRefresh --仅需一行代码就可以为UITableView或者CollectionView加上下拉刷新或者上拉刷新功能。可以自定义上下拉刷新的文字说明。&#xff08;推荐&#xff09; 2. SVPullToRefresh --下拉刷新控件4500star&#xff0c;…

      NYOJ 90 —— 求正整数n划分为若干个正整数的划分个数

      整数划分 时间限制&#xff1a;3000 ms | 内存限制&#xff1a;65535 KB描述将正整数n表示成一系列正整数之和&#xff1a;nn1n2…nk&#xff0c; 其中n1≥n2≥…≥nk≥1&#xff0c;k≥1。 正整数n的这种表示称为正整数n的划分。求正整数n的不 同划分个数。 例如正整数6有如…

      调整命令行的列数和行数 mode con: cols=100 lines=10000

      mode con: cols100 lines10000转载于:https://www.cnblogs.com/passer1991/archive/2013/03/25/2980285.html

      写一个 iOS 复杂表单的正确姿势

      前言 这几天项目的新需求中有个复杂的表单界面&#xff0c;在做的过程中发现要比想象中复杂很多&#xff0c;有好多问题需要处理。有很多东西值得写下来好好梳理下。 需求分析&#xff1a; 6创建网店1.png上图便是UI根据需求给的高保真&#xff0c; 我们先根据这张图片来描述一…