3、颜色校正滤镜:亮度/对比度调节、色相/饱和度调整、颜色矩阵(ColorMatrix)实现、Gamma校正
好,咱们进入第三节课。说实话,颜色校正这块儿,是后处理特效里最实用、也最容易出效果的部分。你想想看,一个场景渲染出来,有时候就是差那么一点点味道——要么太暗,要么颜色太艳,要么整体发灰。这时候,颜色校正滤镜就是你的救星。
我个人习惯把颜色校正分成四个维度来聊:亮度/对比度、色相/饱和度、颜色矩阵,还有Gamma校正。咱们一个一个来。
亮度与对比度调节
先说最简单的。亮度和对比度,说白了就是让画面更亮或更暗,以及让明暗差异更明显。
在Three.js里,我们可以用 EffectComposer 配合自定义着色器来实现。但更省事的方式,是用现成的 ShaderPass 加上一个简单的片元着色器。
核心思路其实就一行公式:
// 亮度对比度着色器核心代码
gl_FragColor = vec4((vUv - 0.5) * contrast + 0.5 + brightness, 1.0);
嗯,这里要注意:brightness 的范围我一般控制在 -0.5 到 0.5 之间,contrast 控制在 0.0 到 2.0 之间。超过这个范围,画面就容易出现裁切——亮部死白,暗部死黑。
色相与饱和度调整
色相调整,说白了就是让颜色在色环上转一圈。饱和度呢,就是让颜色更鲜艳或者更灰。
这里我推荐用 HSL 模型来处理。为什么?因为 RGB 直接调色相太反直觉了。你想想看,把红色调成绿色,在 RGB 空间里你得同时改三个通道,但在 HSL 空间里,你只需要转一下色相值。
核心代码长这样:
// 色相饱和度着色器
vec3 hsl = rgb2hsl(color.rgb);
hsl.x += hueShift; // 色相偏移,范围 0.0 ~ 1.0
hsl.y *= saturation; // 饱和度缩放,1.0 为原样
vec3 result = hsl2rgb(hsl);
我在项目中遇到过一个问题:直接调色相时,皮肤颜色很容易变得诡异。后来我发现,色相偏移量控制在 ±0.05 以内,对肤色的影响就比较自然。超过这个范围,人就变成阿凡达了。
颜色矩阵(ColorMatrix)实现
颜色矩阵,这才是颜色校正的终极武器。说白了,就是用 4x4 的矩阵去变换 RGBA 四个通道。
它的威力在于:你可以用矩阵乘法实现亮度、对比度、色相、饱和度、甚至色彩混合的任意组合。一个矩阵搞定所有。
标准形式是这样的:
// 颜色矩阵着色器
vec4 color = texture2D(tDiffuse, vUv);
mat4 colorMatrix = mat4(
r, 0, 0, 0,
0, g, 0, 0,
0, 0, b, 0,
0, 0, 0, a
);
gl_FragColor = colorMatrix * color;
但说实话,手动写矩阵太痛苦了。我一般用 Three.js 的 ColorMatrix 类,或者直接传一个数组进去。
举个例子,实现一个复古滤镜(Sepia),矩阵是这样的:
const sepiaMatrix = [
0.393, 0.769, 0.189, 0,
0.349, 0.686, 0.168, 0,
0.272, 0.534, 0.131, 0,
0, 0, 0, 1
];
你看,这个矩阵把 RGB 三个通道混合在一起,产生了一种泛黄的老照片效果。这就是颜色矩阵的魅力——你可以任意组合通道。
Gamma校正
最后聊 Gamma 校正。这是个容易让人头疼的概念,我尽量说简单点。
人眼对亮度的感知不是线性的。你想想看,从 0 到 0.1 的亮度变化,人眼觉得很明显;但从 0.9 到 1.0 的变化,几乎看不出来。Gamma 校正就是为了补偿这个非线性。
在 Three.js 里,Gamma 校正通常分两步:
- 编码:在输出到屏幕前,对颜色做 Gamma 变换(一般是 1/2.2 次方)
- 解码:在纹理采样时,对输入颜色做逆 Gamma 变换(2.2 次方)
代码实现很简单:
// Gamma 校正着色器
float gamma = 2.2;
vec3 color = pow(originalColor, vec3(1.0 / gamma)); // 编码
// 或者
vec3 color = pow(originalColor, vec3(gamma)); // 解码
我记得有一次做 HDR 渲染,忘了做 Gamma 校正,结果画面亮部全部过曝,暗部又死黑。折腾了两天才发现是 Gamma 的问题。从那以后,我养成了一个习惯:只要涉及颜色输出,先检查 Gamma 是否做了。
outputColorSpace 属性即可。但如果你用自定义着色器,记得手动处理 Gamma。
总结一下
颜色校正这块,我的建议是:
- 简单场景:用亮度/对比度 + 饱和度,三个参数搞定
- 中等场景:加一个色相偏移,做风格化调色
- 复杂场景:上颜色矩阵,实现 LUT 级别的效果
- 永远别忘了:Gamma 校正,这是颜色准确性的基石
下一节课,咱们聊聊更高级的滤镜——模糊、辉光和景深。这些才是真正让画面「哇塞」起来的东西。