找回密码
 立即注册
查看: 675|回复: 12

体探针漏光解决方案

[复制链接]
发表于 2022-4-11 15:43 | 显示全部楼层 |阅读模式
问题描述

在全局照明领域,体探针插值漏光是存在多年的顽疾.比如 games202 里LPV(Light Propagation Volumes),unity的LPPV(light probe proxy volume),GDC上各种GI分享(某版cod) 还有之前我给项目实现的类似ue VLM的功能.都存在这个问题.和很多技术人员一样,一看到行业困难的技术点,就会自己动脑想一套更好的方案来解决他,因为这样可以名正言顺的造轮子.俺也一样,唯一不同的是我会想出3套^_^.



games202 里gi部分 提及的漏光问题



unity lppv 漏光问题

基础思路




被墙隔离的探针关系

根本的原因当然是探针的密度不肯能无限密,而切分空间的表面可以没有厚度.而一般的探针信息里 并没有描述空间划分的逻辑,所以上图中,只有红色探针往左和绿色探针往右2个区域是正确的,中间的插值就出错了.所以 所有的思路都是去描述空间的划分.或表面上一个像素与体素的归属关系修复上.就是让A点只采样红色探针,B点只采样绿色探针.因为他们的空间归属如此.
方案1:bent normal偏移
我没有把简单normal偏移作为一种方案,因为这种太基础了,unity杭州大会上 分享过.而我在写初版vlm的时候就顺手写了出来基本是非常容易想到的,而且效果也不够好.看下图,AB有个简单的区分方式,就是他们法线不同,沿着各自法线方向去取探针,那么会得到正确的结果.也让他们跳出了中间的错误插值地段. 但是,墙面不是总是简单一个方向的,有些横梁等结构会像黄色一样,法线偏移后依然是错误的探针,因为 AB2个面 这种结构法线完全一样无法区分彼此,还有更严重的问题是,当角色从A面靠近墙面的时候,靠墙的这部分角色法线是朝右边的,所以导致 A处的角色显示绿色的GI.



法线方向偏移采样的问题

所以,我想到了用更大尺度的法线来描述总体法线朝向(或可见度方向).首先想到是屏幕空间normal的mipmap,但是 屏幕空间有相机外丢失信息的天然弊端,所以后面选择了,离线制作场景的bentnormal ,正确做法应该是对应lightmap 用uv2 解析.但为了演示方便我写到了顶点上.



计算bentNormal 到顶点上

测试下效果,用2个非垂直(垂直问题小很多)交叉,隔开的4个空间 分布打3个不同眼色的灯,不打灯的空间为黑色换角色,然后每0.5米一个探针 均匀放置探针.并创建出3dTexture .可以看到 normal 偏移 在非交叉处是对的 偏移方向就刚好是法线方向.



测试的模型



bentnormal 与normal的 效果对比

bentnormal算法
bentnormal的离线计算是比较常见的技术,比较简单就自己想了实现.原理就是 对某个点,法线所在的半球方向随机发出很多射线,没有发生碰撞的那些方向全部加起来,然后归一化.很像初中物理里求一堆力的合力,简单相加符合的力就可以.但是这种简单的计算依然会出现小的漏光,加强版里解决他.



bentnormal 基础版算法



基础版 发射射线

这个图里 黑色的mesh与绿色mesh相交,那么 露出的顶点 显示的红色bentnormal方向是对的,但是最右边的顶点,因为在物体内部 所以他没有计算出bentnormal,这样导致,渲染的黄色部分,bentnormal是 左右2个顶点插值的结果,这样就导致黄色的bentnormal 偏移角度不够,依然会插值到 绿色框内部或右面的探针,产生漏光.
具体的改善是 不要原点发射方向,而是沿着射线方向偏移一点再发射.如下图,再考虑射线的双向碰撞检测,就可以抛弃蓝色碰撞部分,获得绿色部分的合成,这样得到顶点bentnormal(黄色),会更符合环境描述,导致红黄2个插值的结构也更正确.



高级版发射射线



bentnormal 高级版算法

该方法最终效果,关于动态对象,不能取这份数据,需要逐对象分帧每帧发射一条射线,累积附近的偏移方向判断(实时bentnormal计算)

bentnormal 方向偏移方案效果
https://www.zhihu.com/video/1495146705536868352
方案2:DistanceProbe

同样是空间划分的描述,我们可以记录下碰撞体距离,根据是否大于距离判断是否取对面,总之在这种过渡位置不插值,要么取x处 要么取x+1处探针.取哪个根据shadingpoint 与probe的距离 是否大于提前记录的probe到障碍物距离来定.
下图所示,绿色圈表示 当前shadingpoint位置. 2个红圈表示 用来插值的2个probe颜色.为了直观只演示 x方向上的判断.
1.左边红圈处 没有记录往右存在1米内的碰撞 所以直接取x与x+1 ,2个红圈位置的probe颜色来插值.



直接用2个红圈插值

2.右边存在碰撞,但与shadingpoint 距离小于 与碰撞体距离,那么就直接取x处probe颜色为 shadingpoint颜色.



红圈右边存在碰撞,但与shadingpoint 距离小于 与碰撞体距离

3.X处 右边存在碰撞, 与shadingpoint 距离大于 与碰撞体距离,那么就直接取X+1 处probe颜色为 shadingpoint颜色.



X右边存在碰撞, 与shadingpoint 距离大于 与碰撞体距离

所以只要把 偏移数据 再创建一个texture3D 来存储,设置为point filter.即可实现功能.
看下效果(每米增加到8个probe的效果).

记录距离到probe的 偏移采样
https://www.zhihu.com/video/1495397263593238528
这种方式有2个问题.1 需要较高的摆放密度,这是因为 同一个空间内比如 方案1里的 (0.5x0.5x0.5)内,只记录一个 到x+方向 的float距离,(y+ z+同理都是一个float),但是一个空间内不同位置 这个距离应该是不同的,所以需要尽量让这个单位空间去小的范围.2 这种距离固定是只出现在 碰撞面刚好与xyz坐标轴垂直的情况下.如果 表面不是轴对齐 那么 一个小空间内也不能用一个float描述距离,这时候需要记录 平面方程来 判断空间划分 而不是一个 float的distance,存储容量x4,而实际工程中 一定是需要支持非轴对齐的情况的,除非无限细分空间.



左边 非轴对齐表面,右边 轴对齐表面

关于动态对象,这个算这个方案优势之处,因为存储的是空间信息所以 任何shadingpoint都能根据worldposition 直接获取偏移量 得到正确数据
方案3:Decal Offset

前面2种方案 都需要受到 体素/空间 划分密度影响,这是因为他们都是均匀摆放,导致一些位置受限.所以还有一种更直观的想法,就是我可以把某个不规则空间内 应该往哪个方向偏移 记录起来,等采样的时候访问.这种记录可以在任意位置(不需要均匀间隔),任意形状大小(为了方便用cube形状 但支持任何大小). 至于如何区分哪些是框住的部分,那么只要类似延迟贴花,算对象空间内坐标是否<0.5即可(cube中心 对象空间内 xyz任何一方>0.5都不在cube 包含范围内).
从顶视图看 我们为 其中一个空间 摆放 3个偏移cube,预计算每个cube中心的 非遮挡范围的中心方向(可见度cone的轴线方向)为箭头所示,并把这个方向 当作颜色 为3个cube 渲染到单独RendererTexture



为3个位置 摆放cube,确保cube中心的 可见度/非遮挡 方向 为所覆盖像素的偏移方向



3个cube 把自己中心 可见度cone轴线方向 作为颜色渲染到rt上

该方案最终效果

Decal Offset 效果
https://www.zhihu.com/video/1495429178253676544
可以看到,漏光基本修复了,但是 cube之间有接缝,这个需要多摆放一份cube让 偏移方向可以过渡 ,或者 对相邻cube做fade类似 reflectionprobe的 2个fade.
这种方案,因为cube数量多,而材质统一 顶点数少,正式工程,肯定用gpu culling来做,hzb等做剔除后 绘制instance性能很高.对于动态物体因为也是描述空间 而非表面所以 可以直接支持.

3个demo的 源文件工程

jackie2009/Probe_Light_Leak (github.com)

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2022-4-11 15:50 | 显示全部楼层
[赞同]
发表于 2022-4-11 15:57 | 显示全部楼层
[赞][赞][赞]
发表于 2022-4-11 16:03 | 显示全部楼层
不帅这篇居然也上了代码
发表于 2022-4-11 16:10 | 显示全部楼层
真分享 就是希望行业内都会[飙泪笑] 而且是demo不涉及具体项目 还好
发表于 2022-4-11 16:11 | 显示全部楼层
decal 应该会有闪烁吧
发表于 2022-4-11 16:17 | 显示全部楼层
做好cube 边缘fade 后应该不会 下个月落地项目后 我才能判断哪个方案最好
发表于 2022-4-11 16:25 | 显示全部楼层
感觉可以用两个volume texture,一个sdf一个sdf梯度来保证sample point永远离物体一定距离。当然probe密度太小依然gg,还要用不少内存
发表于 2022-4-11 16:26 | 显示全部楼层
距离场梯度 和bentnormal 存入probe 类似 都无法解决关键问题: 薄墙两侧会取到同一个probe 无法区分彼此
发表于 2022-4-11 16:27 | 显示全部楼层
用距离场不就是要偏移sample的位置来解决这个问题吗
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-25 03:36 , Processed in 0.104604 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表