Get Shapes 💖
 
Documentation
 
Changelog
 
Feedback
Bugs & Feature Requests

Index

  • Shapes
  • Immediate-Mode Drawing
  • Anti-Aliasing
  • Blend Modes
  • Draw Order & Depth Testing
  • Meters, Pixels & Noots
  • Degrees, Turns & Radians
  • Performance
  • UI
  • Shapes Feature Table
  • Shapes

    To add shapes to your scene, go to the top menu bar Shapes/Create/...
    Line
    Lines are defined by a Start point and an End point, along with a configurable Thickness. As with many other shapes, you can set Thickness Space to various units, so you can specify Thickness in either meters, pixels or noots.

    Geometry

    Flat 2D lines are flat on the local space XY plane, ignoring Z. This is useful for making lines that are locked to a plane, such as in 2D games, or for a 2D surface in a 3D world such as a screen or minimap
    Billboard lines are positioned in 3D space, still using a quad mesh, always trying to face the camera. Useful for a cheap way of drawing 3D lines without using much geometry
    Volumetric 3D lines are using actual polygons to render a 3D line with the given Thickness

    End Caps

    No Caps - cuts off immediately at each endpoint
    Square Caps - extends by half the Thickness at each endpoint
    Round Caps - extends by half the Thickness at each endpoint, rounding the corners

    Dashed Lines

    Dash Size and Dash Spacing are either in meters, relative to thickness, or a fixed count across the shape, depending on what Dash Space is set to. Dash Offset is always relative to a single period, which means integer values always look the same. Here are some example dashes, when set to Relative dash spacing
    size 1, spacing 1
    size 2, spacing 1
    size 2, spacing 0.5
    size 3, spacing 3
    size 3, spacing 3, offset 0.5

    Blend ModeWhat blend mode to use when drawing this shape
    ColorColor of the line, or, the color of the starting point, when two colors are used
    Color EndColor of the endpoint when two colors are used
    ThicknessHow thick this shape should be, in the given Thickness Space
    Thickness SpaceWhat space Thickness is defined in
    StartLocal space starting point
    EndLocal space endpoint
    GeometryFlat 2D, Billboard, or Volumetric 3D
    Color ModeSingle color, or a gradient from start to end
    End CapsNo caps, Square caps or Round caps
    DashedDashed or solid
    Dash SpaceThe space in which Size and Spacing is defined.
    • Meters
    • Relative (to Thickness), which means a dash size of 1 is always a square dash
    • Fixed Count, where Size is the number of repeating periods across the shape, and Spacing is the fraction (0 to 1) of which should be space
    Dash SnapSnap Dashes to the full length of the shape.
    • Off
    • Tiling (ensures a repeating pattern, ends with space)
    • End To End (ensures a dash is snapped at each end)
    Dash SizeLength of a single dash. When Dash Space is set to fixed count, this is the repeat count
    Dash SpacingSize of the space between dashes. When Dash Space is set to fixed count, this is a value from 0 to 1, where 0.5 means dashes and spaces have the same size
    Dash OffsetOffset of dashes, relative to the repeating period, where 1 = offset by the length of one dash+space, which means that it tiles/repeats at every integer
    Dash TypeType of dash, either Basic, Angled or Rounded
    Dash ModifierChanges the shape of certain dash types
    Vertex & Triangle Count
    4 verts3 trisFlat 2D or Billboard
      Volumetric 3D lines triangle/vert count depends on your 3D primitive detail in the settings window

    Polyline
    Polylines describe a line drawn along a path made of multiple points. A Closed polyline means it's cyclical, its ends are connected. A non-Closed path on the other hand has two endpoints. The Polyline Points use both a global Color, as well as per-point colors, these are multiplied together! You can think of the color as a tint color.
    Just like the lines, you can set Thickness and Thickness Space to various units, scaled by the per-point thickness.

    Joins

    Simple - corners set thickness by vertex distance. Also known as Bad™ joins. These are the cheapest of all! Useful for when you have high point density and don't want mitering effects, or when you just want something cheap!
    Miter - corners are extended to the line's intersection point. Note that they may shoot off into infinity with very sharp corners. Don't cut yourself on these pointybois
    Bevel - corners are chipped off at their halfway angle, not sure who uses these joins to be honest but they're like always a thing
    Round - corners are rounded off all soft, cuddly and good~

    Geometry

    Flat 2D polylines are flat on the local space XY plane, ignoring Z. This is useful for making lines that are locked to a plane, such as in 2D games, or for a 2D surface in a 3D world such as a screen or minimap
    Billboard polylines are positioned in 3D space, still using a flat mesh, always trying to face the camera. Useful for a cheap way of drawing 3D lines without using much geometry

    Blend ModeWhat blend mode to use when drawing this shape
    ColorUniform color, tinted by per-point color
    ThicknessUniform thickness, in the given Thickness Space, scaled by per-point thickness
    Thickness SpaceWhat space Thickness is defined in
    ClosedOpen ends or closed loop
    GeometryFlat 2D or billboard
    JoinsMiter, round or bevel joins
    PointsPoints and their corresponding colors and thicknesses
    Vertex & Triangle Count
    2n verts2n-2 trisMiter, Open
    2n verts2n trisMiter, Closed
    8n-6 verts5n-6 trisBevel, Open
    8n vertsn+4 trisBevel, Closed
    10n-10 verts3n-2 trisRounded, Open
    10n verts3n+4 trisRounded, Closed

    Disc
    The Disc is a versatile shape encapsulating various Disc Types, including pie, ring and arc.
    When in ring or arc mode, Radius is not the distance to the outer edge, but rather distance to the center of a cross section of the ring. This is so that you can specify Thickness and Radius in separate units, with predictable results.
    When drawing arcs or pies, you specify a Start Angle and an End Angle. You can select what angular unit you want to use in the inspector. Note that if you access the disc through code, angles are always in radians.

    Types

    Disc
    Pie 🥧
    Ring
    Arc

    Color Modes

    Single color
    Radial gradient
    Angular gradient
    Bilinear gradient between 4 colors

    Dashed Rings & Arcs

    Dash Size and Dash Spacing are either in meters, relative to thickness, or a fixed count across the shape, depending on what Dash Space is set to. Dash Offset is always relative to a single period, which means integer values always look the same. Here are some example dashes, when set to Relative dash spacing
    size 1, spacing 1
    size 2, spacing 1
    size 2, spacing 0.5
    size 3, spacing 3
    size 3, spacing 3, offset 0.5

    Blend ModeWhat blend mode to use when drawing this shape
    ColorColor of the disc, Radial Inner, Angular Start or Bilinear Inner Start
    Color Outer StartColor of Radial Inner or Bilinear Outer Start
    Color Inner EndColor of Angular End or Bilinear Inner End
    Color Outer EndColor of Bilinear Outer End
    Color ModeSingle, Radial, Angular or Bilinear colors
    GeometryFlat 2D or Billboard
    Disc TypeDisc, Pie, Ring or Arc
    RadiusRadius of Disc & Pie. Radius to center of ring for Ring & Arc
    ThicknessThickness of Ring & Arc
    Angle StartStart Angle for Pie & Arc, stored as radians in code
    Angle EndEnd Angle for Pie & Arc, stored as radians in code
    Arc End CapWhether or not the Arc ends should be rounded
    DashedDashed or solid
    Dash SpaceThe space in which Size and Spacing is defined.
    • Meters
    • Relative (to Thickness), which means a dash size of 1 is always a square dash
    • Fixed Count, where Size is the number of repeating periods across the shape, and Spacing is the fraction (0 to 1) of which should be space
    Dash SnapSnap Dashes to the full length of the shape.
    • Off
    • Tiling (ensures a repeating pattern, ends with space)
    • End To End (ensures a dash is snapped at each end)
    Dash SizeLength of a single dash. When Dash Space is set to fixed count, this is the repeat count
    Dash SpacingSize of the space between dashes. When Dash Space is set to fixed count, this is a value from 0 to 1, where 0.5 means dashes and spaces have the same size
    Dash OffsetOffset of dashes, relative to the repeating period, where 1 = offset by the length of one dash+space, which means that it tiles/repeats at every integer
    Dash TypeType of dash, either Basic, Angled or Rounded
    Dash ModifierChanges the shape of certain dash types
    Vertex & Triangle Count
    4 verts2 tris

    Rectangle
    Rectangles have a Size in width and height, support rounded corners with a specific Radius, as well as optionally being hollow with a given Thickness. In addition, you can set the Pivot to be either in the bottom left or center of the rectangle
    Blend ModeWhat blend mode to use when drawing this shape
    ColorColor (RGB) & opacity (A)
    StyleHard vs rounded corners & hollow vs solid
    PivotWhether size should be relative to the center or bottom left
    WidthWidth of the rectangle. Displayed as Size X in the inspector
    HeightHeight of the rectangle. Displayed as Size Y in the inspector
    ThicknessHow thick this shape should be, in the given Thickness Space
    Thickness SpaceWhat space Thickness is defined in
    Corner Radius ModeWhether to use the same radius for all corners, or separate radii
    Corner RadiusGets or sets the corner radius for all four corners, in meters
    Corner RadiiGets or sets each corner radius, in meters (Order is clockwise, starting bottom left)
    DashedDashed or solid
    Dash SpaceThe space in which Size and Spacing is defined.
    • Meters
    • Relative (to Thickness), which means a dash size of 1 is always a square dash
    • Fixed Count, where Size is the number of repeating periods across the shape, and Spacing is the fraction (0 to 1) of which should be space
    Dash SnapSnap Dashes to the full length of the shape.
    • Off
    • Tiling (ensures a repeating pattern, ends with space)
    • End To End (ensures a dash is snapped at each end)
    Dash SizeLength of a single dash. When Dash Space is set to fixed count, this is the repeat count
    Dash SpacingSize of the space between dashes. When Dash Space is set to fixed count, this is a value from 0 to 1, where 0.5 means dashes and spaces have the same size
    Dash OffsetOffset of dashes, relative to the repeating period, where 1 = offset by the length of one dash+space, which means that it tiles/repeats at every integer
    Dash TypeType of dash, either Basic, Angled or Rounded
    Dash ModifierChanges the shape of certain dash types
    FillGradient color filling
    Vertex & Triangle Count
    4 verts2 tris

    Quad
    Unlike the rectangle, the quad is positioned with each vertex at an arbitrary point in 3D space. The Quad supports four Color Modes, Single Color, Horizontal Gradient, Vertical Gradient and Per-Corner Colors. Color interpolation across a quad is surprisingly nontrivial though, so in light of that, you can configure quality level by changing Quad Interpolation Quality in Shapes settings if you want higher or lower quality depending on your needs
    Blend ModeWhat blend mode to use when drawing this shape
    ColorColor of A, or color of the whole quad. Left color of h-gradient, bottom of v-gradient
    Color BColor of B, or top color for vertical gradients
    Color CColor of C, or right color for horizontal gradients
    Color DColor of D
    Color ModeSingle color, horizontal gradient, vertical gradient or per-corner colors
    ALocal space position of A
    BLocal space position of B
    CLocal space position of C
    DLocal space position of D
    Auto-Set DAutomatically position D based on the other points to form a planar rhombus/rhomboid
    Vertex & Triangle Count
    4 verts2 tris

    Triangle
    Similar to the Quad primitive, Triangles are positioned on a per-vertex basis. Its Color Mode is either Single Color or Per-Corner
    Blend ModeWhat blend mode to use when drawing this shape
    ColorColor of A for per-corner colors, or color of the quad
    Color BColor of B for per-corner colors
    Color CColor of C for per-corner colors
    Color ModeSingle color or per-corner colors
    ALocal space position of A
    BLocal space position of B
    CLocal space position of C
    BorderWhether it should outline the border or fill the shape
    ThicknessHow thick this shape should be, in the given Thickness Space
    Thickness SpaceWhat space Thickness is defined in
    RoundnessA value from 0 to 1 that rounds off corners. 0 is completely sharp, 1 is a large round circle
    Vertex & Triangle Count
    3 verts1 tri

    Regular Polygon
    Regular Polygons have equal side lengths and angles. With this shape you can make equilateral triangles, pentagons, hexagons, and any other regular polygon!
    Blend ModeWhat blend mode to use when drawing this shape
    ColorColor (RGB) & opacity (A)
    GeometryFlat 2D or Billboard
    SidesNumber of sides
    RadiusCenter-to-vertex radius
    Radius SpaceWhat space Radius is defined in
    BorderWhether it should outline the border or fill the shape
    ThicknessHow thick this shape should be, in the given Thickness Space
    Thickness SpaceWhat space Thickness is defined in
    RoundnessA value from 0 to 1 that rounds off corners. 0 is completely sharp, 1 is a large round circle
    AngleAngle of rotation, stored as radians in code
    FillGradient color filling
    Vertex & Triangle Count
    4 verts2 tris

    Polygon
    The Polygon shape is a 2D surface allowing for any number of points (within, you know, reason). The polygon allows for any non-self-intersecting simple polygons, including concave ones, as long as the Triangulation is set to Ear Clipping. While Polygons don't allow for per-vertex colors, it does have support gradient fills!
    Blend ModeWhat blend mode to use when drawing this shape
    ColorColor (RGB) & opacity (A)
    TriangulationWhat method to use when triangulating this polygon. Fast Convex Only is a faster algorithm, but only allows for convex shapes. Ear Clipping supports concave shapes.
    FillGradient color filling
    Vertex & Triangle Count
    Vertex count = number of points
    Triangle count = number of points - 2

    Sphere
    It's a sphere

    Blend ModeWhat blend mode to use when drawing this shape
    ColorColor (RGB) & opacity (A)
    Radius
    Radius SpaceWhat space Radius is defined in
      Sphere triangle/vert count depends on your 3D primitive detail in the settings window

    Torus
    Torus with configurable Radius and Thickness, with separate units. This makes it possible to make a torus with a Radius in meters but a Thickness in, say, pixels, which can be useful for making gizmo-like shapes. The torus is oriented so that the axis of revolution / normal direction is along its Z axis

    Blend ModeWhat blend mode to use when drawing this shape
    ColorColor (RGB) & opacity (A)
    RadiusRadius of the torus, also known as major radius
    Radius SpaceWhat space Radius is defined in
    ThicknessHow thick this shape should be, in the given Thickness Space
    Thickness SpaceWhat space Thickness is defined in
      Torus triangle/vert count depends on your 3D primitive detail in the settings window

    Cone
    A cone with configurable Radius and Length. Optionally, you can toggle the bottom Cap on and off, in case you want a hollow cone
    Blend ModeWhat blend mode to use when drawing this shape
    ColorColor (RGB) & opacity (A)
    RadiusRadius of the base
    LengthDistance from base to tip
    Size SpaceWhat space to use when setting the size
    Fill CapFilled or hollow base
    Vertex & Triangle Count
      Cone triangle/vert count depends on your 3D primitive detail in the settings window

    Cuboid
    A cuboid! Equivalent to a cube if Size is the same along each axis
    Blend ModeWhat blend mode to use when drawing this shape
    ColorColor (RGB) & opacity (A)
    SizeSize along each axis, end to end
    Size SpaceWhat space to use when setting the size
    Vertex & Triangle Count
    8 verts12 tris

    Immediate-Mode Drawing


    Drawing in immediate mode is useful when you want to draw from code, or for shapes that are only temporary, procedural, or where you don't want to deal with the overhead of GameObjects. Immediate mode is instantaneous - it renders only once in the camera you draw in, so if you want to continuously draw, you draw every frame! This means it's very easy to create dynamic setups where what is being drawn can always change with no overhead of destroying or creating GameObjects

    Example

    [ExecuteAlways] public class MyScript : ImmediateModeShapeDrawer {
    
    	public override void DrawShapes( Camera cam ){
    
    		using( Draw.Command( cam ) ){
    
    			// set up static parameters. these are used for all following Draw.Line calls
    			Draw.LineGeometry = LineGeometry.Volumetric3D;
    			Draw.ThicknessSpace = ThicknessSpace.Pixels;
    			Draw.Thickness = 4; // 4px wide
    
    			// set static parameter to draw in the local space of this object
    			Draw.Matrix = transform.localToWorldMatrix;
    
    			// draw lines
    			Draw.Line( Vector3.zero, Vector3.right,   Color.red   );
    			Draw.Line( Vector3.zero, Vector3.up,      Color.green );
    			Draw.Line( Vector3.zero, Vector3.forward, Color.blue  );
    		}
    
    	}
    
    }
    
    Attach this script to any object, and it will draw three 4px wide 3D lines along each axis at the center of the world, with different colors. Let's break it down:

    ImmediateModeShapeDrawer

    This is a helper class you can inherit from, that will make drawing in immediate mode a little bit easier when overriding the DrawShapes() method. This method is called once for every active camera, including the scene view if your script is marked with [ExecuteAlways]. Internally, this is just a wrapper for the camera OnPreRender callback, subscribed to in OnEnable and unsubscribed from in OnDisable. If you don't use this class, then it is highly recommended that you use the appropriate OnPreRender callback for your render pipeline when issuing draw commands

    Draw.Command(...)

    using( Draw.Command( myCamera ) ){} sets up a scope in which you can issue draw commands to the specified camera.
    • Consecutive draw commands of the same type inside of this scope will be GPU instanced, so avoid alternating between types of shapes if you want to use less draw calls
    • I highly recommended setting up draw commands in Camera.onPreRender or RenderPipelineManager.beginCameraRendering
    • ImmediateModeShapeDrawer automatically hooks into these functions in a render pipeline agnostic way, so all you need to do is override DrawShapes() and set up the draw command in there
    • While you can set up draw commands in Update(), it is not recommended. The reason for this is because it's important to not add more commands than you're rendering, as this will stack draw calls. If you're worried about this, you can always go to Shapes/Immediate Mode Monitor in Unity, to make sure nothing is leaking

    Shapes.Draw (static properties)

    Shapes.Draw is the main class for immediate mode drawing, and has two core parts. First, it contains static styling properties that will configure how all following Shapes should be drawn. For example:
    • Draw.Color = Color.red; will make all following Shapes default to red
    • Draw.LineGeometry = LineGeometry.Volumetric3D; will make lines be drawn using 3D geometry instead of flat quads
    • Draw.ThicknessSpace = ThicknessSpace.Pixels; will set the thickness space of all shapes to use pixels instead of meters
    • Draw.Thickness = 4; will make all shapes lines have a width of 4 (pixels, in this case)

    The list above is just a handful of the many static properties in there that you may find useful! Your IDE should be able to show you all available properties to edit if you type Draw.

    Note that when dealing with static properties, it's important to keep in mind that they are global. It's often useful to reset the static states right before issuing your draw commands, so that the states are guaranteed to be consistent, and not unintentionally use values that were set elsewhere
    • Draw.ResetStyle() will reset all styling properties (but not the matrix)
    • Draw.ResetMatrix() will reset the matrix (see below)
    • Draw.ResetAllDrawStates() will reset everything

    Shapes.Draw (drawing matrix)

    You can also set the matrix to use when drawing. A matrix is like a transform - it contains position, rotation and scale, all in one type. In other words, this allows you to draw relative to something other than world space

    Shapes.Draw (draw calls)

    Shapes.Draw also contains the actual draw calls - in this case, we are using Draw.Line in order to draw simple line segments, but it contains lots of other shapes

    • Draw.Line Draws a line between two points
    • Draw.Polyline Draws a polyline along a path (see usage below)
    • Draw.Disc Draws a solid disc/filled circle
    • Draw.Ring Draws a ring/circle with a given thickness
    • Draw.Pie Draws a pie/circle sector
    • Draw.Arc Draws a circular arc
    • Draw.Rectangle Draws a rectangle
    • Draw.RectangleBorder Draws a rectangle border
    • Draw.RegularPolygon Draws a regular n-sided polygon
    • Draw.RegularPolygonBorder Draws a regular n-sided polygon border
    • Draw.Polygon Draws a filled polygon (see usage below)
    • Draw.Triangle Draws a triangle given 3 vertex locations in 3D
    • Draw.TriangleBorder Draws a triangle border given 3 vertex locations in 3D
    • Draw.Quad Draws a quad given 4 vertex locations in 3D
    • Draw.Sphere Draws a sphere
    • Draw.Cuboid Draws a cuboid with a given size along each axis
    • Draw.Cube Draws a cube with a given size
    • Draw.Cone Draws a cone with a given radius and length/height
    • Draw.Torus Draws a torus with a given radius and thickness
    • Draw.Text Draws text mesh pro text
    • Draw.Texture Draws a texture within a rectangular region

    Now, there are way too many overloads to list here, but all Draw functions follow the same pattern:
    Draw.ShapeName( [Positioning], [Essentials], [Specials], [Coloring] )

    • Any unspecified parameters will use the static properties
    • The first few parameters are always for the positioning of the object
    • Second we have the essentials, the most common parameters of the shape, such as the radius of a sphere
    • Third, we have more special case parameters, that you might want to overload that you usually skip
    • Finally, the color override of the shape is always at the very end


    Polylines & Polygons

    Polylines and Polygons can be drawn in several ways. The first and most flexible one is to create a temporary PolylinePath/PolygonPath, then specify its points, and finally drawing it. This method will automatically dispose of mesh data at the end of its scope, since it's in a using block
    using( Draw.Command( cam ) ){
    	using( var p = new PolylinePath() ){
    		p.AddPoint( -1, -1 );
    		p.AddPoint( -1,  1 );
    		p.AddPoint(  1,  1 );
    		p.AddPoint(  1, -1 );
    		Draw.Polyline( p, closed:true, thickness:0.1f, Color.red ); // Drawing happens here
    	} // Disposing of mesh data happens here
    }

    The above code will recreate the mesh every time you draw it. If you instead want a persistent one that you can modify instead of recreate all the time, you can create a PolylinePath/PolygonPath in, say, Awake, and then, importantly, dispose it when you're done with it, usually in OnDestroy or OnDisable. This ensures any mesh data is cleaned up properly.
    (the following example below presumes you're using ImmediateModeShapeDrawer)
    PolylinePath p;
    
    void Awake(){
    	p = new PolylinePath();
    	p.AddPoint( -1, -1 );
    	p.AddPoint( -1,  1 );
    	p.AddPoint(  1,  1 );
    	p.AddPoint(  1, -1 );
    } 
    
    override void DrawShapes( Camera cam ){
    	using( Draw.Command( cam ) ){
    		Draw.Polyline( p, closed:true, thickness:0.1f, Color.red ); // Drawing happens here
    	}
    } 
    
    void OnDestroy() => p.Dispose(); // Disposing of mesh data happens here


    Drawing Text

    Text can be drawn in two ways. The easiest is to use Draw.Text()/Draw.TextRect() directly.
    The second method, is to pass a TextElement into the draw methods - this is much more performant.
    Internally, TextElement will reserve a text cache for a specific string and style you're drawing, which will help Shapes only update the text data when necessary.

    Below is an example implementation using the persistent text helpers
    TextElement elemA, elemB;
    
    void Awake(){
    	elemA = new TextElement();
    	elemB = new TextElement();
    }
    
    override void DrawShapes( Camera cam ){
    	using( Draw.Command( cam ) ){
    		Draw.Text( elemA, "Hello" ); // Draws text using the persistent element elemA
    		Draw.Translate( 0, 1 );
    		Draw.Text( elemB, "This is performant text", Color.red );
    	}
    } 
    
    void OnDestroy(){
    	elemA.Dispose(); // Important - you have to dispose text elements when you are done with them
    	elemB.Dispose();
    }


    Drawing without commands

    In some special cases, you may want to draw without using Draw.Command. For example, if you want to draw gizmos using Shapes, you can issue draw calls directly:
    void OnDrawGizmos(){
    	// set up all static parameters. these are used for all following Draw.Line calls
    	Draw.LineGeometry = LineGeometry.Volumetric3D;
    	Draw.ThicknessSpace = ThicknessSpace.Pixels;
    	Draw.Thickness = 4; // 4px wide
    
    	// draw lines
    	Draw.Line( Vector3.zero, Vector3.right,   Color.red   );
    	Draw.Line( Vector3.zero, Vector3.up,      Color.green );
    	Draw.Line( Vector3.zero, Vector3.forward, Color.blue  );
    }

    However, it's important to keep a few things in mind

    • GPU instancing is not supported without Draw.Command, which means each draw corresponds 1:1 to draw calls on the GPU, which can get expensive with many shapes
    • This will literally draw as soon as you call each draw call, which means that when during the render pipeline these draw calls happen is absolutely crucial, and in many cases they will simply not work, especially in HDRP and URP
    • Drawing like this is equivalent to using Material.SetPass and Graphics.DrawMeshNow
    • Generally, this is a bit of a legacy/advanced/bad way of drawing, so like, pls use Draw.Command instead~

    Anti-Aliasing

    Shapes will look best across the board when your project is using some form of anti-aliasing. 8xMSAA is recommended! Some shapes however, also have built-in local anti-aliasing, which means that they will have smooth edges even when your project has no AA method enabled.

    Local Anti-Aliasing

    Local anti-aliasing or LAA, is when shapes themselves have built-in AA, even when your project/camera isn't using anti-aliasing as a whole. LAA is available for most 2D shapes when using a non-opaque blending mode. There are some exceptions, which can be found in the feature table below

    You can disable or change the quality of local anti-aliasing in the Shapes settings window
    No LAA Fast LAA Corrected LAA
    The difference between Fast and Corrected LAA is subtle - Fast LAA has a slight bias in the diagonal directions, making circular shapes appear ever so slightly rhombous and have a slightly sharper curvature in the orthogonal directions, especially when small. Sometimes the edges in the diagonals are slightly fuzzy as well. Corrected AA fixes both of these issues, but uses a slightly more expensive calculation.

    Line Thinness Fading

    All lines thinner than 1 pixel, will be locked at 1 pixel wide, and instead start fading opacity based on pixel coverage. This feature is always on, and is a very useful technique to ensure that thin lines don't get the pixelated wandering ants effect. Note that this is applied regardless of sizing methods - lines with thickness set in meters will also behave this way as soon as it's smaller than 1 pixel on screen.
    Mind that this effect will only work if your blending mode supports fading. Opaque shapes will only be able to fade if you use MSAA. The higher the MSAA level, the more steps of fading you will have.
    Together with MSAA or LAA, you can get very smooth looking lines. Here's a comparison of a billboard polyline arranged in a sphere, with various options toggled
    AA off
    No Thin Fade
    AA on
    No Thin Fade
    AA off
    Thin Fade
    AA on
    Thin Fade

    Blend Modes

    Blend modes specify how the color of shapes should blend with the color behind it, and also whether or not it will write to the depth buffer.

  • All blend modes use the alpha channel as opacity/strength
  • All blend modes are order independent except Opaque & Transparent
  • All blend modes support LAA with 2D shapes
  • No blend modes write to the depth buffer, except Opaque

  • Opaque
    writes to the depth buffer, and sorts properly even when intersecting other shapes. However, it does not support transparency, unless you have MSAA enabled, in which case it will use alpha to coverage to approximate alpha blending. This is especially useful for short alpha fades, such as the edges of the disc shape. Note that MSAA does not work in the scene view. Opaque shapes in the scene view with alpha less than 0.5 are completely invisible, and those above 0.5 are completely opaque
  • Alpha-to-Coverage fading support with MSAA enabled
  • The only blend mode that writes to the depth buffer
  • Opaque 2D Shapes support LAA if MSAA is enabled

  • Transparent (Alpha Blended)
    is standard "over"-operator blending, similar to having a layer on top of another in photoshop. The shape will affect the color more and more the higher the alpha channel is. A value of 1 means it will just show the color of the shape. A value of 0.5 means it's a halfway blend between the shape and the background, while a value of 0 will be completely invisible, showing only the background.
  • Uses premultiplied alpha, which is useful when rendering to a render texture
  • Order dependent, which means that intersecting and overlapping shapes using this blend mode may not sort properly

  • Linear Dodge (Additive)
    is good for glowing/brightening effects against dark backgrounds
    Color Dodge
    is a harsher non-linear version of additive that goes even brighter when blending with bright colors. Has somewhat unintuitive behaviors when blending with pure black
    Screen
    sometimes also called "soft additive", is the opposite operation of multiply, softly blending toward white instead of black
    Lighten
    outputs the lightest of the shape and its background
    Linear Burn
    darkens linearly. This is the opposite of additive. Unlike multiply, linear burn has a tendency to introduce hue shifting
    Color Burn
    is a harsher non-linear version of linear burn that goes even darker when blending with dark colors. Has somewhat unintuitive behaviors when blending with pure white
    Multiply
    is good for tinting/darkening effects against bright backgrounds. It will softly darken toward black, which is the opposite of screen blending which softly brighens to white
    Darken
    outputs the darkest of the shape and its background
    Subtract
    subtracts this color from the background. It's like linear burn but the colors are inverted and it's annoying to work with

    Draw Order & Depth Testing

    Component Shapes

    Shapes Components are, internally, mesh renderers, and so they will sort the same way any other mesh renderers in Unity would, respecting GameObject Layers, Sorting Layers, and the camera sorting settings in your project
    • Shapes with the opaque blend mode render first, then all other blend modes render. Render Queue depends on the blend mode. The Opaque blend mode uses the Geometry (2450) render queue, all other blend modes use the Transparent (3000) render queue
    • Shapes will also be sorted by Unity's Sorting Layers within the same render queue, and the sorting settings you have in your project, along with being sorted by camera depth
    • All Shapes use depth testing by default (ie: they don't render if they are behind something), this can be changed at the top of components by changing Depth Test under Sorting & Depth. Note that component based shapes that override these values will not be able to use GPU instancing

    Immediate Mode Shapes

    Immediate mode shapes do not use sorting layers, render queues, or any other automatic sorting system, as they are raw draw commands being issued to the GPU. Instead, immediate mode shapes are drawn in the order you specify the draw commands, in the order you run each draw call. For the opaque blend mode, this matters less, but for any other blend mode, great care should be taken to issue all drawing in the order you want to draw them in.
    • Draw Commands will be injected into the render pipeline at the point specified with the second parameter of Draw.Command(). By default, the injection point is:
    • The ImmediateModeShapeDrawer component will subscribe to Unity's beginCameraRendering event in OnEnable
      • As a result, the order of separate IM shape drawers, depend on the order they were enabled in
      • You can explicitly set drawing order by either enabling the objects in a specific order, or changing script execution order in Unity, however...
      • ...I recommend having only one central ImmediateModeShapeDrawer in your scene, then have that call functions in other objects, in order to have full control over draw order.
    • Shapes drawn inside draw commands will draw in the order you issue the draw calls in
      • Each draw call will render on top of the previous one, unless something opaque was in front of it
      • Opaque shapes both write and read from the depth buffer, which means they are automatically rendered with correct depth no matter the order
      • I recommend drawing all opaque shapes first, so that all following calls can take advantage of being culled by the depth buffer. For example, if you draw an opaque shape close to the camera, and then another shape, using any blend mode, further behind that line, the closer line will still be on top since it wrote to the depth buffer
      • Draw.Text currently doesn't support custom depth/stencil settings, as of 4.2.0. More info in the changelog

    Meters, Pixels & Noots

    Shapes with a given thickness, width or radius, generally have configurable units to specify in what space the thickness should be in

    Meters, m

    Meters relate to the scale of your world, rather than pixels or any other screen-space unit. A line with a thickness in meters, will look thinner when you're further away, just like any other geometry in your game

    Pixels, px

    Pixels are screen-space units, where 1 unit covers a single pixel on your screen. This means that the distance from the camera to the shape won't affect its thickness on screen, and will instead always have a consistent pixel size

    Noots, nt

    Noots are pixel-density independent screen-space units, defined as a fraction of the minimum dimension of your resolution.
    By default, there are 100 noots across the shortest dimension of your resolution, so if you are running 1920x1080, then 1 noot will be min(1920,1080)/100 = 1080/100 = 10.8 pixels wide.
    You can configure the number of noots across the screen in the Shapes settings window, if you want to change the default 100 to something else

    Degrees, Turns & Radians

    For shapes that involve angles, you can specify the angles in three different units in the inspector

    Degrees

    define a full turn as 360°, meaning a quarter turn is the familiar 90° angle

    Turns

    define a full turn as 1, which is useful when thinking in fractions of a full turn, where 0.5 is halfway around the circle, 0.25 is a quarter way around, and so forth!

    Radians

    define a full turn as 6.28... = 2π = τ, which is useful in math formulas involving angles, arc lengths, and other relationships of the circle. Internally, angles are always in radians, across the entire library of Shapes. If you want to convert from degrees to radians, you can use degrees*Mathf.Deg2Rad, or turns to radians using turns*ShapesMath.TAU

    Performance

    Shapes is designed to be as light on the CPU as possible, by offloading much of the work to the GPU, which means the CPU can focus on your game, while the GPU takes care of all the drawing.

    General performance considerations

  • Shapes is supported on all platforms that support GPU instancing
  • Shapes works on mobile, though you need to keep general optimization things in mind
  • Avoid having expensive shaders covering many pixels. The more feature rich a shape is, the more expensive it is in general. A good example is the Arc, if you enable end caps and use bilinear color and make it dashed, this means it's now more expensive to render, and you should avoid having them cover a large part of the screen
  • Polygons and the Polylines both generate meshes on the fly when they are modified. They might be expensive on the CPU end in some cases, if you use a lot of points

  • Now, performance will also vary depending on what side of the library you are using and what you are doing with Shapes:

    Component Shapes

    These will be part of Unity's regular render pipelines, which means they will gain all the benefits of instancing - most shapes of the same type will be a single draw call, since they can all share the same mesh! However, as a tradeoff, this means that Unity is not able to frustum cull Shapes automatically, so if you construct an entire game using shapes you might start running into performance issues, but in general they'll be very fast. Tweaking parameters like radius and colors and all of that, is essentially free, and all of these things are simple shader parameters in the end! With the exception of polyline, since that one requires a mesh to update if you change points. Though, even that mesh is generated without any heavy math on the CPU, as it's only passing data rather than doing complex miter join calcs etc.

  • Shapes of the same type are GPU instanced
  • Tweaking per-instance parameters like radius and color is free and doesn't break instancing
  • Polylines and Polygons can't take advantage of GPU instancing
  • Immediate Mode Shapes

    When drawing using immediate mode, try to have Shapes of the same type issue their draw commands consecutively, that way they will be instanced together into a single draw call. However, if you don't use Draw.Command, then by nature of it drawing directly, each shape is a separate draw call on the GPU, which gets expensive quickly.

    UI

    To use Shapes in UI, set your UI to either camera-based or world-space UI, this makes Shapes show up!
    Another alternative is to render shapes into a render target, and display the render target in UI

    Overlay UI mode is however, not supported, using canvas renderers, rect transforms and all, unfortunately.
    It was never actually designed as a UI library, so it wasn't the primary use-case I was focusing on getting up and running, but it was a secondary use case I wanted. However, the reason it doesn't support overlay mode is because it's frankly a nightmare, so the workaround will have to do

    Shapes Feature Table

    Vector Based
    is when a shape has "infinite resolution", as in, it's not an approximation of the shape, and you can zoom in however much you want without loss of detail
    LAA
    is local anti-aliasing support
    Cheap Edits
    means that changing properties, such as color, radius, etc. of this shape is so cheap it's basically free
    GPU Instancing
    is whether or not these shapes will be instanced together to group multiple draw calls into one
    Dashable
    is whether or not it can be dashed (such as dashed lines or dashed rings)
    Gradient Fill
    is whether or not it supports color gradient fill. "yes" means it has gradients fit to that particular shape, "generic" means it only has a non-shape-specific gradient fill where you can make a linear or radial gradient, in either world space or local space
    2D Shapes Vector Based LAA Cheap Edits GPU Instancing Dashable Gradient Fill
    Disc yes yes yes yes n/a yes
    Pie yes yes yes yes n/a yes
    Ring yes yes yes yes yes yes
    Arc yes yes yes yes yes yes
    Line (flat/billboarded) yes yes yes yes yes yes
    Regular Polygon yes yes yes yes yes generic
    Rectangle yes yes yes yes yes generic
    Triangle yes[V] yes yes yes yes yes
    Quad yes[V] no yes yes n/a yes
    Polygon yes[V] no depends[PG] no[I] n/a generic
    Polyline yes yes depends[PL] no[I] no[DP] yes
    Text yes yes n/a[T] no n/a n/a
    Texture n/a n/a n/a no n/a n/a
    3D Shapes
    Line (volumetric) no no yes yes[IM] yes[L] yes
    Sphere no no yes yes[IM] n/a no
    Cuboid yes[V] no yes yes[IM] n/a no
    Cone no no yes yes[IM] n/a no
    Torus no no yes yes[IM] no no

    [V] This shape is inherently polygonal/not smooth, there are no curves to smooth out with vector based approaches
    [PG] Changing the polygon points retriangulates the mesh on the CPU, everything else is cheap
    [PL] Changing the polyline points or miter joins recalculates the mesh on the CPU, everything else is cheap
    [I] Polygons and Polylines use unique meshes, and so they cannot be GPU instanced with each other. The one exception is if you are drawing them in immediate mode using the same PolylinePath/PolygonPath in multiple consecutive calls
    [DP] Dashed polylines are surprisingly difficult, but may come in the future
    [T] Shapes doesn't have a text component since Unity already has that in the form of Text Mesh Pro text, but Shapes does have a wrapper for drawing TMP text in immediate mode, which can in some cases be expensive if you have lots of it
    [IM] shapes of the same type using the same detail level will be instanced together
    [L] 3D lines have limited dash support. No slanted or rounded dashes, and doesn't look very pretty when using a large thickness