使用 Unity 的 Light Probe 进行光照烘培存储时候经常碰到需要手工添加很多 Light Probe 点的情况,手工操作既枯燥又比较繁琐机械。所以需要一种能自动根据选中 Mesh 而在表面根据模型的 Mesh 信息生成一层均匀的 Light Probe 的方法来完成这个过程。
网上有一个简单的根据选中 Mesh 的 AABB 三维包围盒去在 XY 平面根据包围盒大小均匀撒布 Light Probe点,然后向 Z 方向位移一定距离后复制原有所有 Light Probe 点来生成整个 Light Probes Group. 生成的Light Probe 点集就如下图所示:
图 1 按 AABB 包围盒模式的 Light Probe 分布
这种生成方法的主要缺点在于跟物体本身的形状耦合度不高,如果场景需要生成 Light Probe 点不是这样一个比较规则平整的平面的话,如果想要较密较均匀的点集是很困难的,需要你自己手动选中平整的面,一个面一个面这个生成,相当麻烦,特别针对目前所做赛车场景,往往需要的 Probe 点只需要在赛道上均匀分布而其他部分不需要的情况下,不可能针对整个场景来使用这个算法。
图 2 Mesh 表面平均分布的示例图
针对这个问题我们小组查找了些资料,有一种扔飞镖【 1 】 的基于 Triangle Mesh 的物体表面均匀随机采点算法很试用我们目前碰到的问题。它的基本思路为将每个 Triangle 分别看作一个独立的整体,它能获取样点的概率跟他的面积成线性正比。首先将所有三角形面片收集到它定义的一个叫 Bin 的数据结构里面。如下图所示:
图 3 Bin 数据结构
本算法会维护这样的一个数据结构,将三角形按照大小所在的区间,分布在不同的三角形集合内,若最大三角形面积为 Amax, 则 0 号集合面积区间为 [Amax , Amax/2] , 1 号集合的面积区间为 [Amax / 2, Amax / 4] 依次类推,最后一个集合就保留所有未归类到以上区间的三角形,实际情况可根据三角形的数量来决定总共需要几个三角形集合,集合内的三角形为无序(即不排序 ) 。然后首先随机选择集合,然后从选定的集合中,依次遍历该集合内所有三角形,采取拒绝采样选择该轮选中采样的三角形,即随机生成一个 [0,1] 的数若小于 Acur/Bmax.(Acur 为当前选中的三角形, Bmax 为选中三角形所在集合的最大区间值 ) 。则选中该三角形进行随机采样。
当三角形获取一次样点机会后,采用三角形 UV 坐标系进行随机采样,三角形内部随机采样公式如下:
P = (1 - sqrt(r1)) * A + (sqrt(r1) * (1 - r2)) * B + (sqrt(r1) * r2) * C
其中 r1,r2 分别为俩个 [0,1] 的均匀随机数, A , B,C 分别为三角形三个顶点的坐标,详细的数学推导可参见索引文章 [2] 的 4.2 节。假定所采样的三角形为 T ,给定一个样点距离 l, 在 T 中随机采样完成后,若三角形的三个点离采样点的距离都小于 l 则该三角形被抛弃,否则将三角形细分,取 T 的每个边的中点,将三角形分为等同大小的四个三角形 T1 ’, T2 ’, T3 ’, T4 ’如下图所示。并将四个三角形先进行如上的检测,通过后加入到维护的 Bin 数据结构中。
图 4
另外要注意的几点是。
1 ,为了防止采样点距离过近,我们需要维护一个三维数据结构如 OCTree 或者 KD-tree 去检测当前计算好的采样点是否满足距离要求,不满足则重新取采样点,如果超过三次还找不到满足的采样点,则将三角形直接分为四个小三角形加入 Bin 结构中。
2 ,为了防止无限细分,可以设置一个阈值,若三角形面积小于一定面积则,直接取三角形重心点为采样点。当三角形过小则直接抛弃不要。
最后为了构成 LightProbes Group 在每个 Probe 所在的三角形法线方向做一定位移复制成另外一个 Probes。效果图如下:
( 左边为本算法生成分布图,右边为原算法生成分布图 )
将我们算法应用在赛车项目中,对跑道进行 LightProbes 均匀分布,获取了较好的效果,如下图所示:
参考文献:
[1] Dart Throwing on Surfaces , D. Cline1, S. Jeschke1, K. White2, A. Razdan1 and P. Wonka1 ,Eurographics Symposium on Rendering 2009
[2]Shape Distributions , ROBERT OSADA, THOMAS FUNKHOUSER, BERNARD CHAZELLE, and DAVID DOBKIN , ACM Transactions on Graphics (TOG) 2002