# Orthographic unit translation mismatch on grid (e.g. 64 pixels translates incorrectly)

I am looking for some insight into a small problem with unit translations on a grid.

## Update and Solved

I solved my own issue. See below for details. Everything in this part of the post turned out to be correct. If anything it can act as a miniature tutorial / example / help for the next person.

## Setup

• FBO, VAO, VBO
• 512x448 window
• 64x64 grid
• gl_Position = projection * world * position;
• projection is defined by ortho(-w/2.0f, w/2.0f, -h/2.0f, h/2.0f); This is a textbook orthogonal projection function.
• world is defined by a fixed camera position at (0, 0)
• position is defined by the sprite's position.

## Problem

In the screenshot below (1:1 scaling) the grid spacing is 64x64 and I am drawing the unit at (64, 64), however the unit draws roughly ~10px in the wrong position. I've tried uniform window dimensions to prevent any distortion on the pixel size, but now I am a bit lost in the proper way in providing a 1:1 pixel-to-world-unit projection. Anyhow, here are some quick images to aide in the problem.

I decided to super-impose a bunch of the sprites at what the engine believes is 64x offsets.

When this seemed off place, I went about and did the base case of 1 unit. Which seemed to line up as expected. The yellow shows a 1px difference in the movement.

## What I Want

Ideally moving in any direction 64-units would output the following (super-imposed units):

## Vertices

It would appear that the vertices going into the vertex shader are correct. For example, in reference to the first image the data looks like this in the VBO:

      x    y           x    y
----------------------------
tl | 0.0  24.0        64.0 24.0
bl | 0.0  0.0    ->   64.0 0.0
tr | 16.0 0.0         80.0 0.0
br | 16.0 24.0        80.0 24.0


For sake of completeness here is the actual array corresponding to the above movements:

      x     y    z   w   r   g   b   a      s          t
-------------------------------------------------------------
tl | 0.0   23.0 0.0 1.0 0.0 0.0 0.0 1.0 0.14210527 0.62650603
bl | 0.0   0.0  0.0 1.0 0.0 0.0 0.0 1.0 0.14210527 0.76506025
tr | 16.0  0.0  0.0 1.0 0.0 0.0 0.0 1.0 0.2263158  0.76506025
br | 16.0  23.0 0.0 1.0 0.0 0.0 0.0 1.0 0.2263158  0.62650603
-------------------------------------------------------------
-------------------------------------------------------------
tl | 64.0  24.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0        0.21084337
bl | 64.0  0.0  0.0 1.0 0.0 0.0 0.0 1.0 0.0        0.3554217
tr | 80.0  0.0  0.0 1.0 0.0 0.0 0.0 1.0 0.08421053 0.3554217
br | 80.0  24.0 0.0 1.0 0.0 0.0 0.0 1.0 0.08421053 0.21084337

// side bar: I know that I have unnecessary data with having a z-axis.
//           The engine flips between perspective and orthogonal and I
//           haven't selectively started pruning data.


## Projection Matrix

The projection matrix for the 512x448 window looks like this:

0.00390625 0.0         0.0  0.0
0.0        0.004464286 0.0  0.0
0.0        0.0        -1.0  0.0
0.0        0.0         0.0  1.0


and is constructed with a textbook orthogonal projection function:

ortho(-w/2.0f, w/2.0f, -h/2.0f, h/2.0f);
// explicitly: ortho(-512/2.0f, 512/2.0f, -448/2.0f, 448.0f

ortho(float left, float right, float bottom, float top)
{
projection.setIdentity();
projection.m00 = 2.0f / (right - left);
projection.m11 = 2.0f / (top - bottom);
projection.m22 = -1;
projection.m30 = -(right + left) / (right - left);
projection.m31 = -(top + bottom) / (top - bottom);
projection.m32 = 0;
}


## World-view Matrix

The camera's position is just a translation matrix which in this case I just offset by -w/2 and -h/2 to be zero relative to center.

1.0 0.0 0.0 -256.0
0.0 1.0 0.0 -224.0
0.0 0.0 1.0 0.0
0.0 0.0 0.0 1.0


## Solutions I have attempted

1. player.moveRight() would move 1-unit with the aspect ratio factored into the equation. So: gridWidth = 64 / 1.14f. Movement did not fit within the grid.

2. Forced a 512x512 window with a matching orthogonal projection.

3. Tried various magic numbers and tried to draw correlations between the two.

With that said, all I am left to believe is that I am munging up my actual projection. So, I am looking for any insight into maintaining the 1:1 pixel-to-world-unit projection.

• Well constructed question, but maybe we could see your projection & world matrices. You mentioned them above, but didn't include their contents. The problem will be with one of those matrices. – Ken Nov 27 '12 at 9:38
• @Ken No problem at all. I've added my projection and world-space view matrices. I've also included my desired output and my own attempts at the problem. – Justin Van Horne Nov 27 '12 at 14:09
• You matrices look good (I compared them the ones produces by glOrtho and glTranslate. Grapsing at straws here, but opengl expects its matrices to arranged in column-major order, are you doing the same? – Ken Nov 28 '12 at 10:15
• Hm, they are being stored column-major order. – Justin Van Horne Nov 28 '12 at 15:23

I solved my own problem--and rather than just blow it off as a simple explanation, I want to describe the steps I took to debug the issue. I left out that I was using a single FBO for special-effects.

First, it turns out everything above is in fact correct and a step I left out was the problem.

• I verified my orthogonal matrices through-and-through.
• Verified the byte-order of everything.
• Created a square texture. <- Here is the magic
• When I created a square texture, I noticed it was not square on the screen, but square going into the vertex shader.
• This was my first clue that something was wrong. The dimensions of my textures on screen did not match the dimensions that were going to the vertex shader.
• I forgot that I was using an FBO (here comes the sillyness).
• The FBO texture size did not match my viewport texture size for whatever stupid reason.
• Disabled the FBO and the results matched up.
• Fixed the logic with defining my texture size and wah-lah.

I am sorry if this took up anyone's time. I will leave the question around as good measure for anyone that might run into the same problem without knowing it.