贴图的支持及设置

对于现代游戏项目来说,贴图的大小和使用情况是对内存影响的重大因素之一。 幸运的是虚幻引擎 4 有一个健壮的系统,能够对项目中的所有贴图进行没有破坏性的缩减。 在本页中将会简单说明这些系统,以及如何使用它们来为项目减少贴图的内存占用。

贴图分辨率

只需要对某些 .ini 文件稍作改动,虚幻引擎 4 便能支持的贴图分辨率从 1x1 到 8192x8192。 目前支持 DirectX 的显卡及游戏主机支持从 1x1 到 2048x2048 并最高可能到 8192x8192 的各种贴图分辨率。 硬件设备的最高贴图分辨率根据生产商和模型不同,以及可用的贴图内存的数量不同,最高分辨率都会不同。 在虚幻引擎 4 中提供了很多功能和设置来管理渲染到不同地方的贴图分辨率,比如世界的几何体或用户界面。

引擎贴图分辨率限制

虚幻引擎 4 默认限制贴图 mip 的最大值为 14,它有效地限制了最大渲染的贴图分辨率为 8192(从 1x1 到 8192x8192 是 14 mips)。 有一个问题是当导入的贴图分辨率为 8192 时,它在进行渲染时分辨率最多达到 4096 的 mip 1。 在引擎源代码文件中的常量值 MAX_TEXTURE_MIP_COUNT 默认为 13 在做这个限制,它的值可以被改为 14 来支持分辨率 8192 的贴图渲染。 这个常量是在以下源代码文件中被定义的(从版本 QAMar09 开始,请一定要在其他的 QA 版本上进行验证)。

Src\D3D10Drv\Src\D3D10Device.cpp   
Src\Engine\Inc\RHI.h   
Src\Engine\Inc\UnTex.h   
Src\Engine\Src\RHI.cpp   
Src\Engine\Src\TextureCube.cpp

在 4.8 的版本后,已经可以无需修改 C++ 的代码便能够支持 8192 的贴图分辨率了。需要将下面这部分添加到项目的 DefaultEngine.INI 文件中,并设置 MaxLODsize8192

[SystemSettings]
TEXTUREGROUP_World=(MinLODSize=1,MaxLODSize=8192,LODBias=0,MinMagFilter=aniso,MipFilter=point)

添加完这个增加大小的文字区块后,保存文件并重启编辑器。重启编辑器后,任何以 8192 导入的贴图将会显示 8192 作为 LOD 1 的尺寸,将不在被压制到 4096。 在下面的图示中,我们在一个使用 4.8 引擎的项目中修改了 DefaultEngine.ini 文件来支持 8192 的贴图,当这个叫做 T_8K_Test 的贴图在虚幻 4 中加载时, 我们可以看到导入分辨率和显示分辨率都已经是 8192 了。

T_Getting_8K_Textures.png

压缩贴图的内存需求

DXT 是一种基于把像素放入到使用了调色板颜色和插值颜色的 4x4 块中的有损压缩。这将导致一个 8:1 DXT1 和 4:1 DXT5 的常量压缩文件大小。 由于一个特定平台和硬件的视频内存和贴图资源池是固定的,所以必须在贴图分辨率和资源分配上寻求平衡。 以下表格列出了 DXT1 和 DXT5 贴图的各种常用分辨率,并列了完整的 mip(以 1x1 为原生的 mip 0)对应。可以注意到,对内存的需求几乎是贴图分辨率比率的常量倍数, DXT5 贴图需要的内存几乎是它们的对应物 DXT1 的两倍。

因为分辨率和压缩比率的比值是常量,所以这里并没有列出贴图分辨率计算后的内存需求,其实只要简单地乘以分辨率比率即可。 比如,一个分辨率为 1024x512 的贴图所需要的内存是 1024x1024 贴图的一半。

下表中的数据来自由 ATI 的 Compressonator 使用 Box-Filter 生成的 mipmap 贴图并经过 DirectX Texture Compression 压缩获得。

