3

I am trying to get a SCNVector3 from a CGPoint. I am using a gesture recognizer to get the location of a touch (as a CGPoint).

The problem is that the touch doesn't always hit something when I hit test because there isn't always an object being touched. (Touch an empty space to move your ship to that empty spot).

Other Stack Overflow question that I have found uses the SCNHitTestResult to get the worldCoordinates but that doesn't work for me.

Does anyone know how to find this? Given that I know the z coordinate of course. Ships that move always move with a z position of 1.

I Need worldCoordinates to be able to use actions that move a SCNNode to a touch point which has a CGPoint. Thanks!

David Rönnqvist
  • 56,267
  • 18
  • 167
  • 205
Kjell Connelly
  • 247
  • 3
  • 9
  • Is [this the answer](http://stackoverflow.com/questions/22925879/how-do-i-find-my-mouse-point-in-a-scene-using-scenekit/22944797#22944797) you're talking about? Read between the lines there and you'll find a solution. Or wait a couple minutes and I'll finish posting a more specific answer here. – rickster Nov 10 '14 at 18:41

1 Answers1

9

So, you want to turn a point in view space into a point in scene space? The catch to that, of course, is that scene space has a third dimension and view space doesn't. You use the SCNView (or other renderer) methods projectPoint and unprojectPoint to convert between scene space, which is 3D, and view space, which is... also 3D? Yep — two dimensions of screen pixelspoints, and one of normalized depth: the z-coordinate is 0 for points on the near clipping plane and 1 for points on the far clipping plane.

Anyhow, you have a useful constraint in that you're looking to map view-space points onto a specific plane (z=1) in scene space. You have an even more useful constraint if your scene space is oriented so that said plane is orthogonal to the view direction — i.e. the camera is pointing directly in the +z or -z direction.

If you want to map a view-space point to a particular scene-space depth, you need to know what the view-space depth for that plane is. Use projectPoint for that:

SCNVector3 projectedPlaneCenter = [view projectPoint:planeNode.position];
float projectedDepth = projectedPlaneCenter.z;

Now, hold onto that and you can make use of it whenever you need to map a touch location onto that plane:

CGPoint vp = [recognizer locationInView:view];
SCNVector3 vpWithDepth = SCNVector3Make(vp.x, vp.y, projectedDepth);
SCNVector3 scenePoint = [view unprojectPoint:vpWithDepth];

If your scene isn't oriented with the z-axis parallel to the camera, it's a bit harder — you have to work out where your z=1 plane is independently for any view-space point you process. In that case, you might find it easier to add an invisible SCNPlane to your scene and use the hitTest/worldCoordinates method to locate points on that plane.

rickster
  • 124,678
  • 26
  • 272
  • 326
  • `is that scene space has a third dimension and scene space doesn't` => second `scene space` should be `view space` right? – Crashalot Aug 23 '16 at 00:16