上代码自己悟吧
这是metal 着色器语言如下
#include <metal_stdlib>
using namespace metal;
struct Vertex {
float4 position [[position]];
float4 color;
};
vertex Vertex vertex_shader(constant Vertex *vertices [[buffer(0)]],uint vid [[vertex_id]]){
return vertices[vid];
}
fragment float4 fragment_shader(Vertex vert [[stage_in]]) {
return vert.color;
}
struct Uniforms {
float4x4 modelViewProjectionMatrix;
};
vertex Vertex vertex_func(constant Vertex *vertices [[buffer(0)]], constant Uniforms &uniforms [[buffer(1)]], uint vid [[vertex_id]]) {
float4x4 matrix = uniforms.modelViewProjectionMatrix;
Vertex in = vertices[vid];
Vertex out;
out.position = matrix * float4(in.position);
out.color = in.color;
return out;
}
fragment half4 fragment_func(Vertex vert [[stage_in]]) {
return half4(vert.color);
}
MetalView.swift 如下
//
// MetalView.swift
// chapter03
//
// Created by Marius on 1/12/16.
// Copyright © 2016 Marius Horga. All rights reserved.
//
import MetalKit
struct Vertex {
var position: vector_float4
var color: vector_float4
init(pos: vector_float4, col: vector_float4) {
position = pos
color = col
}
}
struct Uniforms {
var modelViewProjectionMatrix: matrix_float4x4
}
/// 相机位置
func translationMatrix(position: float3) -> matrix_float4x4 {
let X = vector_float4(1, 0, 0, 0)
let Y = vector_float4(0, 1, 0, 0)
let Z = vector_float4(0, 0, 1, 0)
let W = vector_float4(position.x, position.y, position.z, 1)
return matrix_float4x4(columns:(X, Y, Z, W))
}
/// 矩阵缩放
func scalingMatrix(scale: Float) -> matrix_float4x4 {
let X = vector_float4(scale, 0, 0, 0)
let Y = vector_float4(0, scale, 0, 0)
let Z = vector_float4(0, 0, scale, 0)
let W = vector_float4(0, 0, 0, 1)
return matrix_float4x4(columns:(X, Y, Z, W))
}
/// 坐标旋转
/// - Parameters:
/// - angle: 角度
/// - axis: 以什么为轴心
/// - Returns: 矩阵
func rotationMatrix(angle: Float, axis: vector_float3) -> matrix_float4x4 {
var X = vector_float4(0, 0, 0, 0)
X.x = axis.x * axis.x + (1 - axis.x * axis.x) * cos(angle)
X.y = axis.x * axis.y * (1 - cos(angle)) - axis.z * sin(angle)
X.z = axis.x * axis.z * (1 - cos(angle)) + axis.y * sin(angle)
X.w = 0.0
var Y = vector_float4(0, 0, 0, 0)
Y.x = axis.x * axis.y * (1 - cos(angle)) + axis.z * sin(angle)
Y.y = axis.y * axis.y + (1 - axis.y * axis.y) * cos(angle)
Y.z = axis.y * axis.z * (1 - cos(angle)) - axis.x * sin(angle)
Y.w = 0.0
var Z = vector_float4(0, 0, 0, 0)
Z.x = axis.x * axis.z * (1 - cos(angle)) - axis.y * sin(angle)
Z.y = axis.y * axis.z * (1 - cos(angle)) + axis.x * sin(angle)
Z.z = axis.z * axis.z + (1 - axis.z * axis.z) * cos(angle)
Z.w = 0.0
let W = vector_float4(0, 0, 0, 1)
return matrix_float4x4(columns:(X, Y, Z, W))
}
func projectionMatrix(near: Float, far: Float, aspect: Float, fovy: Float) -> matrix_float4x4 {
let scaleY = 1 / tan(fovy * 0.5)
let scaleX = scaleY / aspect
let scaleZ = -(far + near) / (far - near)
let scaleW = -2 * far * near / (far - near)
let X = vector_float4(scaleX, 0, 0, 0)
let Y = vector_float4(0, scaleY, 0, 0)
let Z = vector_float4(0, 0, scaleZ, -1)
let W = vector_float4(0, 0, scaleW, 0)
return matrix_float4x4(columns:(X, Y, Z, W))
}
class MetalView: MTKView {
enum UIType {
case triangle
case square
}
var myType:UIType = .square
/// 缓存区的命令串行队列
var commandQueue: MTLCommandQueue?
/// 渲染管道
var rps: MTLRenderPipelineState?
/// 定点缓存数据 vertex_buffer
var vertex_buffer: MTLBuffer?
var index_buffer:MTLBuffer?
var type: MTLTextureType!
var texture: MTLTexture!
var uniformBuffer: MTLBuffer?
/// 矩阵 vertex_data
var vertex_data: [Vertex] = []
var index_data: [UInt16] = [
]
var rotation: Float = 0
required init(coder: NSCoder) {
super.init(coder: coder)
self.clearColor = MTLClearColor.init(red: 0.22, green: 1, blue: 0.4, alpha: 1)
render()
}
func createBuffer() {
// 1. 创建顶点缓存区
switch self.myType {
case .triangle:
vertex_data = [
Vertex.init(pos: [0,0.5,0,1], col: [0,1,0,1]),
Vertex.init(pos: [-0.5,-0.5,0,1], col: [1,0,0,1]),
Vertex.init(pos: [0.5,-0.5,0,1], col: [0,0,1,1]),
]
let length = vertex_data.count * MemoryLayout<Vertex>.size
self.vertex_buffer = self.device?.makeBuffer(bytes: vertex_data, length: length, options: [])
break
case .square:
/// 6 面体八个顶点 xyzw,w 代表权重 是否激活
vertex_data = [
Vertex(pos: [-1.0, -1.0, 1.0, 1.0], col: [1, 1, 1, 1]),
Vertex(pos: [ 1.0, -1.0, 1.0, 1.0], col: [1, 0, 0, 1]),
Vertex(pos: [ 1.0, 1.0, 1.0, 1.0], col: [1, 1, 0, 1]),
Vertex(pos: [-1.0, 1.0, 1.0, 1.0], col: [0, 1, 0, 1]),
Vertex(pos: [-1.0, -1.0, -1.0, 1.0], col: [0, 0.5, 1, 1]),
Vertex(pos: [ 1.0, -1.0, -1.0, 1.0], col: [1, 0.5, 1, 1]),
Vertex(pos: [ 1.0, 1.0, -1.0, 1.0], col: [0, 0.5, 0, 1]),
Vertex(pos: [-1.0, 1.0, -1.0, 1.0], col: [0, 0.5, 1, 1])
]
/// 由点连线
let indexData: [UInt16] = [
0, 1, 2, 2, 3, 0, // front
1, 5, 6, 6, 2, 1, // right
3, 2, 6, 6, 7, 3, // top
4, 5, 1, 1, 0, 4, // bottom
4, 0, 3, 3, 7, 4, // left
7, 6, 5, 5, 4, 7] // back
self.index_data = indexData
/// 点数据
do{
let length = vertex_data.count * MemoryLayout<Vertex>.size
self.vertex_buffer = self.device?.makeBuffer(bytes: vertex_data, length: length, options: [])
}
/// 连线数据
do{
let length = self.index_data.count * MemoryLayout<UInt16>.size
self.index_buffer = self.device?.makeBuffer(bytes: self.index_data, length: length, options: [])
}
/// 投影矩阵 初始化
uniformBuffer = self.device?.makeBuffer(length: MemoryLayout<matrix_float4x4>.size, options: [])
break
}
}
func registerShader() {
//2.1 makeDefaultLibrary:加载项目中所有.metal文件,当然也可以使用其他API来指定metal文件
let library = device!.makeDefaultLibrary()!
// 2.2 从库中加载顶点函数、片元函数 着色器语言和原理
var vertex_func = library.makeFunction(name: "vertex_shader")
var frag_func = library.makeFunction(name: "fragment_shader")
switch self.myType {
case .triangle:
break
case .square:
vertex_func = library.makeFunction(name: "vertex_func")
frag_func = library.makeFunction(name: "fragment_func")
break
}
let rpld = MTLRenderPipelineDescriptor()
rpld.label = "test"
//3.2 可编程函数,用于处理渲染过程中每个顶点、片元
rpld.vertexFunction = vertex_func
rpld.fragmentFunction = frag_func
// view.colorPixelFormat
//3.3 确定渲染管线中颜色附着点0的颜色组件;使用当前view颜色组件
rpld.colorAttachments[0].pixelFormat = self.colorPixelFormat
/// 这个暂时使用无效 invalid 如果xib 里面有值则会闪退,此处目前一定要为 invalid
self.depthStencilPixelFormat = MTLPixelFormat.invalid
do {
try rps = device!.makeRenderPipelineState(descriptor: rpld)
} catch let error {
// self.printView("\(error)")
print("\(error)")
}
commandQueue = device!.makeCommandQueue()
}
func render() {
// 给 device 赋值
device = MTLCreateSystemDefaultDevice()!
self.createBuffer()
self.registerShader()
}
func update() {
let scaled = scalingMatrix(scale: 0.5)
rotation += 1 / 100 * Float.pi / 4
let rotatedY = rotationMatrix(angle: rotation, axis: vector_float3.init(0, 1, 0))
let rotatedX = rotationMatrix(angle: Float.pi / 4, axis: vector_float3.init(1, 0, 0))
let modelMatrix = matrix_multiply(matrix_multiply(rotatedX, rotatedY), scaled)
let cameraPosition = vector_float3(0, 0, -3)
let viewMatrix = translationMatrix(position: cameraPosition)
let projMatrix = projectionMatrix(near: 0, far: 10, aspect: 1, fovy: 1)
let modelViewProjectionMatrix = matrix_multiply(projMatrix, matrix_multiply(viewMatrix, modelMatrix))
let bufferPointer = uniformBuffer?.contents()
var uniforms = Uniforms(modelViewProjectionMatrix: modelViewProjectionMatrix)
memcpy(bufferPointer, &uniforms, MemoryLayout<Uniforms>.size)
}
override func draw(_ rect: CGRect) {
//6. 用于保存渲染过程中的一组结果,渲染命令编码器描述符
if let drawable = currentDrawable, let rpd = currentRenderPassDescriptor {
rpd.colorAttachments[0].clearColor = MTLClearColorMake(0.4, 0.5, 0.5, 1.0)
//5. 为每一次渲染创建一个新的命令缓冲区
let commandBuffer = commandQueue!.makeCommandBuffer()
// 创建渲染命令编码器,通过它来进行渲染的配置
let commandEncoder = commandBuffer?.makeRenderCommandEncoder(descriptor: rpd)
// 设置当前渲染管道状态对象
commandEncoder?.setRenderPipelineState(rps!)
switch self.myType {
case .triangle:
//10. 载入顶点数据
//通过VertexInputIndexVertices将数据传递到顶点函数的对应buffer中
commandEncoder?.setVertexBuffer(vertex_buffer, offset: 0, index: 0)
/// 绘制
commandEncoder?.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: vertex_data.count, instanceCount: 1)
break
case .square:
self.update()
commandEncoder?.setFrontFacing(.counterClockwise)
commandEncoder?.setCullMode(.back)
// 载入顶点数据
commandEncoder?.setVertexBuffer(vertex_buffer, offset: 0, index: 0)
commandEncoder?.setVertexBuffer(uniformBuffer, offset: 0, index: 1)
/// 绘制
commandEncoder?.drawIndexedPrimitives(type: .triangle, indexCount: self.index_buffer!.length / MemoryLayout<UInt16>.size, indexType: MTLIndexType.uint16, indexBuffer: self.index_buffer!, indexBufferOffset: 0)
break
}
// 结束编码
commandEncoder?.endEncoding()
// 锁定缓存区, 等待缓冲区处理完成后绘制
commandBuffer?.present(drawable)
// 将命令缓存区提交给GPU
commandBuffer?.commit()
}
}
}
建议真机,或者跑mac 应用看