金属(iOS)中的多重采样/锯齿边缘

10

我目前正在尝试使用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)
1个回答

21

使用MTKView大大简化了这个过程(只需将视图和管道描述符的sampleCount设置为所需的MSAA样本数),但以下是自己实现的步骤。

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

  2. 在启动时以及每当图层调整大小时,通过创建一个纹理描述符来创建一个多重采样纹理,其尺寸等于您的图层可绘制尺寸,并将其textureType设置为MTLTextureType2DMultisample,将其sampleCount设置为您的多重采样计数。如果使用深度和/或模板缓冲区,请在它们的描述符上设置这些属性。

  3. 在渲染时,将MSAA纹理设置为渲染通道描述符的主要颜色附件的texture,并将当前可绘制纹理设置为resolveTexture

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

  5. 按照正常流程绘制和呈现即可。


2
请注意,在第二步中,您还必须将MSAA纹理的“storageMode”设置为“MTLStorageModePrivate”。理想情况下,您还应该将“usage”设置为“MTLTextureUsageRenderTarget”。 - warrenm
在使用 MTKView 的 sampleCount 时表现良好。只需确保通过 device.supportsTextureSampleCount(count) 确定设备可以使用多少个样本,并确保在使用超过 1 个样本时设置 renderPassDescriptor!.colorAttachments[0].storeAction = MTLStoreAction.storeAndMultisampleResolve - user1300214
1
如果您不需要完整的MSAA缓冲区内容进行进一步处理,则无需使用.storeAndMultisampleResolve存储操作;仅使用.multisampleResolve操作即可满足99%的情况,并可以节省大量内存。 - warrenm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接