3、片元着色器之基础光照模型:兰伯特和半兰伯特光照模型

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);
    }
}
相关推荐
Forest_10107 天前
GLSL(OpenGL 着色器语言)基础语法
着色器
滴水成川15 天前
Metal 着色器与渲染管线
着色器·metal
stevenzqzq15 天前
openGl片段着色器的含义
opengl·着色器
Allen747415 天前
往期项目shader着色器实践效果应用合集
着色器·ta
不收藏找不到我23 天前
10、基于osg引擎生成热力图高度图实现3D热力图可视化、3D热力图实时更新(带过渡效果)
3d·数据可视化·着色器
不收藏找不到我1 个月前
7、基于osg引擎实现读取vtk数据通过着色器实现简单体渲染(1)
着色器
MessiGo1 个月前
OpenGL(4)着色器
apache·着色器
太妃糖耶1 个月前
Shader中着色器的编译目标级别
unity·shader·着色器
HELLOMILI1 个月前
[Unity3D] 动态立方体贴图系统
游戏·unity·游戏引擎·图形渲染·着色器
HELLOMILI1 个月前
第四章:反射-Reflecting Your World《Unity Shaders and Effets Cookbook》
游戏·unity·游戏引擎·游戏程序·图形渲染·材质·着色器