As the content of the Scroll Rect moves, thin horizontal lines (one-pixel height lines) don’t maintain a constant appearance. The lines occasionally appear thicker or thinner and shimmer/flicker while scrolling. Ideally, we want these horizontal lines not to visibly change, maintaining a pixel-perfect appearance throughout. Please note that setting the Canvas to “Pixel Perfect” does not alleviate the issue.
EDIT:
To address the line shimmering, I applied the following solution that ensures pixel-perfect scrolling:
public class PixelPerfectScrollRect : ScrollRect
{
[SerializeField] private Camera m_Camera;
protected override void LateUpdate ()
{
base.LateUpdate();
EnsurePixelPerfectScroll();
}
//...
void EnsurePixelPerfectScroll()
{
if (!m_Camera || !m_Content) return;
var pos = m_Content.position;
var screenPoint = m_Camera.WorldToScreenPoint(pos);
screenPoint.y = Mathf.Round(screenPoint.y);
screenPoint.x = Mathf.Round(screenPoint.x);
pos = m_Camera.ScreenToWorldPoint(screenPoint);
m_Content.position = pos;
}
This method effectively eliminates the line shimmering, but it introduces a new problem: the content movement now appears jerky, especially at low velocities. The jerkiness seems to arise from the immediate adjustment of the position that happens when we round the position to the nearest pixel.
EDIT:
There are many apps, like WhatsApp or various Android/iOS contact list apps, that feature thin divider lines yet still maintain pixel-perfect and smooth scrolling. This suggests that achieving both pixel-perfect appearance and smooth scrolling simultaneously is feasible.
I’m looking for any advice or insight into how this might be accomplished in Unity. If you’ve encountered a similar issue or have any ideas, I would be very grateful to hear from you.
Not Unity UI expert, but I think that might be not possible to fix it with C# code. If I am correct the problem comes from aliasing the edge of mesh, I mean you probably have images as elements and edges of those elements can “land” between pixels, what results in stretchy behaviour. You fixed this by putting the whole thing perfectly aligned with the pixels on the screen.
Now, I suspect that if you rendered perfectly aligned list to render texture, then you used that render texture as your actual viewport (but with original scroll offset), then you would end up with perfect smooth movement (becuase it would be one mesh/texture and it can interpolate color between list elements).
In any case I guess it might be good idea to ask in some graphics/shader section about this problem, plus if you attach video of this behaviour it can be helpful to everyone to see if you are talking about the same problem as they think.
//edit: or actually… try to create list elements (the background or whatever makes those lines) with at least 1px of spacing from the edge - in theory it should prevent bleeding color from the edge if I understood the problem correctly.
Here are the videos (please set them to full screen):
(1) The first video highlights the issue with divider lines shimmering during scrolling. As you can see, the thin lines don’t maintain a constant appearance and exhibit a shimmering effect:
(2) The second one shows that the shimmering effect is gone with the pixel-perfect solution. However, the content moves in a noticeably jerky manner at slower speeds, especially when it’s about to stop:
Thanks for your responses. A two-pixel height line is undesired for my specific use-case, Furthermore, the issue still persists even with a line thickness of up to 3 pixels
The setup for the divider line is rather straightforward as shown below:
Note that the issue of line inconsistency is independent of whether a sprite is used for the Source Image or not. The only way to prevent it (that I know of) is by ensuring the content moves by whole pixels.
Try to do what I said in previous post. Take the sprite I attached here, set it as divider image, but set the height to be also the height of the image (3px) and see if the problem is still there.
It still happens with 3px and using your image. Is not about the sprite attached. Also, I would preferably use thinner lines, so thickening them to avoid line shimmering won’t be a good fit here.
I suspected that. I increased the alpha to something very big (16px), and the shimmering starts to disappear when I set the image component’s height to that amount. I need to do more testing, but thanks for the suggestion, maybe that sort of practice can do the trick.
EDIT: Unfortunately, it still shimmers. The only way to avoid shimmering completely is to thicken the line enough. Although I must admit that it did improve it a bit.
Actually the image I gave you was somehow without the margin, I don’t know why.
I made list with background color the same as single element, I added lines between elements as images (3px height, but actual line on it has 1px, image attached), and disabled pixel perfect canvas. This is how it looks like on my PC:
Obviously not perfect, but there are no those wandering double lines or jumping. What do you think?
I think it looks pretty nice. At least way better than having a one-pixel line with no transparency for sure.
I’ve been testing it and the shimmering’s barely noticeable, thanks!
Now I’m trying to figure out which of the 2 following approaches will work better:
(1) A perfect one-pixel line with 1px alpha on both sides ( @Qriva 's suggestion)
(2) A thin line (possibly 1-2 pixels thick) with blurred edges and 1px alpha on both sides.
I think visually the 2nd looks more consistent, but maybe it’s just me. @Stardog when you mentioned the alpha, were you referring to either of these approaches?
I was meaning (1) except with an 8x8 image (power of two, 7 transparent pixels above, 8 below). From testing, it looks the same as the 3px, so this will only make a difference when the object is rotated on the X axis, or needs 3D perspective. Rotating Z and translating Y it looks the same as the 1px of alpha.
Maybe you didn’t make the height of the gameobject match the line (3px)? And it should be imported as a Sprite.
I recommend just buying this asset - Procedural UI Image. It’s 1px high image will be antialiased by default, even when rotated on Z axis.
I understand that this asset may not be particularly performant, as it uses a single draw call per image and some CPU-intensive operations. This was somewhat off-putting for me. They may have improved performance since I last checked, but I haven’t seen any reviews addressing this. If you own this asset and can confirm any improvements, or share your experiences with it, I’d greatly appreciate it.
I’m curious about how this asset handles shimmering and anti-aliasing. Could you explain why their approach is effective?
Regarding my specific issue, the game object in question is a prefab, and its height is set to 3px to match the 3px sprite. Therefore, each line should appear identical, but they do not. I can confirm that the image has been imported as a Sprite: