中EN
概念页

视锥相交测试

View Frustum Intersection Tests

层次视锥剔除遍历 BVH 时最频繁调用的就是视锥与包围体的测试,理想结果分三态:完全在外(剪掉子树)、完全在内(子树免测)、相交(递归)。本页讲从组合矩阵直接提取六个视锥平面、把"BV 对视锥"转化为"点对扩张/收缩体积"的推导思路,以及视锥-球、视锥-盒的高效保守测试及其误报情况。

三态与保守性(22.14 节)

只区分"排除/可能在内"的简化测试会面临两难:把"可能在内"当作完全在内,会渲染整个子树而不再剔除;对子树每个节点再测排除又常常白费,因为大部分可能确实在内。所以即使不完美,尽量快速区分相交与包含通常值得。

对场景图剔除,快速分类只需保守:排除与包含之间只能错向包含(应排除的被包含只是浪费时间;应包含的被排除会导致渲染错误);包含与相交之间两种误判都合法,只影响效率。保存父 BV 的相交状态是有用的优化;平面掩码和时间相干在 BVH 上效果明显,但对 SIMD 实现帮助较小。

通用推导思路:选一个相对 BV 固定的点 p\mathbf{p},让 BV 紧贴视锥外侧滑动一周,p\mathbf{p} 的轨迹围出一个外扩体积;紧贴内侧滑动则得到与原视锥平面平行的收缩视锥。p\mathbf{p} 在外扩体积之外则 BV 在视锥外,在收缩体积之内则 BV 完全在内,其余为相交。这些体积只取决于 BV 的形状和 p\mathbf{p} 的相对位置,与 BV 位置无关,所以任意位置的 BV 都可对同一组体积测试。

平面提取(22.14.1 节)

组合矩阵 M=PV\mathbf{M}=\mathbf{P}\mathbf{V},点 s\mathbf{s}(sw=1s_w=1)变换为 t=Ms\mathbf{t}=\mathbf{M}\mathbf{s},透视除法后得 u\mathbf{u}。OpenGL 约定下视锥内的点满足 −1≤ui≤1-1\le u_i\le1(DirectX 中 0≤uz≤10\le u_z\le1)。以左平面为例:

−1≤ux  ⟺  −1≤txtw  ⟺  tx+tw≥0  ⟺  (m0,+m3,)⋅s≥0-1\le u_x \iff -1\le\frac{t_x}{t_w} \iff t_x+t_w\ge0 \iff (\mathbf{m}_{0,}+\mathbf{m}_{3,})\cdot\mathbf{s}\ge0

其中 mi,\mathbf{m}_{i,} 表示 M\mathbf{M} 的第 ii 行。取负使法线朝外,六个平面为:

平面方程
左−(m3,+m0,)⋅(x,y,z,1)=0-(\mathbf{m}_{3,}+\mathbf{m}_{0,})\cdot(x,y,z,1)=0
右−(m3,−m0,)⋅(x,y,z,1)=0-(\mathbf{m}_{3,}-\mathbf{m}_{0,})\cdot(x,y,z,1)=0
下−(m3,+m1,)⋅(x,y,z,1)=0-(\mathbf{m}_{3,}+\mathbf{m}_{1,})\cdot(x,y,z,1)=0
上−(m3,−m1,)⋅(x,y,z,1)=0-(\mathbf{m}_{3,}-\mathbf{m}_{1,})\cdot(x,y,z,1)=0
近−(m3,+m2,)⋅(x,y,z,1)=0-(\mathbf{m}_{3,}+\mathbf{m}_{2,})\cdot(x,y,z,1)=0
远−(m3,−m2,)⋅(x,y,z,1)=0-(\mathbf{m}_{3,}-\mathbf{m}_{2,})\cdot(x,y,z,1)=0

(近平面一行按 OpenGL 的 −1≤uz-1\le u_z 推出;DirectX 的 0≤uz0\le u_z 需相应调整。)

视锥-球(22.14.2 节)

  • 正交视锥是盒子,可用球-OBB 测试;再检查球心在各轴上距边界都大于半径即完全包含。
  • 一般视锥:取球心为 p\mathbf{p}。精确的外扩体积有圆角,为效率用"把每个平面沿法线外推 rr"近似,收缩体积为每个平面内推 rr。实现:对六个平面(正半空间朝外)计算球心有符号距离,任一大于 rr 则在外;全部小于 −r-r 则在内;否则报告相交。球心落在尖角区域(圆角之外但在所有外推平面之内)时会把实际在外的球误报为相交——这是保守的,偶尔误报只多一些测试,加更多平面反而总体更慢。
  • 分块着色中的瓦片视锥细长不对称,需要额外的球-盒测试(见 分块着色);还有把视锥分成八分区、按物体中心所在八分区每次省去三个平面的方法。

视锥-盒(22.14.3 节)

方法做法特点
裁剪空间测试把 8 个角用视图和投影矩阵变换到规范视体,做 [−1,1][-1,1] 裁剪测试:全部在某边界外则拒绝,全部在内则包含无需提取平面,适用于任何由点界定的对象(线段、三角形、k-DOP),简单自洽,适合计算着色器
平面-盒测试对六个平面用平面-AABB/OBB 测试,每个平面最多测两个角:最近角在外则完全在外可提前结束;每个平面的最远角都在内则包含CPU 上明显更高效;近远平面平行可共享点积;只需先提取平面

误报:盒在视锥外但靠近角落时会被判为相交,对固定大小的地形网格等大物体更常见。Quílez 的补救是在报告相交后再用视锥角点测试盒的各平面(相当于 SAT 的第二部分),全部在某盒平面外则不相交;但这可能得不偿失——一个 GIS 渲染器中该优化每帧花 2 ms CPU 只省下几个绘制调用。Wihlidal 反其道而行,只用四个侧平面:游戏中近平面几乎被侧平面覆盖,远平面通常设置为能看到所有物体。也可以用 SAT 写一个通用的凸多面体测试,同时适用于线段、三角形、AABB、OBB、k-DOP、视锥和凸多面体的任意组合。

  1. realtime_rendering_4ed.pdf 第 22 章 Intersection Test Methods

相关页面

游戏数学相交测试基础与分离轴Intersection Test Fundamentals & Separating Axis相交测试判断两个对象是否相交(包含、边界相交或分离),有时还需要最近交点或穿透深度与方向,是碰撞检测、视锥剔除、拾取和光线追踪的基础。本页汇总 RTR4 第 22 章的通用工具:光线与曲面的表示、常见包围体定义(AABB、OBB、k-DOP、凸多面体、胶囊与菱形体)、分离轴测试 (SAT)、几何概率与表面积启发式 (SAH)、设计相交例程的经验法则,以及基于 GPU 的拾取。游戏数学包围体重叠测试Bounding Volume Overlap Tests碰撞检测先测试包围体是否重叠,只有重叠时才逐图元测试;最底层则需要三角形之间、三角形与盒之间的精确测试。本页整理 RTR4 第 22.10~22.13 节:平面与 AABB/OBB(只测两个角的"投影半径"法)、三角形-三角形(Guigue-Devillers 行列式法)、三角形-AABB(13 轴 SAT)、球-球、球-盒(Arvo 及其向量化版本)、AABB-AABB、k-DOP-k-DOP 与 OBB-OBB(15 轴 SAT)。更复杂的 BV(OBB、k-DOP)空体积更少、更紧,代价是测试更贵。图形学剔除技术Culling Techniques剔除 (culling) 是在渲染前尽快去掉对最终图像没有贡献的部分。本页讲几何类剔除:背面剔除(含成簇背面剔除与法线锥)、视锥剔除(层次化、平面掩码)、室内场景的入口剔除,以及牺牲质量换速度的细节剔除和小三角形剔除。更复杂的遮挡剔除见 遮挡剔除。游戏数学投影矩阵Projection Matrix投影矩阵把视景体变换到规范视体(OpenGL 为 [-1,1]^3,DirectX 的 z 为 [0,1]),在那里裁剪更高效。正交投影保持平行线平行、物体大小与距离无关;透视投影让远处变小,产生的深度与观察深度成反比,近平面位置和"反向 z"决定深度精度。游戏数学齐次坐标与矩阵约定Homogeneous Coordinates & Matrix Conventions实时渲染用 4×4 矩阵和四元素齐次坐标统一表示点和方向:方向向量 w=0,点 w=1。这样线性变换与平移可以合成为仿射变换并连乘。RTR4 采用列向量记法、右手观察坐标系;DirectX 采用行向量记法,书中强调这只是记法差异。图形学分块着色Tiled Shading分块着色把屏幕划分为瓦片(如 32×32 像素),先为每个瓦片建立可能影响它的光源列表,着色时每个像素在一次着色器调用中只遍历所在瓦片的列表。它可用于延迟着色(tiled deferred),也可用于前向着色(tiled forward,又称 Forward+)。配合 z-prepass 得到的瓦片深度范围可进一步剔除光源,但深度不连续会削弱效果,于是出现 HalfZ、2.5D 剔除等改进。游戏数学几何图元的表示Geometric Primitive Representations除点、向量、矩阵、四元数外,游戏引擎还天天用到直线/射线/线段、球、平面、AABB、OBB、视锥和凸多面体区域。本页按 GEA 整理它们在内存中如何表示以及最基本的「点在内部吗」测试;各种求交与重叠算法见 RTR4 来源的相交测试系列页面。

输入关键词开始搜索

滚轮或双指缩放 · 拖动平移 · 双击放大 / 还原