一、算法原理(Principle)
核心思想:
如果一个物体在当前相机视角下投影到屏幕上的面积小于某个阈值(如仅占屏幕的几个像素),那么它的渲染贡献可以忽略不计,可直接剔除或以极低 LOD 渲染。
这种剔除不是基于物体的真实世界尺寸(World Size),而是基于其在屏幕上的投影面积(Projected Screen-space Area),即"从相机看来它有多大"。
换句话说:
-
一个体积巨大的物体如果离相机很远,它的屏幕空间面积可能非常小。
-
而一个微小的零件如果离相机很近,投影面积却可能很大,仍然需要保留。
因此,这种方法更符合人眼的视觉感知规律,也更适合动态视角场景。
二、计算流程(Computation Pipeline)
步骤 1:计算包围体(Bounding Volume)
对每个几何体预先计算包围体(常见为 AABB 或 OBB)。
例如:
步骤 2:相机视图变换与投影
将包围体的 8 个顶点变换到裁剪空间(Clip Space):
其中:
-
:投影矩阵(Perspective/Orthographic)
-
:视图矩阵
-
:原始坐标
-
:裁剪空间坐标
步骤 3:规范化设备坐标 (NDC)
执行透视除法:
并将其映射到屏幕坐标:
其中为屏幕宽高。
步骤 4:计算屏幕空间投影面积
对所有投影点求最小包围矩形(Screen-space Bounding Box):
或者使用更精确的三角面投影面积求和:
步骤 5:基于阈值剔除
设定一个像素级阈值 (例如 16 px² 或 32 px²):
Cull (剔除或使用低 LOD)
三、数学形式与可视化解释
假设物体中心点距相机距离为,物体包围球半径为
,视角为
,屏幕分辨率为
,则近似的投影面积为:
其中:
-
:投影焦距
-
:屏幕像素尺度
当较大或
很小时,面积急剧下降。
因此可以预先计算"距离阈值表"用于快速剔除:
即距离超过的物体,其投影面积一定低于阈值。
四、优化策略(Optimization Strategies)
1. 层级包围体测试 (Hierarchical Bounding Volume Test)
结合 BVH / Octree,将 SSAC 测试由局部几何上升到节点级别,先剔除整个子树。
2. 基于 GPU 的并行计算
使用 Compute Shader 批量计算各个 geometry 的投影面积(每个线程处理一个物体),并写入可见性缓冲区。
3. 动态阈值调整
根据相机运动速度或场景复杂度动态调整剔除阈值 :
-
快速运动 → 提高阈值(更多剔除)
-
静止镜头 → 降低阈值(更精细)
4. 与 LOD 管线结合
如果 位于两个阈值之间,可选择使用中等 LOD,而非直接剔除,平滑过渡。
投影面积区间 | 操作 |
---|---|
完全剔除 | |
使用低 LOD | |
使用全分辨率渲染 |
5. 与遮挡剔除(Occlusion Culling)组合
先进行视锥剔除,再用 SSAC,再用遮挡剔除,实现三级快速筛选。
五、应用与案例
应用场景 | 实际效果 |
---|---|
游戏引擎(Unreal, Unity) | 在每帧动态场景中自动剔除远处小道具、树叶、螺栓等对象。 |
工业仿真(CAD/PDPS) | 对极大量机械零件进行投影面积筛选,显著降低每帧渲染时间。 |
大规模点云可视化 | 仅保留投影面积较大的点或体素,提高绘制性能。 |
VR/AR 场景 | 因人眼分辨率有限,SSAC 在边缘区域剔除微小几何几乎无感知差异。 |
六、总结
特性 | 说明 |
---|---|
优势 | 与视觉感知一致、易实现、性能显著、可GPU并行 |
局限 | 对非刚体或快速变化场景需要每帧重计算;不考虑遮挡 |
典型优化方向 | 层级剔除、动态阈值、自适应LOD、多阶段过滤 |
🔧 简要伪代码示例
cpp
for (Geometry g : scene.geometries) {
BoundingBox bb = g.getBoundingBox();
Vector3 pts[8] = TransformToClipSpace(bb, camera);
ScreenRect rect = ProjectToScreen(pts, screenWidth, screenHeight);
float area = rect.width * rect.height;
if (area < areaThreshold)
g.visible = false;
else
g.visible = true;
}