Materials¶
Every VAT type plays back through a material node that reads the baked textures and moves the mesh. The nodes live under Ternary Vertex Cache in the material palette (right-click the graph, or search for "VAT").
Each node refuses to compile until the material is set up correctly, and the error names the exact setting to change. That's the fastest way to get it right — wire it up, hit Apply, and follow whatever it tells you.
Setup at a glance¶
| Node | Textures to connect | Tangent Space Normal | Max WPO Displacement | Always Evaluate WPO | Vertex Interpolator | Also required |
|---|---|---|---|---|---|---|
| Rigid Body (Compound) | Position + Rotation | OFF | ≥ bake travel | ON | — | piece index read from UV1 |
| Rigid Body (Instanced) | Position + Rotation | OFF | ≥ bake travel | ON | — | PerInstanceCustomData node (index 0) → PieceIndex |
| Soft Body (both) | Position + NormalTangent | ON | ≥ bake travel | ON | on Normal and Tangent | — |
| Fluid | Position + Normal | OFF | exactly 0 | ON | on Normal | Two-Sided + TwoSidedSign |
Two entries catch people out: Soft Body is the only one wanting Tangent Space Normal on, and Fluid is the only one wanting Max World Position Offset Displacement at 0.
Assigning the data asset¶
VATAsset is a property on the node, not an input pin — select the node and set it in the Details panel. Everything else the node needs is read from it, so nothing compiles until it's assigned.

The fields below it (Num Vertices, Texture Width/Height, Num Frames, Max Displacement) fill in
automatically from the asset and are shown for reference — you don't set them by hand. UVChannel
is the exception: leave it at 1 unless you know your mesh carries the index elsewhere.
Common to every node¶
- VATAsset — see above. Must be assigned first.
- Frame — the playback clock. Drive it with Time × FrameRate (the asset's
FrameRate). Looping is internal; negative values play in reverse.FrameRateis the rate the animation was captured at, so this stays the same whatever Frame Step the bake used — the node accounts for stepping on its own and playback keeps its real-world duration. - Output pins are ordered Normal, Tangent (Soft Body types only), WPO.
- Always Evaluate World Position Offset must be enabled on the material, or a primitive's own WPO toggle or WPO Disable Distance can silently stop the animation.
- Max World Position Offset Displacement must cover the animation's travel, or the mesh gets culled or loses shadows while its vertices are still on screen. The compile error states the number to use.
VAT Soft Body Decode¶
Used by Soft Body and Soft Body (Anim Sequence) bakes.

Inputs: PositionTexture, NormalTangentTexture, Frame, Scale (optional)
Outputs: Normal (tangent space), Tangent (world space), WPO
Properties: VATAsset, UVChannel (default 1)
Material settings: Tangent Space Normal ON; Always Evaluate WPO ON; Max WPO Displacement ≥ bake travel.
Normal and Tangent need a Vertex Interpolator
Route both through a Vertex Interpolator node before the material's Normal and Tangent pins. Wired straight in they're evaluated per-pixel and the shading bands across every triangle. WPO doesn't need one.
The Normal output is tangent-space so the engine applies the two-sided flip and world transform
itself — no manual TwoSidedSign needed, and it stays correct on back faces and under any scale.
The Scale input¶
An optional strength control for the whole deformation. Leave unconnected for a normal bake.
| Value | Result |
|---|---|
unconnected / 1 |
The bake as-is |
0 |
Rest pose — geometry and shading |
| between 0 and 1 | Partial deformation |
above 1 |
Exaggerated |
For a per-instance dial, drive it from Custom Primitive Data (as in the screenshot above) — each placed component can then set its own strength without a separate material instance.
Warning
Scaling above 1 pushes vertices further than the bake's recorded travel, which is what Max World Position Offset Displacement is checked against. Raise that setting by the same factor, or the mesh can be culled early.
VAT RBD Decode Compound¶
For Rigid Body (Compound) bakes.

Inputs: PositionTexture, RotationTexture, Frame
Outputs: Normal (world space), WPO
Properties: VATAsset, UVChannel (default 1)
Material settings: Tangent Space Normal OFF — the Normal output is world-space. Always Evaluate WPO ON; Max WPO Displacement ≥ bake travel.
Both textures must be connected; the rotation texture is what makes pieces tumble rather than just translate. The per-piece index comes from UV1 on the baked mesh automatically.
VAT RBD Decode ISM¶
For Rigid Body (Instanced / ISM) bakes. Same decode as Compound, but the piece index arrives per instance instead of from UV1.

Inputs: PositionTexture, RotationTexture, Frame, PieceIndex
Outputs: Normal (world space), WPO
Material settings: as Compound.
PieceIndex must come from a PerInstanceCustomData node
Wire a PerInstanceCustomData node with index 0 into PieceIndex. This is not optional
and not substitutable: Unreal only uploads per-instance custom data to the GPU when that node is
actually present in the material graph. Without it the data is never uploaded, every instance
reads index 0, and all the pieces collapse onto one another.
Place the VATRBDInstancedComponent at the bake's origin — the material drives each piece out to its
own position from there.
VAT Fluid Decode¶
For Fluid (Geometry Cache) bakes.
Inputs: PositionTexture, NormalTexture, Frame
Outputs: Normal (world space), WPO
Material settings — these differ from every other node:
- Tangent Space Normal OFF
- Max World Position Offset Displacement — exactly
0. Triangles that don't exist on a given frame are hidden by the decode; any non-zero clamp brings them back as visible holes. Culling is handled by the baked mesh's own bounds, so nothing is lost by setting this to 0. - Always Evaluate WPO ON
- Two Sided enabled, and multiply the Normal output by a TwoSidedSign node
Route the Normal output through a Vertex Interpolator.
Playback snaps to whole frames — there is no blending between them.
Older nodes¶
VAT Decode Position and VAT Decode Rotation (under Ternary Vertex Cache ▸ Components) are earlier single-purpose nodes kept for compatibility. They don't support seamless looping. Use the all-in-one nodes above for new work.