想象你是一座巨型快递仓库的主管,仓库里堆着几百万个包裹(三角形),而你手里握着一支手电筒(光线),要在瞬间找出顾客要的那一件。传统做法是把整间仓库按格子逐排扫描过去——这叫光栅化;而光线追踪的做法是:让手电筒直接朝目标方向照过去,光线碰到哪个包裹,答案就水落石出。问题是光线可能在仓库里弹来弹去,每弹一次都要判断撞上了什么,几百万个包裹逐一比效率太低。NVIDIA 的 RTX 显卡为此在芯片里塞进了一群“智能分拣机器人”(RT Core),它们只干一件事:快速判断光线撞没撞上包裹。更妙的是,仓库还配有分区目录(BVH),机器人不必翻遍每个包裹,而是先查区、再查架、最后精确定位到某个包裹。这篇文章带你从零看懂这套“硬件加速分拣系统”:从 RT Core 芯片、BVH 加速结构,到着色器编程与混合渲染,一条完整的技术链路。

岗位关联

掌握光线追踪硬件加速原理,你就能看懂次世代游戏和电影级画面的底层逻辑,建立起图形学核心知识体系,是引擎渲染和 GPU 开发方向技术人员进阶的必修课。

目录
  1. 可视化演示
  2. 光追基础原理
  3. RT Core架构
  4. BVH加速结构
  5. 光追着色器
  6. 光追管线配置
  7. 性能优化策略
  8. 混合渲染技术
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

动态演示RTX光线追踪硬件加速原理的核心机制,通过开始/执行/监控/完成四种模式展示关键概念与交互流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

RTX光线追踪硬件加速原理:RTX光 RTX光线追踪架构总览 RT Core硬件加速单元原理 核心机制可视化 RTX光线追踪硬件加速原理整体架构与关键组件

光追基础原理

想象你站在仓库中央,手里握着一支强光手电筒。你要找的包裹可能藏在任意货架角落,最笨的办法是打开每一扇柜门看一眼——光栅化就是把仓库平面切成方格逐格扫描,不管你需不需要,每个格子都要过一遍。而光线追踪的做法是:直接朝疑似方向照过去,光线碰到什么,答案就水落石出。这个“照”的直觉,几十年前就被图形学家写成了算法,只是当时计算机太慢,直到 RTX 这样的硬件出现才真正走向实时。

光线追踪的核心是“反向思考”:现实中光线从光源出发经过无数次反射进入人眼,顺着算根本不现实。图形学反其道而行之,从相机(人眼)出发,朝每个像素发射光线,让光线“倒放”找到光源。每束光线都要和场景中的三角形求交,找出最近的命中点再计算颜色。一帧画面有几百万像素,意味着几百万束光线同时出发;而每一束光线都要在几百万个三角形中寻找答案。若没有加速结构,这个工作量是几百万乘几百万,任何显卡都扛不住。

要描述一束光线,只需要两个要素:起点和方向。以相机为原点,沿方向向量每前进一段距离,就到达一个新位置。这个“每前进一段距离”用参数 t 表示,t 越大点越远,而求交阶段要找的正是命中那一刻的 t 值。RTX 的硬件加速,本质上就是把求解这个 t 的数学计算铸造成专用电路,让一条光线在纳秒级时间内完成判断。

于是分拣中心的逻辑变得清晰:主管不必弯腰翻每个格子,而是让手电筒沿直线照出去,光线碰到货架边缘的瞬间——t 正好等于到货架的距离——那个点就是要处理的包裹。方向对了、距离对了,剩下的就是材质颜色的事了。

P(t)=O+tD\displaystyle P(t) = O + tD
这条公式描述光线上任意一点的位置:从起点出发,沿着方向走 t 步到哪里。
  1. 光线位置 P(t)光线上任意一点的三维坐标,也常直接简写为 P。
    P(t)P(t)
  2. 起点 O光线的出发点,在光追中通常是相机位置,也可能是反射后的新起点。
    OO
  3. 方向 D单位方向向量,决定光线朝哪个方向前进。
    DD
  4. 距离参数 t光线前进的距离,只有 t≥0 才有物理意义,负数代表光线背后的点。
    t≥0t \ge 0

