高级 #graphics#pipeline#gpu

光栅化管线

图形管线(Graphics Pipeline)把 3D 模型变成屏幕上的像素——顶点处理→光栅化→片元处理→输出合并。GPU 就是专门加速这条管线的硬件

🏭 “3D 模型变屏幕像素”——工厂流水线

你有一个 3D 房间的模型——椅子、桌子、墙壁、灯光。你想在 2D 屏幕上显示”从人的视角看这个房间”。

这个过程就像工厂流水线:原材料(3D 顶点)从一端进入,经过一系列工序(各阶段),最终产出成品(像素的颜色)。

这个流水线就叫 图形管线(Graphics Pipeline)——也叫光栅化管线。GPU 就是专门加速这条管线的”工厂”。


📋 管线的四个阶段

顶点数据                   片元着色器
(3D 模型)                (算每个像素颜色)
    ↓                          ↓
┌─────────┐  ┌──────────┐  ┌─────────┐  ┌──────────┐
│ 顶点着色器 │→│ 光栅化    │→│ 片元着色器 │→│ 输出合并   │→ 屏幕
└─────────┘  └──────────┘  └─────────┘  └──────────┘
   ↑                           ↑
 可编程(GLSL)             可编程(GLSL)

① 顶点着色器(Vertex Shader)——每个顶点算一次

输入:3D 顶点坐标(模型定义时确定的) 输出:裁剪坐标(经过 MVP 变换后)

// 顶点着色器——每个顶点执行一次
#version 330 core
layout (location = 0) in vec3 aPos;       // 输入的顶点坐标
layout (location = 1) in vec3 aColor;     // 顶点颜色

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

out vec3 vertexColor;  // 传递给片元着色器

void main() {
    // MVP 变换:模型→视图→投影
    gl_Position = projection * view * model * vec4(aPos, 1.0);
    vertexColor = aColor;
}

💡 如果一个 3D 模型有 10 万个三角形(30 万个顶点)——顶点着色器要执行 30 万次。但 GPU 有几千个核心,并行完成。


② 光栅化(Rasterization)——三角形变成像素

输入:三个顶点的裁剪坐标(一个三角形) 输出:覆盖的所有像素位置(片元)

光栅化阶段是固定功能的——不能编程,由 GPU 硬件直接完成。

三个顶点定义了一个三角形:
    A(100, 50)
    B(200, 150)
    C(50, 180)

光栅化:确定"哪些像素在这个三角形内部"
    ┌──┬──┬──┬──┬──┐
    │  │  │  │  │  │
    ├──┼──┼──┼──┼──┤
    │  │● │● │● │  │  ● = 被三角形覆盖的像素
    ├──┼──┼──┼──┼──┤
    │  │● │● │● │  │
    ├──┼──┼──┼──┼──┤
    │  │  │  │  │  │
    └──┴──┴──┴──┴──┘

每个覆盖的像素(叫”片元”)都有自己的位置——插值得到的(不是单个顶点了)。


③ 片元着色器(Fragment Shader)——每个像素算一次

输入:插值后的片元数据(位置、法线、纹理坐标) 输出:像素的颜色

片元着色器可以编程——图形程序员在这里实现光照、纹理、阴影等效果。

// 片元着色器——每个覆盖的像素执行一次
#version 330 core

in vec3 vertexColor;       // 从顶点着色器插值得到的颜色
in vec2 texCoord;          // 纹理坐标

uniform sampler2D texture1; // 纹理
uniform vec3 lightPos;     // 光源位置

out vec4 FragColor;        // 最终颜色

void main() {
    // 从纹理采样
    vec4 texColor = texture(texture1, texCoord);
    
    // 和顶点颜色混合
    FragColor = texColor * vec4(vertexColor, 1.0);
}

💡 1920×1080 分辨率,渲染一个复杂的 3D 场景——片元着色器可能要执行数百万次。这就是为什么 GPU 有”数千个核心”——它们就是为了同时处理大量像素。


④ 输出合并(Output Merge)——谁的像素在前面?

最后一步决定:多个物体在同一个像素位置重叠时,谁在前面显示

深度测试:近的挡住远的 → 前面物体的像素覆盖后面
模板测试:按模板裁剪 → 类似"用模板切出形状"
混合:半透明物体 → 前后颜色混合

🔧 可编程 vs 固定功能

阶段可编程?做什么
顶点着色器✅ 可编程变换顶点、传递数据
细分/几何着色器✅ 可编程添加/修改几何
光栅化❌ 固定三角形→像素
片元着色器✅ 可编程算颜色(光照/纹理)
深度/模板测试⚠️ 可配置可见性判断

这是现代 GPU 的关键特点:管线的两端可编程,中间固定。——你可以自由控制”怎么算顶点”和”怎么算颜色”,但”三角形转像素”这个步骤是硬件固定的(因为必须快)。


📝 小结

阶段输入→输出执行次数
顶点着色器3D 顶点 → 裁剪坐标每个顶点一次
光栅化三角形 → 片元(像素候选)硬件自动
片元着色器片元 → 颜色每个像素一次
输出合并深度测试/混合每个像素一次

🎯 小练习:为什么光栅化是”固定功能”而不是可编程的?如果把它做成可编程的,会有什么问题?(提示:想想”性能”和”硬件的专业分工”)

为什么先学这个? 了解管线的整体结构后,深入各个阶段——三角形光栅化与深度缓冲