Frage

I have 2 layers: GUI Layer, and 3D Layer. Each layer has a camera.

GUI Layer Camera settings:

  • Clear Flags: Depth only
  • Culling Mask: GUI Layer
  • Depth: -1
  • Component: a C# script with OnGUI() logic
  • GUILayer, Flare Layer & Audio Listener: On

3D Layer Camera settings:

  • Clear Flags: Depth only
  • Culling Mask: Everything but GUI Layer
  • Depth: 0
  • GUILayer, Flare Layer & Audio Listener: Off

My goal is to show the GUI elements behind 3D elements. The settings are okay, if the C# script is removed / disabled and GUITexture components used instead. However, by using GUITexture component, it is hard to control the size & logic via script.

Therefore, I have some images drawn by GUI.DrawTexture() in scripts assigned to camera. For example:

GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), 
                backgroundTexture, ScaleMode.StretchToFill);

Although the script is attached to GUI Layer as Component, it does not draw behind the 3D objects; instead it is drawn in front of 3D objects.

My question is, how to assign GUI.DrawTexture() to draw on specific layer / how to make the images drawn behind the 3D object?


Update Tried GUI.Depth = -99; in OnGUI() doesn't change the situation.

War es hilfreich?

Lösung

There's no way to draw GUI elements behind 3D objects - unless you use Render Textures! Use a special camera for the 3D objects that you want in the front of the GUI elements, set this camera to render to a texture, and draw this texture in front of the others.

To render to a texture, click on the camera and see its settings on the Inspector; there will be a Target Texture, assign it to a texture. The camera will now draw on this texture, and you can use your GUI.DrawTexture code to draw it in front of other textures.

You need Unity Pro to use this feature.


To check for clicks in these bunch of textures, the textures that are clickable can be verified if you create them like this:

Rect r = new Rect(x,y,width,height);
GUI.DrawTexture(r, texture);
Input.GetMouseButton(0)
    if (r.Contains(Event.current.mousePosition)) DoStuff();

Now the problem is if you want to exclude a click in a button that is behind the 3D object when you click the 3D object. This is more complicated.

You'll first need to detect the click in the 3D object texture (like the code above).

Then, if true, you'll have to cast a ray from the 3D camera (the camera that you assigned the texture) using the mouse coordinates (I think it may be easier to use Camera.ViewportPointToRay() than Camera.ScreenPointToRay to map the coordinates correctly, probably).

Finally, if some 3D object was hit, you just don't check the UI textures.

Andere Tipps

To draw a GUITexture in a specific layer, say "GUI Layer" in the following case, you can use the following:

void Start() {
  GameObject go = new GameObject();
  Rect r = new Rect(0, 0, 100, 100); // the size
  go.AddComponent(new GUITexture().GetType());
  go.guiTexture.pixelInset = r;
  go.guiTexture.texture = (Texture2D)Resources.Load("graphics_name"); // must be placed in Assets/Textures/UI/Resources
  go.layer = LayerMask.NameToLayer("GUI Layer");
  go.transform.position = new Vector3(0, 0, 24);
  go.transform.localScale = new Vector3(0, 0, 1);
  go.name = "some name";
}

Control the order of layer by setting Depth of cameras, with each camera drawing different layer and proper culling mask configured.

You can have a 3D object over your GUITexture, to do so you just have to call the Render method of the camera you want to be on the top:

public Camera GUIcamera;
void OnGUI() {
    // Do your normal GUI stuff here, GUI.DrawTexture or whatever
    GUIcamera.Render ();
}

Of course you will need to have the GUIcamera configured correctly:

  • Less depth than the main camera
  • Clear Flags should be "Depth Only"
  • Culling Mask should be only the layer(s) where the objects to be at top are.
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top