1、什么是兰伯特光照模型?
兰伯特光照模型(Lambertian Lighting Model)是一种漫反射光照模型 ,基于兰伯特余弦定律。原理是:表面接收到的光强度与入射光线和表面发现之间的夹角的余弦值成正比。公式如下:
I = k d ⋅ I L ⋅ m a x ( 0 , c o s θ ) I=k_d·I_L·max(0,cosθ) I=kd⋅IL⋅max(0,cosθ)
其中:
I 表示最终的光照强度 k d 是漫反射系数,表示表面对光的反射程度 I L 是光源的强度 θ 是入射光线和表面法线之间的夹角 c o s θ 可通过法线向量和光源向量的点积计算得出 : c o s θ = N ⋅ L I表示最终的光照强度\\ k_d是漫反射系数,表示表面对光的反射程度 \\ I_L是光源的强度\\ θ是入射光线和表面法线之间的夹角\\ cosθ可通过法线向量和光源向量的点积计算得出:cosθ=N·L I表示最终的光照强度kd是漫反射系数,表示表面对光的反射程度IL是光源的强度θ是入射光线和表面法线之间的夹角cosθ可通过法线向量和光源向量的点积计算得出:cosθ=N⋅L
兰伯特模型适合粗糙、无光泽的表面,因为它不会产生高光反射效果。
用兰伯特模型模拟3D球体:
cpp
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
// 将像素坐标标准化为 [-1, 1] 的范围
vec2 uv = (fragCoord - iResolution.xy * 0.5) / iResolution.y;
// 定义球体的中心和半径
vec2 sphereCenter = vec2(0.0, 0.0); // 屏幕空间球体中心
float sphereRadius = 0.5; // 球体半径(屏幕空间)
// 计算片段到球体中心的2D距离
float dist2D = length(uv - sphereCenter);
// 判断是否在球体内
if (dist2D < sphereRadius) {
// 使用球体方程计算深度(z坐标),假设球体的 z 轴为正
float z = sqrt(sphereRadius * sphereRadius - dist2D * dist2D);
// 计算3D法线
vec3 normal = normalize(vec3(uv - sphereCenter, z));
// 定义光源方向
vec3 lightDir = normalize(vec3(4.0, 5.0, -1.0));
// 漫反射系数
float kd=1.0;
// 光源的强度
float lightIntensity=1.0;
// 使用Lambert光照模型计算亮度
float intensity = kd * lightIntensity * max(dot(normal, lightDir), 0.0);
// 设置球体颜色
vec3 color = vec3(1.0, 0.5, 0.3) * intensity;
fragColor = vec4(color, 1.0);
} else {
// 背景颜色
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
}
2、什么是半兰伯特光照模型?
它是在兰伯特模型基础上的改进,主要用于避免在光照角度较小时出现过暗的情况,从而使物体的暗面更加明亮,看起来更自然。公示如下:
I = k d ⋅ I L ⋅ ( 0.5 ⋅ c o s θ + 0.5 ) = k d ⋅ I L ⋅ ( 0.5 ⋅ ( N ⋅ L ) + 0.5 ) I=k_d·I_L·(0.5·cosθ+0.5)=k_d·I_L·(0.5·(N·L)+0.5) I=kd⋅IL⋅(0.5⋅cosθ+0.5)=kd⋅IL⋅(0.5⋅(N⋅L)+0.5)
与兰伯特模型的区别在于,将光强度的余弦值进行平移并缩放到 0 到 1 的范围内,即使夹角较大时仍能获得一定的光照。
cpp
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
// 将像素坐标标准化为 [-1, 1] 的范围
vec2 uv = (fragCoord - iResolution.xy * 0.5) / iResolution.y;
// 定义球体的中心和半径
vec2 sphereCenter = vec2(0.0, 0.0); // 屏幕空间球体中心
float sphereRadius = 0.5; // 球体半径(屏幕空间)
// 计算片段到球体中心的2D距离
float dist2D = length(uv - sphereCenter);
// 判断是否在球体内
if (dist2D < sphereRadius) {
// 使用球体方程计算深度(z坐标),假设球体的 z 轴为正
float z = sqrt(sphereRadius * sphereRadius - dist2D * dist2D);
// 计算3D法线
vec3 normal = normalize(vec3(uv - sphereCenter, z));
// 定义光源方向
vec3 lightDir = normalize(vec3(4.0, 5.0, -1.0));
// 漫反射系数
float kd=1.0;
// 光源的强度
float lightIntensity=1.0;
// 使用Lambert光照模型计算亮度
float intensity = kd * lightIntensity * (0.5*dot(normal, lightDir)+0.5);
// 设置球体颜色
vec3 color = vec3(1.0, 0.5, 0.3) * intensity;
fragColor = vec4(color, 1.0);
} else {
// 背景颜色
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
}