在iOS的Metal应用程序中,我需要渲染一个附加到简单四边形的半透明纹理。我无法弄清楚正确的colorAttachment RGB和alpha混合因子。
我的设置:
1) 在Photoshop中创建了一个50%不透明度的红色图像。保存为带透明度的PNG格式。该图像存储在我的项目资源文件夹中。
我的设置:
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
getBytes
来检查纹理中实际像素值吗?另外,加载时可以尝试传递MTKTextureLoaderOptionSRGB
(=false
)选项,以确保你没有错误地获取到一个sRGB纹理,如果源数据实际上不在sRGB空间中,可能会导致纹理看起来更暗。 - warrenm