三角形是怎么变成“一格格像素“的?——揭秘光栅化
接着上一步三角形拼好了然后呢上一篇我们讲清了图元装配——GPU 照着索引说明书把散落的点连成了一个个三角形。现在问题很自然地来到了下一步好我手里有一个三角形了。它此刻还只是一个用三条边围出来的、空心的线框骨架。可我的屏幕是由一格一格的像素组成的呀屏幕上要显示的是一片片填满颜色的实心区域而不是几条干巴巴的边线。那么——这个空心的三角形线框是怎么变成一格格填满的实心像素的完成这个从线框到实心像素魔法转变的工序就叫——光栅化Rasterization。它是整条渲染流水线里一个决定性的转折点。今天我们就用大白话把它彻底讲明白。一、光栅化到底在干一件什么事先记住一句话这就是光栅化的全部核心光栅化就是判断这个三角形到底盖住了屏幕上哪些像素格子然后把这些格子一个个地点亮/填上。我们用一个绝妙的比喻——“在方格纸上涂三角形”想象你有一张方格纸每一个小方格,就是屏幕上的一个像素。现在,我给你三个点的位置,让你在这张方格纸上画一个三角形。你先用铅笔,把三个点连起来,画出了三角形的轮廓线。但老师要求:“不能只画线框,要用彩笔,把三角形内部,一格一格地涂满!”于是你开始涂色。你会怎么判断哪些格子该涂呢?你会看:“这个小方格,它的中心,是落在三角形内部,还是外部?”中心在三角形里面→涂!这个像素属于三角形中心在三角形外面→不涂!这个像素不属于三角形你把所有格子都这么判断一遍、涂一遍,最后——一个由实心小方格组成的、填满颜色的三角形,就出现在方格纸上了!这个在方格纸上一格一格判断、一格一格填涂的过程就是光栅化方格纸 你的屏幕;每个小方格 一个像素;判断格子中心在不在三角形内 光栅化的核心计算;填涂 生成一个个待处理的像素。看光栅化就是把矢量的、连续的、光滑的三角形几何图形转换成离散的、一格一格的像素的过程。从数学上的形状变成了屏幕上的方块块。二、为什么图片放大了会看到锯齿和马赛克理解了光栅化你顺便就能搞懂一个生活中的常见现象了。你有没有发现一条斜线或者一个圆的边缘在屏幕上放大了看总是歪歪扭扭、有锯齿像楼梯台阶一样这正是光栅化的副作用因为屏幕的像素,是一个个方方正正的格子。而现实中的斜线、曲线是光滑连续的。用方格子去逼近一条斜线,就好比用一堆小方块去搭一个斜坡——再怎么搭,边缘也是一格一格、锯齿状的台阶,不可能绝对光滑。这就是锯齿Aliasing的由来——它是连续的形状被离散的像素表达时必然产生的误差。那怎么办呢于是就有了大名鼎鼎的技术——“抗锯齿Anti-Aliasing”。它的思路很聪明在锯齿的边缘填上一些过渡的、半深半浅的颜色从视觉上骗过你的眼睛让那些生硬的台阶看起来变得柔和、平滑。你在游戏画质设置里看到的 MSAA、FXAA、TAA 等选项就是各种不同的抗锯齿方案。看一个小小的锯齿现象背后藏着的正是光栅化这道工序的本质——用有限的方格去表达无限光滑的形状。三、光栅化不只是填格子它还很贴心地传数据光栅化最容易被误解的地方是以为它只是确定哪些像素被填。其实它还干了一件极其重要的事——为每个像素插值计算出各种数据。这话有点绕我们还是用比喻假设三角形的三个顶点,颜色分别是红、绿、蓝。那么三角形内部的那些像素,该是什么颜色?光栅化会很聪明地做**“平滑过渡”**:靠近红色顶点的像素,偏红;靠近绿色顶点的像素,偏绿;正中间的像素,是三种颜色的混合……于是,整个三角形内部,呈现出一片红绿蓝丝滑渐变的效果。这个根据三个顶点的值平滑地推算出内部每个像素的值的过程叫插值Interpolation。不光是颜色还有贴图坐标、法线、深度等各种数据都是光栅化通过插值为每个像素算出来的。打个比方:三个顶点像是三根标杆,标好了三个角的数值。而内部千千万万个像素的数值,不用一个个重新测量,而是根据它到三根标杆的远近,平滑地估算出来。又快又自然。这一步插值极其关键——因为下一道工序片元着色器给像素上色、算光照所需要的各种数据全靠光栅化这里插值准备好了光栅化是承前启后的数据加工与分发中心。四、把它放回流水线看清承上启下① 顶点处理 —— 定好每个顶点在屏幕的位置 ↓ ② 图元装配 —— 把顶点连成一个个三角形线框 ↓ ★ 光栅化Rasterization★ ← 我们在这里 —— 判断三角形盖住了哪些像素格子填格子 —— 为每个像素插值算好颜色、贴图、深度等数据 —— 把这一堆待上色的像素片元交给下一步 ↓ ③ 片元处理 —— 给每个像素算出最终颜色上色、打光 ↓ ……测试、输出到屏幕看清它的枢纽地位了吗在它之前流水线处理的是顶点、三角形这种几何图形数量少是形状;在它之后流水线处理的是像素、片元这种屏幕上的点数量巨大是颜色点。光栅化正是从几何世界跨入像素世界的那道大门、那座桥梁。过了这道门我们就从研究形状正式进入了研究每个点该是什么颜色的阶段。尾声光栅化的启示——“再宏大的连续最终都要落地为一个个具体的当下”我们讲完了光栅化——这道把空心的三角形线框变成一格格填满的实心像素的神奇工序。它用方格纸涂色般朴素的方式完成了整条流水线中最关键的一次跨越从连续、光滑、理想的几何形状落地为离散、具体、真实的一个个像素。而在这道从连续到离散、从形状到像素的工序里藏着一个耐人寻味的哲理再宏大、再连续、再理想的东西最终都要落地为一个个具体的、有限的、可执行的当下。你看那个三角形在数学上它是一个完美、连续、无限精确的理想图形;可它要真正显示出来、被人看见就必须落地——被拆解成一个个具体的、有限的像素格子。哪怕会因此产生锯齿哪怕不再那么完美但唯有如此它才从抽象的理念变成了眼前的现实。这多像我们的理想与人生啊。我们心中常怀着一些宏大而连续的理想——一个远大的梦想、一个完美的计划、一幅美好的蓝图。它们在脑海里光滑、圆满、毫无瑕疵;可理想若只停留在连续的想象里它就永远只是一个三角形线框虚无缥缈无法被世界看见。唯有把它光栅化——拆解成一个个具体的、当下能执行的小步骤、小行动像素一格一格地、踏踏实实地去填涂它才能真正显示在现实的屏幕上;而光栅化还坦然地告诉我们“落地”往往意味着接受不完美。连续的理想一旦变成离散的现实难免会有锯齿、有妥协、有遗憾。但成熟的人懂得与其守着一个完美却永不落地的空想不如拥抱一个带着锯齿却真实存在的现实——因为还可以用抗锯齿般的智慧去慢慢地修饰、优化、让它趋于圆满。王阳明讲知行合一,反对空知而不行。光栅化那把理想的连续形状,落地为具体的像素的过程,恰是一场生动的知行合一——再美好的知(理想的三角形),都必须落地为具体的行(一个个实实在在的像素),才有意义。光想不做的三角形,永远显示不到屏幕上。所以当你又抱着一个宏大的梦想却迟迟不敢动手或因追求完美而寸步难行时愿你能想起光栅化那在方格纸上一格一格涂色的朴素画面对自己说“别让我的理想永远停在那个’完美却虚无的线框’里。我要把它’光栅化’——拆成一个个当下能做的、具体的小格子然后一格一格地踏实填满。”哪怕带着锯齿哪怕并不完美——一个落地了的、真实的三角形永远胜过一万个悬浮着的、完美的空想。把连续的理想落地为离散的行动把宏大的蓝图填涂成具体的当下——这就是那道朴素的光栅化工序用它把三角形变成像素的方式为我们上的、关于知行合一的、最生动的一课。