RT Core架构

手电筒方案听起来很聪明,但主管很快发现瓶颈:一帧画面需要几百万束光同时照射,每束光都要判断命中。纯靠 CPU 或通用 GPU 逐条指令去算,就像让普通搬运工去心算每一束光的抛物线,太慢了。NVIDIA 给出的答案很直接:为“光线求交”专门造一种机器人。于是 RTX 显卡的芯片上多了一块名为 RT Core 的专用电路,它在硬件层面直接执行光线与三角形求交、BVH 节点遍历,一条硬件指令完成过去几十条软件指令才能做完的工作。

RT Core 并不是取代 CUDA 核心,而是与 CUDA 核心分工协作:CUDA 核心负责常规渲染和着色计算,RT Core 专职“光线撞上了什么”。每一束光线需要遍历 BVH 树并测试三角形时,CPU 把光线参数交给 RT Core,RT Core 在极短时间内返回命中结果和距离。在 Ada Lovelace(RTX 40 系)架构中,RT Core 进一步集成了不透明测试和三角形双面检测等增强功能,吞吐量较第一代翻了数倍。

那么“光线撞上三角形”的数学判定长什么样?一个三角形由三个顶点确定,光线命中点的位置可以用三个顶点的加权混合来表达,权重称为重心坐标 (u, v)。求解这个方程,本质是解一个 3 元线性方程组——这在大学线性代数里是很基础的运算,但对硬件来说,把它做成固定电路就意味着极低的延迟和极高的吞吐。

和搬运工逐条心算不同,机器人拿到光线参数后一拍脑袋就算出答案:相当于把“解方程组”这件事从程序员的循环里搬进了硅片。这就是硬件加速的底气——相同的数学,不同的执行方式,速度和功耗自然天差地别。

O+tD=(1−u−v)V0+uV1+vV2\displaystyle O + tD = (1-u-v)V_0 + uV_1 + vV_2
把光线位置公式与三角形重心坐标表达式联立,u、v 是三角形内部的平面坐标,解出 t 即命中距离。
  1. 光线前进量 O+tD方程左边是光线上的点,随着 t 变化而移动。
    O+tDO + tD
  2. 顶点权重 (1-u-v)V₀三角形顶点 V₀ 的贡献,权重由另外两个权重决定。
    (1−u−v)V0(1-u-v)V_0
  3. 顶点贡献 uV₁ 与 vV₂u 和 v 分别控制点向 V₁、V₂ 偏移的程度。
    uV1+vV2uV_1 + vV_2
  4. 三角形内判定当 u≥0、v≥0 且 u+v≤1 时,交点才真正落在三角形内部。
    u≥0, v≥0, u+v≤1u \ge 0,\ v \ge 0,\ u+v \le 1

BVH加速结构

就算有了能快速做求交的机器人,如果每束光线都要对几百万个三角形逐一求交,仓库照样瘫痪。主管想出一个办法:给仓库装一套分区目录——先按区域分,再按货架分,最后精确到某个货格。这套目录就是包围体积层次结构(Bounding Volume Hierarchy,BVH)。它的思想极其朴素:用一个个轴对齐的盒子(AABB)把三角形一层层包起来,形成一棵二叉树。大盒套小盒,小盒里才是真正的三角形。

BVH 的构建流程是自顶而下的递归切分:从包含全部三角形的根节点出发,每次选一个切分轴和切分位置,把三角形分成左右两组,各自生成新的包围盒,直到每组三角形数量足够少(例如 1 到 2 个)就作为叶子节点。切分的质量直接影响遍历效率,业界常用表面积启发式(SAH)来选择切分位置:估算光线穿过左右子包围盒的概率(与其表面积成正比),乘以子树的处理代价,选总代价最小的切法。

遍历时,光线从根节点开始:如果连最大的盒子都没撞上,整棵树直接放弃;如果撞上,就继续检查两个子节点。关键来了——如果光线没有撞上左子盒,那么左子树里所有三角形都不可能被命中,这部分可以整体跳过。这就是“剪枝”:把本来要面对的几百万次测试,砍到一条路径上大约几十次。

