每日编程实践: Normal Mapping - 法线贴图
Normal Mapping - 法线贴图
项目目标
实现法线贴图(Normal Mapping)技术,在光线追踪器中渲染带有法线贴图的球体,展示如何在不增加几何复杂度的情况下增加表面细节。
实现过程
技术背景
法线贴图(Normal Mapping) 是一种重要的图形学技术,通过扰动表面法线方向来模拟凹凸细节,而不需要增加几何复杂度。这项技术广泛应用于游戏和电影 CG 中,能够在保持高性能的同时大幅提升视觉效果。
核心技术
- 程序化法线贴图生成 - 生成砖块图案的法线贴图
- 切线空间(Tangent Space) - TBN 矩阵的构建
- 法线变换 - 从切线空间到世界空间
- Phong 光照模型 - 使用扰动后的法线计算光照
- 球面 UV 映射 - 将 2D 纹理映射到 3D 球体
迭代历史
迭代 1: 初始实现
创建基础框架,实现法线贴图的加载、切线空间变换和光照计算。
迭代 2: 修复编译错误
问题: Vec3 operator* 类型不匹配
1 | error: no match for 'operator*' (operand types are 'Vec3' and 'const Vec3') |
原因: Phong 光照计算中尝试将两个 Vec3 相乘,但只定义了 Vec3 * double 的运算符。
解决方案: 添加 mul() 方法用于逐元素乘法(Hadamard product)
1 | Vec3 mul(const Vec3& v) const { |
迭代 3: 警告清理
清理未使用的参数和变量,确保编译时无警告。
最终版本
✅ 编译通过(0 错误 0 警告)
✅ 运行成功(渲染时间 ~3 秒)
✅ 量化验证通过
核心代码
1. 程序化法线贴图生成
1 | Vec3 procedural_normal_map(double u, double v) { |
2. 切线空间到世界空间的转换
1 | Vec3 tangent_to_world(const Vec3& tangent_normal, const Vec3& world_normal) { |
3. 渲染流程
1 | // 获取几何法线 |
运行结果

对比说明
- 左侧球体: 平滑表面(无法线贴图)
- 右侧球体: 砖块纹理(使用法线贴图)
量化验证结果
1 | 左侧(平滑) 球体: |
观察: 右侧球体的标准差略低,这是因为砖块图案使表面光照更加均匀。
技术总结
法线贴图的优势
- 低几何成本: 不增加三角形数量
- 高细节表现: 能模拟凹凸、裂纹、织物纹理等细节
- 动态光照响应: 随光源变化而变化(区别于纹理贴图)
- 易于实现: 只需要在着色器中调整法线方向
与其他技术对比
| 技术 | 几何复杂度 | 细节表现 | 性能 | 光照响应 |
|---|---|---|---|---|
| 高精度建模 | 极高 | 完美 | 低 | 完美 |
| 纹理贴图 | 低 | 静态 | 高 | 无 |
| 法线贴图 | 低 | 动态 | 高 | 完美 |
| 视差贴图 | 低 | 更真实 | 中 | 完美 |
| 位移贴图 | 中 | 完美 | 中 | 完美 |
应用场景
- 游戏实时渲染: 降低模型复杂度,提高帧率
- 电影 CG: 增加细节密度,减少渲染时间
- VR/AR: 减少几何数据传输,降低延迟
- 移动设备: 在低性能硬件上实现高质量渲染
局限性
- 轮廓边缘: 无法改变几何轮廓
- 遮挡关系: 无法产生真实的遮挡效果
- 极端视角: 低角度观察时效果不佳
解决方案: 视差贴图(Parallax Mapping)或位移贴图(Displacement Mapping)
学到的坑
- 向量运算: 注意区分标量乘法(Vec3 * double)和逐元素乘法(Vec3 mul Vec3)
- 法线归一化: 每次变换后都要归一化,否则光照计算会出错
- 切线空间构建: 需要处理法线接近 (0,1,0) 的特殊情况
- UV 映射: 球面 UV 映射需要正确处理 atan2 和 asin 的值域
下一步探索
- 视差贴图(Parallax Mapping) - 更真实的深度效果
- 位移贴图(Displacement Mapping) - 真实改变几何形状
- PBR 材质 - 基于物理的渲染
- 法线贴图压缩 - BC5/BC7 压缩格式
代码仓库
GitHub: daily-coding-practice/2026/02/02-23-Normal-Mapping
完成时间: 2026-02-23 05:40
迭代次数: 2 次编译修复
编译器: g++ 12.3.1 (C++17)
性能: 800×600 图像,渲染时间 ~3 秒
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Chiuhou 技术博客!










