Search Unity

Arfoundation How To Properly Remove Planes And Ref Points

Discussion in 'Handheld AR' started by AndyLangberg, Apr 15, 2019.

  1. AndyLangberg

    AndyLangberg

    Joined:
    Jul 6, 2018
    Posts:
    32
    I have a setup where the user scans for surfaces, clicks on one, and attaches a ref point to that surface. This worked fine until I wanted to implement a reset button that destroys all surfaces and the ref point:



    Code (CSharp):
    1. _arReferencePointManager.TryRemoveReferencePoint(_arRefTrackable);
    2. Destroy(_arRefPoint);
    3. var planeList = new List<ARPlane>();
    4. _arPlaneManager.GetAllPlanes(planeList);
    5. foreach (var arPlane in planeList)
    6.     Destroy(arPlane);
    7.  

    This results in a spam of errors every frame as it's trying to create a new plane at the same position as the one I just removed:


    ArgumentException: An item with the same key has already been added. Key: D04E208B120CD64E-8FF5A5DD81B1B4B2
    at System.Collections.Generic.Dictionary`2[TKey,TValue].TryInsert (TKey key, TValue value, System.Collections.Generic.InsertionBehavior behavior) [0x00000] in <00000000000000000000000000000000>:0
    at UnityEngine.XR.ARFoundation.ARPlaneManager.AddPlane (UnityEngine.Experimental.XR.BoundedPlane boundedPlane) [0x00000] in <00000000000000000000000000000000>:0
    at UnityEngine.XR.ARFoundation.ARPlaneManager.OnPlaneUpdated (UnityEngine.Experimental.XR.PlaneUpdatedEventArgs eventArgs) [0x00000] in <00000000000000000000000000000000>:0
    at System.Action`1[T].Invoke (T obj) [0x00000] in <00000000000000000000000000000000>:0
    at UnityEngine.XR.ARFoundation.ARSubsystemManager.OnPlaneUpdated (UnityEngine.Experimental.XR.PlaneUpdatedEventArgs eventArgs) [0x00000] in <00000000000000000000000000000000>:0
    at System.Action`1[T].Invoke (T obj) [0x00000] in <00000000000000000000000000000000>:0
    at UnityEngine.Experimental.XR.XRPlaneSubsystem.InvokePlaneUpdatedEvent (UnityEngine.Experimental.XR.BoundedPlane plane) [0x00000] in <00000000000000000000000000000000>:0

    (Filename: currently not available on il2cpp Line: -1)


    So it looks like Destroy(ARPlane) isn't a legal way to do it, but looking through the documentation I can't find any other way to remove one. ARSession.Reset() works somewhat, but it resets the camera and everything else, so it's a bit overkill and makes for a bad user experience.
     
    Last edited: Apr 15, 2019
  2. tdmowrer

    tdmowrer

    Unity Technologies

    Joined:
    Apr 21, 2017
    Posts:
    480
    You should not manually Destroy components that are created by one of the managers.

    You can remove a reference point with TryRemoveReferencePoint.

    ARPlanes should not be removed while the plane manager is enabled. The exception you get comes from the fact that it is trying to update the planes almost every frame. Even if we added a check to handle the case where the plane has been destroyed outside its control, it would simply re-add the plane the next time it gets an updated by ARCore or ARKit.

    Having the plane manager enabled tells ARFoundation "I want you to add ARPlanes to my scene and update their GameObjects whenever ARCore/ARKit says they have changed." What are you trying to achieve by Destroy'ing them?
     
  3. AndyLangberg

    AndyLangberg

    Joined:
    Jul 6, 2018
    Posts:
    32
    The main problem some of our test users have reported is that the planes quickly gets quite messy. After moving around between tables there's planes on each one, sometimes several planes overlapping but not joining together for whatever reason, there's planes on the floor beneath the work surfaces, suddenly the laptop gets its own plane, etc etc. So to fix this issue I thought to have the user select a plane in the beginning, add a reference point with an infinitely (more or less) large unity-plane that the user can actually work with, and then hide the meshes of the existing AR planes and new ones. This isn't a problem to do, so far so good.

    Issue comes when the user wants to select a new plane. While the user has moved around there would be a huge new amount of planes being made in the background that he doesn't see, and the second he turns them back on (by re-enabling the meshes), there's going to be a huge mess again. So instead I wanted to simply remove all planes and start scanning anew. But I see no way to do this with the current available functions. Even removing the manager and adding a new one doesn't work, as it's never able to "retrack" a previously tracked surface. The only thing that does work is restarting the whole session, which also restarts the camera. The latter is the implementation I'm currently using, but it does not make for a very smooth user experience. Removing planes would be a whole lot easier, not to mention open up new possibilities for different use cases.
     
  4. tdmowrer

    tdmowrer

    Unity Technologies

    Joined:
    Apr 21, 2017
    Posts:
    480
    If you want to hide/disable certain planes, you can deactivate those GameObjects, e.g.,
    Code (csharp):
    1. foreach(var plane in planes)
    2. {
    3.     plane.gameObject.SetActive(false);
    4. }
    Would that help?
     
  5. AndyLangberg

    AndyLangberg

    Joined:
    Jul 6, 2018
    Posts:
    32
    No, because when the user then "resets" the planes, and we reactivate them, there will suddenly (from the user's point of view) be a ton of planes all over the place that clutters up the place and makes it difficult to choose a new surface. I really need to be able to delete planes for this solution to be viable.
     
  6. Blarp

    Blarp

    Joined:
    May 13, 2014
    Posts:
    158
    remove plane manager.

    use this in your raycast hits at your screen center cursor

    https://docs.unity3d.com/ScriptReference/Experimental.XR.TrackableType.PlaneEstimated.html

    I believe that is closer inline with what you are looking for. You only need to know the plane in which someone is placing a 3d object upon correct? You only need to know the plane position when someone wants to put something down.

    Then slap a reference point so it doesn't drift
     
    Last edited: Apr 30, 2019
  7. Blarp

    Blarp

    Joined:
    May 13, 2014
    Posts:
    158
    ~
     
    Last edited: Apr 30, 2019
  8. AndyLangberg

    AndyLangberg

    Joined:
    Jul 6, 2018
    Posts:
    32
    This is a possible solution. However I think it is good user experience to let the user know which planes they'll be able to select/place the reference point on, as such there needs to be something visible on the screen for the user to click on, which PlaneEstimated doesn't give.
     
    Blarp likes this.
  9. fotalik

    fotalik

    Joined:
    Sep 23, 2017
    Posts:
    18
    @AndyLangberg if you are call
    ARSubsystemManager.planeSubsystem.Stop()
    then ARFoundation will no longer create new Planes in background, while playing user, for example, after player placed an object.
    And when a player presses the Reset button, you need to re-activate this Subsystem again and all Planes return to their places correctly. I had no problems with it :)
     
  10. Arvizio_JD

    Arvizio_JD

    Joined:
    Jan 21, 2019
    Posts:
    1
    We are in the same boat, ARPlaneManager.RemovePlane() only seems to remove the plane till the next update planes event and does not appear to remove the plane from the XRPlaneSubsystem. I tried removing the plane and destroying the game object in trackables with no success. I also tried destroying the ARPlaneManager and creating a new instance of it but as soon as a new plane combines with an existing plane in the XRPlaneSubsystem it disappears, I am assuming because the plane with the original id has been removed from the Trackables object in the scene and when the new plane combines with it the new plane gets destroyed.

    it would be great if there was a way of clearing out the planes in the XRPlaneSubsystem or if ARPlaneManager.RemovePlane() worked as expected. I do not understand the purpose of ARPlaneManager.RemovePlane() if the plane comes back right away and is not removed from the subsystem.

    We most likely use ARSession.Reset() but I also think this is over kill. Resting a single subsystem would be nice as well.

    Justin.
     
  11. AndyLangberg

    AndyLangberg

    Joined:
    Jul 6, 2018
    Posts:
    32
    This doesn't quite do what we want. People who use our app are expected to move to different workplaces, and we don't want "old planes" on other surfaces to still be alive when they do. After a while there's going to be an absolutely massive amount of surfaces that is going to clog up the app and make it messy for the user. We want to be able to remove them without restarting the whole AR session.
     
  12. Tarrag

    Tarrag

    Joined:
    Nov 7, 2016
    Posts:
    85
  13. Blarp

    Blarp

    Joined:
    May 13, 2014
    Posts:
    158
    Use the plane detection as a reference and instantiate your final plane(s) as a new plane gameobject after the fact. That way you have more control over them on cleanup. I'm not sure how you save the generated planes, but instantiate planes in its place and save those instead.

    All those planes have to localize/anchor against something to be in the right spot, such as an image target or point cloud map.