在透明的MTKView中正确设置Alpha混合参数?

4
我最近尝试创建一个透明的MTKView,在其中可以绘制一些几何图形,包括部分透明的几何图形,并且能够正确地与位于MTKView后面的任何视图进行合成。在尝试实现这一目标时,我遇到了两个问题:
1. 在不透明区域上绘制部分透明的三角形会使该区域不再是不透明的。 2. 部分透明像素的颜色与背景没有正确混合,包括多重采样的抗锯齿像素。
我创建了一个测试案例,至少可以演示第一个问题,可能还包括第二个问题。在测试案例中,混合模式设置为:
colorAttachmentDescriptor.isBlendingEnabled = true
colorAttachmentDescriptor.pixelFormat = .bgra8Unorm_srgb
colorAttachmentDescriptor.rgbBlendOperation = .add
colorAttachmentDescriptor.alphaBlendOperation = .add
colorAttachmentDescriptor.sourceRGBBlendFactor = .sourceAlpha
colorAttachmentDescriptor.sourceAlphaBlendFactor = .sourceAlpha
colorAttachmentDescriptor.destinationRGBBlendFactor = .oneMinusSourceAlpha
colorAttachmentDescriptor.destinationAlphaBlendFactor = .oneMinusSourceAlpha

这大概是我在网上看到的推荐做法。
我的测试案例在一个不同颜色的网格上渲染了三个三角形。按照绘制顺序,首先渲染白色(float4(1, 1, 1, 1))的三角形,然后是蓝色(float4(0, 0, 1, 0.5))的三角形,最后是红色(float4(1, 0, 0, 0.5))的三角形。MTKView的清除颜色设置为所有通道的0。
左边是我从测试案例中得到的输出,右边是我期望的输出(在一个插图程序中绘制)。

Test results

如您所见,部分透明的三角形使不透明的白色三角形的不透明度消失。此外,我在左侧绘制的三角形看起来比它们应该的更透明,对像素进行采样可以证实这一点。例如,我期望黑色瓷砖和蓝色三角形重叠的像素应该是float3(0, 0, 0.5),但实际上更接近于float3(0, 0, ~0.737)
此外,多重采样也出现了奇怪的问题:当白色三角形与白色瓷砖和仅有一个透明三角形相交时,似乎根本没有进行多重采样。
我在这个回答中看到,核心动画希望视图使用预乘alpha。确实,将MTKView的清除颜色设置为float4(1, 0, 0, 1)会给场景带来红色的色调,而使用直接alpha时我不希望有任何差异。然而,我的担忧是,我有部分透明的几何体同时重叠着不透明的几何体和完全没有任何东西的情况下,从片段着色器输出预乘alpha的解决方案能处理这种情况吗?也许通过调整混合模式参数可以解决这个问题?那么多重采样呢?它似乎没有解决使用预乘alpha的问题。
我的测试案例在这里可用:https://github.com/Aquilosion/metal-composite
1个回答

0
所以,我找到了一组改变,至少对于示例项目和我的原始项目来说是有效的。我不确定为什么它有效,但我有一些理论!

不要使用srgb帧缓冲或纹理

这实际上让我有了很大的进展:我将我的MTKView的像素格式和颜色附件描述符从bgra8Unorm_srgb改为bgra8Unorm。我还对我的原始项目中的纹理做了同样的更改。我认为这个具体的改变是让多重采样混合正确的关键。

为什么这有帮助呢?我猜测,如果帧缓冲的输出格式设置为线性RGB(而不是sRGB),在场景绘制时混合计算会更准确。由于结果在屏幕上看起来仍然是正确的sRGB,我猜测Core Animation会在之后将非sRGB场景转换为sRGB(或者屏幕使用的其他格式)来进行补偿。

不要使用预乘alpha

我的所有着色器都返回直接的alpha值,一切似乎都正常工作。我链接的答案与此相矛盾,所以我不确定为什么会这样。可能在旧版本中有一些差异,我还没有进行任何研究。

(请注意,将清除颜色的RGB设置为非0值,但alpha为0似乎意味着它确实需要预乘alpha,所以我对这一点不是100%确定,但无论如何,正在进行的混合似乎是准确的。我认为只要您的清除颜色全部为0,它应该是准确的。)

调整混合参数

我使用了以下混合参数,我认为这对于直接alpha混合是正确的:

.isBlendingEnabled = true
.rgbBlendOperation = .add
.alphaBlendOperation = .add
.sourceRGBBlendFactor = .sourceAlpha
.sourceAlphaBlendFactor = .one
.destinationRGBBlendFactor = .oneMinusSourceAlpha
.destinationAlphaBlendFactor = .oneMinusSourceAlpha

我不知道为什么我在问题中包含的混合参数比这些更受欢迎,因为这些参数产生的结果更符合大多数人对 alpha 混合的预期(我本以为会这样!)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接