色彩空间是用于描述颜色在不同介质中呈现方式的标准化模型。它通过映射函数定义了颜色值的范围和转换规则,使得在不同设备或应用之间进行颜色转换变得简单。
在渲染图形时,色彩空间的选择通常受到设备支持的限制。大多数设备默认使用 sRGB 色彩空间,它适合网络图像、数码摄影等应用。sRGB 的设计基于人眼的生理特性,特别是对暗色值的敏感度远高于亮色值。
人眼通过视杆细胞和视锥细胞感知光线。视杆细胞对光线高度敏感,主要在弱光环境下工作,但无法感知颜色;而视锥细胞则负责感知颜色,主要在明亮环境下工作。这种分工使得人眼在不同光照条件下能够适应并感知环境。
在低光环境下,视杆细胞的作用尤为显著。它们对光线的响应是非线性的,尤其对暗色值的变化更加敏感。这种特性使得人类能够在昏暗环境中分辨出微弱的亮度差异。
例如,当我们观察显示器时,线性插值的亮度值并不能直接反映人眼的感知。如下图所示,从黑色(0% 光亮度)到白色(100% 光亮度)的线性渐变中,人眼对 50% 亮度后的变化感知较弱:
通过伽马校正后,亮度的变化更符合人眼的感知特性,呈现出更自然的渐变效果:
sRGB 色彩空间的伽马校正正是基于这种感知特性设计的,并对非常暗的数值进行了额外优化,使显示器上的亮度和颜色过渡更加自然。
纹理支持硬件级的 sRGB 颜色解码,可以提升渲染色彩的准确性,同时提升性能和减少 Shader 编码的复杂度。如果开启 sRGB, Shader 采样纹理时硬件会自动解码为线性数据,纹理大致分为两类:
在编辑器上传纹理时,默认会开启 sRGB 开关。如果上传的是非颜色数据纹理(如法线贴图),可以手动关闭 sRGB 开关。对于 glTF 资产,编辑器会根据纹理类型(如法线贴图、基础贴图)自动适配 sRGB 开关。
加载纹理 默认使用 sRGB 色彩空间。如果需要使用线性空间,可以通过参数关闭 sRGB 设置:
// 使用 Texture2DLoader 加载纹理
engine.resourceManager
.load<Texture2D>({
type: AssetType.Texture2D,
url: "https://***.png",
params: {
isSRGBColorSpace: false // 关闭 sRGB,使用线性空间,如法线贴图
}
});
在手动创建纹理时,也可以通过构造函数参数指定是否使用 sRGB 色彩空间:
export declare class Texture2D extends Texture {
/**
* 创建 Texture2D。
* @param engine - 渲染引擎实例
* @param width - 纹理宽度
* @param height - 纹理高度
* @param format - 纹理格式,默认值为 `TextureFormat.R8G8B8A8`
* @param mipmap - 是否使用多级纹理
* @param isSRGBColorSpace - 是否使用 sRGB 色彩空间,默认值为 `true`
* @param usage - 纹理用途
*/
constructor(
engine: Engine,
width: number,
height: number,
format?: TextureFormat,
mipmap?: boolean,
isSRGBColorSpace?: boolean,
usage?: TextureUsage
);
}
通过正确管理纹理的色彩空间设置,可以确保渲染结果的准确性,同时提升性能。