当前位置: 首页 > news >正文

【C++游戏引擎开发】第13篇:光照模型与Phong基础实现

一、Phong模型数学原理

1.1 光照叠加公式

L = k a I a + k d I d max ⁡ ( 0 , n ⋅ l ) + k s I s max ⁡ ( 0 , r ⋅ v ) α L = k_a I_a + k_d I_d \max(0, \mathbf{n} \cdot \mathbf{l}) + k_s I_s \max(0, \mathbf{r} \cdot \mathbf{v})^\alpha L=kaIa+kdIdmax(0,nl)+ksIsmax(0,rv)α

  • 符号说明
    • k a , k d , k s k_a, k_d, k_s ka,kd,ks:材质的环境/漫反射/高光系数(标量)
    • I a , I d , I s I_a, I_d, I_s Ia,Id,Is:光源的环境/漫反射/高光强度(三通道向量或标量)
    • n \mathbf{n} n:表面单位法线向量
    • l \mathbf{l} l:单位光照方向向量(从表面指向光源)
    • v \mathbf{v} v:单位视线方向向量(从表面指向观察点)
    • r \mathbf{r} r:反射方向单位向量
    • α \alpha α:高光锐度系数(值越大高光越集中)

1.2 核心分量数学推导

1.2.1 环境光(Ambient)

L a = k a ⋅ I a L_a = k_a \cdot I_a La=kaIa

  • 特性:均匀照亮场景,与几何关系和光源方向无关
  • 缺陷:易导致画面“过平”,需结合其他分量使用
1.2.2 漫反射(Lambert’s Cosine Law)

L d = k d ⋅ I d ⋅ max ⁡ ( 0 , n ⋅ l ) L_d = k_d \cdot I_d \cdot \max(0, \mathbf{n} \cdot \mathbf{l}) Ld=kdIdmax(0,nl)

  • 几何解释
    • n ⋅ l = cos ⁡ θ \mathbf{n} \cdot \mathbf{l} = \cos\theta nl=cosθ,其中 θ \theta θ 为入射角
    • max ⁡ ( 0 , ⋅ ) \max(0, \cdot) max(0,) 确保背面无光照贡献
  • 能量守恒:入射角越大,单位面积接收的光能越少
1.2.3 高光反射(Phong Specular)

L s = k s ⋅ I s ⋅ max ⁡ ( 0 , v ⋅ r ) α L_s = k_s \cdot I_s \cdot \max(0, \mathbf{v} \cdot \mathbf{r})^\alpha Ls=ksIsmax(0,vr)α

  • 反射向量计算
    r = 2 ( n ⋅ l ) n − l \mathbf{r} = 2(\mathbf{n} \cdot \mathbf{l})\mathbf{n} - \mathbf{l} r=2(nl)nl
  • Blinn-Phong优化
    • 半角向量 h = l + v ∥ l + v ∥ \mathbf{h} = \frac{\mathbf{l} + \mathbf{v}}{\|\mathbf{l} + \mathbf{v}\|} h=l+vl+v
    • 高光项改写为 ( n ⋅ h ) α (\mathbf{n} \cdot \mathbf{h})^\alpha (nh)α,计算效率更高

1.3 坐标系变换与关键推导

1.3.1 反射向量 r \mathbf{r} r 的严格推导

设入射方向 l \mathbf{l} l 为指向表面的单位向量,法线 n \mathbf{n} n 为单位向量:

  1. l \mathbf{l} l 分解为法线分量和切平面分量:
    l = ( n ⋅ l ) n + l ⊥ \mathbf{l} = (\mathbf{n} \cdot \mathbf{l})\mathbf{n} + \mathbf{l}_{\perp} l=(nl)n+l
  2. 反射方向 r \mathbf{r} r 的法线分量反向,切平面分量不变:
    r = − ( n ⋅ l ) n + l ⊥ = l − 2 ( n ⋅ l ) n \mathbf{r} = -(\mathbf{n} \cdot \mathbf{l})\mathbf{n} + \mathbf{l}_{\perp} = \mathbf{l} - 2(\mathbf{n} \cdot \mathbf{l})\mathbf{n} r=(nl)n+l=l2(nl)n
1.3.2 法线矩阵 N = ( M − 1 ) T \mathbf{N} = (\mathbf{M}^{-1})^T N=(M1)T 的证明

设模型变换矩阵为 M \mathbf{M} M,切线向量 t \mathbf{t} t 变换后为 M t \mathbf{M}\mathbf{t} Mt,法线 n \mathbf{n} n 变换后为 N n \mathbf{N}\mathbf{n} Nn。需满足:
( N n ) ⋅ ( M t ) = 0 (\mathbf{N}\mathbf{n}) \cdot (\mathbf{M}\mathbf{t}) = 0 (Nn)(Mt)=0
展开得:
n T N T M t = 0 \mathbf{n}^T \mathbf{N}^T \mathbf{M} \mathbf{t} = 0 nTNTMt=0
因原始法线与切线正交( n T t = 0 \mathbf{n}^T \mathbf{t} = 0 nTt=0),需有:
N T M = I    ⟹    N = ( M − 1 ) T \mathbf{N}^T \mathbf{M} = \mathbf{I} \implies \mathbf{N} = (\mathbf{M}^{-1})^T NTM=IN=(M1)T

1.3.3 视线方向 v \mathbf{v} v 的计算

在视图坐标系中,设表面点坐标为 p \mathbf{p} p,则:
v = − p ∥ p ∥ \mathbf{v} = -\frac{\mathbf{p}}{\|\mathbf{p}\|} v=pp


http://www.mrgr.cn/news/97898.html

相关文章:

  • 1200 模拟量输入输出功能
  • python调用本地部署的大模型(llama3.2)
  • Vue3 + TypeScript 的 Hooks 实用示例
  • XTG900P可编程网关在焦化厂数据采集的应用
  • 编译freecad
  • xHCI 上 USB 读写分析
  • openharmony—release—4.1开源鸿蒙源码编译踩坑记录
  • Backtrader从0到1——第一个回测策略
  • ubuntu20.04在mid360部署direct_lidar_odometry(DLO)
  • 如何通过前端表格控件实现自动化报表?1
  • Cursor Agent 模式实现复杂工作流的编排与执行
  • 百度地图小区边界爬取
  • 创建型模式究竟解决了什么问题
  • Vue Router(2)
  • 机器学习 | 强化学习方法分类汇总 | 概念向
  • 【教学类-102-07】剪纸图案全套代码07——Python点状虚线优化版本+制作1图2图6图
  • 【GDB】调试程序的基本命令和用法(Qt程序为例)
  • STM32硬件IIC+DMA驱动OLED显示——释放CPU资源,提升实时性
  • IAP Firmware Upload Tools.exe IAP 网络固件升级教程
  • Vue3+Vite+TypeScript+Element Plus开发-12.动态路由-配置