Introducing the Vector API in Unity 2022.1

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

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

1 Like

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?

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);
    }
1 Like

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.