在 Metal 中,经典 Porter-Duff "over" 合成的正确混合因子是什么?
In Metal what are the correct blendFactors for classic Porter-Duff "over" compositing?
在 iOS 的 Metal 应用程序中,我需要渲染附加到简单四边形的半透明纹理。我无法找出正确的 colorAttachment rgb 和 alpha 混合因子。
我的设置:
1) 在 Photoshop 中创建的红色图像,不透明度为 50%。另存为具有透明度的 PNG。图像存储在我的项目资产文件夹中。
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):
正确的混合函数是什么?
更新
如果人们想看一下 Github 上的代码:
https://github.com/turner/HelloMetal/tree/2_pass_render
根据 Warren 的建议,解决方案是将 MTKTextureLoaderOptionSRGB
选项设置为 false
。
在 iOS 的 Metal 应用程序中,我需要渲染附加到简单四边形的半透明纹理。我无法找出正确的 colorAttachment rgb 和 alpha 混合因子。
我的设置:
1) 在 Photoshop 中创建的红色图像,不透明度为 50%。另存为具有透明度的 PNG。图像存储在我的项目资产文件夹中。
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):
正确的混合函数是什么?
更新
如果人们想看一下 Github 上的代码: https://github.com/turner/HelloMetal/tree/2_pass_render
根据 Warren 的建议,解决方案是将 MTKTextureLoaderOptionSRGB
选项设置为 false
。