学习UnityShader入门精要笔记2——标准光照模型

时间:2023-01-25 10:19:10

昨天做完笔记1摘抄,书来来回回翻了好久并不知道底下怎么继续【。

感觉和代码一样,写的时候知道怎么回事儿,文字表述起来就简直了啊!简直了啊!最后想了想还是做摘抄,把一些基础概念提出来回顾也好加深印象也好,就这样吧。。

另 因为是笔记,会有一些自己理解的成分。然而我这浅薄的功底也不敢保证准确性,如果有幸被自己以外的人阅读,请带着自己的思考 :)


————————————————————————————————————————————————————————————————————————

早期处理光照只使用一个光照模型—标准光照模型。其将进入camera的光线分为4种:自发光、高光反射、漫反射、环境光。

标准光照模型只关心 直接光照,即直接从光源出发,到达物体表面后经由表面一次反射进入camera的光。但是真实环境中光线通常会在多个物体间反射最后进入camera。这个反射过程不止一次,通常叫做间接光照。此光照模型中,用环境光来模拟这种间接光照。

漫反射:反射光线的强度与表面法线和光源方向之间夹角余弦成正比。漫反射通常实现方式如下:

fixed4 frag(v2f i) : SV_Target
{
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb*saturate(dot(worldNormal,worldLightDir));
fixed3 color = ambient + diffuse;
return fixed4(color,1);
}

上述实现漫反射的方式也被成为兰伯特光照模型,因为其符合兰伯特定律:在平面某点漫反射光的光强与该反射点法向量和入射光角度的余弦成正比。还有一种实现漫反射的模型在此基础上做了小修改,被称为半兰伯特光照模型。与原兰伯特模型相比,他没有用max防止法向量和光向量的点积小于0的情况,而是对结果做了α倍缩放在加β偏移。绝大多数情况下这两个值均为0.5。借此将法向量和光向量点积值域从[-1,1]映射到[0,1]之间。

fixed4 frag(v2f i) : SV_Target
{
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed halfLambert = dot(worldNormal,worldLightDir)*0.5+0.5;
fixed3 diffuse = _LightColor0.rgb*_Diffuse.rgb*halfLambert;
fixed3 color = ambient + diffuse;
return fixed4(color,1);
}

高光反射:高光反射有几种模型,依次总结(图片均出自UnityShader入门精要!!)
Phong模型:如下图,很好理解。如果反射光线r代表的向量和视向量v重合,人眼感受到的高光应当是最强烈的。随着r和v夹角变大,高光效果减弱。

学习UnityShader入门精要笔记2——标准光照模型

fixed4 frag (v2f i) : SV_Target
{
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);

fixed3 diffuse = _LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal,worldLightDir));

fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal));

fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz-i.worldPos.xyz);

fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(saturate(dot(reflectDir,viewDir)),_Gloss);

return fixed4(ambient+diffuse+specular,1);
}

BlinnPhong:避免计算反射光向量,引入了一个新的向量,对视向量和光向量做相加后再归一化。如下图,此向量与法线夹角越小,则高光效果越好。夹角为0时,视向
量和反射光向量平行。此方法的优点是当camera 和光源距离足够远,可认为此时v和l向量都是定值,此时h为常量。

学习UnityShader入门精要笔记2——标准光照模型

fixed4 frag (v2f i) : SV_Target
{
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb*max(0,dot(worldNormal,worldLightDir));
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
fixed3 halfDir = normalize(worldLightDir+viewDir);
fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(max(0,dot(worldNormal,halfDir)),_Gloss);
return fixed4(ambient+diffuse+specular,1);
}