Swift 如何为渲染到纹理iOS应用程序启用MSAA

Swift 如何为渲染到纹理iOS应用程序启用MSAA,swift,metal,fragment-shader,metalkit,msaa,Swift,Metal,Fragment Shader,Metalkit,Msaa,我有一个工作渲染到纹理玩具iOS应用程序。问题在于它有大量锯齿,因为它是点采样的,而不是抗锯齿的: 我将MTKView子类中的样本数增加到4以启用MSAA 下面是相关代码的外观 // render to texture render pass descriptor renderPassDesc = MTLRenderPassDescriptor() renderPassDesc.EI_configure(clearColor: MTLClearColorMake(1, 1, 1, 1), cle

我有一个工作渲染到纹理玩具iOS应用程序。问题在于它有大量锯齿,因为它是点采样的,而不是抗锯齿的:

我将MTKView子类中的样本数增加到4以启用MSAA

下面是相关代码的外观

// render to texture render pass descriptor
renderPassDesc = MTLRenderPassDescriptor()
renderPassDesc.EI_configure(clearColor: MTLClearColorMake(1, 1, 1, 1), clearDepth: 1)

// my MTLRenderPassDescriptor extension convenience method
public func EI_configure(clearColor:MTLClearColor, clearDepth: Double) {

    // color
    colorAttachments[ 0 ] = MTLRenderPassColorAttachmentDescriptor()
    colorAttachments[ 0 ].storeAction = .store
    colorAttachments[ 0 ].loadAction = .clear
    colorAttachments[ 0 ].clearColor = clearColor

    // depth
    depthAttachment = MTLRenderPassDepthAttachmentDescriptor()
    depthAttachment.storeAction = .dontCare
    depthAttachment.loadAction = .clear
    depthAttachment.clearDepth = clearDepth;

}
我将为MSAA配置的颜色和深度缓冲区附加到renderPassDesc:

在我的绘制循环中,我从使用渲染到的纹理的片段着色器中得到以下错误:

失败的断言片段函数FinalPassorOverlayFragmentShader: 索引0处纹理绑定处绑定的纹理类型MTLTextureType2DMultisample不正确参考底图[0]除MTLTextureType2D外

这是片段着色器:

fragment float4 finalPassOverlayFragmentShader(InterpolatedVertex vert [[ stage_in ]],
                                               texture2d<float> underlay [[ texture(0) ]],
                                               texture2d<float> overlay [[ texture(1) ]]) {

    constexpr sampler defaultSampler;

    float4 _F = overlay.sample(defaultSampler, vert.st).rgba;

    float4 _B = underlay.sample(defaultSampler, vert.st).rgba;

    float4 rgba = _F + (1.0f - _F.a) * _B;

    return rgba;
}
更新1 锯齿看起来是从渲染到纹理,而不是在资源中。下面是一个并列比较。使用启用MSAA的单个过程渲染顶部图像。底部图像渲染为纹理。锯齿状结构在下图中清晰可见

单程

二通

错误与渲染目标a.k.a.颜色和深度附件无关。它是关于通过render命令编码器的片段纹理表传入的纹理-即调用setFragmentTexture的位置:index:。当着色器编码为.type2D时,为索引0传递的是.type2DMultisample,因为您将参考底图声明为texture2d


对于中间步骤,MSAA的设置正常。最终需要将纹理解析为非多采样纹理,以便将其绘制到屏幕上。对于此渲染命令编码器或更高版本的步骤,根据需要,需要将颜色附件的storeAction设置为.multisampleResolve或.storeAndMultisampleResolve。您需要将resolveTexture设置为2D纹理。那可能是你自己的,也可能是可拉丝织物。

