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
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?
I thought it was in progress
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);
}
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.