再聊阴影裁剪与高性能视锥剔除

再聊阴影裁剪与高性能视锥剔除

【USparkle专栏】如果你深怀绝技,爱“搞点研究”,乐于分享也博采众长,我们期待你的加入,让智慧的火花碰撞交织,让知识的传递生生不息!


一、实际需求

因为项目的树与草都采用Compute Shader剔除的GPU Instance绘制,所以需要自己实现阴影投递物的裁剪方法。也就是每一帧具体让哪些物体绘制ShadowMap。该计算的精确性会很影响树(有大量顶点又需要用AlphaTest镂空)的渲染性能。之前实现了一版《阴影视锥裁剪实现》,是在世界空间暴力计算,不算直观,也不精巧。最近有一种非常不错又好理解的新思路,所以再分析一次。

二、主要思路

  • 把物体的AABB的8个顶点转到灯光空间,重新计算出AABB(与灯光空间xyz轴平行)。
  • 把视锥的6个平面与AABB也转到灯光空间。
  • 如果物体AABB的max.z < 视锥AABB的max.z,则把物体AABB的max.z设置为视锥AABB的max.z(这里是比较巧妙一步,解决了本身在视锥外但投影在视锥内的物体)。

满足以上三步后,只要做普通视锥与AABB裁剪就行了,效果演示如下:

期间也尝试过一种裁剪计算量更小但精确度稍差一点的思路,就是在灯光空间下取消z判断,当作2D几何,求交。那么计算量会小很多。主体思想和这套相同,可根据实际项目来判断要省裁剪性能还是提示裁剪精度。演示如下:

三、代码解释

为了方便自己与其他人验证算法,一般用C#实现,等落地时再转Compute Shader。为了代码清晰,一些不复杂的计算直接用Unity的API。做Compute Shader时需要实现这些基础函数,都能找到这种标准件代码。

1. 视锥转换
把视锥体转到灯光空间,并绘制出5个视锥平面的法线(仅调试平面法线方向用),一般为了通用性视锥按6个平面处理,实际绝大部分项目,NearClip都靠近0,当作一个锥体处理。转换的方式比较简单每个点通过灯光矩阵转完 重新计算AABB即可。


灯光空间下 视锥体AABB

2. 对象转换
把投影对象AABB也转到灯光空间,转换方法和视锥那个一样,不过要转8个顶点,并做z轴方向延长。延长后的体积,就是整个阴影有效范围。这里可以做一个小优化,如果最小的z比相机最大的z还大就不用计算了,说明在相机外侧且远离灯光的方向,不可能投影入可见区域。

四、再谈视锥裁剪

这样在转换后做正常视锥裁剪就行,而这部分技术就非常普遍成熟。但写这篇主要是为了分享一种非常规裁剪,用于对树这种少裁剪一棵就影响帧数的项目,会比普通裁剪精确很多。

先看两种裁剪对比效果:


普通视锥裁剪


本方案裁剪

普通裁剪是比较保守但偏向正确和低复杂度的模式,就是要存在至少一个视锥平面,让这AABB的8个点同时在这个平面的外部。所以整体在视锥外部,但不同顶点在不同平面外部的情况就剔除不了。比如下图,没有任何一个平面可以让所有点都满足在它的外侧。


普通裁剪逻辑代码


不满足裁剪条件但应用剔除的情况

这是因为这种方式区分不了上图与下图2种不同情况,为了画面不出错只能选择保守处理:


不满足裁剪条件但不应用剔除的情况

五、精确裁剪推导

这部分逻辑属于功能扩展,如果不是有优化渲染性能要求,不需要了解这部分,直接用常规裁剪就好了。

首先做视锥AABB与物体AABB重叠检测,这不满足,肯定剔除(偏保守,但能加速淘汰)。

我们把物体AABB,与视锥重叠的方式分为2类:

  1. 物体AABB与视锥4个侧面三角形发生碰撞的重叠类型。
  2. 物体AABB不与视锥4个侧面三角形发生碰撞的重叠类型。


物体AABB与视锥4个侧面三角形发生碰撞的重叠类型


物体AABB不与视锥4个侧面三角形发生碰撞的重叠类型

可以这样归纳两类,如果重叠,那么不是物体AABB与视锥4个三角形碰撞,就是物体AABB有个角点在视锥内。

因为不存在只与远平面碰撞而同时又没有顶点在视锥体内的情况。因为这时候AABB会穿透视锥体,而视锥体是封闭多面体,这种时候一定会再与四个侧面发生碰撞,所以可归到第一类里。

对应的代码如下。其中三角形与AABB碰撞函数,是用GitHub上cginc文件改的,后面落地Compute Shader还能直接用它。
https://github.com/bonzajplc/AABB_Tri.compute/blob/master/AABB_Tri.cginc


解决普通视锥裁剪的问题


这是侑虎科技第1541篇文章,感谢作者jackie 偶尔不帅供稿。欢迎转发分享,未经作者授权请勿转载。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群:465082844)

作者主页:https://www.zhihu.com/people/jackie-93-85-85

再次感谢jackie 偶尔不帅的分享,如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群:465082844)