如何为纹理渲染 iOS 应用程序启用 MSAA
How Do I Enable MSAA for a Render to Texture iOS App
我有一个工作渲染纹理玩具 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
:
// color
let colorDesc = MTLTextureDescriptor.texture2DDescriptor(pixelFormat:view.colorPixelFormat, width:Int(view.bounds.size.width), height:Int(view.bounds.size.height), mipmapped:false)
colorDesc.mipmapLevelCount = 1;
colorDesc.textureType = .type2DMultisample
colorDesc.sampleCount = view.sampleCount
colorDesc.usage = [.renderTarget, .shaderRead]
renderPassDesc.colorAttachments[ 0 ].texture = view.device!.makeTexture(descriptor:colorDesc)
// depth
let depthDesc = MTLTextureDescriptor.texture2DDescriptor(pixelFormat:.depth32Float, width:Int(view.bounds.size.width), height:Int(view.bounds.size.height), mipmapped:false)
depthDesc.mipmapLevelCount = 1;
depthDesc.textureType = .type2DMultisample
depthDesc.sampleCount = view.sampleCount
depthDesc.usage = .renderTarget
renderPassDesc.depthAttachment.texture = view.device!.makeTexture(descriptor:depthDesc)
在我的绘制循环中,我的片段着色器使用渲染到的纹理时出现以下错误:
断言片段函数失败(finalPassOverlayFragmentShader
):
underlay[0]
的索引 0 处的纹理绑定(预计 MTLTextureType2D
)绑定的纹理类型不正确 (MTLTextureType2DMultisample
)
这是片段着色器:
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;
}
我确定我在某处遗漏了一个设置,但我找不到它。
我错过了什么?
更新 0
我的 2-pass 玩具现在有 MSAA。唯一的问题是没有太多抗锯齿发生。事实上,很难说有什么改变。这是我的最新设置
// 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
更新 1
锯齿似乎来自渲染到纹理,而不是在资产中。下面是并排比较。 top 图像是在启用 MSAA 的情况下使用单通道渲染的。 bottom 图像渲染为纹理。锯齿在底部图像中清晰可见
单程
2遍
错误与您的渲染目标无关(a.k.a。颜色和深度附件)。它与您通过渲染命令编码器的片段纹理 table 传递的纹理有关——也就是说,您调用的地方 setFragmentTexture(_:index:)
。当着色器编码为预期 .type2D
时,您为索引 0 传递的是 .type2DMultisample
,因为您将 underlay
声明为 texture2d<...>
.
您的 MSAA 设置对于中间步骤是可行的。您最终需要将纹理解析为非多重采样纹理,以便将其绘制到屏幕上。对于该步骤(可能用于此渲染命令编码器或稍后的编码器,具体取决于您的需要),您需要将颜色附件的 storeAction
设置为 .multisampleResolve
或 .storeAndMultisampleResolve
.并且您需要将 resolveTexture
设置为 2D 纹理。这可能是您自己的纹理或可绘制对象的纹理。
我有一个工作渲染纹理玩具 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
:
// color
let colorDesc = MTLTextureDescriptor.texture2DDescriptor(pixelFormat:view.colorPixelFormat, width:Int(view.bounds.size.width), height:Int(view.bounds.size.height), mipmapped:false)
colorDesc.mipmapLevelCount = 1;
colorDesc.textureType = .type2DMultisample
colorDesc.sampleCount = view.sampleCount
colorDesc.usage = [.renderTarget, .shaderRead]
renderPassDesc.colorAttachments[ 0 ].texture = view.device!.makeTexture(descriptor:colorDesc)
// depth
let depthDesc = MTLTextureDescriptor.texture2DDescriptor(pixelFormat:.depth32Float, width:Int(view.bounds.size.width), height:Int(view.bounds.size.height), mipmapped:false)
depthDesc.mipmapLevelCount = 1;
depthDesc.textureType = .type2DMultisample
depthDesc.sampleCount = view.sampleCount
depthDesc.usage = .renderTarget
renderPassDesc.depthAttachment.texture = view.device!.makeTexture(descriptor:depthDesc)
在我的绘制循环中,我的片段着色器使用渲染到的纹理时出现以下错误:
断言片段函数失败(finalPassOverlayFragmentShader
):
underlay[0]
MTLTextureType2D
)绑定的纹理类型不正确 (MTLTextureType2DMultisample
)
这是片段着色器:
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;
}
我确定我在某处遗漏了一个设置,但我找不到它。
我错过了什么?
更新 0
我的 2-pass 玩具现在有 MSAA。唯一的问题是没有太多抗锯齿发生。事实上,很难说有什么改变。这是我的最新设置
// 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
更新 1
锯齿似乎来自渲染到纹理,而不是在资产中。下面是并排比较。 top 图像是在启用 MSAA 的情况下使用单通道渲染的。 bottom 图像渲染为纹理。锯齿在底部图像中清晰可见
单程
2遍
错误与您的渲染目标无关(a.k.a。颜色和深度附件)。它与您通过渲染命令编码器的片段纹理 table 传递的纹理有关——也就是说,您调用的地方 setFragmentTexture(_:index:)
。当着色器编码为预期 .type2D
时,您为索引 0 传递的是 .type2DMultisample
,因为您将 underlay
声明为 texture2d<...>
.
您的 MSAA 设置对于中间步骤是可行的。您最终需要将纹理解析为非多重采样纹理,以便将其绘制到屏幕上。对于该步骤(可能用于此渲染命令编码器或稍后的编码器,具体取决于您的需要),您需要将颜色附件的 storeAction
设置为 .multisampleResolve
或 .storeAndMultisampleResolve
.并且您需要将 resolveTexture
设置为 2D 纹理。这可能是您自己的纹理或可绘制对象的纹理。