如果你玩过近十年的 3A 大作,一定感受过画面质感的飞跃——但如果你仔细对比游戏和电影级 CG,会发现一个微妙但顽固的差异:游戏里的阴影总是偏"硬"、玻璃只有个大概的反光、墙角暗部永远不够自然。这背后不是技术团队偷懒,而是实时渲染三十年来一直用的一把利器——光栅化——在骨子里就决定了这些效果很难做。
光栅化到底在干什么?
要理解光栅化,先想一个问题:一个由几百万个三角形构成的 3D 场景,怎么变成你屏幕上那 1920×1080 个像素的颜色?
光栅化的回答很直接,只有两步:
第一步,投影。 把每个三角形的三个顶点从 3D 空间"拍扁"到 2D 屏幕上——就像用投影仪把幻灯片打到墙上。这个操作叫透视投影,就是模拟人眼的"近大远小"。
第二步,填像素。 对于每个投影后的 2D 三角形,判断屏幕上哪些像素的中心点落在它里面,然后给这些像素涂上颜色。这个过程叫"采样"——说白了就是问:这个像素算不算属于这个三角形?12
用伪代码表示就是:
1for (每个三角形 in 场景) {
2 把它的三个顶点投影到屏幕坐标
3 for (每个像素 in 屏幕) {
4 if (像素中心落在三角形内) {
5 给这个像素涂上三角形的颜色
6 }
7 }
8}这就是最朴素的光栅化。3
为什么它这么快?
对比一下另一种渲染方式——光线追踪——你就明白了。
光线追踪是"每个像素出发,向场景里射一条光线,看它撞到谁"。它的循环是:
1for (每个像素 in 屏幕) {
2 发射一条光线穿过这个像素
3 for (每个三角形 in 场景) {
4 检测光线是否与这个三角形相交
5 }
6 取最近的交点,涂颜色
7}两层循环完全颠倒。3 光线追踪的致命问题是:每一条光线都要跟场景里所有三角形做相交测试——场景有 100 万个三角形,每个像素就要算 100 万次。这还只算一次弹射,如果要算反射、折射,光线要弹好几下,计算量翻倍再翻倍。
而光栅化为什么快?因为它的操作极其简单:
- 投影 就是矩阵乘法,对每个顶点算一次,高效且可并行。
- 填像素 的核心是"点是否在三角形内"——用几何上的叉积就能判断,不需要复杂的"光线-几何体"相交计算。2
- 不需要和场景里其他三角形打交道:每个三角形独立处理,画完就丢。
所以 GPU 设计成"一次处理一大堆三角形"的并行架构,把光栅化跑得飞起——60 帧每秒,每帧几毫秒,轻松搞定。1
但"快"的代价是什么?
问题就出在"每个三角形独立处理"这句话上。
3D 场景里有一个茶壶、一堵墙、一盏灯,用光栅化渲染时,它们 各自画各自的。茶壶不知道自己挡住了墙上的光,墙不知道自己应该反射茶壶的影子,暗处不知道自己应该接收从天花板弹过来的间接光。
但现实世界不是这样运作的。你在房间里看到的一切,都是光在物体之间不断弹射的结果——阳光照到地板,地板反射到天花板,天花板再反射到桌底——这叫 全局光照。阴影、反射、折射、间接光照,所有这些"让画面突然变真"的效果,本质上都是 跨物体的光学现象,需要知道"别的物体在干什么"。4
光栅化的逻辑是"先画完一个物体,再画下一个",它天生没有机制去问:"哎,这个像素的颜色,是不是受那个角落里的物体影响?"
你能看到的"假"
这个缺陷是万恶之源。游戏开发者不得不用各种"奇技淫巧"来补救:
- 阴影:要额外从光源视角再渲染一遍场景(叫"阴影贴图"),然后把结果贴回主画面。但这样做出来的阴影很容易有锯齿、抖动,光源一动就露馅。5
- 反射:没办法让物体自己反射周围环境,只能预先烘焙一张"环境贴图"贴在表面,或者用"屏幕空间反射"——只能反射屏幕里已经画好的东西,屏幕外的一概看不到。
- 间接光:墙角暗部应该接收从周围墙壁弹过来的光,但光栅化根本不知道有这回事,只好粗暴地加一个"环境光"常数,让暗部不完全是黑的——但这显然不是物理正确的。
- 折射:玻璃后面的物体会扭曲,这需要算光线穿过玻璃的路径,没法用填三角形的方式搞出来。
这些效果不是完全做不了,而是 每一种都要单独搞一套复杂的 hack,而且效果还有限——画面"看上去还行",但跟真实世界一比就露怯。45
所以画面"突然变真"的那一步是什么?
光线追踪把这套逻辑翻了过来:不是"逐个物体画到屏幕上",而是"从每个像素出发,模拟光线在场景里的真实路径"。阴影、反射、折射、间接光,在这些光线路径中 自然出现,不需要额外 hack。3
代价就是计算量爆炸——直到最近几年,GPU 硬件终于加入了专门的光线追踪加速单元(英伟达 RTX 系列),才让实时游戏里开始真正跑起光线追踪。
但那是下一篇的内容了。今天你只需要记住:光栅化快,是因为"各画各的";光线追踪真,是因为"模拟光线怎么走"——而"跨物体的光学效果",正是区分这两者的分水岭。