这套目录天然适合硬件实现:RT Core 内部直接内置了 BVH 遍历的状态机,遍历时在硬件层完成“进入左子还是右子”的判断。回到仓库比喻:目录先翻到“东北区”,发现手电筒根本照不到那边,整本分册直接合上不看——光线几乎以零成本跳过了一整个区域。

tmin⁡=max⁡(tnearx, tneary, tnearz),tmax⁡=min⁡(tfarx, tfary, tfarz)\displaystyle t_{\min} = \max\left(t_{\mathrm{near}}^x,\ t_{\mathrm{near}}^y,\ t_{\mathrm{near}}^z\right), \quad t_{\max} = \min\left(t_{\mathrm{far}}^x,\ t_{\mathrm{far}}^y,\ t_{\mathrm{far}}^z\right)
这是光线与轴对齐包围盒求交的“Slab 法”:分别计算光线进入和离开盒子三个方向平面的时刻,再综合判定。
  1. 进入时刻 t_near^x光线在 x 方向上第一次碰到盒子边界的参数 t 值。
    tnearxt_{\mathrm{near}}^x
  2. 离开时刻 t_far^x光线在 x 方向上离开盒子边界的参数 t 值。
    tfarxt_{\mathrm{far}}^x
  3. 取最大与最小三个方向都进入后才算真正进入盒子,任何一个方向已离开就算离开。
    max⁡(⋅) 与 min⁡(⋅)\max(\cdot) \ \text{与} \ \min(\cdot)
  4. 相交判定t_min ≤ t_max 且 t_max≥0 表示光线穿过盒子,有相交可能。
    tmin⁡≤tmax⁡t_{\min} \le t_{\max}

光追着色器

包裹终于被机器人锁定了,但真正的活儿才刚刚开始:不同的包裹需要不同的处理方式。有的要仔细贴面单(反射材质),有的要拆开检查内部(折射材质),有的直接拒收不必理会(阴影)。这些“处理流程”在光线追踪中被称为着色器(Shader),它们是运行在 GPU 上的小程序,决定光线命中后像素呈现什么颜色。

DXR(DirectX Raytracing)规范定义了多种着色器类型,最常用的是三种。Ray Generation 着色器是起点,负责生成光线(设定起点和方向)并调用 TraceRay;Closest Hit 着色器在光线命中最近的物体时执行,计算该点的材质颜色、反射方向或阴影贡献;Miss 着色器在光线什么都没碰到时执行,通常返回天空盒颜色或环境光。三者的协作构成了光追计算的主干流程。

着色器与场景对象的关联通过着色器绑定表(Shader Binding Table, SBT)完成。SBT 可以理解为一本查询手册:每个几何体/实例都对应表中的一个条目,条目里记录了该用哪个命中着色器、哪些参数。光线命中三角形后,硬件根据实例和几何体的编号在 SBT 中找到对应条目并执行。在着色器内部,最常用的计算之一是反射方向:给出入射方向和表面法线,按反射定律推出新的光线方向。

如果把仓库比作快递处理中心,Raygen 就是“发件窗口”——决定手电筒往哪照;Closest Hit 是“签收员”——按包裹类型执行处理标准;Miss 则是“查无此件”窗口——光线飞出了仓库,直接返回背景色。三者配合,一套完整的光追流程就跑通了。

R=I−2(I⋅N)N\displaystyle R = I - 2(I \cdot N)N
镜面反射方向公式:入射方向 I 关于表面法线 N 做镜像翻转,得到反射方向 R。
  1. 点积 I·N入射方向在法线方向上的投影长度,反映光线与表面的夹角关系。
    I⋅NI \cdot N
  2. 法线分量 (I·N)N把投影量沿着法线方向重新构成一个向量。
    (I⋅N)N(I \cdot N)N
  3. 反向两倍 -2把法线方向的分量反向并加倍,完成“镜像”操作。
    −2(I⋅N)N-2(I \cdot N)N
  4. 反射方向 R最终得到与法线夹角等于入射角的新方向,用于继续追踪反射光线。
    RR

光追管线配置

分拣中心要正式运转,光有机器人和手册还不够,还得把所有设备按正确顺序连接起来:传送带、扫码枪、分拣闸口,一个都不能少。DXR 管线就是光追程序中的“工程装配图”。在 DXR 框架下,开发者需要依次完成根签名与管线状态对象(PSO)的创建、加速结构的构建、着色器绑定表的配置,最后调用 DispatchRays 才真正发射光线。

加速结构分为两级。底层加速结构(BLAS)由场景中的几何体(三角形坐标和索引)生成,不关心实例位置,只负责把几何数据组织成 BVH;顶层加速结构(TLAS)则由每个实例的变换矩阵和 BLAS 引用组成,负责处理物体在场景中的摆放、移动和旋转。动画场景中 BLAS 通常只在物体变形时重建,而 TLAS 每帧都要根据实例位置重新构建——因为只要有物体移动,实例的变换就变了。

开发时使用 HLSL 编写着色器,通过 TraceRay 指令触发硬件求交。每个 TraceRay 调用都要传入 RayDesc(光线描述:起点、方向、远近裁剪平面)以及光线类型和掩码。调试方面,Nsight Graphics 提供了 DXR 调试工具,可以逐步查看每条光线的命中流程和 SBT 条目解析,还能可视化 BVH 节点访问的热度分布。而 SBT 索引的定位方式直接决定了“哪个包裹走哪条传送带”。

每个包裹走哪条传送带、由哪台机器处理,全靠这个坐标换算到“工位表”上精确匹配。任何一个编号错位,都可能导致包裹(光线)被送到错误的处理站(着色器),屏幕上的画面就会出现诡异的错误。

sbtIndex=instanceId×geometryCount+geometryId\displaystyle \mathrm{sbtIndex} = \mathrm{instanceId} \times \mathrm{geometryCount} + \mathrm{geometryId}
着色器绑定表索引计算:用实例编号乘以实例内几何体数量,再加几何体编号,把二维位置映射成一维表项。
  1. 实例编号 instanceId场景中第几个实例(例如第 3 辆车)。
    instanceId\mathrm{instanceId}
  2. 几何体数量 geometryCount该实例包含多少份几何体(车窗、车身各算一份)。
    geometryCount\mathrm{geometryCount}
  3. 几何体编号 geometryId实例内部第几份几何体。
    geometryId\mathrm{geometryId}
  4. 表项索引 sbtIndex最终指向着色器绑定表的第几行,从而定位着色器。
    sbtIndex\mathrm{sbtIndex}

性能优化策略

系统跑起来了,主管却发现吞吐量不达标:一帧要发几百万根光线,每根还要在仓库里反弹多次。为了让 60 帧每秒成为现实,业界从三个方向下手:少发光线、发短光线、复用光线。降噪(Denoising)对应“少发”——每像素只发 1 到 2 条光线,画面自然布满噪点,但配合降噪器利用邻域信息补全,视觉上几乎无损;分辨率缩放对应“发短”——用较低分辨率渲染光追结果,再通过超分算法重建到目标分辨率;射线复用则把相邻像素的光线批量化合并,提高缓存命中率。

降噪的技术原理可以这样理解:传统光追每像素需要几百条光线平均才能得到光滑画面,而实时光追只发几条,得到的是带噪声的近似。降噪器把这个带有随机误差的图,加上深度、法线、运动向量作为引导,用双边滤波在保留边缘的同时抹掉噪点。时间累积技术还会把前几帧的信息复用过来,让静态区域越积累越干净。NVIDIA 的 DLSS 更进一步:把整个渲染流程放在较低分辨率上执行,再用 AI 重建出高分辨率图像。

这些优化策略最终都要作用到 RT Core 的利用率上。光线发散度大时硬件会做冗余遍历,通过控制光线方向和复用,可以减少不必要的 BVH 访问,让每个 RT Core 的流水线始终饱和。高斯滤波正是降噪器中最常见的权重函数:距离越远的像素参考价值越低,这种平滑恰好模拟了光线的统计规律。

主管不再要求每件包裹都拆开验货,而是抽样检查再按相似性“脑补”没查的部分——省时但细节不丢。降噪器负责脑补,DLSS 负责超分,射线复用负责少跑腿,仓库吞吐量翻了十倍,顾客却感觉服务质量没降。

