- Home /
How to render a colored 2D rectangle.
Hi-
I am new to Unity and trying to get a handle on some of the basic rendering functions, most of my experience is with C++ and OpenGL.
To start with I would like to render simple colored rectangles in 2d screen space, I've gotten as far as the following C# code (in OnGUI()):
Texture2D red_texture = new Texture2D(2, 2); Color red_color = new Color(1, 0, 0); red_texture.SetPixel(0, 0, red_color); red_texture.SetPixel(1, 0, red_color); red_texture.SetPixel(1, 1, red_color); red_texture.SetPixel(0, 1, red_color); red_texture.Apply(); red_texture.wrapMode = TextureWrapMode.Repeat; GUI.Box (new Rect (0,0,100,100), red_texture);
(I can create the texture elsewhere, I just included it here for clarity).
This renders a fullsized box with default GUI style, and the texture is shown at literal size as a 2x2 small red square where the text would normally appear.
I tried drawing the rectangle at the exact dimensions of the texture (2x2) and it shows up black, I assume that GUI.Box is not meant for general purpose rendering of colored rectangles.
I also tried the following code in OnDrawGizmos():
Texture2D green_texture = new Texture2D(2, 2); Color green_color = new Color(0, 1, 0); green_texture.SetPixel(0, 0, green_color); green_texture.SetPixel(1, 0, green_color); green_texture.SetPixel(1, 1, green_color); green_texture.SetPixel(0, 1, green_color); green_texture.Apply(); green_texture.wrapMode = TextureWrapMode.Repeat; Gizmos.DrawGUITexture(new Rect(100, 100, 200, 200), green_texture);
This doesn't show up at all (I believe I am missing something).
I couldn't find an example of this in the docs or the forums, I'm assuming this is such an easy operation that it doesn't need to be described in detail anywhere but I am stuck at this point, I would appreciate any push in the right direction.
Thanks in advance for any help -MM
UPDATE:
I managed to get a GUI-box with no border by using a default GUIStyle for the box rendering, but the downside is the texture image has to be the exact size of the desired rectangle, here is the code:
void Render_Colored_Rectangle(int x, int y, int w, int h, float r, float g, float b)
{
Texture2D rgb_texture = new Texture2D(w, h);
Color rgb_color = new Color(r, g, b);
int i, j;
for(i = 0;i<w;i++)
{
for(j = 0;j<h;j++)
{
rgb_texture.SetPixel(i, j, rgb_color);
}
}
rgb_texture.Apply();
GUIStyle generic_style = new GUIStyle();
GUI.skin.box = generic_style;
GUI.Box (new Rect (x,y,w,h), rgb_texture);
}
(The display seems to mangle the code in the originalpost but this looks ok)..
This works but is major overkill for a generic rectangle-drawing routine, can anyone clarify the correct way of drawing a basic colored rectangle?
I can use this for now but it's definitely a bad hack, I believe I'm missing something and I haven't found a clear solution in the docs, thanks again for anyone that can point me in the right direction..
Is there some reason you need to use a texture? I don't use Unity GUI; I just draw meshes based on coordinates of an easy-to-code for orthographic camera, and use a solid color shader on them.
I'm only using the texture because that's what GUI.Box needed for specifying a color, I'm open to whatever the correct solution is.
I considered using temporary 3d meshes with an orthographic projection but that seems like the long way to go around just to draw a colored 2d rectangle, I assumed there would be some basic 2d drawing routines included somewhere.
If you can verify that's the best solution for Unity and it's not really feasible any other way I can do it, I'm ok with work-arounds if that's how it has to be..
Unity isn't geared for 2D. Unity GUI isn't geared for drawing anything that isn't textured. I don't see a good match for what you need. Personally, I do my 2D work with scripted quads, orthographic cameras, and simple custom shaders. It's more complicated than I'd like, but it's not really any messier than what you have above, and it's way better on performance, especially if you can combine your rectangles into one mesh, or at least share a material, for batching. Unity GUI items all require a draw call.
Thanks Jessy, this is the verification I was looking for, I expected that Unity might be really "built" for 3d and not much else, now I know the correct direction I need to go in..
Here's a critical piece of information -- to make a solid color shader, go to Jessy's awesome answer here... http://answers.unity3d.com/questions/47385/looking-for-a-flat-shaderno-info-with-just-a-color.html
Answer by Veehmot · May 20, 2013 at 07:12 AM
There's no need to create the whole texture (as of Unity 4). This works as expected:
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);
}
Don't use this code as is. if the above function is called from onGUI, it creates a memory leak because a new texture is being created every frame. Secondly, SetPixel is very very slow and should be avoided on mobile.
I know this question is about GUI. So far I've found the best performance for transparent shades is to use super lightweight shaders on meshes for large transparent elements.
what about memory leak with this code? Is this safe to use?
It is NOT safe, I have experienced running out of memory on a Windows platform with exactly this code, because the Texture2D doesn't get deallocated automatically (although it really should). If you need this code, the fix is to only call 'new Texture2D(1,1)' once and store it in a static variable in your class. On OS X platforms I didn't experience the problem.
Answer by Statement · Dec 19, 2012 at 12:48 AM
Here's one way to do it with GL.Begin/GL.End. You should also be able to draw a mesh similarly with Graphics.DrawMeshNow. Please select a material that accepts color. I just tested this quickly with GUI/Text Shader but you will probably want to use a solid color shader that uses the vertex color channel.
using UnityEngine;
using System.Collections;
public class Example : MonoBehaviour
{
// Please assign a material that is using position and color.
public Material material;
public Rect position = new Rect (16, 16, 128, 24);
public Color color = Color.red;
void OnGUI ()
{
DrawRectangle (position, color);
}
void DrawRectangle (Rect position, Color color)
{
// We shouldn't draw until we are told to do so.
if (Event.current.type != EventType.Repaint)
return;
// Please assign a material that is using position and color.
if (material == null) {
Debug.LogError ("You have forgot to set a material.");
return;
}
material.SetPass (0);
// Optimization hint:
// Consider Graphics.DrawMeshNow
GL.Color (color);
GL.Begin (GL.QUADS);
GL.Vertex3 (position.x, position.y, 0);
GL.Vertex3 (position.x + position.width, position.y, 0);
GL.Vertex3 (position.x + position.width, position.y + position.height, 0);
GL.Vertex3 (position.x, position.y + position.height, 0);
GL.End ();
}
}
Answer by IJM · Dec 12, 2010 at 01:28 AM
Create a new folder in your Assets and name it "Resources", put a white texture of any size (32x32 for example) inside and name it WhiteTexture (It can be BMP, TGA, PNG, JPEG...) and do something like this in OnGUI function:
Texture2D MyTexture = Resources.Load("WhiteTexture") as Texture2D;
GUI.color = new Color(1.0f , 0, 0);//Set color to red
GUI.DrawTexture(new Rect(positionX, positionY, sizeX, sizeY), MyTexture);
GUI.color = Color.white;//Reset color to white
This will render a red rectangle.
p.s. I didn't test this code. =)
Answer by vikingfabian-com · Aug 28, 2014 at 11:39 AM
Drawing a rectangle outline
public static void DrawRectangle(Rect area, int frameWidth, Color color)
{
//Create a one pixel texture with the right color
var texture = new Texture2D(1, 1);
texture.SetPixel(0, 0, color);
texture.Apply();
Rect lineArea = area;
lineArea.height = frameWidth; //Top line
GUI.DrawTexture(lineArea, texture);
lineArea.y = area.yMax - frameWidth; //Bottom
GUI.DrawTexture(lineArea, texture);
lineArea = area;
lineArea.width = frameWidth; //Left
GUI.DrawTexture(lineArea, texture);
lineArea.x = area.xMax - frameWidth;//Right
GUI.DrawTexture(lineArea, texture);
}
Answer by hlynbech · Mar 26, 2013 at 02:52 PM
I found a way to draw a box inside OnGUI that only uses a very small texture, and it works on my machine (mac laptop).
I use this to render a 50% transparent white box on the entire screen, including the GUI elements. Just substitute the color values for whatever color you need. You could even make gradients by setting different colors in this 2 by 2 pixel texture.
void OnGui () {
Texture2D tex = new Texture2D(2,2);
for(int i = 0; i < tex.width; i++)
{
for(int j = 0; j < tex.height; j++)
{
tex.SetPixel(i, j, new Color(1f, 1f, 1f, 0.5f));
}
}
tex.Apply();
GUIStyle tempstyle = new GUIStyle();
tempstyle.normal.background = tex;
GUILayout.BeginArea(new Rect(0,0,Screen.width,Screen.height),tempstyle);
GUILayout.EndArea();
}