whoimi

A geek blog

View on GitHub

- HDRColorGrading技术方案

​ - 整体流程

​ - 详细流程

​ - PQ空间转换

​ - Amplify

​ - PG空间ColorGrading

​ - 线性空间ToneMapping

​ - 显示器亮度配适

​ - 对于hdr显示器

​ - 对于sdr显示器

​ - ToneMapping

​ - hdr显示器Displaymapping曲线设计

​ - Sdr显示器Display Mapping曲线设计

​ - GumatMapping

​ - 相关资源制作

​ - DaVinCi ColorGrading Lut制作

​ - 引擎中导出图片或视频

​ - DaVinCi设置

​ - DaVinCi导入图片

​ - Lut导出cube

​ - cube文件转换成引擎可用的lut

HDRColorGrading技术方案

为了兼容HDR显示屏和SDR显示屏,重新设计了ColorGading和ToneMapping的技术方案。

重点是合理控制颜色空间、亮度和显示器的配适。

整体流程

首先整体流程:

  1. 定义lighting Render Target,格式为R16G16B16A16.

  2. 光照计算结果需进行限制:65535,这部分是为了防止数据溢出。

  3. 进行HDR阶段的后处理。
  4. HDR最后阶段:PQ空间的ColorGrading。这里需要有一个信号放大,用来缩放屏幕亮度和nits的匹配关系。

  5. 针对nits的ToneMapping:根据显示器的nits值选择对应的ToneMapping曲线。

为了能够更好地控制亮度的变化,我尝试使用显示器的nits值来做不同的ToneMapping。sdr为100nits, hdr为10000nits。sdr执行高强度的mapping,hdr执行低强度的mapping。其实原理和很简单,只要对颜色亮度做一个压缩,调整一下亮度范围即可。

  1. Gamut Mapping。
  2. 配适显示器亮度曲线。

颜色处理部分的代码如下:

	float Amplify = 3;
	float ExposureFract = 0.0001 * Amplify;

	HDRColor *= ExposureFract;
	float3 pqSpace = InvertPQcurve(saturate(HDRColor));

	//PQ SPACE ColorLookupTable

	HDRColor = PQcurve(pqSpace);
	HDRColor /= ExposureFract;

	// HDR Display
	{
		OUT.Color.xyz = ToneMapping1(HDRColor * Amplify);
	}
	// LDR Display
	{
		OUT.Color.xyz = ToneMapping2(HDRColor * Amplify);
	}

详细流程

这部分说明关键步骤详细流程。

PQ空间转换

这里我们使用PQ空间,这样使用更多的数据位表示暗部数据。

Note:

这里对于哪个空间更好还是存疑的,因为使用PQ曲线是寒霜引擎的推荐(但是他针对的是端游),同时最后一步还要执行一次PQ,这样精度损失理论上是最小,不过还需要测试和对比。

PQ空间转换代码:

float3 InvertPQcurve(float3 x){
    float c2 = 2413.0 / 128;
    float c3 = 2392.0 / 128;
    float c1 = c3 - c2 + 1.0;
    float m1 = 1305.0 / 8192;
    float m2 = 2523.0 / 32;

    float3 y = pow( (c1 +  c2 * pow(x,m1) )/(1 +  c3 * pow(x,m1)), m2);
    return y ;
}

PQ空间还原代码:

def PQcurve(x):
    c2 = 2413.0 / 4096 * 32
    c3 = 2392.0 / 4096 * 32
    c1 = 3424 / 4096 
    m1 = 2610.0 / 4096 / 4
    m2 = 2523.0 / 4096 * 128

    y = pow((pow(x,1/m2)-c1) / (c2-c3*pow(x,1/m2)), 1.0/m1)
    return y 

PQ空间曲线:

1590136497248

Amplify

为了更好的配适亮度,需要一个缩放Amplify,模拟拍摄过程中的模拟信号放大。

PG空间ColorGrading

进入PQ空间之后采样制作好的PQ空间LUT:

这一步结束之后HDR的ColorGrading就制作完成了。

线性空间ToneMapping

颜色制作完成之后,我们就需要执行tonemap

Note:

我还是考虑使用计算方式的tonemap,不过大部分项目都选择把ToneMapping结合到lut当中去,这里也可以延续这个做法。

但是有个关键的问题是ColorGrading可以用来修改气氛,不同的场景是可以修改的,并且最好sdr和hdr使用同一套内容。所以优先希望简化tonemapping曲线,而不是合并lut。

针对不同的显示器需要不同的曲线。

显示器亮度配适

在输出之前要确定亮度正确的编码,以被不同的显示器正确显示。

对于hdr显示器

如果使用R10G10B10A2格式(目前确认过,HDR支持全部使用这种格式)需要使用PQ曲线进行mapping。

如果使用R16G16B16,使用线性缩放。

对于sdr显示器

如果使用sRGB8,使用线性压缩。

如果使用RGB8U,使用Gamma曲线mapping。

ToneMapping

hdr显示器Displaymapping曲线设计

可以考虑使用UE的FilmToneMapping,这部分会和Sdr显示器有较大区别。

Sdr显示器Display Mapping曲线设计

目前根据常规做法,可以使用ACESFilmToneMapppiong曲线。

Note

当然也可以使用UE的Filmic,不过参数完全不同,效果也一样会有所差别。

GumatMapping

颜色空间的映射需要确定,目前来看是没有进行任何mapping。

相关资源制作

DaVinCi ColorGrading Lut制作

需要制作的资源主要是lut。

引擎中导出图片或视频

导出的图片是linear空间的hdr数据,直接进行PQ编码,得到PQ编码后的文件。此时的数据范围为:0-1.

DaVinCi设置

我们所有的设置都在HDR的PQ空间中进行。所以对于不同的显示器只需要用同一个LUT即可。

DaVinCi的设置大部分保持默认,LookUpTabbles保证为空:

1590733135642

在HDR显示器上进行Lut制作时的设置:

1590733737966

在SDR显示器上进行Lut制作时的设置,这里设置取决于我们如何执行Gamut Mapping,也可以保持和HDR一样:

1590734156399

我们不需要开启Node的HDR mode,只是控制有所区别,对于结果没有影响。

DaVinCi导入图片

直接将图片拖拽到Clip中即可,然后打开Color面板进行调整。

Lut导出cube

完成设置后右键clip点击Generate 3D LUT(33 Point Cube)即可。

1590735234391

此时我们会得到一张.cube文件,大小为33 * 33 * 33的三维纹理。

1590736942822

cube文件转换成引擎可用的lut

1590736912628

下面我们要把从DaVinCi当中导出的.cube文件转化成二维纹理。

打开PS,加载默认的LUT文件(就是netrual lut,不对图像产生影响的lut)。

1590739624304

确定颜色模式为RGB

1590739649754

开启颜色查找功能:

1590739676967

使用默认选项点击确认,得到lut图层:

1590739706978

1590739721058

下面是LUT的图层控制面板:

1590739883952

配置完成之后就得到了修改好的lut,保存成非压缩的png即可:

1590739972583