Metal开发入门(二)绘制三角形

9 篇文章 0 订阅
4 篇文章 0 订阅

GPU在绘制的时候,只会去绘制线和三角形。绘制线段比较好理解,但是为啥是三角形,因为,三角形是在二维平面中利用最少的点就能绘制出来的图形。而且,它可以很容易的切割成两个。本文就是使用Metal来绘制一个三角形

Metal绘制的过程

大体上分为两个部分,一个部分是在整体初始化的过程中,初始化的过程主要是编译metal文件,取得三角形定点和整体的着色函数shader,着色函数和颜色格式组成了一个叫做piplineDescriptor的对象,通过piplineDescriptor即可生成一个piplineState。另一部分是渲染,需要做的是生成一个commandBuffer,commandBuffer有点像数据库中的事务,真正渲染的工作需要由commandEncoder来做。这里commandEncoder接受piplineState和相关的数据。流程图如下:
流程图

描述一个三角形

  1. 创建一个存储三角形三个定点的数据结构,这里的-1和0指的是坐标位置,matal中的坐标如下图:
    在这里插入图片描述
var vetices : [Float] = [
     0,0,0,
      -1,-1,0,
      1,-1,0
  ]
  1. 创建绘制三角形的Shader。新建一个metal文件,命名为shader.metal。在文件中,需要创建两个函数,一个是函数是告诉gpu需要绘制的定点位置,另一个是着色函数,告诉gpu使用什么颜色去绘制这个三角形。
vertex float4 vertex_shader(const device packed_float3 *vertices [[buffer(0)]] ,uint vertexId [[vertex_id]] ){
    return float4(vertices[vertexId],1);
}
fragment half4 fragment_shader(){
    return half4(1,0,0,1);
}

初始化piplineDescriptor和piplineState

let library = device.makeDefaultLibrary()//框架会自动找到项目中的Metal文件
let vertex_shader = library?.makeFunction(name: "vertex_shader")//编译vertex_shader函数
let fragment_shader = library?.makeFunction(name: "fragment_shader")//编译fragment_shader函数
let piplineDescriptor = MTLRenderPipelineDescriptor();//生成piplinDescriptor
piplineDescriptor.vertexFunction = vertex_shader //设置vertex_shader函数
piplineDescriptor.fragmentFunction = fragment_shader//设置fragment_shader函数
piplineDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm //设置颜色格式,这个应该是固定写法
do {
    piplineState = try device.makeRenderPipelineState(descriptor: piplineDescriptor)//通过piplineDescript生成piplineState
} catch let error as NSError {
    print("error \(error.localizedDescription)")
}

绘制

生成一个commandBuffer(简单对比数据库中的事务),通过commandBuffer生成一个encoder。然后为Encode设置piplineState和vertex等数据。

整体代码如下:

import UIKit
import MetalKit

enum Colors {
    static let wenderlichGreen = MTLClearColor(red:0.0,green: 0.4,blue: 0.21,alpha: 1.0)
}

class MyViewController:UIViewController,MTKViewDelegate{
    var vetices : [Float] = [
        0,0,0,
        -1,-1,0,
        1,-1,0
    ]
    var metalView:MTKView{
        return view as! MTKView
    }
    var device:MTLDevice!
    var commandQueue:MTLCommandQueue!
    var vetextBuffer:MTLBuffer!
    var piplineState:MTLRenderPipelineState!
    override func viewDidLoad() {
        super.viewDidLoad()
        metalView.device = MTLCreateSystemDefaultDevice()// 创建设备
        device = metalView.device //设置到controller的成员变量中
        metalView.clearColor = Colors.wenderlichGreen //设置背景颜色
        commandQueue = device.makeCommandQueue() //为gpu准备指令队列
        vetextBuffer = device.makeBuffer(bytes: vetices, length: vetices.count * MemoryLayout<Float>.size, options: []) //定点存储的位置
        let library = device.makeDefaultLibrary()//框架会自动找到项目中的Metal文件
        let vertex_shader = library?.makeFunction(name: "vertex_shader")//编译vertex_shader函数
        let fragment_shader = library?.makeFunction(name: "fragment_shader")//编译fragment_shader函数
        let piplineDescriptor = MTLRenderPipelineDescriptor();//生成piplinDescriptor
        piplineDescriptor.vertexFunction = vertex_shader //设置vertex_shader函数
        piplineDescriptor.fragmentFunction = fragment_shader//设置fragment_shader函数
        piplineDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm //设置颜色格式,这个应该是固定写法
        do {
            piplineState = try device.makeRenderPipelineState(descriptor: piplineDescriptor)//通过piplineDescript生成piplineState
        } catch let error as NSError {
            print("error \(error.localizedDescription)")
        }
        metalView.delegate = self
    }
    func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {
    }
    func draw(in view: MTKView) {
        guard let pState = piplineState else {
            return
        }
        let commandBuffer = commandQueue.makeCommandBuffer() //为指令队列设置缓冲区
        let commandEncoder = commandBuffer?.makeRenderCommandEncoder(descriptor: metalView.currentRenderPassDescriptor!) //为缓冲区创建一个编码器
        commandEncoder?.setRenderPipelineState(pState);
        commandEncoder?.setVertexBuffer(vetextBuffer, offset: 0, index: 0)
        commandEncoder?.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: vetices.count)
        commandEncoder?.endEncoding()//停止编码
        commandBuffer?.present(metalView.currentDrawable as! MTLDrawable) //绘制图像
        commandBuffer?.commit() //提交给gpu
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值