在阅读有关实时应用程序如何在OpneGL下处理颜色的文章时,我注意到一些示例将Color实现为4 floats的集合,而其他示例则使用4 doubles。我什至在游戏开发领域中看到了一些顶点压缩示例,这些示例主张将颜色另存为4 short

所有这些使我渴望了解更多有关此方面的知识:OpenGl(或硬件)的颜色?但是,更重要的是,精度的极限是什么,超过该极限就无法注意到色差?

我的印象是,对此进行更仔细的学习将有助于我更好地思考和决定如何实现适用于不同应用和场景的颜色类别(例如,在内存,速度和颜色多样性之间做出权衡选择)。

感谢您对此提出的想法。

#1 楼

显示屏上显示或保存为标准图像文件格式的颜色每个组件使用8位。因此,要存储这些颜色,只需使用四个字节(unsigned char)就足够了。这些颜色通常使用sRGB色彩空间,其中包括一个非线性的“伽马”变换,该变换会重新分配精度以使其在感知上更加统一,因此它实际上已经接近人类已经可以感知的色差的极限。 (但是,sRGB色域只是所有可物理感知的颜色的子集。更宽的色域需要更多位。)

但是,如果要在图形软件中生成或处理颜色(而不是只是加载/存储它们),出于各种原因,您可能想使用更高的精度。


对颜色执行操作,例如调整亮度和对比度,alpha混合,伽玛校正等。都倾向于失去精度。您可能希望在内部将颜色存储为16位或更多,以便为自己提供更多的精度余量。否则,每次操作后反复四舍五入到8位会导致质量逐渐下降。
类似地,当使用线性颜色(不是sRGB伽玛编码的颜色)进行照明数学运算时,需要额外的精度以确保您最终转换回sRGB时具有足够的精度。
使用浮点颜色而不是整数可能会更快,更方便。在GPU上尤其如此,其中整数数学指令仅占浮点指令吞吐量的一小部分。但是,即使在CPU上,将颜色转换为浮点数,执行大量操作然后再转换回整数当然也要容易得多,而且可能更快,而不是尝试使用整数定点数学来做所有事情。
如果您完全进行HDR渲染,则需要8位以上的精度才能处理更大的色域和强度范围。新的HDR显示器刚刚开始接受每个组件10位或12位的图像。

使用double表示颜色是过大的选择,但是出于上述所有原因,通常使用float表示颜色是内部的。使用GPU时,half(16位浮点数)也很常见,因为它们在硬件中支持该格式。

评论


$ \ begingroup $
很好的答案,谢谢!我只是没有讲到最后一部分:由于缺乏精确度,使用一半不会导致您之前提到的相同问题吗?由于在着色器中经常进行许多颜色计算,因此这在GPU上尤其重要
$ \ endgroup $
– AndrewSteer
16年8月28日在5:09

$ \ begingroup $
@AndrewSteer一半是16位,包括11个有效的尾数精度位,因此虽然不如float精度,但对于大多数色彩操作来说仍然足够。 (如果要输出到高色域HDR显示器,可能还不够;我不确定。)
$ \ endgroup $
–内森·里德(Nathan Reed)
16-8-28在5:10



$ \ begingroup $
一半请参见openexr
$ \ endgroup $
–亚当
20 Dec 24'9:53