简体   繁体   中英

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?

(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.

图片

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)
 }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM