iOS 8 Metal Swift 教程(二):3D图形

这篇教程介绍了如何在iOS 8中使用Metal进行3D图形编程,包括矩阵变换、模型视图投影、统一数据传递、背面剔除等。通过创建节点类、重构代码,演示了如何从三角形到正方体的3D渲染,并引入了投影矩阵以实现透视效果。此外,还讲解了视图变换和旋转立方体,以及如何修改透明度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在开始之前,你可以先参考一下本系列的第一篇教程:

- iOS 8 Metal Swift教程(一) :开始学习

在本篇教程中,你将应用到3D图形中的一系列矩阵变换,并会学习到如下内容:

如何使用模型(model),视图(view)以及投影变换(projection transformations)。

如何使用矩阵运算变换几何图形

如何在着色器(shader)间传递统一数据

如何使用背面剔除(backface culling)来优化渲染

开篇

首先,你需要的下载一个工程,这和此前的教程中用到的是一样的。

构建并运行,请注意你的测试设备需要兼容Metal,然后确认你能看到下面这个三角形。

BeautifulTriangle-240x320.png

现在你需要下载一个Matrix4类,这是事先写好的,然后你需要将其加入你的工程中。这个时候因为你交叉使用了Swift和Objective-C,Xcode会提示你是否要配置一个桥接头文件(Bridging Header),这时候只要选择YES就行。

待会儿要在很多地方用到矩阵,所以你最好先看一遍Matrix4.m和Matrix4.h文件,对这个类有个清晰的认识。

iOS的内建库GLKMatrix中包含了一个用于常见3D运算的GLKMath库,其中包括可以矩阵运算的GLKMatrix4类。

本教程涉及大量的矩阵运算,使用这个库会很方便许多,不过GLKMatrix4是一个C语言结构体,所以在Swift中你不能直接调用它。

呐,所以呢,我就给各位用Objective-C封装了一下C的结构体,这样我们就能愉快的在Swift中使用GLKMatrix4了,下面是这一调用封装过程的图解:

Screen-Shot-2014-09-05-at-4.23.05-PM-480x275.png

再次提醒一下,下面内容真的会有很多矩阵运算,所以你现在还是好好看一下Matrix4类的代码吧。

重构一个节点类(Node Class)

所有的内容在一开始的工程里面的ViewController.swift文件中已经都设置好了,这的确是最简便上手的方式,不过等到你的App变得越来越大越来越复杂那可就说不定了。

在这一小节中,你需要通过以下步骤来重构项目:

1.创建顶点结构(Vertex Structure)

2.创建节点类(Node Class)

3.创建三角形子类(Triangle Subclass)

4.重构视图控制器(View Controller)

5.重构着色器(Shader)

提示:这一节是可以不看的,因为到本节最后只是让你对整个工程有个清晰的认识,如果你想要直接看3D处理的部分,那么可以直接跳过此节,而在下一节的开头你可以下载全新的开始项目——当然那是完全配好了的。

1.创建顶点结构(Vertex Structure)

新建一个文件并以 iOS/Source/Swift File为模板创建一个类,命名为Vertex.swift.

打开该文件,用下面代码覆盖它:

1
2
3
4
5
6
7
8
9
struct  Vertex{
  
   var x,y,z: Float      // position data
   var r,g,b,a: Float    // color data
  
   func floatBuffer() -> [Float] {
     return  [x,y,z,r,g,b,a]
   }
  };

这个结构体会存储每一个顶点的颜色信息和位置信息。其中floatBuffer()方法会按照规定的顺序返回一个float型数组,其中包含的是结构体的位置和颜色的信息。

2.创建节点类(Node Class)

同上创建一个Swif文件命名为Node.swift.

同上步骤,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import Foundationimport Metalimport QuartzCore 
class  Node {
  
   let name: String
   var vertexCount: Int
   var vertexBuffer: MTLBuffer  var device: MTLDevice 
   init(name: String, vertices: Array<Vertex>, device: MTLDevice){
     // 遍历每个顶点并将其序列化为一堆float数据放在一个buffer中
     var vertexData = Array<Float>()
     for  vertex in vertices{
       vertexData += vertex.floatBuffer()
     }
  
     // 用上面的buffer中的数据来创建一个新的顶点buffer
     let dataSize = vertexData.count * sizeofValue(vertexData[0])
     vertexBuffer = device.newBufferWithBytes(vertexData, length: dataSize, options: nil)
  
     // 为实例中的各变量赋值
     self.name = name    self.device = device
     vertexCount = vertices.count
   }
  }

作为要渲染的基本单位,每个节点中的顶点都需要包含有一个名字以便使用,之后设备会为其创建buffer并渲染顶点,buffer的结构大致是这样的:

Screen-Shot-2014-09-05-at-5.28.41-PM-480x54.png

接下来,你需要把当前视图控制器中的部分渲染代码移动到Node中去,这些代码会为特定的顶点渲染起作用。

这样你需要在Node.swift里面添加一个新方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func render(commandQueue: MTLCommandQueue, pipelineState: MTLRenderPipelineState, drawable: CAMetalDrawable, clearColor: MTLClearColor?){
  
   let renderPassDescriptor = MTLRenderPassDescriptor()
   renderPassDescriptor.colorAttachments[0].texture = drawable.texture
   renderPassDescriptor.colorAttachments[0].loadAction = .Clear
   renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(red: 0.0, green: 104.0/255.0, blue: 5.0/255.0, alpha: 1.0)
   renderPassDescriptor.colorAttachments[0].storeAction = .Store 
   let commandBuffer = commandQueue.commandBuffer()
  
   let renderEncoderOpt = commandBuffer.renderCommandEncoderWithDescriptor(renderPassDescriptor)
   if  let renderEncoder = renderEncoderOpt {
     renderEncoder.setRenderPipelineState(pipelineState)
     renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, atIndex: 0)
     renderEncoder.drawPrimitives(.Triangle, vertexStart: 0, vertexCount: vertexCount, instanceCount: vertexCount/3)
     renderEncoder.endEncoding()
   }
  
   commandBuffer.presentDrawable(drawable)
   commandBuffer.commit()
}

在上一篇教程里面你也可以找到这段代码,你会发现这段代码来源于ViewController类的render()方法,不过对于Node的顶点渲染有所改动。

3.创建三角形子类(Triangle Subclass)

同上创建文件,命名为Triangle.swift.

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
import Foundationimport Metal 
class  Triangle: Node {
  
   init(device: MTLDevice){
  
     let V0 = Vertex(x:  0.0, y:   1.0, z:   0.0, r:  1.0, g:  0.0, b:  0.0, a:  1.0)
     let V1 = Vertex(x: -1.0, y:  -1.0, z:   0.0, r:  0.0, g:  1.0, b:  0.0, a:  1.0)
     let V2 = Vertex(x:  1.0, y:  -1.0, z:   0.0, r:  0.0, g:  0.0, b:  1.0, a:  1.0)
  
     var verticesArray = [V0,V1,V2]
     super.init(name:  "Triangle" , vertices: verticesArray, device: device)
   }
  }

这里的Triangle继承于刚刚创建的Node类,在构造函数里有三个关于三角形顶点的常量,最后打包为一个数组并传递给了父类的构造函数中。

4.重构视图控制器(View Controller)

打开ViewController.swift并删除下面这行:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值