Introducing the Vector API in Unity 2022.1

Is it possible to replace the shader which the meshes are rendered with a custom one?

1 Like

It’s not currently possible to render UI Toolkit generated meshes with a different shader. If you want to insert an element that does custom shading with other meshes, you can use an ImmediateModeElement:
https://docs.unity3d.com/ScriptReference/UIElements.ImmediateModeElement.html

2 Likes

Thank you. Is this a planned feature, or is the VectorAPI meant to be used only with the built-in shader and its options, and for everything else one should use immediate mode for the foreseeable future?

We do have custom shading planned for UITK for not just the VectorAPI, but for VisualElements at large.

I would be interested to know more about the kind of effects you would like to use custom shading for?

2 Likes

I thought it was in progress :frowning:
Ideally shadergraph for canvas ui = same concept for uitoolkit too

I’m a beginner at UI, so maybe there are better ways to do this.

One easy example I thought if I could write a shader, I could do a lifebar by just drawing the lifebar via the Vector API, and then having a shader which draws bubbles into the lifebar or makes it seem as if it is filled with some kind of liquid. So all in all, I’d use it to have an easy way to draw meshes into a fixed position in the screen space and then shade them. Also, this way I could update update the shader values via UITK runtime bindings and use the same tooling I use for the rest of my UI.

Is there any tutorial or example showing how to use the immediate mode element?

1 Like

Here’s an example. Basically, you can issue immedate GL calls or use Graphics.DrawMeshNow() with the material of your choice. But most of the time, you’ll want to set the projection matrix to something that makes sense to your use-case.

Note that since your are using your own material, UI Toolkit features that are performed in shader (such as clipping and masking) won’t work for that element.

    protected override void ImmediateRepaint()
    {
        if (material == null)
            return;

        float x0 = layout.x;
        float y0 = layout.y;
        float x1 = layout.x + layout.width;
        float y1 = layout.y + layout.height;

        m_Mesh.vertices = new Vector3[]
        {
            new Vector3(x0, y0, 0),
            new Vector3(x1, y0, 0),
            new Vector3(x1, y1, 0),
            new Vector3(x0, y1, 0)
        };
        m_Mesh.triangles = new int[] { 0, 1, 2, 0, 2, 3 };

        GL.LoadProjectionMatrix(Matrix4x4.Ortho(0, Screen.width, Screen.height, 0, 0, 10));
        GL.modelview = Matrix4x4.identity;
        material.SetPass(0);
        Graphics.DrawMeshNow(m_Mesh, Vector3.zero, Quaternion.identity);
    }
2 Likes

Thank you very much! I also got a simple example working.

However, it doesn’t seem to work together with runtime bindings for me. I have a hierarchy

VisualElement
   Label
   CustomLineElement

I set a datasource for the visualement and I know that works, since I bind the Label to dataSource.name and get the right resolution. I also set some bindings for my CustomLineElement but the problem is that the following code

        protected override void ImmediateRepaint()
        {
                Debug.Log($"Datasource is {dataSource}:{dataSourceType}:{dataSourcePath}");
               //...

always returns

Datasource is ::

i.e. it doesn’t see the datasource (and the runtime bindings also don’t resolve to anything). I figure that is because ImmeadiateRepaint is maybe called before the datasource is actually resolved. I tried calling MarkDirtyRepaint(); in the ImmediateRepaint function as long as it doesn’t find the datasource, but this doesn’t seem to do anything (the function is still only called once).

Do you know how to resolve this?

Hi @frankfringe,

The datasource and dataSourcePath do not need to be resolved for a given element as they are properties of the VisualElement. They might be null or empty if they are set on the parent instead of the current element. To get the “resolved” data context you need to call either VisualElement.GetHierarchicalDataSourceContext or VisualElement.GetDataSourceContext.

Hope this helps.

In the UI toolkit run, create a skill tree, is it appropriate to use Painter2D to create a large number of lines?

1 Like


1 Like

Are there any progress on using Vector API on imported SVG? Is it already available?

It has been a while since I looked at the 2.0.0 API for Vector Graphics, so I apologize if I am wrong or off a bit. As far as I know using Vector Graphics 2.0.0 package there is a Sprite Editor for the imported SVG now. Image below. You can use both Sprite API and SVG API on the imported SVG files as far as I know.

After importing an SVG you can use the Scene class API to set up a list of IDrawable interfaces, a SceneNode for the Clipper, and a list of SceneNodes that act as children Scenes inside of the root scene. There is also the static method that can render your updated and edited SVG on the screen.

VectorUtils.TessellateScene(Scene scene, TesselationOptions option)

For filling Textures with using a UV you can generate a TextureAtlas with VectorUtils.GenerateAtlas( IEnumerable<Geometry> geoms, uint rasterSize)

then fill the uvs using
VectorUtils.FillUVs(IEnumerable<Geometry> geoms, TextureAtlas texAtlas);

The above two methods allow injected your SVG into 3D meshes and also Sprites.
And yes, you can use this API to draw a 3D mesh built from the shape of an SVG.

The IDrawable is implemented by the Path class. Setting the imported SVG into the Scene list of IDrawable opens up the ability to use the Path and Shapes API on it. Both the Path and Shapes classes has stuff like the BezierContour and all the path properties for customizing and editing the SVG via API.

Note the Shapes class inherit from the Filled class that implements the IDrawable interface.
Filled class let’s you set the IFill interface, Fill Transform which is a Matrix2D, and the path properties. The IFill interface is implemented by the GradientFill, TextureFill, SolidFill classes, so you can shove them into the Shapes Fill property.

The BezierContour has an array of BezierPathSegment which are literally just the points of the SVG in Vector2s. Each BezierPathSegment has three Vector2s in it to make up that one segment.

Example if the API is still the same as last time, I looked at the documentation example.
I could not get the code below to format properly for the life of me, sorry.

var path = new Path()
{ 
   contour = new BezierContour() 
     { 
      Segments = segments,
		Closed = false
      },
	pathProps = new PathProperties() 
  {
		Stroke = new Stroke() { Color = Color.red, HalfThickness = 1.0f }
	}
};

Hope this helps a little bit and again it has been a long time, so I apologize if this information is either outdated or a bit incorrect.

1 Like

Thank you very much. My main concern is, the normal import pipeline of SVG will convert it into just a rasterized texture

The last time I check it become raster at runtime. Or maybe I just misunderstood something about vector package

Can we maybe get a couple custom VisualElements (officially, from Unity) for basics such as drawing a line, drawing a curve, drawing a square, etc. - base shapes that are often useful and can be used as a starting point for more complex custom elements?