我们项目构建了Linux版本的客户端,用于DS的压测。最近一段时间, Unreal Linux Client的构建时间异常的久,所以简单的探究了下Cook的原理。最终通过关闭linux平台下的距离场(Distance Field)烘培,缓解了构建时间的问题。
介绍具体问题前,先了解下背景知识。
Unreal在构建的过程中,大致执行如下四步。
烘培(Cook)的过程,是将Editor内Assets转变为运行在各平台的Assets。这个过程一般会执行三个流程:
渲染(Render)和烘培(Cook)是相对平行的两个概念。 渲染主要和如下概念有关
render 渲染
static mesh 网格体
material 材质
shader 着色器
texture 贴图
简单的说,render是在mesh(网格体)上进行着色的过程,这个过程最终是由material(材质)完成。material又由shader代码(着色器)和texture(贴图)构成。
Unreal内的类间关系大致如下:
Cook和Render的关系可以简单的描述为,Cook阶段会为Render生成很多必要内容。本文标题中的距离场就是其中之一。
有向距离场(Signed Distance Field) (SDF),会将各点距离最近表面的距离保存到体积纹理中。网格体外的每个点保存的距离为正值,网格体内的每个点保存的距离为负值。
它有两个具体的应用:
引言中提到的烘培问题就出现在为DistanceFieldAO生成相关数据的过程。通过gdb得到了Cook阶段,引擎的执行堆栈:
UStaticMesh::Serialize
FStaticMeshRenderData::Serialize
FDistanceFieldAsyncQueue::BlockUntilBuildComplete
上述堆栈的上下文代码如下:
uint8 ClassDataStripFlags = 0;
#if WITH_EDITOR
const bool bWantToStripDistanceFieldData = Ar.IsCooking()
&& (!Ar.CookingTarget()->SupportsFeature(ETargetPlatformFeatures::DistanceFieldAO) || !Ar.CookingTarget()->UsesDistanceFields());
ClassDataStripFlags |= (bWantToStripDistanceFieldData ? DistanceFieldDataStripFlag : 0);
#endif
FStripDataFlags StripFlags(Ar, ClassDataStripFlags);
if (!StripFlags.IsDataStrippedForServer() && !StripFlags.IsClassDataStripped(DistanceFieldDataStripFlag))
{
if (Ar.IsSaving())
{
GDistanceFieldAsyncQueue->BlockUntilBuildComplete(Owner, false);
}
for (int32 ResourceIndex = 0; ResourceIndex < LODResources.Num(); ResourceIndex++)
{
FStaticMeshLODResources& LOD = LODResources[ResourceIndex];
bool bValid = (LOD.DistanceFieldData != nullptr);
Ar << bValid;
if (bValid)
{
#if WITH_EDITOR
if (Ar.IsCooking() && Ar.IsSaving())
{
check(LOD.DistanceFieldData != nullptr);
float Divider = Ar.CookingTarget()->GetDownSampleMeshDistanceFieldDivider();
if (Divider > 1)
{
//@todo - strip mips
LOD.DistanceFieldData->Serialize(Ar, Owner);
}
可以看到这里的逻辑,就是等待距离场的异步构建完成,然后将构建得到的内容序列化到各层级的LOD中。
我简单魔改验证了下,在构建linux client时,忽略如上烘培逻辑确实大大减少了构建时间。 而且和相关同学确认,该部分逻辑不影响Gameplay。
不过比较正式的方法应该是修改Cooking Target的Support Feature,初略看了下,大致在如下类进行修改:TLinuxTargetPlatform, FLinuxPlatformProperties。
手头还有其他事情要处理,有一些关于烘培的细节,后续抽时间再研究下:
23年新挖一个《Unreal随笔系列》的坑。所谓随笔就是研究过程中的一些想法随时记录;细节可能来不及考证,甚至一些想法可能也不太成熟,有失偏颇;希望读者也可以帮忙指正和讨论。这个系列主要求量,希望每个月给自己布置一些研究小课题,争取今年发满12篇。