Search Unity

AR Foundation - Detecting planes under planes, how to approach this problem?

Discussion in 'AR' started by MarcoElz, May 11, 2019.

  1. MarcoElz

    MarcoElz

    Joined:
    Jan 28, 2017
    Posts:
    17
    Hello,

    Usually I got the problem that the app detects more planes that it should, and those planes are under the real surface.

    How do you approach this problem?

    [Reference Image]
    (https://imgur.com/a/2yuUIb1)​

    I was thinking on trying to erase all planes where their position value on Y was less than 2-3 meters from the camera.
    Or finding only the upper plane and removing all the others.

    Is there a better way?
     
  2. coder89

    coder89

    Joined:
    Oct 26, 2018
    Posts:
    29
    I have also experienced this problem. However, I also noticed some situations where planes appear above the actual floor (closer to the camera) and then your algorithm would fail. Maybe selecting the biggest horizontal surface and projecting all smaller surfaces onto it (to artificially extend the floor if needed)? However, this approach would fail to detect small tables and sofas.
     
  3. blanx

    blanx

    Joined:
    Feb 26, 2016
    Posts:
    73
    We are also fighting with wrong planes. Currently I try to optimize the position to snap to the closest point of the point cloud as these seem to be way more stable than the planes.
     
  4. MarcoElz

    MarcoElz

    Joined:
    Jan 28, 2017
    Posts:
    17
    Mmm you are right, it would be a problem when the app detects fake planes above the real surface...


    That sounds a really interesting approach, I will try it to do something using the point cloud.


    Also, depending on the game or app you are making, I though that maybe giving the user the ability to select and ignore some planes in a configuration state will be helpful, so they can make their own experience the best.

    I hope we find the best approach to this.
     
  5. AlbyDj90

    AlbyDj90

    Joined:
    Feb 7, 2015
    Posts:
    35
    If I remember right, I solved this problem with this approach.
    -scan the surface
    -i found the plane
    -i try to put something on the plane and I record the ID of the plane
    -the next time I try to put something on the plane I only use the plane with the right ID
     
  6. Christin2015

    Christin2015

    Joined:
    Dec 1, 2015
    Posts:
    48
    @AlbyDj90 :
    Additionally , I would also disable the Collider of ARPlanes I do not want to place models on.
     
  7. AlbyDj90

    AlbyDj90

    Joined:
    Feb 7, 2015
    Posts:
    35
    Clever! You can do this every time the system find another plane that is not our plane...
     
    Christin2015 likes this.
  8. coder89

    coder89

    Joined:
    Oct 26, 2018
    Posts:
    29
    If I remember correctly this can change (bug in AR Foundation?) when you are dealing with suspend/resume case. Do you have a solution to overcome that problem?
     
  9. Dalton-Lima

    Dalton-Lima

    Joined:
    Dec 21, 2016
    Posts:
    19
    I am having this same problem.
    You can consider using a minimum area as a threshold. To compute an area we could use the
    ARPlane.size
    and then multiply
    x
    and
    y
    to get the 'bounding box' area.
    I am also considering using the height difference between the plane and our camera. So we can use that as extra info to discard some improbable planes.
     
  10. BuoDev

    BuoDev

    Joined:
    Nov 28, 2018
    Posts:
    45
    Got interested in this and came up with this solution.

    Basically I check which Plane is closest to the hit FeaturePoint.
    Downside is that there is no guarantee that FeaturePoints are hit along the ray.

    But I'm assuming that the ray angle property will be exposed in a future release as seen in
    ARPointCloudManager
    . So there will be a higher chance of hitting a FeaturePoint.


    // TODO: Expose this as a property
    float raycastAngleInRadians = Mathf.Deg2Rad * 5f;


    Code (CSharp):
    1. void Update()
    2.     {
    3.         if (!TryGetTouchPosition(out Vector2 touchPosition))
    4.             return;
    5.  
    6.         //check for hits on Planes
    7.         if (m_RaycastManager.Raycast(touchPosition, s_PlaneHits, TrackableType.PlaneWithinPolygon))
    8.         {
    9.             //check for FeaturePoint hits along the same ray
    10.             if(m_RaycastManager.Raycast(touchPosition, s_PointHits, TrackableType.FeaturePoint))
    11.             {
    12.                 float positionDifference = 20f;
    13.                 Pose nearestPlaneHitPose = s_PlaneHits[0].pose;
    14.  
    15.                 //loop through each Plane hit and check which position is nearest to the FeaturePoint's position
    16.                 for (int i = 0; i < s_PlaneHits.Count; i++)
    17.                 {
    18.                     //if the absolute difference value is smaller (closer to the FeaturePoint)...
    19.                     if (Mathf.Abs(s_PointHits[0].pose.position.magnitude - s_PlaneHits[i].pose.position.magnitude) < positionDifference)
    20.                     {
    21.                         //...give the positionDifference variable a new value
    22.                         positionDifference = Mathf.Abs(s_PointHits[0].pose.position.magnitude - s_PlaneHits[i].pose.position.magnitude);
    23.                         //and the nearestPlaneHitPose variable a new Pose
    24.                         nearestPlaneHitPose = s_PlaneHits[i].pose;
    25.                     }
    26.                 }
    27.  
    28.                 if (spawnedObject == null)
    29.                 {
    30.                     spawnedObject = Instantiate(m_PlacedPrefab, nearestPlaneHitPose.position, nearestPlaneHitPose.rotation);
    31.                 }
    32.                 else
    33.                 {
    34.                     spawnedObject.transform.position = nearestPlaneHitPose.position;
    35.                 }
    36.             }
    37.             //if no featurePoints are hit, just use the first plane that is hit
    38.             else
    39.             {
    40.                 var firstHitPlanePose = s_PlaneHits[0].pose;
    41.  
    42.                 if (spawnedObject == null)
    43.                 {
    44.                     spawnedObject = Instantiate(m_PlacedPrefab, firstHitPlanePose.position, firstHitPlanePose.rotation);
    45.                 }
    46.                 else
    47.                 {
    48.                     spawnedObject.transform.position = firstHitPlanePose.position;
    49.                 }
    50.             }
    51.         }
    52.     }
    edit: Better to compare Vector3's instead of just height
     
    Last edited: Jul 21, 2019
    blanx likes this.
  11. Rs

    Rs

    Joined:
    Aug 14, 2012
    Posts:
    74
    This is more of a note to self and surely redundant to most readers here but.. make sure
    • ARSession Origin and camera are at (0,0,0)
    • Make sure there's only one ARSessionOrigin
    • Make sure there's only one ARRaycastManager
    In particular, the second point was what was giving me an offset. I accidentally created one too many by adding an ARRaycastManager to an object (which adds ARSessionOrigin as it's required).