-
-
Notifications
You must be signed in to change notification settings - Fork 21.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pixel distortions at texture edges with centered sprite that has odd dimensions #82696
Comments
@vpellen Thanks, I think I can make that work. I am thinking though: Should/could this be improved in Godot itself? I guess low-res pixel-perfect games are just a niche nowadays, but I think they require a few workarounds at the moment that are not very intuitive. So if I take the perspective of a new user who wants to create a pixel game, I think the notion of dealing with half-pixel offsets or limiting your design to even-numbered sprites does not come very natural. On top of that they are facing a wrapping issue that does not seem very intutive at all. I remember that I created an issue some years ago about whether Godot should support a pixel-perfect mode that would only deal in integer coordinates, and would resolve these issues natively. I think back then the answer was that it would be too much effort for too little gain and that nobody really put a lot of work in for 2D anyway since it's very mature already. Since I have always wanted to contribute something to Godot, maybe this is something I could try my hand at one of these days. For now though I have two ideas for the current behavior that I think are worthy of discussion:
Do you think either of these has some merits? |
Thanks for the report. I don't think this is a bug (as already well explained by others), it's just the result of rendering an off-pixel grid sprite. If you want pixel-perfect 2D rendering, you can try some combination of these:
This issue has some useful discussion about these issues #81998 with some solutions and drawbacks. Also searching documentation and other Godot sources might prove useful. |
@vpellen Thanks for the extensive summary. Some of this I knew, and some you clarified. I wonder though: If the viewport is explicitly made for pixel-perfection, then wouldn't it be possible (or even necessary) to use just that configuration setting to realize some specific code paths that fix common problems like the one I raised in this issue? I remember writing a related issue where I actually addressed the problem of proper viewport rotation, which did not work as I expected at the time. I originally raised that issue because I came to Godot from GameMaker and for all its shortcomings, it has the pixel perfect handling nailed down to an art form, so I was hoping that we could learn from them. Since I've been wanting to actually contribute to Godot for quite some time, and I am a sucker for pixel-perfect games, this might be something I would like to try my hand at. But since I am absolutely new to the codebase, I think I would need to get some information about whether or not such a task is hopeless because it might clash with a lot of other requirements the engine has that I am not aware of. I think this issue is not the right place to start a more in-depth discussion about making Godot more friendly to pixel devs, so I'll try to collect my thoughts on this and move it over to the proposals tracker, do you agree? One thought: What's wrong with 480x270? It scales nicely to Full HD with a factor 4, that's why I chose it. Did I miss anything? @bitsawer Thanks for your input and the link. From my perspective, this issue can be closed if you want. |
It doesn't scale perfectly to 2560×1440 (~5.333×), which is a common resolution among players nowadays. This means there will be black bars on all sides of the screen on those displays.
There is already such a proposal: godotengine/godot-proposals#6389 Unfortunately, it's not very actionable in its current state, and nobody has opened a pull request for anything related to that proposal yet. |
@Calinou I may be way over my head with the idea to offer more pixel-art friendly options to godot, probably because there are a lot of cases I am not aware of. Having a perfect pixel game combined with a hi-res menu is certainly one of them. Thanks for the pointer. I might check it out and collect some information when my next vacation rolls around. Maybe I can look into this although I might be biting off more than I can chew. But at least I can use it as an excuse to dive into the codebase. |
@Cerno-b Ironically, I actually wish Godot would move away from pixel perfection. I vastly preferred unity's model of "pixels per unit", because setting max_velocity to some multiple of 16 always kind of annoyed me, and it makes dealing with high-resolution 2D graphics kind of unpleasant. I wonder if there's a proposal for that, come to think of it.. As for the pixelated viewport, it's actually got other uses - There's a game on steam, uhHhh.. starfox clone.. come on brain don't make me look it up.. zero something? X something? Damn it hang on. Ex-Zodiac! I was close. Kind of. Anyway, that game actually uses viewport stretch mode to achieve a low res 3D look. If you're looking explicitly for a pixel perfect look, my best recommendation would be to activate that snap-vertices feature and adjusting sprite pivots manually where necessary. As for the resolution, you can do the math: But, yeah, this is getting a bit outside the realm of this issue. Regardless, I dunno if this constitutes a "bug" beyond maybe that the rounding should be more uniform and everything should be snapping to the left rather than getting smeared? But, as I've mentioned, that's probably just innate to the way the rendering APIs work, at which point your beef is probably with the Khronos Group. |
@vpellen Could you point me to some more information about the multiples of 16 thing? I feel like there are so many more issues to this than I thought initially. About Ex-Zodiac, wouldn't this game deal fairly neutrally with changing pixel-perfect behavior to be more "perfect"? In the end, even though it is 3D, it wants to simulate an old-school look that would be pixel-perfect on an SNES era game due to the output restrictions of the system. So if we consider viewport == pixel perfect visuals, then I don't see the problem in this example, but I have to admit, I know very little at this point. As for the resolution, yeah, I haven't considered higher resolutions and thought FHD was basically the common consensus, but I understand that standards are increasing. Thanks for the hint. When it comes to what's technically possible, I am pretty sure there must be a solution, since GameMaker gets this to work, and I am pretty sure they use a 3D engine under the hood to simulate their sprites as well. But as I said, I'll need some serious reading to even consider presenting a use case for a "fix" if we want to call it that, so having access to a lot of information and past discussions is really helpful, especially to learn about all the use case I may have missed. |
@Cerno-b As for Ex-Zodiac, "pixel perfect" is kind of subjective in the first place, and doesn't really apply to 3D. In 2D it generally means that all the sprites get rendered in perfect alignment with a low-resolution grid, with no rotation or scaling. In Godot, that's achieved with the viewport stretch mode and pixel snapping, as well as just generally not rotating or scaling anything. I actually don't tend to stick to such things because having a higher resolution display with rotated and scaled pixel art affords you some flexibility in how you display things. It can be ugly if used badly, but usually the practical benefits outweigh the cons, at least for me. The interesting thing about Game Maker is it didn't always used to use 3D under the hood. I remember using it nearly 20 years ago, back when it was way more slow and janky - I believe it used DirectDraw (an old 2D equivalent to DirectX), and "alpha transparency" (let alone rotation) was something we could only dream about. |
@vpellen I think we are talking about different things when we talk about pixel perfection. The 16px limitation does not really apply to Godot unless I am missing something, right? I mean you can stick to a fixed tile size but you don't have to in order to get pixel perfection. To clarify, what I mean with pixel perfection is that the game runs in a fixed pixel grid that may or may not be upscaled, and whenever the game is rendered, this grid is strictly observed, even if it leads to duplicate pixels if you're not careful with your target resolutio. As compared to mixed pixel games or non pixel games where the grid is always the actual screen resolution. Purists like me want this nostalgic feel in games where the grid is observed. Other people like the mixed pixel art for it's convenience, flexibility or design aesthetics as you explained. As for rotation, under my definition, rotation is very well possible in pixel perfect games, and games like Nuclear Throne (GameMaker I believe) shows how it's done well (ymmv). As far as I remember it is a pixel perfect game that also uses rotation. Sure those rotations are not smooth but that's exactly the retro look some people aim for. I think Yoshi's Island on SNES made use of rotation and still had to obey the grid. Even Star Fox, a 3d game had to obey the grid on SNES. Both pixel perfection and mixed pixel games have their fanbase. It's a matter of preference I guess, I just wish the viewport mode would reflect more natively in Godot's UI if I'm right that the only use case is to stick to a predefined grid. Maybe I'm missing something but is there a use case where pixel snapping would not be used in viewport mode? To me it seems like switching it off causes a lot of problems, so I wonder why not enforce or at least default to pixel snap in viewport mode. Under a wysiwyg paradigm, is there a reason I would want to have float positions in editor if the game forces the pixels anyway? Shouldn't the editor help the user more to make the game look like it finally would? In the end that's kind of the reason I created this ticket, because the game looked different than the editor and I thought it was a bug. I'm basically looking for a way to make Godot more user friendly for the pixel crowd and need to collect information about what would stand in the way of this concept. |
So a few things. First, the 16 pixel thing is just about the nature of units and how that can make scale awkward to work with - technically it has no bearing on the nature of the rendering. It's just a personal annoyance from a practical standpoint. As for non-snapped in viewport stretch mode, there are a couple of things worth noting. For one, some people might prefer to use linear filtering rather than nearest, which would make the sub-pixel positioning useful. Secondly, the pixel snapping can distort rotated sprites slightly in a way that's undesirable (which I believe is why there's a second option to only snap transforms which, ironically, would not eliminate the problem you're having). You may also be thrown off by the fact that the editor itself does not use viewport stretch mode - it explicitly uses canvas item stretch mode. That's why you don't get issues in the editor. An option for using viewport stretch mode in the editor may actually be useful - although I'm not sure of how the particulars would work. Maybe a proposal could be made for that. One other thing - I actually did some experimenting, and I realized that I could only actually get the distortion you encountered with sprites that were not an even power of two. I tried a 32x32 sprite offset by half a pixel and encountered no such distortion. A 28x28 sprite offset by half a pixel on the other hand reproduced very similar issues. This points to the nature of the underlying issue: It's a floating point precision error given visual form. If you're unfamiliar with floating point precision errors, go type So I guess the two tl;drs are: Edit: Man, the more I think about it, why doesn't the viewport respect stretch and snap settings? |
@vpellen Thanks for the research and following up with @Lucrecious. I'll add one of my own tangentially related issues for completeness, as I think it would be solvable by what I have in mind: #60079 And this one, which is even more tangential but contains a collection of good links to related topics: #57221 Also as self-reminder, here is another good collection of pixel-precision issues that could contains related stuff: godotengine/godot-proposals#6389 I am still naively confident that it should be possible to change the behavior for Nearest Neighbor Viewport mode to accomodate pixel purists more but I'll really have to do some digging into the code before I consider a proposal to not make an ass out of myself ;) Ideally I would be able to try implementing something as a point of reference. I agree on the Linear Viewport mode. There, float coordinates absolutely make sense. It would be interesting to see how this would work in practice with a Viewport editor mode. It might work, but it also might feel a bit clunky. I guess this has to be experienced to be evaluated properly. The power of 2 thing is kinda weird, thanks for taking the time to check it. That would mean it's probably a bit more complicated than just a rounding issue, I guess and all the more reason to get to the bottom of this ;) Yeah, I've had my share of IEEE float run-ins, that's why Python's isclose() function is a thing. Maybe something Godot should also have. So to sum it up, for me, I think this is an interesting project to maybe pursue over Christmas to see if I can understand the codebase well enough to get some concepts of improved pixel-perfect behavior done that might help resolve other issues as well. At least looking into having a viewport mode in the editor. Thanks for your time and all your feedback! |
Godot version
v4.1.2.rc1.official [58f0cae]
System information
Godot v4.1.2.rc1 - Windows 10.0.19045 - Vulkan (Compatibility) - NVIDIA GeForce GTX 960 (NVIDIA; 31.0.15.3623) - AMD Ryzen 5 2600 Six-Core Processor (12 Threads)
Issue description
I have a pixel art project and my sprites have their leftmost pixels duplicated and their rightmost pixels missing.
This is only a problem when the game runs, in the editor the images look fine.
Steps to reproduce
This image shows the issue for a Sprite2D and an AnimatedSprite2D
I set scale to 3 for the screenshot to make the problem more visible
Minimal reproduction project
test2.zip
The text was updated successfully, but these errors were encountered: