1
\$\begingroup\$

I am creating a 2D game using OpenGL and orthographic projection. For sprites, I use textured quads (actually two triangles).

I want the pixel art textures for the sprites to be displayed in a multiple of the original size to avoid blurry textures.

How can I set up a pixel-perfect camera using OpenGL and orthographic projection? After doing so, how do I size the qauds?

\$\endgroup\$
4
\$\begingroup\$

Please take note that the question was unclear and changed meaning 3 times, hence the 3 answers in one

How can I verify that a given size is a multiple of another?

This is a very good case to use the Modulo operator.

Let's say you have a texture tex with size (width, height). Now you want to render the texture with size (drawWidth, drawHeight) on the screen. You can verify that the draw size is a multiple of the original texture size using the following test:

if (drawWidth % tex.width == 0 && drawHeight % tex.height == 0
    && drawWidth != 0 && drawHeight != 0) {
    // Render the texture
}

We need to test if drawWidth and drawHeight are not 0 because 0 modulo anything will return 0.

The Modulo operator returns the remainder of an integer division. So let's say your texture is 64x64, like in your question, and you want to render it with size 127x234:

64 % 127 = 63 (1 remainder 63) // This will fail the test
64 % 234 = 42 (3 remainder 42) // This will fail the test too

But using a multiple (for example, 128x192) gives the following result:

64 % 128 = 0 (2 remainder 0) // Pass
64 % 192 = 0 (3 remainder 0) // Pass

If you want to keep the ratio (always draw a square if the texture is a square, or always draw 2x3 if the texture has a ratio of 2x3), you can add the following to the condition:

if (drawWidth % tex.width == 0 && drawHeight % tex.height == 0
    && (drawWidth / tex.width) == (drawHeight / tex.height)
    && drawWidth != 0 && drawHeight != 0) {
    // Render the texture
}

This will test if the ratio is the same as the original image. The division will always return an integer value because both modulos returned 0.

How can I render these sizes without them being blurry in my viewport?

NOTE: This only needs to be applied if your camera viewport is not alreay pixel-perfect.

Let's say you have a viewport with the following attributes:

screenWidth  // Width of the screen, in pixels
screenHeight // Height of the screen, in pixels
viewWidth    // Width of the OpenGL viewport
viewHeight   // Height of the OpenGL viewport

To render your texture with size (drawWidth, drawHeight), you have to calculate the ratio of the pixels compared to the viewport:

ratioX = viewWidth / screenWidth;
ratioY = viewHeight / screenHeight;

ratioX and ratioY tells you how many units the viewport spans in 1 pixel. If your camera spans from -1 to 1 on the X axis (default OpenGL camera), and your screen width in pixels is 1024, then the ratio will be 2 / 1024 = 0.00195..., which tells you that for each pixel on the screen, the OpenGL position increments by that amount.

You then need to multiply your drawWidth and drawHeight with those ratios:

drawWidth *= ratioX;
drawHeight *= ratioY;

This will give you pixel-perfect rendering of textures. If you want to take into account a texture position, you can multiply your drawX and drawY the same way to scale it.

How can I setup a pixel-perfect camera then?

It is simple to setup a pixel-perfect orthographic projection. You only need to modify 2 matrices in OpenGL (legacy):

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, screenWidth, screenHeight);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glOrtho(0, screenWidth, 0, screenHeight, 1, -1); // Origin in lower-left corner
glOrtho(0, screenWidth, screenHeight, 0, 1, -1); // Origin in upper-left corner
\$\endgroup\$
  • \$\begingroup\$ OK it seems I misstated the question, I am sorry. I want to know how much I have to scale the quads to get that certain pixel size. How can I improve the question? \$\endgroup\$ – schemar Jul 2 '15 at 14:58
  • \$\begingroup\$ Ok, thank you. Sorry for the confusion. And how to do it in modern OpenGL? \$\endgroup\$ – schemar Jul 2 '15 at 15:22
  • \$\begingroup\$ I do beleive it works the exact same way for modern (3+) OpenGL, but I've specified Legacy just in case it doesn't. \$\endgroup\$ – Alexandre Desbiens Jul 2 '15 at 15:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.