4

Disclaimer: I'm pretty new to Unity3D and ARCore, so please bear with me.

I'm using ARCore in Unity3D to create a scene where the user can select models in a ScrollView on the screen and place them using Google's ARCore framework.

So far I have it working; the user touches a model in the ScrollView (which is indicated on-screen in a Panel as the currently selected model, as my plans are to have the ScrollView toggle visibility for more screen view space).

The problem is that when a user selects a model, ARCore is placing a model on the detected plane behind where the ScrollView and selected model Panel objects are (even when you first touch to start scrolling the ScrollView). See below to help visualize.

enter image description here

How can I get ARCore to not place the object behind the ScrollView and Panel? What I've tried is adding to my controller (which is really just the Google HelloARController) a collection of objects that I want to block ARCore's Raycast and iterate through them with a foreach to see if the Raycast hits the GameObjects in the collection

Touch touch;
if (Input.touchCount < 1 || (touch = Input.GetTouch(0)).phase != TouchPhase.Began)
{
    return;
}

//my code; above is Google's
foreach (var item in BlockingObjects) { //BlockingObjects is a List<GameObject>
    if (IsTouchInObject(FirstPersonCamera.ScreenPointToRay(touch.position), item)) {
        return;
    }
}
//end of my code; below is Google's

TrackableHit hit;
TrackableHitFlag raycastFilter = TrackableHitFlag.PlaneWithinBounds | TrackableHitFlag.PlaneWithinPolygon;

With the IsTouchInObject function defined like this:

private bool IsTouchInObject(Ray ray, GameObject obj) {
    RaycastHit rch;
    Physics.Raycast (ray, out rch);
    return (rch.collider != null);
}

The thing that is failing is that rch.collider is always null (I know that I'm not testing against the object at all, I'll worry about that once I can get the Raycast to actually collide with a GameObject). I've tried using Physics/Physics2D with RaycastHit/RacastHit2D and attaching BoxCollider/BoxCollider2D components to the objects I want to detect the hit on, but nothing I've done is working.

