Physics 2d Raycast and IPointerDownHandler order problem

I use Physics 2d Raycast and use IPointerDownHandler with a Box2dCollider on some SpriteRenderer

I’m not understanding how is the logic of order. Sometimes appear to be by Z-Order, and sometimes appears to be by Sorting Layer.

Sometimes I aspect of receiving an event to an object, but I receive an event on a sprite with a background sorting layer of an object farthest from a camera.

I aspect physics 2d Raycast work like “physics cast from camera”, so the object near to the camera has priority.

What am I missing? I didn’t find any specs online.

Sprites may all be the same distance.

Three (3) ways that Unity draws / stacks / sorts / layers / overlays stuff:

https://discussions.unity.com/t/841904/2

In short,

  1. The default 3D Renderers draw stuff according to Z depth - distance from camera.

  2. SpriteRenderers draw according to their Sorting Layer and Sorting Depth properties

  3. UI Canvas Renderers draw in linear transform sequence, like a stack of papers

If you find that you need to mix and match items using these different ways of rendering, and have them appear in ways they are not initially designed for, you need to:

  • identify what you are using
  • search online for the combination of things you are doing and how to to achieve what you want.

There may be more than one solution to try.

Additional reading in the official docs:

https://docs.unity3d.com/Manual/2DSorting.html

And SortingGroups can also be extremely helpful in certain circumstances:

https://docs.unity3d.com/Manual/class-SortingGroup.html

Also, generally physics should be done in FixedUpdate(), although I suppose you could call Raycast anywhere. I forget where the pointer interfaces call from but I assume it’s perhaps in the docs, but a good bet might be Update().

Given your setup, it may be necessary for you to do a RaycastAll and decide what to hit, or else an OverlapPoint

Thanks for your replay, but is quite off-topic. I know how rendering works. I ask how the component Physics2DRaycaster decides to dispatch events.

I assume you are specifically asking how IPointerDown and Physics2DRaycaster works. Not Physiscs2D “raycasting” methods which there are there are 3x3(normal, All, NonAlloc) (OverlapPoint, Raycast, GetRayIntersection), don’t use Physics2D.Raycast with 0 length for pointer checks, that’s for rays within 2d plane, not for rays coming from camera, use OverlapPoint or maybe GetRayIntersection instead. The priority for OverlapPoint is described in docs, supposedly it prefers lowest Z value after filtering out by other conditions.

Back to IPointerDown and Physics2DRaycaster. Luckily for you both of them are within uGUI for which all the source code is available. The links I will be giving will be to slightly older version in the public repository, but I doubt things have changed too much. If you want to be sure you can view the actual latest code in Library/PackageCache/com.unity.ugui folder of your project.

So the overall Call sequnce is something like this: InputModuleEventSystem.RaycastAll Physics2DRaycaster.RaycastPhysics2D.GetRayIntersectionAll .

Physics2DRaycaster is using reflections to call GetRayIntersectionAll instead of doing it directly, but that shouldn’t change anything.

The order for Physics2D.GetRayIntersectionAll isn’t clearly defined in docs although since it is a 3D ray I would expect it to be sorted by Z, just like OverlapPoint, but that doesn’t really matter due to stuff that happens afterwards.

After gathering all the raycast hits from all the raycaster modules Event system sorts them using RaycastComparer . Due to this sorting order returned by Physics2D.GetRayIntersectionAll almost doesn’t matter . The ordering established by RaycastComparer is based on many factors:

  • raycast module (for stuff like overlay canvas stuff being on cameras and the order between multiple cameras)

  • sorting layer

  • sorting order

  • depth → doesn’t seem to be set by Physics2DRaycaster

  • distance → seems to be somewhat useless since it uses ```
    Vector3.Distance(eventCamera.transform.position, m_Hits**.point)**

  • wherem_hits.point``` is Vector2d so the Z position is thrown away. Will differ between objects only based on 2D distance from camera center*

  • - index → the order returned by GetRayIntersectionAll, only used if everything else is identical*

