godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.16k stars 97 forks source link

Add padding to textures in SpriteFrames to avoid mipmap bleeding #7139

Open Warlord56x opened 1 year ago

Warlord56x commented 1 year ago

Describe the project you are working on

I work on a simple 2d platformer game pretty much like Celeste, we use a tilemap, a spritesheet and all the tiles are 8x8 pixel, and all the character and object animations are 8x8 pixel too and are in a seperate spritesheet.

Describe the problem or limitation you are having in your project

The tilemap works perfectly there is no bleeding at all, thanks to the "use_texture_padding" setting in the atlas import on the tilemap, now the problem is that there IS bleeding on the animated sprites since there is no such setting there and we are using a single spritesheet for all the objects and also the character animations.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

The feature is that, I would appreciate a texture padding option on the spriteframes resource or somewhere

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

The code for this should be in the atlas resource somewhere. The main idea is something like adding a 1 pixel padding to the new frame before it is added on the spriteframes resource.

If this enhancement will not be used often, can it be worked around with a few lines of script?

Well it could be worked around, like using more spritesheets for like all the objects and characters, but we wanted something more simple

Is there a reason why this should be core and not an add-on in the asset library?

I suppose it could be made possible with a gdextension plugin or something, but I'm not that familiar with gdextension, to be able to make it.

(It could be that I'm just using something very wrong.)

AThousandShips commented 1 year ago

The code for this should be in the atlas resource somewhere

Where do you mean? This doesn't really clarify how this should be solved

Warlord56x commented 1 year ago

Well since I'm not familiar with the source code of godot I don't know, all I know is that there is a "use_texture_padding" option in the tileset where you add a new "atlas" so I assumed it's some kind of atlas resource

AThousandShips commented 1 year ago

That is really different though

I understand that you might not be familiar with the source, but for proposals like this some basic idea of how to accomplish the new feature is required, might be enough for this time but keep this in mind for the future that if you don't have a more concrete idea it's best to open a discussion

Warlord56x commented 1 year ago

Well I added an implementation Idea, and I admit that it was a mistake on my part not to provide it

AThousandShips commented 1 year ago

Now I'm not sure if you're just experienced a bug but there's no padding needed for sprite frames, each frame is a separate texture, and can't see anywhere internally where it puts them in any sheet

Edit: when created from the editor it uses an atlas texture, my bad

As a workaround you can split it into separate textures, or apply padding, can be done with a script as well, though there's also considerations of compression and other facts that makes using the original texture preferable

Warlord56x commented 1 year ago

Yes, that is my concern, but I suppose I will split them into separate textures until I figure something out, but I suppose it is my fault for using 8*8 pixels for each character/animation/object, thank you for answering though.

AThousandShips commented 1 year ago

Can see if I can work out a little example for a workaround in script, but can see about future improvements, but it takes some more complicated changes to the editor (as it's not a matter of the resource but about the editor generating it)

Warlord56x commented 1 year ago

I really appreciate it. Thanks for the help.

AThousandShips commented 1 year ago

Also you can use the padding system already in the SpriteFrames editor if you edit your files externally to have padding, I can also provide a simple script to add padding to any file given a frame range, will do so soon, then you won't have to worry about compression

Warlord56x commented 1 year ago

I could really use that, thank you, but I don't have the project on hand right now, so I won't be able to try it until the weekend.

AThousandShips commented 1 year ago

Just quickly thrown together but should do the job, you might need to tweak the specifics for file formats and such, but this, together with setting separation to 2 in each direction and offset to 1 should do the trick:

@tool
extends EditorScript

func _run():
    # Substitute with your desired tile size.
    var tile_size := Vector2i(16, 16)
    var tile_size_padded := tile_size + Vector2i(2, 2)
    # Substitute with your texture.
    var img_in = load("input").get_image()
    var size = Vector2i(img_in.get_width() / tile_size.x, img_in.get_height() / tile_size.y)
    var img_out := Image.create(size.x * tile_size_padded.x, size.y * tile_size_padded.y, false, img_in.get_format())
    for y in size.y:
        for x in size.x:
            # Blit top left corner.
            img_out.blit_rect(img_in, Rect2i(Vector2i(x, y) * tile_size, Vector2i(1, 1)), 
                Vector2i(x, y) * tile_size_padded)
            # Blit top right corner.
            img_out.blit_rect(img_in, Rect2i(Vector2i(x + 1, y) * tile_size - Vector2i(1, 0), Vector2i(1, 1)), 
                Vector2i(x + 1, y) * tile_size_padded - Vector2i(1, 0))
            # Blit bottom left corner.
            img_out.blit_rect(img_in, Rect2i(Vector2i(x, y + 1) * tile_size - Vector2i(0, 1), Vector2i(1, 1)), 
                Vector2i(x, y + 1) * tile_size_padded - Vector2i(0, 1))
            # Blit bottom right corner.
            img_out.blit_rect(img_in, Rect2i(Vector2i(x + 1, y + 1) * tile_size - Vector2i(1, 1), Vector2i(1, 1)), 
                Vector2i(x + 1, y + 1) * tile_size_padded - Vector2i(1, 1))
            # Blit top row above original.
            img_out.blit_rect(img_in, Rect2i(Vector2i(x, y) * tile_size, Vector2i(tile_size.x, 1)), 
                Vector2i(x, y) * tile_size_padded + Vector2i(1, 0))
            # Blit bottom row below original.
            img_out.blit_rect(img_in, Rect2i(Vector2i(x, y + 1) * tile_size - Vector2i(0, 1), Vector2i(tile_size.x, 1)), 
                Vector2i(x, y + 1) * tile_size_padded + Vector2i(1, -1))
            # Blit left column left of original.
            img_out.blit_rect(img_in, Rect2i(Vector2i(x, y) * tile_size, Vector2i(1, tile_size.y)), 
                Vector2i(x, y) * tile_size_padded + Vector2i(0, 1))
            # Blit right column right of original.
            img_out.blit_rect(img_in, Rect2i(Vector2i(x + 1, y) * tile_size - Vector2i(1, 0), Vector2i(1, tile_size.y)), 
                Vector2i(x + 1, y) * tile_size_padded + Vector2i(-1, 1))
            img_out.blit_rect(img_in, Rect2i(Vector2i(x, y) * tile_size, tile_size), 
                Vector2i(x, y) * tile_size_padded + Vector2i(1, 1))
    # Substitute with your output file of choice.
    img_out.save_png("output")

One idea would be to have an import setting for image files to import with padding like this, would speed up a lot of things I imagine

KoBeWi commented 1 year ago

You can modify spritesheet padding using my addon: https://github.com/KoBeWi/Godot-Spritesheet-Generator (check the stand-alone version)