MonoGame.Extended
MonoGame.Extended copied to clipboard
[Tiled] TiledMapRenderer draws distorted tiles when scaled
This is a screenshot from a monogame project, scaled to 12x resolution, using an OrthographicCamera with a ScalingViewport from Monogame Extended.
The old man is a Texture2D, drawn with a normal spritebatch, he has perfect upscaling.
The tiles are rendered with TiledMapRenderer, using tiledMapRenderer.Draw(camera.GetViewMatrix());
.
Here we can see many distorted pixels in both axes. Most notably is the top row and the leftmost colum of pixels. The tile to the right is flipped vertically in Tiled map editor. The distorted top row of pixels is kept, even if tile is flipped.
Edit: Here is my correctly drawn tileset drawn with a transparent purple, on top of the distorted tile.
You can use a render target to fix the problem.
- Render your scene into a render target.
- Upscale the render target as you wish.
Thanks. It draws fine at 1x scaling, so that should work. Will implement it later.
Edit: I made it work, but it wasn't really straight forward. So I think it would still be nice if this was possible to fix. Had to do this:
- Create map render target and set its size to game size * 1 / minimum camera zoom
- Translate the map to negative position of camera top left corner.
- Draw map to its custom render target, with some steps to draw transparent ( or parallax layers behind will not show).
- Change back to normal render target.
- Draw map in the default render target, offset to camera top left corner.
Edit: my solution does not work well with camera rotations.
All this compared to one line:
tiledMapRenderer.Draw(camera.GetViewMatrix());
Usually you want to use a render target to upscale to a specific resolution anyways regardless of using tiled maps or not. Perhaps there is room to think about an abstraction to do this for you but it is bleeding into the engine territory.
I will revisit how to make it easier to create a render pass for a 1x scale and upscaling it to the desired resolution with letter-boxing or pillar-boxing. This might be just creating better documentation or introducing code.
@fossegutten Could you explain more why this doesn't work well camera rotations?
I'm not sure what my problem was, but I think it was that the render target was too small when it was rotated, so I had to scale it to twice the size (there is probably a better way to do it than to multiply with 2, as it depends on aspect ratio, but I'm not so good at math). It was a while since i did this (messy) project. But here is a sample from my code, if you would like to see it:
In loadcontent method:
// Scale the render target, for the corners to be filled with tiles, when we rotate camera float rotationBuffer = 2.0f; int renderTargetScale = (int)(Math.Ceiling(1.0f / minCameraZoom) * rotationBuffer); _map = new Map(GraphicsDevice, Content.Load<TiledMap>("sandbox")); _mapRenderTarget = new RenderTarget2D(GraphicsDevice, Game1.gameWidth * renderTargetScale, Game1.gameHeight * renderTargetScale);
In draw method:
// Added additional offset for rotation Vector2 mapOffset = _gameCamera.Position - new Vector2(Game1.gameWidth, Game1.gameHeight) * ( 1.0f / _gameCamera.Zoom) * 0.5f ; mapOffset.Round(); _map.PreDraw(mapOffset); GraphicsDevice.SetRenderTarget(game1._renderTarget);
Edit: Sorry the formatting is horrible here
OK, what I was thinking was using one of the viewport adapters to do the upscaling calculation.
I would be OK with just adding some documentation about "How to avoid distorting your tiles" to resolve this. The scaling factor can come from the viewport adapter to get the correct value for letter-boxing or pillar-boxing.
There is a great post by the community with step-by-step how to solve this: https://community.monogame.net/t/monogame-tiled-zoom-in-cause-warped-tiles-and-wierd-graphics/9730/11