Sub-pixel rounding rendering problem

Hello,

Yes, it’s another post about sub-pixel rendering! Whilst there are many similar questions to mine out there, the solutions are simply not adequate for what I’m trying to do. I am not rounding any of my sprites, or camera, to ints. Whilst my game is a low resolution (320x180), I choose to do this because should I apply a zoom matrix to the game, I don’t want the sprites to be locked to this new larger pixel grid, but rather be still be locked to the 320x180 pixel grid. This means that they will be at ‘sub-pixel’ increments with respect to the new larger pixels, but they are still rendering at the game resolution. Rounding sprites and the camera to ints force them to snap to the larger pixel grid, which I don’t want. This causes problems, however, when the camera is at increments of 0.5, I assume this is because the rasterizer has to ‘guess’ which pixel to snap everything to. When the camera is at these increments, pixel artefacts appear around tiles and some sprites appear distorted. What are my options to combat this? The only solution I’ve found online is to round to integers, which as I have already mentioned, is not desirable.

Thanks for the help

You mean, you run your game in native 320x180 resolution? Then you can’t do much, as a pixel in the backbuffer is a pixel in the backbuffer - the PixelShader wil either output this or that pixel, there is no inbetween.

As far as I understand you do this for optical reasons? Why not run a regular resolution and use a shader to achieve a 320x180 look? So use quads instead of pixels and you can zoom/rotate/move without any snapping at all. I guess you could even do it with normal Spritebatch and just use pixel snapping/quantizing on the texture sampling

I did a prototype a while ago where I wanted pixel like graphics, but higher resolution. The main driver for this was so that I could rotate the sprites cleanly, but maintain the pixel like look.

You can see what that looks like here in a video I posted…

(Yikes, three years ago and my last update on the channel. Oh man…)

Anyway, to achieve this, I rendered at 1920x1080 resolution and took my low res sprites and scaled them up by a factor of 3. I just wrote a little utility method to do this…

private Texture2D CreateScaledTexture(Texture2D sourceTexture, Vector2 scale, GraphicsDevice device, SpriteBatch spriteBatch)
{
	RenderTarget2D target = new RenderTarget2D(device, (int)(sourceTexture.Width * scale.X), (int)(sourceTexture.Height * scale.Y));
	device.SetRenderTarget(target);
	device.Clear(Color.Transparent);
	spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
	spriteBatch.Draw(sourceTexture, new Rectangle(0, 0, target.Width, target.Height), Color.White);
	spriteBatch.End();
	device.SetRenderTarget(null);

	Color[] data = new Color[target.Width * target.Height];
	target.GetData<Color>(data);

	Texture2D scaledTexture = new Texture2D(device, target.Width, target.Height);
	scaledTexture.SetData<Color>(data);

	return scaledTexture;
}

Now that my sprites had more pixel data, I drew them with SamplerState.AnisotropicClamp and when I rotated them they were able to maintain that pixelated look but not get that weird pixel rotation artifacts.

1 Like