性能分析与调试
Texturge 是 CPU 驱动的动画求值系统。21 通道逐字形逐图层曲线求值构成主要开销。理解热点路径与性能模型有助于在高负载场景保持帧率。
性能模型
曲线求值成本估算
每帧的动画求值开销近似为:
总求值次数 ≈ 字形数 × 图层数 × 非空通道数(≤21)
典型场景示例:
| 场景 | 字形数 | 图层数 | 每帧非空通道求值(估) |
|---|---|---|---|
| 简单打字机 | 50 | 1 | ~1,050 |
| 多图层标题 | 30 | 3 | ~3,000 |
| 富文本对话 | 100 | 3 | ~10,000 |
实际开销远低于公式上限,因为:
- 空通道跳过——
FPerLayerCurves::Evaluate仅对NumKeys > 0的通道求值 - 静态字形跳过——
bIsStatic字形直接返回DefaultState,零曲线求值 - 尚未开始 / 已结束字形——
HasStarted/HasFinished提前退出
热点路径
FBakedGlyph::Evaluate 是动画求值的核心热点:
bIsStatic→ 返回DefaultState(零开销)LocalTime < 0(未开始)→ 返回恒等状态(仅bHideFirstFrame时透明)- 遍历
LayerCurves,调用FPerLayerCurves::Evaluate FPerLayerCurves::Evaluate对非空通道:临时构建FRichCurve(BuildRichCurveFromKeys)→Eval(LocalTime)→ 按 BlendMode 组合
性能关键点:
- 曲线键在编译期预烘焙为
TArray<FRichCurveKey>,运行时无曲线解析开销 BuildRichCurveFromKeys每次求值构建临时FRichCurve——大文本 + 多层时可累积(已知技术限制,未来优化方向:缓存 + 脏位或直接对排序 keys 二分搜索)- 编译在需要时完成,运行时零烘焙开销
Unreal Insights 通用分析
Texturge 未注册自定义 Trace 通道与控制台统计命令,使用 Unreal Insights 的通用 CPU 采样分析:
- 启动 Trace 录制(控制台
Trace.Start,或 Unreal Insights 会话启动) - 运行动画场景至少 5 秒收集样本
Trace.Stop停止,在 Insights 中打开.utrace- 按
CPU时间线放大动画播放时段,定位UTextAnimationStageController::TickAnimation、FPerLayerCurves::Evaluate、SlateOnPaint的调用栈占比
分析优先级:
- 检查
TickAnimation总耗时占比;超过 2ms/帧需深入 - 展开求值调用栈,确认是否因字形数 × 图层数过大导致
OnPaint耗时高时,检查是否同时渲染大量UAnimatedTextBlock控件(合批问题,见《性能最佳实践》)
指纹缓存
机制
FAnimationCompiler 使用 CityHash64 计算双指纹(uint64):
| 指纹 | 计算内容 | 缓存命中条件 |
|---|---|---|
TextFingerprint | CityHash64(SourceText) | 文本未变化 |
BlueprintFingerprint | 路径 + 所有 GlyphAnimation 资产签名(MovieScene + Track/Section GetSignature())+ BlueprintVisible CDO 属性值 + StageTransitionConfig + CompileCount + GeneratedClass 地址 | 蓝图未编译、参数未变化 |
缓存失效时机
- 文本内容改变 → 文本指纹变化 → 触发重新烘焙
- Sequencer 中编辑
UGlyphAnimation曲线 → Section 签名变化 → 蓝图指纹变化 - 蓝图编译(含变量修改)→
CompileCount递增 → 指纹变化 SetBlueprintVariable参数修改 → CDO 属性值变化 → 指纹变化
重烘焙冷却
MinFramesBetweenRebakes = 3——参数扫频(如逐帧修改变量)时,最多 3 帧延迟生效,防止洪水重烘焙。缓存失效决策在控件层 / 编辑器预览层(FTexturgePreviewBakeCache),编译期不负责刷新策略。
数据规模建议
| 规模 | 建议 |
|---|---|
| 每控件字形数 | ≤ 500(单行文本常规规模);超长文本拆分多控件 |
| 每字形图层数 | 2~4 层足够绝大多数效果(预设库默认 ≤ 3 层) |
| 同屏动画控件 | ≤ 8 个富文本路径控件(多条目同时播放开销大) |
| 循环动画 | 使用层 NumberOfLoops 或控制器循环,避免逐帧重建 |
TIP
性能优化优先顺序:减少字形数(
SkipAt跳过空白)→ 减少图层数 → 减少非空通道数(删除未使用轨道)→ 合批控件。