Rotated pixels aren't sharp :(

Hello again :smile:

Iā€™m porting and expanding my simple pixel game made in XNA to MonoGame. Porting was fast and now Iā€™m adding new features.

The game is low res and is upscaled to screen size with resolution/matrix class I found online.
I draw textures with SamplerState.PointClamp. Game looks good up untill I wanted to try out rotating texturesā€¦ they are ugly when I upscale them :frowning:

If I play the game in real resolution without upscaling, it looks nice and oldschool.

Gif of rotating pixels in real resolution:

Gif on screen upscaled to 1920x1080:

As you can see the upscaled has rotated pixels instead of squares. How can I fix this? I tried googling and finding help but I didnā€™t find anything. :cry:

My current setup:
MonoGame 3.5 (I didnā€™t go with 3.6 yet :sweat:), Visual Studio 2015 Community, Windows 10, cross-platform template project.
I donā€™t use shaders because I have no experience and knowledge how they work or how to use them :joy:

Thank you :smiley_cat:

Can you post a link to the resolution/matrix class youā€™re using?

You work around this if you draw to a low res rendertarget and only upscale the final image

EDIT:
I understand you want to rotate the sprite, but want the pixels inside to stay unangled (horizontal alignment).
This is super trivial to do and the easiest solution is to upscale after drawing the whole image.
For that you can use rendertargets (if you need help let me know).

Otherwise you can use a custom shader that uses some form of quantization for the pixel shader texture read. (Again I could help you with that, but make sure solution one doesnā€™t work for you first). Thatā€™s not trivial to implement into the default spritebatch.draw() pipeline and youā€™d have to make some adjustments to either monogame itself or make a custom spritebatch implementation.

This should be it XNA 2D Independent Resolution Ā· GitHub
I have made few changes to it, like functions for my Camera system.

Yes I want to rotate the texture without having ā€œrotated lookā€ on the pixels.

About rendertargets, I have read about them but havenā€™t used them, because I read that they use lot of performance and memory(?). :confused:
If I use them, should I create new rendertarget for each frame? Or should I make one large rendertarget and clear it each frame before drawing new stuff on it?

Neither performance nor memory should be a concern if you use one rendertarget (or just a few)

You should create one rendertarget as a field somewhere

    private RenderTarget2D _renderTarget;

Then you need to initialize the rendertarget at the beginning of your game

public void Initialize(...)
{
...
 _renderTarget = new RenderTarget2D(graphicsDevice, width, height);
}

The width, height is what you want your ideal (low resolution) to be.

Then you render everything as usual, but tell the GPU to render to _renderTarget

_graphicsDevice.SetRenderTarget(_renderTarget)
...
render everything
...

done! Now render the result to the screen:

_graphicsDevice.SetRenderTarget(null); // Backbuffer

_spriteBatch.Begin();
_spriteBatch.Draw(_renderTarget, ... final size etc.)
_spriteBatch.End();

As you can see you can treat the rendertarget just like any other sprite/texture.

2 Likes

I got rendertargets work to a point.

For some reason rendertarget draws only top left corner of my game. and no matter what size the rendertarget is, there is just black after certain point. With smaller size the black begins earlierā€¦
And because it shows only the top left corner of game area (not the camera area), the game is unplayable because player cannot see :cry:

Maybe its just that current resolution independence and camera system arenā€™t suited for rendertargets :tired_face:

rendertargets work exactly the same way as your normal ā€œnon-rendertargetā€ state (backbuffer).

In fact, the backbuffer is just another rendertarget.

So the problem must be somewhere inside the code.

What is your screen resolution? You must draw the rendertarget to the complete window!

_spriteBatch.Begin();
_spriteBatch.Draw(_renderTarget, new Rectangle(0,0, WindowWidth, WindowHeight), Color.White);
_spriteBatch.End();

1 Like

Problem is not that the image/rendertarget is small compared to screen. Problem is that the image/rendertarget is literally just the corner of my game because when I render the game, rendertarget is at zero point.

Is it possible to set rendertargetā€™s position before drawing, so that currently visible area is rendered to it? That should fix my problem. :thinking: