← 返回数学 English

显卡背后的数学

从三角形顶点到屏幕像素——你的 GPU 每一帧都在算的数学,一步一步拆给你看

线性代数 矩阵变换 投影几何 光栅化

第一部分:从3D空间到屏幕坐标

一个三角形顶点,如何在几微秒内从虚拟世界飞到你的显示器上

问题登场:一张3D画面,到底是怎么算出来的?

打开任何一款3D游戏,你看到的每一帧画面——角色、建筑、光影——背后都是数十万个三角形。显卡每秒处理这些三角形,把它们变成屏幕上的像素。

但一个三角形在3D世界里的位置——比如"在(x=3.7, y=1.2, z=-8.5)处有一个顶点"——怎么最终变成你显示器上 "第 847 行、第 523 列的那个像素" 呢?

3D 世界中的三角形 (x, y, z) GPU 渲染管线 ? 屏幕上的像素 (行, 列)
整篇文章就是为了解开中间那个 ? —— GPU 的整个数学流水线
⚠ 问题来了 你的显示器是 2D 的(只有行和列),但 3D 世界有 x、y、z 三个维度。怎么把 3D 坐标变成 2D 像素位置? 而且——远处的物体看起来更小,这个"近大远小"怎么变成数学?

第一站:一个"点"的数学表达

在 3D 世界里,任何物体——角色、建筑、云——都由三角形的顶点组成。我们先聚焦一个顶点。

一个点 P 在 3D 空间中的位置,用三个数表示:P = (x, y, z)。但更优雅的写法是把它看成一个列向量

P = xyz

向量不仅可以表示"位置",还可以表示方向位移法线——这些在后续的光照计算中至关重要。

x y z (向里) P(3, 2, 1) x=3 y=2
点 P(3, 2, 1) —— 三个数,对应三个坐标轴上的投影
💡 关键事实 ① 一个顶点 = 一个 3D 列向量。整个三角形的三个顶点,就是三个这样的向量。显卡对它们做的事,本质上就是对向量做数学运算

发现一:平移——把点搬到新位置

你移动游戏角色:按一下右键,角色瞬间从 (3, 2, 1) 位移到 (9, 2, 1)。这很简单:

x'y'z' = xyz + ΔxΔyΔz

每个分量加一个平移量,完事。

x y 原 P(3,2) 平移 (6, 0) 新 P'(9,2) 3 9
平移 = 每个坐标分量加上一个偏移量
✅ 记下结果 平移 = 向量加法。P' = P + T。简单直观,三个分量各加各的。
⚠ 但有个麻烦 平移是加法,旋转和缩放却是乘法。三种操作形式不统一——每次变换都要判断"这次用加法还是乘法?" 后面我们会用一个巧妙的方法把它们全部统一成矩阵乘法

发现二:旋转——矩阵的魔法

旋转比平移复杂。绕 z 轴旋转 θ 角:x 和 y 坐标会互相"掺和",但 z 坐标不变。

x'y'z' = cos θ−sin θ0 sin θcos θ0 001 xyz

这就是矩阵 × 向量。矩阵的每一行和向量的每个分量"一一配对、乘起来、加起来":

x' = cos θ · x − sin θ · y     y' = sin θ · x + cos θ · y
P(3, 2) P' θ
绕原点旋转 θ 角——矩阵乘法一步完成
💡 关键事实 ② 旋转 = 矩阵 × 向量。矩阵乘法天然适合旋转:新坐标变成旧坐标的线性组合(加权求和)。缩放也是矩阵乘法——对角矩阵。
🤔 为什么用矩阵? 矩阵乘法可以把一堆操作"攒起来":先旋转再平移?两个矩阵相乘,得到一个新矩阵,然后一次乘法搞定。这叫变换的复合——GPU 最擅长的就是矩阵乘法。

发现三:缩放——对角线上的力量

缩放最简单:每个轴乘以一个系数。用矩阵写就是:

sx00 0sy0 00sz

三个缩放因子坐在对角线上。矩阵乘法自动变成:x' = sx·x, y' = sy·y, z' = sz·z。

