OKLab 色彩空间详解
OKLab 是一个现代色彩空间,由 Björn Ottosson 提出,专为感知均匀性设计。它在图形渲染、动画、Shader 编程和图像处理中有广泛应用,特别适合需要平滑颜色混合的场景。本文将从基础概念到实际应用,全面解释 OKLab,结合 Shader 和动画插值的背景,帮助你快速理解并上手。
1. 什么是 OKLab?
OKLab 是一种感知均匀的色彩空间,旨在让颜色之间的数学距离更符合人眼的视觉感知。相比传统色彩空间(如 RGB、HSL),OKLab 在颜色混合、渐变和视觉效果优化方面表现更出色。
1.1 OKLab 的三个分量
OKLab 使用三个分量描述颜色:
- L(Lightness):亮度,从 0(纯黑)到 1(纯白)。
- a:绿色到红色的色度轴,负值偏绿,正值偏红。
- b:蓝色到黄色的色度轴,负值偏蓝,正值偏黄。
类比:如果你用 Shader 做过颜色插值,L 类似亮度通道(像 luminance),a 和 b 类似 HSL 的色调,但更符合人眼对颜色差异的感知。
1.2 为什么需要 OKLab?
在 RGB 或 HSL 中,颜色插值(比如红到蓝的渐变)可能导致:
- 不均匀过渡:中间颜色可能偏暗或“脏”(如灰紫色)。
- 视觉失真:颜色距离(ΔE)与人眼感知不一致,比如绿到红的过渡显得突兀。
OKLab 解决了这些问题:
- 感知均匀:颜色之间的距离(欧几里得距离)与人眼感知的差异成正比。
- 平滑混合:插值结果更自然,像你在动画中用
smoothstep优化曲线。 - 广泛色域:能表示人眼可见的所有颜色,适合高质量渲染。
左侧是rgb 右侧是oklab 可以明显看到左侧出现了红蓝以外的颜色

2. OKLab 的工作原理
OKLab 的核心是基于人眼视锥细胞(L、M、S 锥体,分别对应长、中、短波长)的响应,通过数学变换将 RGB 颜色映射到感知均匀的空间。
2.1 核心步骤
从 sRGB 到 OKLab 的转换包括:
- sRGB → Linear RGB:去除伽马校正,得到线性 RGB。
- Linear RGB → LMS:模拟人眼锥细胞的响应。
- LMS 非线性变换:应用立方根(类似感知压缩)。
- LMS → OKLab:通过矩阵变换得到 L, a, b 分量。
反向转换(OKLab → sRGB)则是逆过程。
2.2 为什么感知均匀?
- LMS 空间:基于人眼对红、绿、蓝光的敏感度。
- 立方根:模拟人眼对亮度的非线性感知(类似对数的 Weber-Fechner 法则)。
- 矩阵设计:OKLab 的变换矩阵经过优化,确保颜色距离与视觉差异匹配。
类比 Shader:就像你在 GLSL 中用矩阵变换顶点(从模型空间到屏幕空间),OKLab 用矩阵将 RGB 变换到“人眼空间”。
3. OKLab源码示例
3.3 注意事项
- 数值精度:立方根和立方运算可能导致浮点误差,Shader 中需用
clamp确保输出合法。 - 范围:
- L ∈ [0, 1],a 和 b 通常在 [-0.4, 0.4],但可能超出(需裁剪)。
- RGB 需 clamp 到 [0, 1]。
- 性能:矩阵运算和
pow适合 GPU,Shader 中高效。
4. OKLab 的优势
相比其他色彩空间,OKLab 在以下场景中表现优异:
4.1 颜色混合(插值)
- 问题:在 RGB 中,红 (1, 0, 0) 到蓝 (0, 0, 1) 的插值经过灰紫色,显得暗淡。
- OKLab 解决:在 OKLab 中插值 L, a, b 分量,过渡更鲜艳、自然(如粉红到紫色)。
- 类比动画:RGB 插值像粗糙的
lerp,OKLab 像用smoothstep或贝塞尔曲线优化的平滑过渡。
4.2 颜色差异计算
- OKLab 的欧几里得距离:
[
\Delta E = \sqrt{(L_1 - L_2)^2 + (a_1 - a_2)^2 + (b_1 - b_2)^2}
]
接近人眼感知的颜色差异,适合:- 图像处理(颜色匹配)。
- Shader 中的动态效果(基于色差调整亮度)。
4.3 广泛应用
- 图形渲染:生成平滑渐变(如天空、材质)。
- 数据可视化:确保颜色区分度符合视觉习惯。
- 艺术设计:创建感知一致的调色板。
5. 在 Shader 中的应用
结合你的 Shader 和动画插值经验,OKLab 在以下场景中特别有用:
5.1 平滑颜色渐变
- 场景:用 OKLab 实现天空从蓝到橙的日落渐变。
- 实现:
- 将蓝 (0, 0, 1) 和橙 (1, 0.5, 0) 转换为 OKLab。
- 在 OKLab 空间用
mix(oklab1, oklab2, t)插值。 - 转换回 RGB,生成平滑过渡。
- 优势:避免 RGB 中常见的暗淡中间色,类似你用
smoothstep优化动画曲线。
GLSL 伪代码:
vec3 oklab_mix(vec3 rgb1, vec3 rgb2, float t) {
vec3 oklab1 = rgb_to_oklab(rgb1);
vec3 oklab2 = rgb_to_oklab(rgb2);
vec3 mixed = mix(oklab1, oklab2, t);
return oklab_to_rgb(mixed);
}
1301

被折叠的 条评论
为什么被折叠?



