I'm currently working on a 2D game on iOS and I'm using power of 2 textures (of course). My camera is set to Orthographic because everything I position in the world is pixel perfect.
I'm also using optimized textures for my fonts, which mean that each character are really close to each other inside the texture to be sure to keep the smallest size as possible.
The problem is when I position my text inside the world at a half-pixel position, it seems that Unity blend or change/adjust my UVs coords that I have set for my texture. So the bottom of my 2 (inside the texture) is now rendered over the top of my 5. The reason is that in my texture 2 is above the 5.
But why Unity changes this? Maybe it is something else.
My UVs are pixel perfectly set on my texture, I don't understand why that would be change when I position the text into the world even at a half pixel. Anybody have an idea ?
It's impossible to display a bitmap texture with pixel precision quality at a half pixel position. That's in fact quite logical because half pixels do not exist. So what's happening is that your texture is filtered : the engine interpolates every pixels of the final image from neighboring pixels of your texture to give the impression that you texture is positioned at a half pixel.
Interpolation leads to two problems :
- the image is kind of blurred and there's not much to do against that
- pixels just outside the desired UVs tend to smear inside and that's where padding is useful. On a texture atlas you don't want to stack elements too close of each other or you end up with this problem. If you are sure your texture will never be seen with an important decrease of scale you can use only a minor padding of 1 or 2 pixels but you could need a far bigger padding for a scaled down texture.
Thanks for your reply and the precision of it. One of my teammate already told me something similar which goes in the same way than you. I was then wondering if there were a way to prevent it or disable the interpolation so Unity just use transparency around my UVs coords. But as you said, inside my texture the characters are so close to each other that it's gonna lead me to use the padding solution.
Or I think it might be better for me to never position anything to half pixel if I can. The problem of that is for dynamic positioning which gets a lot more complicated!
Thanks for your help!
Have a nice day
to position things easily with integer values you just have to have 2 sets of coordinates (Vector3). One with float values for the real position and on which you apply movements, one with integer values which is obtained from the first on an update basis. This second Vector3 is what you feed to your gameObject transform position and that's done. For slow moving objects though you'll see small hiccups during translation if you go that way.
That's a good idea too, I'm currently using Math.Round on my float values. I multiply them by 100 before applying Round and divide them again after to have my 2 decimal precision. In my case 0.01f = 1 pixel.
For the smooth movement, like scrolling bar the effect won't be very cool, but I guess I have no choice.
Do you think it could works if I set my UVs inside the scrollbar texture, so the padding will be 1 or 2 pixel of the actual texture, so if the engine interpolate out of my UVs it's still going to use the right texture ? I guess it's a bit of a hack, but on the top of my head it sounds like it could work.
If you don't mind the small blurriness caused by filtering padding is indeed the best way to avoid your problem. You then just have to choose the right padding value for your texture according to how it is used ( i.e. how much it is scaled down on screen or how much it can be viewed along the camera view axis which is mostly irrelevant for GUI textures).
Great, thx, it gave me new thoughts and ideas! I'm definitively going to try one of those A mix of few options might be a good solution for me.