现实生活中所有东西和光接触后产生的结果,不能都用光线传输来模拟,其难负重任,这时着色器粉墨登场。
要显示一个物体需要计算对象表面的每一个点的颜色和亮度。两者有着很紧密的关系。物体的亮度是指有多少光落在物体表面,物体颜色的亮度和色调、饱和度有关。如果两个颜色相同的物体在同样光线条件下,一个比另一个看起来暗,那么很显然,这不是哪个物理表面光线落的多少的问题,而是哪个物体反射光线到环境中更多的问题。颜色的亮度是不同的,在图形学中,一个物体的颜色被称为albedo。
注意一个物体反射的光不可能比接受的多(除非自身就是个光源)。物体颜色一般是通过计算入射光(白色)的反射比例得出的。因为反射出来的光小于接受的光,比值永远小于1。这就是为啥物体的颜色定义在0到1之间,如果是RGB的话就是0到255之间。举例,当比值或颜色或albedo(一回事儿)是0.18,意思就是物体把所接受到的光的18%反射到了环境中。
如果一个物体表面的入射光的能量是1000,物体的颜色是0.5,那么眼睛看到的就是反射出来的500。(注意从物理角度看,这么说是错的,只是在学习着色时,这样解释比较直观)。
为了计算某一点颜色,需要知道两件事:
-
该点处落了多少光。
-
该点的观察角度反射出多少光。
不要忘了,对于一个光泽表面,光反射的量和观察角度有关。
假设物体颜色已知,求一,有多少光到达点P?二,从点P到眼睛的方向上反射出多少光?
-
第一个问题就是计算光线传输(直接光照和间接光照),着色的作用就是明确了光线的选择(只在乎视角方向的光线)。
-
第二个问题比较复杂,接下来慢慢说。
首先,从表面反射回环境中的光线和物体材质有着非常复杂的交互。
-
这些交互一般很难模拟。
-
光反射的量取决于视角方向。除了完美的漫反射表面以外,入射光在每个方向上的反射不是完全相等的。而现实中,绝大部分物体都是漫反射和镜面反射的混合。
-
光在视角方向上反射的量还取决于入射光的方向。如图3,入射角和反射角都相等,但视角不同。上方图反射光正好进入眼睛,而下方的图则不是,眼睛就看不到了。
总结一下 - 模拟光物交互太难(微观或者原子层面),需要另辟蹊径。 - 光反射的量和视角方向ωv有关。 - 给定了ωv的情况下,光反射的量取决于入射光ωi。
着色器,你可以看作是渲染过程的一部分,它负责计算光从表面反射到眼睛(或者场景中其它表面)的量。这至少和两个变量有关:入射光方向,视角方向。入射光和物体本身无关,而反射光取决于物体类型:漫反射表面,还是镜面表面?
收集抵达P点的光线是一个光线传输问题,不过到此为止,我们都算作是着色器。可以把一个着色器当作是程序中的程序,把入射光方向和视角方向看作输入,把这些方向上,表面将反射的光作为输出。
`反射光比例 = shader(ωi,ωo)`
如此复杂的光物交互可以用一个很简单的数学公式来模拟:
`ωr=ωi−2(N.ωi)N`
白话就是,反射方向等于入射方向减去,2倍的法线点乘入射方向再乘以法线。记住,ωr=ωo时,反射率为1(图3上),否则为0(图3下)。
其实这个公式就是完全镜面反射,这个例子在实际过程中根本不会用到。只是用来了解光在难以模拟的时候是如何用数学模型来计算的。这也就是着色器真正的作用:将复杂的光物交互用数学模型代替,虽然不是非常精确或者不符合物理现象,但确是能得到有意义的近似结果。研究着色就是开发新的数学模型,这个本身难度就很高,而且不同的材质影响不同,需要不同的模型,比如为棉花开发一种模型,为丝绸要开发另一种模型。
对于漫反射表面,反射光线在任何角度都是相等的。眼睛看到的光线就是达到表面光线的总量乘以表面颜色(即一部反射回环境的入射光),有时候还会再除以一些数学或者物理上用到的系数。还有一点关于漫反射,入射光和反射光的方向不影响反射量。
总结
光线传输和着色之间分的没那么清,实际上光线传输算法经常会依赖着色器,找出计算入射光所产生的二次射线的方向。
对于着色有两件事情需要记住:
-
着色,是渲染过程的一部分,用来计算光反射到任意视野方向上的量。换句话说,就是图片中物体最终显示的具体样子、颜色、材质、亮度,等等。 模拟一个物体的形状只需要想一个问题:物体接受的光的总量中,有多少反射回了眼睛里(或者说当计算间接光照时,任意方向上的光有多少是有实际意义的)。
-
把着色器当作一个用来解决问题的黑盒。“如果一块木头做的物体被来自方向ωi的光照着,那么反射回环境中在方向ωv上的光有多少?”。着色器就是用来解决这个问题的。把着色器比作黑盒不是因为它内在很神秘,而是因为它可以看作是渲染系统中一个比较独立的模块,这也是为什么着色器的API写起来和应用程序其它部分没什么关系。