Question

Trying to figure out a good solution for handling different resolutions and resizing in a 2D side-scrolling shooter game build with OpenTK (OpenGL).

Ortho is setup as follows.

    private void Setup2DGraphics()
    {
        const double halfWidth = 1920 / 2;
        const double halfHeight = 1080 / 2;
        GL.MatrixMode(MatrixMode.Projection);
        GL.LoadIdentity();
        GL.Ortho(-halfWidth, halfWidth, -halfHeight, halfHeight, -1.0, 1.0);
        GL.MatrixMode(MatrixMode.Modelview);
        GL.LoadIdentity();
    }

Ortho fixes to 1920*1080 to keep the ortho fixed size. Changing size would change game behaviour. Objects movement is set to pixels/sec etc.

    public void ResizeWindow(int width, int height)
    {
        var screenSize = GetOptimalResolution(width, height);

        var offsetHeight = screenSize.Y < height ? (height - screenSize.Y) / 2 : 0;
        var offsetWidth = screenSize.X < width ? (width - screenSize.X) / 2 : 0;

        // Set the viewport
        GL.Viewport((int)offsetWidth, (int)offsetHeight, (int)screenSize.X, (int)screenSize.Y);
    }

GetOptimalResolution returns the viewport size in order to maintain a 16:9 aspect ratio. Example: If screensize is 1024*768, it resturns 1024*576 (shrinking height). It then places the ortho higher in the viewport using half of the height difference as offset. This results in black bars above and below the windows.

This setup works. It prevents aspect ratio issues on all resolutions. However I'm questioning myself if this is the right way to do it? The issues I can think of with this design: - On resolutions lower then 1920*1080, the view is scaled down. This has an effect of how sprites look. For example, text starts to look horrible when scaled down. - If turning down resolution for performance, will this have an effect if the ortho stays the same size?

Did a lot of searching on this topic but so far the only things I can find is plain instructions on how to perform actions, rather then to build solutions. I also found out that using Mipmap's might solve my scaling issue. However the question remains, am I on the right track? Should I look at the aspect ratio problem from a different angle?

Was it helpful?

Solution

For example, text starts to look horrible when scaled down.

Don't use textures for text. Use a technique like signed distance fields for rendering clear text at any resolution.

For artwork, the ideal would be to have resolution specific artwork for a variety of common resolutions / DPIs. Failing that, mipmaps will drastically improve the quality of the rendered texture if it's scaled down from the source texture image.

It also might be easier to work the problem if you stop using pixel coordinates to do stuff. The default OpenGL screen coordinates are (-1,-1) lower left to (1,1) upper right. However, you can alter these using an ortho transform to account for aspect ratio like this

const double aspect = windowWidth / windowHeight;
if (aspect > 1.0) {
  GL.Ortho(-1 * aspect, 1 * aspect, -1, 1, -1.0, 1.0);
} else {
  GL.Ortho(-1, 1, -1 / aspect, 1 / aspect, -1.0, 1.0);
}

This produces a projection matrix that is at least 1 in both dimensions. This lets you treat the screen as a 2x2 square with the origin in the middle, and any additional stuff the viewer can see because of the aspect is cake.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top