声明:http://www.gc-conf.com/ 视频中内容笔记 2020.9.9
在UE4中创建UI时使用的UMG(Unreal Motion Graphics)可能会遇到各种问题,例如如何使用它以及面临什么样的问题。在本次演讲中,将讨论这些问题的解决方案,然后介绍有效利用UMG的更好的方法和优化方法。
Youtube视频页面
https://www.youtube.com/watch?v=x67C_RqRVrg
UE4创建的UI及优化方法
●目标
● 可以使用UMG构建有效的UI
●可以应用UI优化方法
●对象
●UMG 美术
●程序和优化工程师,TA
●范围
UE 4.25
今日主题
●设计
●布局设计 …艺术
●类设计 …工程师
●机制/内部实现原理
●生命周期 …工程师
●优化
●选项 …艺术,工程师
●调试 …艺术,工程师
首先设计部分
布局设计
布局设计后顾之忧
- 重用
- 好看
- 没有浪费
概述
●Widget窗口小部件
小型功能单元中的显示元素
●User Widget用户小部件
通过组合Widget创建的显示元素⇒Main Widget主小部件,Sub Widget子小部件
如下图解释Widget
如下图解释User Widget
布局 按钮组 攻击按钮
布局设计的挑战
●放置小部件的条件是什么?
●如何使用不同的小部件?
●如何重复使用小部件?
●如何重用动画?
问题1:放置小部件的条件是什么?
●注意放置小部件的原因
放置它,以便您可以解释使用它的原因
●请注意布局在不断变化
支持布局更改和多平台
小部件放置示例:
管理多个子Widget的图层
模糊背景(模糊效果)
将锚应用于子Widget
填充子Widget
使范围达到指定大小
用按钮填充宽度
覆盖暂停菜单上的选项屏幕
Main Widget放置示例
Switcher(切换显示对象)
Named Slot(显示在上层)
Safe Zone(可变布局显示)
Sub Widget放置示例
缩放整体
管理多个子Widget
垂直布置内容
因为弹出窗口的描述字段以固定大小显示
练习2:如何使用不同的小部件?
●可以实现功能的
选择可以实现您想要做的事情
●良好的扩展性
选择一种对更改(如添加和删除内容)有较强抵抗力的方法
●成本低
即使具有相同的功能,根据Widget的成本也会有所不同
小部件的不同用法
示例:多个子小部件的层管理
Canvas Panel vs Overlay
示例:滚动显示和操作
Scroll Box vs List View
练习3:如何重用小部件?
●扩展小部件
根据内容轻松使用Widget
●合并小部件
为您的内容创建一个新的Widget
Widget (Text Block)
[问题]
每次都需要调整文本设置
轻松设置文本字体和大小的示例
https://unrealengine.com/marketplace/zh-CN/product/umg-style-classes
停止一遍又一遍地创建按钮,滑块和其他小部件。使用此插件可根据样式类(类似于您从CSS所知的样式类)构建它们。
Widget (Button)
[问题]
更多具有相似功能和设计的按钮
例如,我想重复使用具有“OK/Cancel”选项的相同按钮...
选择并重写放置在子Widget上的共享Widget
练习4:如何重用动画?
●仅使用通用Widget替换资源
始终使用通用的Widget动画
●使用父子关系应用动画
对父Widget进行更改,例如缩放比例和颜色
动画重用
仅使用通用Widget替换资源
在共享的Widget中准备动画
例如,对于按钮,按下时的动画
通过替换放置位置上的资源,
可以播放相同的动画
共享Widget由PreConstruct设置,以反映要在Designer中覆盖的属性
更新按钮文字
更新按钮图片
● 使用父子关系应用动画
准备管理类(父Widget)以管理弹出窗口
将通用的动画放在父Widget中
向要应用动画的Widget的子项添加目标
比例更改和不透明度更改会传播到子窗口小部件
其他注意事项
●避免过度使用画布面板
●避免设置负填充
●如果要复制,请使其成为子部件,依此类推。
布局设计摘要
●注意清晰度,重用性和成本
●与您设计的UI妥协
类设计
我对类设计感到困惑
重用
复杂
分工
Widget类设计示例
UMG最佳做法
复习
创建新的小部件蓝图时,默认的父类是User Widget
User Widget类可以放置在布局中,可以添加或删除
[!] Widget Blueprint限制
●Widget Blueprint不继承Designer上的布局信息
●必须在不继承展示位置信息的情况下设计的父级子级
类设计中的挑战
●您将如何使用Widget结构?
●如何实现Widget?
●如何连接小部件?
挑战1:如何处理Widget结构?
●根据Widget的角色适当安排
了解Engine功能和类别
●创建本机类
添加特定于项目的功能以便于使用
与Widget / UMG相关的Engine类的一部分
只有至少记住这里
(除此之外,仅图像就可以了)
用户定义的Widget
可以存储child的Widget
图层可管理Widget
可以水平存储的Widget
可以存储一个child的Widget
具有独特功能的Widget
在项目中创建的Widget
您如何处理类结构?
对于ActionRPG示例
输入标签
输入按钮
注意每个颜色代表的是什么类别: 灰色Engine内置, 橙色Native,蓝色蓝图。
结构简单
Parent Class全是UserWidget
为项目添加本机类
添加的本机类是 项目特定的通用Widget
基本上,Widget是从通用Widget创建的(蓝图从native创建)
按钮Widget
通用的处理
即使添加
可以只添加更改
在项目中扩展的示例自定义文本
引擎默认文字
项目自定义文字
挑战2:如何实现Widget?
●在蓝图和C ++之间划清界限
落实责任范围
●分成尽可能小的小部件
影响工作冲突,负载等
Widget实现共享
Blueprint Class (对美术友好,给美术用)
●将控件放置在设计器中
●动画控制
●C ++提供的API
Native Class (C++) (面向工程师)
●传递数据
●复杂而昂贵的计算和处理
●与其他类和UI更新的交互通知
Widget实现共享 (Blueprint)
工人A
●Designer的内容
●Widget显示切换
●动画播放
窗口小部件实现共享(C ++)
Widget实现共享(C ++)
工人B
●触发事件
●内容信息
●BP中使用的API
Widget实现共享(C ++实现规则)
●Abstract
Native Class始终是抽象的
●NotBlueprintable
成为另一个本机类的基类
●Blueprintable
蓝图可以派生和继承的项目
挑战3:如何连接小部件?
●利用Native Class和Subsystem
您也可以直接从Widget Blueprint中引用另一个类,
子小部件应尽可能不引用其他类
对于那些想从基础知识中学习子系统的人,请单击此处。
https://www.slideshare.net/EpicGamesJapan/ue4-subsystem
通过本机类更新Widget内容
通过子系统更新Widget内容
类设计总结
●明确和区分类角色
●有效使用本机类
机制/内部实现原理部分
了解其工作原理很有用
●向Widget添加功能变得容易
●瓶颈将变得更加重要
●了解并应用优化选项
示例:UI处理似乎很繁重
就目前而言,即使我查看Unreal Insights,也不知道是什么原因造成的
如果您知道UI处理的机制
因为它在移动
UI处理似乎很繁重
(上图蓝色区域)Slate有这么大的处理负担
⇒让我们进行优化
Widget内部由两部分组成
●UWidget:(控制部分)与其他对象的交互,例如对Slate的控制
●SWidget:(显示部分)与用户的交互,例如布局和交互
简单Widget的开始和结束
Widget Lifecycle生命周期 (5个步骤)
流程和对象更改
1、Create Widget
开始生成过程 -》 与UWidget相关的UObject的生成 -》 只调用一次初始化
Create Widget 的负荷点
引用对象过多
加载时要小心
相关Widget对象加载 相关Widget对象创建
2、OnScreen Widget
向视口Viewport注册 -》 开始生成SWidget -》 SWidget生成-》 UWidget和SWidget 同步-》 施工完成(Construction Script) -》施工完成(Begin Play)
OnScreen Widget 的负荷点
有许多目标时会发生故障
考虑负载平衡进行初始化
RebuildWidget(Slate实例生成)
PreConstruct, Construct (Widget Blueprint 初始化处理集中)
3、Tick Widget
应用包含子Widget的缩放 创建包括子Widget的渲染批处理Render Batch
Tick Widget负荷点
当有许多Widget时,这往往是一个负担
使用缓存进行负载控制
扫描所有Widget并应用缩放 通过扫描所有Widget来创建渲染信息
跨线程通知渲染信息
Game Thread仅创建绘图所需的信息
⇒创建Render Thread RHI命令并传输到GPU
4、Remove Widget
从Viewport中移除 -》开始移除(End Play) -》 删除SWidget
Remove Widget负荷点
5、 Destroy Widget
进行GC
开始销毁Widget =》 删除SWidget
Destroy Widget 负荷点
注意由于GC定位的对象过多而导致的故障
销毁与UWidget关联的对象
生命周期摘要
●注意每个流程的负载点
●了解操作后,在下一章中应用优化
最后部分优化
优化
●选项
●工具
优化选项
● 绑定Bind
● Tick
● Visibility
● Widget Blueprint Option
● Text Option
● Invalidation Box
● Global Invalidation
● Retainer Box
● 资源
● 本地化
● Widget 动画
1、绑定
将值反映到Widget本质上是事件驱动的选择
●对于属性绑定和功能绑定,请检查每个帧值的更新。
资产上的绑定 事件驱动
2、Tick
●Tick实现
●由于成本高,请尽可能避免使用Blueprint Tick
●如有必要,请使用Native代码
● Tick设置
● 默认值为Auto,它将自动ON/OFF
● 当设置为Never时,Tick停止,并且以下功能受到限制。
● Widget Animation
● Latent Action
● Native Tick
● Blueprint Tick
● 补充
本机刻度何时设置为自动?
● Latent Action (Delay等)·触发
● 触发了动画
● 已实施“Blueprint Tick”事件
● 未在本机类中指定
UCLASS(meta = (DisableNativeTick))
如果您不使用Tick,建议使用meta 设置xxx
3、Visibility
Widget可见性和命中测试启用/禁用设置
●互动本身会影响性能
●有必要根据当时的情况进行适当控制
●默认设置为“Visbility(最高费用)”设置
●显示Widget时,如果不需要判断,请使用“Not Hit-Testable”。
●不显示Widget时,则Collapsed的费用是可取的
设置选项 是否显示 命中判断 布局更新 消耗高到低
4、Widget Blueprint Option
● Force Slow Construction Path
● 如果禁用,请使用Widget Template快速构建树
● 如果勾选,能够降低建筑成本和资产规模
● Support Dynamic Creation
● 禁用时,抑制资产规模而不是允许动态生成
● 如果启用,则允许通过CreateWidget()动态创建
5、Text Option
● Wrap with Invalidation Panel 带有无效面板的包装
● 能够生成Invalidation Panel并自动包装Text Block
● 在更新Text Block和Invalidation Panel之间进行权衡
● Simple Text Mode 简单文字模式
● 通过禁用文本格式,换行和位置校正处理来加快速度
● 文字功能和性能折衷
6、 Invalidation Box失效框
●功能
缓存Widget以跳过更新过程并加快速度
下图是第一帧~第五帧,不应用与不应用IB的比较:
通过应用IB减少更新处理的负担
●使用方法
使用Invalidation Box包裹目标Widget,效果会影响所有包裹的目标
●设定
启用CanCache(默认情况下启用)
应用它可以抑制不断增加的widget更新成本
应用前:
应用后:使用缓存跳过处理
7、Global Invalidation
●功能(早期版本)
●能够将失效面板Invalidation Panel缓存效果应用于整个Slate
●Invalidation Box和Global Invalidation不能一起使用
●即使更改布局,也会自动使缓存无效
●使用方法
●输入“ Slate.EnableGlobalInvalidation 1”
●只有“新编辑器窗口(PIE)”在PIE中有效
●效果验证
仅排列2000张Image的情况
即使未放置Invalidation Panel,也将缓存应用于整个Slate,从而降低了成本。
所有批处理元素均被缓存。每帧的绘画处理也被缓存以降低成本。
8、Retainer Box
●功能
在“Render Target渲染目标”上渲染并任意跳过更新过程
下图是第一帧~第五帧,不应用与不应用IB的比较:
应用RB减少了更新处理的负担
●使用方法
使用保留框Retainer Box包装目标Widget,效果会影响所有包装的目标
●设定
在阶段5(第一帧)中以5帧为周期执行更新处理时,如右图所示进行设置。
结果,如下所述,每5帧更新1帧,6帧...,并连续执行。
9、资源(Texture)
Export格式
●导出为.png / .tga,从压缩角度使用2的幂
压缩格式
●[UserInterface2D]未压缩
●通常[DXT]૾根据用途进行更改
●纹理组Texture Group使用[UI]
α 透明通道
●由于资源量大,请仅使用必要的资源。
●如果您想仅使用淡入淡出效果来应用半透明,可以使用Widget功能
Texture Size
● 调整纹理大小,以使纹理不占用内存
● 请勿为小型或不重要的显示器分配较大的尺寸
Mips
● 如果纹理分辨率与目标不匹配,则显示[No Mip Maps]
● 减少要使用的纹理时的[From Texture Group]
10、native化
将Widget Blueprint native化是有效的...?
优点
●减少UObject并改善负载和GC时间,其效果取决于实现方式。
●CPU处理受益于降低蓝图访问成本
缺点
●增加大小,包括native代码
●Widget中的复杂问题隔离
UObject(如变量)不会更改,从而影响BP(如宏)
本地化之前 本地化后
11、小部件动画
●迄今为止的挑战
●复杂动画的评估成本很高
●带有实例化动画的长时间加载
●提高点
●UE4.22:通用Widget Animation
●UE4.25:替换的UProperty→FProperty
●4.22或更早版本(对象数量大) 添加两个按钮变化
●4.22或更高版本(减少的对象数量)
小部件动画的过渡和UObject的数量
案例1:没有动画的状态
案例2:添加一个动画
案例3:添加一个动画和一个Transform轨道
添加动画和轨道会增加成本
添加动画和轨道时对象数量的变化(UE4.24)
12、引擎版本和UObject过渡
什么是版本转换?
对象数量减少40%,尺寸减少50%
趋势取决于Widget的数量?
即使Widget的数量与以前相比增加了,对象数量减少了54%,尺寸减少了71%
由于引擎版本的更新,添加了动画的Widget的对象数发生了变化
13、调试
● 性能评估
● Stats
● Unreal Insights
● 确认设定
● Widget Reflector
● Asset Audit
● 运动追踪
● Slate Debugger
● Debug Tools
调试
控制台命令:Stat Slate
●命令以衡量与板Slate相关的效果
●将增加统计数据的费用,因此这只是一个指导
●但对于识别瓶颈点很有用
Stat Slate
布局更新过程
⇒许多显示对象(几何形状)
元素添加处理
⇒许多批处理
调试
Unreal Insights
●分析应用程序性能
●还可以捕获特定于Slate的事件(“Stat Slate”的目标)
布局更新过程
⇒许多显示对象(几何形状)
Tick处理
⇒有许多Slate正在Tick
调试
Widget Reflector
●一种用于捕获和分析正在使用的资源和设置的工具
https://qiita.com/EGJ-Ken_Kuwano/items/523c97697563751bcc71
Widget Reflector是与Widget相关的调试的有效工具之一,并具有多种功能。
●您可以查看Widget和Slate设置的信息以及当前用于显示的资源。
●您可以通过查看Slate设置来使用它,以查看是否已应用性能分析或优化。
●当您使用它来反向查找Slate实现以供引用时,它也很有用。
●您可以使用字体图集和纹理图集的功能检查加载的资源。
调试
资产审计Asset Audit
●列出资产信息以进行确认的工具
Tick驱动预测
⇒是否运作正常?
Property Bind数
⇒ 更改为事件驱动方法?
调试
控制台命令:SlateDebugger.Start
●焦点转换,捕获,输入事件等。
将Slate事件输出到日志
调试
Debug Tools
●提供与Slate相关的各种调试功能的工具
Test Suite
相关链接
●
UMG (Unreal Motion Graphics) 最佳实践https://docs.unrealengine.com/ja/Engine/UMG/UserGuide/BestPractices/index.html
●官方博客
●官方幻灯片
UMG猫 https://www.slideshare.net/EpicGamesJapan/umg-80334310
●UE4 ANSWERHUB
信息共享:UMG会议资料https://answers.unrealengine.com/questions/833990/view.html