How can I modify the thrust direction to match the image orientation in SceneKit?
I have a spaceship image asset which is designed to be "facing" in the +Z direction, with +X on the left and +Y up. I want a SCNVector3() to push in the direction the boat is facing, so that if I apply a force in the direction of the thrust, the boat will move forward. I found an article telling me that I can shipNode.worldFront
use to get the desired vector, but it doesn't work as I expected. I created shipNode and rotated it as below.
shipNode.rotation = SCNVector4(0,1,0,0)
when i position the camera like this
cameraNode.position = SCNVector3(x: 0, y: 0, z: 10)
I saw the front of the boat aimed at me. So far so good. In touchesBegan, I save the thrust direction and print some values. In touchesEnd I reset the position and thrust direction and rotate the boat π/2 radians in the XZ plane
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
thrustDirection = shipNode.worldFront * Float(-1)
print("touchesBegan.rotation \(shipNode.rotation)")
print("touchesBegan.worldFront \(shipNode.worldFront)")
print("touchesBegan.thrustDirection: \(thrustDirection)")
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
print("touchesEnded")
thrustDirection = SCNVector3()
shipNode.position = SCNVector3()
shipNode.rotation.x = 0
shipNode.rotation.y = 1
shipNode.rotation.z = 0
shipNode.rotation.w += Float.pi / 2
}
Even though SceneKit is showing the spaceship correctly (show me first, then right, then back, then left, then again,), the data being printed has (for me) some uninterpretable but consistent values .
touchesBegan.rotation SCNVector4(x: 0.0, y: 1.0, z: 0.0, w: 0.0)
touchesBegan.worldFront SCNVector3(x: 0.0, y: 0.0, z: -1.0)
touchesBegan.thrustDirection: SCNVector3(x: -0.0, y: -0.0, z: 1.0)
touchesEnded
touchesBegan.rotation SCNVector4(x: 0.0, y: 1.0, z: 0.0, w: 1.57079625)
touchesBegan.worldFront SCNVector3(x: -0.25, y: 0.0, z: -0.899999976)
touchesBegan.thrustDirection: SCNVector3(x: 0.25, y: -0.0, z: 0.899999976)
touchesEnded
touchesBegan.rotation SCNVector4(x: 0.0, y: 1.0, z: 0.0, w: 3.1415925)
touchesBegan.worldFront SCNVector3(x: -3.77489542e-08, y: 0.0, z: -0.124999881)
touchesBegan.thrustDirection: SCNVector3(x: 3.77489542e-08, y: -0.0, z: 0.124999881)
touchesEnded
touchesBegan.rotation SCNVector4(x: 0.0, y: 1.0, z: 0.0, w: 4.71238899)
touchesBegan.worldFront SCNVector3(x: 0.25, y: 0.0, z: -0.899999976)
touchesBegan.thrustDirection: SCNVector3(x: -0.25, y: -0.0, z: 0.899999976)
touchesEnded
touchesBegan.rotation SCNVector4(x: 0.0, y: 1.0, z: 0.0, w: 6.28318501)
touchesBegan.worldFront SCNVector3(x: 7.54979084e-08, y: 0.0, z: -1.0)
touchesBegan.thrustDirection: SCNVector3(x: -7.54979084e-08, y: -0.0, z: 1.0)
touchesEnded
The first data section looks correct - the boat is heading in the desired direction, but the second, third and fourth data sections have strange values for .worldFront
the given number of reported rotations . In case 2, the boat went towards me, but slipped slightly to the right. In the 3rd case, the spaceship backed up towards me. In case 4, the ship is heading towards me, but swiping a little to the left. When I rotate 2π radians, the spaceship is facing and moving forward correctly again.
As of this writing, I've read all the articles suggested by SO, and read the Apple SceneKit documentation, but can't explain the behavior I'm seeing. What am I missing? thank you for your help!
It seems that the thrust direction must be the negative of the ship node direction localFront
converted to world coordinates . I don't know enough math about coordinate systems to understand why this is happening, but the following version touchesBegan
does work.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
thrustDirection = shipNode.convertVector(SCNNode.localFront, to: nil)
thrustDirection.x = -thrustDirection.x
thrustDirection.y = -thrustDirection.y
thrustDirection.z = -thrustDirection.z
}
Converts nil
the convertVector
call to world coordinates. This information actually comes from the function convertPosition
in Apple's documentation . The documentation page convertVector
only shows "No overview available" .
Note that the localFront
type property was introduced in iOS 11.0.