前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >UE(6):LightMap

UE(6):LightMap

作者头像
Peter Lu
发布2022-12-22 15:10:30
9520
发布2022-12-22 15:10:30
举报
文章被收录于专栏:LETLET

我的模样有你的孤单 --- 《模样》

今天介绍一下UE中的lightmap(LM)技术,lightmap算是一个高级版的irradiance environment map(envmap),而irradiance envmap[1]则是Ravi教授在2001年首次将球谐引入到图形学中。所以,本文先介绍irradiance envmap技术,如何使用球谐函数;然后介绍LM对envmap的升级,最后是UE中如何生成和使用LM。

irradiance environment map

Env map

Lightmap

逻辑上很简单,创建UV,然后逐点做一次上面的操作,将矩阵保存在光照贴图中。可是,生活不是诗,平淡生活中的那些刺,如同碎瓶上那浅浅而深邃的裂痕,不易发现却无处不在。

Lightmap UV

上图是纹理UV和LM的UV的不同,纹理UV不需要考虑光源的影响,而LM中不同位置下收到的光源的影响也不同,因此每一个位置都需要独一无二的UV。其次,UV贴图如果不合理,比如分辨率或padding不充分,有可能会产生漏光(light leaking)问题,这是相邻点插值影响导致。我对如何生成LM的UV算法,并没有研究,刚才说的都是看UE的文档了解的,假设我们现在已经创建了UV。

Lightmap UV

UE中还可以选择显示LM的密度,可以查看LM的分辨率设置是否合理。

UE pipeline

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对象,接下来就和直接光的部分是相同操作。

这里,有一个我不太确定的地方:

代码语言:javascript
复制
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,看上去像是沿着法线射入的光照能量最大的情况,为了后面归一化,能量守恒的作用,但不明白为什么要这么算的理论依据。

最后,我们的容器对象是FGatheredLightSamplePadTextureMapping用来避免重叠等漏光问题,最后调用ConvertToLightSample转换为FLightMapData2D对象格式。这里,包括HighQualityLowQuality两种类型。OutCoefficients[0]的第一行存储光照的颜色信息FLinearColor,而OutCoefficients[1]第二行存储球谐的系数

当然,在输出最终的LM时,还会执行数据压缩,向量化的过程,会有一些有损压缩的小技巧在里面。

Skylight

另外,Skylight也涉及到同样的操作,但Skylight不会考虑物体的可见性问题,天圆地方,场景中任意一点都是中心点,然后计算Skylight对该点贡献对应的球谐基函数的参数。UE中采用三阶,最终对应9个参数。

不确定生成环境光的irradiance贴图是否是这个方法,但思路是完全一样的,所以贡献都累计到StationarySkyLighting对象,然后记下来StationarySkyLighting::SHVector对应的系数。

代码语言:javascript
复制
// GatheredLightingSample
void AddIncomingStationarySkyLight()
{
    StationarySkyLighting.AddWeighted();
}

Shader

生成的LM在Shader中的调用也很直接:

代码语言:javascript
复制
// 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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-09-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 LET 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • irradiance environment map
  • Lightmap
  • UE pipeline
    • Skylight
    • Shader
    • 总结
      • 参考资料
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档