Unity Shader自定义光照模型

前几天去一家公司面试,因为简历上写着“能写简单的Shader”,就被问了一个问题:怎么自定义一个光照模型?

直接懵逼了,隐隐约约能联想到的什么漫反射光+镜面反射光+环境光...难道是这个?光照模型就是#pragam surface surf Lambert里面的那个Lambert呗?这不都是写好的吗?还能自定义啊?!本着“程序是严谨的”的心态,宁可说不知道,也不能瞎说。。。

今天有空,抓紧学习一下自定义光照模型...


首先,新建一个SurfaceShader,打开后做如下修改

#pragma surface surf Standard fullforwardshadows >> #pragma surface surfMyLightingModel

之后,在SubShader块儿中实现这个光照模型:


inline float4 LightingMyLightingModel(SurfaceOutput s, fixed3 lightDir, fixed atten)
		{
			float difLight = max(0, dot (s.Normal, lightDir));
			float4 col;
			col.rgb = s.Albedo * _LightColor0.rgb * (difLight * atten * 2);
			col.a = s.Alpha;
			return col;
		}

这个的方法名注意,要前面多了一个“Lighting”,如果直接写“MyLightingModel”是会报错滴...因为找不到,这里具体是怎么做的我也不知道,以后知道了再来补充。

其中lightDir是点到光源的单位向量,atten(attenuation)是衰减系数。如果要用到点到摄像机(观察者)的单位向量,就需要另一个参数:half3 viewDir(因为这个模型是个漫反射模型,就先不考虑观察者角度了)。

dot方法是点乘(点积),在这里求的是入射光线和该点法线的相似度,相似度越高,反射的光线就越多。

关于这个_LightColor0变量,查了一下,比较复杂,是根据当前环境中的各种光源计算出来的...我们只管用就好了。

以上就实现了一个简单的反射的光照模型。


最后来一个漫反射+镜面反射的光照模型,是不是传说中的冯氏反射模型呢?暂且就当做是吧...

float4 LightingPhongModel(SurfaceOutput s, float3 lightDir,half3 viewDir, half atten)
		{
			float4 col;

			float diffuseF = max(0,dot(s.Normal,lightDir));

			float specF;
			float3 H = normalize(lightDir+viewDir);
			float specBase = max(0,dot(s.Normal,H));
			specF = pow(specBase,8);

			col.rgb = s.Albedo * _LightColor0 * diffuseF *atten + _LightColor0*specF; 
			col.a = s.Alpha;
			return col;
		}

float3 H = normalize(lightDir+viewDir);
float specBase = max(0,dot(s.Normal,H));
specF = pow(specBase,8);
这三句是用来计算镜面反射的,镜面反射必然与观察者的位置有关,所以这个方法里用到了这个viewDir参数。


最后来点理论知识,关于漫反射和镜面反射的计算方式。

漫反射:
漫反射与镜面反射的主要区别是法线的分布。如果物体完全光滑的话,那么法线完全垂直于平面,例如镜面及锃亮的金属表面。而很多看起来很光滑平整的物体,如纸,桌面,衣服等,实际上, 用放大镜仔细观察,就会看到其表面是凹凸不平的。法线并不与肉眼看见的面垂直,而是与实际的面平行。
漫反射:光射到粗糙表面时,表面会把光线向着四面八方反射,所以即使入射线平行,由于各点的法线方向不一致,造成反射光线向不同的方向无规则地反射 。这种反射光称为漫反射光。

漫反射的计算
diffuse = Kd x colorLight xmax(N*L,0)
Kd漫反射系数
colorLight 光的颜色
N单位法线向量
L由点指向光源的单位向量
其中N与L点乘,如果结果小于等于0,则漫反射为0

    Unity Shader自定义光照模型_第1张图片


镜面反射:
光射到表面光滑平整,法线均匀的物体表面上,这种反射光称为镜面反射光。

Unity Shader自定义光照模型_第2张图片
Ks 镜面系数
colorLight 光的颜色
N 单位法线向量
L 由点指向光源的单位向量
V 由点指向观察者的单位向量
H(L+V)向量的单位化向量,即normalize(L+V)
shininess镜面强度系数,值越小,高光越分散;值越高,高光越集中。
facing如果N与L的点乘大于0,则facing为1,如果小于等于0,则facing为0

Unity Shader自定义光照模型_第3张图片


部分内容参考和引用自风宇冲http://blog.sina.com.cn/s/blog_471132920101dhnv.html


所谓的光照模型(光照方程),就是模型对光线做出的反应。因为材质和表面光滑度的不同,在光线照射到物体表面后,因为对光线的吸收和折射反射等等,最终进入眼睛的光线。

比较经典的一个例子,游戏《半条命》中使用的HalfLambert,修改一下我们的第一个光照模型:

float difLight = max(0, dot (s.Normal, lightDir));
float hLambert = difLight * 0.5 + 0.5;
float4 col;
col.rgb = s.Albedo * _LightColor0.rgb * (hLambert * atten * 2);
col.a = s.Alpha;
return col;

嗯,很简单,想怎么算就怎么算。但是,要做出炫酷的效果,要学的理论知识还有很多很多...


你可能感兴趣的:(unity,渲染)