分辨率 从 1x1 开始的 Mip 数量 DXT1 DXT5
16x16 5 mip 312 字节 496 字节
32x32 6 mip 824 字节 1.48kb (1,520 字节)
64x64 7 mip 2.80kb (2,872 字节) 5.48kb (5,616 字节)
128x128 8 mip 10.8kb (11,064 字节) 21.4kb (22,000 字节)
256x256 9 mip 42.8kb (43,832 字节) 85.4kb (87,536 字节)
512x512 10 mip 170kb (174,904 字节) 341kb (349,680 字节)
1024x1024 11 mip 682kb (699,192 字节) 1.33MB (1,398,256 字节)
2048x2048 12 mip 2.66MB (2,796,344 字节) 5.33MB (5,592,560 字节)
4096x4096 13 mip 10.6MB (11,184,952 字节) 21.3MB (22,369,776 字节)
8192x8192 14 mip 42.6MB (44,739,384 字节) 85.3MB (89,478,640 字节)

引擎配置的 TextureGroup 属性

游戏中特定的 TextureGroups 支持的最大和最小 LOD (mip) 定义在一些引擎配置文件中。 这些配置的源头都在文件 [Unreal Engine 4 Install Location]\Engine\Config\BaseEngine.ini 中的 [SystemSettings] 部分。

对于开发中的游戏,[your_game]\Config\DefaultEngine.ini 文件也包含了 Engine\Config\ 文件夹下的基本属性的镜像内容, 并且它通常应该是针对项目的做特定修改设置的副本。

请注意,对虚幻编辑器和游戏而言,有不同的 TextureGroup 设置集合的入口。 分别位于在配置文件文件的 [SystemSettingsEditor] 部分和 [SystemSettings] 部分。

在 BaseEngine.ini 文件中的 TextureGroup 设置项看上去和这个类似。注意:较老的 QA 版本可能不是在每个设置中都包括 MinMagFilter 和 MipFilter 属性。

[SystemSettings]
; 请注意这里的任何修改都会影响所有平台!!!

TEXTUREGROUP_World=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point)
TEXTUREGROUP_WorldNormalMap=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point)
TEXTUREGROUP_WorldSpecular=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point)
TEXTUREGROUP_Character=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point)
TEXTUREGROUP_CharacterNormalMap=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point)
TEXTUREGROUP_CharacterSpecular=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point)
TEXTUREGROUP_Weapon=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point)
TEXTUREGROUP_WeaponNormalMap=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point)
TEXTUREGROUP_WeaponSpecular=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point)
TEXTUREGROUP_Vehicle=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point)
TEXTUREGROUP_VehicleNormalMap=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point)
TEXTUREGROUP_VehicleSpecular=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point)
TEXTUREGROUP_Cinematic=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point)
TEXTUREGROUP_Effects=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=linear,MipFilter=point)
TEXTUREGROUP_EffectsNotFiltered=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point)
TEXTUREGROUP_Skybox=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point)
TEXTUREGROUP_UI=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point)
TEXTUREGROUP_Lightmap=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point)
TEXTUREGROUP_Shadowmap=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point,NumStreamedMips=3)
TEXTUREGROUP_RenderTarget=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point)
TEXTUREGROUP_MobileFlattened=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point)
TEXTUREGROUP_Terrain_Heightmap=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point)
TEXTUREGROUP_Terrain_Weightmap=(MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point)
TEXTUREGROUP_Bokeh=(MinLODSize=1,MaxLODSize=256,LODBias=0,MinMagFilter=linear,MipFilter=linear)

[your_game]\Config\DefaultEngine.ini 文件中的 TextureGroup 通常会和这个类似。注意 LOD 设置一般会由游戏本身的设计以及目标平台设置范围限制。

