音视频- iOS使用metal渲染图像(一)

news/2024/11/18 2:40:57/

概要   

        本文主要总结一下Metal的基本使用,用来渲染拍照的到的图像,其中涉及到的有UIKit中的MTKView,Metal中负责渲染的几个类,使用MSL(Metal  Shading Language)编写着色器,最终将图片渲染出来。这一篇先简介一下Metal的工作流程。

Metal对图像的处理流程

       图像的最小单位可以认为是像素,一幅图片由若干像素组成,每个像素在图片中都有一个位置,也就是该像素的坐标。二维下也就是(x,y),三维下也就是(x,y,x)。所以Metal对图像处理,其实就是对每个像素的处理。

        Metal的处理流程简化可以表示成以下这张图,从最左侧的Vertices是提供的初始的顶点数据,经过Vertex function处理

        和OpenGL中类似,Metal中的Vertex stage可以理解为OpenGL中的顶点处理阶段,主要来进行坐标转换,Vertex function就是此阶段实现的方法,同样,fragment stage对应到片段处理阶段,主要计算点的颜色值Fragment function就是此阶段实现的方法。所以Vertex fucntion和fragment function也就对应上了OpenGL中的顶点着色器和片段着色器。只不过编写的语言使用的是Metal的MSL,不再是glsl。

        在顶点处理阶段,有几个坐标需要先明确一下,首先是在使用UIKit布局的时候,通常是以左上角为(0,0),而右下角是(1,1);同时,在使用纹理的时候,对应的纹理也有一个自己的坐标系,在Metal中叫做标准纹理坐标,如下图: 

左上角为(0,0),右下角为(1,1);Metal最终进行绘制的时候,使用的另一种坐标系,就是标准化设备坐标,和上面的就不太一样,如下图:

 在只有2D情况下,中心点是(0,0),左下角是(-1,-1),右上角是(1,1),在3D情况下,z就是表示距离屏幕的距离。结合上面的标准化纹理坐标,如果要将纹理布满整个Metal的绘制范围,那么就需要将四个角的坐标对应上,也就是:

纹理坐标:(0,0)         设备坐标:(-1,1)

纹理坐标:(1,0)         设备坐标:(1,1)

纹理坐标:(0,1)         设备坐标:(-1,-1)

纹理坐标:(1,1)         设备坐标:(1,-1)

这样,就能将纹理中布满整个渲染空间范围,而这个,也就是vertex function主要要做的事情,我举的这个例子是最简单的,实际情况中肯定会很复杂,而且vertex function计算出来的坐标,有时候超过-1~1的这个区间,而这个时候,中间的光栅化器(Rasterization)就发挥作用了。

        光栅化器要做的就是,将vertex function得到的所有坐标以标准化设备坐标为边界进行选取,超出标准化设备坐标的点,一律去掉,并且将范围内的点转换成屏幕上对应的像素。将这些有效像素传递到下一个阶段。

        fragment function接下来登场了,这里面就是将光栅化器筛选出来的有效像素进行上色,当然,具体怎么上色,这个就需要根据实际情况来看,这也就是我们实现自己上色逻辑的重要部分。

        关于vertex function和fragment function的例子,放到下一章实践的时候再看。从纹理坐标到设备坐标,这个主要是针对图像的渲染。试想一个场景,我在一个MTKView上点击了一个点,或者用手指画了一条线,如何使用Metal来绘制呢?我也是突然想到的,以后实现之后再看吧。上面的部分是Metal渲染的概念部分,下面看下Metal中具体实现这个过程,涉及到的一些东西。

 Metal实现绘制的组件

 MTLDevice    

        Metal使用GPU来进行绘制,这个MTLDevice就代表了给当前绘制分配的设备,官方文档中说到这个就相当于一个GPU。这个device主要提供了一些方法,主要有三个方面

  1. 查询设备状态
  2. 创建设备相关的绘制资源,比如缓冲区,纹理等等
  3. 执行渲染的命令

下面是一些代码例子,这几个后面都会介绍:

let defaultLibrary = self.renderDevice.makeDefaultLibrary()let pipelineState = try! self.renderDevice.makeRenderPipelineState(descriptor: pipelineStateDesc)let vertices = self.renderDevice.makeBuffer(bytes: vertexArr!,length: MemoryLayout<AVImageVertex>.size * 6,options: .storageModeShared)

MTLCommandQueue、MTLCommandBuffer、MTLCommandEncoder

        这三个放到了一起,因为它们配合起来完成实际的绘制过程。首先commandQueue是由上面的device创建,从名字能看出来,是一个队列,那么这个队列里面是什么呢?就是commandBuffer。若干commandBuffer的顺序由这个commandQueue来组织,然后依次执行。

        然后是commandBuffer,是个啥呢?它的主要作用是创建commandEncoder,以及在commandEncoder工作完成之后,将所有渲染命令提交,进入commandQueue中。

        那么commandEncoder是干什么的呢?它的主要就是决定了绘制的具体操作,包括需要的顶点资源,绘制的方式(点、线、三角形)等等,具体的绘制都由它管。commandBuffer支持三种commandEncoder。官方文档中特别提到一点,在一个commandBuffer中,某一个时刻只能有一个commandEncoder处于激活状态,这一点我暂时还没有什么体会,后面使用中再慢慢了解吧。我的例子里面只使用了负责图形绘制的MTLRenderCommandEncoder,对其他感兴趣的可以自行去了解。

        然后用一张官方的大图来看下这个绘制的结构:

