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.
The atlas and its slots
Section titled “The atlas and its slots”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 mostSlotHeight. The default profile’sUCFProfile::Resolutionis 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 and the profile
Section titled “The lattice and the profile”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.
Reports and collision
Section titled “Reports and collision”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) andUCFSettings::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 setCrushform.Collision.Deform 0for 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 variableCrushform.Collision.DeferFrames, which overrides the project value.UCFSettings::CollisionBlockTolerance(1.5 cm) andUCFSettings::MaxCollisionBlocks(96) control how many blocks a dented body’s boxes and convexes are cut into.MaxCollisionBlocksis 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.
UCFSettings::DirtUpdateInterval(0.2 s) is the time between two dirt updates of one body.UCFSettings::DirtReferenceSpeed(8 m/s) is the tyre speed at which a surface’s rates apply as written.UCFSettings::MaxDirtSpeedScale(2) caps how much faster tyres multiply them.UCFSettings::DirtEventInterval(0.5 s) andUCFSettings::DirtEventThreshold(0.02) limit the dirt-changed events of one body.
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) andCrushform.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.
Breakables and debris
Section titled “Breakables and debris”UCFBreakableSettings::MaxLiveDebrisPieces(96) is the live debris pieces per world. The oldest is recycled beyond it.UCFBreakableSettings::MaxPersistentDebrisPieces(64) counts apart the pieces of definitions whose debris lasts until respawn.UCFBreakableSettings::DebrisMaxSpawnDistanceCm(10000 cm) is the distance from the local camera beyond which a break spawns no debris, and a broken glass pane throws no shards.UCFBreakableSettings::AnyBodyCheckIntervalSeconds(0.1 s) is how often a fence with units that break from any body looks for bodies near them.
Glass shards
Section titled “Glass shards”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 toUCFGlassDefinition::MaxShardTilestimes 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.
Impact feedback and rolling FX
Section titled “Impact feedback and rolling FX”UCFImpactFeedbackSettings::MaxAudibleDistanceCm(6000 cm) andUCFImpactFeedbackSettings::MaxEffectDistanceCm(8000 cm): impacts farther than these from the local camera play no sound and spawn no effect.UCFImpactFeedbackSettings::MaxVoiceSeconds(3 s) is the longest a played sound holds a voice slot. Each row of an impact set has its ownFCFImpactFeedbackEntry::MaxConcurrentVoices(4 by default), the number of its sounds that may play at once.UCFImpactFeedbackSettings::MaxSoundsPerFrame(2) is the most sounds that start in one frame, and 0 is no cap. The rest wait, strongest first, for later frames.UCFImpactFeedbackSettings::SoundQueueSeconds(0.15 s) is how long a sound over the cap may wait before it is dropped. A device profile can setCrushform.Impact.MaxSoundsPerFrameandCrushform.Impact.SoundQueueSeconds.UCFWheelSettings::FXTuningstops the rolling FX of a vehicle while it is slow.FCFRollingFXTuning::SleepSpeedKPHis 1 km/h by default.
Profiling a crash
Section titled “Profiling a crash”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 velocitiesandDeform 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 offandDeform 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 waitandBody collision job apply. - Hinged parts:
Hinge crowded,Hinge blocked,Hinge detach,Hinge start swing,Hinge loosen,Hinge joint createandHinge joint destroy. - Body distance:
Body distance,Body distance poseandBody distance shapes. - Glass shards:
Glass Shards,Glass Shard data,Glass Shard spawn,Glass Shard hitsandGlass Apply verdict. - Impact feedback:
Play Impact sound,Play Impact effectandImpact 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).
Check that it works
Section titled “Check that it works”Press Play In Editor on a level with a damaged body, then open the console.
Crushform.Statsprints 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 Crushformputs 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 areCrushformTire,CrushformBreakable,CFBreakableInstances,CrushformDebris,CFPropContact,CFImpactFeedback,CrushformVehicle,CrushformChaos,CrushformWheel,CrushformEngine,CrushformPlaygroundandCrushformDebug.
Troubleshooting
Section titled “Troubleshooting”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.