w(x)=12π σe−x22σ2\displaystyle w(x) = \frac{1}{\sqrt{2\pi}\,\sigma} e^{-\frac{x^2}{2\sigma^2}}
高斯权重公式:像素距离越远,对当前像素的降噪贡献越小,σ 控制平滑范围。
  1. 距离 x当前像素与邻居像素之间的距离。
    xx
  2. 标准差 σ决定平滑范围,σ 越大参与平滑的邻居越多。
    σ\sigma
  3. 指数衰减 e^{-x²/2σ²}距离越远权重越小,呈钟形曲线。
    e−x22σ2e^{-\frac{x^2}{2\sigma^2}}
  4. 归一化系数保证所有权重加起来等于 1,不改变图像整体亮度。
    12π σ\frac{1}{\sqrt{2\pi}\,\sigma}

混合渲染技术

在真实项目中,主管最终发现最聪明的做法不是让所有部门都用上手电筒,而是让传统传送带扫描(光栅化)处理常规件,手电筒(光追)只负责高价值件——反射、阴影、全局光。这种“扫描为主、手电筒为辅”的协作方式,就是混合渲染(Hybrid Rendering)。它是当前实时光追落地的主流形态,也是 NVIDIA RTXGI、RTXDI 等高级光照方案的技术底座。

混合渲染的典型流程是:先用一次光栅化 pass 生成 G-Buffer,把每个像素的深度、法线、基础色、粗糙度等信息存成一张张“底稿”;然后对这些像素做光追计算——通常只计算屏幕空间的反射和阴影;紧接着降噪器对稀疏的光追结果做平滑;最后把光追结果与 G-Buffer 合成输出。因为光追只处理高价值信号而不是整幅画面,负载比纯光追低一个数量级。

混合渲染中,RT Core 的优势被发挥到极致:光追反射只需要计算镜面可见区域,软阴影只用少量采样点加降噪,全局光照通过若干探针光追近似间接光。这样一帧画面中,光栅化贡献了主要细节基础,光追贡献了真实感。最终颜色输出就是简单的线性混合,系数 α 控制两种来源的权重——是想要更真实的光追效果,还是想要更高的帧率。

扫描部门干粗活,手电筒小组抠细节,两者产出合在一起,仓库的吞吐量翻番而精确度不减。这正是现代游戏引擎中“性能与画质兼得”的秘诀——不追求所有效果都用最昂贵的方案,而是把资源花在刀刃上。

Color=α⋅Colorraster+(1−α)⋅Colorray\displaystyle \mathrm{Color} = \alpha \cdot \mathrm{Color}_{\mathrm{raster}} + (1-\alpha) \cdot \mathrm{Color}_{\mathrm{ray}}
最终像素颜色是光栅化颜色与光追颜色的加权混合,α 越大越偏向光栅化。
  1. 光栅化颜色 Color_raster由 G-Buffer 重建出的基础着色结果(漫反射+贴图)。
    Colorraster\mathrm{Color}_{\mathrm{raster}}
  2. 光追颜色 Color_ray光线追踪计算出的反射、阴影、全局光贡献。
    Colorray\mathrm{Color}_{\mathrm{ray}}
  3. 混合系数 α两部分的权重分配,α=1 时完全用光栅化,α=0 时完全用光追。
    α\alpha
  4. 最终像素 Color写入帧缓冲的颜色,决定屏幕上的最终效果。
    Color\mathrm{Color}

AI 应用场景

游戏引擎实时渲染

阶段:图像生成与渲染加速

解决的问题:传统光栅化难以实时呈现真实的反射和软阴影,纯光追在 4K 分辨率下性能又严重不足。混合渲染方案用光栅化铺底、光追补反射和阴影,再叠加 DLSS 降噪与超分,兼顾画质与帧率。

具体案例:在《赛博朋克 2077》开启“光线追踪:超级”模式时,游戏对车漆反射、玻璃折射和霓虹灯阴影实时求交。数千盏动态灯的光线在 BVH 中遍历,RT Core 处理求交后,降噪器用空间和时间累积把每像素 1-2 条光线补成平滑画面。

建筑可视化设计

阶段:实时光照模拟

解决的问题:建筑师需要查看日光在不同时段照射室内的效果。传统烘焙光照一旦修改材质就得重新烘焙,迭代缓慢。基于 DXR 的光追可以实时调整时间、日光角度与材质参数,所见即所得。

具体案例:在 Twinmotion 中拖动日光滑块时,底层管线重建 TLAS 更新实例变换,SBT 保持几何体与材质着色器的绑定关系,每像素仅发射少量光线,GPU 降噪器瞬间计算出柔软的日光漫反射和镜面高光。

电影级虚拟制片

阶段:实时预演与合成

解决的问题:影视拍摄现场使用 LED 虚拟背景时,实拍车辆和道具表面需要反射出背景画面。RTX 光追实时计算背景板在光滑物体上的反射,让镜头不必后期合成即可获得逼真反光。

具体案例:在虚拟制片流程中,混合渲染先用光栅化绘制场景底图,再用光追计算演员面部的环境反射与阴影接触关系,配合背景墙实时互动,解决了以往绿幕合成的反射失真问题。

Python 演示

python84 行
import math class Sphere:    def __init__(self, cx, cy, cz, radius, color):        self.cx, self.cy, self.cz = cx, cy, cz        self.radius = radius        self.color = color     def intersect(self, ox, oy, oz, dx, dy, dz):        # 解光线与球面的二次方程, 返回最近命中距离        lx, ly, lz = ox - self.cx, oy - self.cy, oz - self.cz        a = dx * dx + dy * dy + dz * dz        b = 2 * (lx * dx + ly * dy + lz * dz)        c = lx * lx + ly * ly + lz * lz - self.radius * self.radius        disc = b * b - 4 * a * c        if disc < 0:            return None        t = (-b - math.sqrt(disc)) / (2 * a)        if t < 0:            return None        return t class BVHNode:    def __init__(self, sphere_list):        self.sphere_list = sphere_list        self.left = None        self.right = None        if not sphere_list:            self.bound = (0, 0, 0, 0, 0, 0)            return        self.bound = self._compute_bound(sphere_list)        if len(sphere_list) > 2:            mid = len(sphere_list) // 2            self.left = BVHNode(sphere_list[:mid])            self.right = BVHNode(sphere_list[mid:])     def _compute_bound(self, sphere_list):        xs = [s.cx for s in sphere_list]        ys = [s.cy for s in sphere_list]        zs = [s.cz for s in sphere_list]        r = max(s.radius for s in sphere_list)        return (min(xs) - r, max(xs) + r,                min(ys) - r, max(ys) + r,                min(zs) - r, max(zs) + r)     def hit_bound(self, ox, oy, oz, dx, dy, dz):        x0, x1, y0, y1, z0, z1 = self.bound        t_near, t_far = -1e9, 1e9        for p0, p1, o, d in [(x0, x1, ox, dx), (y0, y1, oy, dy), (z0, z1, oz, dz)]:            if abs(d) < 1e-8:                continue            t0 = (p0 - o) / d            t1 = (p1 - o) / d            t_near = max(t_near, min(t0, t1))            t_far = min(t_far, max(t0, t1))        return t_near <= t_far and t_far >= 0     def traverse(self, ox, oy, oz, dx, dy, dz):        if not self.hit_bound(ox, oy, oz, dx, dy, dz):            return None        if self.left is None and self.right is None:            best_t = None            for s in self.sphere_list:                t = s.intersect(ox, oy, oz, dx, dy, dz)                if t is not None and (best_t is None or t < best_t):                    best_t = t            return best_t        t_l = self.left.traverse(ox, oy, oz, dx, dy, dz) if self.left else None        t_r = self.right.traverse(ox, oy, oz, dx, dy, dz) if self.right else None        if t_l is None:            return t_r        if t_r is None:            return t_l        return min(t_l, t_r) if __name__ == "__main__":    spheres = [        Sphere(-4, 0, 0, 1, "red"),        Sphere(4, 0, 0, 1, "green"),        Sphere(0, 0, 0, 0.5, "blue"),    ]    root = BVHNode(spheres)    t = root.traverse(0, 0, -10, 0, 0, 1)    print("Hit distance:", t)
目的:用 Python 模拟 BVH 加速光线求交的“剪枝”逻辑——先用包围盒粗筛,再进入叶子逐个求交,直观展示硬件加速的核心思想。
  1. self.bound = self._compute_bound(sphere_list)每个节点构建时算出包围盒,就像快递仓库给每个分区装上目录。
  2. disc = b * b - 4 * a * c判别式小于 0 说明光线没碰到球体,这是最基础的求交数学。
  3. def hit_bound(self, ox, oy, oz, dx, dy, dz)用 Slab 法判断光线是否穿过包围盒,对应 RT Core 的第一层硬件判定。
  4. if not self.hit_bound(...): return None未命中直接返回,这就是“剪枝”:整棵子树都不必检查。
  5. if self.left is None and self.right is None:到达叶子节点后,才真正对内部球体逐个求交。
  6. min(t_l, t_r)左右子树都有命中时取更近的那个,对应光追中“最近命中”原则。

常见误区

误区我以为光追就是在 CUDA 上跑软件算法,RTX 只是把同一个算法搬到新芯片上,让运算速度翻几倍而已。

正解RT Core 不是“同一算法换芯片”,而是把 BVH 遍历与三角形求交做成了专用硬件电路。软件光追每根光线要按指令流水线走完几百次判断和分支跳转,RT Core 一次硬件调用就返回命中结果,工作流程本质不同。就像普通搬运工要抬头看路、弯腰搬货,而专用机器人直接按轨道滑过去,二者不是效率差异,而是执行方式差异。

为何常见:早期光追确实在 CUDA 上纯软件实现,容易让人以为硬件加速只是量变。

误区我建好 BVH 加速结构后,场景里物体怎么动都不用管了,反正每个三角形都被包围盒包住了。

正解场景中物体移动、旋转或变形时,底层加速结构 BLAS 需要增量重建或 refit,顶层加速结构 TLAS 每帧都要根据实例变换矩阵重新构建。否则包围盒与真实几何位置漂移,光线会“撞空”或漏检。就像仓库货架挪位后目录不更新,快递员按旧目录找包裹必然扑空。

为何常见:把 BVH 想象成静态索引,忽略了它是高度依赖场景当前状态的动态加速结构。

误区想提升画面效果就疯狂加着色器和子光,反正 RT Core 是专用硬件,再复杂也会并行处理完。

正解着色器切换、SBT 查找和调度开销是实打实的成本。任意命中(Any Hit)会打断硬件求交管线,增加分支代价;子光越多递归回溯越深。合理实践是尽量使用不透明三角形、减少着色器绑定切换,必要时用降噪换光线数。硬件虽快,但不是无消耗的魔法。

为何常见:直观认为专用硬件“反正很快”,忽视了调度与内存访问模式对真实吞吐的影响。

误区降噪无非是磨皮滤波,用多了画面会变糊,细节全丢。

正解现代降噪器结合深度、法线和运动向量做边缘保留滤波,时间累积还能跨帧复用信息,在细节几乎不损的情况下把光线数从每像素上百条降到 1-2 条。它更像是“根据包裹外形补全被遮住的标签”,而不是简单糊一层。

为何常见:接触过古老均值滤波产生的“糊感”,容易以偏概全。

面试题

Q1. 光追与光栅化的核心区别是?

单选题 · easy

  • A.光追运算速度一定更快
  • B.逐像素反向发射光线求交← 正确答案
  • C.光栅化依赖专用 RT Core
  • D.光追只能用于离线渲染

答案:B。光追的核心是逐像素发射光线并与场景求交,模拟真实光照传播;光栅化则是把三角形投影到屏幕逐像素覆盖,像扫描仓库找包裹。光追并不天然更快,离线实时都能用。

Q2. RT Core 在硬件上主要加速什么运算?

单选题 · easy

  • A.纹理采样等工作归纹理单元
  • B.光线与三角形求交及 BVH 遍历← 正确答案
  • C.矩阵乘法由 Tensor Core 完成
  • D.视频编码由 NVENC 完成

答案:B。RT Core 是专用“分拣机器人”,把 BVH 节点遍历和三角形相交测试做成专用电路。纹理采样归 TMU,矩阵乘法归 Tensor Core,视频编码归 NVENC,各有分工。

