In a Metal app for iOS I need to render a translucent texture attached to a simple quad. I cannot figure out the correct colorAttachment rgb and alpha blend factors.
My set up:
1) Red image created in Photoshop with 50% opacity. Saved as PNG with transparency. The image is stored in my project Assets folder.
2) I create a Metal texture by first creating a UIImage
then using the .cgImage
- CoreImage - field to extract the image data. This image is now in pre-multiplied format so classic Porter-Duff formulas can be applied. More on that later.
// 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) Here is my rather boring texture fragment shader
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) This is my colorAttachment blend factor settings that are the Porter-Duff "over" formula:
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) When I render a quad with this red translucent texture atop a white background the image is too dark. The incorrect rendering (right image) is rgb = (182, 127, 127). The correct image from Photoshop is rgb (255, 127, 127):
What are the correct blend functions?
If folks want to take a look at the code it is on Github here: https://github.com/turner/HelloMetal/tree/2_pass_render
The solution - per Warren's suggestion - was to set the MTKTextureLoaderOptionSRGB
option to false
.