一、光源类型
Unity中4中光源:平行光、点光源、聚光灯、面光源(只在烘焙时发生作用)。
光源位置、方向、颜色、强度、衰减等等都与他们的属性息息相关,会影响到Shader。
1.平行光
他没有唯一的位置,它的几何属性只有方向。
2.点光源
表示由一个点发出的向所有方向延伸的光。
照亮空间有限,存在位置等属性,存在衰减等等。
3.聚光灯
是由一块锥形区域定义的,从一个特定位置出发,向特定方向延伸的光。
最复杂的一种光源,照亮空间有限,存在位置、方向、衰减等等。
二、在前向渲染中处理不同的光源类型
前向渲染路径时,Unity Shader会访问5个光源属性:
位置、方向、颜色、强度、衰减,
实践:默认平行光和绿色点光源
Pass
{
Tags{"LightMode"="ForwardBase"}//设置Base Pass
CGPROGRAM
#pragma multi_compile_fwdbase //编译指令确保Shader中光照衰减等光照变量被正确赋值。
...
...//片元着色器中
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; //在片元着色器中计算环境光
fixed3 diffuse = _LightColor0.rgb*_Diffuse.rgb*max(0,dot(worldNormal,worldLightDir));
fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(max(0,dot(worldNormal,halfDir)),_Gloss);
fixed atten = 1.0;
return fixed4(ambient+(diffuse+specular)*atten,1.0);
}
------------------------------------------------------
//此时Unity中只有一个平行光,就在Base Pass处理。Base Pass处理的一定是平行光。
//如果没有平行光时,Base Pass会当作全黑的光源处理。
//但当着色器中有多个平行光时,Base Pass会处理最亮的平行光,其他平行光会传递给Addition Pass中处理。
------------------------------------------------------
Pass
{
Tags{"LightMode"="ForwardAdd"} //设置Addition Pass
Blend One One //开启混合模式将此光照结果和之前帧缓存中的光照进行叠加
CGPROGRAM
#pragma multu_compile_fwdadd //保证我们在Pass中得到正确的光照变量
...
...//片元着色器中首先需要判断光源类型,计算不同光源的方向
#ifdef USING_DIRECTIONAL_LIGHT
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
#else
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz-i.worldPosition.xyz);
#endif
//以上为了计算不同光源类型时,光源方向
fixed3 diffuse = _LightColor0.rgb*_Diffuse.rgb*max(0,dot(worldNormal,worldLightDir));
fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(max(0,dot(worldNormal,halfDir)),_Gloss);
#ifdef USING_DIRECTIONAL_lIGHT
fixed atten = 1.0;
#else
float lightCoord = mul(_LightMatrix0,float4(i.worldPosition,1)).xyz;
fixed atten = tex2D(_LightTexture0,dot(lightCoord,lightCoord).rr).UNITY_ATTEN_CHANNEL;
//宏UNITY_ATTEN_CHANNEL是为了得到衰减纹理中衰减值所在的分量。
#endlf
//计算不同光源类型的衰减效果,lightCoord是将顶点位置转换到光源空间
//衰减效果使用一张纹理作为查找表,计算衰减。
//我们通常关心的是纹理对角线上的纹理颜色值,其表示了光源空间中不同距离的衰减值。
return fixed4(ambient+(diffuse+specular)*atten,1.0);
}
也可以使用线性数学方法计算衰减:
float distance = length(_WorldSpaceLightPos0.xyz-i.worldPosition.xyz);
atten = 1.0/distance;
一些补充:
Unity绘制光源的顺序是按照重要程度排序的,与颜色、强度、距离有关。
Untiy不会渲染不在聚光灯内的光源。
在前向渲染路径中,可以使用前向渲染路径中的内置函数和内置变量计算逐顶点与SH光源。