[Likely Bug] Camera Raycasting Ignores Depth

This is probably a bug, but I’m posting here first to see if I just misunderstand something about raycasting and event handling. In short, I find that a GameObject that is set to handle an input event by implementing an interface like IPointerClickHandler can block raycasts from hitting a UI Button even if the GameObject is BEHIND the button – or, even better, behind the raycasting camera altogether! Unity version is 5.1.1f1

EXPECTED BEHAVIOR: A UI Button on a Canvas (in World Space) in the foreground of the scene should receive a raycast from the camera, thus triggering the button.

OBSERVED BEHAVIOR: The raycast is blocked by a GameObject that handles PointerClick events, regardless of the relative distances from the camera, button, and GameObject.

Try it at home:

1) Create a 2D Orthogonal camera at (0,0, -10) facing toward (0,0,0) – the default camera setup for 2D, I believe.

2) Create a GameObject and give it a BoxCollider2D. Size the collider up so it occupies most or all of your
camera’s view. Put it at (0,0, 10). You can make it a sprite to make it easier to see as you’re working with it.

3) Create a MonoBehaviour that implements IPointerClickHandler. Make OnPointerClick just print something to the console. Attach this script to the GameObject in (2).

4) Create a Canvas. Set the Render Mode to World Space. Drag the scene’s Main Camera into the Event Camera field for the canvas (or don’t – it doesn’t seem to make a difference).

5) On the Canvas object, make sure the Graphic Raycaster has its Blocking Objects and Blocking Mask maxed out (set to All and Everything, respectively).

5) Add a Button to the Canvas from (4). Make its OnClick go to some method that prints to the console.

6) Put the Canvas at (0,0,0) and ensure that the button overlaps (just along the Z-axis) with the collider of the GameObject from (2). You should now see that the click-handling GameObject is in the background, and the canvas with the button is in the foreground (and in world space) . It should look something like the attached image when viewed in 3D.

7) Attach a Physics 2D Raycaster component to the Main Camera.

8) Play the scene, and try to click the button. Despite being in the foreground, the click will NOT go to the button – it will instead go to the GameObject in the background.

9) Adjust the Z-coordinate of the GameObject however you see fit – you can move it further into the background, between the camera and the button (making it the foreground) or even BEHIND the camera, and note that the results are still the same. Even when the GameObject is behind the camera, it blocks the button from receiving a raycast.

10) Reset the scene and adjust the GameObject’s Y-coordinate so that it is no longer overlapping with the button in the Z plane. The button can now be clicked on normally! Disabling the GameObject or its Collider also allows the button to be clicked.


So there’s that. A object behind a camera blocking raycasts in FRONT of the camera feels like a bug to me. Unless convinced otherwise, I’ll submit a formal bug report in a few days.

About a month ago, I found the source of this problem and submitted a bug report (including code changes that would fix it) but it never got made into an issue.

The problem: The Physics 2D Raycaster and Graphic Raycaster used by the EventSystem are using the wrong Raycast method to determine the mouse cursor’s position in the world. They are currently using “Raycast” (or a variant thereof), which flattens things into a 2D plane by throwing out the z-coordinate and then looks for overlaps within that plane. This causes two problems. First, it screws with depth (the problem that my original post mentioned). Tossing the z-coordinate away is how things behind the camera end up getting Pointer events. Second, it’s flat-out wrong when working with a perspective camera and World-Space UI elements. The cursor is typically nowhere near the object that the EventSystem things is getting hit.

The Fix: Instead of using Raycast*, Physics2DRaycaster and GraphicRaycaster need to use GetRayIntersection*. GetRayIntersection is designed for projecting a 3D ray into 2D colliders, which is exactly what we want to to (the cursor exists on the camera’s near clipping plane, and a perspective camera would get a hit object in world space by casting a ray from its focus towards the cursor on the clipping plane and beyond).

Currently, I just made new scripts like BetterPhysics2DRaycaster that replace the offending line, and everything works hunky-dory (though the use of private (vs protected) fields on GraphicRaycaster leads to serialization-related warnings on GraphicRaycaster)). I was unable to simply update the existing GUI library because the core Unity DLLs that the GUI project uses are somehow incompatible with the ones used by the engine (for example, there’s a method which returns a Vector2 in one and a Vector3 in the other).

I’ll happily resubmit the report if someone from Unity asks me to – it’s been a month since I submitted the original.

Hi! :smile: Do you have a bug number?? :slight_smile: I can check up on it for you :smile:

Case 725973

1 Like

Awesome!! You won’t need to resubmit :slight_smile: The first time it was looked at it wasn’t reproducible, but it was kept open because it needs to be looked at again. I put it in the “Look at this sooner, as in now” list :slight_smile: We’ll probably hear back tomorrow :smile:

1 Like

Cool, let me know if you’re having trouble reproing it. I certainly am NOT having a problem doing so. Please note that while my submitted ticket only mentioned Physics2DRaycaster, a similar fix will need to be applied to GraphicRaycaster.