Unity 4.6 UI: get camera ray through a button?

I have a responsive UI (Screen Space - Overlay) and I want to add a 3D object spinning behind a certain button. (It’s just a menu screen, luckily, so there are no concerns about collisions or lighting.)

To position that object, I need worldspace coordinates. So I want to cast a ray from the camera though the button.

What can I do, equivalent to “ScreenPointToRay” that will give me a ray from the button? (Center, corner, whatever… I can work with it!)

Thanks in advance!

You can use Transform.position and Camera.ScreenPointToRay.

Thanks! It looks like there may be a bug, though, when using that with a CanvasScaler’s Constant Pixel Size scaleFactor set to something other than 1 (as you need to do for retina displays):

EDIT: I think I have pinpointed the bug: http://forum.unity3d.com/threads/reference-new-4-6-ui-object-position-in-worldspace.267082/ (My workaround was to recreate manually the math that positions the UI button, so that I don’t have to access the new UI system at all to get the coordinates. Worked in my case, although it’s extra complexity.)

The following DOES work with scaleFactor = 1, but otherwise, the reported coordinates shift in a way I can’t explain.

Here’s what I’ve tried, in case it helps anyone. This places a 3D object behind a Unity 4.6 UI button (Screen Space - Overlay), pushes the object away from the near-plane so it’s not clipped in half, and scales the object so it remains a constant pixel size regardless of device display size (which my 2D button does naturally via Canvas Scaler, but a 3D object does not: it would appear larger on larger screens).

UnityScript:

var button2D : GameObject;
var object3D : GameObject;

var setBack : float = 2.5; //Distance beyond camera near-plane to render object (otherwise object will clip)

var referenceScreenHeight : float = 1024; //Object already scaled to look right at this arbitrary screen size; must re-scale to compensate for other screen sizes (assuming UI Canvas uses Constant Pizel Size)

...

object3D.transform.position = Camera.main.ScreenToWorldPoint( Vector3( button2D.transform.position.x, button2D.transform.position.y, Camera.main.nearClipPlane + setBack ) );

object3D.transform.localScale *= referenceScreenHeight / Screen.height;