Skip to content

Instantly share code, notes, and snippets.

@SolarianZ
Last active January 23, 2024 11:58
Show Gist options
  • Save SolarianZ/0157548377b1ee927094e82cfa9624ee to your computer and use it in GitHub Desktop.
Save SolarianZ/0157548377b1ee927094e82cfa9624ee to your computer and use it in GitHub Desktop.
{"category": "Unity Engine/Runtime/Utility", "keywords": "Unity, Runtime, Debug, DrawWireShape"} Drawing shapes with Debug.DrawLine method in the Unity Editor.
using System.Diagnostics;
using UnityEngine;
using UDebug = UnityEngine.Debug;
public static class DebugDrawer
{
public static byte CircleResolution
{
get => _circleResolution;
set
{
const byte MIN_RESOLUTION = 12;
if (value < MIN_RESOLUTION)
{
value = MIN_RESOLUTION;
UDebug.LogError($"{nameof(CircleResolution)} must be greater than {MIN_RESOLUTION}.");
}
_circleResolution = value;
}
}
public static float DotLineSegmentLength
{
get => _dotLineSegmentLength;
set
{
if (value < DotLineGapLength)
{
value = DotLineGapLength;
UDebug.LogError($"{nameof(DotLineSegmentLength)} must be greater than {nameof(DotLineGapLength)}.");
}
_dotLineSegmentLength = value;
}
}
public static float DotLineGapLength
{
get => _dotLineGapLength;
set
{
const float MIN_DOT_LINE_SEG_LEN = 0.01f;
if (value < 0.01f || value > DotLineSegmentLength)
{
value = Mathf.Clamp(value, MIN_DOT_LINE_SEG_LEN, DotLineSegmentLength);
UDebug.LogError($"{nameof(DotLineGapLength)} must be greater than {MIN_DOT_LINE_SEG_LEN} and less than {nameof(DotLineSegmentLength)}.");
}
_dotLineGapLength = value;
}
}
private static byte _circleResolution = 32;
private static float _dotLineSegmentLength = 0.05f;
private static float _dotLineGapLength = 0.03f;
[Conditional("UNITY_EDITOR")]
public static void DrawLine(Vector3 start, Vector3 end, Color? color = null,
float duration = 0.0f, bool depthTest = true, bool dotLine = false)
{
var c = color ?? Color.white;
if (!dotLine)
{
UDebug.DrawLine(start, end, c, duration, depthTest);
return;
}
var lineLen = (end - start).magnitude;
if (lineLen <= DotLineSegmentLength)
{
UDebug.DrawLine(start, end, c, duration, depthTest);
return;
}
var segAndGapLen = DotLineSegmentLength + DotLineGapLength;
var wholeSegAndGapCount = (int)(lineLen / segAndGapLen);
var lastSegLen = lineLen - segAndGapLen * wholeSegAndGapCount;
if (lastSegLen < DotLineGapLength)
lastSegLen -= DotLineGapLength;
else if (lastSegLen > DotLineSegmentLength)
lastSegLen -= segAndGapLen;
var firstSegLen = (DotLineSegmentLength + lastSegLen) / 2;
var dir = (end - start) / lineLen;
end = start + dir * firstSegLen;
UDebug.DrawLine(start, end, c, duration, depthTest);
start = end;
var currentLen = firstSegLen;
var isGap = true;
while (true)
{
if (isGap)
{
var gapLen = Mathf.Min(DotLineGapLength, lineLen - currentLen);
currentLen += gapLen;
start += dir * gapLen;
}
else
{
var segLen = Mathf.Min(DotLineSegmentLength, lineLen - currentLen);
currentLen += segLen;
end = start + dir * segLen;
UDebug.DrawLine(start, end, c, duration, depthTest);
start = end;
}
isGap = !isGap;
if (currentLen >= lineLen)
break;
}
}
[Conditional("UNITY_EDITOR")]
public static void DrawWireBox(Vector3 center, Vector3 size, Quaternion rotation,
Color? color = null, float duration = 0.0f, bool depthTest = true, bool dotLine = false)
{
var c = color ?? Color.white;
var forward = rotation * Vector3.forward;
var up = rotation * Vector3.up;
var right = rotation * Vector3.right;
var extents = size * 0.5f;
var p0 = center + forward * extents.z + up * extents.y - right * extents.x;
var p1 = center + forward * extents.z + up * extents.y + right * extents.x;
var p2 = center - forward * extents.z + up * extents.y + right * extents.x;
var p3 = center - forward * extents.z + up * extents.y - right * extents.x;
var p4 = center + forward * extents.z - up * extents.y - right * extents.x;
var p5 = center + forward * extents.z - up * extents.y + right * extents.x;
var p6 = center - forward * extents.z - up * extents.y + right * extents.x;
var p7 = center - forward * extents.z - up * extents.y - right * extents.x;
DrawLine(p0, p1, c, duration, depthTest, dotLine);
DrawLine(p1, p2, c, duration, depthTest, dotLine);
DrawLine(p2, p3, c, duration, depthTest, dotLine);
DrawLine(p3, p0, c, duration, depthTest, dotLine);
DrawLine(p4, p5, c, duration, depthTest, dotLine);
DrawLine(p5, p6, c, duration, depthTest, dotLine);
DrawLine(p6, p7, c, duration, depthTest, dotLine);
DrawLine(p7, p4, c, duration, depthTest, dotLine);
DrawLine(p0, p4, c, duration, depthTest, dotLine);
DrawLine(p1, p5, c, duration, depthTest, dotLine);
DrawLine(p2, p6, c, duration, depthTest, dotLine);
DrawLine(p3, p7, c, duration, depthTest, dotLine);
}
[Conditional("UNITY_EDITOR")]
public static void DrawWireArc(Vector3 origin, Vector3 fromDir, Vector3 toDir,
Vector3 normal, float radius, bool closed = false, Color? color = null,
float duration = 0.0f, bool depthTest = true, bool dotLine = false)
{
fromDir.Normalize();
var c = color ?? Color.white;
var arcAngle = Vector3.SignedAngle(fromDir, toDir, normal);
if (arcAngle < 0)
{
arcAngle = 360 + arcAngle;
}
var arcResolution = (byte)Mathf.Ceil(CircleResolution / (360f / arcAngle));
var segAngle = arcAngle / arcResolution;
var segStart = origin + fromDir * radius;
for (int i = 1; i <= arcResolution; i++)
{
var segEnd = origin + Quaternion.AngleAxis(segAngle * i, normal) * fromDir * radius;
DrawLine(segStart, segEnd, c, duration, depthTest, dotLine);
segStart = segEnd;
}
if (closed)
{
DrawLine(origin, origin + fromDir * radius, c, duration, depthTest, dotLine);
DrawLine(origin, segStart, c, duration, depthTest, dotLine);
}
}
[Conditional("UNITY_EDITOR")]
public static void DrawWireCircle(Vector3 origin, Vector3 normal, float radius,
Color? color = null, float duration = 0.0f, bool depthTest = true, bool dotLine = false)
{
var c = color ?? Color.white;
var tempAxis = Vector3.Cross(normal, Vector3.up).sqrMagnitude < Mathf.Epsilon
? Vector3.forward
: Vector3.up;
var right = Vector3.Cross(tempAxis, normal);
var forward = Vector3.Cross(right, normal).normalized;
var segAngle = 360f / CircleResolution;
var startPoint = origin + forward * radius;
var lastPoint = startPoint;
for (int i = 1; i < CircleResolution; i++)
{
var newPoint = origin + Quaternion.AngleAxis(segAngle * i, normal) * forward * radius;
DrawLine(lastPoint, newPoint, c, duration, depthTest, dotLine);
lastPoint = newPoint;
}
DrawLine(lastPoint, startPoint, c, duration, depthTest, dotLine);
}
[Conditional("UNITY_EDITOR")]
public static void DrawWireSphere(Vector3 origin, float radius, Quaternion? rotation = null,
Color? color = null, float duration = 0.0f, bool depthTest = true, bool dotLine = false)
{
var q = rotation ?? Quaternion.identity;
DrawWireCircle(origin, q * Vector3.up, radius, color, duration, depthTest, dotLine);
DrawWireCircle(origin, q * Vector3.right, radius, color, duration, depthTest, dotLine);
DrawWireCircle(origin, q * Vector3.forward, radius, color, duration, depthTest, dotLine);
}
[Conditional("UNITY_EDITOR")]
public static void DrawWireCylinder(Vector3 point0, Vector3 point1, float radius,
Color? color = null, float duration = 0.0f, bool depthTest = true, bool dotLine = false)
{
var c = color ?? Color.white;
var dir = point1 - point0;
var q = Quaternion.FromToRotation(Vector3.forward, dir);
var p0 = point0 + q * Vector3.up * radius;
var p1 = point0 + q * Vector3.down * radius;
var p2 = point0 + q * Vector3.left * radius;
var p3 = point0 + q * Vector3.right * radius;
var p4 = point1 + q * Vector3.up * radius;
var p5 = point1 + q * Vector3.down * radius;
var p6 = point1 + q * Vector3.left * radius;
var p7 = point1 + q * Vector3.right * radius;
DrawLine(p0, p4, c, duration, depthTest, dotLine);
DrawLine(p1, p5, c, duration, depthTest, dotLine);
DrawLine(p2, p6, c, duration, depthTest, dotLine);
DrawLine(p3, p7, c, duration, depthTest, dotLine);
DrawWireCircle(point0, point0 - point1, radius, c, duration, depthTest, dotLine);
DrawWireCircle(point1, point1 - point0, radius, c, duration, depthTest, dotLine);
}
[Conditional("UNITY_EDITOR")]
public static void DrawWireCapsule(Vector3 point0, Vector3 point1, float radius,
Color? color = null, float duration = 0.0f, bool depthTest = true, bool dotLine = false)
{
var c = color ?? Color.white;
var dir = point1 - point0;
var q = Quaternion.FromToRotation(Vector3.forward, dir);
var p0 = point0 + q * Vector3.up * radius;
var p1 = point0 + q * Vector3.down * radius;
var p2 = point0 + q * Vector3.left * radius;
var p3 = point0 + q * Vector3.right * radius;
var p4 = point1 + q * Vector3.up * radius;
var p5 = point1 + q * Vector3.down * radius;
var p6 = point1 + q * Vector3.left * radius;
var p7 = point1 + q * Vector3.right * radius;
DrawLine(p0, p4, c, duration, depthTest, dotLine);
DrawLine(p1, p5, c, duration, depthTest, dotLine);
DrawLine(p2, p6, c, duration, depthTest, dotLine);
DrawLine(p3, p7, c, duration, depthTest, dotLine);
DrawWireCircle(point0, point0 - point1, radius, c, duration, depthTest, dotLine);
DrawWireCircle(point1, point1 - point0, radius, c, duration, depthTest, dotLine);
DrawWireArc(point0, p0 - point0, p1 - point0, p2 - p3, radius, false, c, duration, depthTest, dotLine);
DrawWireArc(point0, p2 - point0, p3 - point0, p1 - p0, radius, false, c, duration, depthTest, dotLine);
DrawWireArc(point1, p4 - point1, p5 - point1, p7 - p6, radius, false, c, duration, depthTest, dotLine);
DrawWireArc(point1, p6 - point1, p7 - point1, p4 - p5, radius, false, c, duration, depthTest, dotLine);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment