[GAMES104]-作业2
因为一直要赶一堆莫名其妙的ddl和考试 task3没做 日后再补_(:з」∠)_
Color Grading与LUT
调色是增强画面表现力的一种很有效的手段. 本次作业我们处理的颜色在sRGB空间内, 红、绿、蓝三个颜色分别用一个\([0,1]\)的实数来表示. 将三原色分别用一个坐标轴来表示, 便构成了如图所示的色彩空间(图片来自defold.com):
在进行调色时, 我们对渲染结果的每个像素进行处理, 根据像素原本的RGB值将其映射到一个新的色彩空间. 这种映射一般采用LUT(look up table)图来进行. LUT有1D和3D之分, Pilot Engine使用的是3D的LUT, 它看上去像这个样子:
这张图片的长为\(1024\)个像素, 宽为\(32\)个像素, 可以看出它由\(32\)个小色块组成. 将这些小方块自上而下拼接在一起, 便组成了一个\(32 \times 32 \times 32\)的色彩空间. 我们需要做的便是根据每个像素的RGB分量找到它在这张图上对应的像素. 具体来说, 原像素的\(G\)分量指示了新像素在LUT上的纵坐标, \(B\)分量指示了新像素所属的色块编号, \(R\)分量指示了新像素在某个色块内部的横坐标.
编写Shader
我们需要编写的Shader文件是color_grading.frag
, 可以在\engine\shader\glsl\
中找到.
这个shader已经提供了原像素的颜色in_color
和LUT的2D采样器color_grading_lut_texture_sampler
. 我们需要根据原像素的颜色计算出调色后的颜色并将其赋值给out_color
作为输出.
在计算前, 需要获取像素的颜色值:
1 | highp vec4 color = subpassLoad(in_color).rgba; |
颜色值是一个四维向量, 四个维度分别代表R、G、B和alpha, 均为\([0,1]\)的实数.
在计算出坐标后, 需要从LUT上获取对应的颜色:
1 | highp vec4 color_sampled = texture(color_grading_lut_texture_sampler, uv); |
其中color_grading_lut_texture_sampler
已经提供, uv
是一个二维向量, \(u\)代表横坐标, \(v\)代表纵坐标, 坐标原点在图片的左上角, \(x\)轴方向向右, \(y\)轴方向向下. \(u,v\)也是\([0,1]\)上的实数.
我们还需要获取LUT的长宽:
1 | highp ivec2 lut_tex_size = textureSize(color_grading_lut_texture_sampler, 0); |
有了如上函数, 不难计算出每个像素在LUT上的对应位置. 设\(C\)是LUT的宽, \(R,G,B\)分别为像素的原颜色分量, 则有: \[ u = \frac{\lfloor B \cdot C \rfloor + R}{C}\\ v = G \] 为了提高准确度和防止越界, 可以在LUT的边界上各留出0.5个像素, 将RGB值映射到\(C-1\)个像素中去. 具体细节见代码:
1 |
|
效果展示与自定义LUT
在\engine\asset\texture\lut
中存放着不同的LUT. 通过修改\engine\asset\global\rendering.global.json
中"color_grading_map"
项可以替换不同的LUT.
在不进行调色时的效果是这样的:
调色后的效果:
要创建自定义的LUT, 只需在GIMP或者PhotoShop等工具编辑原始LUT图像(可以附一张截图方便观察调色效果).
负片效果的LUT:
偏冷色调(好像太绿了):
PS:调色后会出现看上去很奇怪的色块, 目前还不知道如何解决