文章

URP中着色器去色代码

URP中着色器去色代码

URP中着色器去色代码

00 前置知识

通常的做法是使用

\[Y=0.2126R+0.7152G+0.0722B\]

代码在Packages/com.unity.render-pipelines.core/Runtime/Utilities/ColorUtils.cs

1
2
3
4
5
6
7
/// <summary>
/// Returns the luminance of the specified color. The input is considered to be in linear
/// space with sRGB primaries and a D65 white point.
/// </summary>
/// <param name="color">The color to compute the luminance for.</param>
/// <returns>A luminance value.</returns>
public static float Luminance(in Color color) => color.r * 0.2126729f + color.g * 0.7151522f + color.b * 0.072175f;

等价于hlsl代码:

1
2
/// 等价于
float luminance = dot(color.rgb, float3(0.2126729f, 0.7151522f, 0.072175f));

01 实施

要注意的是, 这里的输入是线性颜色, 如果输入的是sRGB的颜色(通常材质球面板上的直接输入就是sRGB颜色)则需要先转一次线性, 计算明度后再把明度转回来, 代码在Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
real3 SRGBToLinear(real3 c)
{
#if defined(UNITY_COLORSPACE_GAMMA) && REAL_IS_HALF
    c = min(c, 100.0); // Make sure not to exceed HALF_MAX after the pow() below
#endif
    real3 linearRGBLo  = c / 12.92;
    real3 linearRGBHi  = PositivePow((c + 0.055) / 1.055, real3(2.4, 2.4, 2.4));
    real3 linearRGB    = (c <= 0.04045) ? linearRGBLo : linearRGBHi;
    return linearRGB;
}

real4 SRGBToLinear(real4 c)
{
    return real4(SRGBToLinear(c.rgb), c.a);
}

real LinearToSRGB(real c)
{
    real sRGBLo = c * 12.92;
    real sRGBHi = (PositivePow(c, 1.0/2.4) * 1.055) - 0.055;
    real sRGB   = (c <= 0.0031308) ? sRGBLo : sRGBHi;
    return sRGB;
}

当然, 如果你不想转线性, 可以直接用拟合函数(推荐)

1
float luminance = dot(color.rgb, float3(0.299f, 0.587f, 0.114f));

如果你要转, 则精确算法如下

1
2
3
float3 lin = SRGBToLinear(color.rgb);
float luma = dot(lin, float3(0.2126729, 0.7151522, 0.072175));
float gray = LinearToSRGB(luma);

02 数据对比验证

sRGB+NTSC代表拟合函数

Lin+Rec709代表精确算法

RGBFast (sRGB+NTSC)Accurate (Lin+Rec709)Difference
0.20.30.50.29290.3033+0.0104
0.80.60.20.61420.6331+0.0189
0.50.20.70.34670.3518+0.0051
1.01.01.01.00001.0000~0
0.00.00.00.00000.00000

这里是纯色, 即rgb值一样的颜色, 两种算法的误差图, 可以看到差别在1e^-8这个量级

Grayscale-Accurate-vs-Fast

Difference-between

参考网页
本文由作者按照 CC BY 4.0 进行授权