金属中的 Multisampling/jagged 个边 (iOS)

Multisampling/jagged edges in Metal (iOS)

我目前正在尝试绘制一个将在 Swift 中使用 Metal 制作动画的图形。我已经成功地绘制了我的图形的单个框架。图形很简单,正如您从这张图片中看到的那样。我想不通的是如何对绘图进行多重采样。一般而言,似乎很少有关于 Metal 的参考,尤其是在 Swift 语法方面。

self.metalLayer = CAMetalLayer()
self.metalLayer.device = self.device
self.metalLayer.pixelFormat = .BGRA8Unorm
self.metalLayer.framebufferOnly = true
self.metalLayer.frame = self.view.frame
self.view.layer.addSublayer(self.metalLayer)

self.renderer = SunRenderer(device: self.device, frame: self.view.frame)

let defaultLibrary = self.device.newDefaultLibrary()
let fragmentProgram = defaultLibrary!.newFunctionWithName("basic_fragment")
let vertexProgram = defaultLibrary!.newFunctionWithName("basic_vertex")

let pipelineStateDescriptor = MTLRenderPipelineDescriptor()
pipelineStateDescriptor.vertexFunction = vertexProgram
pipelineStateDescriptor.fragmentFunction = fragmentProgram
pipelineStateDescriptor.colorAttachments[0].pixelFormat = .BGRA8Unorm
pipelineStateDescriptor.colorAttachments[0].blendingEnabled = true

pipelineStateDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperation.Add
pipelineStateDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperation.Add
pipelineStateDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactor.SourceAlpha
pipelineStateDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactor.SourceAlpha
pipelineStateDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactor.OneMinusSourceAlpha
pipelineStateDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactor.OneMinusSourceAlpha

问题是,如何平滑这些边缘?

更新:

所以我实现了一个 MultiSample 纹理并将 sampleCount 设置为 4。我没有注意到任何差异,所以我怀疑我做错了什么。

决赛:

所以,最终,多重采样确实有效。最初,我让顶点用 0 alpha 包裹这些“光线”。这是使边缘更平滑的技巧。对于这些顶点,多重采样似乎并没有改善边缘。当我恢复到每条射线有 4 个顶点时,多重采样改善了它们的边缘。

let defaultLibrary = self.device.newDefaultLibrary()
let fragmentProgram = defaultLibrary!.newFunctionWithName("basic_fragment")
let vertexProgram = defaultLibrary!.newFunctionWithName("basic_vertex")
        
let pipelineStateDescriptor = MTLRenderPipelineDescriptor()
pipelineStateDescriptor.vertexFunction = vertexProgram
pipelineStateDescriptor.fragmentFunction = fragmentProgram
pipelineStateDescriptor.colorAttachments[0].pixelFormat = .BGRA8Unorm
pipelineStateDescriptor.colorAttachments[0].blendingEnabled = true
pipelineStateDescriptor.sampleCount = 4
        
pipelineStateDescriptor.colorAttachments[0].rgbBlendOperation =    MTLBlendOperation.Add
pipelineStateDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperation.Add
pipelineStateDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactor.SourceAlpha
pipelineStateDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactor.SourceAlpha

pipelineStateDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactor.OneMinusSourceAlpha
pipelineStateDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactor.OneMinusSourceAlpha

let desc = MTLTextureDescriptor()
desc.textureType = MTLTextureType.Type2DMultisample
desc.width = Int(self.view.frame.width)
desc.height = Int(self.view.frame.height)
desc.sampleCount = 4
desc.pixelFormat = .BGRA8Unorm
        
self.sampletex = self.device.newTextureWithDescriptor(desc)


// When rendering
let renderPassDescriptor = MTLRenderPassDescriptor()
renderPassDescriptor.colorAttachments[0].texture = sampletex
renderPassDescriptor.colorAttachments[0].resolveTexture = drawable.texture
renderPassDescriptor.colorAttachments[0].loadAction = .Clear
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(red: 23/255.0, green: 26/255.0, blue: 31/255.0, alpha: 0.0)
renderPassDescriptor.colorAttachments[0].storeAction = .MultisampleResolve
    
    
let commandBuffer = commandQueue.commandBuffer()
    
let renderEncoder = commandBuffer.renderCommandEncoderWithDescriptor(renderPassDescriptor)
renderEncoder.setRenderPipelineState(pipelineState)

使用 MTKView 这要简单得多(只需将 sampleCount 设置为视图和管道描述符上所需的 MSAA 样本数),但这里是滚动你自己的步骤。

  1. 创建渲染管线状态时,将渲染管线状态描述符的 sampleCount 设置为多重采样计数。

  2. 在启动时,每当图层调整大小时,创建一个多采样纹理,其尺寸等于图层的可绘制大小,方法是创建一个纹理描述符,其 textureTypeMTLTextureType2DMultisample 并且其sampleCount 是您的多重样本计数。如果您使用的是深度 and/or 模板缓冲区,请在它们的描述符上也设置这些属性。

  3. 渲染时,将MSAA纹理设置为渲染通道描述符的原色附件的texture,并将当前drawable的纹理设置为resolveTexture

  4. 将颜色附件的 storeAction 设置为 MTLStoreActionMultisampleResolve 以便 MSAA 纹理在通道结束时解析到渲染缓冲区中。

  5. 像往常一样绘画和展示。