GPU 干两件事:① 把顶点流处理成裁剪空间顶点;② 据此画像素。 前两课把「哪些像素」和「像素什么颜色」解决了,本课管颜色从哪取——以及取完之后往哪写。
本节点在骨架 ② 的第 3 环——像素已经有颜色了,但那颜色还没从贴图上取。
采样贴图有一个绕不开的矛盾:屏幕上的一个像素,覆盖的贴图面积可能远大于一个纹素。 这时如果还去取最细的那一层,相邻像素会取到毫不相关的纹素——整片花纹开始闪烁、起摩尔纹。 硬件对此的解法是:先在片元里算出 uv 相对屏幕的变化率,再据此选一个够粗的层。 本段只增加一样东西:屏幕导数与层选择。
决定选哪一层的不是「贴图本身多大」,而是 uv 在一个像素上变了多少。同样的贴图,压得越扁,选的层越粗。
把 uv 缩放推大:一像素覆盖的贴图面积变大。 第一种模式下会看到摩尔纹与闪烁——那就是「不选层」的代价;第二种模式下花纹会平滑地退成灰,这就是选层。
先在「最细层」把 uv 缩放推到最大,看花纹怎么烂掉;再切到「按导数选层」。注意看:密的地方不再闪,而是均匀地变糊。
| 项 | 值 | |
|---|---|---|
| 项 | 值 | |
|---|---|---|
| 项 | 值 | |
|---|---|---|
dpdx/dpdy 相同)。
③ 的 λ 就是由它算出来的——件二「按导数选层」用的正是这个 λ。
知道选层的依据是uv 在一个像素上变了多少(屏幕导数),而不是贴图本身的尺寸; 也知道「越密越糊」不是画质变差,而是用分辨率换掉闪烁。
跑不起来先看设备要求:活例由真 GPU 出画面 —— 手机需 Android 12+ 且 Chrome 121+,或 iOS / iPadOS 26+;电脑需 Chrome / Edge 113+ 或 Safari 26+。Android 上取不到适配器多是设备不支持 Vulkan 1.1+,会自动改走兼容模式(需 Chrome 146+)。不满足时画面区会写出原因与自查步骤,同一页的示意图与数值表照常可读。
本节点在骨架 ② 的第 4 环——层已经选好了,但那一层里还只是一堆纹素。
上一段只解决了「去哪一层」。可层里是一格一格的值,而 uv 是连续的浮点: 落在格子中间时取哪一个?取 uv 超出 [0,1] 时怎么办?这两件事由采样器状态决定—— 过滤(邻近取 1 个纹素 / 双线性取 2×2 加权)与寻址(超出范围怎么折回)。 本段只增加一样东西:采样器状态。
同一个 uv,换个寻址模式就落到完全不同的纹素上。采样器状态不是画质选项,它决定取到哪个值。
放大看过滤:本页的贴图只有 4×4 个纹素,被放大到整屏,所以格子清晰可见。 「邻近」给出硬边方格,「双线性」给出它们之间的过渡——那个过渡不是在贴图里,是采出来的。
看寻址:uv 从 0 一直到 3.2,本来就超出了 [0,1]。「重复」把它折回并平铺; 「钳制」把边缘那一列拉成条纹;「镜像」来回翻转。
先在「邻近」下看清 4×4 的格子边界,再切「双线性」。注意看:格子变糊了,但没有任何一行代码在混合颜色——是采样器按权重把四个纹素加权出来的。
| 项 | 值 | |
|---|---|---|
| 项 | 值 | |
|---|---|---|
| 纹素 | 权重 | 颜色 |
|---|
(1−fx)(1−fy) + fx(1−fy) + (1−fx)fy + fx·fy = 1)。
切到「邻近」时权重会变成 one-hot:一个 1,其余 0——那时采样器只取一个纹素。
知道「贴着看」和「远远看」的区别由采样器状态决定:过滤决定层内取几个纹素、怎么加权, 寻址决定 uv 超出范围时折向哪里——两者都不在贴图数据里,而在采样方式里。
本节点在骨架 ② 的最后一环——片元已经算出颜色了,但它还没写进缓冲。
上面两段都在讲「怎么取到一个颜色」。可颜色算完还有一步: 它怎么和缓冲里已有的内容合并。半透明物体要与后面已画好的东西叠加, 而叠加是与绘制顺序有关的——先画的先在缓冲里,后画的按公式叠上去; 写入时如果目标是 sRGB,硬件还会把线性值编码一次。 本段只增加一样东西:输出合并(混合与写入编码)。
混合不是「把颜色加一遍」——它按 alpha 在源与目标之间加权。而写入编码是值本身变了:0.5 写进去会变成 0.735。
先看顺序:把混合关掉,切换绘制顺序——谁后画谁在上,结果完全不同。 再打开混合,两者叠加,顺序仍然影响最终颜色。
右边是写入编码示意 · 等价重现 同一个线性灰阶,上半原样写入、下半按 sRGB 编码后写入。 两者的中灰差得很明显:128 对 188。真正的编码由硬件在写入时做,本页用同一条传递函数重现它。
把混合关掉、来回切绘制顺序。注意看:不透明物体的遮挡关系,本质上就是谁后落进缓冲——这与它们谁离相机更近无关。
| 项 | 值 | |
|---|---|---|
| 项 | 值 | |
|---|---|---|
| 顺序 | 结果 | |
|---|---|---|
src×α + dst×(1−α) 算出来的;③ 把两种顺序的结果并排放着——
混合开着时两者不同,混合关掉时只取决于谁后画。这就是「半透明物体要排序」的全部理由。
知道片元算完之后还有一关:与缓冲里已有内容合并。半透明的叠加与绘制顺序有关, 所以顺序不透明物体时才不需要排序;也知道写入 sRGB 目标时值会在写入那一刻被编码。