欢迎访问循迹研究室,Github上的开源项目:github.com/hxhb以及项目介绍,热更新方案的系列文章:Unreal Engine#热更新
一些在工作之余研究和开发的技术方案与成果预览:展示柜,如果您对其中某些项目感兴趣可以发邮件到imzlp@foxmail.com

除本站外,我还创建了一个由社区驱动的虚幻引擎中文知识库站点https://ue5wiki.com/,托管在Github Pages上。欢迎投稿技术内容,为建设虚幻中文技术社区添砖加瓦!投稿规则请看:Wiki内容编写格式与规则

How to write a good technical article

技术文章是能够有效锻炼表达能力和进行技术积累的方法。与单纯的技术笔记不同,我认为的技术文章应该是对实际的问题新技术思路的解决方案,而不是技术点的简单堆砌。

对于如何写一篇我认为合格的技术文章, 最近做了一些思考,本篇文章会探讨我写文章时的一些思路和步骤,以及工具推荐和CI/CD自动化发布的实现。

阅读全文 »

ASTC texture compression analysis and efficiency optimization in UE

ASTCAdaptive Scalable Texture Compression的简称,是在移动端流行的贴图压缩方案。当平台使用ASTC打包时,UE默认使用Intel ISPC Texture Compressor压缩贴图,但它具有一些局限性,只支持8x8及以上的压缩规格,10x1012x12则不支持,如果在项目中指定它们,也是会使用8x8的规格。除ISPC外,引擎中也提供了ARM的astc-encoder压缩方式,可以支持8x8以下的规格,但默认未启用,而且引擎中的集成压缩效率非常低,在大规模资源中,使用astc-encoder压缩贴图对Cook耗时是非常大的挑战。

本篇文章分析UE中贴图使用ASTC压缩的配置以及实现方式,以及引擎中astc-encoder的压缩效率和优化思路。

阅读全文 »

Multi-stage automated resource inspection scheme in UE

在大型项目中,资源的规模非常庞大,涉及的制作团队也非常广泛,场景、角色、UI、动画、特效、蓝图、数据表格等等,随之而来就是资源量和资源规范的管理难以把控。

对于制定的资源规格,美术制作人员难以覆盖100%的情况,会存在不经意间漏掉,大多数情况下都是包内发现问题后再处理,而且对于存量的资源,需要耗费大量的人力处理,难以审查和修复。

基于这种痛点,我之前开发了一个资源扫描工具,可以方便地编辑规则对项目内的资源进行扫描。

近期,我对插件做了全方面地升级,增强了编辑时和自动化检查的能力,本篇文章会介绍如何利用ResScannerUE实现编辑时提交时CI定时或Hook任务Cook时等各个阶段的资源扫描,把错误地资源尽可能地在制作时暴露出来并提示解决,避免包内资源异常。

在插件的具体实现上,也针对扫描速度做了很多优化,尽可能把检查变成一个无感知的行为,文章内会具体介绍。

阅读全文 »

An Efficient ZSTD Shader Dictionary Training Scheme

在文章基于 ZSTD 字典的 Shader 压缩方案中,我介绍了一种利用ZSTD字典压缩UE的ShaderCode的方法,可以极大地提升ShaderLibrary的压缩比。但训练字典和使用字典进行压缩的流程仍然比较复杂,并不是一个高效的工程实现:

  1. 需关闭引擎默认的Shader压缩
  2. Cook一遍项目才能Dump每个Unique Shader的ShaderCode
  3. 基于Dump出的ShaderCode文件,使用ZSTD程序训练字典
  4. 再次执行完整的Cook过程,使用字典进行压缩,生成最终的shaderbytecode

根据上述的流程,需要变动引擎才能实现Dump ShaderCode;其次是流程的割裂,Dump ShaderCode之后需要拉起zstd程序执行训练才能得到字典;最后,仍需要再Cook一遍工程,使用训练出的字典压缩Shader。并且在关掉Shader的压缩后会导致使用LZ4压缩的DDC Cache Miss,重复Cook执行的时间开销巨大,在海量Shader的项目中耗时无法接受。

基于这种痛点,我研究并实现了一种高效的字典训练方法,无需修改引擎,并且十分快速地训练字典和基于字典压缩。能够直接从ushaderbytecode中训练字典,并生成使用ZSTD+字典压缩的ushaderbytecode,极大地提升了处理效率,完全Plugin-Only的实现,接入成本几乎为零,后续将作为HotPatcher的扩展模块发布。

阅读全文 »

A runtime reorganization scheme for Pak in Unreal Engine

Pak是UE中的UFS中的一环(Unreal File System),是在应用层构造的一种虚拟文件系统。用于把游戏相关的资源、文件打包至一个Pak文件中,避免在运行时对游戏资源的访问创建出大量的文件句柄,并且可以做读缓存(PakCache),提升加载效率。

