一、吸收和散射
光线由光源发射出来后,就会与一些物体相交,通常相交的结果有两个:吸收和散射。
光线在物体表面经过散射后,有两种方向,一种散射到物体内部,称为折射或透射;另一种散射到外部,称为反射。对于不透明物体,折射光(非单色光)被吸收一部分,可能改变光线颜色。
为区分两种散射方向,在光照模型中使用不同部分计算它们:高光反射(specular)与漫反射(diffuse)。前者表示光线在物体表面的反射,后者表示折射、吸收、散射出物体表面的光线。
二、标准光照模型
标准光照模型的基本方法是,将进入摄像机的光线分为4个部分:
1.自发光:该部分用于描述当给定一个方向时,表面本身会像该方向发射多少辐射量。(如果没有使用全局光照,自发光的表面不会照亮周围物体,只会使本身看起来更亮)
2.高光反射:该部分用于描述光源照射到物体表面时,该表面在完全镜面反射的方向反射出多少能量。
3.漫反射:该部分用于描述当光线从光源照射到物体表面时,会向每个方向散射的能量。
4.环境光:该部分用于描述其他的间接光照。
三、光照模型的计算方式
1.逐像素光照
在片元着色器中计算,以每个像素为基础,得到它的法线(对顶点法线插值或从法线纹理中采样得到),然后进行光照模型的计算。
2.逐顶点光照
在顶点着色器中计算,在每个顶点上计算光照,然后在渲染图元内部进行线性插值,最后输出像素颜色。
四、环境光设置
Window>>Rendering>>Lighting>>Environment>>Environment Lighting>>Ambient Color内控制:
如图,Instensity控制光的强度,调色板控制颜色。
五、Unity中实现漫反射
1.逐顶点光照:
Shader "ShaderStudy/Chapter 6/6-4"
{
Properties
{
//材质的漫反射颜色
_Diffuse("DiffuseColor",Color) = (1,1,1,1)
}
SubShader
{
Pass
{
Tags {"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Diffuse;
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 color : COLOR;
};
//逐顶点光照
v2f vert(a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
//通过变量UNITY_LOGHTMODEL_AMBIENT获得环境光。
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//计算世界空间下的顶点法线方向,normalize返回单位向量,mul为矩阵相乘
fixed3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
//计算世界空间下的光线方向
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
//这里就是使用基本光照模型中漫反射部分的计算公式,dot为点乘(cross为叉乘),saturate函数将所得矢量或标量的值限定在[0,1]之间
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLight));
//对环境光和漫反射光照部分相加,得到最终的光照结果。
o.color = ambient + diffuse;
return o;
}
fixed4 frag(v2f i) :SV_Target
{
return fixed4(i.color,1.0);
}
ENDCG
}
}
}
2.逐像素光照:
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Diffuse;
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
};
//逐顶点光照
v2f vert(a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = mul(v.normal,(float3x3)unity_WorldToObject);
return o;
}
fixed4 frag(v2f i) :SV_Target
{
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(normalize(i.worldNormal), normalize(_WorldSpaceLightPos0.xyz)));
return fixed4(UNITY_LIGHTMODEL_AMBIENT.xyz + diffuse, 1.0);
}
ENDCG