将SCNNode旋转到用户点击的位置

时间:2017-04-26 00:40:48

标签: ios swift scenekit

我希望bobNode查看用户在屏幕上点击的位置。我正在努力旋转bobNode。我正在记录水龙头位置,当我点击时它可以正常工作。我永远不会得到print("Angle: " + String(describing: angle))。应用程序加载时唯一的时间print("Testing Renderer function"),打印11次,之后不再打印。我想我对于旋转bobNode的概念感到困惑。如果我说错了可以有人向我解释如何解决这个问题。

代码:

var sceneView: SCNView! // for now
var bobNode: SCNNode!
var lastTouch: CGPoint? = nil

let bobScene = SCNScene(named: "art.scnassets/man.scn")!

func start(){
    let scene = SCNScene()

    sceneView.delegate = self

    bobNode = bobScene.rootNode.childNode(withName: "Player", recursively: true)!

    bobNode.scale = SCNVector3(x: 0.15, y: 0.15, z: 0.15)
    bobNode.eulerAngles = SCNVector3(x: GLKMathDegreesToRadians(75), y: 0.0, z: GLKMathDegreesToRadians(180))//Don't use rotaion THAT shit is retarded

    scene.rootNode.addChildNode(bobNode)

    sceneView.scene = scene

    let camera = SCNCamera()
    let cameraNode = SCNNode()
    cameraNode.camera = camera
    cameraNode.position = SCNVector3(x: bobNode.position.x, y: bobNode.position.y, z: 10.0)

    scene.rootNode.addChildNode(cameraNode)        

}

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

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

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

private func handleTouches(touches: Set<UITouch>) {
    for touch in touches {
        let touchLocation = touch.location(in: sceneView)
        lastTouch = touchLocation
        print("Touch: " + String(describing: lastTouch))
    }
}

func renderer(_ renderer: SCNSceneRenderer, didSimulatePhysicsAtTime time: TimeInterval) {
    if let _ = bobNode {
        updatePlayer()
    }
}

func updatePlayer() {
    print("Testing Renderer function")
    if let touch = lastTouch {
        let currentPosition = bobNode.position

        let angle = atan2(CGFloat(currentPosition.y) - CGFloat(touch.y), CGFloat(currentPosition.x) - CGFloat(touch.x)) + CGFloat(Double.pi)

        print("Angle: " + String(describing: angle))

        let rotateAction = SCNAction.rotateBy(x: 0.0, y: angle, z: 0.0, duration: 0)

        bobNode.runAction(rotateAction)
    }
}

1 个答案:

答案 0 :(得分:1)

最简单的解决方案是将 SCNLookAtConstraint 添加到bobNode

当您创建SCNLookAtConstraint时,它需要目标SCNNode ,并且SceneKit将在每帧向指定目标旋转bobNode

让我们称之为targetNode(可能没有几何体),它位于用户点击位置正下方的场景3D空间中。当用户点击更改时,它的位置需要更新。

当然,用户点击在屏幕的坐标空间中表示为2D点,需要将其转换为场景的3D空间。

可以使用 SCNView unprojectPoint:方法完成此操作。 你必须传递一个SCNVector3参数,该参数保存屏幕点击的X和Y坐标,它的Z分量介于0.0和1.0之间,表示2D点在场景3D中的投影深度空间(相机的近剪裁平面和远剪裁平面之间)。我想你需要它接近0.0。

设置

// Create the look-at constraint
SCNLookAtConstraint lookAtConstr = [SCNLookAtConstraint lookAtConstraintWithTarget:];

// Set to bobNode's .constraints property
bobNode.constraints = @[lookAtConstr];

每一帧

// tapLocation is the screen tap location from UIEvent
SCNVector3 tapPosition = SCNVector3Make(tapLocation.x, tapLocation.y, 0.0);

// unproject from 2D screen to 3D scene space
SCNVector3 targetNodePosition = [scnView unprojectPoint:tapPosition];

// Update the targetNode position
targetNode.position = targetNodePosition;