我的模样有你的孤单 --- 《模样》
今天介绍一下UE中的lightmap(LM)技术,lightmap算是一个高级版的irradiance environment map(envmap),而irradiance envmap[1]则是Ravi教授在2001年首次将球谐引入到图形学中。所以,本文先介绍irradiance envmap技术,如何使用球谐函数;然后介绍LM对envmap的升级,最后是UE中如何生成和使用LM。
Env map
逻辑上很简单,创建UV,然后逐点做一次上面的操作,将矩阵保存在光照贴图中。可是,生活不是诗,平淡生活中的那些刺,如同碎瓶上那浅浅而深邃的裂痕,不易发现却无处不在。
Lightmap UV
上图是纹理UV和LM的UV的不同,纹理UV不需要考虑光源的影响,而LM中不同位置下收到的光源的影响也不同,因此每一个位置都需要独一无二的UV。其次,UV贴图如果不合理,比如分辨率或padding不充分,有可能会产生漏光(light leaking)问题,这是相邻点插值影响导致。我对如何生成LM的UV算法,并没有研究,刚才说的都是看UE的文档了解的,假设我们现在已经创建了UV。
Lightmap UV
UE中还可以选择显示LM的密度,可以查看LM的分辨率设置是否合理。
UV贴图准备就绪,下面就是如何生成LM内容了。这部分我没法调试,只能看代码,所以不太确定理解的是否准确,很多逻辑都是自圆其说,我承认有赌的成分。本部分纯属虚构,欢迎追究法律责任。
Lightmap Pipeline
UE的LM采用了2阶,光源包括直接光照和间接光照两个贡献。如上图,生成LM的入口是在FStaticLightingSystem::ProcessTextureMapping
,首先,根据TextureMapping的高度和宽度,创建对应的LightMapData
容器,该容器中元素类型是FGatheredLightMapSample
,保存该点对应的球谐函数的参数。
有了容器后,首先计算直接光照的球谐贡献,对应方法CalculateDirectAreaLightingTextureMapping
,该方法会遍历UV贴图,对应两个for
循环,贴图中每一个像素,计算光源对该点的光照强度LightIntensity
和软阴影程度Transmission
,都是FLinearColor
对象。前者只要基于光源本身的强度,光源类型以及随距离衰减等因素;后者则基于蒙特卡洛采样的方式,估算面积光下的软阴影比例,如下图,在光源面上随机生成N个点,连接该点和物体的某点,判断光源和物体之间是否有遮盖物,根据结果得到软阴影的值。
Soft Shadow
这样,我们有了光源以及可见性,在加上该点的法线,基于这些参数,CalculatePointLighting
方法中实现了对该贡献的球谐函数转换,UE中称为FGatheredLightSample
对象,对应球谐函数中,TGatheredLightSample<SHOrder>::AddWeighted
实现该点所有光源贡献的累加,对应积分的部分。最终,基于上面两个方法,根据公式获取该点的。
间接光部分我并没有深入了解具体技术细节,涉及的内容可以开一个专题。本质是基于之前的Photon Mapping技术,估算出该点的irradiance,然后根据irradiance,创建对应的FGatheredLightSample
对象,接下来就和直接光的部分是相同操作。
这里,有一个我不太确定的地方:
FGatheredLightSampleUtil::PointLightWorldSpace()
{
Result.SHVector.AddIncomingRadiance(Color, 1, WorldDirection);
FSHVector2 SH = FSHVector2::SHBasisFunction(TangentDirection);
Result.SHCorrection = Color.GetLuminance() * (0.282095f * SH.V[0] + 0.325735f * SH.V[2]);
}
这里,不仅计算了该光源和基函数的乘积(AddIncomingRadiance),还计算了在局部坐标下光照SHCorrection
,看上去像是沿着法线射入的光照能量最大的情况,为了后面归一化,能量守恒的作用,但不明白为什么要这么算的理论依据。
最后,我们的容器对象是FGatheredLightSample
,PadTextureMapping
用来避免重叠等漏光问题,最后调用ConvertToLightSample
转换为FLightMapData2D
对象格式。这里,包括HighQuality
和LowQuality
两种类型。OutCoefficients[0]
的第一行存储光照的颜色信息FLinearColor
,而OutCoefficients[1]
第二行存储球谐的系数
当然,在输出最终的LM时,还会执行数据压缩,向量化的过程,会有一些有损压缩的小技巧在里面。
另外,Skylight也涉及到同样的操作,但Skylight不会考虑物体的可见性问题,天圆地方,场景中任意一点都是中心点,然后计算Skylight对该点贡献对应的球谐基函数的参数。UE中采用三阶,最终对应9个参数。
不确定生成环境光的irradiance贴图是否是这个方法,但思路是完全一样的,所以贡献都累计到StationarySkyLighting
对象,然后记下来StationarySkyLighting::SHVector
对应的系数。
// GatheredLightingSample
void AddIncomingStationarySkyLight()
{
StationarySkyLighting.AddWeighted();
}
生成的LM在Shader中的调用也很直接:
// LightmapCommon.ush
void GetLightMapColorHQ()
{
// 获取光照颜色
half3 UVW = ...;
// 获取球谐系数L_lm
float4 SH = ...;
// 计算irradiance:n^tMn
half Directionality = max( 0.0, dot( SH, float4(WorldNormal.yzx, 1) ) );
half Luma = L * Directionality;
// 计算radiance对应的color
half3 Color = Luma * UVW;
// 获取Diffuse光贡献
OutDiffuseLighting = Color;
}
// 环境光贴图中的SH
float3 GetSkySHDiffuse()
{
...
return max(0, Intermediate0 + Intermediate1 + Intermediate2);
}
UE中一个光源如何保证能量守恒,这块我还没查阅过,比如哪些光是通过LM的方式计算贡献,哪些是RenderLights,通过BRDF的方式,是按照static和dynamic区分,以及涉及到不同平台的质量LQ和HQ。另外,还涉及到阴影图等内容,很多谜团需要一点点的解惑。
LightMap是我今年才了解的一个概念,最初是在Unity的SRP中介绍光照贴图的内容,看完之后一脸懵。后来,看到BabylonJS,以及threejs也支持,突然觉得这个看上去好像很重要的样子。读博后,在UE中遇到的第一个缺陷就是漏光问题,所以,了解了一些关于LM应用的内容,比如分辨率以及GPU创建LM等。所以,我本人也很好奇LM的具体技术实现,从今以后,听到光照贴图后,我可能不会心虚了。
本文介绍了irradiance environment map的原理,后来延伸到图形学中的Precomputed radiance transfer(PBR)领域,以及UE中如何生成LightMap,在Shader中如何使用lightmap的相关内容。
To see the world, things dangerous to come to, to see behind walls, to draw closer, to find each other and to feel. That is the purpose of LIFE.
这张照片是我2017年某个夜晚,从公司办公楼下来时所拍摄的,当时耳机里正好播放的是许巍的'执着'。当听到那句“我想超越这平凡的生活,注定现在暂时漂泊”时,眼眶湿润,毕竟男子汉不许哭,所以我不会这样说。人都有迷茫的时候,就好比鲁迅写的,地上本没有路,走的人多了,也就成了路。所谓的迷茫,以我的经历就是社会循规蹈矩的给你安排了一条路,你不想走,可又找不到自己的路。这让我想到了白日梦冒险家中的男主人公Walter,如果你见过格陵兰,喜马拉雅和冰岛的火山,就再不会被生活打败。
可是,选一条少有人走的路太难了,而且,每个人无论如何坚持,最终都只是这宇宙中的一粒尘埃,何必挣扎呢,早点投降早躺平。所以,我并不鼓励我关心的人去追求那些飘渺的生活意义,我只希望他们开心,如果他们想要坚持自己的梦想,我希望他们能有一个积极的心态来努力,毕竟,人的选择有很多,看尽世界美景,品尝美味,感受不同的风土人文,有意义是用来修饰活着,而不是寻找的目标。再不行,如果还想坚持的话,希望你不是一个人前行,may the force be with you。
正是个人的这点经历,才让我想到了开头的那句歌词。人都会迷茫,这就好比修仙里的渡劫,渡劫本就是自己的事情,别人也帮不上什么。我唯一能做的,可能就是让迷茫的人不再孤单吧。
[1]
An Efficient Representation for Irradiance Environment Maps: https://graphics.stanford.edu/papers/envmap/envmap.pdf