美文网首页
Swift Metal渲染一个球

Swift Metal渲染一个球

作者: 星星编程 | 来源:发表于2022-04-07 11:56 被阅读0次

    首先创建一个设备检测GPU是否支持。

    guard let device = MTLCreateSystemDefaultDevice() else {
    fatalError("GPU is not supported") }
    

    通过设备创建MTKView

    let view = MTKView(frame: frame, device: device)
    

    通过Model I/O创建一个球模型,并设置数据用于更容易呈现的缓冲区。

    let mdlMesh = MDLMesh(sphereWithExtent: [Float(200.0/frame.size.width),Float( 200.0/frame.size.height), 0.0],
                                 segments: [100, 100],
                                 inwardNormals: false,
                                 geometryType: .triangles,
                                 allocator: allocator)
    

    从导入模型顶点到生成最终图像的整个过程,通常被称为呈现管道。呈现管道是一个列表命令发送给GPU,以及资源(顶点,材质和灯光)制作最后的图像。管道包括可编程和非可编程函数,被称为顶点函数和片元函数。

    let descriptor = MTLRenderPipelineDescriptor()
    descriptor.colorAttachments[0].pixelFormat = .bgra8Unorm
    descriptor.vertexFunction = vertexFunction
    descriptor.fragmentFunction = fragmentFunction
    descriptor.vertexDescriptor = MTKMetalVertexDescriptorFromModelIO(mesh.vertexDescriptor)
     pipelineState = try! device.makeRenderPipelineState(descriptor: descriptor)
    

    如果游戏只是呈现一个静止的图像,那么它就不会有多少乐趣。移动一个字符在屏幕周围的流动方式要求GPU渲染一个静态图像大约每秒60次。每个静止图像被称为一帧,图像出现的速度称为帧速率。当你最喜欢的游戏出现卡顿时,通常是因为帧率比较低,特别是当有过多的背景处理会消耗GPU。通过实现MTKViewDelegate方法进行渲染,从而完成图像的更新。

    接下来看一下运行效果吧


    球.png

    所有代码晒一下,仅供参考

    import UIKit
    import MetalKit
    
    class Deom1: UIView {
        private var device:MTLDevice!
        private var pipelineState:MTLRenderPipelineState!
        private var mesh:MTKMesh!
        
        
        override init(frame: CGRect) {
            super.init(frame: frame)
     
            device = MTLCreateSystemDefaultDevice()
            let view = MTKView(frame: frame, device: device)
            view.clearColor = MTLClearColor(red: 1, green: 1, blue: 1, alpha: 1)
            view.delegate = self
            self.addSubview(view)
            
            let allocator = MTKMeshBufferAllocator(device: device)
            let mdlMesh = MDLMesh(sphereWithExtent: [Float(200.0/frame.size.width),Float( 200.0/frame.size.height), 0.0],
                                  segments: [100, 100],
                                  inwardNormals: false,
                                  geometryType: .triangles,
                                  allocator: allocator)
            mesh = try! MTKMesh(mesh: mdlMesh, device: device)
            
            
            let shader = """
            #include <metal_stdlib>
            using namespace metal;
            struct VertexIn {
             float4 position [[ attribute(0) ]];
            };
            vertex float4 vertex_main(const VertexIn vertex_in [[ stage_in ]]) {
             return vertex_in.position;
            }
            fragment float4 fragment_main() {
             return float4(1, 0, 0, 1);
            }
            """
            let library = try! device.makeLibrary(source: shader, options: nil)
            let vertexFunction = library.makeFunction(name: "vertex_main")
            let fragmentFunction = library.makeFunction(name: "fragment_main")
            
            let descriptor = MTLRenderPipelineDescriptor()
            descriptor.colorAttachments[0].pixelFormat = .bgra8Unorm
            descriptor.vertexFunction = vertexFunction
            descriptor.fragmentFunction = fragmentFunction
            descriptor.vertexDescriptor =
            MTKMetalVertexDescriptorFromModelIO(mesh.vertexDescriptor)
            
            pipelineState = try! device.makeRenderPipelineState(descriptor: descriptor)
            
        }
        
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
    }
    
    extension Deom1:MTKViewDelegate{
        func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {
            
        }
        
        func draw(in view: MTKView) {
            guard let commandQueue = device.makeCommandQueue() else {
                fatalError("Could not create a command queue") }
            guard let commandBuffer = commandQueue.makeCommandBuffer(),
                  let descriptor = view.currentRenderPassDescriptor,
                  let renderEncoder =
                    commandBuffer.makeRenderCommandEncoder(descriptor: descriptor)
            else { fatalError() }
            
            renderEncoder.setRenderPipelineState(pipelineState)
            renderEncoder.setVertexBuffer(mesh.vertexBuffers[0].buffer,
                                          offset: 0, index: 0)
            
            guard let submesh = mesh.submeshes.first else {
                fatalError()
            }
            
            renderEncoder.drawIndexedPrimitives(type: .line,
                                                indexCount: submesh.indexCount,
                                                indexType: submesh.indexType,
                                                indexBuffer: submesh.indexBuffer.buffer,
                                                indexBufferOffset: 0)
            
            renderEncoder.endEncoding()
            
            guard let drawable = view.currentDrawable else {
                fatalError()
            }
            commandBuffer.present(drawable)
            commandBuffer.commit()
        }
        
    }
    
    

    相关文章

      网友评论

          本文标题:Swift Metal渲染一个球

          本文链接:https://www.haomeiwen.com/subject/lfyjsrtx.html