/images/avatar.png

Papalqi

UE4 TextAssetFormat

需求:常常多人修改一个资源如何做到不锁资源多人协作。 方向1. 能够进行类似文本不同资源的diff合并 方向2,将资源解耦,将常常需要修改的部分单独作为一个资源。 方案一:使用TextAssetFormat方案 我们在 Editor preference 中搜索 Text Asset Format​。可打开配置 然后在资产右键​ Asset Action 可以 export to text format 保存成 utxt 格式的文件。 在资产被引用时,如果对应 uasset 后缀名不存在,则会去搜索 utxt 后缀名并加载。如果不被引用是不会加载的。 我们一个Uasset在内存中是一个UPackage的数据结构,其结构如上。对于大部分数据来讲。其明文存储的东西其实是它的File Summary和它的结构数据。但是所有走序列化的数据都是在一个数据块中,例如如下一个Montage: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 { "Exports": { "AM_Dunan_ComboXFinish02:ActAnimNotify_AutoTrace_2": { "__Class": "Class /Script/X21.

UE4 从UProperty到FProperty

UE4 在4.25中,进行了一些非常重要的改进。 其中就有FProperty。 一.老旧的结构体系 UE4中带有前缀U的类是UObject派生类。每个UObject都有一个与之对应的UClass,这个UClass保存了所有的反射系统相关的信息,描述了各个Property之间的内存布局和关系;通过UClass可以遍历所有的序列化属性;通过Object对象的实例化地址就可以将相应的Property的值取出来,进行读写操作。 UClass保留了这个对象的结构信息。它在内部拥有成员的元素列表,例如UFunction,UEnum,UProperty等。它们一起作用来提供“反射”机制。从命名不难看出UClass 和下文中的UProperty,都是从UObject继承而来,主要是为了使用Object的GC功能。 UProperty将变量定义为类的组成部分。这也是我们这次的重点内容。 不管我们是在蓝图中还是在C++中,属性都是由我们的UProperty来指定的。这些属性包括蓝图变量和节点,以及执行节点的返回值。 二.反射 我们将C++编译成exe文件。编译器将C++中的信息翻译成了机器语言。我们本身的函数名称在编译时将会被替换和省略。因此你不能在自己的程序中使用字符串"HogeHogeFunc"来处理任何事情。反射是静态或者动态的去构造这一映射信息,并且在运行时使用他们。UE4是静态反射的。 在UE4中,我们在通过他特殊的宏,将所需要反射的数据进行标记,从而自动的生成供运行时查询的信息。 从而其生成了一些额外的信息。 三.反射案例 四.FProperty 在创建类时,会生成大量属性,包括蓝图类。有些类型将可能有几十万多个UProperty,因为所有的UProperty继承自UObject,因此会产生各种各样的开销。这一特性对整个引擎影响及其广泛,包括额外的内存空间,UProperty构建/销毁成本,垃圾回收性能。 从4.25开始,此UProperty已完全更改为FProperty。 前缀“F”说明其不再继承UObject。UProperty类的定义仍然存在,但它只用于在将早期版本中创建的资源转换为FProperty做一次。 这是4.24的继承关系。 这是4.25的继承关系 由于Field与UObject和UField大多数函数拥有相同的名称,因此当您更新引擎时,只需将其从UxxProperty重命名为FxxProperty即可。 五.改善点 内存消耗减少 在整个应用程序中使用的UObject中内存占用中,Property占40%以上,根据情况也有超过60%的程度。特别是在包含多个函数调用的蓝图很多的情况下。在ThirdPersonTemplate中,UE4.24的UObject合计有5万多个,其中70%左右是Property。这些消耗直接没了。 由于继承了UObject,因此每个属性不再需要超过100个字节的额外内存。 虽然每个容量都是微乎其微的,但由于数量众多,有时会减少数十MByte或更多的内存使用量。 使用宏调用8个BoolProperty返回值的函数2304次。 如前所述,由于不适用NewObject而是C++的New和Delete,因此生成和销毁特性也变得简单和快速。同样,您还可以缩短应用程序的启动时间。 六.结论 4.25 UProperty变成了FProperty 继承UObject后的开销不见了 提高了引擎启动时间 GC处理时间明显改善 内存使用量的减少 打包后包体体积减少

UE4 UBT 解析

一. 调试UBT 打开项⽬的默认的构建命令⾏ 可以获得如下的 BuildCommandLine 1 ..\..\Build\BatchFiles\Build.bat -Target="ActionRPGEditor Win64 Debug" -Target="ShaderCompileWorker Win64 Development -Quiet" -WaitMutex - FromMsBuild 这⾥的 Build.bat,是可以直接换成 UnrealBuildTool.exe 的,如果你打开 Build.bat 查看内容,会发现⾥⾯的多数内容就是如何⽤ C# 构建⼀个 UnrealBuildTool.exe,然后调⽤这个 UnrealBuildTool.exe。 所以我们把 UnrealBuildTool 作为启动⼯程,然后启动命令⾏改成上⾯的 Build.bat 的命令⾏,就可以启动 UnrealBuildTool 的调试,如下图: 1.1启动调试 因为不知道 main 函数在哪⾥,这⾥有两种常⻅的调试⽅式 ⼀、直接按下 F11 启动,代码会⾃动停在 Main 函数的第⼀⾏,如下图 ⼆、通过 Attach 的⽅式调试,这种⽅式⼀般⽤于⼆段甚⾄三段启动的程序(也就是⼀个 exe 启动另⼀个exe,我们⽆法控制 F11 的位置,典型的就是UBT会启动 UHT的exe) 我们找到Main函数,然后在写下如下代码和断点,这样任何⽅式启动程序(包括⼆段启动)都⼀定会进⼊死循环。 Attach到⼀个进程上,此时断点⼀定会停在死循环⾥⾯。 通过运⾏时修改内存的⽅式,把死循环解开,⽐如这⾥的把 i 改成 1。接下来就可以愉快的调试了。 二. 文件结构 Module 是构成 Unreal 的基本元素,每一个 Module 封装和实现了一组功能,并且可以供其他的 Module 使用,整个 Unreal Engine 就是靠各个 Module 组合驱动的。我们创建的游戏项目本身,就是一个单独的Module。

[译]Low-level Thinking in High-level Shading Languages

很多聪明人写的代码,本可以以更好的方式编写。 偶尔我会听到“这是未优化的”(this is unoptimized)或者这只是个“例子”(educational example)作为借口,但大多数时候这个借口都不成立。因为他们其实不知道如何做到正确。 此外,供应商的SDK示例中的代码也不总是正确的。当最优秀的牛人都做得不好时,这是一个行业的问题。 1 (x – 0.3) * 2.5 = x * 2.5 + (-0.75) 很久之前,我们需要写汇编,从2003年之后的一切都是HLSL或者GLSL。这当然是一种进步,我们使用更高层次的抽象语言进行shading。这没毛病,但是,随着硬件与我们正在使用的抽象内容之间的差距的扩大,人们与硬件失去联系的风险就越来越大了。如果我们只看到HLSL代码,而从来没有不知道GPU运行的是什么,这将是个严重的问题。本文要传达的信息是,在使用高级着色语言时保持低级别(Low-Level)心态对于编写高性能着色器至关重要。 这表现的很清楚,为什么我们应该使用低级别的思考。我们只移动一些东西,加一些括号,就能实现一个更快的着色器。这是通过理解底层硬件并将HLSL构造映射到它从而来实现的。 本文使用的硬件是Radeon HD4870((用于生成最易读的反汇编代码)),但本文中的大部分都是通用的,除非另有说明否则适用于任何GPU。硬件之间具有诸多的不同。 即使您没有观察到特定GPU的性能提高,也有可能对其他的GPU有所提升。GPU有大量的ALU。如果我们将ALU的利用率从50%降低到25%,这却并不一定能够提高性能。因为同时其会受到其他因素的限制(贴图和内存带宽等)因此可能不会提高性能,但可以让你降低功耗,并且为新feature留出更多空间。最后如果你解决了TEX/BW,会给你带来相对于的收益。 “编译器将优化它” 编译器不懂你的思想。编译器只理解着色器中的操作的语义。他们不知道你在努力完成什么。许多可能的优化都“不安全”,因此必须由人来完成。 他们没有整张贴图数据 他们只有有限数据 他们不能打破常规 这可能认为的最简单的代码示例,您可能认为它可以自动优化为使用MAD指令,而不是ADD+MUL,因为这两个常量都是立即数。 然而编译器并不是这么想的。 驱动程序仅限于传递的D3D字节码的语义。最终在GPU上执行的代码就是你写在着色器上的内容!大多数情况下你可以在PS3看到一样的结果。但是上面这种情况例外,可能是因为那里的常数为1.0f。其他的情况都不会变为MAD。 Xbox360着色器编译器很有趣。 它什么都不在乎。 即使你明显破坏了数字,你也会一直做这个优化。 即使它导致常量溢出或下溢为零,也无关紧要。 如果上述式子中1的位置是一个常数,GOGOGO。上车,直接优化 如果上述式子中1的位置是0,这样的话MUL不就好了吗? 太棒了! 所以当然会产生很多小误差。 如果在此转换中丢失了许多浮点数精度,则不会立即注意到为什么会发生这种情况。 我们在这里处理IEEE的浮点数。更改操作顺序并不安全。如果你运气好,你会得到同样的结果。 改变顺序更可能会提高精确度。但是,根据数值的不同,并不总是行得通。 在最坏的情况下,它可能会被上溢或下溢破坏,或者如果不进行优化,它可能会在正确运行的部分返回NaN。一般来说,编译器擅长于:移除死代码,消除未使用的资源,折叠常数,寄存器分配,代码调度;但通常不会:更改代码的含义、中断依赖关系、违反规则。 例如我们的x = 0.2f sqrt(0.1f * (0.2f - x)) ,returns 0 sqrt(0.02f - 0.1f * x) ,returns NaN 这种差异是因为第二个表达式将非常小的负值传递给sqrt。 请记住,0.

蓝图的一些细节

一些基本的Ctrl和Alt类似的基本操作就不说了。 快捷键T可以防止我们选中透明物体,当有大量的雾气或烟雾并且干扰对象选择时,可以使用此功能。 蓝图书签功能 当您按下☆图标时,将显示[新书签]注册框,输入书签名称即可。 这将帮助你快速阅读蓝图和进行跳转。 具有快速跳转功能的蓝图迭代 在[编辑器首选项]-> [常规]-> [键盘快捷键]的“图形编辑器”中指定。 您可以使用Ctrl + N(N:数字键)进行保存,并使用Shift + N(N:数字键)进行移动。 使用快速跳转移动如果已经使用Ctrl + 1,Ctrl + 2,Ctrl + 3保存了蓝图视图,则可以输入Ctrl + 1,Shift + 2,Shift + 3到达你保存时的地方Ctrl +N。。 蓝图宏的开销 宏以与C ++宏相同的方式替换节点。其特征是宏的节点在宏节点所在的位置扩展。与函数不同,除非放置了节点,否则不会对其进行编译。放置的节点像内联函数一样展开,因此调用它的成本应比调用函数的成本低。 仅添加矢量的函数和宏就是这样。 宏为321毫秒,函数结果为392毫秒。宏仍然更快,但是它可能没有您所关心的那么大。由于包括了逻辑的复杂性,函数和宏之间的速度差异变得更加明显。当然,这种加法会产生这样的差异,因此,如果它成为复杂的逻辑,则可能会出现明显的速度差异。 在UE4中,当您双击BP节点时,Visual Studio(或Xcode)将自动启动并打开实现该BP节点的代码。 当您想详细了解如何使用节点和处理内容时,这很方便,但是说实话,有时在不使用BP的情况下意外双击就可能导致Visual Studio在未经许可的情况下启动. 在这种情况下Navigate to Native Functions from Blueprint Call Nodes,让我们禁用编辑器设置!即使双击该节点,Visual Studio也不会在未经许可的情况下启动! 拉直连接和左对齐快捷方式 如果像我一样,希望将蓝图组织得井井有条,您可能已经知道“拉直连接”工具,该工具可让您在选定节点之间建立直连。 不幸的是,默认情况下,此选项没有快捷方式,但是经过深思熟虑的UE4允许您定义一个。我将说明如何进行这些简单的步骤,并在以后节省大量时间。 首先,我们需要进入Editor Preferences,然后进入Keyboard Shortcuts部分。在此处,我们将在搜索栏中输入“straig”以查找与“拉直连接”命令。可以设置两个绑定,个人而言,我只在H键上设置了一个(它既快速又易于使用,并且尚未绑定到其他东西)。 然后,我们可以使用我经常使用的“向左对齐”选项进行相同的操作。就个人而言,我将其绑定到V键。 现在,一切就绪。我们可以在图形编辑器中对其进行测试。只需选择要排列的节点,然后按H(如果要水平对齐节点)或按V(如果要垂直对齐节点)。 编辑器蓝图组件 Asher在他的Inside中就是用这个功能做了自己的高度雾的生成工具。 创建一个小部件。首先,我们需要创建一个类型为Editor Widget的新资产。对于此示例,我们将仅制作一个小的“ Hello World”按钮。编辑器小部件窗口应如下所示: 在小部件的事件图中,我们添加以下简单行为: 运行小部件。这个小部件非常简单,但是它显示了为编辑器创建UMG小部件的主要原理。现在,我们要对其进行测试。 当我们单击按钮Hello World时:在视口中将看到日志行“ Hello World”。假设我们处于编辑器上下文中,则可以调用任何编辑器函数。

关闭双击蓝图跳转VistualStudio

在UE4中,当您双击BP节点时,Visual Studio(或Xcode)将自动启动并打开实现该BP节点的代码。 当您想详细了解如何使用节点和处理内容时,这很方便,但是说实话,有时在不使用BP的情况下意外双击就可能导致Visual Studio在未经许可的情况下启动. 在这种情况下Navigate to Native Functions from Blueprint Call Nodes,让我们禁用编辑器设置!即使双击该节点,Visual Studio也不会在未经许可的情况下启动!

UE4 VirtualTexture 源码解析

一.基础、原理和使用 Unreal最早从2017年就开始进行VirtualTexture功能的研发工作。4.17版本初次的提交,4.23 版本正式放出SVT和RVT,4.26 版本推出Adaptive VT。 按照使用上的不同,在引擎中一共有四种不同的VT类型 UVirtualTexture2D直接是继承于UTexture2D的,是最普遍上的的VT类型。 ULightMapVirtualTexture2D跟 UVirtualTexture2D没有什么太大的区别,主要是使用在LightMap中使用。 URuntimeVirtualTexture,RVT,后面会讲到其最终的用法。 如果RVT勾选了Adaptive,那么RVT则会变成AdaptiveRVT。 大致上我们按照生成的时机不同,主要分为两种VT的格式。UVirtualTexture2D和ULightMapVirtualTexture2D叫做SVT(Streaming Virtual texture)。而URuntimeVirtualTexture和他的衍生类别AdaptiveRVT称之为RVT((Runtime Virtual texture))。 1.1Streaming Virtual Texture VT功能并不是UE4引擎默认开启的,如果我们想要使用Virtual texture ,需要在项目设置中设置Enable Virtual Texture Support。而勾选Enable Virtual texture lightmaps,则会将我们的Lightmap变为VT形式。 1.1.1 普通贴图转换为Virtual Texture 当我们重启编辑器后,我们可以把之前普通的贴图右键点击转换为VirtualTexture。使用这种方式编辑器将检索与之相关的材质使用。会将会改变使用到这张贴图的材质的采样方式。 多选批量转换当然也是支持的。 我们也可以在贴图的设置中去设置这张贴图是否是VirtualTexture。 不过,这样我们就必须手动的去调整材质里对于VT的采样方案。不然材质会报编译错误 1.1.2 导入为VirtualTexture 之前的操作是把项目中已知的贴图进行转换,当我们想要新增贴图时,由于贴图的大小限制,我们可以把一张超大的贴图切割开,然后同时导入多张texture ,如果他的命名规则如下图所示那么他就会按照UDIM多象限UV进行排列并且识别为VirtualTexture。 当然,如果我们只是导入一张贴图的话,会根据项目中的配置来进行判断,分辨率如果大于这个设置,将会转换为VirtualTexture。如果比这个小的话,将视为普通的贴图处理。 1.2 Virtual Texture的目的 在这里我们希望去讨论VT的实现目的。假设我们的游戏画面是静止不动的,并且如果我们能够实时创建这么一张贴图来显示我们的场景,我们假设屏幕分辨率是1920x1080 ,用RGB8来进行存储。 920x1080x3 =6075KB≈5.93MB,(显存利用率) 也就是说,我们显卡的显存只需要用 6MB 就完全够了。这种极端的情况用现有的硬件实现起来恐怕不太现实。这种情况很难在一个动态的场景中实时的去做到,但是即使是有一些cache的冗余数据,就算到了100倍的冗余,其空间使用也小于我们目前的Texture Pool的大小设置。 因此,Virtual Texture的基本思路就是:把能看到的贴图才加载进来,没看到的不加载;进的精度高,远处的精度低。如下图所示,如果我们只把看到的部分(高亮的部分加载进来)那么内存占用上将大大减少。 从中我们可以看出Virtual Texture实则是解决我们空间存储的问题。世间所有的炼金术都遵循等价交换,你既然节省了空间,那么你的时间消耗则会增加,这是一个以时间换空间的技术:在每个Tile动态加载卸载的过程中和VT采样时都将产生额外的性能开销。因此我们是否需要开启,将哪些贴图进行开启,都是一个值得权衡的问题。而不是无脑的去使用。 既然解决的是贴图的内存管理问题,其跟传统的基于Mipmap的贴图和可见性的Texture Streaming管理是不同的。传统的StreamMgr只会根据可见性和对应的Mipmap来进行流送的处理,也就是说我们并不能对单张贴图的某一部分进行更为精确的控制,也就是有了过多的冗余信息。例如我只看到了一个贴图的一个角落,却要把他整个都加载进来。 而VirtualTexture 这种将整个Texture分为Tile 的方案,则考虑了这一冗余数据的处理。VT的劣势也很明显,在镜头剧烈变化的时候,其会不停的进行加载卸载的操作,如果配置不当会导致明显的帧率问题。 1.3 Runtime Virtual Texture 首先我们将解释一下RVT(Runtime Virtual Texure) 和普通的SVT(streaming Virtual Texture)的区别。RVT是一张动态在场景中获取的VT,因此所有的数据并不需要存储在硬盘中,而是在我们需要某一块时(相机看到的时候)直接渲染出来。