Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to move car body along wheels in swift?

Tags:

ios

swift

arkit

I have been trying to move car body along with wheels. I have creating augmented reality project, where placing car model in horizontal plane and Car are controlled by four buttons namelu acceleration, steering, reverse and brake. car left, right are controller by steering while acceleration and reverse.

Actually now i can able to placing 3d car model in horizontal plane but dont know how to rotate car wheels like forward and backward along with car body.

Here is the code where i have been trying for placing 3d object:

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

    if let touch = touches.first {

        // gives us the location of where we touched on the 2D screen.
        let touchLocation = touch.location(in: sceneView)

        // hitTest is performed to get the 3D coordinates corresponding to the 2D coordinates that we got from touching the screen.
        // That 3d coordinate will only be considered when it is on the existing plane that we detected.
        let results = sceneView.hitTest(touchLocation, types: .existingPlaneUsingExtent)

        // if we have got some results using the hitTest then do this.
        if let hitResult = results.first {


           let boxScene = SCNScene(named: "art.scnassets/porsche.scn")!

            if let boxNode = boxScene.rootNode.childNode(withName: "car", recursively: true) {
                print("box:::\(boxNode.childNodes)")

                boxNode.position = SCNVector3(x: hitResult.worldTransform.columns.3.x, y: hitResult.worldTransform.columns.3.y + 0.15, z: hitResult.worldTransform.columns.3.z)

                // finally the box is added to the scene.
                sceneView.scene.rootNode.addChildNode(boxNode)

            }


        }

    }
}

Detecting horizontal plane functionality code:

   func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {

    if anchor is ARPlaneAnchor {

        // anchors can be of many types, as we are just dealing with horizontal plane detection we need to downcast anchor to ARPlaneAnchor
        let planeAnchor = anchor as! ARPlaneAnchor

        // creating a plane geometry with the help of dimentions we got using plane anchor.
        let plane = SCNPlane(width: CGFloat(planeAnchor.extent.x), height: CGFloat(planeAnchor.extent.z))

        // a node is basically a position.
        let planeNode = SCNNode()

        // setting the position of the plane geometry to the position we got using plane anchor.
        planeNode.position = SCNVector3(x: planeAnchor.center.x, y: 0, z: planeAnchor.center.z)

        // when a plane is created its created in xy plane instead of xz plane, so we need to rotate it along x axis.
        planeNode.transform = SCNMatrix4MakeRotation(-Float.pi/2, 1, 0, 0)

        //create a material object
        let gridMaterial = SCNMaterial()

        //setting the material as an image. A material can also be set to a color.
        gridMaterial.diffuse.contents = UIImage(named: "art.scnassets/grid.png")

        // assigning the material to the plane
        plane.materials = [gridMaterial]


        // assigning the position to the plane
        planeNode.geometry = plane

        //adding the plane node in our scene
        node.addChildNode(planeNode)



    }

    else {

        return
    }

}

Any help much appreciated!!!

like image 981
PvDev Avatar asked May 15 '18 09:05

PvDev


1 Answers

This is quite comprehensive task.

You should make your car as SCNPhysicsVehicle subclass.

SCNPhysicsVehicle is a physics behavior that modifies a physics body to behave like a car, motorcycle, or other wheeled vehicle.

To build a vehicle, designate an SCNPhysicsBody object as its chassis and an array of SCNPhysicsVehicleWheel objects as its wheels. For each wheel, you define physical characteristics such as suspension and traction, and associate a node in your scene to provide the wheel’s size and visual representation. After you construct a vehicle, you can control it in terms of acceleration, braking, and steering.

General: https://developer.apple.com/documentation/scenekit/scnphysicsbody

For wheels: https://developer.apple.com/documentation/scenekit/scnphysicsvehiclewheel

Example:

var vehicle = SCNPhysicsVehicle()
  1. You need to create ground with static body.

    func createGround(planeAnchor: ARPlaneAnchor) -> SCNNode {
       let ground = SCNNode(geometry: SCNPlane(width: CGFloat(planeAnchor.extent.x), height: CGFloat(CGFloat(planeAnchor.extent.z))))
       ground.position = SCNVector3(planeAnchor.center.x,planeAnchor.center.y,planeAnchor.center.z)
       ground.eulerAngles = SCNVector3(90.degreesToRadians, 0, 0)
       let staticBody = SCNPhysicsBody.static() // it must be static
       ground.physicsBody = staticBody
       return ground
       }
    
  2. You need to setup your car.

    func setupCar() {
    
    let scene = SCNScene(named: "YourScene.scn")
    let chassis = (scene?.rootNode.childNode(withName: "chassis", recursively: true))! // Your chassis
    let frontLeftWheel = chassis.childNode(withName: "frontLeftWheel", recursively: true)!
    let frontRightWheel = chassis.childNode(withName: "frontRightWheel", recursively: true)!
    let rearLeftWheel = chassis.childNode(withName: "rearLeftWheel", recursively: true)!
    let rearRightWheel = chassis.childNode(withName: "rearRightWheel", recursively: true)!
    
    // physic behavior for wheels
    
    let v_frontLeftWheel = SCNPhysicsVehicleWheel(node: frontLeftWheel)
    let v_frontRightWheel = SCNPhysicsVehicleWheel(node: frontRightWheel)
    let v_rearRightWheel = SCNPhysicsVehicleWheel(node: rearLeftWheel)
    let v_rearLeftWheel = SCNPhysicsVehicleWheel(node: rearRightWheel)
    
    
    chassis.position = SCNVector(0,0,0) // insert your desired position
    let body = SCNPhysicsBody(type: .dynamic, shape: SCNPhysicsShape(node: chassis, options: [SCNPhysicsShape.Option.keepAsCompound: true]))
    body.mass = 1
    chassis.physicsBody = body
    self.vehicle = SCNPhysicsVehicle(chassisBody: chassis.physicsBody!, wheels: [v_rearRightWheel, v_rearLeftWheel, v_frontRightWheel, v_frontLeftWheel])
    self.sceneView.scene.physicsWorld.addBehavior(self.vehicle)
    self.sceneView.scene.rootNode.addChildNode(chassis)
    }
    
    1. Now you can manipulate with your car.

       func renderer(_ renderer: SCNSceneRenderer, didSimulatePhysicsAtTime time: TimeInterval) {
      
       var engineForce: CGFloat = 5
       var brakingForce: CGFloat = 0
      
       // here you can manipulate your car steering angle
       self.vehicle.setSteeringAngle(0, forWheelAt: 2) 
       self.vehicle.setSteeringAngle(0, forWheelAt: 3)
      
      
       self.vehicle.applyEngineForce(engineForce, forWheelAt: 0)
       self.vehicle.applyEngineForce(engineForce, forWheelAt: 1)
       self.vehicle.applyBrakingForce(0, forWheelAt: 0)
       self.vehicle.applyBrakingForce(0, forWheelAt: 1)
       }
      

P.S. Don't forget to add to your viewDidLoad():

        self.sceneView.delegate = self
        self.sceneView.scene?.physicsWorld.contactDelegate = self

P.P.S This is only general idea, you must do some research and find working solution to your specific situation.

A little hint for you, steering can be done via CoreMotion.

I hope it helped!

like image 94
Eugene Avatar answered Nov 17 '22 22:11

Eugene