让我先回答您的最后一个问题:是的,这是设置MTKView
以显示HDR内容的有效且很好的方式.但是,正如您所指出的,您还需要告诉MTLView
通过设置metalLayer.edrMetadata = .hlg
将EDR值映射到显示器的亮度范围.
或者,我发现以下设置也适用于显示EDR内容:
metalLayer.wantsExtendedDynamicRangeContent = true
metalLayer.colorspace = CGColorSpace(name: CGColorSpace.extendedLinearSRGB)
colorPixelFormat = .rgba16Float
在这种情况下,视图似乎知道如何将扩展的线性EDR值自动映射到其显示器上-不需要设置edrMetadata
.
剩下的我想分成两个主题:
Working Color Space
您是正确的:当设置为CIContextOption.workingColorSpace: NSNull()
时,您将有效地禁用Core Image的自动色彩管理.然而,只有在以下情况下,我才建议这样做:
- 你知道输入的 colored颜色 空间是什么,
- 您不应用任何内置滤镜(因为它们假定它们的输入在CI的默认工作 colored颜色 空间中),并且
- 您将输出配置为与输入在相同的 colored颜色 空间中.
因此,在您的情况下,如果您永远不想在流水线中应用滤镜,您可能可以通过将工作空间设置为NSNull()
来禁用 colored颜色 匹配.这甚至会节省一点处理时间,尽管不是很多,因为 colored颜色 空间转换相当便宜.
在大多数情况下,我建议不要使用workingColorSpace
选项,让CI决定使用什么.
Output Color Space
第CIContextOption.outputColorSpace
章很有误导性它似乎并没有在几乎所有的用例中使用-至少到目前为止我还没有看到任何效果.
那是因为通常你要么
- 将输出色彩空间直接传递给渲染API
CIContext
,如createCGImage(_ image:, from fromRect:, format:, colorSpace:)
中所示,
- 或者渲染目的地定义 colored颜色 空间.
第二点是这里的症结所在.我相信您正在使用CIRenderDestination
API呈现到视图中,可能定义如下:
let destination = CIRenderDestination(width: Int(drawableSize.width),
height: Int(drawableSize.height),
pixelFormat: self.colorPixelFormat,
commandBuffer: commandBuffer,
mtlTextureProvider: { () -> MTLTexture in
return currentDrawable.texture
})
这里的问题是,CIRenderDestination
本身不能完全推断目标的 colored颜色 空间(它通常默认为sRGB).这就是为什么您必须明确设置它的原因.
在这里,您知道视图期望可绘制纹理包含以itur_2100_HLG
为单位的像素数据.因此,要么直接设置,要么直接将其设置为视图的 colored颜色 空间:
destination.colorSpace = metalLayer.colorspace
然后,Core Image将知道在渲染到目标时要转换到哪个 colored颜色 空间.
有了这一更改,色彩管理关闭(CIContextOption.workingColorSpace: NSNull()
)和打开之间现在应该没有更多区别.