godotengine/godot

Flickering sprite bleed on top row of moving sprite2ds and animatedsprites in Godot V4 (does not appear in V3)

Proggle opened this issue ยท 15 comments

Godot version

v4.0.beta2.official [f8745f2]
and
v4.0.beta4.official [e675154]

System information

Windows 10

Issue description

Godot 4 has introduced additional sprite bleed that wasn't present in V3. Example: the white line appearing above these sprites.

The one on the left is an animatedSprite, the one on the right is a Sprite2D

sprite_frames_v4b2.DEBUG.2022-10-09.18-46-16.mp4

This appears regardless of whether or not the 'fix alpha border' checkmark is enabled, and appears at seemingly random times. However, it happens on both sprites simultaneously.

It also seems to only bleed above the sprites, and not in the other 3 directions. Since it only appears for 1 frame, my video isn't capturing every appearance - it happens both when they are moving upwards and moving downwards.

Steps to reproduce

Move a sprite around, eventually you will notice flickering bleed.

Minimal reproduction project

sprite_bleed.zip

I ran the MRP but was unable to reproduce the issue with default settings. I could however reproduce the issue by setting the texture filtering mode to "linear".

Did you verify that all the settings are the same between the MRP and your Godot 3 project? Importantly repear and filtering are now properties of Node2Ds rather than import settings on the sprite, so you need to ensure that they are the same. Especially if you were relying on the "pixel art 2D" texture preset

Running the MRP on my computer consistently produces this behavior. I just re-downloaded the zip and opened it in v4.0.beta2.official [f8745f2]

and am still seeing it, even with the settings on 'nearest'.

image

video doesn't capture all the flickers but it gets one right at the beginning.

sprite_frames_v4b2.DEBUG.2022-10-12.22-23-17.mp4

I first noticed this behavior porting a more complicated project from V3, but the MRP itself is V4 native.

In your Godot 3.x project are you have the rendering/2d/snapping/use_gpu_pixel_snap project setting enabled by any chance?

In your Godot 3.x project are you have the rendering/2d/snapping/use_gpu_pixel_snap project setting enabled by any chance?

Not that I know of. Here's a fresh godot3 project I made, recreating the minimal godot 4 project. It works without flicker.

SpritebleedG3.zip

(It also has the godot icon in frame, so screenshots can be differentiated). I'd attach a video, but a video of the sprites moving up and down without flickering isn't that interesting.

Just as an update, I've tested this with Beta 4 and it still happens.

SpritebleedG3_UpdateToBeta4.zip
For this test, instead of making a project in the beta from scratch, I imported the G3 MRP project to G4B4. I then changed filter mode to 'nearest neighbor', since that always needs to be done.

Still happening in the 4.0 release version.

I can confirm this on 4.0.rc 8208060 (Linux, GeForce RTX 4090 with NVIDIA 525.89.02):

simplescreenrecorder-2023-03-01_19.10.45.mp4

This occurs with both Forward+ and Compatibility rendering methods.

However, I'm not convinced this is a bug. The atlas sprite has a white background, which is bound to create issues whenever a texture is not perfectly aligned with the camera:
block_characters

If you replace white with transparency, the issue goes away entirely.

PS: Even if you don't replace white with transparency, enabling Snap 2D Transforms To Pixel and Snap 2D Vertices To Pixel seems to fix the issue too. (Enabling either of those may work too, but I've only tested each combination for a minute or so.)

However, I'm not convinced this is a bug. The atlas sprite has a white background, which is bound to create issues whenever a texture is not perfectly aligned with the camera:

It absolutely is a bug. Godot is being asked to render some specific pixels and it's putting the wrong ones on screen. Sprite bleed might be a common problem to encounter when developing an engine (I spent several weeks wrangling a bug to get Pixi rendering in JS to avoid bleeding while resizing), but it's by no means impossible to avoid (after all, Godot 3 didn't have these sprite bleed issues).

Putting a 1 pixel border around every edge of every sprite in an atlas as a workaround is a bad idea - it makes everything involving tiles and spritesheets WAY harder to work with, especially when editing them in an image program. Because of that (and to minimize file size), most assets packs and tilesets which are available for game use are designed with the assumption that the engine will display pixels correctly. If godot is going to be dev-friendly, it shouldn't require developers to go into all their assets and do additional processing by hand to work around an engine bug. If adding 2-pixel-wide gutters around every frame is necessary for the engine, that should be done programmatically by the engine itself - but since godot 3 doesn't have this issue, it's probably just a bug that can be fixed more elegantly.

EDIT: Anyway, I went back to v4 alpha 1 and it's present there, so that narrows down what changes were responsible a little bit. Gonna try titrating versions a bit further.

sprite_frames_v4b2.zip
Well, have struck out on finding a version without the bug, looks like it was probably part of the big render rewrite. On the plus side, I've managed to capture a static version of the sprite bleed, in the editor view, so it should be easier to figure out what's going on.

It appears that at this zoom level and location, sprite2d and animatedsprite objects at y= 76 show the sprite bleed, regardless of x coordinate. Zooming out makes the bleed disappear, returning to this zoom restore the bleed. Resizing the window or going fullscreen have the bleed persist as well.

image

moving the window around, it's possible to get different objects to bleed, and even to get bleed on the left-hand side
image
image

Hopefully that will make it easier to diagnose

I can reproduce this issue in version 4.1.1 as well. However, I know how to fix it. Just shrink each direction of the source rectangle by 0.01 pixels in width and height during rendering. That is,
RenderRect = InflateRect(SourceRect, -0.01, -0.01)

Manually setting the Sprite2D can also fix this problem, but it doesn't work for AnimatedSprite2D since it only accepts integer rectangle coordinates.
fix

Using the latest build: Issue is still there. I fixed it by surrounding every sprite with transparency, resulting in a bigger file size but no bleeding anymore.

Dumb problems require dumb solutions I guess. Crazy for an engine like this that gets celebrated alot by the pixel art community.

image

miv391 commented

Tested with v4.2.dev5.official [e3e2528].

I added green lines to the left and bottom edge. So if everything would work as expected, you would never see white lines and always green lines at left and botton edges. This happens when the sprites are positioned at *.5 pixels. The sprites don't need to move.

kuva

Left and top edges start to bleed and bottom edge is cut. If the position is e.g. *.1, this doesn't happen.

As Calinou said, setting either "Snap 2d Transforms to Pixel" or "Snap 2D Vertices to Pixel" on seems to fix this.

It's actually very easy to stumble upon this bug:

  1. create new project
  2. add Sprite2D with icon.svg
  3. add code:
extends Sprite2D

func _process(delta: float) -> void:
	position += Vector2(5, 5) * delta

The icon moves smoothly except for the flickering edges. Editing the svg file and adding empty space around the icon removes the flickering.

It is unfortunate that this is probably one of the most common first Godot programs new Godot users create.

sepTN commented

So I just got hit by this weird bug where my slime showing sprite bleeding on the top of the image. So I just leave it at that because it was minor.

But today when I rearranged the slime in my room scene, I turned my grid snap on again (8px by 8px)
image

The bleeding is now gone, I'm not sure what happened.

This is possibly a related issue to #81998 where it seems to be bleeding part of the spritesheet itself despite being imported as individual frames.

Minoxs commented

As described in #81998, an AtlasTexture can be used to fix this issue without requiring modifying the spritesheet itself. If intended, it's not super intuitive and should be documented better, especially for anyone porting from v3.