高级 #graphics#rasterization#depth

三角形光栅化与深度缓冲

光栅化把三角形转换成像素——判断像素在三角形内部。Z-buffer(深度缓冲)解决"哪个像素在前"的问题——每个像素存最近物体的深度值

🎨 画一个三角形——逐个像素检查

光栅化的核心问题:给定三个顶点的屏幕坐标,判断哪些像素在三角形内部。

你拿起喷漆罐在墙上喷一个三角形——喷漆(像素)只能落在三角形覆盖的区域内。你得搞清楚哪些点在里面、哪些在外面。

判断方法:重心坐标

三角形由三个顶点 A, B, C 定义。
点 P 是否在内部?→ 用重心坐标 (α, β, γ) 判断
P = α·A + β·B + γ·C

如果 α ≥ 0, β ≥ 0, γ ≥ 0 → P 在内部
任何一个是负数 → P 在外部
# 简化的判断——用叉积检查点是否在三条边的同一侧
def point_in_triangle(P, A, B, C):
    def sign(p1, p2, p3):
        return (p1[0]-p3[0])*(p2[1]-p3[1]) - (p2[0]-p3[0])*(p1[1]-p3[1])
    
    d1 = sign(P, A, B)
    d2 = sign(P, B, C)
    d3 = sign(P, C, A)
    
    has_neg = (d1 < 0) or (d2 < 0) or (d3 < 0)
    has_pos = (d1 > 0) or (d2 > 0) or (d3 > 0)
    
    return not (has_neg and has_pos)

🏔️ Z-buffer——哪个像素在前面?

两个三角形重叠了——谁在前面显示?

画家算法:先画远处的物体,近处的覆盖上去——但三角形互相穿插时失败。

Z-buffer 是更好的方案:每个像素存”到目前为止最近物体的深度值”。

初始化:所有像素深度 = ∞(最远)

对每个三角形的每个像素:
  1. 算这个像素处三角形的深度 z
  2. 如果 z < depth_buffer[x][y](更近):
      → 更新颜色和深度
  3. 否则 → 被挡住了,不画

例子(两个三角形重叠):
深度缓冲:      ∞   ∞   ∞
画近处(红色):0.3 0.4 0.2 → 像素变红
画远处(蓝色):0.8 > 0.3 → 不画,红色保留

⚡ 背面剔除——不要浪费性能

立方体最多只有 3 个面面向相机——另外 3 个面被挡住了。GPU 通过检查三角形顶点的绕序判断是否面向相机:

逆时针顶点 → 正面
顺时针顶点 → 背面(剔除,不渲染)

glEnable(GL_CULL_FACE);  // 开启背面剔除

📝 小结

概念一句话
光栅化判断像素是否在三角形内部
重心坐标三角形内任意点的参数化表示
Z-buffer每个像素存最近物体的深度
背面剔除跳过背向相机的面

为什么先学这个? 有了像素和深度,接下来学习纹理映射与滤波——怎么给三角形”贴图”。