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.