¡Hello! My name is Daniel and I’m using Unity for 2 years. I’ve learned a lot of things on this time and now I’m developing a game with two more colleagues. Our game is tiny detailed pixel perfect game.
We faced “the pixel perfect problem” in early days. We didn’t worry too much, because we thought it’d be easily solved after some googling. We’re so mistaken… After weeks of googling and try lots of apparently suitable solutions, we keep getting some pixels duplication/deletion.
With Pixel Perfect I mean every single pixel in my sprite is represented proportional in Unity, I mean, they can be scaled up or down, but all of them by the same amount. I’ve been trying a huge number of things:
Sprites importing
Filter mode: Point
Pixels per unit: 100, 1, sprite size
Format color: True color, RGBA32
Sprites material
Pixel snap checked
Sprites movement
Pixel snap: code a function that set movement in a grid of 0.01 or 1 (depending on pixels per unit of sprites)
Camera
Orthographic
Size = Screen.height / 2 * pixelsPerUnit
Size = Screen.height / 2 * spriteSize
Pixel snap: code a function that set movement in a grid of 0.01 or 1 (depending on pixels per unit of sprites)
Quality settings (Rendering)
Texture quality: full res
Anisotropic textures: disabled
Anti aliasing: disabled
By the way, I’m using Unity 4.6 (porting to 5). After trying all this with no results, I’m about to quit, is very frustrating… It’d be great if you guys could throw some light on this topic. Maybe a tip, a tutorial or any other stuff.
Sébastien Dubois from Amplitude Studios gave many tipps how they achieved “Pixel Perfect” for their game - have a look at his Unite 2014 talk maybe it helps to address some of your issues:
One thing that bothered me about pixel snap is that it functions on a PER-VERTEX basis. In the shader, the code which applies the pixel snap (if I understand it right), applies an adjustment to the position of the current vertex. It doesn’t have any awareness of the other vertices, and the positions of the other vertices are not affected by this instance of the ‘fix’. What can happen, and what I have literally seen happen, is that vertices on the left and right edges of a sprite can be ‘fixed’ differently, and independently. I had a spaceship sprite which, as it moved, it would wiggle in a slight and strange way, as if the width of the sprite were alternating between ± 1 pixel width difference. This was noticeable because I was using a special shader which made it really obvious. I believe it’s somewhat to do with the inaccuracy of floating point math, whereby the result of rounding pixel coordinates on one vertex may produce a number that isn’t quite rounded in the same way for the other vertices. So one vertex was getting shifted to the left, while the other wasn’t, or vice versa. I guess that might have something to do with me using floating point coords for sprite positioning, but I also tried it with integer coordinates - and you know, floating point numbers have some trouble accurately representing exact integer values… and that very slight difference may be enough to cause numbers to sometimes round up, rather than down, adding or subtracting one pixel to the width of the sprite geometry. That is enough to make pixels appear or disappear, and can be quite noticeable. At least this is my theory, and it’s especially noticeable if you are using point sampling (like I was). Maybe less noticeable with bilinear, but still, sprites shouldn’t be changing their pixel width AT ALL. I think it’d be better to note use this feature, and instead have unity implement some kind of ‘adjustment’ at the vertex data level, as the mesh data is submitted to the gpu, rather than in the shader, so that width and height are maintained.
I don’t know if this is your problem or the only part of it, but I found this to be a problem with no easy workaround. If you don’t use sprites and you create your own quad geometry you can maybe better control the exact amount of pixels that the sprite spans and reduce the issues with point sampling.
@AwesomeAppDev thanks for your video! I’ve been following them for months and I’ve watched that video a couple of times too…
@rogueknight thanks your your answer. My sprites already are POT. I know the plugin (I’ve spoken with the creator too), I think we’ll have to buy it.
@imaginaryhuman_1 Thans a lot for your detailed answer. That’s exactly the main problem! My sprites are stretched or compressed horizontally, always about 1 pixel. It looks really weird on areas like legs (compare left image with centered and right). So, what’s the point? Use pixel snap? Not use it? Make a custom shader for sprites…?
I dont know if there is actually a way to use pixelsnap that really works… what was Unity’s intention? Maybe you have to position the sprite at always 0.5 above an integer pixel position, or 0.25, or something, so that when things round or whatever it does so in the same way to all vertices? Worth playing around with that to see if it helps. Otherwise I guess you want to create your own procedural geometry with exact coordinates.
Actually I’ve read about that in some thread. It’s supppossed that if you place your sprite with an offset of a float point number (I don’t remember how much) the pixel snap works properly. I’ll try it some and if it’s work I’ll post here. Thanks a lot for your responses.
It’s crazy how much effort is needed just to get the very basic stuff needed for a 2D game. You’d think these are exactly the kind of things the engine would be automatically handling.
I ran into many issues with 2D in Unity but through numerous experiments by myself and others shared on the forums finally got around them. The past 3 projects have went smoothly.
Your list in the OP looks very much like what I am doing except I also take care in how I import sprite images into Unity.
I am used to being able to just bring in an image with sprites or tiles all gridded right next to each other. However, this doesn’t work with Unity. So I ended up having a 2-pixel transparent border around every sprite or tile image. For example, if my tile images are 32x32 I have 2 transparent rows before the tile images and 2 transparent columns. Then I have a 32x32 tile image. 2 transparent columns. Another 32x32 tile image. Until the end of the row and then 2 transparent columns. Another 2 transparent rows. Then same process again for this row of tiles. I use the same approach for sprite images. Otherwise you can get weird artifacts.
Thank you very much for you answer @GarBenjamin ! Wow, that’s exactly our feeling! We wish a “PixelPerfect” option exist, in the same way as 2D or 3D project, and get things working properly directly…
About your 2 pixels border approach… Should it be exactly 2 pixels width/height? By now we’re importing an individual image of idle like next image:
Obviously “border” is wider than 2 pixels. Shouldn’t it work because of that? I mean, should it be EXACTLY 2 pixels? Any other advice about the rest of configurations? They are a lot, so mixing and combining all of them is quite difficult…
You guys don’t really understand the nature of the problem. Currently, Unity will do pixel perfect without any effort, but only if your resolution never changes. This is the same for all engines that are build on top of 3D hardware.
If you want to support a device which has higher or lower resolution then you will incur lossy results.
For example, you want your game to have a virtual resolution of 320x240? then you create a resolution of 320x240 and set camera to ortho with a size of 120 (half height), and all units are then 1 unit = 1 pixel. This will always be pixel perfect.
But what if a phone has a non standard size? You can minimise this issue a fair bit by using sprite shader snap feature, and designing the resolution smaller than the target display, as at least scaling up will only add pixels as opposed to removing them because there isn’t resolution to support.
Hi @hippocoder , thank you for your answer. I’m afraid I’m not explaining well. I don’t intend my resolution changes, since the beginning my target resolution is the default offered by Unity, 1920 x 1080. We don’t intend to export this to any mobile platform. Anyway, though my resolution is static, I don’t know the settings to get pixel perfect with no effort for that single resolution…
I’m following your instructions and still my sprite is not seeing pixel perfect (actually the screenshot above was get with this settings). Am I missing something? Do you really think it deserves to use 1 ppu and multply all forces (including gravity) times 100? Sorry if this is maybe too obvious doubts, but for me this task is not so effortless
Actually Hippocoder is right… when I had my project in the same resolution display as it was designed for the problem was pretty much gone… it was only when displaying in a different resolution that it then became a problem. This didn’t really resolve it for me though, because I am working at a fixed development resolution of 1920x1080 and have my camera say to 540 height, so that it adjusts and scales to all resolutions the same… this kind of setup does not work with the pixel snapping. The pixel snap will work if you are using like a 1:1 pixel mapping where, in higher resolutions, your graphics get smaller ie use the same number of pixels. So I think you can’t use pixelsnap if you are scaling your graphics to fit the resolution instead of changing the camera size.
Yeah there is more to it than that. There are numerous things that need to be done. Some are obvious yes such as keeping the display a perfect 1 to 1 pixel mapping (or a scaling so things are doubled or tripled exactly). The 2D pixel work needs many different things to all be taken into account such as the OP lists as well as taking some additional consideration on the sprite images themselves when loaded in to the sprite editor.
@neil89 if you can make a tiny project that illustrates the issue and upload it I will see if I can get it working using my current workflow / bag of tricks.
EDIT: I should add that I use 4.6 don’t plan on moving to 5 until at least another month or two. So if you can dupe the issue in a 4.6 project I will try to resolve it.
Thanks to all of you, specially @GarBenjamin , I’ve achieved pixel perfect on Unity 4.6 following some minor tweaks:
Setting up the output resolution. I was building my game on 1920x1080, though my screen max resolution is 1280x1024. So, I changed the built resolution to that one
Set orthographic camera size to [ Screen height / (2 * Pixels Per Unit) ]. Since my PPU is 100, I set camera size to 5.12.
Assigned sprite renderer material with Pixel snap enabled
That was all. If I run the game on Editor, Game panel is not same resolution as my screen so camera size should be adjusted (thanks again to @GarBenjamin by set this point clear too).
Again, thanks a lot to everybody who support me on this and try to help. I hope this help more people too. We’re in touch. Regards!
It’s also worth noting that pixel-perfect rendering is a lot more necessary when dealing with scaled pixel art. For higher-resolution games, running native-resolution sprites, slight changes in individual pixels are much harder for the average eye to perceive.
When you are scaling up pixel-based artwork, however, these differences become much more evident, even to the untrained eye. For cases like this pixel-perfect rendering becomes much more important.
One method you might consider is an adjustment to the movement controller for individual sprites. In a 3D environment, improper pixel rendering often occurs because an objects position is between where a pixel difference would normally occur. A simple script could be used to adjust an objects “rendered” position based on integer values in order to keep it’s rendered sprite pixel-perfect.
@RichardKain that is spot on. In my very low res pixel project all sprites are positioned to pixels. The camera is also positioned to pixels when scrolling.
Like you said though I do think many people might not understand the issue because unless you are working with very low res pixel art the issues won’t be noticeable. If you just make a 2D game using hd graphics the problems will likely not even be noticeable. But when you are working with sprites that are like 16 x 16 pixels and on screen that is essentially 256 x192 pixels these little distortions / glitches are very noticeable. The same artifact occuring on a sprite 80 x 67 pixels on a 1280 x 800 display will probably not even be noticed.
Right. A game like, say…Rogue Legacy wouldn’t really suffer from this issue all that much. It’s a 2D game, sure, but it is designed from the ground up to be run at high-definition resolutions. Most of its sprites are designed to look good at HD resolutions. Any such artifacts from scaling would be much less obvious.
However, a game like, say…Shovel Knight would have a lot more of a problem with this issue. That game is designed to emulate old-school retro pixel resolutions and graphics. Scaling artifacts for a game like that would be much more noticeable to the player, and much more distracting.
I’ve reading around the forum and everyone posts the same equation that I see here: Screen height / (2 * Pixels Per Unit)
This does enable pixel perfect rendering, but changes the scale of the sprites depending on the resolution, which is undesirable. I’ll paste a part of my answer from another thread.
In order to achieve pixel-perfect rendering and render everything in the appropriate scale regardless of the screen resolution, you just need to set the camera size taking the following into account:
the screen resolution
the pixels per unit of the assets
a desired orthographic camera size
I have created a simple camera script (which is free) that takes all of this into account. You can set the desired camera height (or width) and the script will find the closest pixel-perfect camera size. It works for every resolution, be it on mobile or even the arbitrary resolutions used in the editor. See it in action in this HTML5 demo.
Also, pixel snap (as imaginaryhuman explained) corrects a sprite per vertex. This does not enable pixel-perfect rendering but just reduces the shimmering artifact. Also, as he points out, it may create another artifact if 2 vertices get corrected in a different way. So, I would avoid using that.
Something to also keep in mind is that the graphics hardware API (OpenGL/DirectX etc) typically works using floating point math. This practically guarantees that some amount of imprecision is going to creep in somewhere. Vertex data is floating point as well. Even if you could pass exact ideal 4-vertex values to every vertex in a custom shader to have it ‘correct’ the positions and maintain exact sprite width and height to whole integer values, it’s still going to have to deal with the fact the data is floating point and may result in a little bit of offset in terms of position.
I particularly had an issue with pixel accuracy because I had this shader which indirectly rendered pixel colors, ie using a lookup table mapping instead of using the texture colors. It was extremely difficult to get exactly precise lookup of the exact right pixels from the indirect palette texture, without some kind of shimmering or dancing or occasional glitching of the pixels. I think the best and only way and only scenario in which this can be accomplished is when you are using as close to integer coordinates as possible in a SINGLE resolution display with exact 1:1 pixel:texture mapping, and avoiding pixel snap for the earlier stated reasons.
I could get a rock solid display of pixel data this way at e.g. 1920x1080, at least most of the time, but as soon as the resolution changes, with the same sprite geometry size and texture data, you’re practically guaranteed to see artifacts. You just can’t expect to use the same texture data at a non 1:1 ratio ie at a higher or lower resolution. Any mismatch between the texture grid and pixel grid is going to present a problem. You really ideally need a custom set of sprite texture data for every resolution, hand-adjusted to look exactly how you want it, and even then that WILL mean that certain pixel-level features will differ slightly and it might be noticeable or change the character of the art.
I really wish also it was easy to have unity NOT internally upscale non-power-of-2 texture data to power-of-2. I know it helps with speed and compatibility but this is 2016… it just introduces more blurring and other issues, and is a total no-deal if your pixel data is ‘data’ and not colors.
Well the other brothers (and some other retro titles I did for clients) came out years ago, and I have not had a single complaint or review about funny pixels. They all universally say the graphics are great. That is because the art is great. I was aware of all and any pixel problems of course but chose to completely ignore it, suspecting gamers really, really don’t care (they don’t care).
Also means I can zoom.
I think what the real solution here is, is to not care but instead apply retro antialiasing which is on asset store / in a thread someplace. That smooths out all the problems.
All this drama is really developer centric. It’s a magnifying glass operated by the developer obsessing over what they decide are important flaws.