如何在金属上使用模板测试绘制凹形

时间:2017-04-22 18:51:47

标签: swift metal stencil-buffer

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

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

concave shape

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

Area to be ignored

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

设置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)

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

有任何线索吗?

提前谢谢

1 个答案:

答案 0 :(得分:3)

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

我希望你没有渲染,虽然取决于你的顶点顺序和正面缠绕模式,你可能会看到三角形的背面,在这种情况下,模板测试是有效的禁用。如果你不关心正面和背面,只需设置两个模板描述符。

我认为你需要做两次传递:首先,只有模板渲染;第二,颜色渲染由模板缓冲区控制。仅对于模板,您将进行比较功能def passengerride_params params.require(:passengerride).permit(:title, { image: :preview }) end 。这将切换(反转)在给定像素上绘制的每个三角形的低位,为您提供偶数或奇数的指示。因为比较函数和操作都不涉及参考值,所以它无关紧要。

对于第二遍,您将比较函数设置为has_attached_file :image, url: "/system/:hash.:extension", hash_secret: "abc123" validates_attachment :image, styles: { original: ['500x500>', :jpg] }, content_type: { content_type: ["image/jpeg", "image/jpg", "image/gif", "image/png"] }, presence: true, size: { in: 0..5000.kilobytes } ,参考值设置为1.操作都应为.always。另外,请务必将模板附件加载操作设置为.equal(不是.keep)。