漫反射: 投射在粗糙表面上的光向各个方向反射的现象。
镜面反射: 物体的反射面是光滑的,光线平行反射,如镜子,平静的水面等。
//一个漫反射Shader
Shader "Custom/BasicDiffuse2" {
Properties {
_EmissiveColor ("Emissive Color", Color) = (1, 1, 1, 1)
_AmbientColor ("Ambient Color", Color) = (1, 1, 1, 1)
_MySliderValue ("this is a Slider", Range(0, 10)) = 2.5
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
//#pragma surface 表面着色函数 漫反射函数
#pragma surface surf BasicDiffuse
//在这里创建与属性同名的变量,Unity会自动将二者关联起来,它们拥有同样的数据。
//当你在SubShader里创建好变量后,就可以在surf()函数里使用它们了。
float4 _EmissiveColor;
float4 _AmbientColor;
float _MySliderValue;//镜面反射强度
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o) {
float4 c;
//pow()函数参阅官方在线文档
//http://http.developer.nvidia.com/CgTutorial/cg_tutorial_appendix_e.html
c = pow((_EmissiveColor + _AmbientColor), _MySliderValue);//镜面反射
o.Albedo = c.rgb;
o.Alpha = c.a;
}
//自定义漫反射函数
//函数名的格式必须为Lighting<任何名字>
//可以使用三种格式的光照模型函数:
//1.该函数用于需要使用延迟着色的项目
//half4 LightingName(SurfaceOutput s, half4 light){}
//2.该函数用于不需要视角方向的前向着色
//half4 LightingName(SurfaceOutput s, half3 lightDir, half atten){}
//3.该函数用于需要视角方向的前向着色
//half4 LightingName(SurfaceOutput s, half3 lightDir, half3 viewDir, half atten){}
//s : surf函数的输出
//lightDir : 点到光源的单位向量
//viewDir : 点到摄像机的单位向量
//atten: 衰减系数
//原理: 为了完成漫反射计算,需要将Unity和SurfaceOutput结构体提供给我们的数据做乘法运算。
//为此我们需要乘上s.Albedo(来自于sur函数)和_LightColor0.rgb(来自Unity)然后再将结果与
//(difLight*atten)相乘,最后,返回这个值作为颜色值。
inline float4 LightingBasicDiffuse (SurfaceOutput s, fixed3 lightDir, fixed atten)
{
float difLight = max(0, dot(s.Normal, lightDir));//漫反射强度
float4 col;
col.rgb = s.Albedo * _LightColor0.rgb * (difLight * atten * 2);
col.a = s.Alpha;
return col;
}
ENDCG
}
FallBack "Diffuse"
}
dot函数(dot product function)是Cg语言的另一个内置数学函数,我们可以用它来比较两个向量在空间里的方向。点积函数会检查两个向量是互相平行还是互相垂直。任意两个向量都可以通过点积函数获得-1~1的夹角范围,-1表示平行向量并背离你的方向,1也表示平等向量,不过是朝向你的方向,0表示和你垂直的方向向量。矢量点积(或内积)的归一化向量N和L是测量两个向量之间夹角的方法。两个向量之间的夹角越小,点积越大,表面可以接受的入射光也越多。
max函数:可以限制点积函数的计算结果。max函数采用两个参数max(arg1, arg2),我们在着色器里使用max函数来确保漫反射的计算结果永远介于0和尚点积最大值之间。这样你就永远不会得到小于0的值,更不会是-1,否则可能会在你的着色器区间生成极度黑色的区域,并且在之后的着色器运算过程中容易出问题。在Cg标准函数库里还有一个类似的saturate函数,可以帮助我们将浮点值限制在0~1。saturate(和max)两者唯一的区别是saturate可以直接将浮点值转换成饱和度。max函数包含两个参数并返回二者之间最大的值。