Bake Pipeline Overview

Texturge’s bake pipeline compiles a UTextAnimationBlueprint and the given text into precomputed FBakedAnimation data. Baking happens on demand (widget initialization, text changes, after Blueprint compilation); runtime only performs efficient evaluation.

NOTE

Texturge has no font → SDF texture bake pipeline. The animation compilation pipeline processes per-glyph curve data and does not involve GPU texture generation.

Pipeline Entry Point

FAnimationCompiler::BakeAllStages() is the single entry point of the bake pipeline:

struct TEXTURGE_API FAnimationCompiler
{
    static constexpr int32 MinFramesBetweenRebakes = 3;

    using FAnimInstanceCustomizer = TFunction<void(UTextAnimInstance*)>;

    static FBakedAnimation BakeAllStages(
        UTextAnimationBlueprint* Blueprint,
        const FString& Text,
        const FAnimInstanceCustomizer& InstanceCustomizer = nullptr);
};

The third parameter InstanceCustomizer injects into the temporary bake instance (e.g. applying parameter overrides); the Blueprint CDO is never modified.

Pipeline Stages

Stage 1: Building Schedule Infos

  1. BuildScheduleInfos(Text) iterates all Unicode code points of the text, generating TArray<FGlyphScheduleInfo>
  2. Prefills each glyph’s index, string, and classification (Whitespace / Punctuation / CJK / Decorator)
  3. Classification is determined by the Texturge::Unicode utilities; surrogate pairs (Emoji) map to a single glyph

Stage 2: Blueprint Event Baking

  1. Creates a temporary UTextAnimInstance (Blueprint->GeneratedClass)
  2. If an InstanceCustomizer is passed, applies it to the temporary instance first (parameter override injection point)
  3. ProcessEvent invokes the BP-overridden BuildDefaultAnimation(GlyphCount, Text)
  4. If the Blueprint override returns an invalid result, falls back to the C++ default _Implementation:
BuildScheduleInfos(Text)
  → CreateLayer(GlyphAnimations[0], Override, Schedule)   ← base layer
  → CreateFactory(BaseLayer, Schedule)
  → for i in 1..N: Factory->AddLayer(CreateLayer(GlyphAnimations[i], Additive, Schedule))
  → Factory->Bake() → FBakedStage

Stage 3: Factory Baking (UGlyphAnimationFactory::Bake)

Bake() returns FBakedStage and runs a three-step pipeline:

STEP 1:   per-layer independent baking
          for each Layer: BakeStageWithCurves(Layer.Curves, Layer.Schedule)
          → each Glyph gets a single-layer bake result

STEP 1.5: consume Layer-level ordered tweak steps
          for each Layer: ApplyGlyphOverrideSteps(Layer.GlyphCurveOverrides)
          → execute Multiply/Divide/Add/Subtract on TArray<FRichCurveKey> in order
          → multiply/divide: Value/Tangent/Weight scaled proportionally (weighted Bezier tangents)
          → add/subtract: Value only
          → empty tracks: create identity key pairs from existing key time ranges

STEP 2:   per-Glyph per-Layer copy
          for each Glyph:
            for each Layer:
              SrcCurveSet.OffsetBy(LayerStartTime)
              FBakedGlyph.AddLayer() → FPerLayerCurves
          → curves are not merged; each layer keeps independent curve data

STEP 3:   factory-level global post-processing
          3a: ApplyFactorySchedule(Skip/StartDelay) — acts on merged Glyph StartTime
          3b: Factory.GlyphCurveOverrides baked into FBakedGlyph.FactoryOverride
              → applied once to the final blended state during evaluation
          3c: animation clipping (SetAnimationClipAt) — front/back trim (playback axis)
          → skip bIsStatic Glyphs

NOTE

Animation clipping (0.3.0): layer- and factory-level SetAnimationClipAt(FrontTrim, BackTrim) trims on the playback axis; finite loops are materialized as expansion (only the last loop is modified); fully-trimmed glyphs become static.

Stage 4: Assembling the Final Output

  1. Assemble FBakedAnimation: DefaultStage comes from BuildDefaultAnimation; IntroStage / OutroStage are nullptr
  2. Compute dual fingerprints: TextFingerprint = CityHash64(SourceText), BlueprintFingerprint (see below)
  3. Return FBakedAnimation (move semantics, supports Double-Buffer publishing)

Fingerprint Caching

FingerprintComputationInvalidation
TextFingerprintCityHash64(SourceText)text content changes
BlueprintFingerprintHash of: path name + all GlyphAnimation asset signatures (MovieScene + GetSignature() of all Tracks/Sections) + all BlueprintVisible CDO property values + StageTransitionConfig + CompileCount + GeneratedClass pointer addressBlueprint recompile / parameter changes

Key mechanisms:

  • Track/Section signature traversal: Sequencer edits only update Section signatures, not the parent MovieScene signature — fingerprints must traverse all sub-objects
  • CompileCount: a uint32 incremented on every compile, ensuring the fingerprint still changes when UE reuses compiled instances with unchanged addresses
  • Re-bake cooldown: MinFramesBetweenRebakes = 3 frames, preventing flood re-baking during parameter sweeps
  • Cache invalidation responsibility lives at the widget layer / editor preview layer (FTexturgePreviewBakeCache); the compile time does not manage cache refresh policy

TIP

After modifying parameters via SetBlueprintVariable, the fingerprint change triggers a re-bake, but subject to the 3-frame cooldown — high-frequency parameter sweeps take effect with at most a 3-frame delay.

images/bake-pipeline-flow.png — Bake pipeline flow diagram: inputs (blueprint GlyphAnimations + source text) → stage 1 BuildScheduleInfos (code point classification) → stage 2 BuildDefaultAnimation event (Layer/Factory orchestration) → stage 3 Factory::Bake three-step pipeline (per-layer bake → layer tweaks → per-glyph copy → factory post-process) → stage 4 FBakedAnimation output with dual fingerprint computation