Skip to content
CRUSHFORMV1.1.0
GET IT ON FAB

INTEGRATIONPERFORMANCE

Performance

Crushform’s cost comes from a few knobs: the atlas and its slots, the resolution of each lattice, how often the plugin rebuilds collision and dirt, and how many tyres, debris pieces and sounds may run at once. This page names each knob with its default. It gives no frame times, because they depend on your project. Measure your own project with the commands in the last section of this page.

Every damaged body takes one slot in the atlas, and the slot holds its lattice. The atlas is the render target in UCFSettings::Atlas. Its surface is capped at 4096 texels on each side (MaxAtlasSize in CFTypes.h), and the number of slots is the surface divided by one slot, UCFSettings::SlotWidth by UCFSettings::SlotHeight.

  • A lattice fits a slot when its ResX times ResZ is at most SlotWidth, and its ResY is at most SlotHeight. The default profile’s UCFProfile::Resolution is 16 by 8 by 8, which fits the default slot of 256 by 8.
  • A slot must hold the smallest lattice, 4 by 4 nodes. A slot smaller than 16 texels wide or 4 texels high leaves the dents invisible, and the log says so.
  • The atlas must be linear B8G8R8A8: an RTF_RGBA8 render target, or a BGRA8 texture without sRGB. Any other format leaves the dents invisible too.

When every slot is taken, a new damaged body takes the slot of the farthest damaged body, but only if that body is farther from the camera than the new one. The farthest body then waits and draws undamaged until a slot is free again. A body at the same distance as the farthest one waits too.

The lattice is the cost that a profile sets for each body.

  • UCFProfile::Resolution (16 by 8 by 8 by default) is the node count of the lattice. A bigger lattice needs a bigger slot, as above.
  • UCFProfile::bDents (on): when it is off, hits and crush presses never dent or scratch the body. Dirt still works.
  • UCFProfile::DirtScale (1): every dirt deposit on the body is multiplied by it. At 0 the body gets no dirt grid at all.
  • UCFProfile::MaxPlausibleDeltaV (40 m/s): a harder hit is reported at this limit, and the server rejects anything above it.
  • UCFSettings::MaxReportsPerSecond (60) is how many reports per second the server accepts from one component. A sending client’s bucket holds that many reports; the server’s bucket is 1.5 times deeper. UCFSettings::MaxReportsPerBatch (8) is the most reports a driving client sends in one frame.
  • UCFSettings::ScrapeReportInterval (0.1 s) is the time between two scrape reports of one component.
  • UCFSettings::CollisionRebuildThreshold (2 cm) and UCFSettings::CollisionRebuildInterval (0.5 s) control when a dented body’s collision is built again. A rebuild happens only when a node has moved this far, and no sooner than the interval.
  • UCFSettings::bDeformCollision (on): turning it off takes away the whole cost of following dents: no blocks, no cut for a torn part, no hull for a loose part. Vehicles then collide as authored, so a car pushed in by a crash is not pushed in for what hits it, and a torn part starts inside the body’s collision and the solver pushes it out. A device profile can set Crushform.Collision.Deform 0 for weak devices.
  • UCFSettings::CollisionDeferFrames (1) is 0 or 1. At 1 a heavy collision build runs on a worker: a torn part’s cut, the body’s rebuild after a dent and a torn part’s hull. The body’s rebuild and cut are on the body before the next frame’s physics, and if the worker has not finished by then, the game thread waits for it there. So the frame of the hit stays short, and the next frame can be the longer one on a slow machine. 0 builds everything in the frame of the hit. A device profile can set the console variable Crushform.Collision.DeferFrames, which overrides the project value.
  • UCFSettings::CollisionBlockTolerance (1.5 cm) and UCFSettings::MaxCollisionBlocks (96) control how many blocks a dented body’s boxes and convexes are cut into. MaxCollisionBlocks is the most blocks that all the boxes and convexes of one body are cut into together. A value at or below the number of those shapes cuts nothing: each stays one hull.

The tyre budget decides which wheels deform. UCFTireSettings::Scope picks the mode, and the budget’s values are project settings under Crushform Tire; see Project settings. Each value is also a console variable, which overrides the project value when a console command or a command-line argument sets it. All of them are described in the console reference:

  • Crushform.Tire.MaxWheels (30): the tyres that may deform at once. The viewer’s own vehicle always deforms, even past the cap.
  • Crushform.Tire.Radius (4000 cm): the distance from the camera within which other vehicles’ tyres may deform.
  • Crushform.Tire.LodDistance1 (1500 cm) and Crushform.Tire.LodDistance2 (3000 cm): the distances where a tyre traces a thinner ray fan, and then the thinnest fan against simple collision.
  • Crushform.Tire.UpdateInterval (0.25 s): the time between two budget passes.
  • Crushform.Tire.Hysteresis (0.15): how far a granted tyre’s boundaries widen, so that a tyre on a boundary does not flicker.
  • Crushform.Tire.OnScreenTolerance (0.5 s): how long after it was last drawn a wheel still ranks as on screen.
  • Crushform.Tire.Enable (1): set to 0 and every tyre relaxes back to round.

The sleep of resting wheels has no console variable: UCFTireSettings::SleepDistance (1 cm) and UCFTireSettings::SleepAngleDeg (0.5 degrees): a settled wheel that stays within these can fall asleep, and it stops tracing until its pose changes. A negative SleepDistance turns sleep off.

  • Crushform.Glass.ShardScale (1) is the share of each break’s shards that are thrown, from 0 to 1. Each shard is a particle of the pane’s Niagara system, so the count is the cost of a break. A break throws up to UCFGlassDefinition::MaxShardTiles times the shard pieces of the definition: up to 60 for the laminated preset (12 × 5) and up to 64 for the tempered one (16 × 4). 0.5 throws about half of them, and 0 throws none: the pane still breaks, with no particles.
  • Crushform.Glass.MaxLiveShards (512) is the most shards of broken panes alive at once, and 0 is no cap. It bounds the cost of a pile-up, where several panes break together: 512 is about eight laminated breaks, and it holds all the panes of one car. Past the cap the oldest broken panes’ shards are released first, and one break’s shards beyond the cap are cut.
  • Crushform.Glass.ShardSystemsPerFrame (1) is the shard systems started in one frame, and 0 is no limit. The rest start on the next frames, in order, moved along their velocity by the time they waited, up to 0.25 s. It keeps a pile-up’s broken panes out of one frame; raise it if your game can spare the frame and wants all the shards at the moment of the crash.
  • Each broken pane takes one pooled Niagara component for its shards and returns it when they finish, when the pane is repaired, or at the end of play. So the pool holds one component per broken pane, not one per shard.

A crash runs its hit path mostly on the game thread in several stages, and each stage has its own named scope. To see where the time goes, enter stat namedevents, then Trace.Start cpu,frame,bookmark before the crash and Trace.Stop after it, and open the trace in Unreal Insights: each scope below appears under its name. With UCFSettings::CollisionDeferFrames above 0 the cut and the hulls run on a worker thread, the cut scopes below included; Body collision block convex runs on worker threads either way. The scopes, grouped by stage, are:

  • Hit input: Deform Hit gate, Deform Ignored actors, Deform Hit mass, Deform Hit giving way, Deform Hit contacts, Deform Hit distance, Deform Hit velocities and Deform Hit root pose.
  • Lattice and reports: Deform Mark chunks, Deform Debug hit, Deform Predict, Deform Damage schedule, Deform Render mark, Deform Part damage, Deform Shake off and Deform PartCollision wait.
  • Body collision: Body collision cut subtract, Body collision cut prepare, Body collision cut watch, Body collision block convex, Collision blocks clip convex, Deform Collision poll, Body collision job start, Body collision job wait and Body collision job apply.
  • Hinged parts: Hinge crowded, Hinge blocked, Hinge detach, Hinge start swing, Hinge loosen, Hinge joint create and Hinge joint destroy.
  • Body distance: Body distance, Body distance pose and Body distance shapes.
  • Glass shards: Glass Shards, Glass Shard data, Glass Shard spawn, Glass Shard hits and Glass Apply verdict.
  • Impact feedback: Play Impact sound, Play Impact effect and Impact sound queue.

The body collision’s build runs on a worker thread: a crash frame shows the job’s start, which copies the lattice the worker reads, and its apply in the frame the job lands in. The wait appears when the deadline came before the worker finished, or when a build that was still running was dropped (a repair, a reattach, a body rebuilt or lost, the end of play).

Press Play In Editor on a level with a damaged body, then open the console.

  • Crushform.Stats prints the atlas first, in this form. A growing number of waiting bodies or evictions means the atlas is full.
Crushform atlas: <used> of <total> slots used, <waiting> waiting, <evictions> evictions, <uploads> uploads.

Then it prints one line for each damageable actor in the world: server lattice where this machine holds the damage, client view where it draws the server’s. The line goes on with the actor’s generation, its pending reports and chunks, and its counters: hits, reports sent, accepted and rejected, collision builds with the longest one in milliseconds, the collision waits (the builds the game thread waited for at their deadline), the parts held (the parts that waited for their cut before they fell), and the part hulls. A dedicated server process, which draws nothing, prints Crushform atlas: none in this process (a dedicated server draws nothing). instead of the first line.

  • stat Crushform puts the core module’s timed steps on screen, such as the deform tick, the dirt update and the body collision rebuild, each in milliseconds. The other stat groups are CrushformTire, CrushformBreakable, CFBreakableInstances, CrushformDebris, CFPropContact, CFImpactFeedback, CrushformVehicle, CrushformChaos, CrushformWheel, CrushformEngine, CrushformPlayground and CrushformDebug.

Dents stop on some damaged vehicles. Cause: the atlas is full. The farthest damaged bodies wait for a slot and draw undamaged until one is free. Crushform.Stats shows the waiting count and the evictions. Fix: make UCFSettings::Atlas larger. The slot count is the atlas size divided by the slot size, up to the 4096-texel cap, so a larger atlas holds more damaged bodies at once.

Dents never appear, and the log says the slot is too small. Cause: UCFSettings::SlotWidth is below 16 texels or UCFSettings::SlotHeight is below 4. Fix: raise the slot size to at least 16 by 4 texels. The default is 256 by 8.

Dents never appear, and the log names the atlas’s pixel format. Cause: the atlas is not linear B8G8R8A8. An sRGB texture, or any other format, is refused. Fix: use an RTF_RGBA8 render target, or a BGRA8 texture with sRGB turned off.