Q3. 关于 BVH 加速结构,下列说法正确的是?

多选题 · mid

  • A.BVH 是递归的二叉树结构← 正确答案
  • B.未命中父包围盒时可剪枝← 正确答案
  • C.BVH 结构永远无需重建
  • D.SAH 用于优化切分质量← 正确答案

答案:ABD。BVH 是二叉树,用盒体层层包裹几何体;未命中父盒即“剪枝”整支子树;场景变化时需要 refit 或重建;SAH(表面积启发式)能降低遍历期望成本。选 C 的人误把 BVH 当成了静态索引。

Q4. 光线方程 P(t)=O+tD 中,t 的物理意义是?

单选题 · mid

  • A.光线的颜色参数
  • B.沿方向走的距离参数← 正确答案
  • C.光线的亮度阈值
  • D.光源的温度参数

答案:B。t 是光线沿方向 D 前进的距离参数,t≥0 表示光线前方的点。命中物体时 t 值就是到交点的距离,相当于快递员手电筒“照了多远”。

Q5. 重心坐标判定中,命中点在三角形内部的充要条件是?

单选题 · mid

  • A.u 与 v 之和恰好为 1
  • B.u、v 非负且求和不超过 1← 正确答案
  • C.u、v 均大于零且求和大于零
  • D.u 与 v 同时恰等于 0

答案:B。三个权重 (1-u-v)、u、v 都必须非负,点才落在三角形内;边界上会有权重为 0,所以用 ≥ 而非 >。这对应交点落在三角形内部还是边上的精确判断。

Q6. 关于 DXR 光追管线,正确的说法有?

多选题 · hard

  • A.底层加速结构 BLAS 由几何体生成← 正确答案
  • B.顶层 TLAS 引用实例与变换矩阵← 正确答案
  • C.SBT 决定命中后执行哪个着色器← 正确答案
  • D.DispatchRays 前无需创建 PSO

答案:ABC。BLAS 吃几何体、TLAS 吃实例(含变换矩阵),SBT 用实例/几何 ID 定位着色器。DispatchRays 之前必须先创建根签名和管线状态对象(PSO),D 说反了。

Q7. 降噪技术(Denoising)的主要目的是?

单选题 · easy

  • A.提高渲染分辨率输出
  • B.少量光线加平滑重建画质← 正确答案
  • C.压缩场景贴图尺寸
  • D.增加全局光照亮度

答案:B。光追每像素只发 1-2 条光线会产生噪点,降噪利用邻域与时间信息重建近似画质,相当于抽样验货后按相似性补全未验部分。

Q8. 混合渲染中 G-Buffer 的主要作用是?

单选题 · hard

  • A.存储光追生成的全部反射颜色
  • B.提供深度法线基础色供处理合成← 正确答案
  • C.保存 BVH 的树形结构内容
  • D.记录着色器绑定表的所有条目

答案:B。G-Buffer(几何缓冲)存每个像素的深度、法线、基础色等,光追反射基于这些信息生成,并供降噪和最终合成复用。它不是光追结果,也不负责保存 BVH 或 SBT。

Q9. RTX 性能优化可行的策略有哪些?

多选题 · hard

  • A.使用 DLSS 低分辨率渲染加超分重建← 正确答案
  • B.每像素发射上千条光线且完全不用降噪
  • C.利用时间累积提升降噪稳定性← 正确答案
  • D.增加 Any Hit 着色器数量追求效果

答案:AC。DLSS 降分辨率渲染再超分是可行加速法;时间累积让降噪跨帧复用信息;暴力发上千条光且不降噪是性能灾难;Any Hit 越多越易打断硬件求交管线,反而拖慢整体渲染速度。

Q10. 反射方向公式 R=I-2(I·N)N 中,I·N 表示?

单选题 · mid

  • A.反射光线的总强度大小
  • B.入射方向在法线的投影分量← 正确答案
  • C.材质折射率的数值大小
  • D.光源发光的亮度强弱

答案:B。I·N 是入射向量与法线向量的点积,几何意义是入射方向在法线方向的投影长度,决定反射方向中沿法线分量的多少;2 倍反转后得到严格镜面反射方向。