How can I modify the thrust direction to match the image orientation in SceneKit?


663

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.worldFrontuse 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 .worldFrontthe 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!

663

It seems that the thrust direction must be the negative of the ship node direction localFrontconverted to world coordinates . I don't know enough math about coordinate systems to understand why this is happening, but the following version touchesBegandoes 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 nilthe convertVectorcall to world coordinates. This information actually comes from the function convertPositionin Apple's documentation . The documentation page convertVectoronly shows "No overview available" .

Note that the localFronttype property was introduced in iOS 11.0.

Related


How can I turn the image in the correct orientation?

question_mark_77 I have a sheet of paper with scans of documents on it, I use tesseract to recognize the text, but sometimes the image is in the wrong orientation, then I cut these documents from the sheet and process each document individually, but I need to

How can I modify the content of a range in MATCH()?

ajax333221 I'm doing trim + clean + uppercasethis to make matching IDs easier: =IFNA(MATCH(UPPER(TRIM(CLEAN(A1))), datos!B2:datos!B999, 0), -1)+1 This returns the line number or 0 and works fine. However, I'm currently referencing column B, the modified ID co

How can I modify the content of a range in MATCH()?

ajax333221 I'm doing trim + clean + uppercasethis to make matching IDs easier: =IFNA(MATCH(UPPER(TRIM(CLEAN(A1))), datos!B2:datos!B999, 0), -1)+1 This returns the line number or 0 and works fine. However, I'm currently referencing column B, the modified ID co

How can I change the flow direction of the background image?

username I have a panorama app and it's localized. It applies to the flow of the application: FlowDirection flow = (FlowDirection)Enum.Parse(typeof(FlowDirection), AppResources.ResourceFlowDirection); RootFrame.FlowDirection = flow; This way it applies the or

How can I change the flow direction of the background image?

username I have a panorama app and it's localized. It applies to the flow of the application: FlowDirection flow = (FlowDirection)Enum.Parse(typeof(FlowDirection), AppResources.ResourceFlowDirection); RootFrame.FlowDirection = flow; This way it applies the or

SceneKit - Modify the speed at which a node faces the direction

Dilraj S Devgun I'm currently developing an ARKit game using SceneKit and I'm having trouble controlling and moving nodes. The layout of the game is very simple, I have a node that represents a tank with dynamic physics. I can successfully add nodes to the map

How can I modify this regex to match non-breaking spaces?

Skyler I'm using John Gruber's regular expressions to try and match URLs in documents. I have expressed the regular expression in Python as follows: URL_PATTERN = re.compile(ur'(?i)\b((?:https?://)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<

How can I modify this regex so that it doesn't match * * *

Alexandria (?<!\*)\*([^*]+?)\*(?!\*)/g This is basically a regular expression that matches Markdown italics. It will match the following cases: This *is* Markdown. This *is Markdown.* *This* is *Markdown.* *This is Markdown.* Note: There are negatives here t

How can I modify this regex to match non-breaking spaces?

Skyler I'm using John Gruber's regular expressions to try and match URLs in documents. I have expressed the regular expression in Python as follows: URL_PATTERN = re.compile(ur'(?i)\b((?:https?://)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<