Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ARkit how to rotate an object to face another object

In developing an AR game app, I run into one (actually two but if I figure out a way to tackle this problem, then there is another expected issue) problem that is my 3D objects do not face a target object. The second expected issues is is it possible that the objects keeps looking at other moving objects?

Lets say that for the first issue, the Xcode default project of AR comes with the spaceship node which is floating up in the space, and when I add an object called like B, then I want the head of spaceship to point to the B object anytime.

For the second issue, how to monitor all positions of moving objects in ARSCNView and make a node face the moving ones by tracking the movement of them? Like As are moving and B is keeping track of the position of As and points itself to As the whole time in the app.

Could you give me hints or solutions to figure this out?

like image 921
Ryohei Avatar asked Jan 30 '26 21:01

Ryohei


1 Answers

(1). You can use billboardConstraint to make focus to camera view always with it's free axes, like

    let billboardConstraint = SCNBillboardConstraint()
    billboardConstraint.freeAxes = SCNBillboardAxis.Y
    someNode.constraints = [billboardConstraint]

This someNode always be focus on camera because we make Y axis as to be free to rotate and other 2 axis are fixed with respect to camera.

(2). How to achieve: 2 nodes will focus with each other: We can use SCNLookAtConstraint for this case.

like:

    let lookAtConstraints = SCNLookAtConstraint(target: node3)
    node2.constraints = [lookAtConstraints] 

so node2 always looks at node3 for the entire session.

For understanding, you can refer the following piece of code:

 // Create different geometry nodes
 enum GeometryType {
     case Box
     case Pyramid
     case Capsule
     case Cone
    case Cylinder
  }

  func getGeometry(type: GeometryType) -> SCNGeometry {
    switch type {
    case .Box:          return SCNBox(width: 0.2, height: 0.2, length: 0.2, chamferRadius: 0.05)
    case .Pyramid:      return SCNPyramid(width: 0.2, height: 0.2, length: 0.2)
    case .Capsule:      return SCNCapsule(capRadius: 0.2, height: 0.1)
    case .Cone:         return SCNCone(topRadius: 0.0, bottomRadius: 0.2, height: 0.4)
    case .Cylinder:     return SCNCylinder(radius: 0.05, height: 0.2)
    }
}

// Let's do the experiment:

func threeNodesExperiment() {

    // always focus on camera view
    let geometry1 : SCNGeometry! = getGeometry(type: .Pyramid)
    geometry1.firstMaterial?.diffuse.contents = UIColor.red
    let node1 = SCNNode(geometry: geometry1)
    node1.position = SCNVector3Make(0.4, 0, -0.5)

    let billboardConstraint = SCNBillboardConstraint()
    billboardConstraint.freeAxes = SCNBillboardAxis.Y
    node1.constraints = [billboardConstraint]
    rootNode.addChildNode(node1)

    // two nodes focusing each other
    let geometry2 = getGeometry(type: .Cylinder)
    geometry2.firstMaterial?.diffuse.contents = UIColor.green
    let node2 = SCNNode(geometry: geometry2)
    node2.position = SCNVector3Make(-0.1, 0, -0.5)

    let geometry3 = getGeometry(type: .Box)
    geometry3.firstMaterial?.diffuse.contents = UIColor.blue
    let node3 = SCNNode(geometry: geometry3)
    node3.position = SCNVector3Make(0.2, 0, -0.5)

    let lookAtConstraints = SCNLookAtConstraint(target: node3)
    node2.constraints = [lookAtConstraints]

    [node2, node3].forEach{ rootNode.addChildNode($0) }
}

Output:

node1 (red node) always be focus to camera view. (change camera position and do experiment).

node2 (green node) and node3 (blue node) are always looking each other.

image

Custom Rotation with some theta value to a 3-D node:

(1). Using CAAnimation:

// (1). CAAnimation
private func rotateNode(node : SCNNode, theta : Double, with animation : Bool = false) {
    if animation {
        let rotation = CABasicAnimation(keyPath: "rotation")
        rotation.fromValue = SCNVector4Make(0,1,0,0) // along x-z plane
        rotation.toValue = SCNVector4Make(0,1,0,Float(theta))
        rotation.duration = 3.0
        rotation.repeatCount = Float.infinity
        node.addAnimation(rotation, forKey: "Rotate it")
    }
    node.rotation = SCNVector4Make(0, 1, 0, Float(theta))  // along x-z plane
    print("rotating node with angel :\(theta)")
}

(2). SCNTransaction

// (2). SCNTransaction
private func rotateUsingTransaction(node : SCNNode, theta : Double) {
    SCNTransaction.begin()
    SCNTransaction.animationDuration = 5.0
    node.rotation = SCNVector4Make(0, 1, 0, Float(theta))
    SCNTransaction.completionBlock = {
        print("Transaction completed")
    }
    SCNTransaction.commit()
}

(3). SCNAction

// (3). SCNAction
private func moveUpDown(node : SCNNode) {
    let moveUp = SCNAction.moveBy(x: 0, y: 1, z: 0, duration: 1)
    moveUp.timingMode = .easeInEaseOut
    let moveDown = SCNAction.moveBy(x: 0, y: -1, z: 0, duration: 1)
    moveDown.timingMode = .easeInEaseOut
    let moveSequence = SCNAction.sequence([moveUp,moveDown])
    let moveLoop = SCNAction.repeatForever(moveSequence)
    node.runAction(moveLoop)
 }
like image 57
Ashis Laha Avatar answered Feb 01 '26 12:02

Ashis Laha



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!