Checking for transparency in texture when clicking on GameObject

Hello community,

My game world is composed of many billboarded quads* displaying textures that contain transparency. All of these quads have colliders, and I’m using NGUI to handle my UI notifications (clicks, drags, etc…).

I’ve modified NGUI so that when UI happens, my own raycasting method gets called. This provides a list of GameObjects that are candidates to handle the UI. I now need to go through each GameObject and determine if the click point corresponds to a transparent pixel on the texture (if so, go on to the next candidate).

I have all of the math in place to know which texture pixel I need to test, but am having a lot of difficulty actually getting the pixel value. I’m targeting mobile, therefore memory is at a premium. Allowing texture reading/writing disallows compression, which exceeds memory constraints if all my textures are left uncompressed.

Some notes:

  1. I do have a working solution: for each texture I want to test, I blit it to a RenderedTexture. I them copy the RenderedTexture to an uncompressed Texture2D and read the pixel value. This works, but bumps my render time from ~0.2 ms to ~15ms on desktop (I’m sure it’s far worse on mobile). Specifically, the more objects there are to test, the more times I have to repeat the above steps in a single frame.

  2. I tried using Graphics.DrawMeshNow, but was never able to catch the output (my RenderedTexture was always empty). I’m guessing DrawMeshNow is async, and I was trying to read the RenderedTexture immediately.

  3. Related to the note above, I would really like a synchronous solution. I essentially trick NGUI into thinking it hit a different GameObject than it did. I’m afraid that if I wait a frame to modify NGUI’s target, something screwy could have already happened.

  4. One thought I had was to render all of my candidate GameObjects to a single RenderTexture using proper depth sorting. I could use a custom shader to give the opaque parts of each texture a unique color. Then it would simply be a matter of testing what color a pixel held at a particular location. This has the advantage of at least stabilizing the performance hit as the list of candidates grows. As with attempting to use Graphics.DrawMeshNow(), I still need to do this in a blocking/synchronous manner.

If you’ve gotten this far, thanks for getting through the wall of text! Also, thanks for any insight you can provide.

*The GameObjects are actually a little more complex than billboarded quads, but that shouldn’t impact anything I’ve discussed. Also, using Sprites is out, because I need functionality that sprites don’t provide.

EDIT: I now have a more targeted version of this question here: Does Graphics.DrawMeshNow() block the thread until rendering is complete - Unity Answers

If anyone has thoughts related specifically to Graphics.DrawMeshNow, the other question is probably the more appropriate place to answer/comment.

So you know which texture and which pixel to test, but can’t read the texture? What if you tried to render only a single quad with this texture, mapping it so the hovered pixel is stretched all over it, render this quad into 1x1 renderTarget and read that?