Niagara and VFX
Five VFX events, deterministic weighted Niagara variation, wood splinters that take on the broken object's texture and never hang in the air, external presentation listeners and the built-in spawn budget.
The five events
ESDFVFXEvent:
| Event | Emitted when |
|---|---|
LightImpact | A valid hit below the profile’s heavy VFX thresholds |
HeavyImpact | A hit at or above HeavyImpactVFXMinimumPower or HeavyImpactVFXMinimumImpulse |
Break | The object is destroyed |
DebrisImpact | A debris piece collides fast enough |
Custom | Requested explicitly by your own code, with a name |
Custom is what makes the VFX layer extensible without touching the framework: your gameplay can
request a named effect through the same deterministic, budgeted path as the built-in events.
Weighted variations
Each event reads an array of FSDFWeightedNiagaraSystem:
| Property | Default | Meaning |
|---|---|---|
System | none | Soft UNiagaraSystem reference |
Weight | 1.0 | Relative selection weight |
MinimumScale | 0.9 | Lower bound of the random scale |
MaximumScale | 1.1 | Upper bound |
bOrientToImpactNormal | true | Align the system’s local Z axis to the impact normal |
RotationOffset | zero | Rotation applied after orientation |
Soft references mean the Niagara assets are loaded on demand, not pinned by every profile that mentions them. Empty and zero-weight entries are ignored safely.
Orientation
With bOrientToImpactNormal enabled, the system’s local Z axis is aligned to ImpactNormal, then
RotationOffset is applied. That is the behaviour you want for surface-hugging effects — dust
puffs, splinter sprays, chips.
Disable it for effects authored in world space, such as a volumetric burst that should always rise vertically regardless of which face was hit.
Splinters that look like the object
The supplied wood break effect (NS_SDF_Impact_Wood, used by every wood preset) makes its splinters
and chips belong to the object that broke:
- They start where you struck it and burst up and along the swing — never back into the object, where a tall prop’s back or openings would catch them.
- They never hang in the air. Splinters collide on the Camera trace channel, which every SDF debris body ignores: they fly through the broken pieces and land on the real floor. A splinter that still stalls above the floor the object stood on is removed, and every splinter shrinks away at the end of its life instead of popping.
- They take on the object’s look. Splinters show the object’s own base colour texture, each from a different spot; chips are tinted from it and keep their shapes. A light oak bench throws light oak splinters.
How the texture is found
- When SDF generates, regenerates or modifies a destructible, it records the texture wired into the
dominant material’s Base Color in the profile’s
SourceAppearance(FSDFDebrisAppearance:BaseColorTexture,AverageColor,bValid). - Without a recorded texture, SDF inspects the material at runtime and keeps colour textures only —
sRGB, not normal, roughness, AO or mask maps, not virtual — preferring names such as
BaseColor,Albedo,Diffuse,_BCor_D. - When nothing qualifies, the splinters keep the supplied wood look.
The texture feeds SDF’s own particle materials, M_SDF_WoodSplinter_Source and
M_SDF_WoodChip_Source. The object’s material is never put on particles: a material without the
Niagara usage flags renders as the grey default checker in a cooked game.
User parameters written on every built-in spawn
SDF sets these on the spawned component before it activates. Systems that do not declare them ignore them.
| Name | Type | Meaning |
|---|---|---|
SDFImpactDirection | Vector3 | Hit direction blended with the surface normal |
SDFImpactStrength | Float | Destruction Power: VeryLight 0.6, Light 0.85, Medium 1.0, Heavy 1.4, Massive 1.8 |
SDFRandomSeed | Int32 | Seed carried by the request |
SDFSplinterOrigin | Position | The struck point (break location when the hit carried none) |
SDFSplinterDirection | Vector3 | Burst direction: up, along the swing, a little out of the struck face |
SDFBoundsMin, SDFBoundsMax | Position | World bounds of the intact object; SDFBoundsMin.Z is the floor it stood on |
SDFSourceBaseColor | Texture | The object’s base colour texture, or none |
SDFUseSourceTexture | Float | 1 when a texture was found, else 0 |
SDFSourceColor | Linear Color | Average colour of that texture, recorded at authoring |
For a duplicated wood system, keep the emitter names NE_SDF_Splinters and NE_SDF_WoodChips and
run the editor command SDF.Dev.SetupSplinterEffect /Game/Path/NS_YourWood.NS_YourWood. It wires
the texture user parameter into the renderers’ material bindings and saves the system.
Pass user parameters as module inputs
The supplied splinter modules receive User. values through module inputs bound to the user
parameters, not by reading them inside custom HLSL. Keep those bindings when editing, and recompile
after every change: one emitter that fails to compile stops the whole effect.
Deterministic selection
SelectWeightedVFXVariation(Variations, RandomSeed, OutScale, OutRotation, ImpactNormal, ImpactDirection)
is a pure, static, Blueprint-callable function. The same seed yields the same system, scale and
rotation.
Built-in spawning versus delegates
| Property | Effect |
|---|---|
bEnableVFXRequests | Master switch: emit VFX requests at all |
bEnableBuiltInVFXSpawning | Also spawn the selected Niagara system directly |
Requests are always emitted
As with audio, disabling built-in spawning keeps the requests flowing. An external presentation system receives a fully resolved selection — system, scale, rotation, seed — and decides what to do with it.
The request payload
FSDFDestructionVFXRequest:
| Field | Meaning |
|---|---|
Event | Which of the five events |
CustomEventName | Semantic identifier, meaningful for Custom |
SourceActor | The destructible |
Location | World position |
ImpactNormal | Surface normal used for orientation |
ImpactDirection | Direction of the causing hit |
Rotation | Resolved rotation |
Scale | Resolved scale |
ImpactSpeed | Speed associated with the event |
DestructionPower | Power of the causing hit |
SelectedSystem | The Niagara variation picked |
RandomSeed | Seed used |
SelectedVariationIndex | Index into the profile array |
bBuiltInSpawnRequested | Built-in spawning was configured |
bBuiltInSpawnAttempted | A spawn was actually attempted |
bBuiltInSpawnSuppressedByBudget | The per-frame built-in VFX budget suppressed it |
SplinterOrigin | Where splinters start: the struck point on a break |
SplinterDirection | Burst direction for splinters |
SourceBounds | World bounds of the intact object |
Appearance | FSDFDebrisAppearance of the broken object (texture, average colour, valid flag) |
Requesting a custom effect
RequestVFXEvent(Event, Location, ImpactNormal, ImpactDirection, ImpactSpeed, DestructionPower, RandomSeed, CustomName)
on the destructible component resolves and emits one request. Pass Custom with a CustomName that
your presentation system understands, and populate CustomEffects on the profile if you also want
built-in spawning.
DestructibleComponent->RequestVFXEvent(
ESDFVFXEvent::Custom,
ImpactLocation,
ImpactNormal,
ImpactDirection,
/* ImpactSpeed */ 0.f,
ESDFDestructionPower::Medium,
/* RandomSeed */ -1,
TEXT("EmberBurst"));
Where to listen
| Scope | Delegate |
|---|---|
| One object | USDFDestructibleComponent::OnDestructionVFXRequested |
| Whole world | USDFDestructionSubsystem::OnDestructionVFXRequested |
The global delegate is the correct integration point for a pooled particle manager or a custom Niagara routing layer.
Debris impact VFX
Throttled by the same three-property pattern as audio:
MinimumDebrisImpactVFXSpeed(default200.0);DebrisImpactVFXCooldown(default0.15s);MaximumDebrisImpactVFXPerDebrisActor(default1).
VFX budget
MaxBuiltInVFXEventsPerFrame (default 64) caps built-in spawning only. External listeners keep
receiving every request.
GetVFXStats returns FSDFDestructionVFXStats with TotalRequests, TotalBuiltInSpawnAttempts,
TotalBuiltInSpawnsSuppressed and BuiltInSpawnAttemptsThisFrame. GetLastVFXRequest returns the
most recent payload; ResetVFXStatistics clears the counters.
Budget your own spawns too
If you route VFX to your own system and disable built-in spawning, the framework’s VFX budget no longer protects you. Apply your own cap in the listener — a large radial event can legitimately produce dozens of requests in one frame.
Last updated: 2026-10-01