Unreal4.27 High Quality Reflection在手机上的问题
问题描述Unreal4.27中材质开启High Quality Reflection后在手机上效果有问题,跟PC编辑器效果不一致,测试机型是小米11pro,不同机型问题的表现不一样,iphone12还没有问题。
测试场景有一个静态模型,用的引擎自带的地板SM_Template_Map_Floor,缩放为6,也就是长宽是60米,用的Chrome材质并开启了High Quality Reflection,还有三个静态点光源,光源强度为1000lm,三个Sphere Reflection Capture,一个静态Sky Light,Reflection Capture跟点光源的位置只有高度不同,点光源高度是500,Reflection Capture高度是200,效果如下:
手机上的效果就有问题了(在华为Mate40 pro上为黑屏):
不过Box Reflection Capture在手机上和编辑器中的效果是一致的:
4.25中Sphere Reflection Capture也没问题:
问题分析
Unreal中Sky Light和Reflection Capture都是通过Cubemap提供的光照,Sky Light提供无限远处的环境光,Reflection Capture提供局部的环境光。
不开启HQ Reflection和Box Reflection Capture都没有问题,所以应该从Box和Sphere、HQ Reflection开启和关闭之间的不同入手。
[*]Reflection Capture的形状用来控制场景中的哪些物体会被Capture到Cubemap,哪些物体会使用这个Cubemap,以及矫正后反射向量的计算方法。
[*]开启HQ Reflection会使用矫正后的反射向量,不开启HQ Reflection不会矫正。
综上所述,嫌疑最大的就是反射向量的矫正。
反射向量矫正
对比4.25和4.27的Shader代码:
最大的不同是4.25是在世界坐标系计算,4.27是在局部坐标系计算,4.27还对计算进行了简化,按理说这不应该导致编辑器和手机上效果不一致啊,但是把4.25的代码Copy过去,效果竟然一致了。
emmm,找到这次提交的日志,是整理了一下代码、提升了clear coat,按理说不应该整理出来bug呀:
突然灵光一闪,PC和手机的区别其中一点就是手机上有半精度,而PC没有,半精度的问题之前也遇到过很多,再仔细看4.25和4.27的代码,发现4.25用的float,4.27用的half。然后把4.27相关的计算改成float,效果就一致了,这样就确定了是半精度导致的计算问题。
问题解决
简单的解决方法就是把反射向量的矫正改成全精度,但是这会导致更大的开销,更好的解决办法是查出哪里计算有问题,然后避免这个问题,由于Shader调试的环境有问题,所以用了比较笨的方法,用RenderDoc修改Shader来查问题。
第一步先验证一下之前猜测的原因,把float的默认精度从mediump改成highp,结果就正确了:
验证了是计算精度的问题,第二步就是找出来哪一步计算出了问题,我用的方法就是把相关的变量改成highp,然后一个一个改成mediump,哪个改成mediump出了问题,就是哪里计算出了问题,最后查出来是这两个变量需要是highp:
这里的v94是Shader中的QuadraticCoef,二次函数的系数,v96是Shader中的LocalPosition,是当前渲染的像素在Sphere Capture坐标系中的位置,所以这个问题就出在dot(LocalPosition, LocalPosition)这里,计算结果超出了half能表示的最大值,好像也没什么好办法避免,所以最终的解决方案是提高这三个变量的精度:
进一步可以得出结论,当渲染的像素距离影响它的Sphere Reflection Capture中心很远时(很远也没有多远),就会出现计算错误。
<hr/>Update:后来发现当Reflection Capture半径大了后,还是有问题,所以还是全部改成了float。
<hr/>反射向量矫正的原理
解决完了问题顺便记录一下反射向量矫正的计算方法。只有当Cubemap提供无限远处的光照时,才可以直接使用反射向量采样,如Unreal的Sky Light:
当Cubemap提供局部的光照时,直接使用反射向量采样就会有问题,比如在一个反光的地板上走的时候,从相同的角度会一直看到相同的反射,这是因为反射向量一直没变,而真实世界中反射不仅取决于观察角度,还取决于观察位置:
解决方法就是把每个Cubemap跟一个虚拟的几何体绑定,根据这个几何体对反射向量进行矫正再采样,结果如下:
虚拟的几何体有两种:Sphere和Box,对应Unreal的两种Reflection Capture,这个几何体决定了场景中哪些物体会被Capture到Cubemap,哪些物体会使用这个Cubemap,以及矫正反射向量的计算方法。Sphere几何体在类似球形的模型上有更好的效果,整体的效果比较统一,但是在大的平面上距离Cubemap的中心点越远,误差越大;Box适用于矩形的房间或走廊,在box的边缘误差较大。
如下图,计算出反射向量R跟几何体的交点,矫正后的反射向量就是Cubemap中心C到交点P,这两种计算方法就只是计算交点的方式不同:
可以这样理解,当这个反光的平面在Cubemap的中心时,此时用反射向量是准确的,当逐渐把平面往下移动时,看到的反射的点也应该往下移动,到了上图中的位置,反射的点应该是P,所以要用CP采用Cubemap。
Ray-Sphere Intersection
射线和球的交点有两种求法,第一种是几何的方法:
只要求出了和就能知道 https://www.zhihu.com/equation?tex=t_%7B0%7D 和 https://www.zhihu.com/equation?tex=t_%7B1%7D ,所以步骤如下:
[*]https://www.zhihu.com/equation?tex=L+%5Ccdot+D 求出
[*]根据 https://www.zhihu.com/equation?tex=L 、求出
[*]根据 https://www.zhihu.com/equation?tex=radius 、求出
第二种是代数的方法,射线方程:
球的方程:
https://www.zhihu.com/equation?tex=%28p-c%29%5E%7B2%7D+-+R%5E%7B2%7D+%3D+0
把射线方程代入到球的方程,解出t来,就能求出交点:
https://www.zhihu.com/equation?tex=%28o+%2B+td+-+c%29%5E%7B2%7D+-+R%5E%7B2%7D+%3D+0
Unreal就是用的这种方法,代码中的QuadraticCoef就是二次方程的系数,Determinant就是二次方程的判别式 https://www.zhihu.com/equation?tex=%5CDelta+%3D+b%5E%7B2%7D+-+4ac 。
Ray-Box Intersection
射线和Box求交点的方法叫做slab method,把一个Box看成三个对面(两个平行的平面)的交集。
关键思想,光线进入所有对面才算进入Box,光线只要离开一个对面就算离开Box,求出进入时间 https://www.zhihu.com/equation?tex=t_%7Benter%7D 和离开时间 https://www.zhihu.com/equation?tex=t_%7Bexit%7D ,如果,那就说明光线在Box里待了一段时间,又因为考虑的是射线,不是直线,所以 https://www.zhihu.com/equation?tex=t_%7Bexit%7D+%3C+0 时也没有交点,所以相交的条件就是:
&& https://www.zhihu.com/equation?tex=t_%7Bexit%7D+%3E%3D+0
那如何计算射线跟其中一个slab的交点呢?轴对齐的Box计算简单,Unreal中的Box可以旋转,不过是在Box的局部坐标系计算的。比如考虑跟yz平面平行的这个对面,随着t的变化,它们的x是不变的,只需要x分量就能求出来跟这个对面的交点:
射线方程是:
这个slab的方程是:
https://www.zhihu.com/equation?tex=x+%3D+p_%7Bx%7D%5E%7B%27%7D
所以:
https://www.zhihu.com/equation?tex=t+%3D+%5Cfrac%7Bp_%7Bx%7D%5E%7B%27%7D+-+o_%7Bx%7D%7D%7Bd_%7Bx%7D%7D
这样还可以利用SIMD同时计算出跟x、y、z三个slab的交点,要是求跟任意一个平面的交点,计算就复杂多了。
Reference
https://zhuanlan.zhihu.com/p/266223117
https://developer.arm.com/documentation/102179/latest/
https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection
https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-box-intersection
https://www.bilibili.com/video/BV1X7411F744?p=13
页:
[1]