Is there an equivalent to Pixels-Per-Unit for background images?

I’m converting a bunch of UI from the old UI system with 9-grid backgrounds. The sprites used the “Pixels-Per-Unit” to control how the corners of a 9-grid scales but, as far as I can tell, there is no equivalent for UI Toolkit. I’m looking for options which ideally don’t involve regenerating all my background assets to match the screen resolution.

You are correct that UI Toolkit ignores the pixels-per-unit, even for 9-grids. This isn’t a use-case we were aware of, but we’ll see if we can take it into account (should be feasible after a quick look into it).

Can you give me more details about your workflow to match the screen resolution? Do you use an asset preprocessor to change the pixels-per-unit value according to the target device?

What I did in the old UI system was set the canvas to “Scale With Screen Size,” “Match Width Or Height” with the slider all the way to match height. The goal is to show the same amount of content vertically on every screen and flex the layout in the horizontal. Then I create all my background textures at 2x the resolution required for my reference resolution so I have extra detail available for monitors which are higher resolution than my reference resolution. I use the Pixels-Per-Unit to scale all my assets down by 2x to match the reference resolution. It means I can layout my UI in pixel units for my typical user and know that its not going to alias horribly on higher resolution monitors. It may not be the best way to do things, but it makes layout easy and gives a reasonably consistent experience across a wide variety of monitors.

The only place I have found where setting pixels-per-unit actually matters for this strategy is with 9-grid assets because the scale of the corners is decided by the actual resolution of the asset so they all end up twice as big as they should be. Playing with it some more, the easy fix for me is just to double my reference resolution and, as I port the dimensions of my UI across, double all the dimensions. Then when the layout scales to match the screen all the 9-grids end up the right size. Now that I this figured out, the biggest hassle of 9-grids is that the slices end up in the CSS. I’m skinning the UI by defining a bunch of variables with image urls, fonts and colors and reskinning just means swapping out the variable definitions. With 9-grids I have to have a style for the background to include the slices and that (as far as I can tell) forces me to reference a specific background from my markup rather than the CSS which is less than ideal. Is there a way from CSS to specify that what to use the slices I specified when I imported the texture?

The broader context of where I am is that I have a fairly sizable chunk of complicated in-game UI written in the old UI system which I was about to retrofit with a skinning system which was going to be big effort on a UI cobbled together from prefabs. Since we are at least a year out from shipping I thought I’d take a chance on UIToolkit as the CSS style sheets make skinning much easier. So far its mostly been a big win as the performance is much better, the new animation system is a huge improvement (assuming it survives the experimental stage) and writing custom elements is more flexible than attaching MonoBehaviors to prefabs. I’m still early in my process looking for blockers (I’ve got a bunch drag & drop coming up which has me a bit worried) but so far I am finding solutions for everything.

1 Like

Thanks for the detailed feedback, this is very interesting.

Yes, we basically ignore the pixels-per-unit since UI Toolkit doesn’t work in world units (at least, not until we support world-space rendering). That said, I may make sense to adjust the 9-slices according to the pixels-per-unit value, if only to get parity with Canvas UI. I’ll add a task to see if that makes sense for us to do this.

When using plain textures, the -unity-slice-* styles are the only way to build a 9-grid.

When using sprites, the sprite borders (as defined in the Sprite Editor) will be used unless there’s a slice-style applied to that element. So if you want to use the sprite border for the 9-grid, you have to make sure that there are no -unity-slice-* styles applied on that element. If I understand your question right, there’s no way to select whether to use the style or the sprite borders if both are defined.

Great! We’re here to help if you need it.

1 Like

To feed the discussion, a little example :

I have a 9-sliced asset with 512x512 dimensions.

When the end scale of the element is lower than the asset dimension, this results in deformation of the borders :
7899007--1006201--upload_2022-2-15_18-31-43.png

The problem disappears when the element dimensions are higher than the original asset dimensions :
7899007--1006204--upload_2022-2-15_18-31-55.png

With the legacy Canvas UI, we could easily fix the deformation by modifying the pixels-per-unit property :
7899007--1006213--upload_2022-2-15_18-36-58.jpg

7899007--1006219--upload_2022-2-15_18-38-37.png

To solve this use case, I’m unsure if UITK should take into account the pixel density of the asset, or another way :smile:

In 2022.2, UI Toolkit will take the pixels-per-unit value into account to rescale the 9-slices. We also introduced a new “-unity-slice-scale” style if you want to provide a custom scaling. This should accomodate your use-case. We unfortunately cannot backport this feature, however.

2 Likes