I am trying to set my co-ordinate system such that the y-axis points down the screen.
// Determine view-projection matrix
glm::mat4 projection = glm::ortho(
-3.0f, // left
3.0f, // right
3.0f, // bottom
-3.0f); // top
// Right handed rule:
// x points right
// y points down
// z points into the screen
glm::mat4 view = glm::lookAt(
glm::vec3(0, 0, -1), // camera position
glm::vec3(0, 0, 0), // look at
glm::vec3(0, -1, 0) // up vector
);
glm::mat4 viewProjMatrix = projection * view;
However, when I try to render 2 objects:
A at (0, 0)
B at (1, 1)
A appears in the centre of the screen, and B appears in the top-right. I would expect it to appear in the bottom-right.
What am I missing here?
My camera was positioned correctly (in a manner of speaking), but I was flipping the y-axis in the call to glOrtho
.
Imagine a right-handed co-ordinate system such as OpenGL uses by convention:
If my objects were positioned in this world and we viewed them from the front, we would see this:
B
A
This is the same as what I was seeing, but we weren't viewing from the front. As @Scheff pointed out in the comments, my call to glm::lookat
was flipping my camera upside-down and positioning it "behind" the screen.
Now, if you imagine that you are doing a handstand behind your monitor, A and B would now look like this:
∀
𐐒
Wait, but isn't this what I wanted - B in the bottom-right?
Right, but in addition to my camera being positioned strangely, my y-axis was being flipped by the call to glm::ortho
. Normally the value for bottom
should be less than the value for top
(as in this example).
Thus producing, once again:
B
A
So, one solution would have been to swap the top
and bottom
parameters in glOrtho
:
glm::mat4 view = glm::lookAt(
glm::vec3(0, 0, -1), // camera position
glm::vec3(0, 0, 0), // look at
glm::vec3(0, -1, 0) // up vector
);
glm::mat4 projection = glm::ortho(
-3.0f, // left
3.0f, // right
-3.0f, // bottom (less than top -> y-axis is not inverted!)
3.0f); // top
The solution above works, but there is a much simpler solution - or at least much simpler to visualize! And that is just to position the camera in front of the scene and flip the y-axis using glOrtho
(by keeping bottom
greater than top
):
glm::mat4 view = glm::lookAt(
glm::vec3(0, 0, 1), // camera position
glm::vec3(0, 0, 0), // look at
glm::vec3(0, 1, 0) // up vector
);
glm::mat4 projection = glm::ortho(
-3.0f, // left
3.0f, // right
3.0f, // bottom (greater than top -> y-axis is inverted!)
-3.0f); // top
Flipping the y-axis may result in upside-down textures, which can be fixed by swapping your top and bottom texture co-ordinates.
Viewing the scene from a different angle may result in faces being culled, if face culling is enabled. This can be fixed by changing the winding order of your vertices, or by changing which faces get culled.