想象你要拍一张漆黑森林的夜景照片。如果只靠相机那一侧的灯光,你永远拍不出树荫下、岩石背面的细腻阴影——因为那些地方的光,是从四面八方“偷偷溜达”过来的间接光。聪明的做法是:先放飞成千上万只萤火虫,让它们落满森林的每个角落,记录下“哪里亮、哪里暗”的分布图;然后你端着相机,目光落在一片叶子上时,低头问问附近落定的萤火虫:“你们这儿亮不亮?”——用它们的密度来估算亮度。这就是光子映射(Photon Mapping)的核心思路:先布好光场,再查询光场。它把“光从哪来”和“光到哪去”拆成两个独立阶段,轻轻松松解决了纯光线追踪望而却步的焦散与全局光照难题。今天,虽然它已被更通用的路径追踪取代,但“先勘探、再问路”的思想,仍像一座看不见的地基,托举着现代渲染技术的天空。
学习光子映射,你将理解“预计算分布 + 在线查询”这一跨越渲染与分布式系统的经典模式——这是图形学工程师理解现代光照方案、系统架构师设计缓存策略的共同思维底座。
可视化演示
展示系统处理流水线、实时性能指标曲线及多方案对比分析,包含数据流转、吞吐延迟监控与方案评估。
本节配有交互动效(进入视口后自动加载,约 3KB)。
系统可视化 处理流程:输入→处理→模型→输出 性能监控:实时指标 P=L×T
算法诞生背景
深夜的森林摄影师遇到的第一道坎是:相机只能从一个点看出去,而照亮树叶背面的光,是从无数方向经过无数次弹跳才抵达的。纯光线追踪的做法是“一根光线走到底”——眼睛看向某个像素,光线打进场景,弹一次、两次……但如果要覆盖所有可能的间接光路径,光线的数量会像爆炸一样增长,等算完时太阳都升起来了。更要命的是焦散:一束穿过玻璃水杯的光,会在桌面上聚成一道刺眼的亮纹。这种聚集效果需要极其精确的光路统计,纯光线追踪要么花天文时间,要么干脆算不出来。
要让电脑理解“总亮度从哪儿来”,数学家们写下了一本总账本——渲染方程。它说:一个点发出的光,等于它自己发的光,加上所有从四面八方照过来的光,经过材质反射后叠加的结果。这个方程本身客观精确,难的是如何高效地“查账”。
渲染方程本身没有错,错的是“一根根光线硬追”的执行方式。于是 1995 年,Henrik Wann Jensen 提出了光子映射——与其从相机这边孤军奋战,不如先让“光”自己出发,把整个森林的光照分布提前摸清。这正是“先侦察、再进攻”的破局智慧。
- 左侧总输出亮度$L(x, \omega_o)$ 表示从表面点 x、沿观察方向 ω_o 射出的总辐射亮度——也就是摄影师最终看到的颜色。
- 自身发光项$L_e(x, \omega_o)$ 是表面上点 x 自己发出的光(只有光源材质才有这一项),像黑暗中自带的荧光。
- 入射光积分$\int_\Omega f_r(x, \omega_i, \omega_o) \, L_i(x, \omega_i) \cos\theta_i \, d\omega_i$ 把来自半球方向 Ω 上每一条入射光线的贡献累加,乘上材质反射函数和夹角余弦,再对所有方向求总和。
双向发射思想
放萤火虫的妙处,在于把一个大难题拆成了两个小步骤。第一,先放飞萤火虫:让成千上万只“光子”从光源出发,飞向森林的各个角落,落在树叶、岩石、地面,记录下它们的位置和能量。第二,再拿着地图问路:摄影师端着相机,沿着视线方向射出一根光线,当它命中某片叶子时,只需查看那附近“萤火虫的密度”,就能得知这个地方的间接光照。两个方向——光从光源来,视线从相机去——在场景表面“会师”,信息的拼图就完整了。
这种“双向”设计解决了一个致命痛点:纯光线追踪中,每个像素都需要从光源重新走一遍漫长的间接光照路径,代价极高。而光子映射中的光子图是一次性的“公共财富”——光源分布不变时,无论相机怎么转、镜头怎么换,这张图都能反复使用。摄影师的构图可以随意调整,而不用惊动任何一只萤火虫。
这个“先建图、后查询”的结构,是整个光子映射的灵魂。它告诉我们:很多时候,与其在每次提问时从头计算世界,不如提前把世界整理成一份索引——这正是从摄影棚到数据库都通用的工程哲学。
- 集合 $\mathcal{N}_k(x)$表示查询点 x 周围最近的 k 个光子组成的集合——就像你回头看到的最近一圈萤火虫。
- 取最大值 $\max$在这 k 个光子中,找到距离最远的那一个,它的距离就是查询圆的半径。
- 欧氏距离 $\| x - x_p \|$查询点 x 与光子位置 x_p 之间的直线距离,衡量“这只萤火虫离我多远”。
光子发射追踪
释放萤火虫不是乱撒一气。经验丰富的向导知道:森林中更亮的灯源,应该放出更多的萤火虫去勘探。光子映射的发射策略同样遵循“多亮多发”的原则——光源的功率越大,分配给它的光子数就越多。每一只萤火虫(光子)携带一份均等的能量,从光源出发踏上旅程。
光子打到物体表面后,命运则由“光子轮盘”决定:大多数光子被表面吸收,结束旅程;一部分被反射,继续飞行;还有一部分被折射,穿入透明物体内部。每当我光子被迫停下,它就将自己的位置、入射方向与剩余能量记入光子图——萤火虫就这样一盏一盏地在森林里安了家。为了模拟随机过程,算法使用俄罗斯轮盘赌来决定追踪的终止,既保证了能量守恒,又避免了无止境地弹跳。
光子追踪的质量,直接决定光子图的“勘探精度”。光子越多,森林的明暗地图就越细腻;但每多一只萤火虫,都要付出存储与计算的代价。如何把这些海量光子组织成高效查询的索引?这就轮到下一节的数据结构登场了。
- 分子 $P_{\text{source}}$光源的总功率,代表这片森林里所有光明的总和。
- 分母 $N_{\text{photon}}$发射到场景中的光子总数,即萤火虫的只数。
- 相除得单光子能量$E_p$ 是每只萤火虫携带的能量,数值上等于功率除以数量——平均主义分配,保证总能量守恒。
KD树光子图
几千只萤火虫的落点记录堆在笔记本上,摄影师不可能每次问路都从头翻到尾——他需要一本“花名册”:按位置分区登记,快速定位。光子映射中的这本花名册,就是 KD 树。KD 树是一种把空间反复二分的数据结构:先挑出一个维度(比如 x 方向),找到所有光子的中位数位置,把空间切成一左一右两半;再在左右子空间中换下一个维度(y 方向)继续切分,如此交替,直到每个区域的光子数量足够少。最终形成的是一棵平衡二叉树。
当摄影师想知道某个叶子附近有多少光子时,他从树的根部出发,根据查询点的坐标,像走迷宫一样快速步入相关分支——那些明显距离过远的子树被整棵剪掉,不再细看。这样,“这台机器周围的所有萤火虫”可以在对数级别的时间里找到。
有了 KD 树这本高效花名册,光子映射的“查询”阶段才真正拥有了实用价值。摄影师的目光落向任意一片叶子,都能立刻知道周围住着多少只萤火虫——这正是下一节“光线查询渲染”的前奏。
- $\log n$ 导航代价从 KD 树根节点出发,每层比较一次坐标就能排除一半空间,所以深度是 log_2 n。
- $+k$ 收集代价找到目标区域后,还需要把圈内 k 个光子逐一装入结果集,这部分代价和 k 成正比。
- 整体复杂度$O(\log n + k)$ 表示总耗时随光子总量增长极其缓慢——花名册翻得再厚,找人也只需翻几页。
光线查询渲染
摄影师终于举起了相机。他沿着视线射出一根主光线,光线穿过镜头、飞进森林,撞上某片叶子——这个交点,就是他要评估亮度的目标。此时他低头看向那本花名册,以交点为圆心、第 k 近光子距离为半径画出一个查询球,球内所有萤火虫的位置与能量被瞬间读取出来。接下来的问题只有一个:这些萤火虫到底说明了多亮?
答案藏在“密度”里。查询球内的光子能量总和,除以球体面积,得到单位面积上的光照贡献——这就是辐射度估计。每个光子携带的入射方向与能量,还要经过材质反射函数的加权,才能正确影响最终颜色。于是我们得到光子映射最核心的计算公式。它不再试图精确计算渲染方程的积分,而是用“局部光子密度”这个统计量来近似它——这就是典型的“用抽样代替积分”。
辐射度估计是两阶段思想的最终交汇点:光源发射的光子图在此被相机光线消费,两边的信息合流成像素的颜色。摄影师问萤火虫“亮不亮”,得到的不再是模糊的主观感受,而是一个有物理单位的客观读数。
- 求和符号 $\sum_{p=1}^{n}$遍历查询球内全部 n 只光子,逐一累加它们的贡献——每只萤火虫都要发言。
- 材质反射函数 $f_r(x, \omega, \omega_p)$描述表面点 x 的材质如何把来自 ω_p 方向的光反射到观察方向 ω——粗糙木头与光滑玻璃的翻译方式截然不同。
- 光子能量 $\Phi_p$第 p 只光子的能量值,越亮的萤火虫对最终亮度的贡献越大。
- 分母 $\pi r_k^2$查询圆的面积。球的半径越大,面积越大,同样的光子数被摊薄,亮度估算就越低——这就是“密度”的含义。
焦散间接光照
有一些场景会让摄影师忍不住感叹“大自然真会打光”:阳光穿过水晶球,在桌面上投下一道漩涡状的亮斑;泳池底的水波纹光影,像一张金色渔网。这些就是焦散——光经过镜面反射或折射后,像凸透镜聚焦一样在某个区域高度聚集。在光子映射出现之前,焦散是纯光线追踪的噩梦,因为聚光的光路极其狭窄,普通光线采样十有八九会错过它。
但对于光子映射,焦散成了“主场优势”:当萤火虫从光源出发被水面折射后,它们会像被风吹进河道一样,挤进那片波光区域,导致局部光子密度暴涨。查询时,圆内光子数量骤然增多,辐射度估计自然给出刺眼的高亮度——焦散亮斑无需任何特殊处理,就这样被轻轻松松“统计”了出来。类似地,漫反射表面的间接光、光泽表面的模糊反射,也都由光子密度和方向分布统一刻画。
焦散与间接光的自然涌现,让光子映射成为 2000 年代电影特效与建筑渲染的宠儿。珠宝广告里那句“如星光般璀璨”的真实感,正是来自这只看不见的“萤火虫统计师”。
- 分子 $n(x)$查询圆内的光子数量——在焦散区域,这个数会突然飙高。
- 分母 $\pi r_k^2(x)$查询圆的面积。光子越多、圆越小,密度越大。
- 密度比值 $\rho(x)$单位面积上的光子数,是亮度估算的直接依据。
局限与演进
再美丽的萤火虫森林也有它的烦恼。首先,几十万到上百万光子的存储和建立 KD 树的过程,要把整座森林的地图刻在内存里——对于当年的计算机,这是一笔不小的开销。其次,辐射度估计是有偏的:如果查询半径选得太小,圆内光子稀疏,亮度会闪烁出明显的噪声;如果半径选得太大,又把附近不同材质的光照糊成一团,丢失细节。你永远在“颗粒感”和“模糊感”之间左右为难。
研究者们尝试用渐进光子映射来修复:先撒少量光子,算出粗糙结果,然后随着渲染推进不断补充光子,并逐步缩小查询半径。这就好像先让一小群萤火虫粗略勘探,再派大部队加密补点,地图越画越精细。然而,2000 年代中期,路径追踪凭借更简洁的数学和更可扩展的硬件逐渐崛起,最终在渲染领域完成了统一。光子映射作为一种独立算法退居幕后,但它揭示的双向思想与密度估计思路,却在新方法中换了马甲继续发光。
这个故事给我们的启示是:技术会被迭代,但“用密度近似光照、用预计算换实时”的设计思想,却像是树根一样扎进了更深的土壤。
- 极限符号 $\lim_{N \to \infty}$代表光子数量不断增加、直至无穷的极限过程。
- 估计值 $\hat L_N(x)$使用 N 个光子估算出的点 x 的亮度,是带有误差的近似值。
- 真实值 $L(x)$点 x 的物理真实亮度——理论上需要无穷多光子才能精确达到。
思想现代遗产
如果今天你打开一个现代渲染器,几乎找不到名为“Photon Mapping“的按钮。但如果你知道往哪儿看,就会发现它的影子无处不在。双向路径追踪把”从光源出发的光子路径“与”从相机出发的视线路径“按多种方式拼接——这正是光子映射”双向会师“思想的蒙特卡洛升级版。光照贴图与 Light Probe 系统,把”预计算分布、运行时查询”的模式搬到烘焙与实时渲染中:先离线放出百万光子算好贴图,再在游戏运行时极速查询。
更有趣的是,这个模式早已溢出图形学的边界。在分布式系统中,热点缓存机制同样遵循“预言光分布、在线查热点”的逻辑:统计阶段预先分析哪些数据会被高频访问,查询阶段快速命中缓存以避免穿透后端。你甚至可以说,从京东秒杀的流量预热,到 CDN 的节点调度,都藏着那只萤火虫的身影。
从森林摄影到渲染方程,从光子图到分布式热点缓存,光子映射留下的最珍贵遗产,是那句朴素的洞见:世界可以被提前理解,而理解可以被打包复用。
- 分子 $O(N \cdot M)$不做预计算时,M 个像素各自追踪 N 条光路,代价相乘。
- 分母 $O(N + M)$预计算后,N 次发射建图加上 M 次查询,两者相加。
- 整体比值 S速度提升倍数,体现了“一次勘探、万次问路”的杠杆效应。
AI 应用场景
影视广告与产品渲染
阶段:离线光照预计算
解决的问题:珠宝、香水、汽车广告需要极致的焦散与细腻反射,传统逐帧渲染要花数天。光子映射先离线发射数千万光子建立全局光照图,最终渲染时每个像素只需查询附近光子即可获得间接光照,速度提升一个数量级,且效果稳定不闪烁。
具体案例:某国际珠宝品牌拍摄钻石吊坠广告,钻石内部的色散焦散在金属表面形成彩色光斑。渲染团队用光子映射预计算光场,再结合摄影机动画复用同一张光子图,将单帧渲染时间从 40 分钟压到 6 分钟。
建筑可视化室内漫游
阶段:光照贴图烘焙
解决的问题:建筑方案汇报需要设计师在白天、黄昏、夜晚三种灯光下自由切换视角。如果每次移动相机都重新计算全局光照,交互卡顿到无法演示。光子映射把光照预计算为场景各处的光子分布,相机漫游时实时查询,让客户像玩游戏一样“走进”未来的房子。
具体案例:某设计院为大型商场项目生成室内漫游视频,用光子映射预计算太阳光与筒灯的面光源分布,所有墙面、地面、家具的间接光一次成型,最终在普通笔记本上也能 60 帧流畅展示。
分布式系统的热点缓存
阶段:离线统计与在线查询
解决的问题:大型电商大促时,少量爆款商品会吸引绝大多数流量。缓存系统需要知道“哪里是光聚集的焦散区”,才能提前预热节点、避免数据库被压垮。光子映射“预计算分布+在线查询”的思想被抽象为热点分析服务:离线统计热key分布,在线用近似最近邻查询快速定位流量热点。
具体案例:某电商平台在大促前夜运行热点预测任务,将历史流量视为“光子”构建热点分布图,网关收到请求时用 KD 树快速查询附近热点节点并自动扩容,命中率达 93%,数据库负载降低了一半。
Python 演示
import mathimport random class PhotonMapper: """二维极简光子映射: 阶段一发射光子建光子图, 阶段二查询亮度。""" def __init__(self, width=45, height=18): self.width = width self.height = height self.light_x = 22 self.light_y = 1 self.photons = [] # 光子图: 每个元素为 (x, y, power) self.grid = [[0] * width for _ in range(height)] self.query_count = 0 # 统计查询次数 def emit_photons(self, num=3000): """阶段一: 从光源向下撒光子, 圆形障碍物吸收光子, 其余落在地面。""" random.seed(7) for _ in range(num): x, y = self.light_x, self.light_y angle = random.uniform(-0.55, 0.55) # 近似朝下扩散 vx = math.sin(angle) vy = 1.0 for _s in range(200): nx = x + vx ny = y + vy if (nx - 15) ** 2 + (ny - 9) ** 2 < 3.0: # 圆形障碍物吸收 break if nx < 1 or nx >= self.width - 1 or ny >= self.height - 1: if ny >= self.height - 1 and 0 < nx < self.width: self.photons.append((int(nx), self.height - 1, 1.0)) self.grid[self.height - 1][int(nx)] += 1 break x, y = nx, ny def query(self, x, y, k=8): """阶段二: 找距离最近的 k 个光子估算亮度。""" self.query_count += 1 dists = [] for px, py, power in self.photons: dists.append((math.hypot(px - x, py - y), power)) dists.sort(key=lambda item: item[0]) if not dists: return 0.0 nearest = dists[:k] radius = nearest[-1][0] if radius < 0.5: radius = 0.5 density = sum(p for _d, p in nearest) / (math.pi * radius * radius) return min(density, 1.0) def render(self): """输出 ASCII 亮度热力图, 越亮字符越密。""" chars = " .:+*#%&@" rows = [] for yy in range(self.height): line = "" for xx in range(self.width): value = self.query(xx, yy, k=8) idx = min(int(value * 18), len(chars) - 1) line += chars[idx] rows.append(line) return "\n".join(rows) if __name__ == "__main__": pm = PhotonMapper() pm.emit_photons(4000) print("光子图容量:", len(pm.photons)) print(pm.render()) print("总查询次数:", pm.query_count)
self.photons.append((int(nx), self.height - 1, 1.0))光子落在地面时,把位置和能量存入光子图,这是“萤火虫安家”的一步。self.grid[self.height - 1][int(nx)] += 1用网格统计同位置光子数,方便后续验证密度分布。def query(self, x, y, k=8)第二阶段核心:找到距离查询点最近的 k 个光子,即“问附近的萤火虫”。dists.sort(key=lambda item: item[0])按距离排序后截取前 k 个,模拟 KD 树最近邻查询的逻辑。density = sum(p for _d, p in nearest) / (math.pi * radius * radius)辐射度估计:圆内光子总能量除以圆面积,密度越大越亮。value = self.query(xx, yy, k=8)对热力图上每个像素点执行查询,生成整张亮度地图。
常见误区
误区我以为光子映射就是“从相机发射光子到场景里”,毕竟名字里带“光线”,而且我们常说“光线追踪是从眼睛出发的”,光子应该也一样。
正解恰恰相反,光子映射中“光子”特指从光源发射的粒子。它效仿物理世界:光源发出光子,打在场景表面留下能量分布;而相机那边发出的叫“视线”。两只队伍从两端出发,在表面上会师。可以想象:萤火虫从灯的方向飞出,摄影师的目光从眼睛方向看来,两者在树叶上相遇。
为何常见:因为“光线追踪从相机出发”先入为主,学习者容易把“光子”和“光线”混为一谈,忽略了光子映射的“双向”设计正是它的创新点。
误区我一直以为光子图就是渲染好的照片——光子落在哪,哪个像素就亮,最后输出一张完整图像。
正解光子图保存的是一份“场数据”:每个光子的位置、方向和能量,是三维空间中的一个分布集合,而不是二维图像。它像森林萤火虫的分布地图,本身不是照片,只有配合相机视线查询时,才被“读取”成亮度值。换一个相机角度,同一张光子图还能再生成一张全新的照片。
为何常见:人眼习惯把“存储的东西”和“看到的结果”划等号,忽略了光子图作为中间表示的复用潜力。
误区只要把光子数调到几千万,渲染就一定又亮又平滑,问题全解决。
正解光子越多,确实能降低噪声,但也带来两个代价:存储和 KD 树构建的开销线性增长;且当查询半径固定时,过密的光子会浪费计算资源。更重要的是,查询半径 r 的选择与光子数量必须匹配:光子少但半径大,会模糊细节;光子多但半径小,仍可能出现局部空洞。这是在调“颗粒度”与“清晰度”的平衡,不是单一变量游戏。
为何常见:人们习惯认为“样本越多越好”,忽略了有偏估计算法中半径与数量的耦合关系。
误区焦散不就是物体表面的反光吗?比如金属上的亮点,直接打高光就行,没必要那么大动干戈。
正解金属高光是直接光在光滑表面上的镜像反射,光路只有一条;而焦散是光线经过反射或折射后,在另一个表面重新聚集形成的图案——比如水晶球在桌面上投出的亮纹。它需要统计“多条折射光如何汇聚到一个区域”,这正是光子映射用光子密度轻松捕捉、而纯光线追踪难以采样的原因。
为何常见:视觉上两者都是“亮斑”,初学者容易从外观而非光路机制去归类。
误区现在渲染都用路径追踪,光子映射已经进了历史垃圾堆,学它纯属浪费时间。
正解算法本身确实退居二线,但它的两条核心思想——“双向路径会师”和“预计算分布+在线查询”——是现代渲染与系统设计的公共财富。双向路径追踪是它的数学升级版,光照烘焙、分布式热点缓存也都沿用同一模式。理解它,等于拿到了一把打开后续一大片技术的钥匙。
为何常见:人们容易把“不再主流”等同于“没有价值”,忽略了思想与方法论的传承关系。
面试题
Q1. 光子映射的两阶段中,第一阶段是从哪里出发?
- A.从相机镜头出发向场景发射光线
- B.从场景光源出发向四周发射光子← 正确答案
- C.从屏幕像素出发反向追踪光照
- D.从表面材质出发向光源查找能量
答案:B。光子映射第一阶段是“放萤火虫”——从光源发射光子记录分布;第二阶段才是从相机发视线。选项A和C描述的是光线追踪的单向视角,D则是反向查找,均不符合光子映射的设计。
Q2. 光子图通常用什么数据结构组织以加速最近邻查询?
- A.哈希表散列存储所有光子的能量
- B.链表依次串联所有光子位置
- C.KD树按维度切分空间存储← 正确答案
- D.栈按发射先后顺序保存数据
答案:C。光子映射在三维场景中做最近邻查询,KD树通过交替按维度取中位数切分空间,使查询复杂度降到对数级。哈希表难以高效支持距离查询,链表和栈则只能线性遍历。
Q3. 下面哪种光学现象属于焦散?
- A.烟雾缭绕的柔和漫反射阴影
- B.透明玻璃杯底聚集的亮纹← 正确答案
- C.粗糙墙面均匀的散射光
- D.屏幕表面看到的镜面高光
答案:B。焦散是光经过折射或镜面反射后重新聚集形成的亮斑,玻璃杯底的亮纹正是典型。A和C是漫反射现象,D是直接镜面反射,都不涉及光线的折射聚集。
Q4. 辐射度估计中查询半径 r 取多大合适?
- A.越大越平滑太大容易丢失细节← 正确答案
- B.越小越精细越小必定毫无噪声
- C.与场景光子总数完全无关
- D.固定等于屏幕像素大小的一半
答案:A。查询半径大则圈内光子多、画面平滑但细节模糊;半径小则细节锐利,但光子稀疏处会噪声明显。半径需根据光子密度自适应(如取第 k 近邻距离),与像素无关,故B、C、D均错误。
Q5. 光子映射能解决纯光线追踪的哪些痛点?
- A.间接光照需要海量光线难以收敛← 正确答案
- B.焦散光路狭窄采样次数爆炸← 正确答案
- C.从光源和相机分别出发需要合并
- D.场景中复杂物体网格自动生成
答案:AB。光子映射用“先建光子图再查询”的方式,让间接光照和焦散不需要相机侧每根光线都完整追踪光路。而C描述的是双向思想本身而非痛点,D则是几何建模问题,均与算法动机无关。
Q6. 光子映射中光子撞击表面后一般会如何处理?
- A.删除光子,不再参与计算
- B.记录能量位置并随机反弹吸收← 正确答案
- C.无限反弹直到能量变为无穷
- D.传送回光源循环无限次使用
答案:B。光子撞击表面后,先记录位置与能量,再通过俄罗斯轮盘赌随机决定被吸收、反射还是折射。直接删除会丢失光照信息,无限反弹违反能量守恒,传送回光源则破坏了从光源发射的物理过程。
Q7. 光子映射相比路径追踪存在哪些局限?
- A.需要额外存储海量光子与KD树← 正确答案
- B.查询半径选择不当会带来偏差← 正确答案
- C.完全无法渲染漫反射粗糙表面
- D.无法处理任何镜面反射材质
答案:AB。光子映射的主要短板是存储开销大和辐射度估计有偏(半径过大模糊、过小噪声)。但漫反射正是它的强项,镜面反射也能通过光子追踪处理,故C、D说法错误。
Q8. 光源功率P发射N个光子时单个光子能量是多少?
- A.等于P乘以N总能量随光子数变大
- B.等于P除以N总能量保持不变← 正确答案
- C.等于N除以P光子越多单光子越强
- D.等于P加上N两者直接线性叠加
答案:B。光子映射遵循能量守恒,光源总功率 P 被均分给 N 个光子,所以单光子能量为 P/N,所有光子能量之和恒为 P。其他选项都违反了总能量守恒。
Q9. 光子映射的核心思想用一句话概括是?
- A.先向光源发射光子再向相机发射
- B.先撒光子记录分布再查询估亮度← 正确答案
- C.先构建均匀网格再穷举所有像素
- D.先完全随机采样再平均所有颜色
答案:B。光子映射的精华是“先建图、后查询”:先从光源发射光子记录分布,再从相机发光线查询光子密度估计亮度。A把方向搞反,C的均匀网格和D的纯随机平均都不是光子映射的机制。
Q10. 光子映射的思想对现代技术有哪些正面启发?
- A.双向路径追踪共享双向路径思想← 正确答案
- B.光照贴图复用预计算光照数据← 正确答案
- C.分布式缓存借鉴热点分布查询← 正确答案
- D.神经网络反向传播借鉴该算法
答案:ABC。双向路径追踪是光子映射“会师”思想的数学升级,光照贴图复用预计算光照,分布式缓存的热点统计也延续“预分布+在线查询”模式。反向传播是深度学习优化算法,与光子映射没有继承关系。