The Theory
A 9-slice control is a way to render an image that has become very popular when building UI, with widespread support. It comes down to dividing an image in 9 regions and scaling them independently. See this Wikipedia article for more information.
Why is this important? Consider this image:
If we scale it uniformly, you will end up with results like this:
However, if we split the image in 9 regions:
Then we can scale each region independently, keeping the size of the border constant and scaling the interior to fit the available space:
9-slice in Unreal Engine 4
So I have good news and bad news for you. The good news is that UMG has support for 9-slice images, through the Brush interface. The bad news is that it’s pretty rigid and hard to use.
In order to use 9-slice scaling on a Brush, you simply select Box in the Draw As option and set the Margins:
The Margins will specify the percentage of the image that will correspond to the slices, for each side. Unfortunately, that’s all the control you get.
When you place an image on your UI, you’re applying a scale to change the image from the original texture size to the size it will have on the screen (at the reference resolution of 1920×1080). Ideally, you could specify the size of the slices independently, but this is not currently possible in Unreal Engine as of 4.24. The only thing that scales in the middle part. The size of the borders will be fixed and predetermined by the size of the original texture.
If you want to have thinner borders, you need to create a separate, lower resolution texture. In this GIF Rectangle_thin is the same texture as Rectangle, but at half resolution:
The only way I’ve found to scale the border itself without changing the texture is using the Render Transform, which is far from ideal.
Things get weirder
But wait, there’s more. Unreal provides another 9-slice mode, called a Border. It’s meant to work in the same way but avoid drawing the center piece. This is extremely useful to reduce fillrate when you have an image with a transparent center section.
But Border works…funny in Unreal. Looking at the code, I can see that the implementation of Box and Border are independent (one is in FSlateElementBatcher::AddBoxElement()
the other in FSlateElementBatcher::AddBorderElement()
). And while Border has the same restriction of relying on the original texture size, it also add a layout scale that depends on your DPI Scale and even your Zoom, while working in the Editor.
This is what it looks like when you switch between Border and Box. As long as DPI scale is set to 1.0 (I select Screen Size as Monitor 21.5″-24″ in the viewport’s top right ) the Zoom is set to 1:1, they match. But if you zoom in, they don’t:
Best practices
I wish the 9-slice received some love as it’s an incredibly useful tool. In the meantime, here’s what I’d recommend:
- Avoid the Border tool, as it will look different depending on the resolution of the game. Use Box and pay the price of drawing transparent pixels.
- Preview the margins using the Border tool, if the image is opaque. It’s the only way to see what the slices are, as there is no debug visualization.
- Scale the original texture to get the desired border size.
- If the Box brush just won’t do, you’ll have to construct it manually using layout controls.