- Home /
Display a Line in GUI without texture - GUI Line ?
Instead of using a texture2d, how do you display a line running across the GUI?
Could you be more specific?
You want to draw a horizontal line within a label?
You want to draw a line across the screen?
You want to draw a line to separate your GUI controls?
You want to draw lines with GUI real-time?
Just a line across the screen or even within a label. Just in GUI space and not in 3D
Well, it's just a line that is part of the GUI for display/decorative purposes... OnGUI is updated every frame, not sure if that is realtime.
Speaking of which, there is no way to underline or strikethrough gui text in Unity
Answer by Cherno · May 23, 2014 at 02:37 PM
There's an updarted version of the DrawLine script, it works without problem (watch out, long script incoming)
You just call it with Drawing.DrawLine(Vector2 pointA, Vector2 pointB, Color color, float width, bool antiAlias)
EDIT: THIS IS AN OLDER VERSION WHICH HAS AA, BUT ALSO GHOSTING ISSUES. UNDER IT, I ADDED A NEW VERSION THAT ALSO HAS CIRCLE DRAWING I WROTE MYSELF, USE THAT ONE.
using System.Reflection;
using UnityEngine;
// Line drawing routine originally courtesy of Linusmartensson:
// http://forum.unity3d.com/threads/71979-Drawing-lines-in-the-editor
//
// Rewritten to improve performance by Yossarian King / August 2013.
//
// This version produces virtually identical results to the original (tested by drawing
// one over the other and observing errors of one pixel or less), but for large numbers
// of lines this version is more than four times faster than the original, and comes
// within about 70% of the raw performance of Graphics.DrawTexture.
//
// Peak performance on my laptop is around 200,000 lines per second. The laptop is
// Windows 7 64-bit, Intel Core2 Duo CPU 2.53GHz, 4G RAM, NVIDIA GeForce GT 220M.
// Line width and anti-aliasing had negligible impact on performance.
//
// For a graph of benchmark results in a standalone Windows build, see this image:
// https://app.box.com/s/hyuhi565dtolqdm97e00
//
// For a Google spreadsheet with full benchmark results, see:
// https://docs.google.com/spreadsheet/ccc?key=0AvJlJlbRO26VdHhzeHNRMVF2UHZHMXFCTVFZN011V1E&usp=sharing
public static class Drawing
{
private static Texture2D aaLineTex = null;
private static Texture2D lineTex = null;
private static Material blitMaterial = null;
private static Material blendMaterial = null;
private static Rect lineRect = new Rect(0, 0, 1, 1);
// Draw a line in screen space, suitable for use from OnGUI calls from either
// MonoBehaviour or EditorWindow. Note that this should only be called during repaint
// events, when (Event.current.type == EventType.Repaint).
//
// Works by computing a matrix that transforms a unit square -- Rect(0,0,1,1) -- into
// a scaled, rotated, and offset rectangle that corresponds to the line and its width.
// A DrawTexture call used to draw a line texture into the transformed rectangle.
//
// More specifically:
// scale x by line length, y by line width
// rotate around z by the angle of the line
// offset by the position of the upper left corner of the target rectangle
//
// By working out the matrices and applying some trigonometry, the matrix calculation comes
// out pretty simple. See https://app.box.com/s/xi08ow8o8ujymazg100j for a picture of my
// notebook with the calculations.
public static void DrawLine(Vector2 pointA, Vector2 pointB, Color color, float width, bool antiAlias)
{
// Normally the static initializer does this, but to handle texture reinitialization
// after editor play mode stops we need this check in the Editor.
#if UNITY_EDITOR
if (!lineTex)
{
Initialize();
}
#endif
// Note that theta = atan2(dy, dx) is the angle we want to rotate by, but instead
// of calculating the angle we just use the sine (dy/len) and cosine (dx/len).
float dx = pointB.x - pointA.x;
float dy = pointB.y - pointA.y;
float len = Mathf.Sqrt(dx * dx + dy * dy);
// Early out on tiny lines to avoid divide by zero.
// Plus what's the point of drawing a line 1/1000th of a pixel long??
if (len < 0.001f)
{
return;
}
// Pick texture and material (and tweak width) based on anti-alias setting.
Texture2D tex;
Material mat;
if (antiAlias)
{
// Multiplying by three is fine for anti-aliasing width-1 lines, but make a wide "fringe"
// for thicker lines, which may or may not be desirable.
width = width * 3.0f;
tex = aaLineTex;
mat = blendMaterial;
}
else
{
tex = lineTex;
mat = blitMaterial;
}
float wdx = width * dy / len;
float wdy = width * dx / len;
Matrix4x4 matrix = Matrix4x4.identity;
matrix.m00 = dx;
matrix.m01 = -wdx;
matrix.m03 = pointA.x + 0.5f * wdx;
matrix.m10 = dy;
matrix.m11 = wdy;
matrix.m13 = pointA.y - 0.5f * wdy;
// Use GL matrix and Graphics.DrawTexture rather than GUI.matrix and GUI.DrawTexture,
// for better performance. (Setting GUI.matrix is slow, and GUI.DrawTexture is just a
// wrapper on Graphics.DrawTexture.)
GL.PushMatrix();
GL.MultMatrix(matrix);
Graphics.DrawTexture(lineRect, tex, lineRect, 0, 0, 0, 0, color, mat);
GL.PopMatrix();
}
// Other than method name, DrawBezierLine is unchanged from Linusmartensson's original implementation.
public static void DrawBezierLine(Vector2 start, Vector2 startTangent, Vector2 end, Vector2 endTangent, Color color, float width, bool antiAlias, int segments)
{
Vector2 lastV = CubeBezier(start, startTangent, end, endTangent, 0);
for (int i = 1; i < segments; ++i)
{
Vector2 v = CubeBezier(start, startTangent, end, endTangent, i/(float)segments);
Drawing.DrawLine(lastV, v, color, width, antiAlias);
lastV = v;
}
}
private static Vector2 CubeBezier(Vector2 s, Vector2 st, Vector2 e, Vector2 et, float t)
{
float rt = 1 - t;
return rt * rt * rt * s + 3 * rt * rt * t * st + 3 * rt * t * t * et + t * t * t * e;
}
// This static initializer works for runtime, but apparently isn't called when
// Editor play mode stops, so DrawLine will re-initialize if needed.
static Drawing()
{
Initialize();
}
private static void Initialize()
{
if (lineTex == null)
{
lineTex = new Texture2D(1, 1, TextureFormat.ARGB32, false);
lineTex.SetPixel(0, 1, Color.white);
lineTex.Apply();
}
if (aaLineTex == null)
{
// TODO: better anti-aliasing of wide lines with a larger texture? or use Graphics.DrawTexture with border settings
aaLineTex = new Texture2D(1, 3, TextureFormat.ARGB32, false);
aaLineTex.SetPixel(0, 0, new Color(1, 1, 1, 0));
aaLineTex.SetPixel(0, 1, Color.white);
aaLineTex.SetPixel(0, 2, new Color(1, 1, 1, 0));
aaLineTex.Apply();
}
// GUI.blitMaterial and GUI.blendMaterial are used internally by GUI.DrawTexture,
// depending on the alphaBlend parameter. Use reflection to "borrow" these references.
blitMaterial = (Material)typeof(GUI).GetMethod("get_blitMaterial", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, null);
blendMaterial = (Material)typeof(GUI).GetMethod("get_blendMaterial", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, null);
}
}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Edit: This is the updated version of the script. It has no AA, but it also gets rid of the ghosting issues, and it has added circle drawing functionality added by me: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
using System.Reflection;
using UnityEngine;
// Line drawing routine originally courtesy of Linusmartensson:
// http://forum.unity3d.com/threads/71979-Drawing-lines-in-the-editor
//
// Rewritten to improve performance by Yossarian King / August 2013.
//
// This version produces virtually identical results to the original (tested by drawing
// one over the other and observing errors of one pixel or less), but for large numbers
// of lines this version is more than four times faster than the original, and comes
// within about 70% of the raw performance of Graphics.DrawTexture.
//
// Peak performance on my laptop is around 200,000 lines per second. The laptop is
// Windows 7 64-bit, Intel Core2 Duo CPU 2.53GHz, 4G RAM, NVIDIA GeForce GT 220M.
// Line width and anti-aliasing had negligible impact on performance.
//
// For a graph of benchmark results in a standalone Windows build, see this image:
// https://app.box.com/s/hyuhi565dtolqdm97e00
//
// For a Google spreadsheet with full benchmark results, see:
// https://docs.google.com/spreadsheet/ccc?key=0AvJlJlbRO26VdHhzeHNRMVF2UHZHMXFCTVFZN011V1E&usp=sharing
public static class Drawing
{
private static Texture2D aaLineTex = null;
private static Texture2D lineTex = null;
private static Material blitMaterial = null;
private static Material blendMaterial = null;
private static Rect lineRect = new Rect(0, 0, 1, 1);
// Draw a line in screen space, suitable for use from OnGUI calls from either
// MonoBehaviour or EditorWindow. Note that this should only be called during repaint
// events, when (Event.current.type == EventType.Repaint).
//
// Works by computing a matrix that transforms a unit square -- Rect(0,0,1,1) -- into
// a scaled, rotated, and offset rectangle that corresponds to the line and its width.
// A DrawTexture call used to draw a line texture into the transformed rectangle.
//
// More specifically:
// scale x by line length, y by line width
// rotate around z by the angle of the line
// offset by the position of the upper left corner of the target rectangle
//
// By working out the matrices and applying some trigonometry, the matrix calculation comes
// out pretty simple. See https://app.box.com/s/xi08ow8o8ujymazg100j for a picture of my
// notebook with the calculations.
public static void DrawLine(Vector2 pointA, Vector2 pointB, Color color, float width, bool antiAlias)
{
// Normally the static initializer does this, but to handle texture reinitialization
// after editor play mode stops we need this check in the Editor.
#if UNITY_EDITOR
if (!lineTex)
{
Initialize();
}
#endif
// Note that theta = atan2(dy, dx) is the angle we want to rotate by, but instead
// of calculating the angle we just use the sine (dy/len) and cosine (dx/len).
float dx = pointB.x - pointA.x;
float dy = pointB.y - pointA.y;
float len = Mathf.Sqrt(dx * dx + dy * dy);
// Early out on tiny lines to avoid divide by zero.
// Plus what's the point of drawing a line 1/1000th of a pixel long??
if (len < 0.001f)
{
return;
}
// Pick texture and material (and tweak width) based on anti-alias setting.
Texture2D tex;
Material mat;
if (antiAlias)
{
// Multiplying by three is fine for anti-aliasing width-1 lines, but make a wide "fringe"
// for thicker lines, which may or may not be desirable.
width = width * 3.0f;
tex = aaLineTex;
mat = blendMaterial;
}
else
{
tex = lineTex;
mat = blitMaterial;
}
float wdx = width * dy / len;
float wdy = width * dx / len;
Matrix4x4 matrix = Matrix4x4.identity;
matrix.m00 = dx;
matrix.m01 = -wdx;
matrix.m03 = pointA.x + 0.5f * wdx;
matrix.m10 = dy;
matrix.m11 = wdy;
matrix.m13 = pointA.y - 0.5f * wdy;
// Use GL matrix and Graphics.DrawTexture rather than GUI.matrix and GUI.DrawTexture,
// for better performance. (Setting GUI.matrix is slow, and GUI.DrawTexture is just a
// wrapper on Graphics.DrawTexture.)
GL.PushMatrix();
GL.MultMatrix(matrix);
//Graphics.DrawTexture(lineRect, tex, lineRect, 0, 0, 0, 0, color, mat);
//Replaced by:
GUI.color = color;//this and...
GUI.DrawTexture( lineRect, tex );//this
GL.PopMatrix();
}
public static void DrawCircle(Vector2 center, int radius, Color color, float width, int segmentsPerQuarter) {
DrawCircle(center, radius, color, width, false, segmentsPerQuarter);
}
public static void DrawCircle(Vector2 center, int radius, Color color, float width, bool antiAlias, int segmentsPerQuarter) {
float rh = (float)radius / 2;
Vector2 p1 = new Vector2(center.x, center.y - radius);
Vector2 p1_tan_a = new Vector2(center.x - rh, center.y - radius);
Vector2 p1_tan_b = new Vector2(center.x + rh, center.y - radius);
Vector2 p2 = new Vector2(center.x + radius, center.y);
Vector2 p2_tan_a = new Vector2(center.x + radius, center.y - rh);
Vector2 p2_tan_b = new Vector2(center.x + radius, center.y + rh);
Vector2 p3 = new Vector2(center.x, center.y + radius);
Vector2 p3_tan_a = new Vector2(center.x - rh, center.y + radius);
Vector2 p3_tan_b = new Vector2(center.x + rh, center.y + radius);
Vector2 p4 = new Vector2(center.x - radius, center.y);
Vector2 p4_tan_a = new Vector2(center.x - radius, center.y - rh);
Vector2 p4_tan_b = new Vector2(center.x - radius, center.y + rh);
DrawBezierLine(p1, p1_tan_b, p2, p2_tan_a, color, width, antiAlias, segmentsPerQuarter);
DrawBezierLine(p2, p2_tan_b, p3, p3_tan_b, color, width, antiAlias, segmentsPerQuarter);
DrawBezierLine(p3, p3_tan_a, p4, p4_tan_b, color, width, antiAlias, segmentsPerQuarter);
DrawBezierLine(p4, p4_tan_a, p1, p1_tan_a, color, width, antiAlias, segmentsPerQuarter);
}
// Other than method name, DrawBezierLine is unchanged from Linusmartensson's original implementation.
public static void DrawBezierLine(Vector2 start, Vector2 startTangent, Vector2 end, Vector2 endTangent, Color color, float width, bool antiAlias, int segments)
{
Vector2 lastV = CubeBezier(start, startTangent, end, endTangent, 0);
for (int i = 1; i < segments + 1; ++i)
{
Vector2 v = CubeBezier(start, startTangent, end, endTangent, i/(float)segments);
Drawing.DrawLine(lastV, v, color, width, antiAlias);
lastV = v;
}
}
private static Vector2 CubeBezier(Vector2 s, Vector2 st, Vector2 e, Vector2 et, float t)
{
float rt = 1 - t;
return rt * rt * rt * s + 3 * rt * rt * t * st + 3 * rt * t * t * et + t * t * t * e;
}
// This static initializer works for runtime, but apparently isn't called when
// Editor play mode stops, so DrawLine will re-initialize if needed.
static Drawing()
{
Initialize();
}
private static void Initialize()
{
if (lineTex == null)
{
lineTex = new Texture2D(1, 1, TextureFormat.ARGB32, false);
lineTex.SetPixel(0, 1, Color.white);
lineTex.Apply();
}
if (aaLineTex == null)
{
// TODO: better anti-aliasing of wide lines with a larger texture? or use Graphics.DrawTexture with border settings
aaLineTex = new Texture2D(1, 3, TextureFormat.ARGB32, false);
aaLineTex.SetPixel(0, 0, new Color(1, 1, 1, 0));
aaLineTex.SetPixel(0, 1, Color.white);
aaLineTex.SetPixel(0, 2, new Color(1, 1, 1, 0));
aaLineTex.Apply();
}
// GUI.blitMaterial and GUI.blendMaterial are used internally by GUI.DrawTexture,
// depending on the alphaBlend parameter. Use reflection to "borrow" these references.
blitMaterial = (Material)typeof(GUI).GetMethod("get_blitMaterial", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, null);
blendMaterial = (Material)typeof(GUI).GetMethod("get_blendMaterial", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, null);
}
}
I edited my answer and added a new verersion of the script to the end of it.
Answer by radsimu · Sep 03, 2015 at 02:32 PM
Why not use a texture??? you have the Texture2D.White which is static so no resources are being used. You can control the tint to change its color. Is there something that restricts you from using a texture for your task?
GUI.color = Color.green;
GUI.DrawTexture(rect, Texture2D.whiteTexture, ScaleMode.StretchToFill);
And you can rotate it using GUIUtility. You should be able to create your own function which draws a line with controllable width, between two points.
Answer by ina · Jan 31, 2014 at 03:54 PM
This works:
Didn't work for me. Even when I told it to go from 0,0 to Screen.Width, it only filled half the screen across. Didn't make any sense.
Point A to Point B, seemed to always start in the middle, not the actual points. So weird.
As of Unity 5 this solution is error prone to bugs when resizing a window (I have no clue why). Use the built-in line drawing from Handles
ins$$anonymous$$d. See answer here http://answers.unity3d.com/answers/1145527/view.html.
That link appears to be dead, and I'm having trouble finding good references on how to use Handles inside of OnGUI. Can you find a working link, by any chance?
Answer by DaveA · Nov 16, 2011 at 07:07 AM
All I want is a decorative line that runs across my GUI... GL.Line seems just a tad overkill?!
Welcome to unityGUI.... the GUI system in unity is being re-vamped in 3.5. Personally, I've put off making my GUI's till 3.5.
Answer by CHPedersen · Nov 16, 2011 at 11:46 AM
GL calls are a perfectly decent way to accomplish that. Here's an alternative, though, if you want to avoid messing with OpenGL.
You want something that looks like the lines in this window, right?
Make an image that's a single pixel of a constant color. Then make a guistyle and set the background of its normal to your 1-pixel-constant-color texture. Then draw a GUI.Box or GUILayout.Box that's about 2 pixels wide, and render it with that GUIstyle. It will display as a line, similar to the example above.
Hmm then I have to switch between several different GUIStyles throughout...
This was my immediate thought, but the question says no textures.
I think this is the way to go if small textures are allowed.
Oh, sorry, I misread the no-textures limitation. I thought that meant "Don't use a thin 2x1024 texture of a static size and draw it in a label", or somesuch, I wasn't aware it meant no 1px-textures for style backgrounds, too. >_<
Hi
Can you share the code please. I want exactly like this image in my project.
Please share code.
@Programmer - He explains exactly how to do it. What is unclear?
Your answer
Follow this Question
Related Questions
Mathf.Lerp 2 Answers
Making texture cover whole button 1 Answer
My OnGUI() Won't show the Button elements :( 0 Answers
Draw an Arrow on the Screen 1 Answer