Gamma 校正
物理亮度是基于光子数量的, 一般是线性的, 而传统的CRT显示器, 会将亮度做2.2次幂. 即会将中间的笔直的直线, 映射成为下方弯曲的直线.
可以计算下[0, 1]内的数取2.2次幂的结果, 接近0的数
0.
2
2.2
<
0.2
=
0.02
0.2^{2.2} < 0.2 ~= 0.02
0.22.2<0.2 =0.02 而
0.
8
2.2
=
0.61
0.8^{2.2} ~= 0.61
0.82.2 =0.61
所以我们如果将0.5的亮度在物理中提量1倍, 到1.0, 而在显示器上实际呈现的效果将会是从0.218 提高到 1, 增幅达到4.5倍, 显然是不科学的.
因此需要Gamma校正, 先对我们的亮度取
1
2.2
\frac{1}{2.2}
2.21次幂, 比如
(
0.
5
1
2.2
)
2.2
(0.5^{\frac{1}{2.2}} )^{2.2}
(0.52.21)2.2 就会变回到线性空间了.
但是要注意Gamma校正一定要放在最后一步, 如果放在fragment shader之间做Gamma校正, 那么后面取的颜色都是在校正后的非线性空间上, 会出问题.
sRGB纹理
sRGB空间定义的gamma接近于2.2, 因此相当于gamma空间
当我们在sRGB空间去制作图片, 并且在sRGB中观看图片, 没什么问题.
但是如果我们是将纹理放置到线性空间(上图中笔直的线的空间), 那么会有问题, 因为我们输出到显示器上的时候, 会自动进行Gamma校正, 会使得颜色在上边的曲线上, 这样颜色就会过曝.
解决方法, 校正回来, 对
颜
色
1
g
a
m
m
a
颜色^{\frac{1}{gamma}}
颜色gamma1校正回来.
衰减
光的衰减物理上与距离平方成反比
float attenuation = 1.0 / (distance * distance)
然而这样的衰减在实际屏幕上, 造成衰减效果过于剧烈, 光只能照亮一小部分区域,
另一种方式使用以下双曲线函数
float attenuation = 1.0 / distance
双曲线函数比二次函数 不用gamma校正更真实, 因为在屏幕的gamma次数下
双曲函数衰减会变成如下形式
(
1.0
/
d
i
s
t
a
n
c
e
)
2.2
∼
(
1.0
/
d
i
s
c
a
n
t
e
)
2
(1.0 / distance)^{2.2} \sim (1.0 / discante)^2
(1.0/distance)2.2∼(1.0/discante)2, 在屏幕gamma次数下, 更接近物理模型.