Background gradients

Hello,

it would be great if we could define gradients for backgrounds in the style sheets. Something like:

background-image: linear-gradient(to right, rgba(255, 255, 255, 0) 98%, #ffffff 100%);

Are you guys planning on adding this feature?

5 Likes

It would also be usefull to be able to assign a texture 2D directly via code.

You can do that like this:

pictureElement.style.backgroundImage = new StyleBackground(image);

The only way to acheive gradients right now is through custom drawing using the mesh api. If you install the com.unity.ui package, you can then use the PackageManager window to install usage examples.
6349404--705798--upload_2020-9-25_13-49-0.png You can launch this sample using window>UI Toolkit> Examples> Rendering> Mesh API

4 Likes

Thanks for the tip. I am giving it a try, but it is quite cumbersome and I don’t have much experience with creating meshes. It will have to do for now or I will just ask our designer for the png with gradient.
However I would still like to know if you are planning on ever adding the css property for gradients.

I have an issue with the uxml traits. When I set them in the UIBuilder, they apply fine and the mesh is drawn. However when I change focus to any other VisualElement and return back to the Gradient, the values for colors are reset - the mesh is unchanged however.

Here’s how it looks:
6356763--707040--upload_2020-9-28_10-36-37.png

And here’s the code:

public class Gradient : VisualElement {
        public new class UxmlFactory : UxmlFactory<Gradient, GradientUxmlTraits> { }

        public class GradientUxmlTraits : UxmlTraits {
            UxmlColorAttributeDescription leftColor = new UxmlColorAttributeDescription {name = "left-color", defaultValue = Color.red};
            UxmlColorAttributeDescription rightColor = new UxmlColorAttributeDescription {name = "right-color", defaultValue = Color.black};


            public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) {
                base.Init(ve, bag, cc);

                if(ve == null)
                    throw new ArgumentNullException(nameof(ve));

                var grad = (Gradient) ve;
                grad.leftColor = leftColor.GetValueFromBag(bag, cc);
                grad.rightColor = rightColor.GetValueFromBag(bag, cc);
            }
        }

        public Gradient() {
            generateVisualContent += GenerateVisualContent;
        }

        public Color leftColor;
        public Color rightColor;

        static readonly Vertex[] vertices = new Vertex[4];
        static readonly ushort[] indices = {0, 1, 2, 2, 3, 0};

        void GenerateVisualContent(MeshGenerationContext mgc) {
            var rect = contentRect;
            if (rect.width < 0.1f || rect.height < 0.1f)
                return;
            vertices[0].tint = leftColor;
            vertices[1].tint = leftColor;
            vertices[2].tint = rightColor;
            vertices[3].tint = rightColor;

            var left = 0f;
            var right = rect.width;
            var top = 0f;
            var bottom = rect.height;

            vertices[0].position = new Vector3(left, bottom, Vertex.nearZ);
            vertices[1].position = new Vector3(left, top, Vertex.nearZ);
            vertices[2].position = new Vector3(right, top, Vertex.nearZ);
            vertices[3].position = new Vector3(right, bottom, Vertex.nearZ);

            MeshWriteData mwd = mgc.Allocate(vertices.Length, indices.Length);
            mwd.SetAllVertices(vertices);
            mwd.SetAllIndices(indices);
        }

Am I missing anything?

leftColor and rightColor fields on your element need to be C# properties in order for UI Builder to be able to read your UXML attribute values currently set on your element. UI Builder relies on reflection to find get-properties on an element based on the name of the custom attribute. In your case, the names are good (they match the attribute names) but they are not C# properties.

1 Like

Wow, is it documented somewhere?
BTW, I’d prefer C# attributes instead of extending UxmlTraits just to define some attributes. Something like this:

[UxmlString("custom-attribute")]
private string MyCustomAttribute { get; set; }

If this would be possible, I’d bet the names shouldn’t necessary match too.
And why do we need to have our own inner UxmlFactory? Why can’t it just be a C# attribute too?
Something like this:

[UxmlElement]
public class MyCustomElement : VisualElement {
4 Likes

An alternative to the mesh API is to use the Vector Graphics package com.unity.vectorgraphics. You can define a gradient in an SVG asset. Make sure you set the “Generated Asset Type” to “UI Toolkit Vector Image” in the importer.

3 Likes

@RunninglVlan This is indeed cumbersome and what you described is exactly where we want to go in future releases

2 Likes

+1 to adding linear gradient support to USS!

Using the Vector Graphics package is also extremely cumbersome. Despite having preview packages enabled, it wouldn’t show up in my Package Manager so I had to add it to my manifest manually, and then I had to install Inkscape and figure out how to make the gradient I wanted in it. Finally exported a rectangle with my gradient to SVG and imported it in Unity as a “UI Toolkit Vector Image”. My objective was to use the gradient as background image for a button with curved border radius, but no matter what I did I couldn’t get the gradient image to honor the border mask (Overflow set to hidden) so… for now I’m kicking this down the road and just using a PNG image containing my gradient. It won’t scale well, but it should get the job done until this can be achieved with the stylesheet.

1 Like

More than a year later, and the com.unity.vectorgraphics package is still not coming up in the Unity Registry packages…

How does the unity-slice attribute work with vector graphics?
I have an SVG file that looks like this (couldn’t upload the actual SVG file because it’s not an accepted extension.)


But since it’s an SVG file, I’m not sure what the values for the unity-slice attribute should be? It should be possible to express it in “relative units”, but the attribute only accepts integers (I assume it’s the pixel units of a statically sized texture).

Last time I read something official about it, it was considered “experimental” because no one was working on it
https://discussions.unity.com/t/795542 page-4#post-6873428

Ah… that sucks…

This trick works with UI Toolkit:

I applied it successfully in my project:

1 Like

Awesome! I’ll mention this to my art team (guy)

I noticed you’re using square corners. Are there any issues when using rounded corners?

1 Like

Several of my elements have round corners however I didn’t plan to make rounded windows, though now that you mention it I might try it.

Modern UIs require gradient (with parsimony). Being able to easily generate gradients at runtime using linear-gradient would be extremely valuable.

3 Likes