参考资料

nvidia官网cg编程指南链接

基本光照

固定管道使用的基本光照计算公式
surfaceColor = emissive + ambient + diffuse + specular
surfaceColor:最终颜色
emissive:自发光颜色
ambient:环境关颜色
diffuse:漫反射关颜色
specular:镜面高光颜色

光照计算

emissive = Ke
ke:材质的emissive颜色

自发光是在没有光照的情况下现在的颜色,光照计算直接就是该颜色想象一下在一个黑暗无光的背景,如果物体emissive=color(1,0,0,1),当前物体就显示出红色,surfaceColor = emissive + 0+ 0 + 0

ambient = Ka x globalAmbient
Ka:材质的ambient颜色
globalAmbient:全局环境光的颜色

diffuse = Kd x lightColor x max(N · L, 0)

kd:材质的漫反射颜色

lightColor :漫反射光照颜色

N:物体表面法线

L:光照向量(是从表面位置指向光源位置的向量,与光的方向相反)

当N与L之间的夹角大于90度是值为负数,光照不能照到物体的背面故取值为0

其中向量全部归一化了

unity2D项目shader unity shader emission_光照模型

specular = Ks x lightColor x facing x (max(N · H, 0)) shininess

Ks :材质的镜面反射颜色

lightColor:漫反射光照颜色

facing:默认为1,协调光照,相当于光照强度

N:物体表面法线

V:视角,物体到摄像机向量

L:光照向量(是从表面位置指向光源位置的向量,与光的方向相反)

H:H = V+L (N与L之间夹角中一半的向量);

shininess:高光级别值越大高光区域越小(是N*H的幂N*H的值在0-1)

其中向量全部归一化了

unity2D项目shader unity shader emission_unity2D项目shader_02

常用选项
其中emissive一般用于特殊效果,最常用的光照模型是排除他的及
surfaceColor = ambient + diffuse + specular
ambient :一般在一个场景中就一个环境光
diffuse 与specular的光照颜色一般在同一个光源里面设置同样的颜色

上面提到的光照模型还没有计算衰减
方向光不需要衰减,点光源和聚光灯是需要衰减的

光照衰减

衰减公式 :attenuationFactor=1/(Kc+Kl*d+Kq*d^2)

unity2D项目shader unity shader emission_光照模型_03


Kc,Kl,Kq:衰减常量

d:当前光照点与光源的距离

平行光

光线是平行了如太阳关,距离太远了所以不需要衰减

点光源

直接在漫反射与镜面发生乘以衰减值attenuationFactor

公式:surfaceColor = emissive + ambient + (diffuse + specular)*attenuationFactor

聚光灯

unity2D项目shader unity shader emission_unity2D项目shader_04

D:光源方向
V:光源与光照点的向量
取舍:为聚关灯照射的角度一般取cos值
判断一点是否在聚关灯照射范围,取d,v之间的cos值(向量点积)与取舍值比较

if(dot(d,v)<取舍) 
 return false//不知光照范围 
 公式: 
 if(dot(d,v)<取舍) 
 return false//不在光照范围 
 else 
 surfaceColor = emissive + ambient + (diffuse + specular)*attenuationFactor

这样计算的光照在光照范围内是均匀的,而真实世界是有外围衰减的,我们将聚光灯分为两部分,内部光照强度不变,外表向外光照强度递减

unity2D项目shader unity shader emission_光照模型_05


使用hlsl及cg都提供的一个内置函数smoothstep(min,max,x),计算0到1的平滑插值范围[min,max]小于min为0,打于max为1hlsl官网函数详情

计算公式为

if(dot(d,v)<取舍) 
 return false//不在光照范围 
 else 
 surfaceColor = emissive + ambient + 
 (diffuse + specular)*attenuationFactor*smoothstep(外部,内部,dot(d,v))