1 - 调色 ColorGrading
又开了个新坑,主要是给目前碰到的图形学算法(主渲染向)做一个类似索引的功能。
本文将介绍调色 ColorGrading 的原理,并在 GAMES104 作业里实现这个后处理算法。
原理
有关 ColorGrading 的介绍详见 GAMES104 相关文章。
如图,要想实现 ColorGrading 效果得通过 LUT 和片段着色器。对于处理前画面的每个像素:
- 根据它的 RGB 在 LUT 中查找对应的位置;
- 根据位置读取 LUT 中对应的颜色值;
- 使用读取的颜色值输出。
但早期着色器语言(如 OpenGL ES 2.0)不支持 3D 纹理,因此需要将 3D 的 LUT 拆分成 2D 的,通过切分它的 Z 轴(即蓝色轴)实现。
为了查找 2D 的 LUT,需要用蓝色通道值计算在第几个格子里采样,公式如下:
NEAREST
采样:返回离采样坐标最近纹素的颜色值;LINEAR
采样:返回当前纹素和其周围一定距离纹素的颜色插值结果;
需要注意的是,由于蓝色通道值被用于计算采样格子序号,导致它总是整数,会使得结果有突兀。因此可以通过读取相邻的两个格子然后插值解决:
实践
GLSL (GAMES104)
直接从 GAMES104 的作业 2 里搬过来了:
#version 310 es #extension GL_GOOGLE_include_directive : enable #include "constants.h" #define ColorGridingIntensity 1.0 layout(input_attachment_index = 0, set = 0, binding = 0) uniform highp subpassInput in_color; layout(set = 0, binding = 1) uniform sampler2D color_grading_lut_texture_sampler; layout(location = 0) out highp vec4 out_color; void main() { // 获取LUT大小以计算格子数 highp ivec2 lut_tex_size = textureSize(color_grading_lut_texture_sampler, 0); highp float _COLORS = float(lut_tex_size.x / lut_tex_size.y); // 上一阶段传过来的画面 highp vec4 color = subpassLoad(in_color).rgba; // 计算要采样第几个格子 highp float blueColor = color.b * (_COLORS - 1.0); // 手动给蓝色值插值 highp vec2 uv1 = vec2((color.r+ floor(blueColor))/_COLORS,color.g); highp vec2 uv2 = vec2((color.r+ ceil(blueColor))/_COLORS,color.g); highp vec4 c1 = texture(color_grading_lut_texture_sampler, uv1); highp vec4 c2 = texture(color_grading_lut_texture_sampler, uv2); highp vec4 newColor = mix(c1, c2, fract(blueColor)); // 按调色强度系数处理最终结果 out_color = mix(color,newColor,ColorGridingIntensity); }
效果如下: