How to find out if the surface detected by ARKit is no more available?

2.2k views Asked by At

I am working on an application with ARKit and SceneKit frameworks. In my application I have enabled surface detection (I followed the placing objects sample provided by Apple). How to find if the surface detected is no more available? That is, initially only if user has detected the surface in ARSession I am allowing him to place the 3D object.

But if the user moves rapidly or focuses somewhere, the detected surface area is getting lost. In this case if the user tries to place another object I shouldn't allow him to place it until he scans the floor again and get the surface corrected.

Is there any delegate which is available to let us know that the surface detected is no more available?

2

There are 2 answers

6
Alan On

There are delegate functions that you can use. The delegate is the ARSCNViewDelegate

It has a function that is renderer(_:didRemove:for:) that fires when an ARAnchor has been removed. You can use this function to perform some operation when a surface gets removed.

ARSCNViewDelegate Link

0
rickster On

There are two ways to “lose” a surface, so there’s more than one approach to dealing with such a problem.


As noted in the other answer, there’s an ARSCNViewDelegate method that ARKit calls when an anchor is removed from the AR session. However, ARKit doesn’t remove plane anchors during a running session — once it’s detected a plane, it assumes the plane is always there. So that method gets called only if:

  1. You remove the plane anchor directly by passing it to session.remove(anchor:), or
  2. You reset the session by running it again with the .removeExistingAnchors option.

I’m not sure the former is a good idea, but the latter is important to handle, so you probably want your delegate to handle it well.


You can also “lose” a surface by having it pass out of view — for example, ARKit detects a table, and then the user turns around so the camera isn’t pointed at or near the table anymore.

ARKit itself doesn’t offer you any help for dealing with this problem. It gives you all the info you need to do the math yourself, though. You get the plane anchor’s position, orientation, and size, so you can calculate its four corner points. And you get the camera’s projection matrix, so you can check for whether any point is in the viewing frustum.

Since you’re already using SceneKit, though, there are also ways to get SceneKit to do the math for you... Working backwards:

  1. SceneKit gives you an isNode(_:insideFrustumOf:) test, so if you have a SCNNode whose bounding box matches the extent of your plane anchor, you can pass that along with the camera (view.pointOfView) to find out if the node is visible.
  2. To get a node whose bounding box matches a plane anchor, implement the ARSCNViewDelegate didAdd and didUpdate callbacks to create/update an SCNPlane whose position and dimensions match the ARPlaneAnchor’s center and extent. (Don’t forget to flip the plane sideways, since SCNPlane is vertically oriented by default.)
  3. If you don’t want that plane visible in the AR view, set its materials to be transparent.