Skip to content

Instantly share code, notes, and snippets.

@birjj
Last active September 27, 2018 17:41
Show Gist options
  • Save birjj/d49dbfab4ee448a70738a8cdb9642b9f to your computer and use it in GitHub Desktop.
Save birjj/d49dbfab4ee448a70738a8cdb9642b9f to your computer and use it in GitHub Desktop.
How the Source engine simulates rope

How the Source engine simulates rope

approximate measurements of rope in the Source engine are available here
this will look at non-solid ropes that aren't affected by wind
a JS implementation is available

Ropes in the Source engine span from a move_rope to a keyframe_rope (or from a keyframe_rope to a keyframe_rope). In both cases two values are relevant for the rope simulation: slack and subdivision.

Slack indicates how low the rope hangs. It is simply a scalar value (usually in the range of a few hundred) that is added to the length of the rope when it is initialized [1]. This means that, for a 10-segment rope, each segment has an additional length of slack / 10. When simulating, this will lead to a rope that hangs lower.

Subdivision indicates how smooth the rope is. It does not affect simulation directly, but is applied before rendering through applying a catmull rom spline. This smooths out the otherwise coarse 10-segment ropes.

Generation

The ropes are generated of 10 different nodes including start/end, connected by 9 springs. Each spring is given a length of (distFromStartToEnd + slack + fudge) / numSprings.

Once the rope is generated it is simulated for 3 seconds worth of timesteps. This allows it to reach a resting state before it is displayed to the user.

Simulation

Ropes are simulated using the simple physics engine. This simply applies the formula pos + vel * dampening + accel * (timestep * timestep * 0.5) to each node, with a dampening factor of 0.98. The only forces that affect a non-solid rope that isn't affected by wind is gravity.

After this simple physical simulation is ran, constraints are applied. This loops 3 times, and each time it does the following:

  1. Run through all the springs and calculate vTo, a vector going from Node2 to Node1.
  2. Check if the length of vTo is longer than the length of the spring.
  3. If it is, multiply vTo by a factor of 1 - (spring length / vTo length)
    • Move Node1 by -0.5 * vTo
    • Move Node2 by 0.5 * vTo

This will keep the nodes from straying further from eachother than the spring length. If they are further than allowed, 1 - (expected / actual) becomes a number in the range [0,1], being closer to 0 the closer they are to the expected length. This means that they are corrected to their expected length every time they are seen as too long.

Smoothing

After the nodes are simulated, the rope is smoothed based on the number of subdivisions the mapper has chosen. This calculates the Catmull-Rom spline with points prevNode, curNode, nextNode and nextNextNode. The point (t) along the spline is set as (iSubdiv + 1) / (numSubdivs + 1), meaning that for a 2-subdiv the first point is at 1 / 3, while the second one is 2 / 3.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment