Lab 015 – Exploring Physics Joints

Loading some entities and adding physics joints between them.

A while back @kahunamoore.bsky.social mentioned some interest in seeing something about PhysicsJoints on the site, so I put together this Lab. I’ve used physics in other 3D frameworks and platforms, but this is my first time doing anything with physics in RealityKit. I will probably explore physics more in a future series. Or you could always nerd-snip me into creating more labs…

There are a handful of concepts we need to get physics joints working.

  1. A parent entity that will host our PhysicsSimulationComponent and PhysicsJointsComponent
  2. On each entity, we need to add Collision and PhysicsBody components (I did this in RealityComposer Pro)
  3. Load out parent entity, then get the child entities
  4. Add pins to each entity. I’m using a hinge orientation that will allow the entities to swing from the x axis.
  5. Add the pins to a join
  6. Add the join to a simulation

Example 1:

Load two entities and join them together.

let hingeOrientation = simd_quatf(from: [1, 0, 0], to: [0, 0, 1])

if let simple = scene.findEntity(named: "Simple") {
    simple.components.set(PhysicsSimulationComponent())
    simple.components.set(PhysicsJointsComponent())
    
    if let ballA = simple.findEntity(named: "a"),
       let ballB = simple.findEntity(named: "b") {
        
        // Create a pin for each ball
        let pin1 = ballA.pins.set(
            named: "demo_ballA_to_ballB_hinge",
            position: .zero,
            orientation: hingeOrientation
        )
        let pin2 = ballB.pins.set(
            named: "demo_ballB_to_ballA_hinge",
            position: ballB.position(relativeTo: ballA),
            orientation: hingeOrientation
        )
        
        // Join the pins together
        let simpleJoint = PhysicsRevoluteJoint(pin0: pin1, pin1: pin2)
        
        // Add the join to the simulation
        Task {
            try simpleJoint.addToSimulation()
        }
    }
}

Example 2:

Load a chain of balls from the Reality Composer Pro scene.

if let chain = scene.findEntity(named: "Chain") {
    chain.components.set(PhysicsSimulationComponent())
    chain.components.set(PhysicsJointsComponent())

    // The balls are chrildren of the Chain entity. Each one named ball1, ball2, etc.
    let balls = chain.children
        .filter { $0.name.hasPrefix("ball") }
        .sorted { Int($0.name.dropFirst(4))! < Int($1.name.dropFirst(4))! }

    // We create connections by using two copies of the balls array.
    // We drop the first element of the second array to shift the positions.
    // Then we can zip the arrays to join them (ball1 to ball2, ball2 to ball3,...)
    let chainJoints = zip(balls, balls.dropFirst()).map { (ball1, ball2) -> PhysicsRevoluteJoint in

        // For each pair, create pins and join them together
        let pin1 = ball1.pins.set(
            named: "ball\(ball1.name)_to_\(ball2.name)_hinge",
            position: .zero,
            orientation: hingeOrientation
        )

        let pin2 = ball2.pins.set(
            named: "ball\(ball2.name)_to_\(ball1.name)_hinge",
            position: ball2.position(relativeTo: ball1),
            orientation: hingeOrientation
        )

        return PhysicsRevoluteJoint(pin0: pin1, pin1: pin2)
    }

    // Add all joints to simulation
    Task {
        try chainJoints.forEach { try $0.addToSimulation() }
    }
}

I had initially set these joints up manually. It was a repetitive mess. Then I asked Cursor to help refactor it. This introduced me to zip in Swift, which I had not encountered before. What a novel way to create these joints!

Video demo

Video demo showing spheres connected with physics joints

Example code for this lab can be found in Lab015.swift in the Step Into Labs repo

Support our work so we can continue to bring you new examples and articles.

Download the Xcode project with this and many more labs from Step Into Vision.

Questions or feedback?