颜色空间
全库目录221
本文目录8
sRGB中间灰值不是一半光能。把编码值直接当作线性光能做运算,会改变亮度关系。颜色空间记录原色、白点和传递函数;采样解码后在线性空间处理,显示时再编码。
颜色编码
线性光照计算
现实中的光能量可以线性相加。两盏相同灯一起照射,理想情况下总能量是单盏的两倍。
显示和图片编码通常不是线性的。例如把黑与白的编码值平均为0.5,显示时对应约0.214的线性值;线性光能的平均应为0.5,编码后约为0.735。加法、乘法和插值产生的错误不同,不能一概理解为固定的变暗系数。
典型流程:
sRGB 颜色纹理
→ 采样时解码为 Linear
→ 光照、混合和后处理
→ Tone Mapping
→ 输出编码到显示空间sRGB传递函数
sRGB 使用分段传递函数。低值部分近似线性,其余部分接近幂函数。
从 sRGB 编码值 解码到线性值 的常见形式:
用 是简化近似,不是完整 sRGB 定义。
sRGB 还规定色度原色和白点。讨论广色域、HDR 显示时,不能只看传递函数。
编码、原色与输出
编码的逆变换为
本式用于非负的标准sRGB范围,广色域变换产生的负值与超范围值需按工作流程处理,不能先裁剪再期待恢复颜色。把sRGB解码为线性值只改变传递函数,不会改变原色;线性sRGB和线性Display P3仍是不同的RGB坐标系。转换原色时通常经XYZ矩阵,白点不同时还需色适应。
以下HLSL标量函数用于离线核对或需要手动转换的明确接口,输入限定在 。使用sRGB资源视图自动转换时,Shader直接使用读取值;手动再解码会重复变换。
float DecodeSRGB(float encoded)
{
return encoded <= 0.04045 ? encoded / 12.92
: pow((encoded + 0.055) / 1.055, 2.4);
}
float EncodeSRGB(float linearValue)
{
return linearValue <= 0.0031308 ? linearValue * 12.92
: 1.055 * pow(linearValue, 1.0 / 2.4) - 0.055;
}纹理过滤需要先把参与的颜色样本解码,再在线性值之间插值;混合目标也需要按API规定完成目标解码、混合和写入编码。输出到sRGB视图与手动编码二者选定一种,避免重复。输出编码是显示链末端的表示转换,不能替代Tone Mapping。
纹理编码选择
先依据资产的数值定义和文件编码判断。颜色图片可能使用sRGB,也可能已经是线性HDR;数据纹理则按定义读取数值。
常用 sRGB
- Base Color/Albedo;
- UI 彩色图片;
- 手绘颜色和部分 Emissive 颜色。
常用 Linear/Data
- Normal;
- Roughness、Metallic、AO;
- Mask、Height、SDF;
- LUT 和数值查找纹理;
- 深度和运动向量。
不能因为一张贴图看起来是灰色就判断它是 Linear。灰色照片仍是颜色,单通道 Roughness 才是数据。
在线性sRGB中,RGB到XYZ的Y分量是0.2126R+0.7152G+0.0722B。纯红(1,0,0)的相对亮度约0.2126,纯绿约0.7152,因此编码值或RGB最大分量相等不等于亮度相等。把sRGB红通道0.5先解码得到约0.2140,再乘0.2126,亮度约0.0455;直接把编码0.5代入矩阵会得到0.1063。
这个计算展示两个顺序不同的操作:先去传递函数,再变换原色坐标。白点不同还需要按选定色适应模型变换XYZ;本页不以一组亮度系数替代完整色域与白点转换。
验证方法
0.5的sRGB解码约为0.214,先比较数值再看显示。检查颜色纹理与数据纹理view,防止手动解码和硬件解码叠加。平方反比照度机制以直接光照为主归属,这里只核对计算空间。
test_post.py 检查0.5解码、线性中灰编码和分段阈值两侧往返,正文函数通过DXC编译。实际资源视图和显示输出尚未运行。
相关主题
参考资料
- W3C CSS Color 4:Sample code for color conversions,核对sRGB分段传递函数、线性sRGB与XYZ矩阵。
- IEC 61966-2-1定义sRGB;本次公式以公开W3C转换代码核对,未声称已取得IEC付费标准全文。