一些记录
首先需要明确的几点
1、默认PS环境下的颜色是gamma sRGB color space 调色板中的颜色值是线性颜色经过sRGB OETF后的值。
2、
sRGB颜色空间的OETF近似值:pow(col,0.45) EOTF:pow(col,2.2) 因为sRGB的传递函数近似一条pow2.2的伽马曲线
3、引擎中常说的线性,并不是一个颜色空间的概念,应该将其理解为一种working space,以UE和Unity最常见的SDR显示器输出管线来说。引擎中的working space是linear sRGB color space,也就是说我们选择的颜色空间始终是sRGB颜色空间。不过在这个working space下的颜色的值都是线性颜色的值。
不考虑CRT校正,自然界中的颜色信息是线性变化的。同理,我们保证颜色是以线性的颜色值为参考标准,一个线性颜色,由于不同的颜色空间有不同的OETF,所以当其转换到不同的颜色空间时,他们在不同的颜色空间下的颜色数值可能不一样,但他们代表的是一个颜色。
以下以PS导出的sRGB图到引擎中的流程做说明,如之前所说PS中的颜色值是线性颜色经sRGB OETF后的值,所以PS中显示的颜色如果是a,那么其对应线性颜色的值为pow(a,2.2),PS在存贮sRGB图片的时候存的不是线性的pow(a,2.2)颜色信息,而是存储的经过sRGB OETF的信息a。
PS到UE的流程(设PS中显示的颜色为a)
1、如果图片勾选了sRGB,那么引擎就会认为这张图是存储了PS导出时进行过一次OETF的颜色信息,所以要返回正确的线性颜色,引擎就会做一次pow(2.2)的处理,即此时的颜色返回值为pow(a,2.2),其实就是其在linear sRGB color space下的值。再加上之后的引擎sRGB OETF编码和CRT的pow(2.2)抵消,最后看到的颜色就和PS的颜色相同了。
2、如果图片没有勾选sRGB,那么引擎就不会对颜色做处理,所以直接在linear sRGB color space下返回的a的值就会使看上去就变亮,所以就需要在材质中pow(2.2)才能保证颜色和PS中看上去相同。
https://zhuanlan.zhihu.com/p/36507196
如果到Unity中 则gamma空间和线性工作流分开看
1、如果是gamma工作流,那么无论导入的图片是否勾选sRGB的选项,引擎都不会对图片信息做处理。所以导入的颜色图片还是a,伽马工作流也没有tonemapping和引擎的sRGB OETF,所以只有之后的CRT的pow(2.2),其值就等于线性下的pow(a,2.2),所以看到的颜色就是PS中的颜色。
所以很重要的一点就是这种伽马工作流的情况下,unity中所作的所有颜色,光照等的计算。都是在gamma sRGB color space下进行的,是非线性的。
2、如果是线性工作流,那么会和UE的处理一样
如果图片勾上sRGB,那么引擎会做一次pow(2.2)的处理将颜色转到线性颜色
如果图片没有勾sRGB,那么引擎则不会做处理
可以看出,PS导出的一张颜色图,导进UE后勾选了sRGB,材质直接采样输出可以保证颜色和PS中的颜色看上去相同。但虽然看上去虽然相同,linear sRGB color space下的颜色已经需要用线性颜色的值来表示了。所以一旦牵扯到sRGB贴图中的某些通道要拿来做光照计算之类的操作的话,勾上了sRGB的贴图就不能直接把贴图通道的返回值拿来做计算了。
比如PS出一张128颜色的中灰图,导入UE,如果贴图勾选了sRGB。那么进引擎后引擎会做pow(2.2)的处理,此时导入的sRGB图中PS下的128也就是PS下的中灰。此时在引擎中的值变成了pow(0.5,2.2)=0.218。而UE材质中的值都是线性的值,所以和UE材质中的0.5是对不上的。也就是说UE材质里填的0.5,是线性下的0.5的值,其对应于PS中的颜色就应该是pow(0.5,0.45)=0.73的值了。
所以,为了让UE中的线性值的0.5和PS中的sRGB的128能对的上,需要怎么做呢。那就需要根据贴图是否勾选了sRGB来在材质中进行pow计算来使他们对上。
以贴图不勾选sRGB的情况来说明。以PS中的中灰(0.5)为例,引擎不会做pow(2.2)的校正,所以进UE后其值还是为0.5 这时UE材质中的线性0.5就能和PS颜色中的中灰128对上。
同理,如果贴图勾选了sRGB。进UE后值为pow(0.5,2.2),所以要在材质中添加pow0.45来使值对上。
这种光照计算相关的贴图的使用一般出现在一些卡渲游戏的ILM图中:
碧蓝做法(Base、SSS、ILM等所有图都不勾sRGB)材质中全部算完后pow2.2
所以从节省计算量的角度出发,这些与光照相关的贴图应尽量不勾选sRGB,这样最大的好处是能方便美术同学做图,美术同学不需要考虑这些颜色变换,只需要知道材质参数的0.5就直接对应PS中的128就行了。
以上所说都是针对的PS的RGB颜色通道,A通道的信息使用稍有不同。主要原因是UE不会对导入的贴图A通道做任何校正处理。
所以以带A通道的TGA格式贴图为例,如果A通道的信息是用于存储一些矢量信息用于算光照之类的,那么UE贴图中不勾sRGB直接将采样的值用于计算就行。如果A通道的信息是当成颜色信息用,比如要用于贴图的透明度通道,那么就需要在材质中添加pow2.2,以转到linear sRGB space。
但是一般的特效半透贴图都是PNG格式的,UE中采样PNG A通道输出的信息就直接是PNG图片的透明信息,没有一个专门的透明度的通道。那要怎么知道这个采样PNG的A通道的信息到底是什么信息呢,这里用如下贴图做测试。
UE材质中直接采样输出A通道,直接输出是这样
这说明采样PNG A通道返回的值也是没有经过处理的值,所以材质里也需要添加pow2.2来保证PNG的透明度信息也转换到linear sRGB space下。
补充:
上面对于PNG格式的图片的描述不是很准确,PNG图片有24位和32位俩种格式,32位格式的PNG是有8位来存透明度信息的。平时在PS中处理图片时通道面板一般只有RGB三个,如果图层不透明度是100%,并且图层中所有像素都占满。那么此时导出的PNG图就是24位的,没有透明度信息。但是反之一旦图层不透明度不是100%,或者有些像素没有颜色信息。那么此时PS导出PNG图会自动处理成32位的,PS会在存图时自动用8位来存透明度信息。只不过对于透明度的处理,美术同学在PS中工作时无需关心。
同时PS的导出选项中可以设置强制带上透明度,比如本身没有透明信息的24位的图也可以通过该方式强制导出成32位。。
同时要注意PS中调整A通道的值的时候,工作空间下的灰色要设成Gray Gamma2.2才能保证A通道颜色拾取的值和RGB通道的显示一样。只影响PS中的显示值,不影响实际的线性颜色值。
而像其他如Substance下的working space和引擎一样都是线性的,所以导出光照计算相关的贴图的时候直接选Linear来存,存的信息就是没有经过OETF的线性信息,导入引擎后默认sRGB就是勾掉的,直接参与线性光照计算即可
透明混合:
线性工作流下透明混合也是线性的过程,所以都是在线性空间下计算
Unity伽马工作流下透明混合则是直接在sRGB颜色空间下计算的
这也就是unity伽马工作流和线性工作流半透效果有比较大区别的原因
由于卡渲游戏风格化要求较高,其实很多项目的tonemapping颜色映射主要体现在了bloom曝光的部分,线性working space用的更多的还是PBR相关的项目,在线性下进行光照计算,再经过tonemapping,color space transformation转换颜色到输出设备的颜色空间,一般都是这样的流程。
HDR
这个词的理解就比较微妙,在各种地方都会出现。比如引擎中的这个linear sRGB color space就是个HDR的working space,因为光的计算能到几万尼特。HDR又会出现在颜色空间的定义中,比如Rec2020、ACEScg这样的HDR颜色空间。HDR还会出现在LDR显示器和HDR显示器和其对应的OETF中。所以要注意他们的区分。不能简单的用HDR一个词来概括他的定义。
COD SDR Pipeline:
1、PS将线性颜色进sRGB OETF编码存储为图片传给引擎
2、引擎获取图片,经sRGB EOTF转成线性值
3、传入光照计算,得到高动态范围的scene referred image
4、scene referred image到display referred image的转化(Tonemapping颜色映射),引擎使用显示器颜色空间的OETF对最后输出编码然后发给显示器
5、显示器EOTF
Tonemapping主要发生在线性下光照计算完后,此时需要将高范围的颜色转换到有限的显示器亮度值下,本质是用一个函数把高动态范围的亮度值映射到0~1的范围下。
在看HDR Pipeline前,先需要了解ACES
ACES
主要提供了颜色编码和度量规范,文件格式规范和颜色转换规范
ACES2065-1(ACES AP0)和ACEScg颜色空间的广色域,ACEScg(AP1)多用于CG和VFX的渲染计算。
UE4在SDR下的实现与ACES sRGB几乎一样
COD HDR Pipeline:
COD的HDR Pipeline和UE的有些区别,具体请看乐乐姐的文章,这里主要记录UE相关
1、前面部分和SDR Pipeline一样,还是sRGB图进来转线性然后在linear sRGB color space下一顿算
2、UE也有CLUT的生成,将场景的线性亮度转换为0-1的编码值,后续通过ST2084ToLinear进行解码来得到线性亮度值参与后续计算
3、应用曝光参数将亮度缩放(white balance),同时将颜色空间从sRGB转换到HDR颜色空间(ACESAP1),然后在linear ACESAP1 color space下应用Color Grading。由于渲染都是在linear sRGB color space下算的,所以色度值始终都在sRGB色度范围内。
4、Tonemapping和引擎display mapping输出到特定的显示器上
display mapping根据显示器为SDR还是HDR显示器分为俩种情况:
SDR下的Output Transform使用ACES的LMT+RRT+ODT
ACES LMT修正高亮度的蓝色值导致的过饱和问题
ACES RRT的Tonemapping
先抵消之前LMT的Blue Correction,然后把颜色空间从AP1变回sRGB颜色空间
根据SDR显示器应用OETF编码传递给显示器
HDR下的Output Transform
没有类似Tonemapping的计算,而是在color Grading后直接把颜色空间从AP1变回sRGB。然后直接进行ODT,也就是PQ的OETF编码把编码后的HDR信号传递给HDR显示器。
显示器EOTF
关于SP和引擎效果对齐,建议看乐乐姐的文章。由于SP中只有IBL光照部分,所以要在SP中自定义shader,添加直接光部分。而且由于间接光漫反射(Unity3阶SH,SP2阶SH,区别较小)和高光反射(UnityMipmap,SP近似重要性采样,区别较大)的区别,SP和引擎中的效果多少还是有差距的。但最主要需要统一的区域还是tonemapping的影响,思路是根据引擎中使用的tonemapping曲线,生成相应的SP的LUT做校正,具体见文章。
参考:https://www.zhihu.com/people/lele-feng-15/posts