Screen tearing with non-int zoom levels and spritesheets

I am experiencing screen tearing when I use a zoom that isn’t an integer value along with drawing using spritesheets.

        public Matrix GetTransformation(GraphicsDevice graphicsDevice)
        {
            this.TransformMatrix = Matrix.CreateTranslation(new Vector3((int)-this.DrawPosition.X, (int)-this.DrawPosition.Y, 0)) *
                                         Matrix.CreateRotationZ(Rotation) *
                                         Matrix.CreateScale(Zoom) *
                                         Matrix.CreateTranslation(new Vector3(ViewportWidth * 0.5f, ViewportHeight * 0.5f, 0));

            return TransformMatrix;
        }

This gets added as the matrix in a spritebatch.begin call. I also am setting SamplerState.PointClamp.


            Program.SpriteBatch.Begin(SpriteSortMode.Deferred,
                BlendState.AlphaBlend,
                SamplerState.PointClamp,
                null,
                null,
                null,
                currentCamera.GetTransformation(graphicsDevice));

Any ideas how I can resolve screen tearing? Most examples I see say to use PointClamp which isn’t helping here or say to use an INT value for camera or zoom values, which I am using for position but I can’t use for zoom because I want non-int zoom values.

I’m using 0.5f increments to zoom in/out and I don’t experience any tearing with the below code:

public Matrix WorldTranformMatrix
        {
            get
            {
                return Matrix.CreateTranslation(new Vector3(-new Vector2(position.X * scrollSpeedModifier, position.Y), 0f)) *
                       Matrix.CreateTranslation(new Vector3(-origin, 0f)) *
                       Matrix.CreateRotationZ(rotation) *
                       Matrix.CreateScale(zoom, zoom, 1f) *
                       Matrix.CreateTranslation(new Vector3(origin, 0f));
            }
        }

You can check the whole code here

Yeah there seem to be specific zoom levels where there isn’t tearing but I’m looking to zoom smoothly using smaller increments like .1f unfortunately. I think I need a fix that works for any zoom amount :frowning:

Actually, my zoom uses linear interpolation, which results in a butter-smooth zooming I have no tearing whatsoever. Feel free to download the code and run the game, you can use the mouse wheel to zoom in and out and you can check the corresponding code. I use 0.5 zoom increments, but the in between values are calculated with linear interpolation and they are not nice numbers :slight_smile:

Screen tearing is an issue that occurs when the video frame buffer is changed when the monitor is in the middle of its refresh cycle, and it’s fixed by V-sync and/or adaptive sync. Since you’re talking about an issue that happens with non-integer scaling values and Point sampler states, I assume the problem you’re encountering is pixel distortion.

Pixel distortion is the result of non-integer point-sample scaling. Some pixels end up looking wider/taller than others, and the end result is a bit wonky. If you don’t want pixel distortion, you have to use non-point sampling, like linear or anisotropic. But with non-point sampling, you get some blurriness instead at scales higher than 1.

If you don’t want blurriness and you don’t want pixel distortion, then you have to use integer values to scale and use point sampling. If you can’t limit scaling to integer values, then you have to decide between blurriness and pixel distortion. With modern display technology, there’s no way around it.

1 Like

image

Sorry if I’m using the wrong terms… this is a screen shot of this happening. The tiles are 64x64 exact pixels and the zoom is 1.5f.

The tiles should be 96x96 at this zoom level (64 * 1.5) but they are drawing as 95x96 instead, which is leading to this weird spacing issue which I perhaps was wrongly calling screen tearing.

Its not always there… as you move and the camera position or zoom change, the spacing issues sometimes go away.

I used the same tiles before as individual textures and didn’t have this problem. This problem has only started since I moved all the individual tiles to sprite sheets and started using the SpriteBatch.Draw() command with the SourceRectangle overload.

This is a common problem with spritebatch.

A fix is to pad your textures on your texture sheet by 1 pixel on the outside of each texture using the edge pixel of that texture

The pixel on the outside of your texture is bleeding through when your drawing with non whole numbers (which happens when you zoom not using whole numbers)

Ive never had much luck using pointclamp

I’d read some posts about that and was afraid I may have to revert to that.

This does resolve it. Thanks!