Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert 2D point to 3D using SceneKit's unprojectPoint without having a depth value?

Tags:

ios

3d

scenekit

Is it possible to use SceneKit's unprojectPoint to convert a 2D point to 3D without having a depth value? I only need to find the 3D location in the XZ plane. Y can be always 0 or any value since I'm not using it.

I'm trying to do this for iOS 8 Beta.

I had something similar with JavaScript and Three.js (WebGL) like this:

function getMouse3D(x, y) {
    var pos = new THREE.Vector3(0, 0, 0);
    var pMouse = new THREE.Vector3(
        (x / renderer.domElement.width) * 2 - 1,
       -(y / renderer.domElement.height) * 2 + 1,
       1
    );
    //
    projector.unprojectVector(pMouse, camera);

    var cam = camera.position;
    var m = pMouse.y / ( pMouse.y - cam.y );

    pos.x = pMouse.x + ( cam.x - pMouse.x ) * m;
    pos.z = pMouse.z + ( cam.z - pMouse.z ) * m;

    return pos;
};

But I don't know how to translate the part with unprojectVector to SceneKit.


What I want to do is to be able to drag an object around in the XZ plane only. The vertical axis Y will be ignored.

Since the object would need to move along a plane, one solution would be to use hitTest method, but I don't think is very good in terms of performance to do it for every touch/drag event. Also, it wouldn't allow the object to move outside the plane either.

I've tried a solution based on the accepted answer here, but it didn't worked. Using one depth value for unprojectPoint, if dragging the object around in the +/-Z direction the object doesn't stay under the finger too long, but it moves away from it instead. I need to have the dragged object stay under the finger no matter where is it moved in the XZ plane.

like image 916
CAM Avatar asked Oct 31 '22 21:10

CAM


1 Answers

First, are you actually looking for a position in the xz-plane or the xy-plane? By default, the camera looks in the -z direction, so the x- and y-axes of the 3D Scene Kit coordinate system go in the same directions as they do in the 2D view coordinate system. (Well, y is flipped by default in UIKit, but it's still the vertical axis.) The xz-plane is then orthogonal to the plane of the screen.

Second, a depth value is a necessary part of converting from 2D to 3D. I'm not an expert on three.js, but from looking at their library documentation (which apparently can't be linked into), their unprojectVector still takes a Vector3. And that's what you're constructing for pMouse in your code above — a vector whose z- and y-coordinates come from the 2D mouse position, and whose z-coordinate is 1.

SceneKit's unprojectPoint works the same way — it takes a point whose z-coordinate refers to a depth in clip space, and maps that to a point in your scene's world space.

If your world space is oriented such that the only variation you care about is in the x- and y-axes, you may pass any z-value you want to unprojectPoint, and ignore the z-value in the vector you get back. Otherwise, pass -1 to map to the far clipping plane, 1 for the near clipping plane, or 0 for halfway in between — the plane whose z-coordinate (in camera space) is 0. If you're using the unprojected point to position a node in the scene, the best advice is to just try different z-values (between -1 and 1) until you get the behavior you want.

However, it's a good idea to be thinking about what you're using an unprojected vector for — if the next thing you'd be doing with it is testing for intersections with scene geometry, look at hitTest: instead.

like image 113
rickster Avatar answered Nov 15 '22 06:11

rickster