(This solution was taken from something on the Unity3D forums in which someone had a similar issue, but not with AR, with their own 3D world with a 2D overlay. I can't find that forum post to provide reference, sorry).

Any help would be greatly appreciated.

EDIT/NOTE: I've now noticed there is a Graphic Raycaster component on the Canvas, which contains my ScrollView and Panel. I've tried setting the Blocking Objects to Two D (while adding a Box Collider 2D to the ScrollView and Panel) and Blocking Mask to Ignore Raycast (and a couple other things) to no avail. Is there a combination of values for these properties that could do it?

In the spirit of today's date:

Help me, StackOverflow...uh...Kenobi... You're my only hope.

Daevin
  • 778
  • 3
  • 14
  • 31
  • It seems like you have the scroll view on the Surface on which you draw everything. Can't you divide screen into 2 parts ? Surface (for camera and touch) and below it the scroll view ? Than the situation you've mentioned won't be possible – Fixus Dec 17 '17 at 15:12
  • @Fixus right now the `ScrollView` and `Panel` are in the same `Canvas`, but I read somewhere that there can only be 1 `Canvas` in a scene. Is that wrong? Again, I'm quite new to Unity, so I don't know what you mean by dividing the screen into 2 parts. Even doing that, how would I have the `Panel` that displays the selected model floating on top of the AR view? I need a solution for the situation I mentioned, not a way to prevent the situation from happening. This is the layout that I need to create. – Daevin Dec 18 '17 at 18:38

2 Answers2

6

Have you tried wrapping the Raycast with:

 if (!EventSystem.current.IsPointerOverGameObject(touch.fingerId)) {...}

https://answers.unity.com/questions/1406243/ui-in-arcore-helloar-example.html

Saico
  • 544
  • 5
  • 12
  • I don't know why you were downvoted, can someone explain why? Otherwise, this seems to work but it requires adding an `EventSystem` component to the objects, the ramifications of which I don't know, so I'm hesitant to use it. Can someone elaborate, perhaps? – Daevin Dec 27 '17 at 17:01
  • Correction: no, do not add an `EventSystem` component to anything and this works. Although I still would like to know why this was downvoted... (i.e. are there any performance/other issues with using the `IsPointerOverGameObject` method?) – Daevin Dec 27 '17 at 18:54
  • Is there any other solution ? this is not working in arcore 1.13 if (!EventSystem.current.IsPointerOverGameObject(gesture.FingerId)) i had try this for new example – Hardik Nov 20 '19 at 10:52
  • got the solution if any one want. just place this line in ManipulationSystem.cs in update before all update called. – Hardik Nov 20 '19 at 11:01
3

This is my first answer on StackOverflow so bear with me. I'm building a similar app where you can select different models from a UI Panel in unity and place the model on the detected plane in real world. The only hack I was able to devise to overcome the problem you're having is to do the following :

In your HelloARController.CS, initialize a bool 'place_model' (or any name you want) and set it to false. Now you need to scroll to the portion where you augment your model in the real world.

if (Session.Raycast(m_firstPersonCamera.ScreenPointToRay(touch.position), raycastFilter, out hit))
                {
                    // Create an anchor to allow ARCore to track the hitpoint as understanding of the physical
                    // world evolves.



                        var anchor = Session.CreateAnchor(hit.Point, Quaternion.identity);

                        // Intanstiate an Andy Android object as a child of the anchor; it's transform will now benefit
                        // from the anchor's tracking.
                        var andyObject = Instantiate(m_andy, hit.Point, Quaternion.identity,
                            anchor.transform);

                        // Andy should look at the camera but still be flush with the plane.
                        andyObject.transform.LookAt(m_firstPersonCamera.transform);
                        andyObject.transform.rotation = Quaternion.Euler(0.0f,
                            andyObject.transform.rotation.eulerAngles.y, andyObject.transform.rotation.z);

                        andyObject.AddComponent<BoxCollider>();
                        // Use a plane attachment component to maintain Andy's y-offset from the plane
                        // (occurs after anchor updates).
                        andyObject.GetComponent<PlaneAttachment>().Attach(hit.Plane);
}

Change the above code to something like this :

if (place_model){   // changed portion
if (Session.Raycast(m_firstPersonCamera.ScreenPointToRay(touch.position), raycastFilter, out hit))
                {
                    // Create an anchor to allow ARCore to track the hitpoint as understanding of the physical
                    // world evolves.



                        var anchor = Session.CreateAnchor(hit.Point, Quaternion.identity);

                        // Intanstiate an Andy Android object as a child of the anchor; it's transform will now benefit
                        // from the anchor's tracking.
                        var andyObject = Instantiate(m_andy, hit.Point, Quaternion.identity,
                            anchor.transform);

                        // Andy should look at the camera but still be flush with the plane.
                        andyObject.transform.LookAt(m_firstPersonCamera.transform);
                        andyObject.transform.rotation = Quaternion.Euler(0.0f,
                            andyObject.transform.rotation.eulerAngles.y, andyObject.transform.rotation.z);

                        andyObject.AddComponent<BoxCollider>();
                        // Use a plane attachment component to maintain Andy's y-offset from the plane
                        // (occurs after anchor updates).
                        andyObject.GetComponent<PlaneAttachment>().Attach(hit.Plane);

place_model = false // changed portion
    }

}

Now you won't be able to place a model no matter what. Because the script augmenting the model to the real world isn't running, as the bool 'place_model' is set to false. Now, just when you want to augment the model to the real world, you select the model from your panel and set the 'place_model' bool to true. This is simple as you just need to set an event listener to your button, setting the bool to true when you click the button. The next time you touch on the tracked plane, your model gets augmented.

Hope this solves your problem...

Adil.R
  • 180
  • 1
  • 5
  • 19
  • 1
    Well, it doesn't exactly solve my problem, but it seems to provide the same/similar experience as the solution I envisioned. Thanks! – Daevin Dec 27 '17 at 15:33
  • Session doesn't have this method called Raycast anymore. Is there any other alternative? –  Apr 26 '19 at 10:06