While these sorting conditions are somewhat similar to conditions for drawing order sorting there are few differences. 2D sorting axis is completely ignored. When using SortingGroup result will likely be mess unless you have set sorting layers within sorting group to match with the global sorting order in which case you wouldn’t need sorting groups. SortingGroups are also likely to be used in combination with sorting axis (which isn’t taken into account). Even if you attached physics collider to sorting group instead of sprites within sorting group it would still not work since Physics2DRaycaster only takes sorting layer and sortingOrder only from SpriteRenderer, TilemapRenderer, SpriteShapeRenderer. Due to the same reason it will also not take into account sorting layer for noncanvas TextMeshPro text component or any other component which supports sorting layer/order but isn’t one of the 3.

Assuming with this knowledge you still can’t reorganize the structure of your game to get desired clicking priority I see two major options:

A) Don’t use IPointerDown… interfaces for noncanvas objects. Call Physics2D.OverlapPointAll yourself and choose correct result based on your own rules. Most annoying part with this is ensuring that clicking on overlay canvas doesn’t result in clicks on non canvas objects (whole Raycaster/EventSystem/InputModule setup gives that for free). One hacky workaround I have used is placing a transparent rectangle behind all the UI to serve as pointer click receiver, and using pointer events received by that instead of querying raw mouse input API .

B) Customize the sorting order within Unity. Doesn’t seem like you can easily override the sorting order within EventSystem by subclassing it. But you could create your own version of Physics2DRaycaster (it’s only 100lines of code) and set better values within RaycastResult. It would be even simpler if you threw out the part that deals with various cases of maxRayIntersections and the reflections for accessing Physics , since in your game you can probably make reasonable assumptions about both. Adding basic support for SortingGroup and TextmeshPro shouldn’t be difficult, it might even possible to support sorting axis (with some limitations) by storing the position along sorting axis either in distance or depth fields.

1 Like

Note that this is a UI thing, not a feature implemented by the 2D physics or 2D teams. That forum is the best place to ask.

The Physics2DRaycaster was implemented by the UI team. It uses Physics2D.GetRaycastNonAlloc which is a pseudo-3D raycast. 2D physics is obviously 2D only, it uses the XY plane and knows nothing about the Z axis and definately nothing about rendering including sorting groups etc. The above call does a 2D (XY plane) raycast and then sorts the result using the “Transform.position.z” (in the Z direction of the ray) because the 2D raycast knows nothing about Z.

Whilst using Raycast for 3D is correct, there’s only this pseudo-3D call for 2D because in reality, you’d use Physics2D.OverlapPoint. Don’t use the “All” suffixes btw for any 2D physics queries; they allocate a full array and return it each time which is wasteful.

Small correction, order returned by Physics2D.GetRaycastNonAlloc Physics2D.GetRayIntersectionAll slightly matters. Index is the last variable RaycastComparer looks at, if everything else is equal.

Edit: mixed up Raycast with RayIntersection

Was that to me? I don’t follow. I didn’t implement this, I was simply saying how “Physics2D.GetRaycastNonAlloc” works, irrelevant of what Physics2DRaycast does with it which TBH I have no idea of.

Is “index” something related to the internals of “Physics2DRaycast”?

Sorry I meant GetRayIntersectionNonAlloc not GetRaycastNonAlloc . And no it wasn’t addresed to you MelvMay. I was talking about description of EventSystem and Physics2DRaycaster .

1 Like

I didn’t actually notice you typed it wrong, I just typed it wrong myself too! :slight_smile:

From what I see at runtime, the order is based on SortingLayer of the SpriteRenderer, but SortingGroup is ignored.

That caused a lot of confusion because:

a) if the object has not a renderer, z-order wins
b) if has a SpriteRenderers, wins the sorting layer/index, but this is not what I see because drawing order is based on the Sorting Group and axis

So, besides the fact that the component is not fully integrated with other Unity Systems, I think this kind of specs must be in the documentation.

I just moved collider away from SpriteRenderer and its works.

Thanks to all for your contributions.

Agreed. This is why I mentioned that this is a Unity UI thing and that this kind of thing should be mentioned on their forums there! Nobody on this forum has the access to change how that works or modify its documentation.