Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 使用金属绘制矩形_Swift_Macos_Metal - Fatal编程技术网

Swift 使用金属绘制矩形

Swift 使用金属绘制矩形,swift,macos,metal,Swift,Macos,Metal,我正在尝试使用金属渲染矩形。但是矩形是倾斜的,如屏幕截图所示。我想知道这里出了什么问题 似乎没有使用顶点索引正确加载矩形的顶点。我试着效仿本文中的例子- 下面是MetalView的代码和使用的着色器- import Cocoa import Metal // Swift doesn't allow to extend a protocol with another protocol; however, we can do default implementation for a specif

我正在尝试使用金属渲染矩形。但是矩形是倾斜的,如屏幕截图所示。我想知道这里出了什么问题

似乎没有使用顶点索引正确加载矩形的顶点。我试着效仿本文中的例子-

下面是MetalView的代码和使用的着色器-

import Cocoa
import Metal

// Swift doesn't allow to extend a protocol with another protocol; however, we can do default implementation for a specific protocol.
extension NSObjectProtocol {
    /// Makes the receiving value accessible within the passed block parameter.
    /// - parameter block: Closure executing a given task on the receiving function value.
    public func setUp(_ block: (Self)->Void) {
        block(self)
    }
    
    /// Makes the receiving value accessible within the passed block parameter and ends up returning the modified value.
    /// - parameter block: Closure executing a given task on the receiving function value.
    /// - returns: The modified value
    public func set(_ block: (Self)->Void) -> Self {
        block(self)
        return self
    }
}


extension MetalView {
    private struct VertexInput {
        var position: SIMD4<Float>
        var rgba: SIMD4<Float>
    }
}

/// `NSView` handling the first basic metal commands.
final class MetalView: NSView {
    private let device: MTLDevice
    private let queue: MTLCommandQueue
    private let vertexBuffer: MTLBuffer
    private let indexCount: Int
    private let indexBuffer: MTLBuffer
//    private let rectBuffer: MTLBuffer
    private let renderPipeline: MTLRenderPipelineState
    
    init?(frame: NSRect, device: MTLDevice, queue: MTLCommandQueue) {
        // Setup the Device and Command Queue (non-transient objects: expensive to create. Do save it)
        (self.device, self.queue) = (device, queue)
        self.queue.label = App.bundleIdentifier + ".queue"
        
        // Setup shader library
        guard let library = device.makeDefaultLibrary(),
            let vertexFunc = library.makeFunction(name: "rect_vertex"),
            let fragmentFunc = library.makeFunction(name: "rect_fragment") else { return nil }
        
        // Setup pipeline (non-transient)
        let pipelineDescriptor = MTLRenderPipelineDescriptor().set {
            $0.vertexFunction = vertexFunc
            $0.fragmentFunction = fragmentFunc
            $0.colorAttachments[0].pixelFormat = .bgra8Unorm   // 8-bit unsigned integer [0, 255]
        }
        guard let pipelineState = try? device.makeRenderPipelineState(descriptor: pipelineDescriptor) else { return nil }
        self.renderPipeline = pipelineState
        
        // Setup buffer (non-transient). Coordinates defined in clip space: [-1,+1]
        let vertices =  [VertexInput(position: SIMD4(-0.5, -0.5, 0.0, 1.0), rgba: SIMD4(1.0, 1.0, 1.0, 1.0)),
                         VertexInput(position: SIMD4(0.5, 0.5, 0.0, 1.0), rgba: SIMD4(0.0, 1.0, 1.0, 1.0)),
                         VertexInput(position: SIMD4(-0.5, 0.5, 0.0, 0.0), rgba: SIMD4(1.0, 0.0, 0.0, 1.0)),
                         VertexInput(position: SIMD4(0.5, -0.5, 0.0, 1.0), rgba: SIMD4(0.0, 1.0, 1.0, 1.0))]
        let size = vertices.count * MemoryLayout<VertexInput>.stride
        guard let buffer = device.makeBuffer(bytes: vertices, length: size, options: .cpuCacheModeWriteCombined) else { return nil }
        self.vertexBuffer = buffer.set { $0.label = App.bundleIdentifier + ".buffer" }
        
        // set index info
        let indexInfo : [UInt16] = [2, 1, 0, 0, 3, 1];
        let indexCount = indexInfo.count * MemoryLayout<UInt16>.stride
        guard let indexBuffer = device.makeBuffer(bytes: indexInfo, length: indexCount, options: .cpuCacheModeWriteCombined) else { return nil }
        self.indexBuffer = indexBuffer.set { $0.label = App.bundleIdentifier + ".buffer" }
        self.indexCount = indexInfo.count
        
        super.init(frame: frame)
        
        // Setup layer (backing layer)
        self.wantsLayer = true
        self.metalLayer.setUp { (layer) in
            layer.device = device
            layer.pixelFormat = .bgra8Unorm
            layer.framebufferOnly = true
        }
    }
    
    required init?(coder aDecoder: NSCoder) { fatalError() }
    private var metalLayer: CAMetalLayer { self.layer as! CAMetalLayer }
    override func makeBackingLayer() -> CALayer { CAMetalLayer() }
    
    override func viewDidMoveToWindow() {
        super.viewDidMoveToWindow()
        
        guard let window = self.window else { return }
        self.metalLayer.contentsScale = window.backingScaleFactor
        self.redraw()
    }
    
    override func setBoundsSize(_ newSize: NSSize) {
        super.setBoundsSize(newSize)
        self.metalLayer.drawableSize = convertToBacking(bounds).size
        self.redraw()
    }
    
    override func setFrameSize(_ newSize: NSSize) {
        super.setFrameSize(newSize)
        self.metalLayer.drawableSize = convertToBacking(bounds).size
        self.redraw()
    }
}

extension MetalView {
    /// Draws a triangle in the metal layer drawable.
    private func redraw() {
        // Setup Command Buffer (transient)
        guard let drawable = self.metalLayer.nextDrawable(),
              let commandBuffer = self.queue.makeCommandBuffer() else { return }
        
        let renderPass = MTLRenderPassDescriptor().set {
            $0.colorAttachments[0].setUp { (attachment) in
                attachment.texture = drawable.texture
                attachment.clearColor = MTLClearColor(red: 0.6, green: 0.6, blue: 0.6, alpha: 1)
                attachment.loadAction = .clear
                attachment.storeAction = .store
            }
        }
        
        guard let encoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPass) else { return }
        encoder.setRenderPipelineState(self.renderPipeline)
        encoder.setVertexBuffer(self.vertexBuffer, offset: 0, index: 0)
        encoder.drawIndexedPrimitives(type: .triangle, indexCount: self.indexCount, indexType: .uint16, indexBuffer: self.indexBuffer, indexBufferOffset: 0)
//        encoder.setFrontFacing(.counterClockwise)
        encoder.endEncoding()
        
