Attempt to fix sprite sheet pixel bleeding in OpenGL 2D causing sprite distortion

While working on a project, I encountered the common problem of pixel bleeding when trying to draw subregions of my sprite sheet. This caused sort of "seams" to appear at the edges of my sprites. You can see the issue here, on the right and top of the sprite .

Doing some searching, I found others with a similar problem, and a suggested solution (here, and here for example) was to offset my texture coordinates by a bit, such as 0.5. I tried this, and it seemed to work. But I have noticed that sometimes, depending on where the sprite or camera is, I get a bit of distortion on the sprites. Here, the left side appears to be cut off, and here, the bottom seems to have expanded. (I should note, the distortion happens on all sides, I just happened to take screenshots of it happening on the bottom and left.) It may be a little difficult to see in screenshots, but it is definitely noticeable in motion. For reference, here is the part of the sprite sheet that is being displayed here

Does anybody have any idea what is going on here? I didn’t actually notice this issue until recently. I originally set out to resolve the pixel bleeding when I saw it occurring between my tile sprites. This new issue does not occur with them using my current half-pixel offset solution (or if it does, it’s not noticeable).

Code:

Texture parameters

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 

Texture coordinate calculation

std::vector<glm::vec4> Texture2D::GetUVs(int w, int h) { std::vector<glm::vec4> uvs; int rows = Width/ w; int columns = Height / h;  for(int c = 0; c < columns; c ++) {     for(int i = 0; i < rows; i ++)     {         float offset = 0.5;         uvs.emplace_back(glm::vec4(float(((i) * w + offset))/Width,                               float(((1 + i) * w - offset))/Width,                               float(((c) * h + offset))/Height,                               float(((1 + c) * h - offset))/Height));     } } return uvs; 

Where Width and Height are the dimensions of the sprite sheet, and w and h are the dimensions of the subregion, in this case 32 and 32.

How I pass the uvs to the shader

GLfloat verticies[] = {     uv.x, uv.w,     uv.y, uv.z,     uv.x, uv.z,      uv.x, uv.w,     uv.y, uv.w,     uv.y, uv.z };  this->shader.Use().SetVector2fv("uvs", 12, verticies); 

Where uv is the uv at an index in the uvs vector that was returned above in the GetUVs function.

Vertex shader

#version 330 core layout (location = 0) in vec2 vertex;   out vec2 TextureCoordinates;  uniform vec2 uvs[6]; uniform mat4 model; uniform mat4 projection;  void main() {     const vec2 position [6] = vec2[]     (         vec2(0.0f, 1.0f),         vec2(1.0f, 0.0f),         vec2(0.0f, 0.0f),          vec2(0.0f, 1.0f),         vec2(1.0f, 1.0f),         vec2(1.0f, 0.0f)     );     TextureCoordinates = uvs[gl_VertexID];    gl_Position = projection * model * vec4(position[gl_VertexID], 0.0, 1.0); } 

Fragment shader

#version 330 core in vec2 TextureCoordinates; out vec4 color;  uniform sampler2D image; uniform vec4 spriteColor;  void main() {         color = vec4(spriteColor) * texture(image, TextureCoordinates); }   

Thanks for reading. I have asked this question a few places and not gotten any response, so any help is greatly appreciated.

Sprite Distortion (Ghosting While Moving and Artifacts when Mirroring to External Display)

I am working on my first MonoGame project. I love the framework so far!

I have implemented my own letterbox/pillarboxing to scale my native resolution by the maximum integer scale allowable on my display. Basically, I determine the maximum integer scale, set my PreferredBackBuffer to the screen resolution, create a Viewport that is my native resolution * maximum scale, and then set my SpriteBatch to draw everything at Matrix.CreateScale(max_scale).

This works much better than rendering to a texture that has my native resolution and then scaling it up. (Scaling using a Matrix in SpriteBatch, as opposed to just rendering to a texture and then scaling it up, allows you to fake “subpixel rendering” to some extent).

That said, I am facing two issues.

  1. When my sprite moves, there is very subtle “ghosting” happening. The sprite is subtly blurry and there’s a faint ghostly trail behind it.

  2. When I mirror to an external monitor, there is less ghosting, but there is ugly artifacting on the outside of sprite when stationary. See below.

enter image description here

Rounding my player’s position to integers in the Draw() command doesn’t help for either problem.

Does anyone have any thoughts about how to fix these issues?

Here is my game class:

using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input;  namespace MyMonoGame {     public class MyGame : Game     {         // declare variables         GraphicsDeviceManager graphics;         SpriteBatch sprite_batch;          // resolution management         int native_width;         int native_height;         int screen_width;         int screen_height;         int max_scale;         int horizontal_margin;         int vertical_margin;          // objects         Player player;          public MyGame()         {             // create GraphicsDeviceManager instance             graphics = new GraphicsDeviceManager(this);             // specify root directory             Content.RootDirectory = "Content";         }          protected override void Initialize()         {             // set window title             this.Window.Title = "My Game";              // create SpriteBatch instance, which can be used to draw textures.             sprite_batch = new SpriteBatch(GraphicsDevice);              // initialize some variables             native_width = 160;             native_height = 144;              // resolution management             // get screen size             screen_width = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;             screen_height = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;             // get max_scale, the maximum integer scale that will fit on the screen             // note: must be integer to prevent pixel distortion             int width_divisor = (int) Math.Floor((float)screen_width/(float)native_width);             int height_divisor = (int) Math.Floor((float)screen_height/(float)native_height);             max_scale = Math.Min(width_divisor, height_divisor);             // get margins for letterboxing and pillarboxing             int max_width = native_width * max_scale;             int max_height = native_height * max_scale;             horizontal_margin = (int)((screen_width - max_width)/2f);             vertical_margin = (int)((screen_height - max_height)/2f);              // toggle fullscreen             graphics.PreferredBackBufferWidth = screen_width;             graphics.PreferredBackBufferHeight = screen_height;             graphics.ToggleFullScreen();             GraphicsDevice.Viewport = new Viewport(horizontal_margin, vertical_margin, native_width * max_scale, native_height * max_scale);             graphics.ApplyChanges();              // objects             player = new Player(this);         }          protected override void LoadContent()         {         }          protected override void UnloadContent()         {         }          protected override void Update(GameTime gameTime)         {             if (Keyboard.GetState().IsKeyDown(Keys.Escape))                 Exit();              // update objects             player.Update(gameTime);         }          protected override void Draw(GameTime gameTime)         {             // clear window & fill with solid color             GraphicsDevice.Clear(Color.DarkRed);              // draw objects             var transform_matrix = Matrix.CreateScale(max_scale);             sprite_batch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, DepthStencilState.None, RasterizerState.CullCounterClockwise, transformMatrix: transform_matrix);             player.Draw(sprite_batch);             sprite_batch.End();         }     } } 

The screen will cause Z distortion after rotating

After screen rotation, the screen display will cause Z distortion when playing video or quickly switching photos.

We tried several monitors. ENVIRONMENT: Display = HDMI/DP Resolution = 1920x1080p / 1920×1920 OS = Ubuntu 18.04, Kernel 4.18.20 Platform: Intel Apollo Lake N4200

STEP: 1. System boot up 2. Rotation display to left/right/inverted 3. Play video

rotate to the right, Z distortion happen

$ xrandr -o right

rotate to the upside down, Z distortion happen

$ xrandr -o inverted

rotate to the left, Z distortion happen

$ xrandr -o left

rotate to the normal

$ xrandr -o normal

RESULT: screen will cause Z distortion. see the recording video below: https://drive.google.com/drive/folders/15oDuXqsMn8Q-39K8StbfkuBeL_CWF584?usp=sharing

Can I pay with cash at Copenhagen Distortion music festival?

I was at Roskilde festival. They had an agreement with banking industry and would not accept cash. It was mandatory to use credit card.

Soon I will visit Copenhagen Distortion and wonder if I can pay with cash (or other anonymous/pseudonymous payment method). I feel privacy wise uncomfortable to use credit card.

I found only

They absolutely hate it when I pay with cash. Everybody uses credit. Even the street meat guy takes credit card or mobile pay.

Is a ticket, in addition to Gadearmbånd, recommended for Copenhagen Distortion music festival?

For the Copenhagen Distortion music festival, on cphdistortion.dk they list various tickets. It looks like the only I need to get is Gadearmbånd.

Quote from visitcopenhagen:

The legendary street raves are financed by the thousands of guests who buy the “Gadearmbånd” so Distortion can clean up the streets when the incomparable music and street rave labyrinth ends. Distortion Ø and Distortion Club are ticketed events and the Distortion Pass will get you access to all the music-mayhem.

Can anybody tell me what I will get with Distortion Ø? Do most people buy it? What is the benefit? Can I also buy local when I am there?

What causes barrel distortion?

Here are some scenarios for barrel distortion:

  • When a target is too close to a camera, the photo will show barrel distortion.

  • My flip cell phone’s camera often produces barrel distortion.

  • Some lenses are intended to produce barrel distortion, such as wide angle lenses

What make a lens produce barrel distortion?

Why is there barrel distortion in the above cases?

Does barrel distortion have anything to do with whether the subject is focused or not? (If the target is too close to the lens, it may not be possible to move the sensor for its image to be focused due to the limit size of the camera.)

Ubuntu Audio Static Distortion [Intel 82801AA-ICH]

Ubuntu Audio Static Distortion [Intel 82801AA-ICH]

Audio: After a few minutes the audio output becomes static distorted, (System Wide with all Audio Applications VLC etc. But especially noticeable with YouTube’s Audio/Video playback), sounding as though something is causing it to be overdriven into what is called ‘Clipping’, (But even at low volume levels). If I click on the Volume Icon on the top right of the Ubuntu screen, and then click on the ‘Sound Settings’ item of that drop down menu below the Volume Slider, Opening the Sound Settings GUI, this seems to Temporarily resolve the Static as though doing this is resetting whatever is causing the Issue. In some instances, Muting and then unmuting the audio first, helps to ‘reset’ when opening the ‘Sound Settings’ GUI. But every few minutes the Issue returns. Forcing me to have to manually use the Drop down menu approach to clear up the distorted audio each and every time. Attempting to change levels and setting of alsamixer has no real effect on this issue, alsamixer has no ‘automute’ option in this instance. But opening the default Pulse Audio ‘Sound Settings’ GUI does. Whether the allow louder than 100 percent Check Box is unchecked or checked makes no difference in this behavior. However, this clearly indicates that the errant behavior is something associated with Pulse Audio.

32 Bit Ubuntu 16.04LTS Guest In VirtualBox 64 Bit Windows 10 Host (Windows Audio Drivers are NOT the issue). Motherboard: ASRock B250M Pro4-1B Rev 1.04

Result of: aplay -l **** List of PLAYBACK Hardware Devices **** card 0: I82801AAICH [Intel 82801AA-ICH], device 0: Intel ICH [Intel 82801AA-ICH] Subdevices: 0/1 Subdevice #0: subdevice #0

I attempted this “fix” ..In Terminal: sudo gedit /etc/pulse/default.pa and adding tsched=0 to load-module module-udev-detect so it becomes load-module module-udev-detect tsched=0 Save and Exit default.pa ..Pulse Audio can then be restarted in Terminal by: pulseaudio -k ..Doing this Did NOT solve the issue for me.

Next I attempted this “fix”: …edit /etc/pulse/daemon.conf sudo -H gedit /etc/pulse/daemon.conf ..Find the line ; resample-method = speex-float-1 uncomment (remove the 😉 and change to resample-method = src-sinc-best-quality ..Next: ; default-sample-rate = 44100 Should become: ; default-sample-rate = 48000 If the lines are not there at all, then add them. Reboot for changes to take effect.

I merely added the Uncommented Lines Below the ;Commented one’s, (to make undoing whatever doesn’t work easier).. ; resample-method = speex-float-1 resample-method = src-sinc-best-quality ; default-sample-rate = 44100 default-sample-rate = 48000 Then Rebooted for changes to take effect. ..Also Doing this Did NOT solve the issue for me.

So what is the Specific “Fix” that will actually work in this instance?