VerletLine is a simulated rope or cable with a generated mesh. Give it control points, pin the ends to objects, and it hangs, swings, collides, carries rigidbodies and can be cut. It is 3D only. The points are solved by a Burst rope kernel, and the meshes of all ropes in a scene are built together by one Burst system, with no threads per rope.
Setting up a rope #
- Create a GameObject with
VerletLine. It adds the mesh components it needs. - Set two or more control points. Each is a bezier point with a position and handles, and the handles are offsets relative to the point.
- Add pins at the ends, see below. A rope with one pin hangs from it, and a rope with two pins spans between them.
- Assign a
VerletLineSettingsObject(or use the built-in default settings) and a material, then press Play.
Control points are in the local space of the line object, so its position, rotation and scale apply. The line’s own Transform is driven: it follows the first point of the line every step. Do not scale the object unevenly.
The rope component #
| Setting | Default | What it does |
|---|---|---|
settings | none | A settings asset shared between ropes. When set it is used instead of defaultSettings. |
defaultSettings | built in | The settings used when no asset is assigned. |
controlPoints | none | The bezier points that shape the line. |
pins | none | The pins that tie points of the line to Transforms. |
distanceBetweenSegments | 0.1 | The distance between points in world units. Smaller is smoother and costs more, and the rope is limited to roughly 4,000 points. |
substeps | 8 | Smaller steps inside each fixed step, 1 to 32. More is stiffer and truer, and costs more. |
iterations | 6 | The most solves per substep, 1 to 16. It stops as soon as every segment holds its length. |
startCap, profile, endCap | rounded caps, circle | Optional meshes for the start and end of the rope and an optional cross section for its body. |
ignoreColliders | empty | Colliders the rope never collides with. |
ignorePinColliders | on | Ignore every collider on or under a pin’s Transform, and the colliders of a pin’s force target, so a rope can hang from a character without hitting it. |
prewarm, prewarmSeconds | on, 10 | Settle the rope before the first frame, for at most this many simulated seconds. |
Rope settings #
The same settings exist as a shared ScriptableObject (VerletLineSettingsObject) and as a plain class on the component (VerletLineSettings). Curves are read along the rope from 0 at the start to 1 at the end.
| Setting | Default scale | What it does |
|---|---|---|
taper | 0.05 | The thickness of the rope along its length, as a diameter in world units. |
twist | 0 | How many degrees the profile twists per point. |
constantAcceleration | (0, -9.81, 0) | Acceleration on every point, gravity by default. |
mass | 0.1 | The mass along the rope, used for collision response and for the load a rope puts on a rigidbody. |
damping | 0.2 | Quadratic drag: the deceleration is this times the speed squared, so slow movement is barely damped and fast movement is slowed strongly. |
stretchiness | 0.1 | How far each segment may stretch freely, as a ratio of its rest length. |
stretchCompliance | 0 (none) | How much a segment gives under tension beyond its free stretch, in metres per newton. Zero holds the length once the free stretch is used up, larger is a stretchier, springier rope. It behaves the same at any step or iteration count. |
enableCollision | on | Whether the rope collides with colliders. |
collisionLayers | Everything | The layers the rope collides with. |
snapPoint | -1 (never snaps) | The stretch ratio beyond which the rope snaps. A negative scale means it never snaps. |
Pins #
A VerletSystemPin ties one point of the rope to a Transform. linePosition picks the point, from 0 at the start to 1 at the end. Only every second point of a rope is simulated, the points between are interpolated, so a pin that lands on an in-between point is attached to the nearest simulated one.
| Mode | What it does |
|---|---|
Static | The point is held exactly on the Transform, including in the rendered mesh, so a pinned end never lags the object it hangs from. |
Kinematic | The Transform follows the point. |
ForceTransfer | The point is held at the Transform and the strain on it is applied to a Rigidbody (forceTarget) as a force at the pin, scaled by forceScale (default 100). Use it for a swinging weight or a bridge. |
Several pins on one body share the effective mass of that body, so a plank tied at four corners behaves as one plank. The rope also pushes back on rigidbodies it collides with. AddPin(pin) adds a pin and is safe to call before the rope is built.
Collision #
Every point of the rope is pushed out of colliders on the collision layers. Trigger colliders are ignored. Colliders on or under a pin Transform, on a pin’s force target and in ignoreColliders are skipped when ignorePinColliders is on. Call RefreshIgnoredColliders() if a pinned object gains or loses colliders at runtime. OnCollision fires each step a point is pushed out, with the point index, the collider and the position.
Heavy loads #
A rope can carry rigidbodies through ForceTransfer pins, and the Rope Example scene builds a rope bridge to show it: two ropes and 26 planks tied at four corners each, with cubes rained onto it. There is one limit to know about. A heavy impact stretches the rope for one fixed step, because the rope and PhysX are coupled with a one step lag. The lever is a shorter Time.fixedDeltaTime. On the sample bridge the rope stays well behaved for cubes up to roughly 15 to 30 kg.
Breaking and snapping #
BreakSegmentAtPosition(0..1)orBreakSegmentAtIndex(index)cut the rope, removing that segment from the mesh and letting the two parts move apart.OnBreakAtIndexfires with the point index when the rope breaks.- A snap point with a non-negative scale makes the rope snap when a segment stretches past the ratio.
From code #
| Member | What it does |
|---|---|
Rebuild() | Rebuilds the rope from its control points and discards its motion. Call it after changing the control points, the spacing or the mesh parts at runtime. It is called for you at Start. |
Warm(maxSeconds, settleSpeed) | Settles the rope on demand with the pins held still. Pins do not pull on rigidbodies, Kinematic pins do not move their Transform and no collision events are raised while it runs. |
IsBuilt, PointCount | Whether the rope is simulating, and how many points it has (zero before it is built). |
GetPointPosition(index) | The simulated world position of a point. |
GetIndexAtPosition(position) | The nearest point index for a position along the rope, 0 to 1. |
GetClosestIndexAtWorldPosition(worldPosition, out index, out distance) | The point nearest to a world position, with an index of -1 when the rope is not built. |
AddPin(pin) | Adds a pin. |
BreakSegmentAtPosition, BreakSegmentAtIndex | Cut the rope. |
RefreshIgnoredColliders() | Re-reads the collider ignore sets. |
How it runs #
- The simulation steps in
FixedUpdate. The mesh is built inLateUpdateby a Burst job scheduled together for all ropes by a hiddenVerletLineSystem, and interpolated between fixed steps so it is smooth at any frame rate. - The solve is a direct tridiagonal solve in double precision, iterated until every segment holds its length.
BezierPointhandles are offsets from their point. The rope inspector draws the points and handles in the scene view so you can drag them.
Samples #
The Rope Example has a post pivot turning at constant speed and the rope bridge described above, built into the scene at edit time so you can inspect it without entering Play Mode. See the Overview for the import path.