这个图还是比较清晰的,我会面会根据代码来一步一步地对应上去。 图中有些地方没有介绍到,后面涉及到的我会特别提到

MTKView

        这个是将Metal的工作和UI框架相联系的一个东西,一方面继承自UIView,参与UIKit中的工作,一方面实现了Metal的协议,参与Metal绘制的逻辑工作,还是挺重要的,其实用起来比较方便。使用这个类需要实现一个协议:MTKViewDelegate,必须实现其中的两个方法

  1. func mtkView(MTKView, drawableSizeWillChange: CGSize),这个方法主要是在布局发生改变,需要重新调整View大小的时候,会被调用,传入的drawableSizeWillChange就是新的尺寸;
  2. func draw(in: MTKView) 这个方法中通常就是具体的绘制操作,也就是前面提到的使用commandQueue、commandBuffer以及commandEncoder的地方。

结束

        以上主要从Metal绘制流程,绘制的功能组件以及UIKit中的MTKView这三个方面简介使用Metal的几个主要部分,接下来,后来的会从我自己的使用过程,来具体看看Metal绘制的流程。

如果有不对的地方,欢迎大家指正,相互学习,共同进步吧。


http://www.ppmy.cn/news/3827.html

相关文章

三面美团 Java 岗,HR 现场直接发 offer,他是横着走出来的

前情提要 这是一个发生在我朋友身上的真实事情&#xff1a; 这里就叫他程序员 Y 吧。 程序员 Y 工作不到两年&#xff0c;周末在朋友圈发了个喜报&#xff0c;准备入职美团。 之后&#xff0c;我就带着祝福跟 Y 聊了许久&#xff0c;聊天的内容就是具体了解一下他面试的过程…

Python实现批量采集美女视*频 <无水印>

前言 大家早好、午好、晚好吖 ❤ ~ 我给大家准备了一些资料&#xff0c;包括: 2022最新Python视频教程、Python电子书10个G &#xff08;涵盖基础、爬虫、数据分析、web开发、机器学习、人工智能、面试题&#xff09;、Python学习路线图等等 直接在文末名片自取即可&#x…

python大作业高分项目--射击闯关游戏

项目功能&#xff1a; 地图编辑器&#xff1a;可以实现玩家自己定义每一关卡的样式和难易程度 运行界面&#xff1a;实现了玩家的移动&#xff0c;跳跃&#xff0c;发射子弹&#xff0c;投掷手雷&#xff0c;以及敌人的AL&#xff08;移动&#xff0c;发射子弹&#xff0c;扔…

【大数据技术Hadoop+Spark】MapReduce概要、思想、编程模型组件、工作原理详解(超详细)

MapReduce是Hadoop系统核心组件之一&#xff0c;它是一种可用于大数据并行处理的计算模型、框架和平台&#xff0c;主要解决海量数据的计算&#xff0c;是目前分布式计算模型中应用较为广泛的一种。 一、MapReduce核心思想 MapReduce的核心思想是“分而治之”。所谓“分而治之…

PostgreSQL的学习心得和知识总结(一百一十七)|语法级自上而下完美实现MySQL数据库的 label:loop 的实现方案

目录结构 注:提前言明 本文借鉴了以下博主、书籍或网站的内容,其列表如下: 1、参考书籍:《PostgreSQL数据库内核分析》 2、参考书籍:《数据库事务处理的艺术:事务管理与并发控制》 3、PostgreSQL数据库仓库链接,点击前往 4、日本著名PostgreSQL数据库专家 铃木启修 网站…

测试用例等级怎么划分?别再傻傻的一脸懵逼

我们都知道测试工程师最基本的能力便是编写测试用例&#xff0c;可是看似简单的用例&#xff0c;后面其实蕴含这个很多人忽略的细节&#xff0c;今天就来说测试里面所蕴含的很多细节。 很多时候不只是测试和测试用例息息相关&#xff0c;开发&#xff0c;产品也有的时候对于测试…

类加载器、类加载器的过程、类加载的分类、双亲委派模型

文章目录1.类加载器1.1类加载器1.2类加载的过程1.3类加载的分类1.4 双亲委派模型1.5 ClassLoader 中的两个方法1.类加载器 1.1类加载器 作用 负责将.class文件&#xff08;存储的物理文件&#xff09;加载到内存中 1.2类加载的过程 类加载时机 创建类的实例&#xff08;对象…

新产品开发流程管理_以市场为驱动

第1章 创新的挑战 1.1 挑战&#xff1a;如何真正做到创新 企业都有不凡的成长目标。 引发成长的四种来源&#xff1a; **- 市场成长 市场份额增长新市场的出现收购** 以上四种来源获得企业成长困难且代价高。 **市场成长&#xff1a;**很多工业化国家和行业中的市场是成熟…