【问题标题】:How to draw concave shape using Stencil test on Metal如何使用金属模板测试绘制凹形
【发布时间】:2017-09-19 16:06:57
【问题描述】:

这是我第一次尝试使用 Stencil 测试,但我看到了一些使用 OpenGL 的示例和一些关于 Metal 的示例,但重点是深度测试。我了解 Stencil 测试背后的理论,但我不知道如何在 Metal 上进行设置。

我想画不规则的形状。为简单起见,让我们考虑以下 2D 多边形:

我希望模板通过重叠三角形的数量为奇数的地方,这样我就可以达到这样的效果,白色区域是要忽略的区域:

我正在按照确切的顺序执行以下步骤:

设置depthStencilPixelFormat:

mtkView.depthStencilPixelFormat = .stencil8
mtkView.clearStencil = .allZeros

模板附件:

let textureDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .stencil8, width: drawable.texture.width, height: drawable.texture.height, mipmapped: true)

textureDescriptor.textureType = .type2D
textureDescriptor.storageMode = .private
textureDescriptor.usage = [.renderTarget, .shaderRead, .shaderWrite]
mainPassStencilTexture = device.makeTexture(descriptor: textureDescriptor)

let stencilAttachment = MTLRenderPassStencilAttachmentDescriptor()

stencilAttachment.texture = mainPassStencilTexture
stencilAttachment.clearStencil = 0
stencilAttachment.loadAction = .clear
stencilAttachment.storeAction = .store
renderPassDescriptor.stencilAttachment = stencilAttachment

模板描述符:

stencilDescriptor.depthCompareFunction = MTLCompareFunction.always
stencilDescriptor.isDepthWriteEnabled = true

stencilDescriptor.frontFaceStencil.stencilCompareFunction = MTLCompareFunction.equal
stencilDescriptor.frontFaceStencil.stencilFailureOperation = MTLStencilOperation.keep
stencilDescriptor.frontFaceStencil.depthFailureOperation = MTLStencilOperation.keep
stencilDescriptor.frontFaceStencil.depthStencilPassOperation = MTLStencilOperation.invert

stencilDescriptor.frontFaceStencil.readMask = 0x1
stencilDescriptor.frontFaceStencil.writeMask = 0x1
stencilDescriptor.backFaceStencil = nil

depthStencilState =  device.makeDepthStencilState(descriptor: stencilDescriptor)

最后,我在主通道中设置参考值和模板状态:

renderEncoder.setStencilReferenceValue(0x1)
renderEncoder.setDepthStencilState(self.depthStencilState)

我是否遗漏了什么,因为我得到的结果就像根本没有模板一样。更改深度测试的设置时我可以看到一些差异,但更改模板设置时没有任何反应...

有什么线索吗?

提前谢谢你

【问题讨论】:

    标签: swift metal stencil-buffer


    【解决方案1】:

    您将模板纹理清除为 0。参考值为 1。比较函数为“相等”。因此,比较将失败(1 不等于 0)。 stencil 比较失败时的操作是“keep”,因此stencil 纹理保持为0。后续片段没有任何变化。

    我希望您不会得到任何渲染,尽管根据您的顶点顺序和正面缠绕模式,您可能正在查看三角形的背面,在这种情况下,模板测试是有效的禁用。如果您不关心正面与背面,只需以相同的方式设置两个模板描述符。

    我认为你需要做两遍:第一,仅模板渲染;其次,由模板缓冲区控制的颜色渲染。仅对于模板,您将使用比较函数.always。这将切换(反转)在给定像素上绘制的每个三角形的低位,为您提供偶数或奇数的指示。因为比较函数和操作都没有涉及到引用值,所以不管是什么。

    对于第二遍,您将比较函数设置为.equal,并将参考值设置为 1。所有操作都应为.keep。另外,请确保将模板附件加载操作设置为 .load(而不是 .clear)。

    【讨论】:

    • 嗨@Ken!抱歉我的回复晚了……这解决了我的问题。正如你所说的,第一件事是缠绕模式。我使用顺时针顺序绘制,这意味着三角形是背面的。因为我没有定义背面模板,所以我在应用模板测试时没有看到任何差异。其次,我做了 2 遍,一个用于 Stencil 存储奇数/偶数个三角形,另一个用于基于第一个遍的模板缓冲区渲染场景。有什么方法可以一次性完成吗?非常感谢
    • 不客气。我认为没有任何方法可以一次性完成。由于任何给定的三角形都是在给定的像素上绘制的,因此尚不知道是否会有更多以及最终是偶数还是奇数。因此,无法决定是将当前片段实际绘制到颜色附件还是丢弃它。
    猜你喜欢
    • 1970-01-01
    • 2016-02-18
    • 1970-01-01
    • 2014-01-27
    • 2010-10-16
    • 1970-01-01
    • 2014-01-17
    • 2016-06-23
    • 1970-01-01
    相关资源
    最近更新 更多