Unity Shader自定义光照模型

27 篇文章 1 订阅

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

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

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


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

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

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


[plain]  view plain  copy
  1. inline float4 LightingMyLightingModel(SurfaceOutput s, fixed3 lightDir, fixed atten)  
  2.         {  
  3.             float difLight = max(0, dot (s.Normal, lightDir));  
  4.             float4 col;  
  5.             col.rgb = s.Albedo * _LightColor0.rgb * (difLight * atten * 2);  
  6.             col.a = s.Alpha;  
  7.             return col;  
  8.         }</span>  

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

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

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

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

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


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

[plain]  view plain  copy
  1. float4 LightingPhongModel(SurfaceOutput s, float3 lightDir,half3 viewDir, half atten)  
  2.         {  
  3.             float4 col;  
  4.   
  5.             float diffuseF = max(0,dot(s.Normal,lightDir));  
  6.   
  7.             float specF;  
  8.             float3 H = normalize(lightDir+viewDir);  
  9.             float specBase = max(0,dot(s.Normal,H));  
  10.             specF = pow(specBase,8);  
  11.   
  12.             col.rgb = s.Albedo * _LightColor0 * diffuseF *atten + _LightColor0*specF;   
  13.             col.a = s.Alpha;  
  14.             return col;  
  15.         }</span>  

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


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

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

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

    


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

【风宇冲】Unity3D教程宝典之Shader篇:第十五讲 <wbr>光照基础
Ks 镜面系数
colorLight 光的颜色
N 单位法线向量
L 由点指向光源的单位向量
V 由点指向观察者的单位向量
H(L+V)向量的单位化向量,即normalize(L+V)
shininess镜面强度系数,值越小,高光越分散;值越高,高光越集中。
facing如果N与L的点乘大于0,则facing为1,如果小于等于0,则facing为0


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


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

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

[plain]  view plain  copy
  1. float difLight = max(0, dot (s.Normal, lightDir));  
  2. float hLambert = difLight * 0.5 + 0.5;  
  3. float4 col;  
  4. col.rgb = s.Albedo * _LightColor0.rgb * (hLambert * atten * 2);  
  5. col.a = s.Alpha;  
  6. return col;  

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值