并且,在UFS中,可以控制每个Pak的优先级,可以用来控制文件系统中文件的优先级。在通过UFS加载文件时,优先级高的Pak中的文件会被首先命中,就可以替换掉低优先级的文件,这也是UE实现热更新的关键,详见之前的热更新系列文章

但默认情况下,Pak的打包都是在UE端进行的,PakUtilitiesUnrealPak都是开发端的功能,运行时不存在,这意味着不能在运行时创建出Pak文件。但Pak本身是Archive的文件形式,理论上是可以进行运行时重组的。

本篇文章就从Pak的创建、文件格式、UFS分析、运行时重组可行性等方面着手,探讨运行时重组Pak的实现细节以及应用方向。

阅读全文 »

Shader compression scheme based on ZSTD dictionary

随着项目规模的日益增大,UE里Shader的变体数量逐渐累增,往往能够达到数百万的Shader变体,虽然UE为了避免Shader的重复存储提供了Share Material Shader Code功能,可以把Shader序列化到一个独立的ushaderbytecode文件中,但也会占用几百M的包体大小。而UE默认情况下,把这些NotUAsset文件默认进Chunk0,即必须进基础包,对于移动端的基础包影响很大,几百M的空间,可以放很多资源了。

为了解决这个问题,只能从三个方面入手:

  1. 降低项目中的变体数量,Dump出项目中的Shader信息,分析哪些是不必要的;
  2. 拆分shaderbytecode,基础包中只包含必要的Shader,其余按需下载。但UE默认没有提供这样的机制,可以使用我开发的HotPatcher拆分基础包,生成多个shader lib,使用热更流程动态下载资源和所需的shaderbytecode。
  3. 使用压缩率更高的算法来对ShaderCode进行压缩,引擎中默认使用LZ4;

第一种方式需要TA和美术协同实现,想要有显著的提升较为困难。第二种方案详见之前的热更新系列文章(Unreal Engine#热更新)。本篇文章从第三种方式入手,为Shader实现了一种特殊的压缩方式,可以有效地降低shaderbytecode的大小,大幅度提升Shader的压缩比,并且可以与方案2结合使用,在拆分shaderbytecode的同时,大幅度提高压缩率。

阅读全文 »

Efficient Debugging: Start UE Android App with command line parameters

在使用UE开发的过程中,指定命令行参数(Command Line)是一个经常会用到的功能,可以方便地控制部分流程、开关等。UE也是大量地使用了Comandline来控制引擎的行为,官方文档:Command-Line Arguments,不同的模块都可以从Commandline中读取或检查参数,实现自定义的命令行参数功能。

但是,对于移动端Android平台,并不能很方便地指定启动参数,需要编辑ue4commandline.txt文件,非常繁琐。

基于这种痛点需求,我利用元旦的假期开发一个UE的Android的插件,可以让Android的程序像PC一样方便启动和指定命令行参数,并且不需要修改引擎,启用插件后打包Apk即可使用,开源在Github上:hxhb/AppCmderUE

本篇文章分析了UE在Androdid端Commandline的读取规则,并介绍了AppCmderUE插件的实现原理与使用方法。

阅读全文 »

UE Resource Management: Engine Packaging Resource Analysis

默认情况下,在UE中打包项目时,会拉起BuildCookRun来执行Compile/Cook/Pak/Stage等一系列流程。在UE中,只有参与Cook的资源才会被打包,但是通常会包含很多预期之外的资源,可能会造成困扰,到底引擎依赖哪些资源?以及该如何管理UE参与打包的资源。

本篇文章从UE打包时分析资源进行Cook的规则入手,研究在打包时究竟会将哪些资源进行Cook,了解这一点对于资源管理很有作用,基于此可以实现自定义的Cook过程,将Cook任务分配至不同的进程乃至机器实现并行化,加速UE的构建过程。

除了uasset这些资源外,打包时还有很多Non-Asset文件,如ini、Shader Library、AssetRegistry、或者项目中添加的脚本文件等等,在之前的文章UE热更新:需求分析与方案设计中有过介绍,UE对于它们的收集并不在Cook阶段(Shader Library和AssetRegistry是在Cook阶段生成),本篇文章暂不作讨论,后续会写一篇专门介绍的文章。

阅读全文 »

My 2021 Annual Summary

我一直希望做的所有事情都是可以量化、能够被记录的,不然一年又一年循环往复会记不起自己到底做了什么事情,所以会做一个年度总结。

2021年马上结束,回想这一年,发生了许多事,有了很多新的想法,也是对我影响最大的一年。

阅读全文 »