在Metal中,经典的Porter-Duff“over”合成的正确混合因子是什么?

3
在iOS的Metal应用程序中,我需要渲染一个附加到简单四边形的半透明纹理。我无法弄清楚正确的colorAttachment RGB和alpha混合因子。
我的设置:
1) 在Photoshop中创建了一个50%不透明度的红色图像。保存为带透明度的PNG格式。该图像存储在我的项目资源文件夹中。

enter image description here

2)我通过首先创建一个UIImage,然后使用.cgImage - CoreImage - 字段提取图像数据来创建一个Metal纹理。这个图像现在是预乘格式,因此可以应用经典的Porter-Duff公式。稍后会详细介绍。

// load hero texture
do {

    let textureLoader = MTKTextureLoader(device: device)

    guard let image = UIImage(named:"red_translucent") else {
        fatalError("Error: Can not create UIImage")
    }

    if (image.cgImage?.alphaInfo == .premultipliedLast) {
        print("texture uses premultiplied alpha. Rock.")
    }

    heroTexture = try textureLoader.newTexture(with: image.cgImage!, options: nil)
} catch {
    fatalError("Error: Can not load texture")
}

3) 这是我的相当无聊的纹理片段着色器

fragment float4 textureFragmentShader(_Vertex_ vert [[ stage_in ]], texture2d<float> texas [[ texture(0) ]]) {

    constexpr sampler defaultSampler;

    float4 rgba = texas.sample(defaultSampler, vert.st).rgba;
    return rgba;
}

4) 这是我的colorAttachment混合因子设置,使用的是Porter-Duff "over"公式:

descriptor.colorAttachments[ 0 ].isBlendingEnabled = true

descriptor.colorAttachments[ 0 ].rgbBlendOperation = .add
descriptor.colorAttachments[ 0 ].alphaBlendOperation = .add

descriptor.colorAttachments[ 0 ].sourceRGBBlendFactor = .one
descriptor.colorAttachments[ 0 ].sourceAlphaBlendFactor = .one

descriptor.colorAttachments[ 0 ].destinationRGBBlendFactor = .oneMinusSourceAlpha
descriptor.colorAttachments[ 0 ].destinationAlphaBlendFactor = .oneMinusSourceAlpha

5) 当我在白色背景上使用这个红色半透明的纹理渲染四边形时,图像太暗了。错误的渲染(右图)是rgb =(182,127,127)。来自Photoshop的正确图像是rgb(255,127,127):

enter image description here

什么是正确的混合函数?

更新

如果大家想看代码,可以在Github上查看,链接在这里: https://github.com/turner/HelloMetal/tree/2_pass_render


我无法使用手动生成的纹理来重现这个问题。你尝试过使用getBytes来检查纹理中实际像素值吗?另外,加载时可以尝试传递MTKTextureLoaderOptionSRGB(=false)选项,以确保你没有错误地获取到一个sRGB纹理,如果源数据实际上不在sRGB空间中,可能会导致纹理看起来更暗。 - warrenm
嗨 Warren,我会尝试一下。这个项目在Github上,如果你想看一下的话:https://github.com/turner/HelloMetal/tree/2_pass_render。它是名为2_pass_render的分支。 - dugla
太棒了!禁用sRGB就解决了问题。太好了。谢谢Warren。 - dugla
1个回答

1
解决方案 - 按照Warren的建议 - 是将MTKTextureLoaderOptionSRGB选项设置为false

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