Search code examples
iosswiftrotationarkitscnnode

SCNNode Look At Current Position and Always Orient Relative Up


Problem:

I am attempting to make a node look at the phone with the top of the node ALWAYs pointing towards the north pole of the phone, no matter how the phone is oriented. Let's assume the node is at the center and the phone starts off at (0, 0, 10) and assume the node has a geometry of a rectangle that is similar to that of a phone. I want the top of that rectangle to always point "up" relative to where I am located.

So we have

let node = SCNNode()
node.position = SCNVector3(0, 0, 0)

self.sceneView.pointOfView.position = (0, 0, 10)

//The top of the node should be pointing towards (0, 100, 0) and 
//should be facing the phone.

Initial Position

Now let's move over to self.sceneView.pointOfView.position = (10, 0, 0) so we are going to want the node to follow and rotate about the Y axis 90 degrees.

node.eulerAngles.y = Float(90*Double.pi/180)

change to X axis

Now let's move over the phone to position self.sceneView.pointOfView.position = (0, 10, 0)

We have our initial rotation of 90 degrees around Y-axis and now we are adding a rotation around the ORIGINAL X-axis or the CURRENT Z-axis from our current position. (I say that because I am open to suggestions on how to solve this and I want this understood as much as possible).

So now we have

node.eulerAngles.x = Float(90*Double.pi/180)

and our node is pointing "UP" relative to our position; that is, we are in front of the node, and the node is pointing "UP" based on our past transforms.

enter image description here

My Efforts:

I have attempted using node.look(at:, up:, localFront:) to no avail. I attempted

node.look(at: self.sceneView.pointOfView!.position, up: self.sceneView.pointOfView.worldUp, localFront: SCNNode.localFront)

but this causes the node to move when I rotate the phone and I don't want that to happen. I don't want the node to move when I rotate from landscape to portrait, as well as I don't want the node to rotate.

Question:

How can I make it where the node is always pointing upwards from my position and always look at me, without moving, rotating, or turning when I rotate the phone? I only want X and Y movements. I am open to any suggestions.


Solution

  • func carouselLookAtMe() {
        //Here we use tangent lines on a sphere, relating to the POSITIVE Y Axis, to find the point at which the up direction is.
        let currentPos = self.sceneView.pointOfView!.position
        let D:Float = pow(currentPos.x, 2) + pow(currentPos.y, 2) + pow(currentPos.z, 2)
    
        let newPos = SCNVector3(0, abs(Float(D/Float(currentPos.y))), 0)
        let xDiff = currentPos.x-self.carousel.position.x
        let yDiff = currentPos.y-self.carousel.position.y
        let zDiff = currentPos.z-self.carousel.position.z
    
        let upVectorPos = SCNVector3(newPos.x-xDiff, newPos.y-yDiff, newPos.z-zDiff)
        self.carousel.look(at: self.sceneView.pointOfView!.position, up: upVectorPos, localFront: SCNVector3(0, 0, 1))
    }
    

    Notes: self.carousel is the node that I want to look at me. It stays looking at me while orienting upwards, relatively speaking.

    I call this inside func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor)