This will be a brief overview of the new UI Toolkit Vector API that recently landed in Unity 2022.1
First, a bit of (mesh generation) context:
UI Toolkit already provides the Mesh API which allows drawing custom content into a VisualElement. However, while everything is possible, it is hard to use. The code required to generate a single quad has to allocate vertices and indices, and provide coordinates in a clockwise direction. There is a few way it could not work as expected and it not the easiest thing to debug.
void OnGenerateVisualContent(MeshGenerationContext mgc)
{
var mesh = mgc.Allocate(4, 6);
mesh.SetNextVertex(new Vertex() { position = new Vector3(p0.x, p0.y, Vertex.nearZ), tint = wireColor});
mesh.SetNextVertex(new Vertex() { position = new Vector3(p1.x, p1.y, Vertex.nearZ), tint = wireColor});
mesh.SetNextVertex(new Vertex() { position = new Vector3(p2.x, p2.y, Vertex.nearZ), tint = wireColor});
mesh.SetNextVertex(new Vertex() { position = new Vector3(p3.x, p3.y, Vertex.nearZ), tint = wireColor});
mesh.SetNextIndex(0);
mesh.SetNextIndex(1);
mesh.SetNextIndex(2);
mesh.SetNextIndex(0);
mesh.SetNextIndex(2);
mesh.SetNextIndex(3);
}
Overall, this is a tool for power users, but most users only want to generate very simple geometry, so this is unfortunate.
Vector API
Inspired by HTML Canvas, the new API allow C# programmer to build at a higher level, expressing directly their intention. The API provide easy to use methods for
- Lines
- Arcs
- Beziers
- Fills
- Strokes
- and more!
This is the same example using the new Vector APIs.
void OnGenerateVisualContent(MeshGenerationContext mgc)
{
var paint2D = mgc.painter2D;
paint2D.fillColor = wireColor;
paint2D.BeginPath();
paint2D.MoveTo(p0);
paint2D.LineTo(p1);
paint2D.LineTo(p2);
paint2D.LineTo(p3);
paint2D.ClosePath();
paint2D.Fill();
}
To build paths, you use the painter2D object in the context and issue commands that moves a kind of virtual pen. So here, we move the pen to the first position, and chain lines together to build a quad.
Once the path is done, you can either Fill it or Stroke it.
This remove the need to do many manual tasks as the allocation and the overall management of the data is abstracted, and the process is much more scalable for more complex shapes.
When doing some visual, doing a quad is the basic, but this API allows doing munch more than that using the different methods (LineTo, Arc, ArcTo, BezierCurveTo) and their arguments.
Another Example Setting the Color, Caps and Joins
Setting the color, the way segments are connected, the width of the line is easy with a one liner addition to an existing path. You can use the following options for the connections :
painter.strokeColor = Color.white;
painter.lineJoin = LineJoin.Round;
painter.lineCap = LineCap.Round;
painter.lineWidth = 10.0f;
painter.BeginPath();
painter.MoveTo(new Vector2(100, 100));
painter.LineTo(new Vector2(120, 120));
painter.LineTo(new Vector2(140, 100));
painter.LineTo(new Vector2(160, 120));
painter.LineTo(new Vector2(180, 100));
painter.LineTo(new Vector2(200, 120));
painter.LineTo(new Vector2(220, 100));
painter.Stroke();
With these tool combined, complex path can be achieved:
Fill the shapes:
The path previously defined can also be filled.
paint2D.fillColor = Color.Blue;
paint2D.BeginPath();
paint2D.Arc(new Vector2(100,100) 50.0f, 0.0f, 360.0f);
paint2D.Fill();
Holes:
Holes can be created by using the an argument with paint2D.Fill
We support two fill rules: odd-even and non-zero.
- When using odd-even, new inner segments will toggle if the shape is filled or not.
- When using non-zero, the fill is toggled when crossing a shape with a different winding order.
You can read about those fill rules on the web, this is well documented.
Technical:
The systems generate all the geometry, but it also allows the rendering to use arcs with an infinite precision without having an infinitely complex geometry.
Here is a zoom on the result. We can see some color compression artifact when the gif was generated, but no vertices.
The anti-aliasing used on these curves is the same as what UI toolkit uses for the rounded corners of the visual elements.
Not implemented:
We donât have any option for line patterns, gradients, texturing yet.
The anti-aliasing does not work on self intersecting path.
Final Words
We hope this will enable new uses cases for some projects, and we aim at collecting even more feedback to improve the tool in the future. Lets us know your thought and questions!