本文借鉴《Unity Shader入门精要》,算是对自己学习的总结,也希望分享下所学知识~~
漫反射用于物体表面随机散射到各个方向的辐射度进行建模的。
漫反射中的视角位置是不重要的,反射在任何方向上的分布都是一样的。
漫反射光照符合兰伯特定律:反射光线的强度 与 表面法线 和 光源方向 之间夹角的余弦值 成正比。
ps:
1.单位向量的夹角的余弦值 = 法线方向 · 光源方向
2.乘法代表颜色叠加,白色 * 红色物理上感觉应该是红色,计算起来为:(1,1,1)*(1,0,0) = (1,0,0) 就是红色
公式:
反射光线强度 = 入射光线颜色 * 漫反射颜色 * max( 0, 法线方向 · 光源方向 )
case 1:逐顶点光照
shader "diffuseVertexLevel"
{
Properties
{
_Diffuse("Diffuse", Color) = (1, 1, 1, 1) //声明漫反射颜色
}
SubShader
{
Pass
{
Tags {
"LightMode"="ForwardBase"//指明了Pass的光照模式
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
fixed3 color : COLOR;
};
fixed4 _Diffuse;
v2f vert (a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos( v.vertex );//to 裁剪空间
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//Unity内置变量 获得环境光信息
fixed3 worldNormal = UnityObjectToWorldNormal( v.normal );//获取世界空间下的法线方向
fixed3 worldLight = normalize( _WorldSpaceLightPos0.xyz );//获得光源的方向
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate( dot(worldNormal, worldLight) );//该Pass处理的光源的颜色和强度信息
o.color = ambient + diffuse;//间接光照+漫反射光照
return o;
}
fixed4 frag (v2f i) : SV_Target
{
return fixed4(i.color,1.0);//直接返回颜色值,剩余的做差值
}
ENDCG
}
}
FallBack "Diffuse"
}
case 2:逐片元操作(只写两个着色器,其他都一样)
v2f vert (a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
fixed3 worldNormal = UnityObjectToWorldNormal( v.normal );
o.worldNormal = worldNormal;//把世界空间下的法线传递给片元着色器
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldLightDir = normalize( _WorldSpaceLightPos0.xyz );
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate( dot( i.worldNormal, worldLightDir ) );
fixed3 color = ambient + diffuse;
return fixed4(color, 1.0);
}
逐顶点和逐片元的区别:
1.逐顶点光照,在每个顶点上计算光照,然后会在渲染图元内部进行线性插值,最后输出颜色。
2.逐片元光照,是对每个片元都执行一次。
顶点的数量少,逐顶点效率更高,但是效果会有明显的棱角现象。