Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to scale on-screen pixels?

Tags:

2d

xna

sprite

I have written a 2D Jump&Run Engine resulting in a 320x224 (320x240) image. To maintain the old school "pixely"-feel to it, I would like to scale the resulting image by 2 or 3 or 4, according to the resolution of the user.

I don't want to scale each and every sprite, but the resulting image!

Thanks in advance :)

like image 310
pumpy Avatar asked Jul 19 '10 17:07

pumpy


3 Answers

Bob's answer is correct about changing the filtering mode to TextureFilter.Point to keep things nice and pixelated.

But possibly a better method than scaling each sprite (as you'd also have to scale the position of each sprite) is to just pass a matrix to SpriteBatch.Begin, like so:

sb.Begin(/* first three parameters */, Matrix.CreateScale(4f));

That will give you the scaling you want without having to modify all your draw calls.

However it is worth noting that, if you use floating-point offsets in your game, you will end up with things not aligned to pixel boundaries after you scale up (with either method).

There are two solutions to this. The first is to have a function like this:

public static Vector2 Floor(Vector2 v)
{
    return new Vector2((float)Math.Floor(v.X), (float)Math.Floor(v.Y));
}

And then pass your position through that function every time you draw a sprite. Although this might not work if your sprites use any rotation or offsets. And again you'll be back to modifying every single draw call.

The "correct" way to do this, if you want a plain point-wise scale-up of your whole scene, is to draw your scene to a render target at the original size. And then draw your render target to screen, scaled up (with TextureFilter.Point).

The function you want to look at is GraphicsDevice.SetRenderTarget. This MSDN article might be worth reading. If you're on or moving to XNA 4.0, this might be worth reading.

I couldn't find a simpler XNA sample for this quickly, but the Bloom Postprocess sample uses a render target that it then applies a blur shader to. You could simply ignore the shader entirely and just do the scale-up.

like image 138
Andrew Russell Avatar answered Sep 20 '22 12:09

Andrew Russell


You could use a pixelation effect. Draw to a RenderTarget2D, then draw the result to the screen using a Pixel Shader. There's a tool called Shazzam Shader Editor that let's you try out pixel shaders and it includes one that does pixelation: http://shazzam-tool.com/

This may not be what you wanted, but it could be good for allowing a high-resolution mode and for having the same effect no matter what resolution was used... Before

After

like image 21
Jason Goemaat Avatar answered Sep 20 '22 12:09

Jason Goemaat


I'm not exactly sure what you mean by "resulting in ... an image" but if you mean your end result is a texture then you can draw that to the screen and set a scale:

spriteBatch.Draw(texture, position, source, color, rotation, origin, scale, effects, depth);

Just replace the scale with whatever number you want (2, 3, or 4). I do something similar but scale per sprite and not the resulting image. If you mean something else let me know and I'll try to help.

XNA defaults to anti-aliasing the scaled image. If you want to retain the pixelated goodness you'll need to draw in immediate sort mode and set some additional parameters:

spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None);
GraphicsDevice.SamplerStates[0].MagFilter = TextureFilter.Point;
GraphicsDevice.SamplerStates[0].MinFilter = TextureFilter.Point;
GraphicsDevice.SamplerStates[0].MipFilter = TextureFilter.Point;

It's either the Point or the None TextureFilter. I'm at work so I'm trying to remember off the top of my head. I'll confirm one way or the other later today.

like image 44
Bob Avatar answered Sep 22 '22 12:09

Bob