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);
    }
}
相关推荐
小春熙子12 小时前
Unity图形学之着色器之间传递参数
unity·游戏引擎·技术美术·着色器
优雅永不过时·12 小时前
three.js实现地球 外部扫描的着色器
前端·javascript·webgl·three.js·着色器
踏实探索2 天前
OpenLayers教程12_WebGL自定义着色器:实现高级渲染效果
前端·arcgis·vue·webgl·着色器
Padid6 天前
SRP 实现 Cook-Torrance BRDF
c++·笔记·unity·游戏程序·图形渲染·着色器
UTwelve11 天前
【UE5】在材质中实现球形法线技术,常用于改善植物等表面的渲染效果
ue5·材质·虚幻引擎·着色器·虚幻4
UTwelve15 天前
【UE5】一种老派的假反射做法,可以用于移动端,或对反射的速度、清晰度有需求的地方
ue5·虚幻引擎·着色器·虚幻4
Padid16 天前
Unity SRP学习笔记(二)
笔记·学习·unity·游戏引擎·图形渲染·着色器
优雅永不过时·18 天前
使用three.js 实现 自定义绘制平面的效果
前端·javascript·平面·github·threejs·着色器
不收藏找不到我20 天前
2、片元着色器之有向距离场(SDF)运算:并集、差集、交集
着色器
不收藏找不到我20 天前
2、顶点着色器之视图矩阵
矩阵·着色器