        // Present drawable is a convenience completion block that will get executed once your command buffer finishes, and will output the final texture to screen.
        commandBuffer.present(drawable)
        commandBuffer.commit()
    }
}
导入可可粉
进口金属
//Swift不允许使用其他协议扩展协议;但是,我们可以为特定协议执行默认实现。
扩展NSObjectProtocol{
///使接收值在传递的块参数内可访问。
///-参数块:对接收函数值执行给定任务的闭包。
公共函数设置(uu-block:(Self)->Void){
块(自身)
}
///使接收值在传递的块参数内可访问,并最终返回修改后的值。
///-参数块:对接收函数值执行给定任务的闭包。
///-返回:修改后的值
公共函数集(uu:(Self)->Void)->Self{
块(自身)
回归自我
}
}
扩展MetalView{
私有结构VertexInput{
变量位置:SIMD4
变量rgba:SIMD4
}
}
///`NSView`处理第一个基本金属命令。
最终类MetalView:NSView{
专用出租设备:MTLDevice
私有let队列:MTLCommandQueue
私有let vertexBuffer:MTLBuffer
私有let indexCount:Int
私人出租索引缓冲:MTLBuffer
//专用缓冲区:MTLBuffer
私有let renderPipeline:MTLRenderPipelineState
初始化?(帧:NSRect,设备:MTLDevice,队列:MTLCommandQueue){
//设置设备和命令队列(非临时对象:创建成本高。请保存)
(self.device,self.queue)=(设备,队列)
self.queue.label=App.bundleIdentifier+“.queue”
//设置着色器库
guard let library=device.makeDefaultLibrary(),
设vertexFunc=library.makeFunction(名称:“rect_vertex”),
让fragmentFunc=library.makeFunction(名称:“rect_fragment”)else{return nil}
//设置管道(非瞬态)
让pipelineDescriptor=MTLRenderPipelineDescriptor().set{
$0.vertexFunction=vertexFunc
$0.fragmentFunction=fragmentFunc
$0.colorAttachments[0].pixelFormat=.bgra8Unorm//8位无符号整数[0,255]
}
guard let pipelineState=try?device.makeRenderPipelineState(描述符:pipelineDescriptor)else{return nil}
self.renderPipeline=pipelineState
//设置缓冲区(非瞬态)。在剪辑空间中定义的坐标:[-1,+1]
设顶点=[VertexInput(位置:SIMD4(-0.5,-0.5,0.0,1.0),rgba:SIMD4(1.0,1.0,1.0,1.0)),
顶点输入(位置:SIMD4(0.5,0.5,0.0,1.0),rgba:SIMD4(0.0,1.0,1.0,1.0)),
顶点输入(位置:SIMD4(-0.5,0.5,0.0,0.0),rgba:SIMD4(1.0,0.0,0.0,1.0)),
顶点输入(位置:SIMD4(0.5,-0.5,0.0,1.0),rgba:SIMD4(0.0,1.0,1.0,1.0))]
让大小=顶点数*MemoryLayout.stride
guard let buffer=device.makeBuffer(字节:顶点,长度:大小,选项:.cpucachodewritecombined)else{return nil}
self.vertexBuffer=buffer.set{$0.label=App.bundleIdentifier+“.buffer”}
//设置索引信息
让indexInfo:[UInt16]=[2,1,0,0,3,1];
让indexCount=indexInfo.count*MemoryLayout.stride
guard let indexBuffer=device.makeBuffer(字节:indexInfo,长度:indexCount,选项:.cpucachedWriteCombined)else{return nil}
self.indexBuffer=indexBuffer.set{$0.label=App.bundleIdentifier+“.buffer”}
self.indexCount=indexInfo.count
super.init(frame:frame)
//设置层(背衬层)
self.wantsLayer=true
self.metalLayer.setUp{(层)位于
层设备=设备
layer.pixelFormat=.bgra8Unorm
layer.framebufferOnly=true
}
}
必需的初始化?(编码器aDecoder:NSCoder){fatalError()}
私有变量metalLayer:CAMetalLayer{self.layer as!CAMetalLayer}
重写func makeBackingLayer()->CALayer{CAMetalLayer()}
重写func VIEWDIDMOVETOW(){
super.viewdimovetowindow()
guard let window=self.window else{return}
self.metalayer.contentsScale=window.backingScaleFactor
self.redraw()
}
重写func setBoundsSize(uSize:NSSize){
super.setBoundsSize(新闻大小)
self.metalayer.drawableSize=ConvertToBack(bounds).size
self.redraw()
}
重写func setFrameSize(\uNewSize:NSSize){
super.setFrameSize(新闻大小)
self.metalayer.drawableSize=ConvertToBack(bounds).size
self.redraw()
}
}
扩展MetalView{
///在可绘制的金属层中绘制三角形。
私有函数重绘(){
//设置命令缓冲区(瞬态)
guard let drawable=self.metalLayer.nextDrawable(),
让commandBuffer=self.queue.makeCommandBuffer()else{return}
让renderPass=MTLRenderPassDescriptor().set{
$0.colorAttachments[0]。安装程序{(附件)位于
attachment.texture=drawable.texture
附件.clearColor=MTLClearColor(红色:0.6,绿色:0.6,蓝色:0.6,alpha:1)
附件.loadAction=.clear
附件.storeAction=.store
}
}
guard let encoder=commandBuffer.makeRenderCommandEncoder(描述符:renderPass)else{return}
编码器.setRenderPipelineState(self.renderPipeline)
编码器.setVertexBuffer(self.vertexBuffer,o
#include <metal_stdlib>
using namespace metal;

struct VertexInput {
 float4 position [[ position ]];
 float4 rgba;
};

vertex VertexInput rect_vertex(device VertexInput const* const vertices [[buffer(0)]], uint vid [[vertex_id]]) {
    return vertices[vid];
}

fragment float4 rect_fragment(VertexInput vert [[stage_in]]) {
    return vert.rgba;
}