Direct2D - 如何使用位图实现伽马校正透明度(alpha)?

4
我正在使用Direct2D绘制位图。这些位图利用了透明度(alpha通道)。
混合看起来不对劲。
作为测试,我加载了一个纯黑的png图像,透明度为50%,并将其绘制在白色背景上。结果是像素的红色,绿色和蓝色值为127(0x7F7F7F)。这表明Direct2D的混合忽略了伽马值,并将颜色值视为线性值。
(位图使用常规sRGB颜色空间,每个像素为32位,每个颜色通道(红、绿、蓝和Alpha)8位。它们以GUID_WICPixelFormat32bppPBGRA格式加载。)
在sRGB中,介于黑色和白色之间的混合值为186(0xBABABA)。这是我想要的理想结果。
Direct2D能否显示具有伽马值关注的透明度?我该怎么做?任何帮助都将不胜感激。

Direct2D vs Gamma-correct blend


我认为你搞反了。在sRGB中,50%看起来像黑色和白色之间的一半(在亮度上,有点)。它看起来太亮或太暗了吗?这可能是由于显示方式的原因。 - a stray cat
我的理解是sRGB颜色空间定义了像素强度和实际存储数量之间的非线性转换,即伽马曲线。例如,8位颜色值范围为0-255,但由于伽马曲线,127(中间值)的值在约20%的亮度下显示。因此,黑白的伽马校正50%混合应具有186个像素值(73%的全幅)。因此,在Direct2d中,我的混合看起来太暗了。 - Jeff McClintock
@astraycat如果您查看交替的黑色和白色像素并将它们与实心块进行比较,则BABABA块在正确校准的监视器上应具有相同的亮度。即使在未校准的监视器上,BABABA也应该比7F7F7F更接近。 - Mark Ransom
2个回答

2
混合应该在线性颜色空间中正确完成,因此混合sRGB像素的过程应该是:
  1. 转换为线性
  2. 混合
  3. 转换回sRGB。
请注意,在黑色或白色像素中,步骤(1)和(3)不起作用,可以省略。
请参见PNG规范的alpha通道处理部分。特别是,请注意以下内容:

计算组合样本值的方程式为

output = alpha * foreground + (1-alpha) * background

其中alpha值和输入输出样本值均表示为0到1范围内的分数。此计算应使用强度样本(而非伽马编码样本)执行

该部分包含有关alpha通道处理的示例C代码。
在这个问题被提出的时候,HWND渲染目标(绘制到屏幕上)不支持线性像素格式。然而,Direct-2D HwndRender目标现在已经被接口ID2D1DeviceContext所取代。这些是通过IDXGIFactory2::CreateSwapChainForHwnd()创建的,并支持更多的像素格式,如DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,当进行混合时会自动执行正确的颜色空间转换(由@Jeff McClintock提供的信息)。

谢谢,这很有道理(在线性颜色空间中执行混合),但如何在Direct2D中实现呢?(也许需要将渲染目标和位图设置为特定的像素格式?) - Jeff McClintock
1
我做了一些研究。据我所知,Direct2D HWND渲染目标(绘制到屏幕)不支持线性像素格式,如果将位图转换为线性格式,则不再支持硬件加速(Direct2D的主要优势)。Direct3D(Direct2D基于此)确实支持对位图进行操作,其中像素在混合操作期间转换为线性颜色空间并返回。可惜Direct2D不支持此功能。 - Jeff McClintock
更新:Direct-2D HwndRender 目标已被 ID2D1DeviceContext 接口取代。这些通过 IDXGIFactory2::CreateSwapChainForHwnd() 创建,并支持更多的像素格式,如 DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,在混合时会自动执行正确的颜色空间转换。 - Jeff McClintock
1
谢谢,@Jeff McClintock,我已经将您的更新纳入答案中。 - Glenn Randers-Pehrson

1

Direct-2D 1.0 HwndRenderTarget 在像素值上直接执行混合计算。这会导致使用 alpha 通道合成标准 sRGB 图像时出现错误。错误是因为 Direct 2D 将伽马压缩的强度值视为线性强度值。

忽略伽马会导致合成质量差、几何抗锯齿、图像调整大小和文本呈现效果差。

有一个解决方法,即“预扭曲”位图的 alpha 值来补偿混合计算引入的错误。

示例: 左侧图像通过在线性色彩空间中执行混合处理进行正确合成,中心图像是 Direct 2D(阴影太暗且对比度太高),右侧图像是在预扭曲 alpha 通道后的 Direct2D。

Direct 2D Renders alpha blends to dark and 'contrasty'

请见:https://bel.fi/alankila/lcd/alpcor.html

更新!:Direct-2D的新版本(1.1)支持SRGB后缓冲区,可以正确执行混合。使用IDXGIFactory2 :: CreateSwapChainForHwnd()来使用改进的颜色深度选项。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接