Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Draw a simple rectangle filled with a color

Discussion in 'Immediate Mode GUI (IMGUI)' started by Cascho01, Dec 21, 2011.

  1. Cascho01

    Cascho01

    Joined:
    Mar 19, 2010
    Posts:
    1,347
    We can draw labels with a texture inside, but how to draw a rectangle (label) with just a color in it?
     
  2. jedy

    jedy

    Joined:
    Aug 1, 2010
    Posts:
    579
    1. Create a new Texture2D(1,1)
    2. Fill it with the desired color ( SetPixel )
    3. Set it's wrap mode to repeat
    4. Use Texture2D.Apply() to apply the changes
    5. Create a GUIStyle
    6. Set it's .normal background texture to the texture you just created
     
  3. Cascho01

    Cascho01

    Joined:
    Mar 19, 2010
    Posts:
    1,347
    Thanks, that´s what I do so far, thought there must be an easier way!
     
  4. jedy

    jedy

    Joined:
    Aug 1, 2010
    Posts:
    579
    This is pretty efficient. No need for anything else.
     
    karan-veer likes this.
  5. Cascho01

    Cascho01

    Joined:
    Mar 19, 2010
    Posts:
    1,347
    function OnGUI () {
    GUI.Label (Rect (25, 25, 100, 30), color);
    }

    would be muuuuuch easier :D
     
  6. jedy

    jedy

    Joined:
    Aug 1, 2010
    Posts:
    579
    It's how it should look
    GUI.Label(Rect(25, 25, 100, 30), style);
    Simple as that.

    Make sure to initialize the texture2d and the style just once, otherwise your garbage collection will go crazy and cause spikes.
     
  7. Cascho01

    Cascho01

    Joined:
    Mar 19, 2010
    Posts:
    1,347
    Ok, thanks, what I don´t like is filling up a texture and blowing it up just to render some pixels on screen -especially when the color is changing often in runtime.
    No problem if there´s no other way!
     
    chummydino likes this.
  8. kblood

    kblood

    Joined:
    Jun 20, 2012
    Posts:
    92
    I found this code in another thread and it helped me doing this easy:

    void DrawQuad(Rect position, Color color) {
    Texture2D texture = new Texture2D(1, 1);
    texture.SetPixel(0,0,color);
    texture.Apply();
    GUI.skin.box.normal.background = texture;
    GUI.Box(position, GUIContent.none);
    }

    I hope it helps others as well.
     
  9. ProbePLayer

    ProbePLayer

    Joined:
    Oct 19, 2012
    Posts:
    19
    Awesome! that code really worked for me. Thanks kblood.
     
    Eristen likes this.
  10. IQpierce

    IQpierce

    Joined:
    Jan 24, 2011
    Posts:
    43
    kblood's code is horrible and will cause your game to break. Do not use it. Read the warning from jedy two messages up: initializing a new Texture2D object in every OnGUI call (i.e. every frame) will be a huge memory problem. Additionally, there's no reason to set "GUI.skin.box.normal.background" - this is changing the look of a default skin and can affect how other GUIs appear.

    As an aside, I don't understand why this is so hard to do in Unity's own GUI tools - why aren't there simple DrawRect, DrawLine, DrawCircle, etc. functions? It's very odd to me.

    Here is code that works and doesn't chew through memory indefinitely:

    Code (csharp):
    1.  
    2.    
    3.     private static Texture2D _staticRectTexture;
    4.     private static GUIStyle _staticRectStyle;
    5.  
    6.     // Note that this function is only meant to be called from OnGUI() functions.
    7.     public static void GUIDrawRect( Rect position, Color color )
    8.     {
    9.         if( _staticRectTexture == null )
    10.         {
    11.             _staticRectTexture = new Texture2D( 1, 1 );
    12.         }
    13.  
    14.         if( _staticRectStyle == null )
    15.         {
    16.             _staticRectStyle = new GUIStyle();
    17.         }
    18.  
    19.         _staticRectTexture.SetPixel( 0, 0, color );
    20.         _staticRectTexture.Apply();
    21.  
    22.         _staticRectStyle.normal.background = _staticRectTexture;
    23.  
    24.         GUI.Box( position, GUIContent.none, _staticRectStyle );
    25.  
    26.  
    27.     }
    28.  
     
    ZO5KmUG6R, ruudvangaal, Xevin and 3 others like this.
  11. CB-InDev

    CB-InDev

    Joined:
    Apr 4, 2014
    Posts:
    11
    Thanks for sharing, I'm new to Unity and was looking for some tutorials on simple 2D app creation.

    I find it interesting that unlike other IDEs, adding a button/box/text/etc... seems a little more complex in Unity. Maybe I am missing a toolbar or something.

    Let me know if you can help.

    As an example, in my signature I show an app (PopQuiz!) I created with Visual Studio for WIndows 8. Creating an app like this for Unity is my goal, so I can transfer it to other platforms easily.
     
  12. artificialfool

    artificialfool

    Joined:
    Nov 29, 2012
    Posts:
    2
    Thanks very much IQpierce, just what I needed.
     
  13. Rachan

    Rachan

    Joined:
    Dec 3, 2012
    Posts:
    759
    Be careful Texture2D texture = new Texture2D(1, 1); will eating your memory :)
     
  14. mh114

    mh114

    Joined:
    Nov 17, 2013
    Posts:
    295
    No need to update the texture all the time. Just set the texture pixel to white (once, when creating it) and set the GUI.color before drawing the box. (You should also save the original GUI color and restore it after drawing the box.)
     
    Xevin likes this.
  15. Obsidanse

    Obsidanse

    Joined:
    Mar 2, 2014
    Posts:
    3
    Why there isn't an option of (new Rect (x,y,w,h),colour) is beyond me.
     
  16. Cameron_SM

    Cameron_SM

    Joined:
    Jun 1, 2009
    Posts:
    915
    The code given in this thread isn't terribly efficent. This is what I use:

    Code (CSharp):
    1.  
    2. public static class EditorGUITools
    3. {
    4.  
    5.     private static readonly Texture2D backgroundTexture = Texture2D.whiteTexture;
    6.     private static readonly GUIStyle textureStyle = new GUIStyle {normal = new GUIStyleState { background = backgroundTexture } };
    7.  
    8.     public static void DrawRect(Rect position, Color color, GUIContent content = null)
    9.     {
    10.         var backgroundColor = GUI.backgroundColor;
    11.         GUI.backgroundColor = color;
    12.         GUI.Box(position, content ?? GUIContent.none, textureStyle);
    13.         GUI.backgroundColor = backgroundColor;
    14.     }
    15.  
    16.     public static void LayoutBox(Color color, GUIContent content = null)
    17.     {
    18.         var backgroundColor = GUI.backgroundColor;
    19.         GUI.backgroundColor = color;
    20.         GUILayout.Box(content ?? GUIContent.none, textureStyle);
    21.         GUI.backgroundColor = backgroundColor;
    22.     }
    23. }
    24.  
     
    Last edited: Aug 14, 2016
  17. KeinZantezuken

    KeinZantezuken

    Joined:
    Mar 28, 2017
    Posts:
    53
    Cameron860

    is
    Code (CSharp):
    1.  private static readonly Texture2D backgroundTexture = Texture2D.whiteTexture;
    possible at runtime? I tried it but the "texture" is being transparent/invisible as if it does not present. Variant with initializing new texture at Start/Awake works fine ofc:

    Code (CSharp):
    1. public void Awake()
    2. {
    3.         if(drawTexture == null )
    4.         {
    5.             drawTexture  = new Texture2D( 1, 1 );
    6.            drawTexture.SetPixel( 0, 0, color );
    7.            drawTexture.Apply();
    8.         }
    9. }
    10.  
     
  18. ARRAYEWHY

    ARRAYEWHY

    Joined:
    Jan 9, 2014
    Posts:
    9
    Works like a charm! Thank you so much!
     
  19. cielbird

    cielbird

    Joined:
    Dec 15, 2017
    Posts:
    11
    First off that was just rude. With that aside, it would be better to define the texture at the beginning in an awake or start function. Here's how I would do it:
    Code (csharp):
    1.  
    2.     private static Texture2D _staticRectTexture;
    3.     private static GUIStyle _staticRectStyle;
    4.    
    5.     void Awake(){
    6.            _staticRectTexture = new Texture2D( 1, 1 );
    7.            _staticRectStyle = new GUIStyle();
    8.     }
    9.  
    10.     public static void GUIDrawRect( Rect position, Color color )
    11.     {
    12.  
    13.         _staticRectTexture.SetPixel( 0, 0, color );
    14.         _staticRectTexture.Apply();
    15.  
    16.         _staticRectStyle.normal.background = _staticRectTexture;
    17.  
    18.         GUI.Box( position, GUIContent.none, _staticRectStyle );
    19.  
    20.     }
    21.  
     
    ffxiangyu and TashaSkyUpchurch like this.
  20. Mikilo

    Mikilo

    Joined:
    Jan 29, 2013
    Posts:
    694
    I don't understand why he is being rude. He is clearly right. The code was horrible and people liked it.

    And your code implies to work in a MonoBehaviour, clearly not much better.
     
    Jerem_, _slash_ and Wright like this.
  21. TashaSkyUpchurch

    TashaSkyUpchurch

    Joined:
    Jan 25, 2018
    Posts:
    13
    I agree with unity_dA5TCa2krrACsQ, IQpierce was being rude. Though likely not purposefully, some people sometimes forget to no be rude, or don't care or can't manage it because of language barriers.

    Regardless. Serious question here. What is wrong with using unity_dA5TCa2krrACsQ code in a MonoBehaviour? Isn't it standard to do nearly everything inside them? I mean. even if your class is not derived from MonoBehaviour it's likely that the thread was dispatched from one.

    Does this work with 3D games?
     
    Xevin likes this.
  22. NoBrainer-David

    NoBrainer-David

    Joined:
    Jan 5, 2014
    Posts:
    34
    The code relies on Awake() being called to initialize the texture and the GUIStyle. This can be achieved by putting it inside of a MonoBehavior. This, however, requires the MonoBehavior to be active somewhere in the scene.

    It would be more elegant to just construct the GUIStyle and the Texture2D statically, as Cameron860 does in his code. Then, you don't have to worry about dragging the MonoBehavior into every scene where you want this functionality.

    Putting everything inside of MonoBehaviors is the way I started out using Unity. With time, you will certainly see more and more situations where this limits you or where it makes reasoning about what is happening harder. Richard Fine held an amazing talk at Unite 2016 that totally opened my eyes to ScriptableObjects. After you are convinced and want to know more specific examples on how to let this drive the architecture of your game, Ryan Hipples talk is fantastic.
    If you are overwhelmed and don't quite see how you can turn these condensed conference-code examples into functionality for your project, check out this open-source project for implementations aimed at production use.

    Disclaimer: I started and am responsible for that project and it is still very much a work in progress.
     
    TashaSkyUpchurch likes this.
  23. Don-Tako

    Don-Tako

    Joined:
    Jan 31, 2013
    Posts:
    7
    Simple:
    Code (CSharp):
    1. public GUIStyle guiStyle;
    2.     void OnGUI()
    3.     {
    4.             GUI.Label(new Rect(0, 0, Screen.width, Screen.height), "", guiStyle);
    5.     }
    Remember set a background image on Gui Style > Normal > Background
     
  24. unity_cXBEP6h1lIWdUA

    unity_cXBEP6h1lIWdUA

    Joined:
    Sep 25, 2018
    Posts:
    1
  25. Keysawn

    Keysawn

    Joined:
    Sep 1, 2018
    Posts:
    4
    I will NEVER get why something so simple could be so complicated... I mean, this is just changing the color of a box. This is beyond my understanding.
     
  26. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    1,317
    I know this is an ancient thread, but in the editor, which is basically the only place you'd care about IMGUI these days, you can simply use EditorGUI.DrawRect.

    If you are using runtime OnGUI for whatever reason, I'd suggest you create a global 1x1 white texture like others have mentioned, and then just manipulate
    GUI.color
    (basically just mimicking the way you'd do this with editor gui using the built-in EditorGUIUtility.whiteTexture):

    Code (CSharp):
    1.  
    2. // in OnGUI
    3. GUI.color = color;
    4. GUI.Box( rect, Global.whiteTexture );
    5. GUI.color = Color.white;
    6.  
    7.  
    8. // elsewhere
    9. static class Global {
    10.     public static readonly Texture whiteTexture;
    11.  
    12.     static Global () {
    13.         whiteTexture = new Texture( 1, 1 );
    14.         whiteTexture.SetPixel( 0, 0, Color.white );
    15.         whiteTexture.Apply();
    16.     }
    17. }
     
  27. CyRaid

    CyRaid

    Joined:
    Mar 31, 2015
    Posts:
    134
    Why wouldn't you use Texture2D.whiteTexture ?
     
    Deleted User, ZO5KmUG6R and Madgvox like this.
  28. workhard

    workhard

    Joined:
    Apr 11, 2020
    Posts:
    1
    Why the hell is there is no an option for DrawRectangle(w,h,x,y)
     
    dayugegehome likes this.
  29. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    863
    Too often I google how to do something dead simple and stumble upon an ancient thread all about difficult ways to do it. Maybe we should tag some unity stuff to maybe notice this?

    Or maybe I'm wrong and there is a way in editor GUI to draw a box outline with one method call?

    For those who are searching:

    Code (CSharp):
    1.             protected void DrawBox(Rect rect, Color color)
    2.             {
    3.                 EditorGUI.DrawRect(new Rect(rect.min.x, rect.min.y, 1f, rect.height), color);
    4.                 EditorGUI.DrawRect(new Rect(rect.max.x, rect.min.y, 1f, rect.height), color);
    5.                 EditorGUI.DrawRect(new Rect(rect.min.x, rect.max.y, rect.width, 1f), color);
    6.                 EditorGUI.DrawRect(new Rect(rect.min.x, rect.min.y, rect.width, 1f), color);
    7.             }
    It ain't pretty though, the corners are not pixel perfect, and can't be without some trickery because the pixel offsets seem to depend on the box size.
     
    Last edited: Oct 21, 2020
    Eristen and Spyler21 like this.
  30. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    1,317
    You can draw a box outline using the Handles.DrawSolidRectangleWithOutline method, as long as you're in a
    Handles.BeginGUI
    block. If you pass a clear color to the fill, it will only draw the outline.
     
  31. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    863
    I'm in a custom window.
     
  32. radiantboy

    radiantboy

    Joined:
    Nov 21, 2012
    Posts:
    1,633
    In OnGUI():

    Code (CSharp):
    1.  GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), Textures.Yellow, ScaleMode.StretchToFill, false);
     
    acakebread likes this.
  33. ruudvangaal

    ruudvangaal

    Joined:
    May 15, 2017
    Posts:
    27
    The Textures class doesn't seem to exist in my Unity 2019.4 version. Is that a custom one you built?
     
    acakebread likes this.
  34. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    1,317
    Handles works within custom windows, if I recall correctly -- GL will draw into the current context.
     
  35. radiantboy

    radiantboy

    Joined:
    Nov 21, 2012
    Posts:
    1,633
    Sorry my fault I didn't realise but that class is custom. But you could could easily make it or just pass a texture instead
     
    acakebread likes this.
  36. acakebread

    acakebread

    Joined:
    Jul 11, 2016
    Posts:
    12
    I refactored my debug box draw function to use this - far more reliable than Unity's 'GUI.Box' which has weird offsets and doesn't draw where you want it to. This solution is pixel perfect on the screen
     
  37. funkyCoty

    funkyCoty

    Joined:
    May 22, 2018
    Posts:
    719
    For custom Editor windows, I'm using this:

    Code (CSharp):
    1. private void DrawInspectorColoredBox(float height, Color color)
    2. {
    3.     var boxRect = EditorGUILayout.BeginVertical();
    4.     GUILayout.Space(height);
    5.     EditorGUI.DrawRect(boxRect, color);
    6.     EditorGUILayout.EndVertical();
    7. }
     
    Spyler21 likes this.