Pixel art looks bad when it's rendered in my engine

Started by
7 comments, last by FantasyVII 5 years, 1 month ago

Hi everyone,

When I render a sprite in my engine which is using OpenGL 4.5, the pixel art looks different from what it is supposed to.

Here is an image of how the art should look like vs how it looks like in my engine.

The image on left is how the grass tile should look like.

The image on the right is how my engine renders it.

hmm.thumb.png.8ea25b11a9652f5ad08b84fad0dee493.png

You can see the difference on the edge of the tile. The line is not quite straight.

I'm using an orthographic matrix and the image position is at the origin (0, 0) which in my engine is in the middle of the screen.

 

Anyone know what is causing this and how to fix it?

Cheers!

 

Advertisement

First thing I noticed is that the left image is taller than the right image.  This probably means that there's an error in your projection matrix.  Wild guess, but are you running in a window, and using the full dimensions of that window (as opposed to the client area of the window) to set up your projection matrix?

The second thing I noticed is that neither half of the image is clean pixel art.  The image itself appears to be a png, but I'm seeing what can only be described as jpeg artefacts in the image.  Was it like that when you uploaded it?  When you ran the screen capture?  In the source image?

 

42 minutes ago, a light breeze said:

First thing I noticed is that the left image is taller than the right image.  This probably means that there's an error in your projection matrix.  Wild guess, but are you running in a window, and using the full dimensions of that window (as opposed to the client area of the window) to set up your projection matrix?

The second thing I noticed is that neither half of the image is clean pixel art.  The image itself appears to be a png, but I'm seeing what can only be described as jpeg artefacts in the image.  Was it like that when you uploaded it?  When you ran the screen capture?  In the source image?

Apologies for the bad image. Both tiles have different zoom level which I messed up in paint. Then I saved the image in jpg format then png which created these artifacts. My apologies.

Here is a better image and I will also include a screenshot of my window and original tile.

 

The projection matrix uses the correct client area size as opposed to the window size.

 

 

 

better.png

og.png

grass.png

ok, here is some progress. By moving the sprite 0.5f units down the issue is kind of fixed? but not really?

new.thumb.png.1eb5a0cb189831a599055fba0b00adbf.png

notice how the top green pixel is now at the bottom.

left sprite is the original sprite. Right sprite is the one the engine is rendering.

I'm reading about pixel perfect rendering and how in OpenGL (0, 0) is the center of a pixel not the top left of the pixel. So I have to add 0.5 to something? I don't know for sure... I'm still researching this. Any thoughts are much appreciated.

Ok, more progress. I added one extra transparent pixel at the top and bottom of the grass tile. This solved the issue. looks like OpenGL was sampling the pixel from the top to bottom? if that makes any sense.

 

I don't know if this is a good solution. Does anyone know why this happens? Any thoughts?

 

[Edit]

more updates. If I set my window client rendering area resolution to 1280, 720 (the window size is actually 1296, 759 with borders) everything is rendered perfectly. If I make the client rendering area to 1920, 1080 (the window size is actually 1936, 1119 with borders) everything looks messed up.

ugh... this is frustrating... It's 12:32 am... it's late. I'm going to bed. I will continue this tomorrow.

 

1280, 720 image

Good.thumb.png.1bc2b626146d567f2eab7ca0b069cff0.png

 

1920, 1080 image

bad.thumb.png.d8f266762477d0dc73987199ea99d4cf.png

Are you sampling the texture in repeat mode? Try clamp to edge!

Might also still be a minor problem with texture coordinates.

Clearly either your texture coordinates or your vertex coordinates are wrong (after transformation).  Could be a problem with your projection matrix, could be an off-by-one error, could be the result of inexact floating point operations, could be something else that I haven't considered.  I can't see from the results which one of these it is.  Things to try:

  • Print out your vertex coordinates, both before and after projection.  (Your vertex coordinates should map to perfect integer screen coordinates.)
  • Print out your texture coordinates.  (Your texture coordinates should map to perfect integer texel coordinates.  The width and height of your image on the screen in pixels should be the same as or a multiple of the size of your image on the texture in texels).
  • Replace your texture with a black-and-white checkerboard where each square is 2×2 pixels.  (This will make it easier to see where the rendering error appears, including any patterns.)

Thank you guys so much.

There were two issues.

1- I was dividing my vertex by two to get the center point and center the quad in the middle of the screen. So if I had a 10x10 pixel sprite, I would divide x,y components by 2 two get the center point which is 5,5 to center it in the middle of the screen. So my vertices would be as follow

*note, the postive y-axis is up for me. not down.

 


Top left vertex of the quad = -5, 5
Top right vertex of the quad = 5, 5
Bottom right vertex of the quad = 5, -5
Bottom left vertex of the quad = -5, -5

 

so that is perfect. However, if my sprite had an odd number like 11x10 pixels, 11/2 = 5.5. Cast that to an int you will get 5. So my vertex would still be as above even though my sprite is 11x10 which means I'm missing a pixel.

So I fixed that. The issue was almost solved.

 

The next thing is that if I had an odd resolution like 1920x1081, the same thing would happen. The issue was I would take my resolution and again divide it by two. so my ortho matrix would be

 


int left = -(Engine::GetWindow().GetClientSize().x / 2);
int right = Engine::GetWindow().GetClientSize().x / 2;
int top = Engine::GetWindow().GetClientSize().y / 2;
int bottom = -(Engine::GetWindow().GetClientSize().y / 2);

Camera* camera = (Camera*)CameraGameObject->AddComponent(new Camera(Matrix4::Orthographic(left, right, top, bottom, -1.0f, 1.0f)));

 

again, after fixing that to account for the odd resolutions, my issue is now completely fixed. I have also checked my texture coordinates and that was mapped perfectly between 0 and 1.

 

So, thank you guys, that was very helpful !

 

Cheers !!!

This topic is closed to new replies.

Advertisement