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);
    }
}
相关推荐
吃豆腐长肉3 天前
着色器 (三)
opengl·着色器
吃豆腐长肉3 天前
opengl 着色器 (四)最终章收尾
opengl·着色器
浅陌sss11 天前
UnityShaderLab 实现黑白着色器效果
着色器
0~max~014 天前
OpenGL编译用户着色器shader
着色器
程序员正茂25 天前
Unity着色器Shader根据到某点的距离显示不同颜色
unity·shader·着色器
小春熙子1 个月前
Unity图形学之着色器之间传递参数
unity·游戏引擎·技术美术·着色器
优雅永不过时·1 个月前
three.js实现地球 外部扫描的着色器
前端·javascript·webgl·three.js·着色器
踏实探索1 个月前
OpenLayers教程12_WebGL自定义着色器:实现高级渲染效果
前端·arcgis·vue·webgl·着色器
Padid1 个月前
SRP 实现 Cook-Torrance BRDF
c++·笔记·unity·游戏程序·图形渲染·着色器
UTwelve1 个月前
【UE5】在材质中实现球形法线技术,常用于改善植物等表面的渲染效果
ue5·材质·虚幻引擎·着色器·虚幻4