iOS 开发者的 Metal 养成计划「6」 —— 利用 MetalKit 解决图片纹理和三维模型兼容性的痛点
发布于:2018-03-07 12:11,阅读数:1578,点赞数:0
# 引言 说完了 Metal 的各种细节,该说说如何更有效地开发 Metal 应用了。在开发 OpenGL 应用时,苹果提供了`GLKit`来帮助开发者。同样的,苹果为开发者提供了`MetalKit`来帮助开发者更快地开发应用。 附:文章小结中会提供一个持续更新的非常适合初学者的关于 Metal 的教程网站,欢迎订阅后查看。 # MetalKit > Build Metal apps quicker and easier, using far less code. Render graphics in a standard Metal view, load textures from many sources, and work efficiently with models provided by Model I/O. MetalKit 主要干了两件事: - 能让开发者使用更少的代码,更快速地开发 Metal App。 - 提供了绘制 Metal 图形的标准 View、加载纹理以及加载模型的标准工具库。 以上是在开发 Metal App 过程中几乎都会使用到的。 ## MTKView 和`GLKit`中提供的`GLKView`类似的,苹果提供了`MTKView`封装来方便开发者使用。 使用`MTKView`的方法很简单,大概步骤如下: - 构造`MTKView`对象并且作为子 View 添加到容器中。 - 设置`delegate`属性,用于回调。`func draw(in view: MTKView)`方法会在需要重绘时被自动调用。 - 设置`device`属性,可使用`MTLCreateSystemDefaultDevice()`方法获得默认`device`。 - 在`func draw(in view: MTKView)`方法中添加绘制命令。 在之前的文章中提到过,在编码渲染命令阶段会需要一个`MTLRenderPassDescriptor`对象,如果使用`MTKView`,那么这个对象可以直接通过`currentRenderPassDescriptor`属性取到。 使用`MTKView`,开发者需要关心的就仅仅是在`draw`方法里添加绘制代码即可。 ## MTKTextureLoader 正如`MTKTextureLoader`的字面意思,用于加载纹理。 #### 图片文件 对于不了解图形的初学者来说,加载图片到图形引擎中并不是那么容易理解。开发者们平时接触最多的图片大概是`jpg`、`png`等一系列格式的图片。这些文件都是经过特定编码器编码的,它们文件本身的数据并不是图形引擎可读的数据。如果需要使用它们,需要经过`libjpeg`、`libpng`等库对图片进行解码,获得解码后的图形数据。 #### 像素格式 由于图片本身包含的通道数、颜色格式各不相同,解码后的数据也并不一定是大家最熟悉的`RGBA`数据。有的图像也许是不包含透明通道的`RGB`格式,有的图像是苹果系统默认的`BGR`格式,还有`YCbCr`、`CMYK`、灰度等各种像素格式。 除此之外,像素对应每一个颜色值也未必是一个字节。最容易让大众理解的就是`RGBA8888`格式,一个像素点有 RGBA 四个通道,各占用`8位`即`1个字节`长度,那么一个像素点的数据就是`4个字节`。也有`RGBA6666`等格式,一个通道只占用`6位`,一个像素点一共占用`3个字节`。 #### 字节对其 那么知道了某个像素格式一个像素占用的内存大小,那么像素数据的大小该如何计算呢?再以`RGBA8888`举例,一个像素点占用`4个字节`,再乘上分辨率就是这个图片所占的大小了。但也并非所有的图片都可以用每个像素所占的字节数去乘分辨率去计算图片大小,这里涉及`bytesPerRow`的概念,大部分硬件在处理图片时都会有`字节对其`以确保最高性能,在每一行的数据不满足对其字节的情况下在每一行后面补充冗余数据(对其的字节数随硬件不同而不同)。这也就意味着行尾像素的下一个数据并不一定是下一行的第一个像素的数据,如果在不考虑字节对其的情况下强行喂数据,会出现像素点错位的现象:  #### 常规纹理加载 图片格式很复杂,但`MTKTextureLoader`可以助我们一臂之力,直接使用未解码的图片数据即可生成纹理,实现如下: ```swift guard let data = NSDataAsset.init(name: name)?.data else { // error } guard let texture = try? textureLoader.newTexture(data: data, options: nil) else { // error } ``` Metal 会帮助开发者解码文件并上传显存,生成的`MTLTexture`对象。此对象可以直接用于渲染命令绘制。 #### 其他 在上面的代码实现中,构造纹理的方法的第二个参数传入了`nil`,默认加载的是二维纹理,且使用默认配置生成。如需要指定参数,如`生成 Mipmap`,`使用三维纹理`等,可通过第二个参数传入参数字典指定,具体请参考官方文档。 ## MTKModel 三维绘制是 Metal 一个重要的方向。`MTKModel`是一系列模型加载抽象类的集合。 #### 三维模型 在图形引擎中绘制图形,使用的是顶点坐标、贴图坐标、索引等的统称为顶点数据。那么三维模型文件的主要功能就是描述这个模型的顶点数据。普通模型文件中90%以上的数据都是顶点数据,除此之外还会包含其他数据例如: - 贴图、法线贴图等贴图信息。 - 漫反射率、镜面反射率等光学属性。 - 光源、摄像机等其他数据。 - 包含骨骼动画的模型还会包含各个关键帧的数据。 与图片文件类似的,市面上会有各种各样的模型文件,以不同的格式封装起来。例如常用的`obj`、`fbx`等。在图形引擎中加载这些模型会需要各种各样的库去解析,解析出来的数据结构可能还各不相同,兼容多个模型格式也是一件很痛苦的事情。 幸运的是苹果帮助开发者完成了这部分工作,即`ModelIO`。 #### ModelIO 在 iOS/macOS SDK 中包含了很多图形引擎,例如`SpriteKit`、`SceneKit`、`MetalKit`、`GLKit`等。除了`SpriteKit`属于 2D 引擎之外,其他引擎都具备三维绘图的能力。那么跟图片类似的,提供一个跨引擎的统一的三维模型解决方案是很有必要的。因此`ModelIO`诞生了。 > Import, export, and manipulate 3D models using a common infrastructure that integrates MetalKit, GLKit, and SceneKit. `ModelIO`会帮助开发者解析模型文件,并封装为统一的`MDLObject`、`MDLMesh`等对象,让开发者使用三维模型跟使用各个格式的图片一样简单。 关于三维绘制,由于内容比较多,就不在本系列文章中细讲了。 # 小结 MetalKit 解决了在图形开发时的两个痛点:图片纹理加载和三维模型加载。以及提供了一个标准的`MTKView`来快速构建开发环境,让开发者们能更专注地进行业务开发。 附:本文开头提到的教程网站为:[metalkit.org](http://metalkit.org)。此网站在国内环境浏览,排版上可能会遇到一些问题,大家自备梯子。
评论:0条