Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Collision between two nodes not detected ARKit

I created two nodes: a sphere and a box:

    var sphere = SCNNode(geometry: SCNSphere(radius: 0.005))
    //I get the box node from scn file
    let boxScene = SCNScene(named: "art.scnassets/world.scn")!
    var boxNode: SCNNode?

I want two nodes or physicsBody's to interact, so I created a category for categoryBitMask and contactTestBitMask:

struct CollisionCategory: OptionSet {
    let rawValue: Int
    static let box = CollisionCategory(rawValue: 1)
    static let sphere = CollisionCategory(rawValue: 2)
} 

Here I set the box node as a physics body:

self.boxScene.rootNode.enumerateChildNodes { (node, _) in
    if node.name == "box" {
        boxNode = node
        let boxBodyShape = SCNPhysicsShape(geometry: SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0.1), options: nil)
        let physicsBody = SCNPhysicsBody(type: .static, shape: boxBodyShape)
        boxNode!.physicsBody = physicsBody
        boxNode!.physicsBody?.categoryBitMask = CollisionCategory.box.rawValue
        boxNode!.physicsBody?.contactTestBitMask = CollisionCategory.sphere.rawValue
        boxNode!.physicsBody?.collisionBitMask = boxNode!.physicsBody!.contactTestBitMask
    }
}

Here I set the sphere node in the render function, which you can move around the view:

func setUpSphere() {
         let sphereBodySphere = SCNPhysicsShape(geometry: SCNSphere(radius: 0.005))
         let physicsBody = SCNPhysicsBody(type: .kinematic, shape: sphereBodySphere)
         sphere.physicsBody = physicsBody
         sphere.physicsBody?.categoryBitMask = CollisionCategory.sphere.rawValue
         sphere.physicsBody?.contactTestBitMask = CollisionCategory.box.rawValue
         sphere.geometry?.firstMaterial?.diffuse.contents = UIColor.blue
         sphere.physicsBody?.collisionBitMask = sphere.physicsBody!.contactTestBitMask
         previousPoint = currentPosition 
}

///It Adds a sphere and changes his position
func renderer(_ renderer: SCNSceneRenderer, willRenderScene scene: SCNScene, atTime time: TimeInterval) {
    guard let pointOfView = sceneView.pointOfView else { return }
    let mat = pointOfView.transform
    let dir = SCNVector3(-1 * mat.m31, -1 * mat.m32, -1 * mat.m33)
    let currentPosition = pointOfView.position + (dir * 0.185)

    if buttonPressed {
        if let previousPoint = previousPoint {
            sphere.position = currentPosition
            sceneView.scene.rootNode.addChildNode(sphere)
        }
     }
}

I added the protocol SCNPhysicsContactDelegate to the ViewController, and I set in ViewDidLoad():

override func viewDidLoad() {
    super.viewDidLoad()
    sceneView.delegate = self
    sceneView.scene.physicsWorld.contactDelegate = self
    ///I correctly see the shapes of the sphere and the box physics            bodies using
    sceneView.debugOptions = .showPhysicsShapes
    createBox()
    setUpSphere()
    sceneView.scene = boxScene
    sceneView.scene.physicsWorld.contactDelegate = self
}

Then I added that function:

func physicsWorld(_ world: SCNPhysicsWorld, didEnd contact: SCNPhysicsContact) {
        print("Collision!")
}

enter image description here

This is what happens.

When the two nodes collide nothing happens, so I can't know if the two bodies are touching. Could the problem be about .kinematic, .static or about the function render()? I followed step by step different tutorials about collisions in ARKit: Tutorial 1, Tutorial 2. I have no idea why it doesn't work like expected. Is there something wrong in my code?

Download file code link: https://ufile.io/20sla

like image 819
Edoardo Avatar asked Nov 07 '22 21:11

Edoardo


1 Answers

willRenderScene is called uptown 60 times a second for every time the scene is going to be rendered. Since you're recreating the physics body every time it's probably messing up the physics engine determine collisions.

Try changing your code to only create the physics body once during setup.

like image 96
Craig Siemens Avatar answered Nov 13 '22 05:11

Craig Siemens