Metal 在片段附件和片段着色器参数之间预乘纹理 alpha——为什么?

Metal is premultiplying texture alpha between fragment attachment & fragment shader arg— why?

提问人:Slipp D. Thompson 提问时间:11/11/2023 最后编辑:Slipp D. Thompson 更新时间:11/11/2023 访问量:39

问:

我确信 Metal 在附件和片段着色器参数 () 之间的某个点对我的纹理进行了 alpha 预乘。Xcode Metal Frame Capture似乎证实了这一点:commandEncoder.setFragmentTexture(…, index: 0)texture2d<float> texture [[texture(0)]],

检查命令的片段纹理绑定:draw…

Fragment binding in Xcode's frame debugger

显示这显然是一个非 alpha 预乘的图像(我知道它来自的 CGImage 是正确的——它是从网络中提取的,并使用 texture.replace(..., withBytes: ...) 手动加载,而不是 MTKTextureLoader):

在启用预乘 Alpha 的情况下进行检查;半透明边缘太亮而无法正确: 在启用预乘 Alpha 的情况下进行检查; 正确的图像: Inspecting with Pre-Multiplied Alpha enabled; too light on the semi-transparent edges to be correct Inspecting with Pre-Multiplied Alpha enabled; correct imagery

但是,当调试片段着色器中调用返回的相同纹素时(使用纹理片段绑定),像素现在显然是 alpha 预乘的:dataTexture.sample(dataTextureSampler, in.dataTextureCoordinate)0

在启用预乘 Alpha 的情况下进行检查;正确的图像:在禁用预乘 Alpha 的情况下进行检查;半透明边缘太暗而无法正确: Inspecting with Pre-Multiplied Alpha enabled; correct imagery Inspecting with Pre-Multiplied Alpha disabled; too dark on the semi-transparent edges to be correct


那么,Metal为什么要这样做呢?这在任何地方都有记录吗?(我已经搜索了金属着色语言规范 3.1 版,但无济于事。这是可以以某种方式配置的吗?dataTexture 的参数名称暗示了这样做的目的——除非我另有说明,否则我真的想将文字值保留在纹理中。

正在使用 RGB 进行混合:add、one、oneMinusSourceAlpha;A:加法、一法、一减法SourceAlpha;按照预乘 alpha 混合的惯例(尽管我很确定这在这里无关紧要,因为我们查看的是片段输入,而不是混合输出)。

将 Xcode 15.0.1 与运行 iPadOS 11 的 iPad Pro 11“ 2021 iPad13,6 搭配使用 17.1;以及 Xcode 15.1 beta 2 和运行 iOS 14 beta 2 的 iPhone 14 Pro iPhone15,2。

iOS Xcode 3D 金属

评论

0赞 Spo1ler 11/11/2023
我很确定在对纹理进行采样时没有进行预乘。
0赞 Slipp D. Thompson 11/14/2023
@Spo1ler 根据我的经验,我 100% 同意——这不是 3D 渲染引擎的工作方式。但是确凿的证据——GPU 上的实际像素值,以及将非预乘图像放在 GPU 上并且它正常工作的后果,但如果我在渲染前预乘图像,那么我在渲染时会得到一个双倍预乘的图像(需要在碎片着色器中执行)——说明并非如此。所以,是的,它不应该像这样工作,但问题是:为什么我会看到我所看到的确凿证据?color.rgb /= color.a;
0赞 Slipp D. Thompson 11/14/2023
暂时看来,Xcode Frame Debugger 的纹理资源检查器可能有问题——像素的 RGBA 值告诉我它是预乘的,但视觉效果只有在禁用预乘 Alpha 的情况下看起来才正确。

答: 暂无答案