为了支持广色域,您需要将 MTKView 设置colorPixelFormat
为BGRA10_XR或bgra10_XR_sRGB。我怀疑colorSpace
macOS MTKViews 的属性在 iOS 上不受支持,因为 iOS 中的颜色管理不是活动的而是有针对性的(请阅读Best practice for color management)。
没有看到您的图像及其实际值,很难诊断,但我会解释我的发现和实验。我建议你像我一样从调试单一颜色开始。
例如,P3 色彩空间中最红的点是什么?可以通过UIColor
如下方式定义:
UIColor(displayP3Red: 1, green: 0, blue: 0, alpha: 1)
将 UIButton 添加到您的视图中,并将背景设置为该颜色以进行调试。您可以在代码中获取组件以查看这些值在 sRGB 中的变化,
var fRed : CGFloat = 0
var fGreen : CGFloat = 0
var fBlue : CGFloat = 0
var fAlpha : CGFloat = 0
let c = UIColor(displayP3Red: 1, green: 0, blue: 0, alpha: 1)
c.getRed(&fRed, green: &fGreen, blue: &fBlue, alpha: &fAlpha)
或者您可以使用 macOS 颜色同步实用程序中的计算器,
确保选择Extended Range,否则值将被限制为 0 和 1。
因此,如您所见,您的 P3(1, 0, 0) 对应于扩展 sRGB 中的 (1.0930, -0.2267, -0.1501)。
现在,回到你的MTKView
,
如果您将 MTKView 的 colorPixelFormat 设置为.BGRA10_XR
,那么如果着色器的输出为,您将获得最亮的红色,
(1.0930, -0.2267, -0.1501)
如果您将colorPixelFormat
MTKView 的 设置为.bgra10_XR_sRGB
,那么如果您的着色器的输出是,您将获得最亮的红色,
(1.22486, -0.0420312, -0.0196301)
因为您必须编写线性 RGB 值,因为这种纹理格式将为您应用伽马校正。应用逆伽玛时要小心,因为有负值。我用这个功能,
let f = {(c: Float) -> Float in
if fabs(c) <= 0.04045 {
return c / 12.92
}
return sign(c) * powf((fabs(c) + 0.055) / 1.055, 2.4)
}
最后一个缺失的部分是创建一个广色域UIImage
。将颜色空间设置为CGColorSpace.displayP3
并复制数据。但是什么数据,对吧?此图像中最亮的红色将是
(1, 0, 0)
或 (65535, 0, 0) 以 16 位整数表示。
我在代码中所做的是使用.rgba16Unorm
纹理来处理displayP3
色彩空间中的图像,其中 (1, 0, 0) 将是 P3 中最亮的红色。这样,我可以直接将其内容复制到UIImage
. 然后,为了显示,我将颜色转换传递给着色器以在显示之前从 P3 转换为扩展的 sRGB(因此,不饱和颜色)。我使用线性颜色,所以我的变换只是一个 3x3 矩阵。我将视图设置为.bgra10_XR_sRGB
,因此会自动为我应用伽玛。
那个(列主)矩阵是,
1.2249 -0.2247 0
-0.0420 1.0419 0
-0.0197 -0.0786 1.0979
你可以在这里阅读我是如何生成它的:Exploring the display-P3 color space
这是我使用 UIButtons 和 MTKView 构建的示例,在 iPhoneX 上截屏,
左边的按钮是 sRGB 上最亮的红色,而右边的按钮使用的是 displayP3 颜色。在中心,我放置了一个 MTKView,它输出如上所述的转换后的线性颜色。
同样的绿色实验,
现在,如果您在最近的 iPhone 或 iPad 上看到这一点,您应该会看到中间的正方形和右侧的按钮都具有相同的亮色。如果您在无法显示它们的 Mac 上看到此内容,则左侧按钮将显示相同颜色。如果您在没有适当颜色管理的 Windows 机器或浏览器中看到此问题,左侧按钮也可能显示为不同的颜色,但这只是因为整个图像被解释为 sRGB 并且显然这些像素具有不同的值......但外观不会正确。
如果您需要更多参考,请查看testP3UIColor
我在此处添加的单元测试:ColorTests.swift,
我初始化的函数UIImage
:Image.swift,
和一个示例应用程序来尝试转换:SampleColorPalette
我没有尝试过CIImages
,但我想同样的原则也适用。
我希望这些信息对您有所帮助。我也花了很长时间才弄清楚如何正确显示颜色,因为我在 Metal SDK 文档中找不到对 displayP3 支持的任何明确引用。