核心概念

色彩空间

什么是色彩空间?

色彩空间是用于描述颜色在不同介质中呈现方式的标准化模型。它通过映射函数定义了颜色值的范围和转换规则,使得在不同设备或应用之间进行颜色转换变得简单。

在渲染图形时,色彩空间的选择通常受到设备支持的限制。大多数设备默认使用 sRGB 色彩空间,它适合网络图像、数码摄影等应用。sRGB 的设计基于人眼的生理特性,特别是对暗色值的敏感度远高于亮色值。

人眼感知与 sRGB 色彩空间

人眼通过视杆细胞和视锥细胞感知光线。视杆细胞对光线高度敏感,主要在弱光环境下工作,但无法感知颜色;而视锥细胞则负责感知颜色,主要在明亮环境下工作。这种分工使得人眼在不同光照条件下能够适应并感知环境。

为什么人眼对低光更敏感?

在低光环境下,视杆细胞的作用尤为显著。它们对光线的响应是非线性的,尤其对暗色值的变化更加敏感。这种特性使得人类能够在昏暗环境中分辨出微弱的亮度差异。

例如,当我们观察显示器时,线性插值的亮度值并不能直接反映人眼的感知。如下图所示,从黑色(0% 光亮度)到白色(100% 光亮度)的线性渐变中,人眼对 50% 亮度后的变化感知较弱:

通过伽马校正后,亮度的变化更符合人眼的感知特性,呈现出更自然的渐变效果:

sRGB 色彩空间的伽马校正正是基于这种感知特性设计的,并对非常暗的数值进行了额外优化,使显示器上的亮度和颜色过渡更加自然。

sRGB 纹理

纹理支持硬件级的 sRGB 颜色解码,可以提升渲染色彩的准确性,同时提升性能和减少 Shader 编码的复杂度。如果开启 sRGB, Shader 采样纹理时硬件会自动解码为线性数据,纹理大致分为两类:

  • 颜色纹理(如基础贴图、自发光贴图)应使用 sRGB 色彩空间,因为这些纹理通常是通过显示器在 sRGB 空间创作的。
  • 数据纹理(如法线贴图、金属粗糙度贴图)无需使用 sRGB 色彩空间,这些非颜色数据本身就存储在线性空间。

编辑器使用

在编辑器上传纹理时,默认会开启 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
  );
}

通过正确管理纹理的色彩空间设置,可以确保渲染结果的准确性,同时提升性能。

这篇文档对您有帮助吗?