Search code examples
scenekitios11

iOS 11 SceneKit hitTest:options: fails


I'm facing a difficult situation using hitTest:options: in SceneKit on iOS 11.

In a maping application I have a terrain node. Using hitTest:options: I was able for long to spot a point on the terrain from a touch on the screen. It still work as expected with released binary on iOS 11, and also on Xcode 9 compiled binary for iOS 10 simulator.

But iOS 11 binary on iOS 11 SDK gives totaly eratic results. Return array from hitTest:options: may contain no result or too many. Moreover, most of the time none of the results is valid. Here below are images to illustrate the point. All image are from a scene with no hidden node.

Edit: I made a test today using hitTestWithSegmentFromPoint:toPoint:options: and got false results also.

First with working simulator.

one hit ok It shows a normal hit on the terrain. The hit point is illustrated with a red ball. It is half inset in the terrain as its center is right on the terrain.

3 hits ok 3 hits ok yaw These two images show a case where the "ray" cross the terrain 3 times. We got 3 hits all placed correctly on the terrain.The second image change the angle of view to show the 3 points.

Now the failing iOS 11 situation:

one hit ko On this picture we got one hit but it is "nowhere" between the two mountains, not on the terrain.

The last two pictures show other attempts with 4 and 16 hits, all "in the blue" with no connection to the terrain.

Sometimes the hit are "away" past the terrain, sometimes they are between the camera and the terrain.

4 hits ko 16 hits ko


Solution

  • Four years latter I went back to this problem and found a solution to my original problem.

    After Apple released iOS 11.2, multiples hits were solved but we got a "no hits" conundrum.

    The problem lies in a specific situation that was not fully explained in the original question. After a terrain is originally computed and displayed we always get a first hit. Then we pan the terrain to center the hit point and rebuild a new terrain sector. In the process, we save computing by reusing severals geometry elements, only changing the z coordinates of the terrain vertexes. The problem lies in reusing the triangle strip SCNGeometryElement. From now on, any terrain built by reusing this object is fine looking but fails the hitTest method.

    It turns out that the SCNGeometryElement can't be reused and should be rebuilt. The originally working code was :

    t_strip = [geom_cour geometryElementAtIndex:0];
    

    To workaround the HitTest: failure we have to do :

    //get current triangle strip
    SCNGeometryElement *t_strip_g = [geom_cour geometryElementAtIndex:0];
    //create a new one using the current as a template
    t_strip = [SCNGeometryElement geometryElementWithData:t_strip_g.data
                                            primitiveType:t_strip_g.primitiveType
                                           primitiveCount:t_strip_g.primitiveCount
                                            bytesPerIndex:t_strip_g.bytesPerIndex];
    

    The current SCNGeometryElement is used as a template to recreate a new one with exactly the same values.