Skip to content
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

All textures within a spritelist are drawn blurry when scaled, expect for one #275

Closed
Awlexus opened this issue Oct 25, 2018 · 12 comments
Closed

Comments

@Awlexus
Copy link

Awlexus commented Oct 25, 2018

Bug Report

I load a list sprites from a tileset and then add them to a spritelist. When I increase the scale for these images over 1, they get drawn blurry except for one.

arcade version: 1.3.6

Actual behavior:

Notice how only the right tire is drawn sharp
What it looks like

Expected behavior:

They should the same as this screenshot taken from the Tiled
image

Steps to reproduce/example code:

How I load the texture
def get_tileset_texture(self, tileset_name: str, gid: int, scale: float = 1) -> arcade.Texture:
    """ Fetches a texture from a tileset """
    tileset = self.tilesets[tileset_name]
    return arcade.load_texture(
        file_name=os.path.join(ASSETS_PATH, tileset["image"]),
        x=(gid % tileset["columns"]) * (tileset["tilewidth"] + tileset["spacing"]),
        y=(gid // tileset["columns"]) * (tileset["tileheight"] + tileset["spacing"]),
        width=tileset["tilewidth"],
        height=tileset["tileheight"],
        scale=scale)
How I add them to the list
sprite = arcade.Sprite(center_x=xpos, center_y=-ypos, image_width=texture.width * scale,
                                    image_height=texture.height * scale, scale=scale)

sprite.append_texture(texture)
sprite.set_texture(0)
sprites.append(sprite)
@pvcraven
Copy link
Member

Hard to tell without a full working example.

I would guess it is blurry because the pixels are not landing directly on the boundaries. That is, a pixel drawn at an x, y of (0.5, 0.5) will be blurry.

It is easiest to get pixels to line up if sprites are sized in powers of 2 (16, 32, 64, 128, etc.)

Can you check this? Or post GitHub or small working example?

@ByteCommander
Copy link

@pvcraven Thanks for your response, we are working together on this project here: https://gitlab.com/ByteCommander/code-jam-3/tree/assets - that branch should have the exact display as in the screenshots, though we see this blurring in all places where there are multiple sprites with the same texture. One instance of the texture is always sharp, all others blurry.

@ByteCommander
Copy link

ByteCommander commented Oct 28, 2018

I found a workaround:

If we change the texture magnification filter from NEAREST to LINEAR in the load_textures and load_texture function, there will be no smoothing/blurring/interpolation and we get nice sharp pixel art:

arcade/draw_commands.py#216 and arcade/draw_commands.py#333:

    gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER,
                       gl.GL_NEAREST)

For now, we have to copy, change and monkeypatch the whole function in order to change this behaviour, which is not really cool. It would be great if you could add an optional keyword argument to load_texture like smooth=True, which could be used to switch between LINEAR/smooth and NEAREST/sharp scaling for each texture.

@pvcraven
Copy link
Member

image

Is this what it looks like for you? I'm not seeing the blurring on this image. What platform are you on?

I can look at a 1.3.7 release to fix.

@pvcraven
Copy link
Member

Ok, nevermind. I removed the monkey-patch

@pvcraven
Copy link
Member

Try version the new 1.3.7 version of Arcade and see if it works better for you.

@ByteCommander
Copy link

Wow, thank you. That was quick.
Yes, with the update to 1.3.7 and the monkeypatch code removed, our pixel art looks nice and sharp, as wanted.
I just fear that other people who have "real" art could probably have rather benefited from the smooth scaling, which was why I suggested making this configurable. I don't know, for our project it's cool now, so thanks again.

@israel-dryer
Copy link

israel-dryer commented Jan 2, 2020

I'm having this issue as well with 2.2.1, but only when scaled above 1:

LEFT IMAGE scaled with arcade.Sprite('Images/canon.png', scale=3); however, also tried arcade.load_texture(file_name='./Images/canon.png', scale=3) with the same result.

RIGHT IMAGE scaled directly with PIL

image

example code

import arcade

GAME_SCALING = 3

class TestWindow(arcade.Window):
    
    def __init__(self, width=300, height=100, title='Image Scaling'):
        super().__init__(width, height, title)
        
        # setup sprites
        self.sprite_list = None
        self.sprite_arcade_scaled = None
        self.sprite_PIL_scaled = None

        arcade.set_background_color(arcade.color.BLACK_BEAN)

        self.setup()

    def setup(self):
        """ Setup game sprites """
        self.sprite_list = arcade.SpriteList()

        self.sprite_arcade_scaled = arcade.Sprite('Images/canon.png', scale=3)
        self.sprite_arcade_scaled.position = (50, 50)

        self.sprite_PIL_scaled = arcade.Sprite('Images/canon2.png')
        self.sprite_PIL_scaled.position = (100, 50)

        self.sprite_list.append(self.sprite_arcade_scaled)
        self.sprite_list.append(self.sprite_PIL_scaled)

    def on_draw(self):
        """Draw sprites to screen """
        arcade.start_render()
        self.sprite_list.draw()


TestWindow()
arcade.run()

canon

@pvcraven
Copy link
Member

pvcraven commented Jan 4, 2020

Make sure the image's boundaries rest exactly on pixel boundaries. If a sprite isn't pixel-perfect it will blur. You might try scaling with 4, which would increase the likelyhood you are on boundaries?

@leonardoobaptistaa
Copy link

leonardoobaptistaa commented May 3, 2022

EDIT: Don't use this, use the comment below ( self.scene.draw(pixelated=True) )

ORIGINAL:
for future references
if you have the same problem with pixel art games, the scene's object draw method now accepts a filter param, like:

import pyglet.gl as gl
self.scene.draw(filter = gl.GL_NEAREST)

@einarf
Copy link
Member

einarf commented May 3, 2022

It should be enough to pass pixelated=True

@leonardoobaptistaa
Copy link

thanks for that, way better API

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants