Real-time global illumination — approximating transport in 16 milliseconds实时全局光照——在 16 毫秒内近似光传输
Lesson 11 built a Monte Carlo estimator for the rendering equation and stated the contracts under which its raw accumulation is unbiased. Driving that raw error low can cost hundreds to thousands of paths per pixel. A game has about 16 ms per frame, so it chooses a different error–latency contract: a few transport samples plus cached, approximate, and temporally reused information. This lesson studies three recurring tactics — precompute, approximate, and amortize — through shadow maps, ambient occlusion, baked light, probes, and screen-space reflections. 第 11 课为渲染方程构造了蒙特卡洛估计器,并说明原始累积在什么契约下无偏。要把原始误差压低,每像素可能需要数百到数千条路径。游戏每帧只有约 16 毫秒,因此选择另一套误差–延迟契约:少量光传输样本,加上缓存、近似和跨帧复用的信息。本课通过阴影贴图、环境光遮蔽、烘焙光照、探针与屏幕空间反射,研究三种反复出现的策略:预计算、近似和摊销。
Five moves. (1) The budget wall: restate why a low-error raw Monte Carlo estimate is unaffordable per frame at typical budgets, and name three recurring responses — precompute (bake), approximate (screen-space or sparse sampling), and amortize (temporal reuse). They are a useful taxonomy, not an exhaustive theorem; modern renderers also combine importance sampling, spatial reuse, upscaling, specialized hardware, and learned reconstruction. (2) Shadows via shadow mapping: render depth from the light's view, then compare; meet acne and peter-panning and the bias that trades between them, then PCF and cascades. (3) Ambient occlusion: the "how open is the sky here" term, approximated in screen space by SSAO. (4) Precomputed indirect light: radiosity, lightmaps (static only), and irradiance probes with spherical harmonics (for dynamic objects). (5) Screen-space and the new era: SSR and its on-screen-only limit, then hardware ray tracing + ML denoising + DDGI closing the gap to dynamic GI (bridge to lesson 15). The widget dissects the single most instructive bug in the set: shadow-map bias.
五步走。(1) 预算之墙:重申为何在典型逐帧预算下无法负担低误差的原始蒙特卡洛估计,并点出三种反复出现的应对——预计算(烘焙)、近似(屏幕空间或稀疏采样)、摊销(时序复用)。它们是一套有用的分类,不是穷尽一切的定理;现代渲染器还会组合重要性采样、空间复用、上采样、专用硬件与学习式重建。(2) 用阴影贴图做阴影:从光源视角渲染深度,再比较;见识阴影痤疮与彼得潘,以及在二者之间权衡的偏置,然后是 PCF 与级联。(3) 环境光遮蔽:那个“这里天空有多开阔”的项,由 SSAO 在屏幕空间近似。(4) 预计算间接光:辐射度、光照贴图(仅限静态)、以及带球谐的辐照度探针(用于动态物体)。(5) 屏幕空间与新纪元:SSR 及其“只有屏幕上才有”的局限,然后是硬件光线追踪 + ML 去噪 + DDGI 逼近动态 GI(通往第 15 课的桥)。小控件将解剖整套方法里最有教益的那个 bug:阴影贴图偏置。
1 · The budget wall — offline-quality convergence does not fit one frame预算之墙——离线质量的收敛塞不进一帧
Recall the constraint from lesson 01: a real-time frame must finish in roughly 16.7 ms at 60 FPS (and half that, ~8 ms, at 120 FPS). Now recall lesson 11: path tracing estimates the recursive integral ∫ fr Li (ωi·n) dωi by sampling light paths. For IID finite-variance samples, standard error has the 1/√N baseline, so halving it needs four times the samples; low-discrepancy and reuse methods can improve practical behavior but do not make high-quality raw convergence free. A clean offline frame might spend hundreds to thousands of paths per pixel. At full HD, even 256 paths per pixel means about 5 × 10⁸ primary paths before their bounce rays. Typical real-time budgets therefore cannot drive the raw estimator to a clean offline error level without reconstruction and reuse.
回忆第 01 课的约束:实时一帧在 60 FPS 下必须在大约 16.7 毫秒 内画完(120 FPS 下则减半,~8 毫秒)。再回忆第 11 课:路径追踪通过采样光路来估计递归积分 ∫ fr Li (ωi·n) dωi。对方差有限的 IID 样本,标准误差以 1/√N 为基线,因此减半需要四倍样本;低差异与复用方法能改善实践表现,却不会让高质量原始收敛变成免费。一帧干净的离线画面每像素可能花数百到数千条路径。在全高清下,仅每像素 256 条路径就约有 5 × 10⁸ 条主路径,尚未计算它们的反弹光线。因此典型实时预算若没有重建与复用,就无法把原始估计器压到干净离线图像的误差水平。
So real-time rendering chooses which error to tolerate and where to reuse work. Three recurring strategies organize this lesson:
因此实时渲染会选择容忍哪种误差、又在哪里复用工作。本课用三种反复出现的策略来组织这些方法:
Keep this triple in view as a diagnostic. A shadow map precomputes the light's visibility for the current frame (§2). SSAO approximates ambient occlusion from the depth buffer (§3). Lightmaps precompute an indirect-light solution (§4). Temporal accumulation amortizes samples across frames (§5). Modern systems combine these with sparse ray tracing, importance sampling, spatial reuse, and learned reconstruction. The question is never “did it solve the equation?” in the abstract; it is “which estimator, bias, variance, failure support, latency, and temporal-stability contract did it choose?”
把这三元组当作诊断工具。阴影贴图为当前帧预计算光源可见性(§2);SSAO 从深度缓冲近似环境光遮蔽(§3);光照贴图预计算一份间接光解(§4);时序累积把样本跨帧摊销(§5)。现代系统还会把它们与稀疏光线追踪、重要性采样、空间复用和学习式重建结合。问题从来不是抽象地问“它是否解出了方程”,而是问“它选择了怎样的估计器、偏差、方差、失效支撑、延迟与时间稳定性契约?”
2 · Shadows via shadow mapping — a depth test from the light's eye用阴影贴图做阴影——从光源之眼做一次深度测试
A shadow is pure visibility toward a light: point x is lit if the light can see it, and shadowed if some closer surface blocks the view. Path tracing answers this with a shadow ray. Rasterization cannot shoot arbitrary rays cheaply — but it is superb at one thing: rendering depth from a viewpoint. So flip the viewpoint. Shadow mapping is a two-pass idea:
阴影本质上就是朝向光源的可见性:如果光源能看到点 x,它就被照亮;如果有更近的表面挡住了视线,它就在阴影里。路径追踪用一条阴影光线来回答。光栅化没法便宜地发射任意光线——但它极擅长一件事:从某个视点渲染深度。那就把视点翻过去。阴影贴图是一个两遍(two-pass)的想法:
- Pass 1 — build the map. Put a virtual camera at the light, looking into the scene, and rasterize only depth. The result is the shadow map: a texture where each texel stores the distance from the light to the nearest surface along that direction. This is exactly the light's z-buffer (lesson 04).第一遍——建图。把一台虚拟相机放在光源处、朝场景看,只光栅化深度。结果就是阴影贴图:一张纹理,每个纹素存着沿该方向从光源到最近表面的距离。这恰好就是光源的 z 缓冲(第 04 课)。
- Pass 2 — shade and test. Render the scene normally from the eye. For each visible point x, transform it into the light's space to get its true light-space depth d(x) and the texel it falls under. Look up the stored depth zmap. If d(x) > zmap + bias, something nearer to the light was recorded there — so x is in shadow. Otherwise it is lit.第二遍——着色并测试。照常从眼睛渲染场景。对每个可见点 x,把它变换到光源空间,得到它真正的光源空间深度 d(x) 以及它落在哪个纹素下。查出存储的深度 zmap。若 d(x) > zmap + 偏置,说明那里记录过更靠近光源的东西——于是 x 在阴影里。否则它被照亮。
The whole subtlety hides in that + bias. The shadow map is a finite grid: each texel stores one depth for a little patch of surface, but the real surface under that texel slopes and spans a range of depths. So the stored value is a quantized, slightly-wrong estimate of the true depth. Compare a point against it naively and half the lit surface reports d(x) > zmap purely from that quantization error — the surface shadows itself in stripes. This is shadow acne.
全部的微妙都藏在那个 + 偏置 里。阴影贴图是一张有限的网格:每个纹素为一小片表面只存一个深度,可那纹素底下真实的表面是倾斜的、跨着一段深度范围。所以存下来的值是对真实深度的、量化过的、略有偏差的估计。若拿一个点朴素地去和它比,光照表面里会有一半仅仅因为这点量化误差就报出 d(x) > zmap——表面把自己投成了一条条纹的阴影。这就是阴影痤疮(shadow acne)。
The fix is to nudge the comparison: add a small bias so a point must be meaningfully farther than the stored depth before it counts as shadowed. Too little bias and the acne stripes remain. But push the bias too high and you overshoot the other way: real contact shadows lift off, and an object's shadow visibly detaches from its base as if the object were floating — peter-panning (the shadow, like Peter Pan's, comes unstuck from the feet). Bias is a single knob trading one artifact against the other, and the widget below lets you feel exactly where the safe middle is.
解法是把比较推一下:加一个小小的偏置,让一个点必须明显地比存储深度更远,才算作被遮蔽。偏置太小,痤疮条纹还在。可偏置推得太高就矫枉过正到另一头:真实的接触阴影被抬起,物体的阴影会明显地从它的底部脱开,仿佛物体悬浮着——彼得潘(peter-panning)(阴影像彼得潘那样,从脚上松脱了)。偏置这一个旋钮在两种瑕疵之间权衡,下面的控件让你精确地感受到那个安全的中间地带在哪。
A constant bias is a compromise: surfaces nearly edge-on to the light need a large bias (their depth changes fast across one texel), while surfaces facing the light need almost none. The standard refinement is slope-scaled bias — scale the bias by how grazing the light angle is (roughly by tan of the angle between the surface normal and the light). This shrinks the peter-panning you pay on flat faces while still killing acne on steep ones. The widget uses a single flat receiver, so a constant bias suffices to show the trade cleanly.
常数偏移是一种折中:几乎与光线平行(掠射)的表面需要大偏移(它们的深度在一个纹素内变化很快),而正对光的表面几乎不需要。标准的改进是斜率缩放偏移(slope-scaled bias)——按光照角度有多掠射来缩放偏移(大致按表面法线与光线夹角的 tan)。这在平面上减少了你要付出的彼得潘现象,同时仍能消灭陡面上的痤疮。本控件只用了一个平整的接收面,所以一个常数偏移就足以干净地展示这个取舍。
Two more pieces make shadow maps usable in practice. PCF (percentage-closer filtering) softens the hard, aliased shadow edge: instead of one depth comparison, sample the map at several neighboring texels, run the test on each, and average the pass/fail results. A point half-inside the penumbra comes back "60% lit," giving a soft edge instead of a jagged binary one. And cascaded shadow maps (CSM) handle large scenes: a single map spread over a whole outdoor level would give each texel a huge footprint (chunky shadows). CSM slices the view frustum by distance into a few cascades and gives each its own map — high resolution near the camera where you look, coarse far away where you don't.
还有两件事让阴影贴图在实践中可用。PCF(百分比渐近滤波)柔化那道生硬、走样的阴影边缘:不做单次深度比较,而是在邻近的几个纹素上采样该图、对每个都跑一遍测试、再把通过/未通过的结果平均。一个半陷在半影里的点会返回“照亮 60%”,从而得到柔和的边缘,而不是锯齿状的非黑即白。而级联阴影贴图(CSM)应对大场景:单张图铺满整个户外关卡,会让每个纹素覆盖一大片(块状阴影)。CSM 按距离把视锥切成几段级联、各给一张自己的图——相机近处(你看的地方)高分辨率,远处(你不看的地方)粗糙。
3 · Ambient occlusion — how open is the sky here?环境光遮蔽——这里的天空有多开阔?
Split the incoming light Li into direct (from named light sources — handled by shadow maps) and ambient (a soft, everywhere glow standing in for all the indirect bounces we cannot afford). A crude but common ambient model just adds a constant to every surface. The problem: that constant floods creases, contact points, and cavities that should be darker because surrounding geometry blocks most of the sky. Ambient occlusion is the missing factor — for each point, what fraction of the hemisphere above it is open versus occluded by nearby surfaces. A corner where two walls meet is occluded, so it should be darker; an exposed flat is fully open.
把入射光 Li 拆成直接光(来自具名光源——由阴影贴图处理)与环境光(一层柔和、无处不在的辉光,替代所有我们负担不起的间接反弹)。一个粗糙但常见的环境光模型只是给每个表面加一个常数。问题在于:这个常数会漫进那些本该更暗的折缝、接触点与凹陷——因为周围的几何挡住了大部分天空。环境光遮蔽就是那个缺失的因子——对每个点,问它上方半球有多大比例是开阔的,又有多少被邻近表面遮蔽。两面墙相交的角落是被遮蔽的,故应更暗;一块暴露的平面则完全开阔。
Computing true occlusion means casting many rays over the hemisphere per point — again, too expensive per frame. SSAO (screen-space ambient occlusion) is the classic approximate trick: it never touches the real geometry. It reads the depth buffer — which the rasterizer already produced — and, around each pixel, samples a few nearby depth values. If many neighbors are closer to the camera than the surface here, this pixel sits in a pocket surrounded by geometry, so darken it; if neighbors fall away, it is open, so leave it bright. It is a purely 2.5-D estimate from data already on screen — which is exactly why it is cheap, and exactly why it has the same blind spot as everything screen-space (§5): it can only account for occluders the camera can see.
计算真实遮蔽意味着对每个点在半球上投出许多光线——同样,逐帧太贵。SSAO(屏幕空间环境光遮蔽)是经典的近似技巧:它根本不碰真实几何。它读取深度缓冲——那是光栅器已经产出的——在每个像素周围采样几个邻近的深度值。若许多邻居比此处表面更靠近相机,说明这个像素坐在被几何环绕的凹坑里,就把它压暗;若邻居纷纷退远,它就是开阔的,保持明亮。这是一个纯粹 2.5 维的、从屏幕已有数据得来的估计——这正是它便宜的原因,也正是它和一切屏幕空间方法(§5)有同样盲点的原因:它只能顾及相机看得见的遮挡物。
4 · Precomputed indirect light — radiosity, lightmaps, and probes预计算间接光——辐射度、光照贴图与探针
The hardest term is the recursive one: light that bounces off other surfaces before reaching x — indirect illumination, the soft color-bleeding fill that makes a scene look real. If the geometry and lights do not move, we can pay for it once, offline, and read the result back for free every frame. That is the precompute route, and it has a lineage.
最难的项是那个递归项:在到达 x 之前先从别的表面反弹过的光——间接光照,那种柔和的、渗色的补光,正是它让场景显得真实。如果几何与光源都不动,我们就可以一次性、离线地为它付账,之后每一帧免费回读结果。这就是预计算路线,它有一条谱系。
Radiosity is the classical method for the diffuse case. Break every surface into small patches; the light leaving patch i is its emission plus the light it receives from every other patch j, weighted by a form factor Fij that encodes how much of j's hemisphere i occupies (their mutual geometry — size, distance, orientation). That is a big linear system of patch radiosities; solve it once and you have full diffuse interreflection — soft, physically-based fill light. It is view-independent (diffuse light looks the same from every angle), which is exactly what makes the solution reusable.
辐射度(radiosity)是处理漫反射情形的经典方法。把每个表面拆成小面片;离开面片 i 的光,等于它自身的发射加上它从其他每个面片 j 收到的光,后者按一个形状因子 Fij 加权——该因子编码了 i 占据 j 半球的比例(它们相互的几何:大小、距离、朝向)。这是一个关于各面片辐射度的大型线性系统;解一次,你就得到完整的漫反射互反射——柔和的、基于物理的补光。它与视角无关(漫射光从任何角度看都一样),而这正是解可以复用的原因。
Lightmaps are how that precomputed result ships in a game. Bake the indirect (and often the static direct) illumination into a texture unwrapped over the static geometry; at runtime, shading a wall is just a texture fetch — nearly free, and gorgeous. The iron catch is in the word static: a lightmap is correct only for the geometry and lights it was baked with. Move a wall, open a door, or swing a light and the baked shadows and bounce lie. And crucially, lightmaps live on static surfaces — they say nothing about how to light a moving character walking through that baked room.
光照贴图(lightmaps)是那份预计算结果在游戏里的交付形式。把间接光(常常还有静态直接光)烘焙进一张在静态几何上展开的纹理;运行时,给一面墙着色只是一次纹理取样——几乎免费,而且极美。铁一般的坑就在静态二字:光照贴图只对烘焙时所用的几何与光源才正确。挪一面墙、开一扇门、或转动一盏灯,烘焙好的阴影与反弹就都在撒谎。而且关键在于,光照贴图长在静态表面上——它对如何照亮一个穿过那间烘焙房间的移动角色只字未提。
That gap is filled by irradiance probes (light probes). Scatter sample points through the volume of the scene; at each probe, precompute the light arriving from every direction and store it compactly. A dynamic object then reads the nearest probes and interpolates — so a character darkens as it walks into shade and picks up a red glow beside a red wall, all without per-frame bounce computation. The compact storage is the elegant part: incoming light over a sphere is a smooth low-frequency function, so we expand it in spherical harmonics (SH) and keep only the first few coefficients (often just 9, for the diffuse "L2" band). Those few numbers reconstruct the soft directional irradiance well enough for diffuse shading. Probes are precompute for the light field in space; lightmaps are precompute for it on surfaces — the pair covers static rooms and the dynamic actors moving through them.
这个空缺由辐照度探针(光照探针)填补。在场景体积里撒下采样点;在每个探针处,预计算从各个方向到来的光并紧凑地存下。动态物体随后读取最近的几个探针并插值——于是角色走进阴影会变暗、走到红墙边会染上一层红晕,全程无需逐帧计算反弹。紧凑存储是其精巧之处:球面上的入射光是一个平滑的低频函数,所以我们用球谐(SH)把它展开,只保留前几个系数(漫反射常常只用 9 个,即“L2”band)。这寥寥几个数就能重建出足够好的、柔和的方向性辐照度,用于漫反射着色。探针是对空间中光场的预计算;光照贴图是对表面上光场的预计算——二者搭配,覆盖了静态房间和穿行其中的动态角色。
| Technique | Buys which term | Verb | Handles dynamic? |
|---|---|---|---|
| Shadow map | direct-light visibility | precompute (per frame) | yes (rebuilt each frame) |
| SSAO | ambient occlusion | approximate (screen-space) | yes, but on-screen only |
| Lightmap | indirect on surfaces | precompute (offline bake) | no — static geometry & lights |
| Light probe + SH | indirect on moving objects | precompute (offline bake) | dynamic objects, static lights |
| SSR | glossy/mirror reflection | approximate (screen-space) | yes, but on-screen only |
| 技术 | 买下哪一项 | 动词 | 能处理动态吗 |
|---|---|---|---|
| 阴影贴图 | 直接光可见性 | 预计算(每帧) | 能(每帧重建) |
| SSAO | 环境光遮蔽 | 近似(屏幕空间) | 能,但仅限屏幕上 |
| 光照贴图 | 表面上的间接光 | 预计算(离线烘焙) | 否——静态几何与光源 |
| 光照探针 + SH | 移动物体上的间接光 | 预计算(离线烘焙) | 动态物体,静态光源 |
| SSR | 光泽/镜面反射 | 近似(屏幕空间) | 能,但仅限屏幕上 |
5 · Screen-space, and the new era屏幕空间,以及新纪元
SSR (screen-space reflections) fakes the mirror/glossy term the same way SSAO fakes occlusion: reuse the frame you already rendered. From a reflective pixel, reflect the view ray about the surface normal and march that ray through the depth buffer, stepping until it crosses a stored depth — a hit. Sample the already-shaded color there and blend it in as the reflection. When it works, you get gorgeous wet floors and glossy tabletops for the price of a screen-space raymarch, no extra scene traversal.
SSR(屏幕空间反射)伪造镜面/光泽项的方式,和 SSAO 伪造遮蔽如出一辙:复用你已经渲染好的这一帧。从一个反射像素出发,把视线光线关于表面法线反射,然后让那条光线在深度缓冲里步进,一步步走到它越过某个存储深度处——即一次命中。取那里已经着色好的颜色,作为反射混合进来。当它奏效时,你能以一次屏幕空间光线步进的代价换来极美的湿地板和光泽桌面,无需额外的场景遍历。
SSR, SSAO, and every screen-space method share one fundamental limitation: they can only use what is currently on screen. The depth buffer holds the visible surfaces and nothing else — so a reflection of the sky, of an object just off the edge of the frame, or of a surface hidden behind the reflector simply has no data to draw from. SSR characteristically fails at screen edges (reflections fade out) and cannot reflect anything the camera itself cannot see. It approximates the reflection integral using a 2-D shadow of the 3-D world; whatever that shadow omits, the reflection omits too.
SSR、SSAO 以及每一种屏幕空间方法都共享一个根本局限:它们只能用当前屏幕上有的东西。深度缓冲只保存可见表面、别无其他——所以对天空、对刚好落在画面边缘之外的物体、或对藏在反射体背后的表面的反射,根本没有数据可取。SSR 的典型失败发生在屏幕边缘(反射逐渐淡出),并且无法反射任何相机自己看不到的东西。它用三维世界的一张二维"影子"来近似反射积分;那张影子漏掉什么,反射就跟着漏掉什么。
This blind spot is precisely what the new era removes. Hardware ray tracing (lesson 10's BVH, now in silicon) lets a real-time renderer shoot a modest number of true rays per pixel into the actual scene — off-screen geometry included — for shadows, reflections, and one or two bounces of GI. The catch returns us to §1: a modest ray count is noisy. The unlock is pairing it with two of our three verbs — amortize across frames (reuse and accumulate samples over time) and ML denoising (a neural network trained to reconstruct a clean image from a sparse, noisy one). Schemes like DDGI (dynamic diffuse GI) go further: keep the light-probe idea from §4 but update the probes every frame with a few traced rays each, so the baked indirect light of lightmaps becomes fully dynamic — lights and geometry can move. This is the direct bridge to lesson 15, where real-time and offline rendering, split back in lesson 01, finally begin to converge.
这个盲点,正是新纪元所消除的。硬件光线追踪(第 10 课的 BVH,如今做进了芯片)让实时渲染器能向真实场景——包括屏幕外的几何——每像素射出为数不多的真光线,用于阴影、反射、以及一两次反弹的 GI。而问题又把我们带回 §1:光线数不多就有噪声。破局之道是把它与我们三个动词中的两个配对——跨帧摊销(随时间复用并累积样本)与 ML 去噪(一个被训练来从稀疏、含噪的图重建出干净图的神经网络)。像 DDGI(动态漫反射 GI) 这样的方案更进一步:保留 §4 的光照探针思想,但每帧用少量追踪光线更新探针,于是光照贴图那份烘焙好的间接光变得完全动态——光源与几何都能移动。这正是通往第 15 课的桥,在那里,第 01 课分开的实时与离线渲染,终于开始融合。
Where this points next接下来指向何处
We now have the real-time toolbox as a coherent set rather than a bag of tricks: techniques choose where to precompute, approximate, sample, reuse, and reconstruct. A high-sample reference path tracer can be an engineering reference under the same scene, material, spectral, and numerical model; it is not physical reality itself. But everything so far has assumed a frozen scene — one instant, held still while we shade it. Real content moves: characters walk, cameras pan, cloth billows. Lesson 13 leaves shading for animation and motion — how positions change over time, interpolation and easing, skeletal rigs and skinning, and why motion introduces its own sampling problem in time (the temporal cousin of the aliasing from lesson 06).
现在我们把实时工具箱看成一套连贯的体系、而非一袋子技巧:各种技术选择在哪里预计算、近似、采样、复用和重建。在相同场景、材质、光谱和数值模型下,高采样参考路径追踪器可以作为工程基准;它并不等于物理现实本身。但到目前为止,一切都假设场景是冻结的——一个瞬间,被定住让我们着色。真实内容会动:角色行走、相机横摇、布料翻卷。第 13 课离开着色,转向动画与运动——位置如何随时间变化、插值与缓动、骨骼绑定与蒙皮,以及为什么运动会在时间上引入它自己的采样问题(第 06 课走样在时间上的表亲)。
Typical real-time budgets cannot drive a raw path estimator to clean offline error each frame. For IID finite-variance samples, 1/√N is the standard-error baseline; practical systems therefore combine sparse samples with precomputation, approximation, and amortization, plus spatial reuse and reconstruction. Shadow maps cache the light's visibility as projected depth from the light's view, then test d(x) ≤ zmap + bias; too little bias gives acne, too much gives peter-panning — PCF filters edges and cascades allocate resolution by range. SSAO approximates ambient occlusion from the depth buffer. Lightmaps bake indirect light onto static surfaces; light probes + spherical harmonics store a low-frequency field for dynamic objects. SSR marches the visible depth buffer and therefore misses off-screen information. Hardware ray tracing + ML denoising + DDGI spend more budget on dynamic transport while accepting their own bias, variance, and temporal-failure contracts.
典型实时预算无法在每一帧把原始路径估计器压到干净离线图像的误差水平。对方差有限的 IID 样本,1/√N 是标准误差基线;因此实践系统把稀疏样本与预计算、近似、摊销结合,并加入空间复用与重建。阴影贴图从光源视角把可见性缓存为投影深度,再测试 d(x) ≤ zmap + bias;偏置太小产生痤疮,太大产生彼得潘——PCF 过滤边缘,级联按距离分配分辨率。SSAO 从深度缓冲近似环境光遮蔽。光照贴图把间接光烘焙到静态表面上;光照探针 + 球谐存储供动态物体读取的低频场。SSR 沿可见深度缓冲步进,因此会漏掉屏外信息。硬件光追 + ML 去噪 + DDGI把更多预算用于动态光传输,同时也接受各自的偏差、方差与时序失效契约。
Interview prompts面试题
- Why can't a real-time renderer use the same raw sampling budget as an offline one? (§1 — for IID finite-variance samples, standard error follows the 1/√N baseline; hundreds–thousands of paths per pixel do not fit typical ~16 ms budgets, so real-time systems use sparse sampling, precomputation, approximation, reuse, and reconstruction.) 为什么实时渲染器不能使用与离线渲染相同的原始采样预算?(§1 — 对方差有限的 IID 样本,标准误差遵循 1/√N 基线;每像素数百至数千条路径塞不进典型的 ~16 毫秒 预算,因此实时系统采用稀疏采样、预计算、近似、复用与重建。)
- Describe the shadow-mapping algorithm end to end. (§2 — pass 1: rasterize depth from the light's viewpoint into a shadow map; pass 2: for each shaded point, project into light space and compare its true depth d(x) to the stored texel depth + bias; shadowed if it is meaningfully farther.) 从头到尾描述阴影贴图算法。(§2 — 第一遍:从光源视角把深度光栅化进阴影贴图;第二遍:对每个着色点投影到光源空间,把它真实深度 d(x) 与存储的纹素深度 + 偏置 相比;若明显更远则在阴影里。)
- What are shadow acne and peter-panning, and how does the bias trade between them? (§2 — acne is stripes of self-shadow from a lit surface reading d > zmap due to depth quantization; too much bias overshoots and lifts the shadow off the contact point, detaching it — peter-panning; bias is the single knob between the two.) 什么是阴影痤疮与彼得潘,偏置如何在二者间权衡?(§2 — 痤疮是被照亮表面因深度量化读出 d > zmap 而产生的条纹状自阴影;偏置过大则矫枉过正,把阴影从接触点抬起、使其脱开——即彼得潘;偏置是二者之间唯一的旋钮。)
- What does PCF do, and why do we want it? (§2 — percentage-closer filtering samples several neighboring shadow-map texels, runs the depth test on each, and averages pass/fail to produce a soft, anti-aliased shadow edge instead of a jagged binary one.) PCF 做什么,我们为什么要它?(§2 — 百分比渐近滤波对邻近的几个阴影贴图纹素采样、对每个都跑深度测试、再把通过/未通过平均,从而得到柔和的、抗锯齿的阴影边缘,而非锯齿状的非黑即白。)
- Lightmaps vs light probes — when do you reach for each? (§4 — lightmaps bake indirect light onto static surfaces and are correct only for static geometry & lights; probes bake incoming light into points in space so dynamic objects can interpolate it — static walls use lightmaps, moving characters use probes.) 光照贴图 vs 光照探针——各自在什么时候用?(§4 — 光照贴图把间接光烘焙到静态表面,只对静态几何与光源正确;探针把入射光烘焙到空间中的点,好让动态物体插值——静态墙面用光照贴图,移动角色用探针。)
- Why store probe irradiance in spherical harmonics, and what is SSR's fundamental limitation? (§4–5 — incoming light over a sphere is smooth/low-frequency, so a few SH coefficients (often 9) reconstruct diffuse irradiance compactly; SSR can only reflect what is on screen — the depth buffer holds visible surfaces only, so off-screen and hidden geometry, and screen edges, have no data.) 为什么把探针辐照度存成球谐,SSR 的根本局限又是什么?(§4–5 — 球面上的入射光平滑、低频,故寥寥几个 SH 系数(常为 9 个)就能紧凑重建漫反射辐照度;SSR 只能反射屏幕上有的东西——深度缓冲只存可见表面,故屏幕外、被遮挡的几何以及屏幕边缘都没有数据。)