本篇文章搬运自我自己的博客,原文链接:
https://imzlp.me/posts/8470/imzlp.meUE在打包时默认使用Zlib
作为资源的压缩算法,但是从压缩率和解压速度来看它并不是最好的选择,可以从Squash Compression Benchmark去看各种压缩算的效率对比,我选择了facebook开源的ZStandard作为替换Zlib的压缩实现,因为ZSTD在保证压缩比的同时还具有不错的解压效率。 本篇文章并不只是讲怎么在UE里集成一个压缩算法,还会简单介绍一下UE里的一些功能的模块化组织方式——ModularFeature
,使用这种方式可以比较方便地替换某些功能的实现,本文中的替换压缩算法是一个实践。
我在UE中集成ZSTD的方式是写了一个插件,源码集成,开源在Github上:hxhb/ue4-zstd,支持Android和Windows(iOS和Mac还未测试),欢迎Star。
写在前面
其实ZStandard在考虑压缩速度的情况下和zlib的压缩比是差不多的(zstd的compression level为10
左右),但是zstd解压更快。zstd的压缩level为1~22
,默认情况下为3,我写的插件中默认Level为10
,可以通过启动引擎时指定-zstdlevel=
参数来指定(如果编译了UnrealPak也可以通过修改项目设置的Pacakge
-PakFileCompressionCommandlineOptions
的-zstdlevel=
参数来指定)。
ModularFeature
UE中所有的ModularFeature的实现都要继承自IModularFeature
,它内部没有任何成员,只是作为一个通用类型。可以从 ModularFeature
的组织方式由IModularFeatures
类来管理(默认实现为FModularFeatures
),它提供了注册/取消注册/根据名字获取IModularFeature
的实例,它本质上实现的功能是把一个Name与一堆实现对应起来,比如UE内的压缩算法都是属于COMPRESSION_FORMAT_FEATURE_NAME
的,它对应这一个数组,里面的每一个元素都是一个压缩算法的实现,这样就可以根据我们的需求来随意指定使用哪一个压缩算法。
// Runtime/Core/Private/Features/ModularFeatures.cpp
void FModularFeatures::RegisterModularFeature( const FName Type, IModularFeature* ModularFeature )
{
ModularFeaturesMap.AddUnique( Type, ModularFeature );
ModularFeatureRegisteredEvent.Broadcast( Type, ModularFeature );
}
可以看到注册一个ModularFeature
就是往一个Map里添加元素,注意ModularFeaturesMap
不是普通的TMap
,它是TMiltiMap
,允许一个key对应多个value。
具体的流程为:
- 在UE的Module加载时把我们缩写的
ModularFeature
注册到IModularFeatures
中; - 在使用的时候就可以根据我们的
ModularFeature
类别的名字来查找某个ModularFeature
的所有实现; - 之后就可以通过自己定义的接口来调用
ModularFeature
实现的功能了。
注意IModularFeatures::GetModularFeature
是通过模板实现的,可以做到直接获取到某个Feature类别的具体类型。
指定压缩算法
首先先来看一下UE中怎么替换打包时使用的压缩算法:
打开Project Settings
找到Packing
-Pak File Compression Format(s)
:

它是一个FString类型,可以输入一串字符串,使用逗号分隔,如果指定了多个,则该列表将按优先级顺序排列,并在格式错误或不可用(未启用插件等)的情况下回退到其他格式。
该字符串用于传递给UnrealPak
的-compressionformats=
参数。
// Programs/AutomationTool/Scripts/CopyBuildToStagingDirectory.Automation.cs
string CompressionFormats = "";
if (PlatformGameConfig.GetString("/Script/UnrealEd.ProjectPackagingSettings", "PakFileCompressionFormats", out CompressionFormats))
{
CompressionFormats = " -compressionformats=" + CompressionFormats;
}
在模块PakFileUtilities
中,默认使用的是ZLib
压缩算法。
// Developer/PakFileUtilities/Private/PakFileUtilities.cpp
FString DesiredCompressionFormats;
// look for -compressionformats or -compressionformat on the commandline
if (FParse::