[SystemSettings]
TEXTUREGROUP_Character=(MinLODSize=256,MaxLODSize=1024,LODBias=0)
TEXTUREGROUP_CharacterNormalMap=(MinLODSize=256,MaxLODSize=1024,LODBias=0)
TEXTUREGROUP_CharacterSpecular=(MinLODSize=256,MaxLODSize=1024,LODBias=0)
TEXTUREGROUP_Cinematic=(MinLODSize=256,MaxLODSize=4096,LODBias=0)
TEXTUREGROUP_Effects=(MinLODSize=128,MaxLODSize=512,LODBias=1)
TEXTUREGROUP_Lightmap=(MinLODSize=512,MaxLODSize=4096,LODBias=0)
TEXTUREGROUP_Shadowmap=(MinLODSize=512,MaxLODSize=4096,LODBias=0,NumStreamedMips=3)
TEXTUREGROUP_RenderTarget=(MinLODSize=1,MaxLODSize=4096,LODBias=0)
TEXTUREGROUP_Skybox=(MinLODSize=512,MaxLODSize=2048,LODBias=0)
TEXTUREGROUP_UI=(MinLODSize=512,MaxLODSize=1024,LODBias=1)
TEXTUREGROUP_Vehicle=(MinLODSize=512,MaxLODSize=1024,LODBias=0)
TEXTUREGROUP_VehicleNormalMap=(MinLODSize=512,MaxLODSize=1024,LODBias=0)
TEXTUREGROUP_VehicleSpecular=(MinLODSize=512,MaxLODSize=1024,LODBias=0)
TEXTUREGROUP_Weapon=(MinLODSize=256,MaxLODSize=1024,LODBias=0)
TEXTUREGROUP_WeaponNormalMap=(MinLODSize=256,MaxLODSize=1024,LODBias=0)
TEXTUREGROUP_WeaponSpecular=(MinLODSize=256,MaxLODSize=1024,LODBias=0)
TEXTUREGROUP_World=(MinLODSize=256,MaxLODSize=1024,LODBias=1)
TEXTUREGROUP_WorldNormalMap=(MinLODSize=256,MaxLODSize=1024,LODBias=1)
TEXTUREGROUP_WorldSpecular=(MinLODSize=256,MaxLODSize=1024,LODBias=1)
TEXTUREGROUP_MobileFlattened=(MinLODSize=8,MaxLODSize=256,LODBias=0)
r.setres=1024x768

PC AppCompat Buckets

AppCompat 在启动时通过收集一些信息来覆盖掉 SystemSettings 中的预设值。当应用程序兼容性被启用时(仅 PC),系统会衡量机器的兼容性,然后用所谓的 5 套 “bucket” 中的一套来覆盖掉 Engine.ini 中的数值。可以进一步查看在 Engine\Config\ 目录内的 BaseCompat.ini 文件来了解如何使用。

AppCompat 应该只会在第一次运行(并非编辑器)时只检查一次。它会先检查 [game]Engine.ini 中的 [AppCompat] 区块,这个区块包含先前对这台机器的打分数值。如果 AppCompat 已经应用过的话,这部分不会被改变,避免用户的自定义修改再次被覆盖掉。

AppCompat 特意忽视了对编辑器的应用,这样做能够避免在开发阶段,不同的机器上显示资源会得到不同的效果。这也是将设置拆成了 SystemSettings 和 SystemSettingsEditor 两个文件的缘由。

也可以通过放置一个空的 DefaultCompat.ini 文件来禁用 AppCompat 功能,这个文件能够使得初始化数值直接取自 Engine.ini 中的 [SystemSettings]。这么做的话,整个系统的运作方式和引入 AppCompat 之前的行为完全一致。

贴图组(TEXTUREGROUP)属性

每个贴图组都对贴图在游戏过程中如何渲染的属性做了定义。将贴图分为不同的几个通用组能够对不同类型的游戏贴图的内存占用做更好的控制和管理。

