Is OpenGL coordinate system left-handed or right-handed?
Asked Answered
H

6

110

I am trying to understand the OpenGL coordinate system. However, some tutorials say the default coordinate system is left handed (see http://www.c-sharpcorner.com/UploadFile/jeradus/OpenGLBasics11172005014307AM/OpenGLBasics.aspx) and others say it is right handed (see http://www.falloutsoftware.com/tutorials/gl/gl0.htm). Which is correct? I understand that we can transform one to the other by mirroring but I would like to know the default coordinates.

Hest answered 8/11, 2010 at 13:0 Comment(4)
Related programmers.stackexchange.com/a/88776/12693Kepler
Doesn't this depend entirely on how you write your transforms in the shaders and is therefore entirely up to you?Cowlick
Just my two cents evl.uic.edu/ralph/508S98/coordinates.html, it has a few self explanatory images.Judgeship
I don't suppose you'd consider updating your accepted answer?Alec
F
151

There is some confusion here.

enter image description here

OpenGL is right handed in object space and world space.

But in window space (aka screen space) we are suddenly left handed.

How did this happen?

The way we get from right-handed to left-handed is a negative z scaling entry in the glOrtho or glFrustum projection matrices. Scaling z by -1 (while leaving x and y as they were) has the effect of changing the handedness of the coordinate system.

For glFrustum,

enter image description here enter image description here

far and near are supposed to be positive, with far > near. Say far=1000 and near=1. Then C= -( 1001 ) / ( 999 ) = -1.002.

See here for more details and diagrams.

From an orthographic perspective, glOrtho generates a matrix like this:

enter image description here

Here, left, right, bottom and top are just the coordinates for left vertical, right vertical, bottom horizontal, top horizontal clipping planes (resp).

The near and far planes, however, are specified differently. The near parameter is defined as

  • Near: The distance to the nearer depth clipping plane. This distance is negative if the plane is to be behind the viewer.

and far:

  • zFar The distance to the farther depth clipping plane. This distance is negative if the plane is to be behind the viewer.

Here we have a typical canonical view volume

canonical

Because the z multiplier is (-2/(far-near)), the minus sign effectively scales z by -1. This means that "z" is turned left handed during the viewing transformation, unbeknownst to most people as they simply work in OpenGL as a "right handed" coordinate system.

So, if you call

glOrthof(-1, 1, -1, 1, 10, -10) ; // near=10, FAR=-10,

Then the NEAR PLANE is 10 units ahead of you. Where are you? Why, at the origin, with the x-axis to your right, the y-axis on top of your head, and your nose pointing down the negative z-axis (that's the default "By default, the camera is situated at the origin, points down the negative z-axis, and has an up-vector of (0, 1, 0)."). So the near plane is at z=-10. The far plane is 10 units behind you, at z=+10.

Ferocity answered 9/9, 2012 at 3:47 Comment(10)
"the forward vector is negated in gluLookAt" - can you confirm that this is that the case? Not gluPerspective or glFrustum or glOrtho?Kepler
Yes, in the last few lines, matrix2[2] = -forward[0]; .. flips the direction of the forward vector.Ferocity
We're suddenly left-handed from clip space onwards not just window space.Parchment
+1 for the whole answer, -1 (wait, rather -2) for "The way we get from right-handed to left-handed is because the forward vector is negated in the standard implementation of gluLookAt(), which is the function everybody uses to create the view matrix. When you negate the forward vector, this has the effect of changing the handedness of the coordinate system.", which is mere rubbish...Strontia
...Negating the forward vector in the gluLookAt computation has nothing to do with changing the handedness of the coordinate space, that's just how this matrix is computed (and in fact +z is indeed "backward" in right-handed space). gluLookAt does nothing else than compute an ordinary rigid body transformation (rotation+translation) in right-handed space. It is the projection matrices used by the fixed function pipeline (and usually by shaders, too) that perform the actual handedness change in their negation of the z-component, as you already noted in your answer.Strontia
@ChristianRau The upper 3x3 of the lookAt matrix is a change of basis, or just 3 vectors. It consists of a new forward, new right, and new up vector. In the code linked, the forward components are computed as forward[0] = center3D[0] - eyePosition3D[0];, but in the final assignment into the matrix they are suddenly inverted matrix2[2] = -forward[0];. Your discussion in the previous 2 comments appears high level and I don't think you really understand what you're talking about. That said, still haven't resolved w/perspective projection.Ferocity
Hmm, it appears that the reason the forward vector is negated is because OpenGL's default forward vector is (0,0,-1). For that reason it may be true that the lookAt matrix does not change the handedness of the coordinate system.Ferocity
"Your discussion in the previous 2 comments appears high level and I don't think you really understand what you're talking about." - Sorry to counter that one with a classic "no, you might not be aware of what you're talking about" (sorry, but "high level", what the...?). Of course the 3x3 part is a change of basis, as every ordinary rotation is, this doesn't neccessarily imply a change of handedness, and in the case of the standard rigid body transformation that gluLookAt creates it certainly doesn't.Strontia
@Ferocity Your saying if you compute your view matrix using rotation and translation functions only (which I guess you wouldn't accuse of changing handedness), instead of gluLookAt, there wouldn't be a change of basis while gluLookAt does one? Definitely not (since you probably know that not "everybody" uses gluLookAt for view matrix computation), since as you should know gluLookAt does nothing else than a bunch of rotation and translation calls (be they even disguised as the "high level" term "change of basis") with absolutely no reflections involved.Strontia
What is the convention on using your fingers to represent axis? I see different illustrations assigning different axis to different fingers. I use the Ogl/left hand analogy to align my hand with the NDC (x to the right, y to the top, z into the scene/screen). Index is X, thumb is Y, middle is Z?Goingover
T
37

By default the Normalized Device Coordinate is left-handed.

The glDepthRange is by default [0, 1] (near, far) making the +z axis point into the screen and with +x to the right and +y up it is a left-handed system.

Changing the depth range to [1, 0] will make the system right-handed.

Quoting a previous answer from Nicol: (the strike-through is my work, explained below)

I'm surprised nobody mentioned something: OpenGL works in a left-handed coordinate system too. At least, it does when you're working with shaders and use the default depth range.

Once you throw out the fixed-function pipeline, you deal directly with "clip-space". The OpenGL Specification defines clip-space as a 4D homogeneous coordinate system. When you follow the transforms through normalized device coordinates, and down to window space, you find this.

Window space is in the space of a window's pixels. The origin is in the lower-left corner, with +Y going up and +X going right. That sounds very much like a right-handed coordinate system. But what about Z?

The default depth range (glDepthRange) sets the near Z value to 0 and the far Z value to one. So the +Z is going away from the viewer.

That's a left-handed coordinate system. Yes, you can change the depth test from GL_LESS to GL_GREATER and change the glDepthRange from [0, 1] to [1, 0]. But the default state of OpenGL is to work in a left-handed coordinate system. And none of the transforms necessary to get to window space from clip-space negate the Z. So clip-space, the output of the vertex (or geometry) shader is a left-handed space (kinda. It's a 4D homogeneous space, so it's hard to pin down the handedness).

In the fixed-function pipeline, the standard projection matrices (produced by glOrtho, glFrustum and the like) all transform from a right-handed space to a left-handed one. They flip the meaning of Z; just check the matrices they generate. In eye space, +Z moves towards the viewer; in post-projection space, it moves away.

I suspect Microsoft (and GLide) simply didn't bother to perform the negation in their projection matrices.

I did strike one part since it diverged from my findings.

Either changing the DepthRange or the DepthFunc and using the ClearDepth(0) works but when using both they cancelled out each other back to a left-handed system.

Tati answered 22/4, 2012 at 0:50 Comment(9)
The depth range can't be [1, -1]. I think you meant [1, 0]. Also, this has been pointed out before.Melar
Your answer is great, too bad it is to a DirectX question, you should repost it here!Tati
I don't think this was worth resurrecting 2 years old question.Undertint
@Undertint why do you think correcting a false statement is not worth it? I have spent several hours troubleshooting vertex coordinates and matrix rotation generation just to find out that the default coordinate system in fact was not right-handed.Tati
@phq: "why do you think" Because it is a minor implementation detail that can be easily fixed by adding a "-" sign.Undertint
The question was whether it was a left- or right-handed system. This answer has more details than that, explaining two other ways to get it right-handed, adding a -1 in a matrix transformation is yet another way of doing it. But none of that matters if you believe the system is right-handed by default, you can only change something if you know what you are changing from. StillTati
I found the answer very enlightening, and it came up in searches so it was worth it for me.Gunshy
As I understand that, NDC is always left-handed, while window coordinates can be left-handed (default) or right-handed depending on depth range.Kepler
@Kepler not only the DepthRange but it and the DepthFunc together, note the last paragraph about them cancel each other out.Tati
K
21

ONLY NDC

You should only notice that OpenGL only knows NDC! and that is a left-handed coordinate system.

No matter what coordinate system you use -- left-handed or right-handed axis-coordinate system -- all need to be mirrored to NDC. If you like, you can totally handle world-space as left-handed coordinate system.

Why do we usually use right-handed coordinate system in world-space?

I think it`s conventional. It just does. Maybe it just want to distinguish from DirectX.

Kibbutz answered 2/7, 2014 at 10:20 Comment(4)
I think this doesn't get repeated enough. All these diagrams showing "modeling transform", "view transform", "perspective transform" fail to show they're not an intrinsic part of OpenGL. You could even do all your transforms manually, with or without shaders, with or without matrices.Respectable
It might be nicer if repeating it to include the words "normalised device coordinates" though.Ithaman
OpenGL predates DirectX by a few years, so OpenGL were certainly not trying to distinguish themselves from DirectX. The lead developer of DirectX, Alex St. John, has said that Microsoft's decision to go for a left-handed co-ordinate system was "in part out of personal preference" and "an arbitrary choice."Sanderlin
This is not entirely correct. OpenGL also knows the clipping coordinate system, since clipping happens in that. The clip coordinate system has the same handedness as NDC coordinate system tho.Dustin
G
12

The book "WebGl Programming Guide" by Kouichi Matsuda spends almost ten pages on "WebGl/OpenGl: Left or Right Handed?"

According to the book:

  • In practice, most people use a right-handed system

  • OpenGl actually is a left-handed system internally

  • Internally, more deeply it's actually neither. At the very bottom OpenGl doesn't care about the z-value. The order in which you draw things determines what is drawn on top (draw a triangle first, then a quad, the quad overrides the triangle).

I don't fully agree with the "it's neither" but that's probably a philosophical question anyway.

Gudrin answered 4/6, 2014 at 9:6 Comment(1)
The order in which you draw things determines what is drawn on top (draw a triangle first, then a quad, the quad overrides the triangle). This is true, in the absence of depth testing. In the presence of depth testing, the z value of a fragment is compared with the value in the depth buffer, and the fragment discarded if it fails the depth test, so the quad may or may not overwrite the triangle depending on their depths and the depth function used.Abreast
F
4

Opengl is definitely left-handed. You see a lot of tutorials stating the opposite because they are negating the z-value in projection matrix. When the final vertices are computed inside vertex shader, it's converting the vertices that you pass from client-side (right-hand coord) to left-handed, and the vertices will then be passed to geometry shader and fragment shader. If you use right-hand coordinate system in client-side, Opengl doesn't care. It only knows normalized coordinate system, which is left handed.

Edit: If you don't trust me, just experiment in your vertex shader by adding a translation matrix, and you can easily see if Opengl is left-handed or not.

Finalize answered 28/6, 2017 at 7:20 Comment(1)
I think you're right about people thinking OpenGL is right-handed because of tutorials that negate the z in the projection matrix, however I don't think it's inherently left-handed either. There is nothing in the OpenGL spec that indicates either way. The only justification I can find for saying it's left-handed is that the default depth testing function is GL_LESS which would typically mean that objects with a lower z value are seen to be closer - but depth testing itself is disabled by default anyway so it really comes down to how your application uses the GL.Freewheeling
F
3

By using OpenGL's built in projection and transformation functions, observing the movements on screen follow the rules of the right-handed coordinate system. For example, if an object in front of your view is translated in the positive z direction, then the object will move towards you.

The depth buffer is quite the opposite, and this is where the NDC (Normalized Device Coordinates) come into play. If passing GL_LESS into the glDepthFunc means that pixels will draw when they are nearer to you than what's already in the depth buffer, then pixels are considered to live in a left-handed coordinate system.

There's one more coordinate system, and that's the viewport! The viewport's coordinate system is such that +x points to the right, and +y points down. I think by this point the handedness is moot since we're only dealing with x, y at this point.

Lastly, gluLookAt under the hood has to negate the look-at vector. Since the math assumes a vector is pointing in a positive direction towards the object it's looking at, and a camera looks down -z, the look-at vector must be negated so that it aligns with the camera.

Something to chew on. It doesn't make much sense to call the z direction of a right handed coordinate system a forward vector :). I think Microsoft realized this when they designed Direct3D.

Fielder answered 29/12, 2019 at 5:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.