Blend Modes Reference

Texturge Beta defines blending between every glyph animation layer through the ETextAnimationBlendMode enum. Blending executes per channel in FPerLayerCurves::Evaluate; each FBakedGlyph holds a layer-organized TArray<FPerLayerCurves> (each layer with its own BlendMode).

Mode Overview

Enum valueNameBehaviorTypical scenario
Additiveadditive blendingcurrent layer value added to the accumulated resulteffect stacking (shake + swing)
Overrideoverride blendingcurrent layer value replaces the accumulated resultmutually exclusive style switching / base layer
Multiplymultiply blendingcurrent layer value multiplied with the accumulated resultintensity modulation (fade × bounce)
CrossFadecross fadeinterpolates with the accumulated result at a fixed weightblend transitions

Per-Mode Details

Additive

Result[channel] = Accumulated[channel] + CurrentLayer[channel]
  • Later layers accumulate on top of all previous layers
  • Suitable for combining multiple effects; multi-layer Additive is the common combination pattern in the preset library (Bounce / Shake etc.)

NOTE

Multi-layer Additive accumulation can push values beyond reasonable ranges; control amplitudes in your animation curves.

Override

Result[channel] = CurrentLayer[channel]
  • Completely replaces the accumulated result
  • Usually used as the base layer (specified in CreateLayer); later layers use it only when full replacement is needed

Multiply

Result[channel] = Accumulated[channel] × CurrentLayer[channel]
  • Scales or attenuates upstream layer effects
  • Channel value 1.0 leaves the upstream result unchanged; 0.0 fully eliminates it

CrossFade

Result[channel] = Lerp(Accumulated[channel], CurrentLayer[channel], 0.5f)

Per-Channel Evaluation Semantics

FPerLayerCurves::Evaluate(float LocalTime, FGlyphAnimationState& InOutState) processes every curve channel independently:

  1. Empty channels skipped — channels with Keys.Num() == 0 do not participate, preserving existing InOutState values. This guarantees no cross-layer contamination: Layer[0] has ScaleX but no Opacity, Layer[1] has Opacity but no ScaleX → final ScaleX comes from Layer[0], Opacity from Layer[1]
  2. Non-empty channels first build a temporary FRichCurve, Eval(LocalTime), then combine by this layer’s BlendMode
  3. Combination proceeds layer by layer starting from FGlyphAnimationState::Identity()

Per-layer combination example:

OutState = Identity()
Layer[0] (Override)  → OutState.PositionOffset = (10, 0),  Scale = (1, 1)
Layer[1] (Additive)  → OutState.PositionOffset += (5, 5)   → (15, 5)
Layer[2] (Multiply)  → OutState.Scale *= (1.2, 1.0)        → (1.2, 1)
Final: PositionOffset=(15, 5), Scale=(1.2, 1)

NOTE

A single FPerLayerCurves has only one BlendMode (applied to all non-empty channels); there is no per-channel independent BlendMode. Split into multiple layers when different blending semantics are needed.

Tint Channel Stacking Rules

Color channels (Color / ShadowColor) blend differently from other channels:

  • The tint identity is Transparent (0,0,0,0); applying the multiply rule 0 × anything = 0 would permanently tint black
  • Therefore tint channels use additive stacking: Base.Color += Layer.Color (consistent with the bake pipeline, fixed in 0.4.0)
  • Multi-layer tinting controls intensity through the A channel (tint share): A=1.0 fully tinted, A=0.5 1:1 with the text color

Visual Comparison Table

ScenarioAdditiveOverrideMultiplyCrossFade
Offset stackingshake + swing → compound offsetkeep swing offset onlyshake × swing → reduced offsetfixed 0.5 interpolation
Color blendingtints stack → brighter/strongerkeep top tint onlynot applicable to tint (identity-0 trap)fixed 0.5 interpolation
Scale modulationscale up + down → cancel outkeep down-scale onlyscale up × 0.5 → half scalefixed 0.5 interpolation

Interaction with Stage Transitions

Stage transitions are configured by UTextAnimationBlueprint::StageTransitionConfig (FStageTransitionConfig):

FieldDefaultDescription
IntroToDefaultCrossFade0.1intro → default transition duration (seconds)
DefaultToOutroCrossFade0.1default → outro transition duration (seconds)
EasingFuncEEasingFunc::Lineartransition easing function

Layer hierarchy:

Glyph render state
  └─ FBakedGlyph::Evaluate —— per-layer blending (ETextAnimationBlendMode, within a layer)
        └─ UTextAnimationStageController —— stage transitions (FStageTransitionConfig, across stages)
images/blend-per-channel.png — Per-layer blending diagram: a single glyph with three layers, Layer0 Override provides base translation and scale, Layer1 Additive stacks shake offsets, Layer2 Multiply modulates scale, each layer only affects its non-empty channels
images/stage-crossfade-layers.png — Layer hierarchy diagram: per-layer channel blending at the bottom (FBakedGlyph::Evaluate combining by BlendMode), stage transitions on top (UTextAnimationStageController advancing per FStageTransitionConfig), the two levels are independent