1.Light结构体
struct Light
{
float3 Strength; // 光源的颜色
float FalloffStart; // 仅供点光源/聚光灯
float3 Direction; // 仅供方向光源/聚光灯
float FalloffEnd; // 仅供点光源/聚光灯
float3 Position; // 仅供点光源/聚光灯
float SpotPower; // 仅供聚光灯
};
2.辅助函数
2.1 衰减因子
点光源和聚光灯的线性衰减。
float CalcAttenuation(float d, float falloffStart, float falloffEnd)
{
return saturate((falloffEnd-d) / (falloffEnd - falloffStart));
}
2.2 反射率
根据光向量L和表面法线n之间的夹角,根据菲涅尔效应近似计算出以n为法线的表面反射光的百分比。
float3 SchlickFresnel(float3 R0, float3 normal, float3 lightVec)
{
float cosIncidentAngle = saturate(dot(normal, lightVec));
float f0 = 1.0f - cosIncidentAngle;
float3 reflectPercent = R0 + (1.0f - R0)*(f0*f0*f0*f0*f0);
return reflectPercent;
}
2.3 光量
计算反射到观察者眼中的光量,该值为漫反射光亮和镜面反射光量的总和。
float3 BlinnPhong(float3 lightStrength, float3 lightVec, float3 normal, float3 toEye, Material mat)
{
const float m = mat.Shininess * 256.0f; //Shininess表示光泽度
float3 halfVec = normalize(toEye + lightVec);
float roughnessFactor = (m + 8.0f)*pow(max(dot(halfVec, normal), 0.0f), m) / 8.0f;
float3 fresnelFactor = SchlickFresnel(mat.FresnelR0, halfVec, lightVec);
float3 specAlbedo = fresnelFactor*roughnessFactor;
//由镜面反射公式得到的结果超出[0,1]时,按比例缩小
specAlbedo = specAlbedo / (specAlbedo + 1.0f);
return (mat.DiffuseAlbedo.rgb + specAlbedo) * lightStrength;
}
2.4 方向光源光量
输出来自某方向光源发出,经表面反射入观察者眼中的光量。
float3 ComputeDirectionalLight(Light L, Material mat, float3 normal, float3 toEye)
{
//光向量与光线传播方向相反
float3 lightVec = -L.Direction;
// 通过朗伯余弦定理按比例降低光强
float ndotl = max(dot(lightVec, normal), 0.0f);
float3 lightStrength = L.Strength * ndotl;
return BlinnPhong(lightStrength, lightVec, normal, toEye, mat);
}
2.5 点光源光量
输出从点光源放出,经表面反射入观察者眼中的光量。
float3 ComputePointLight(Light L, Material mat, float3 pos, float3 normal, float3 toEye)
{
//自表面指向光源的向量
float3 lightVec = L.Position - pos;
//表面到光源的距离
float d = length(lightVec);
//范围检测
if(d > L.FalloffEnd)
return 0.0f;
//对光向量进行规范化处理
lightVec /= d;
//通过朗伯余弦定理按比例降低光强
float ndotl = max(dot(lightVec, normal), 0.0f);
float3 lightStrength = L.Strength * ndotl;
//根据距离计算光的衰减
float att = CalcAttenuation(d, L.FalloffStart, L.FalloffEnd);
lightStrength *= att;
return BlinnPhong(lightStrength, lightVec, normal, toEye, mat);
}
2.6 聚光灯光量
float3 ComputeSpotLight(Light L, Material mat, float3 pos, float3 normal, float3 toEye)
{
// 自表面指向光源的向量
float3 lightVec = L.Position - pos;
// 表面到光源的距离
float d = length(lightVec);
// 范围检测
if(d > L.FalloffEnd)
return 0.0f;
// 对光向量进行规范化处理
lightVec /= d;
// 通过朗伯余弦定理按比例降低光强
float ndotl = max(dot(lightVec, normal), 0.0f);
float3 lightStrength = L.Strength * ndotl;
// 根据距离计算光的衰减
float att = CalcAttenuation(d, L.FalloffStart, L.FalloffEnd);
lightStrength *= att;
// 根据聚光灯照明模型对光强进行缩放处理
float spotFactor = pow(max(dot(-lightVec, L.Direction), 0.0f), L.SpotPower);
lightStrength *= spotFactor;
return BlinnPhong(lightStrength, lightVec, normal, toEye, mat);
}