Metal(iOS)中的多重采样/锯齿状边缘
Posted
技术标签:
【中文标题】Metal(iOS)中的多重采样/锯齿状边缘【英文标题】:Multisampling/jagged edges in Metal (iOS) 【发布时间】:2016-07-13 15:19:34 【问题描述】:我目前正在尝试绘制一个将在 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】:使用 MTKView
(只需将 sampleCount
设置为视图和管道描述符上所需的 MSAA 样本数),这要简单得多,但以下是滚动您自己的步骤。
创建渲染管道状态时,将渲染管道状态描述符的sampleCount
设置为多重采样计数。
在启动时,以及每当层调整大小时,通过创建一个纹理描述符,其textureType
是MTLTextureType2DMultisample
并且其sampleCount
是您的多重采样计数,从而创建一个尺寸等于图层可绘制大小的多重采样纹理。如果您正在使用深度和/或模板缓冲区,请在其描述符上设置这些属性。
渲染时,将MSAA纹理设置为render pass描述符的原色附件texture
,将当前drawable的纹理设置为resolveTexture
。
将颜色附件的storeAction
设置为MTLStoreActionMultisampleResolve
,以便在通道结束时将MSAA 纹理解析到渲染缓冲区中。
像往常一样绘制和呈现。
【讨论】:
请注意,在第2步中,您还必须将MSAA纹理的storageMode
设置为MTLStorageModePrivate
。理想情况下,您还应该将usage
设置为MTLTextureUsageRenderTarget
。
使用 MTKView sampleCount
工作得很好。只需确保使用 device.supportsTextureSampleCount(count)
确定设备可以使用多少个样本,如果使用超过 1 个样本,请确保设置 renderPassDescriptor!.colorAttachments[0].storeAction = MTLStoreAction.storeAndMultisampleResolve
。
如果您不需要 MSAA 缓冲区的全部内容进行进一步处理,则无需使用 .storeAndMultisampleResolve
存储操作;只需使用 .multisampleResolve
操作即可满足 99% 的情况,并且可以节省大量内存。以上是关于Metal(iOS)中的多重采样/锯齿状边缘的主要内容,如果未能解决你的问题,请参考以下文章