Skip to content

Instantly share code, notes, and snippets.

@pardeike
Created August 7, 2024 03:51
Show Gist options
  • Save pardeike/f353262a5c682d956f0a05caade08c4d to your computer and use it in GitHub Desktop.
Save pardeike/f353262a5c682d956f0a05caade08c4d to your computer and use it in GitHub Desktop.
Demo demonstrating physics joints breaking in RealityKit
// put the following code into a new VisionOS 2 beta project and run it
// inside a real device (hand tracking will fail in the simulator)
// interacting with the door on the hinge will separate it from the hinge
import SwiftUI
import RealityKit
import ARKit
let mat1 = UnlitMaterial(color: .blue)
let mat2 = UnlitMaterial(color: .yellow)
let mat3 = UnlitMaterial(color: .red)
let thickness = Float(0.005)
let width = Float(0.1)
let trackingProvider = HandTrackingProvider()
let arKitSession = ARKitSession()
@main
struct PhysicsTestApp: App {
var body: some SwiftUI.Scene {
ImmersiveSpace { ImmersiveView() }
.immersionStyle(selection: .constant(.mixed), in: .mixed)
}
}
struct ImmersiveView: View {
@State var handRoot = Entity()
@State var parts: [String: Entity] = [:]
var body: some View {
RealityView { content in
let hingeEntity = ModelEntity(mesh: .generateCylinder(height: width, radius: thickness / 1.5), materials: [mat2])
hingeEntity.generateCollisionShapes(recursive: false)
hingeEntity.components.set(PhysicsBodyComponent(mode: .kinematic))
hingeEntity.components.set(OpacityComponent(opacity: 0.5))
hingeEntity.transform.rotation = .init(angle: .pi / 2, axis: [0, 0, 1])
hingeEntity.position = [0, 1, -0.5 - width / 2]
content.add(hingeEntity)
let doorEntity = ModelEntity(mesh: .generateBox(size: [width, thickness, width]), materials: [mat1])
doorEntity.generateCollisionShapes(recursive: false)
doorEntity.components.set(PhysicsBodyComponent(mode: .dynamic))
doorEntity.components.set(OpacityComponent(opacity: 0.5))
doorEntity.position = [0, 1, -0.5]
content.add(doorEntity)
let hingePin = hingeEntity.pins.set(named: "Hinge", orientation: .init(angle: .pi / 2, axis: [0, 0, 1]))
let doorPin = doorEntity.pins.set(named: "Door", position: [0, 0, width / -2])
let doorHingeJoint = PhysicsRevoluteJoint(pin0: hingePin, pin1: doorPin)
try! doorHingeJoint.addToSimulation()
content.add(handRoot)
}
.task {
try! await arKitSession.run([trackingProvider])
for await update in trackingProvider.anchorUpdates {
let anchor = update.anchor
guard anchor.isTracked else { continue }
guard let handSkeleton = update.anchor.handSkeleton else { continue }
for joint in handSkeleton.allJoints.filter({ $0.isTracked }) {
let partID = "\(joint.name)-\(anchor.chirality)"
var part = parts[partID]
if part == nil {
part = ModelEntity(mesh: .generateSphere(radius: 0.01), materials: [mat3])
part!.generateCollisionShapes(recursive: false)
part!.components.set(PhysicsBodyComponent(mode: .kinematic))
part!.components.set(OpacityComponent(opacity: 0.5))
handRoot.addChild(part!)
parts[partID] = part
}
let transform = anchor.originFromAnchorTransform * joint.anchorFromJointTransform
part!.setTransformMatrix(transform, relativeTo: nil)
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment