直接跳到内容

光照模型

光照模型是 3D 图形学中模拟光线与物体表面交互的数学方法,它决定了物体在场景中的视觉外观。在 Web 3D 开发中,合理的光照模型能够显著增强场景的真实感和沉浸感,是创建逼真视觉效果的关键技术。

光照模型基础

光照模型描述了光线如何与材质表面相互作用,包括吸收、反射和透射等物理现象。计算机图形学中的光照模型是对真实光照的近似,平衡计算成本和视觉效果。

特点:

  • 基于物理的简化模型,而非完全物理准确
  • 分离光照计算与材质属性
  • 支持实时渲染的性能要求

示意图 (光线与表面交互):

入射光线 → 表面 → 反射光线 + 吸收 + 透射
    ↓        ↓         ↓
  方向     材质属性    方向/强度

局部光照与全局光照

光照模型分为局部光照和全局光照两大类。局部光照只考虑直接光照,全局光照还包含间接光照和光线反弹效果。

特点:

  • 局部光照:计算简单,适合实时渲染
  • 全局光照:效果真实,计算成本高
  • Web 3D 主要使用局部光照模型

示意图对比:

局部光照:        全局光照:
光源 → 表面 → 眼睛    光源 → 表面A → 表面B → 眼睛

                   间接光照

环境光照

环境光照模拟场景中的间接光照,为物体提供基础亮度。这是最简单的光照分量,不考虑光线方向。

特点:

  • 恒定照明,无方向性
  • 防止完全黑暗的区域
  • 通常与场景环境贴图结合

环境光计算公式:

颜色 = 材质环境色 × 环境光强度

示意图 (环境光效果):

无环境光:        有环境光:
  [暗部全黑]        [暗部可见]
  /        \       /        \
 |  暗面   |     |  灰色面  |
  \        /       \        /

漫反射光照

漫反射模拟光线在粗糙表面的均匀散射,遵循 Lambert 余弦定律。反射强度与表面法线和光线方向的夹角余弦成正比。

特点:

  • 方向敏感,与观察角度无关
  • 产生柔和的明暗过渡
  • 使用点积计算光照强度

Lambert 定律示意图:

表面法线  光线方向
   ↑       ↗
   |      /
   |     /
   |    /
   | θ /
表面-------
强度 ∝ cos(θ) = 点积(法线, 光线)

漫反射计算公式:

强度 = max(点积(法线, 光线方向), 0)
颜色 = 材质漫反射色 × 光颜色 × 强度

镜面反射光照

镜面反射模拟光线在光滑表面的集中反射,产生高光效果。常见模型包括 Phong 和 Blinn-Phong 模型。

特点:

  • 观察角度敏感
  • 产生明亮的高光点
  • 受表面光滑度影响

镜面反射示意图:

光线方向  视线方向
   ↗       ↘
    \       /
     \     /
      \   /
       \ /
       表面
反射方向 = 反射(光线方向, 法线)

Phong 镜面模型

Phong 模型通过反射方向与视线方向的点积计算高光,再通过指数控制高光集中度。

特点:

  • 直观的物理意义
  • 计算反射方向向量
  • 高光指数控制光泽度

Phong 计算公式:

反射方向 = 反射(-光线方向, 法线)
高光强度 = max(点积(反射方向, 视线方向), 0)^光泽度

Blinn-Phong 模型

Blinn-Phong 使用半角向量替代反射向量,计算更高效且高光更自然,是现代图形 API 的默认模型。

特点:

  • 计算成本低于 Phong 模型
  • 高光过渡更平滑
  • 广泛用于实时渲染

半角向量示意图:

光线方向  视线方向
   ↗       ↘
    \       /
     \     /
      \   /
       \ /
        H (半角向量)
法线 →  ↑

Blinn-Phong 计算公式:

半角向量 = 归一化(光线方向 + 视线方向)
高光强度 = max(点积(法线, 半角向量), 0)^光泽度

完整光照方程

将各光照分量组合得到完整的光照模型,通常采用环境光、漫反射和镜面反射的加和模型。

完整 Phong 光照模型:

最终颜色 = 环境光 + 漫反射 + 镜面反射
        = 材质环境 × 光环境 
        + 材质漫反射 × 光颜色 × max(点积(法线, 光线), 0)
        + 材质镜面 × 光颜色 × max(点积(反射方向, 视线), 0)^光泽度

各分量效果示意图:

环境光:    漫反射:     镜面反射:     组合效果:
 均匀灰色    方向明暗     高光亮斑     完整光照
  [    ]     [亮/暗]     [ 亮斑 ]     [真实感]
  /    \     /    \      /    \       /    \
 | 灰   |   | 渐变 |    | 亮点 |     | 综合 |
  \    /     \    /      \    /       \    /

光源类型

不同类型的光源影响光照计算的方式,Web 3D 中常见的光源包括定向光、点光源和聚光灯。

定向光

定向光模拟无限远处的光源 (如太阳),所有光线平行且强度不变。

特点:

  • 方向恒定,无位置概念
  • 计算简单高效
  • 适合室外场景

示意图 (定向光):

平行光线:
   ↓↓↓↓↓
   ↓↓↓↓↓ → 表面
   ↓↓↓↓↓
  方向一致

点光源

点光源从特定位置向所有方向发射光线,强度随距离衰减。

特点:

  • 有明确位置
  • 强度随距离衰减
  • 适合灯泡、蜡烛等效果

示意图 (点光源):

  光源

  /|\
 / | \  光线辐射
/  |  \

点光源衰减公式:

衰减 = 1.0 / (常数 + 线性×距离 + 二次×距离²)

聚光灯

聚光灯发射锥形光线,具有位置、方向和锥角限制。

特点:

  • 锥形照明区域
  • 内外锥角控制边缘软化
  • 适合手电筒、车灯效果

示意图 (聚光灯):

  光源

  /|\
 / | \  照明锥体
/  |  \
---θ--- 锥角

聚光灯强度计算:

角度 = 点积(光线方向, 聚光方向)
强度 = (角度 - 外锥角) / (内锥角 - 外锥角)
强度 = clamp(强度, 0, 1)

法线向量处理

法线向量在光照计算中至关重要,但需要正确处理变换和插值才能获得准确结果。

特点:

  • 必须使用模型矩阵的逆转置矩阵变换
  • 片段着色器中需要重新归一化
  • 支持法线贴图增强细节

法线变换示意图:

顶点法线 → 模型矩阵逆转置 → 世界空间法线
   ↓              ↓             ↓
局部空间       特殊变换       光照计算

法线贴图效果:

无法线贴图:       有法线贴图:
  平滑表面          细节凹凸
  [      ]         [ /\/\ ]
  /      \         /      \
 |  平    |       | 凹凸   |
  \      /         \      /

着色频率

着色频率决定光照计算的粒度,影响视觉效果和性能。主要分为逐顶点着色和逐片段着色。

逐顶点着色

在顶点着色器中计算光照,结果在三角形内插值。

特点:

  • 计算量小,性能高
  • 细节不足,出现马赫带
  • 适合简单场景或低性能设备

示意图 (逐顶点着色):

顶点计算光照 → 插值颜色 → 片段输出
   v0(红)       渐变        像素
   / \        红---绿
 v1(绿)-v2(蓝)  \ /

逐片段着色

在片段着色器中为每个像素计算光照。

特点:

  • 视觉效果平滑准确
  • 计算量较大
  • 现代渲染的标准做法

示意图 (逐片段着色):

顶点传递数据 → 逐像素计算 → 精确光照
  法线、位置     每个像素       平滑过渡

WebGL 中的光照实现

在 WebGL 中实现光照需要精心设计着色器和 JavaScript 代码,合理管理光源参数和材质属性。

顶点着色器示例:

glsl
attribute vec3 position;
attribute vec3 normal;

uniform mat4 modelViewProjection;
uniform mat4 modelMatrix;
uniform mat3 normalMatrix;

varying vec3 vNormal;
varying vec3 vPosition;

void main() {
    gl_Position = modelViewProjection * vec4(position, 1.0);
    vNormal = normalMatrix * normal;
    vPosition = vec3(modelMatrix * vec4(position, 1.0));
}

片段着色器示例:

glsl
varying vec3 vNormal;
varying vec3 vPosition;

uniform vec3 lightPosition;
uniform vec3 lightColor;
uniform vec3 ambientColor;
uniform vec3 diffuseColor;
uniform vec3 specularColor;
uniform float shininess;

void main() {
    // 向量计算
    vec3 normal = normalize(vNormal);
    vec3 lightDir = normalize(lightPosition - vPosition);
    vec3 viewDir = normalize(-vPosition);
    vec3 reflectDir = reflect(-lightDir, normal);
    
    // 环境光
    vec3 ambient = ambientColor * diffuseColor;
    
    // 漫反射
    float diff = max(dot(normal, lightDir), 0.0);
    vec3 diffuse = lightColor * diff * diffuseColor;
    
    // 镜面反射 (Blinn-Phong)
    vec3 halfwayDir = normalize(lightDir + viewDir);
    float spec = pow(max(dot(normal, halfwayDir), 0.0), shininess);
    vec3 specular = lightColor * spec * specularColor;
    
    gl_FragColor = vec4(ambient + diffuse + specular, 1.0);
}

性能优化策略

光照计算是渲染管线中的性能瓶颈之一,需要采用合适的优化策略。

特点:

  • 减少光照计算复杂度
  • 使用光照贴图预计算静态光照
  • 限制动态光源数量

优化技术对比:

完整逐像素光照 → 简化光照模型 → 光照贴图 + 球谐光照
   高质量          平衡质量性能       高性能静态场景
   ↓               ↓               ↓
计算密集        实时友好          预计算为主
光照模型已经加载完毕