现在三种基本变换都写成了矩阵:

变换形式矩阵大小
缩放矩阵 × 向量3×3
旋转矩阵 × 向量3×3
平移向量加法
⚠ 不和谐 缩放和旋转是 3×3 矩阵乘法,平移却是加法。三种操作没法合并成一个矩阵。这是接下来要解决的核心问题。

发现四:齐次坐标——用 4 个数表示 3D 点

解决方案出奇地优雅:给每个 3D 向量加一个"第四分量",称为 w。

P = xyz1

普通 3D 点的 w = 1;方向向量(不需要平移的向量,如法线)的 w = 0。

现在平移也能写成 4×4 矩阵乘法的形式了:

x'y'z'1 = 100Δx 010Δy 001Δz 0001 xyz1

看!第四行把 w=1 原样带到结果中;而最右边一列(蓝色)的三个数正是平移量——它们在矩阵乘法中和 w=1 相乘后被加到 x', y', z' 上。

💡 关键事实 ③ 齐次坐标 (x, y, z, w=1) 让平移变成了一次矩阵乘法。从此以后,缩放、旋转、平移,全都是 4×4 矩阵乘法——统一了!
✅ 记下结果 4×4 齐次矩阵 = 显卡的"通用语言"。所有空间变换,不论类型,都是 矩阵 × 4D 向量。GPU 的硬件就是为这种运算设计的——几千个核心并行做矩阵乘法。

发现五:MVP——三步合成一步

一个三角形顶点从"模型文件里的坐标"到"屏幕上的位置",要经过三个矩阵变换。GPU 把它们缩写为 M·V·P

① Model 矩阵(模型变换)
把顶点从"物体自身坐标系"搬到"世界坐标系"
物 → 世:包含缩放、旋转、平移
② View 矩阵(视图变换)
把世界坐标搬到"摄像机坐标系"
世 → 眼:相当于把摄像机挪到原点
③ Projection 矩阵(投影变换)
把摄像机看到的3D场景"压扁"到2D裁剪空间
眼 → 屏:近大远小在这里编码

三件事,但 GPU 只做一次矩阵乘法

vclip = P · V · M · vlocal

GPU 先把三个矩阵乘成一个大矩阵 MVP = P·V·M,然后对每个顶点只做一次 4×4 × 4×1 的乘法。

🤔 为什么先乘矩阵? 矩阵乘法满足结合律:(P·V)·M = P·(V·M)。一帧有几十万个顶点,每个顶点都做三次矩阵乘法太慢。先把三个矩阵乘好(只需算 1 次),然后每个顶点用这个大矩阵乘 1 次——节省 67% 的运算。

发现六:透视投影——"近大远小"怎样变成数学

这是显卡数学中最巧妙的部分。你的眼睛(或摄像机)是一个点,物体越远看起来越小。这个效果怎么用矩阵编码?

眼睛/摄像机 近裁剪面 远裁剪面 远处物体投影小,近处物体投影大
视锥体 (Frustum):眼睛看到的金字塔形空间

核心公式——投影矩阵的精髓在最后一行:

投影矩阵 P = 00−10  →  它把 z 坐标搬到了 w 分量
💡 关键事实 ④ 投影矩阵不直接做除法——它把"深度信息"藏进了 w 分量。离摄像机越远的点,w 越大。接下来的一步——透视除法——才真正让远处物体变小。

发现七:透视除法——除以 w 的神奇效果

投影矩阵乘完后,我们得到了一个 4D 向量 (xc, yc, zc, wc)。最后一步:

xndcyndczndc = xc / wcyc / wczc / wc

因为投影矩阵的设计,wc ≈ 原来的 z(深度)。所以:z 越大 → w 越大 → 除以更大的数 → x, y 变小 → 远处物体缩小!

深度 z→ z=2 w≈2 z=5 w≈5 z=10 w≈10 同样大小的物体,视觉大小 = 真实大小 / w
透视除法:GPU 硬件自动执行——每个顶点必经的最后一步
✅ 记下结果 经过 MVP 矩阵 + 透视除法,一个 3D 世界中的顶点 (x, y, z) 变成了归一化设备坐标 NDC:x, y 都在 [-1, 1] 范围内,z 在 [0, 1] 范围内。最后再映射到屏幕像素(如 1920×1080),就叫视口变换——简单的线性映射。
🤔 NDC 为什么是 [-1, 1]? 它让 GPU 与分辨率无关。不管你屏幕是 720p 还是 4K,裁剪和背面剔除都在 [-1, 1] 的 NDC 空间完成——这是硬件固定的"标准尺"。

第二部分:三角形内部——从轮廓到像素

三个顶点确定了屏幕上的位置,但三角形里面的成千上万个像素怎么办?

发现八:光栅化——三角形变成像素

三个顶点在屏幕上有了位置(比如 (100, 200), (350, 100), (280, 400)),但三角形内部怎么填充?这就是光栅化 (Rasterization)

GPU 使用边缘函数 (edge function)来判断一个像素在三角形内还是外:

EAB(P) = (Bx − Ax)(Py − Ay) − (By − Ay)(Px − Ax)

这是二维叉积的符号。三条边各算一次,如果三个结果同号——像素就在三角形内。

A B C ✓ 内部 ✗ 外部
边缘函数:三边各判断一次,全同号 = 在三角形内
💡 关键事实 ⑤ 边缘函数是光栅化的核心公式——它把一个几何问题("点在三角形内吗?")变成了一个代数问题("三个表达式同号吗?")。GPU 硬件里专门有电路加速这个计算。

发现九:重心坐标——三个顶点的"份额"

一个像素在三角形内了,但它的颜色、深度、纹理坐标怎么确定?答案:重心坐标 (Barycentric Coordinates)

P = α · A + β · B + γ · C   其中  α + β + γ = 1,且 α, β, γ ≥ 0

α, β, γ 是三个顶点的"权重"。像素离 A 越近,α 越大;在 A 点上,α = 1 且 β = γ = 0。

A (α=1) B (β=1) C (γ=1) P γ ∝ 面积(PAB) β ∝ 面积(PAC) α ∝ 面积(PBC)
重心坐标:像素与对面顶点围成的面积,占总面积的比例 = 该顶点的权重
💡 关键事实 ⑥ 任何一个顶点的属性(颜色、纹理坐标、法线方向),都可以用这三个权重在三角形内部平滑插值。这就是为什么一个三角形的三个顶点有三种颜色时,中间能看到渐变。
P = 0.33·A + 0.33·B + 0.34·C  (和为 1.00 ✓)

扩展一:纹理映射——给三角形"贴纸"

每个顶点不仅有 3D 坐标,还有纹理坐标 (u, v)。u 和 v 在 [0, 1] 范围内,表示在纹理图片上的位置。

像素 (xscreen, yscreen) 已知 α, β, γ 三个权重后,它的纹理坐标自然就是三个顶点纹理坐标的加权平均:

uv = α · uAvA + β · uBvB + γ · uCvC

但有一个陷阱:透视变换会让纹理坐标的线性插值失真。直接用屏幕坐标的 α,β,γ 插值 (u,v) 是不对的! 正确的做法是先对 (u/w, v/w, 1/w) 插值,再除以 1/w 恢复——这叫透视校正插值

🤔 为什么不能直接插? 透视变换是非线性的。远处纹理变密、近处纹理变疏。不用 w 校正的话,纹理看起来会"扭曲"——就像老式 PS1 游戏那种"波浪"效果。现代 GPU 在硬件层面自动处理这件事。

扩展二:光照——法向量、点积与颜色

一个像素的颜色不光来自纹理——还有光照。核心公式:

亮度 = N · L

其中 N 是表面法向量(单位长度),L 是光源方向(单位长度)。它们的内积 = |N|·|L|·cos(夹角)。

当 N 和 L 方向一致时(正对光源,夹角 = 0°)→ cos(0) = 1 → 最亮。当夹角为 90° 时 → cos(90°) = 0 → 全黑

N (法向量) L (光源) θ 亮度 = N·L = cos(θ) = cos(45°) ≈ 0.71
点积 = 光照的数学本质:两个方向"多一致"
夹角 θN·L = cos(θ)效果
0°(正对光源)1.0最亮
45°≈ 0.71中等
60°0.5较暗
90°0全黑
> 90°< 0 → 钳位到 0光源在背面
🤔 法向量也要矩阵变换吗? 是的——但用的是不同的矩阵。法向量用 Model 矩阵的逆转置矩阵(即 M−T)变换,保证变换后依然是单位向量且垂直于表面。GPU 在顶点着色器中自动处理。

全篇地图:一个顶点的生命史

现在回头看——一个从 3D 模型文件里读出的顶点,到底经历了什么?

① 局部坐标 (x, y, z, 1)
模型文件中的原始位置
② × Model 矩阵世界坐标
缩放 + 旋转 + 平移 = 一把到位
③ × View 矩阵摄像机坐标
世界以摄像机为原点重新定位
④ × Projection 矩阵裁剪空间
深度藏入 w,准备好被透视
⑤ 透视除法 (/w) → NDC [-1,1]
近大远小在此生效
⑥ 视口变换屏幕坐标 (像素)
[-1,1] 线性映射到 [0, 1920]×[0, 1080]
⑦ 光栅化三角形内像素
边缘函数判断内外
⑧ 重心坐标插值片元属性
颜色/纹理/法线 = 三个顶点的加权平均
⑨ 纹理采样 + 光照最终像素颜色 RGB
N·L 点积决定亮度,纹理查找决定色调
✅ 一条公式统治全部 从 3D 顶点到屏幕像素的完整旅程,可以压缩成:
屏幕颜色 = 纹理( 插值( 视口( /w( P·V·M · v局部 ) ) ) ) · N·L

核心运算:矩阵乘法、透视除法、边缘判断、权重插值、点积——全部是线性代数

彩蛋:这些数学不只属于显卡

显卡管线的数学工具箱——矩阵、齐次坐标、重心坐标、点积——在看似完全不同的领域反复出现:

GPU 中的概念跨领域等价物领域
4×4 齐次变换矩阵机器人运动学中的 DH 矩阵机器人学
MVP = P·V·M 矩阵复合坐标系链式变换物理/工程
重心坐标插值有限元方法中的形函数计算力学
N·L 漫反射点积两个向量的余弦相似度机器学习/NLP
透视投影矩阵相机标定中的内参矩阵计算机视觉
齐次坐标 (x,y,z,w)射影几何中的齐次表示纯数学
光栅化边缘函数计算几何中的点在多边形内判断GIS/CAD
💡 主角登场:线性代数 显卡背后的数学本质上就是线性代数在 3D 渲染这个具体问题上的应用。你学会的不只是"显卡怎么画三角形",更是如何用矩阵和向量来描述、变换、投影空间中的物体——这是现代科技(图形学、机器人、AI、物理模拟)的通用语言。

你现在已经能从零推导出这一切了

回头看第 ① 节的那个问号:3D 三角形顶点 → 屏幕像素

你现在知道:

1
齐次坐标 (x, y, z, 1) 表示顶点,用 4×4 矩阵 做平移、旋转、缩放
2
P·V·M 三步合成一个矩阵,每个顶点只乘一次
3
投影矩阵把深度藏进 w 分量除以 w 实现近大远小
4
屏幕上的三个顶点围成三角形,边缘函数 判断哪些像素在里面
5
重心坐标 给三个顶点分配权重,三角形内部属性平滑过渡
6
N·L 点积 算出光照亮度,纹理采样定下颜色
✅ 你手里的工具箱 矩阵乘法、齐次坐标、透视除法、边缘函数、重心坐标、点积——这六个概念,就是现代 GPU 每秒处理数十亿个三角形的全部数学基础。你不用记 API 的名字(OpenGL?Vulkan?DirectX?——它们只是同一套数学的不同方言),因为你已经懂了里面的数学。