Hi Ui Team
I’m seeing noticeable color banding in wide, dark UI Toolkit linear-gradient and radial-gradient backgrounds, both editor and on mobile.
The project uses Linear color space and URP
Please advise
This is most likely because UI Toolkit uses a 16bit render texture per default (to save on mobile bandwidth) but applies that to all platforms.
You can create a custom panel configuration + create a custom render texture and set it to a 32 bit format
There could be many things at play (graphics api, render target format, urp settings, alpha gradient, etc). Could you submit a case in the bug reporter (Help>Report a bug), we’ll investigate.
Following causes banding, due to 0% i think?
background-color: #081217;
background-image: linear-gradient(
160deg,
#1e3a42 0%,
#081217 100%
);
Meanwhile im submitting the project as bug report.
Update: CASE IN-151280
Possibly. Even if the shader performs its computations in half precision, blending can take place in the RT precision. So if it’s R8G8B8A8_SRGB it could be 8 bits, which can easily produce bands like that. For example, with Vulkan the minimum guaranteed is 8 bits in this case:
basic blend operations are performed with a precision and dynamic range no lower than that used to represent destination components.
Also if the render target is SRGB (likely for overlay UI in linear project unless you enabled HDR output and it’s actually being used), the blending would occur before the SRGB-encoding, so in linear. This can’t yield a perceptually smooth gradient. Not saying it is the case, but it’s something that we’ve seen this in the past.
Sorry for not fully understanding the technical details, but this game is built purely with UI Toolkit using a Screen Space - Overlay setup. I’d like to use a modern Unity version along with modern workflows (like the Linear color space), and I’d love to resolve this without compromising on visual quality or look and feel.
Since I’ve already submitted the bug report along with the project files, I’m assuming it will be tested and hopefully a fix or workaround can be provided?
Yes, the case will be investigated, no need to submit again.
This is 8-bit quantization. The gradient is written to an 8-bit target, so it only has as many distinct colors as the biggest difference between your stops, which is 43 here. Those 44 values get spread over the whole fill, so each one covers a wide flat strip. The lower the contrast, the fewer values you get and the wider the strips, so dark low-contrast gradients are the worst case. This is not specific to UI Toolkit: CSS gradients in a browser band the same way, for the same reason.
You can reduce the banding appearance with a small custom shader that offsets each pixel by half a color level, so the two neighboring levels interleave instead of meeting at a hard edge. On your gradient the widest band goes from 48px to 8px.
Keep the element with the gradient a leaf if you can. -unity-material is inherited, so its children end up rendering with the custom material too, and every material change breaks the batch and costs extra draw calls. If it needs children, set -unity-material: none; on them.
Custom Function body:
float2 pixelPos = ScreenPosition.xy * _ScreenParams.xy;
float noise = frac(52.9829189 * frac(dot(pixelPos, float2(0.06711056, 0.00583715))));
float offset = (noise - 0.5) / 255.0;
Out = float4(saturate(In.rgb + offset), In.a);
// In Linear use:
// Out = float4(saturate(In.rgb + (offset * 2.0) * max(sqrt(max(In.rgb, 0.0)), 0.039)), In.a);
Shader Graph
USS
.my-gradient {
-unity-material: url("project://database/Assets/DitherGradient.mat");
}
Shouldn’t this just be a setting in panel settings? I could see this workaround could be helpfull on low end devices but on pc would be good to have ability to choose output format/bit depth.