美术前上个礼拜找我问光照图总是烘焙过暗的问题,一时兴起我在 Gamma 和 Linear 两个颜色空间切换了下,发现一个 Shader 明暗不同,另一个 毫无变化,于是激发了我去研究下在 Unity 里使用 Linear 的细节。(虽然最后发现美术的问题跟这个不太有关系)

  这里不想在过多冗长的去复述关于所有 Gamma 校正的历史和概念,假设已经阅读过相关资料,比如以下(包括但不限于):

  https://www.cnblogs.com/murongxiaopifu/p/9001314.html

  https://blog.csdn.net/candycat1992/article/details/46228771

  https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch24.html

  https://www.qiankanglai.me/2014/12/24/gamma-correction/

  https://docs.unity3d.com/Manual/LinearLighting.html

  这里仅仅讨论下 Unity 平台下 Linear 空间下渲染出现的和预期不一致的错误(姑且先叫错误,着实还不明白的地方),和所理解然后预期的结果不一致。测试场景也很简单,制作三张红色贴图A, B 和 C,其中 A 和 B 一样:(127,0,0),C 为(187,0,0),其中187=((127/255)^0.45)*255。A 导入选项为 Linear,不勾选 sRGB,B 勾选 sRGB,C勾选 sRGB。

     

A                                                            B                                                           C

  可以发现,A 保持颜色不变,B 和 C 的颜色都变暗,都被做了 Gamma 校正 2.2,所以更暗;尤其是 C,原本 187 的颜色被矫正后,正好变成127,这是符合预期的。

  接下来在场景中创建三个材质,使用 Shader:Unit/Texture 来显示贴图本身颜色,贴图分别使用 A, B, C;然后创建一个 Sphere 分别使用这三个材质在 Linear 空间下渲染查看颜色。显示效果如下:

     

A                                                                                 B                                                                       C

  然而预期结果为:球 A 和 C 均为 (127,0,0)B 为(55,0,0)。根据:A 贴图为 Linear,采样后不会被硬件 Gamma 2.2 而维持原样,Shader 计算输出到 ColorBuffer 时 Gamma 0.45 提亮,最终输出到显示器再 Gamma 2.2,最终输出颜色(127,0,0);B 贴图为 sRGB,采样后被硬件 Gamma 2.2 为 ((127/255)^2.2)*255=55,然后 Shader 中计算输出 ColorBuffer 时 Gamma 0.45 变回到127,最终被显示器 Gamma 2.2,输出颜色(55,0,0);

  以上可以看到实际渲染结果和预期结果的差异:实际渲染结果都被“提亮“了,都额外的被多增加了一个 Gamma 0.45。可是至少 Linear 的图片是什么颜色就应该输出什么颜色。于是将以上三种情况分别在手机上使用 RenderDoc 抓帧分析下。

  场景 A:

以上分别显示了 A 场景中,图片的格式,以及纹理缓存的格式:

  Red127_Linear 格式:GL_COMPRESSED_RGB8_ETC2,颜色为(127,0,0);

  Color Buffer 格式:GL_SRGB8_ALPHA8,颜色为(187,0,0),

  由于写入 ColorBuffer 会做 Gamma 0.45 的校正,所以 ColorBuffer 这个颜色是正确的,配合显示器的 Gamma 2.2 校正,应该正好为(127,0,0)。可是实际上显示器输出的就是 ColorBuffer 的内容(187,0,0),像是没有经过 Gamma 2.2 校正;抑或是因为 sRGB 格式的 ColorBuffer 再次被 Gamma 0.45,然后再被显示器 Gamma 2.2,否则如何解释呢?暂时不明白。

  

  那么再看下场景 B:

  Red127_sRGB 格式:GL_COMPRESSED_SRGB_ETC2 颜色为(55,0,0),因为 sRGB 图片做了 Gamma 2.2 校正;

  ColorBuffer 格式:GL_SRGB8_ALPHA8,颜色为(127,0,0),

  所以当 Color 输出到显示器做了 Gamma 2.2 校正后,实际颜色应该为 (55,0,0),然而貌似也少了这一步,跟情况 A 一样。

  最后来看下场景 C:

  Red187_sRGB 格式:GL_COMPRESSED_SRGB_ETC2 颜色为(127,0,0),因为 sRGB 图片做了 Gamma 2.2 校正;
  ColorBuffer 格式:GL_SRGB8_ALPHA8,颜色为(187,0,0),

  最后 ColorBuffer 输出经过显示器的 Gamma 2.2 矫正后应该输出颜色 (127,0,0),然而实际却是(187,0,0),同场景 A 和 B 的情况一模一样。

  以上测试使用 Unity 2018.1.2f1。


  综上,以上三种结果和过程分析都指向一个事实:Unity 在 Linear 颜色空间下直接将 sRGB 格式的 ColorBuffer 输出到了显示器,缺少了 Gamma 2.2 这一步,使得颜色都变亮了,无法得出预期的结果,或许有什么地方理解的还不到位,也或者我缺少了过程中的某个设置,目前还不得而知,如果有哪位大牛知道,还请指点下。

