我将MTKView设置为使用MTLPixelFormat.rgba16Float。我遇到显示问题,最好用下图来描述:
因此,预期的UIColor会被冲洗掉,但仅限于在MTKView中显示时。当我将可绘制纹理转换回图像以通过CIIMage在UIView中显示时,我获得了原始颜色。这是我创建该输出的方法:
let colorSpace = CGColorSpaceCreateDeviceRGB()
let kciOptions = [kCIImageColorSpace: colorSpace,
kCIContextOutputPremultiplied: true,
kCIContextUseSoftwareRenderer: false] as [String : Any]
let strokeCIImage = CIImage(mtlTexture: metalTextureComposite, options: kciOptions)!.oriented(CGImagePropertyOrientation.downMirrored)
let imageCropCG = cicontext.createCGImage(strokeCIImage, from: bbox, format: kCIFormatABGR8, colorSpace: colorSpace)
其他相关设置:
uiColorBrushDefault: UIColor = UIColor(red: 0.92, green: 0.79, blue: 0.18, alpha: 1.0)
self.colorPixelFormat = MTLPixelFormat.rgba16Float
renderPipelineDescriptor.colorAttachments[0].pixelFormat = self.colorPixelFormat
// below is the colorspace for the texture which is tinted with UIColor
let colorSpace = CGColorSpaceCreateDeviceRGB()
let texDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: MTLPixelFormat.rgba8Unorm, width: Int(width), height: Int(height), mipmapped: isMipmaped)
target = texDescriptor.textureType
texture = device.makeTexture(descriptor: texDescriptor)
一些帖子暗示sRGB被假定为某个地方,但没有具体说明如何禁用它。
我希望我在MTKView上显示的颜色与输入匹配(无论如何都尽可能接近),并且仍然能够将该纹理转换为可以在ImageView中显示的颜色。我已经在iPad Air和新的iPad Pro上进行了测试。行为相同。任何帮助将不胜感激。
答案 0 :(得分:1)
因此,您似乎已经很接近完整的解决方案。但是,你所拥有的并不是很正确。这是一个Metal函数,它将从sRGB转换为线性值,然后您可以将其写入您的Metal着色器中(我仍然建议您写入sRGB纹理,但您也可以写入16位纹理)。请注意,sRGB不是简单的2.2伽玛曲线。
// Convert a non-linear log value to a linear value.
// Note that normV must be normalized in the range [0.0 1.0].
static inline
float sRGB_nonLinearNormToLinear(float normV)
{
if (normV <= 0.04045f) {
normV *= (1.0f / 12.92f);
} else {
const float a = 0.055f;
const float gamma = 2.4f;
//const float gamma = 1.0f / (1.0f / 2.4f);
normV = (normV + a) * (1.0f / (1.0f + a));
normV = pow(normV, gamma);
}
return normV;
}
答案 1 :(得分:0)
事实证明,关键在于取消固有嵌入在UIColor中的伽玛校正
let colorSRGB = UIColor(red: 0.92, green: 0.79, blue: 0.18, alpha: 1.0)
let rgbaSRGB = colorSRGB.getRGBAComponents()!
let gammapower : CGFloat = 2.2
let r = pow(rgbaSRGB.red, gammapower)
let g = pow(rgbaSRGB.green, gammapower)
let b = pow(rgbaSRGB.blue, gammapower)
let a = pow(rgbaSRGB.alpha, gammapower)
let colorNoGamma: UIColor = UIColor(red: CGFloat(r), green: CGFloat(g), blue: CGFloat(b), alpha: CGFloat(a))
一旦我通过colorNoGamma
通过MTLPixelFormat.rgba16Float
应用于MKTView,结果将匹配显示colorSRGB
的UIView。一旦您仔细考虑,它就会变得有意义...感谢@MoDJ引导我走上了正确的道路。
请注意,在MTKView端,我可以将纹理设置保留为最初定义的,即:
let texDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: MTLPixelFormat.rgba8Unorm, width: Int(width), height: Int(height), mipmapped: isMipmaped)
target = texDescriptor.textureType
并且,如果我想将currentDrawable转换为要在UIImageView中显示的纹理,那么我想确保我不应用任何色彩空间设置。即:
let strokeCIImage = CIImage(mtlTexture: metalTextureComposite, options: [:])!.oriented(CGImagePropertyOrientation.downMirrored)
let imageCropCG = cicontext.createCGImage(strokeCIImage, from: box, format: kCIFormatABGR8, colorSpace: colorSpace) // kCIFormatRGBA8 gives same result. Not sure what's proper
let layerStroke = CALayer()
layerStroke.frame = bbox
layerStroke.contents = imageCropCG
请注意,参数options: [:]
意味着我没有像定义kciOptions
的原始帖子中那样传递任何色彩空间/预乘/渲染器设置