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

【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还能直接用它。
github.com/bonzajplc/A...

解决普通视锥裁剪的问题


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

作者主页:www.zhihu.com/people/jack...

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

相关推荐
伽蓝_游戏3 小时前
UGUI源码剖析(15):Slider的运行时逻辑与编辑器实现
游戏·ui·unity·性能优化·c#·游戏引擎·.net
蒋星熠12 小时前
Flutter跨平台工程实践与原理透视:从渲染引擎到高质产物
开发语言·python·算法·flutter·设计模式·性能优化·硬件工程
float_六七14 小时前
数据库连接池:性能优化的秘密武器
数据库·oracle·性能优化
翻滚丷大头鱼16 小时前
android 性能优化—ANR
android·性能优化
翻滚丷大头鱼16 小时前
android 性能优化—内存泄漏,内存溢出OOM
android·性能优化
Linux运维技术栈18 小时前
域名网页加载慢怎么解决:从测速到优化的全链路性能优化实战
运维·网络·nginx·性能优化·cloudflare
荣光波比20 小时前
Nginx 实战系列(六)—— Nginx 性能优化与防盗链配置指南
运维·nginx·性能优化·云计算
DemonAvenger1 天前
MySQL内存优化:缓冲池与查询缓存调优实战指南
数据库·mysql·性能优化
前端小万1 天前
一次紧急的现场性能问题排查
前端·性能优化
老马啸西风1 天前
v0.29.2 敏感词性能优化之基本类型拆箱、装箱的进一步优化的尝试
性能优化·开源·nlp·github·敏感词