【本文固定地址:https://www.cnblogs.com/yaukey/p/unity_linear_color_space_unexpected_results.html

实验 Unity Linear Color Space 发现结果不符合预期的更多相关文章

  1. Unity Lighting - Choosing a Color Space 选择色彩空间(四)

      Choosing a Color Space 选择色彩空间 In addition to selecting a rendering path, it’s important to choose ...

  2. unity color space 选取

    https://unity3d.com/cn/learn/tutorials/topics/graphics/choosing-color-space https://docs.unity3d.com ...

  3. unity linear work flow

    看了下unity linear space的工作流 srgb read tex deferred gbuffer01  srgb rt float rt----pps float rt 最后 blit ...

  4. Color Space

    色域(Color Space),又被称为色彩空间,它代表了一个色彩影像所能表现的色彩具体情况.我们经常用到的色彩空间主要有RGB.CMYK.Lab等,而RGB色彩 空间又有AdobeRGB.Apple ...

  5. Color Space 和 Color Range

    颜色有两个属性Color Range和Color Space 有关Color Space的解释可以看下面两个链接: https://www.jianshu.com/p/facdbab5ac20 htt ...

  6. unity linear space时 photoshop blend的正确设置

    gamma correction的dcc设置 ps在线性空间下工作 blend的时候颜色设置 勾选用灰度系数混合rgb 1.0 这样就是在线性空间下工作了 这样素材在数学上是正确的 r8g8b8a8格 ...

  7. Color Space: Ycc

    在进行图像扫描时,有一种重要的扫描输入设备PhotoCd,由于PhotoCd在存储图像的时候要经过一种模式压缩,所以PhotoCd采用了Ycc颜色空间,此空间将亮度作由它的主要组件,具有两个单独的颜色 ...

  8. Color Space: HSV

    HSV(hue,saturation,value)颜色空间的模型对应于圆柱坐标系中的一个圆锥形子集,圆锥的顶面对应于V=1. 它包含RGB模型中的R=1,G=1,B=1 三个面,所代表的颜色较亮.色彩 ...

  9. Color Space: HSI

    HSI色彩空间是从人的视觉系统出发,用色调(Hue).色饱和度(Saturation或Chroma)和亮度 (Intensity或Brightness)来描述色彩.HSI色彩空间可以用一个圆锥空间模型 ...

随机推荐

  1. NOIP模拟3

    期望得分:30+90+100=220 实际得分:30+0+10=40 T1智障错误:n*m是n行m列,硬是做成了m行n列 T2智障错误:读入三个数写了两个%d T3智障错误:数值相同不代表是同一个数 ...

  2. CF839 D 容斥

    求$gcd>1$的所有$gcd(a_i,a_{i+1}…a_{n})*(n-i+1)$的和 首先先标记所有出现的数.从高到低枚举一个数k,记录它的倍数出现次数cnt,那么当前所有组合的答案就是$ ...

  3. SQLServer字符串的一些截取技巧

    先看一张科学家的生卒年月表 截取科学家的出生年份可以很方便的用left函数截取,如果要截取去世年份,需要先获取字符“—”的位置. select substring(c,charindex('—',c) ...

  4. 为什么 .NET 会被叫做 .NET?

    微软开发.NET Framework是在20世纪90年代后期,最初是叫做“下一代Windows服务”(Next Generation Windows Services 简称 NGWS). 那么为什么微 ...

  5. 【NOIP】普及组2009 细胞分裂

    [算法]数论 [题解]均分的本质是A整除B,A整除B等价于A的质因数是B的子集. 1.将m1分解质因数,即m1=p1^a1*p2^a2*...*pk^ak 所以M=m1^m2=p1^(a1*m2)*p ...

  6. jQuery 页面加载初始化

    jQuery 页面加载初始化的方法有3种 ,页面在加载的时候都会执行脚本,应该没什么区别,主要看习惯吧,本人觉得第二种方法最好,比较简洁. 第一种: $(document).ready(functio ...

  7. 2017ACM暑期多校联合训练 - Team 6 1003 HDU 6098 Inversion (模拟)

    题目链接 Problem Description Give an array A, the index starts from 1. Now we want to know Bi=maxi∤jAj , ...

  8. python3学习笔记.2.基础

    1.编码 默认编码是 utf-8 # -*- coding: utf-8 -*- 2.注释 单行注释  # 多行注释,用三个单引号或双引号 3.关键字 可在交互窗口查询. >>> i ...

  9. Attention-over-Attention Neural Networks for Reading Comprehension论文总结

    Attention-over-Attention Neural Networks for Reading Comprehension 论文地址:https://arxiv.org/pdf/1607.0 ...

  10. Attention is all you need 论文详解(转)

    一.背景 自从Attention机制在提出之后,加入Attention的Seq2Seq模型在各个任务上都有了提升,所以现在的seq2seq模型指的都是结合rnn和attention的模型.传统的基于R ...