每日编程实践: Triangle Rasterization - 三角形光栅化器
Triangle Rasterization - 三角形光栅化器
项目目标
今天的目标是从零实现一个三角形光栅化器,这是现代3D图形渲染管线的核心组件之一。
光栅化器的职责是:将三角形(几何)转换为屏幕上的像素(图像)。
我们将实现:
- ✅ Barycentric 坐标算法 - 判断点是否在三角形内
- ✅ Z-Buffer 深度测试 - 正确处理遮挡关系
- ✅ 颜色插值 - 顶点颜色的平滑渐变
- ✅ 边界框优化 - 只遍历必要的像素
实现过程
迭代历史
05:33 - 初始版本: 编写完整的光栅化器代码
- 实现 Vec2/Vec3/Color 基础数据结构
- 实现 barycentric() 重心坐标计算
- 实现 rasterizeTriangle() 光栅化函数
- 初始化帧缓冲和深度缓冲
05:34 - 编译错误: 缺少
<limits>头文件- 错误信息:
'numeric_limits' is not a member of 'std' - 原因:使用了
std::numeric_limits<float>::max()但没有包含<limits> - 修复:添加
#include <limits>
- 错误信息:
05:35 - ✅ 编译成功,运行成功
- 生成 rasterization_output.png
- 三个三角形正确渲染
05:37 - ✅ 量化验证通过
- 红色三角形区域:RGB(220, 53, 54) ✅
- 绿色三角形区域:RGB(46, 147, 119) ✅
- 蓝色三角形(中心):RGB(62, 62, 240) ✅
- 深度测试正确:蓝色三角形(z=0.3)遮挡了红色(z=0.5)和绿色(z=0.6)
核心代码
1. 重心坐标算法
重心坐标是判断点是否在三角形内的经典方法:
1 | Vec3 barycentric(const Vec2& p, const Vec2& a, const Vec2& b, const Vec2& c) { |
关键特性:
- 如果
u, v, w都 ≥ 0,则点在三角形内 u + v + w = 1(标准化)- 可用于插值任何顶点属性(颜色、纹理坐标、法线等)
2. 光栅化主循环
1 | void rasterizeTriangle( |
优化要点:
- 边界框 - 只遍历三角形覆盖的区域,而非整个屏幕
- 深度测试 - 只更新更近的像素(z < zbuffer[idx])
- 像素中心 - 采样点在像素中心(x+0.5, y+0.5)
运行结果

场景包含3个重叠的三角形:
- 红色三角形(左侧)- 深度 z=0.5,红色渐变
- 绿色三角形(右侧)- 深度 z=0.6,绿色渐变
- 蓝色三角形(中心)- 深度 z=0.3(最前面),蓝色渐变
深度测试验证:蓝色三角形正确遮挡了红色和绿色三角形的重叠部分。
技术总结
学到的技术点
Barycentric 坐标系统
- 三角形内任意点可表示为顶点的加权组合
- 权重和为1,且都非负时点在三角形内
- 是插值的数学基础
Z-Buffer 算法
- 解决可见性问题的经典算法(1974年 Catmull 发明)
- 线性空间复杂度:O(width × height)
- 与绘制顺序无关(任意顺序都能得到正确结果)
插值的意义
- 从顶点属性平滑过渡到片段属性
- 用于颜色、纹理坐标、法线、深度等
- 是着色器编程的核心概念
边界框优化
- 避免遍历整个屏幕(800×600 = 480,000 像素)
- 小三角形可能只需检查几百个像素
- 性能提升可达 10-100 倍
遇到的坑和解决方案
问题:编译错误 - numeric_limits 找不到
1 | error: 'numeric_limits' is not a member of 'std' |
原因:
1 | std::vector<float> zbuffer(width * height, std::numeric_limits<float>::max()); |
使用了 std::numeric_limits 但没有包含 <limits> 头文件。
解决:
1 |
教训:C++ 标准库的模板类需要显式包含对应头文件,不像 Python 那样自动导入。
性能分析
算法复杂度:
- 时间:O(N × A)
- N = 三角形数量
- A = 每个三角形的边界框面积(像素数)
- 空间:O(W × H)
- W × H = 屏幕分辨率
本例:
- 屏幕:800×600 = 480,000 像素
- 3个三角形,每个约 10,000-50,000 像素
- 总检查次数:约 100,000 次重心坐标计算
- 运行时间:< 0.1 秒(未优化的 C++ 代码)
可能的优化:
- SIMD 向量化 - SSE/AVX 加速重心坐标计算
- 多线程 - 按扫描线或tile并行
- Early-Z - 提前深度测试,减少不必要的插值
- Hierarchical Z-Buffer - 多层次深度缓冲
扩展方向
这个基础光栅化器是现代GPU渲染管线的简化版本。后续可以扩展:
- 透视校正纹理映射 - 除以 w 分量修正透视失真
- 抗锯齿(Anti-Aliasing) - MSAA / SSAA / FXAA
- 背面剔除(Back-face Culling) - 只渲染朝向相机的三角形
- 顶点着色器 + 片段着色器 - 可编程渲染管线
- 延迟渲染(Deferred Rendering) - G-Buffer 方法
代码仓库
GitHub: daily-coding-practice/2026/02/02-26-Triangle-Rasterization
参考资料
- Barycentric Coordinates - Wikipedia
- Z-buffering - Wikipedia
- Rasterization - Wikipedia
- Tiny Renderer Tutorial - 优秀的图形学入门教程
- Scratchapixel - Rasterization - 详细的光栅化教程
完成时间: 2026-02-26 05:41
迭代次数: 2 次
编译器: g++ (C++11)
总耗时: 11 分钟
下一步计划:
- B-spline 曲线
- BVH 加速结构
- 抗锯齿技术(MSAA/FXAA)
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Chiuhou 技术博客!










