什么是光照模型
光照模型就是模拟光在物体间的传递过程,以确保物体可见表面每一点的亮度和颜色。
当光照射到一个物体表面时,光可能被吸收、反射或折射。反射和折射的光使物体可见。如果入射光全部被吸收,物体将不可见,称物体为黑体。
一个物体表面呈现的颜色是有物体表面向视线方向辐射的光能中各种波长的分布所确定的。
如果物体是不透明的,则物体表面呈现的颜色仅有其反射光决定,通常把反射光考虑成环境反射光、漫反射光和镜面反射光三个分量的组合。
环境反射光(Ambient Light)
环境反射光是由于邻近物体所造成的光多次反射所产生的。光是从来自四面八方的,如从墙壁、地板以及天花伴等反射回来的光,是一种分布光源。
通常将这种光产生的效应简化为在各个方向都有均匀的光亮度Ia。
一个物体只有环境光照明时,其表面上各个点的明暗程度完全一样。其光亮度表示为:
Ie = Ia * Ka
- Ie:物体的环境光反射光亮度;
- Ia:环境光亮度;
- Ka:物体表面的环境光反射系数( 0 ≤ Ka ≤ 1)
//环境光直接获取
//UNITY_LIGHTMODEL_AMBIENT是Unity自带的宏定义常量
float3 ambientLighting = float3(UNITY_LIGHTMODEL_AMBIENT) * float3(_Color);
//_Color是Shader中添加的一个Property属性
Properties {
_Color ("Diffuse Material Color", Color) = (1,1,1,1)
}
漫反射光(DIffuse Light)
漫反射光是由特定的光源在物体表面反射光中那些向空间各方向均匀反射出去的光。这种光的反射强度与观察点的位置是无关的,它的光强度与入射光方向和反射点处于的表面法线间的夹角余弦成正比。
假设物体表面在P点的法线为N,从P点指向光源的向量为L,两者夹角为θ。点P处漫反射光亮度为:
Id = Ip * Kd * COSθ
- Id:表面漫反射光亮度;
- IP:入射光的光亮度;
- Kd:漫反射系数(决定与表面材料及入射光波长) ( 0 ≤ Kd ≤ 1);
- θ:入射光线与法线间的夹角,0 ≤ θ ≤ PI / 2;
//计算的漫反射光
float3 diffuseReflection = float3(_LightColor0) * float3(_Color)* max(0.0, dot(normalDirection, lightDirection));
镜面反射光(Specular Light)
镜面反射光是朝一个方向的反射光。
对于理想镜面,入射到表面的光严格地遵守光的反射定律,只有在反射方向上,观察者才能看到从镜面反射出来的光线,如下图a。
对于一般光滑平面,由于表面具有一定的粗糙度,其表面实际上是有许多朝向不同的微小表面组成,其镜面反射光散布在反射方向周围,如下图b。
镜面反射光亮度可表示为:
Is = Is * Ks * cosnφ
- Is:观察者接受到的镜面反射光亮度;
- Ip:入射光的亮度;
- Ks:镜面反射系数(与材料材质和入射光波有关);
- φ:镜面反射方向与视线方向的夹角;
- n:镜面反射光的会聚系数(与物体表面的光滑度相关),一般1 ≤ n ≤ 2000;
对于较光滑的表面,其镜面反射光会聚程度较高,n值较大;而较粗糙的镜面反射光呈发散状态,n值较小。
//_Object2World与_World2Object均为unity提供的内置uniform参数
float4x4 modelMatrix = _Object2World;
//世界坐标系到对象坐标系的变换矩阵
float4x4 modelMatrixInverse = _World2Object;
//法向量N变化至对象坐标系
float3 normalDirection = normalize(float3(mul(float4(input.normal, 0.0), modelMatrixInverse)));
//平行光源的入射向量L直接由uniform_WorldSpaceLightPos0给出
float3 lightDirection =normalize(float3(_WorldSpaceLightPos0));
//观察向量V由摄像机坐标与顶点坐标矢量相减
float3 viewDirection = normalize(float3(float4(_WorldSpaceCameraPos, 1.0)
- mul(modelMatrix, input.vertex)));
//镜面反射光的计算
float3 specularReflection=float3(_LightColor0)*float3(_SpecColor)*pow(max(0.0,dot(reflect(-lightDirection, normalDirection),viewDirection)),_Shininess);