前言
在学习的过程中,因为有很多知识点,所以我的需要要求是必须把前面的完全掌握才去学后面的,即使不能也要达到及格线,后面再回来继续学习,反复几次,可以对内容掌握的比较透,及格线的标准是,看过 shader 的要求之后,再打开记事本,写出完整的 shader,因为有很多内置函数变量什么的,如果这些内容不能很熟练,也会加大学习难度,也会分心,总觉得一点都没掌握好。
一、光照篇
光照系统分为三个基本部分:
- 全局光照
- 漫反射
- 高光反射
最终结果为
提个基本的东西,Shader 中向量相乘有三种,点乘法,叉乘,还有分量分别相乘
dot(v1, v2) //点乘,结果是一个单值 float
v1 * v2 //分量分别相乘
1.全局光照
全局光照相对比较简单。直接采用全局光照的颜色值就行叠加到最终颜色里就行:
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
2.漫反射
漫反射基本的分为 普通漫反射 和 半兰博特反射 ( ) 两种。
普通漫反射
这种情况下漫反射实际上等于反射光线的颜色,由于漫反射的反射方向是各个方向相等的,所以不用考虑视角方向。
相关的几个参数为:
- 光线方向 (3维向量)
- 法线方向 (3维向量)
- 光照颜色 (3维向量)
最终结果为
这里考虑一个问题,就是漫反射的结果范围,最小是颜色值为 这个很容易理解,当光线与物体表面垂直时漫反射的光颜色最亮等于入射光线的值,即 ,所以漫反射的颜色范围是 。
漫反射由于反射光是各向相同的,所以射入视线中的光线大小只与光线入射角度和颜色有关,想象一下,如果入射角度与表面完全平行,则漫反射的光线为 0,光线逐渐上扬,直到与表面垂直,这个时候漫反射的光线为最大值,这里定为1,那么就可以取光线在法线方向的分量,这里利用了向量的点乘的物理性质(投影性质)。
一般漫反射还会有一个相关的颜色
,先来看看这个值在颜色计算中的位置:
颜色向量相乘:
从物理意义上可以理解为
的每个分量表示了每个颜色通量的反射程度,比如
为
时表示不反射红色。
这部分的代码总结为:
fixed diffuse = lightColor.rgb * DiffuseColor.rgb * saturate(dot(normal, lightDir))
注意:光线方向和法线方向必须在同一空间中相乘才有效,一般会转到世界空间中进行计算,saturate 是对表达式进行比较,如果小于 0,则取 0,否则取表达式的值,这样防止了背光面有一个负的颜色叠加。
半兰博特反射
考虑到在普通漫反射的情况下,背光的面漫反射全部为 0,无法凸显出背光面的形状,所以进行了改进。公式如下:
相应的代码为:
fixed diffuse = lightColor.rgb * dot(normal, lightDir) * 0.5 + 0.5
由于 dot(normal, lightDir)
的取值范围是
,所以最终颜色结果还是
,在表面与光线反向垂直是漫反射的结果为
,与光线垂直时结果为
纹理
考虑纹理颜色的话就在全局光照和漫反射的光线颜色上乘以纹理颜色即可,公式如下:
完整的代码如下:
fixed diffuse = lightColor.rgb * texColor.rgb * DiffuseColor.rgb * saturate(dot(normal, lightDir))
从物理意义上可以理解光照颜色为纹理颜色反射系数。