属性 描述
MinLODSize 渲染时用的最小的 mip 尺寸,以像素定义,必须为 1 到 8192 中 2 的幂,并且必须小于 MaxLODSize。
MaxLODSize 渲染时用的最大的 mip 尺寸,以像素定义,必须为 1 到 8192 中 2 的幂,并且必须大于 MinLODSize。
LODBias A negative or positive value that determines the number of mip levels to offset prior to uploading for render, clamped within MinLODSize and MaxLODSize.
MinMagFilter Specifies the texture filter type when textures are minified or magnified by the GPU. See the chart below.
MipFilter Specifies whether the GPU should blend two mips together when viewing the texture from a distance or at a grazing angle. See the chart below.
NumStreamedMips 能够被流加载卸载的 mips 的数量。如果一个贴图有 10 个 mips,并且该数值设置为 2,那么仅两个最高级别的 mips 被允许流加载或卸载,因此任何时候该贴图都有 8~10 个 mips 留存于内存。该数值为 0 意味着该贴图永远都会被完全加载。将该数值设为 -1 意味着所有的 mips 都可以被流加载或卸载(不过这里还有其他限制会控制)。NumStreamedMips 是一个可选设置项,默认值为 -1。

过滤器

MinMagFilter MipFilter filter type
point - Point
linear point Bilinear
linear - Trilinear
aniso point Anisotropic Point
aniso - Anisotropic Linear

TextureGroup, LODGroup and LODBias

在配置文件中的 TextureGroup 和 LODBias,配合贴图属性中的 LODGroup 和 LODBias 决定每个贴图最终的 mip 使用方式。

比如在 [游戏]Engine.ini 文件中的 TextureGroup 可能是这个样子的:

TEXTUREGROUP_World=(MinLODSize=256,MaxLODSize=1024,LODBias=0,MinMagFilter=aniso,MipFilter=point,NumStreamedMips=3)

任何贴图只要设置为 TEXTUREGROUP_World 的 LODGroup,都将使用这套参数用于渲染时的 mip 范围。在贴图属性里面的 LODBias 会和配置文件中的 TextureGroup 定义的 LODBias 叠加起来计算。

mip 最终用于渲染的是 LODBias 偏差(bias) 或者 偏移 得到的。LODBias 在 LODGroup 的 Min/Max 范围之前就进行计算。在贴图属性中的 LODBias 会和 TextureGroup 中的 LODBias 相加得到最终的 LODBias 数值。 LODBias 为 0 是指主贴图分辨率(原分辨率)。LODBias 为 1 则是第一个降级的分辨率,2 则是第二个。比如一个 1024x1024 的贴图,LODBias 为 1 则采用 512x512 这一级的 mip 来渲染。

定义在每个贴图的属性中的 LODBias 可以为正数或者负数,这样能够对 TextureGroup 中默认的 LODBias 进行或高或低的调整。 比如:

  • TextureGroup LODBias 为 0 并且贴图属性中的 LODBias 为 0,最终的 LODBias 则为 0。

  • TextureGroup LODBias 为 0 并且贴图属性中的 LODBias 为 1,最终的 LODBias 则为 1。

  • TextureGroup LODBias 为 1 并且贴图属性中的 LODBias 为 1,最终的 LODBias 则为 2。

  • TextureGroup LODBias 为 1 并且贴图属性中的 LODBias 为 -1,最终的 LODBias 则为 0。

在最终的 LODBias 计算后,会再检查该贴图的 mip 以确保符合 TextureGroup 的 Min/Max 的 LODSize 范围,如果需要的话会再修正。 这样能够通过一个简单的配置文件的改动就能对特定 TextureGroup 的 min/max 的 LOD 范围进行有效的控制。

比如,一个 1024x1024 的贴图,LODBias 为 1 时使用 512x512 的 mip,如果它属于上面提到的 TEXTUREGROUP_World 的 LOD 组,便会对它进一步确认是否在该 TextureGroup 的 LODSize 的最大最小值之间,在这个例子中则是 256 到 1024。 每个游戏都应该有自己定义的 TextureGroup 的设置,美术和关卡策划应该要理解每个贴图组中的 MinLODSize 和 MaxLODSize 的设定。

贴图属性

对于贴图的各个属性的解释,请查看 贴图属性 页面。