非常感谢肯。让我试着解开你的答案。1在我的frag着色器中,允许使用多重采样与当前点采样纹理的正确语法是什么。2“我的渲染到纹理”过程将生成定义为“多重采样”的纹理。我的玩具应用程序采用多样本纹理和叠加纹理,并在上面显示的frag着色器中合成它们。超级简单。3我不完全理解分解纹理的作用,您能否详细说明并区分.multisampleResolve和.storeAndMultisampleResolve?你能给我指一下这方面的相关文档吗?我在文档中做了更多的挖掘。关于“解析纹理”和“存储”操作的使用。如果我将颜色附件存储操作设置为.store和multisampler,请解决我为“解析”纹理设置的存储操作?您可以将参考底图声明为texture2d_ms,但您只能从中读取,而不能读取样本。您希望合成的效果如何?在我看来,您希望在合成步骤之前解决抗锯齿问题,所以您希望这样做。多次采样只是一个中间步骤。MS纹理每个texcoord有多个采样值,但最终您需要一个值,例如当绘制到屏幕时。解析是从多个值中生成单个值。.multisampleResolve将解析的数据存储在resolveTexture中,但在其他情况下会丢弃MS纹理的数据。Store和MultiSamplerSolve都解析为resolveTexture,并将数据存储在MS纹理中。只有在解决后需要对其执行其他操作时,您才会这样做。如果您还没有,请查看。它已存档,但仍然相关。查看图形渲染和新增页面。我解决了锯齿问题。我忘记使用UIScreen.main.scale来放大渲染目标。AA正在发生。很好。关于您的更新,您现在是否使用resolveTex而不是tex进行FinalPassaOverlayFragmentShader的合成过程?是的。创建resolve纹理修复了该错误。但是,我没有看到反走样。所以我想澄清一下。MS已为“渲染到纹理”步骤启用。我用这个纹理作为背景,在上面我合成了一个半透明的纹理。我看到在“渲染到纹理”步骤中渲染的纹理中出现锯齿。合成很好。实际上,有轻微的抗锯齿现象。但是,当我在非渲染到纹理的示例中使用多重采样时,我看到的AA完全不同。奇怪。你确定“渲染到纹理”过程的输入中没有锯齿,而不是它的结果吗?
fragment float4 finalPassOverlayFragmentShader(InterpolatedVertex vert [[ stage_in ]],
                                               texture2d<float> underlay [[ texture(0) ]],
                                               texture2d<float> overlay [[ texture(1) ]]) {

    constexpr sampler defaultSampler;

    float4 _F = overlay.sample(defaultSampler, vert.st).rgba;

    float4 _B = underlay.sample(defaultSampler, vert.st).rgba;

    float4 rgba = _F + (1.0f - _F.a) * _B;

    return rgba;
}
// color - multi-sampled texture target
let desc = MTLTextureDescriptor.texture2DDescriptor(pixelFormat:format, width:w, height:h, mipmapped:false)
desc.mipmapLevelCount = 1;
desc.textureType = .type2DMultisample
desc.sampleCount = view.sampleCount
desc.usage = .renderTarget
let tex:MTLTexture? = view.device!.makeTexture(descriptor:desc)

// color - point-sampled resolve-texture
let resolveDesc = MTLTextureDescriptor.texture2DDescriptor(pixelFormat:format, width:w, height:h, mipmapped:true)
let resolveTex:MTLTexture? = view.device!.makeTexture(descriptor:resolveDesc)

// depth texture target
let depthDesc = MTLTextureDescriptor.texture2DDescriptor(pixelFormat:.format, width:w, height:h, mipmapped:false)
depthDesc.mipmapLevelCount = 1;
depthDesc.textureType = .type2DMultisample
depthDesc.sampleCount = view.sampleCount
depthDesc.usage = .renderTarget
let depthTex:MTLTexture? = view.device!.makeTexture(descriptor:depthDesc)

// render pass descriptor
renderPassDesc = MTLRenderPassDescriptor()
// color
renderPassDesc.colorAttachments[ 0 ] = MTLRenderPassColorAttachmentDescriptor()
renderPassDesc.colorAttachments[ 0 ].storeAction = .storeAndMultisampleResolve
renderPassDesc.colorAttachments[ 0 ].loadAction = .clear
renderPassDesc.colorAttachments[ 0 ].clearColor = MTLClearColorMake(0.25, 0.25, 0.25, 1)
renderPassDesc.colorAttachments[ 0 ].texture = tex
renderPassDesc.colorAttachments[ 0 ].resolveTexture = resolveTex
// depth
renderPassDesc.depthAttachment = MTLRenderPassDepthAttachmentDescriptor()
renderPassDesc.depthAttachment.storeAction = .dontCare
renderPassDesc.depthAttachment.loadAction = .clear
renderPassDesc.depthAttachment.clearDepth = 1;
renderPassDesc.depthAttachment.texture = depthTex