Metal入门一 旋转的六面体

上代码自己悟吧

这是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 应用看

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值