## Orthographic Projection

Member
Posts: 215
Joined: 2008.06
Post: #1
I'm trying to set up a proper orthographic viewpoint on a quad, and it's giving me no end of trouble.

First off: calling a glRotate(45.0f, -1.0f, 0.0f, 1.0f) generates a skew that a...

glRotate(1.0f, -1.0f, 0.0f, 0.0f); //Called at every update to make a spin effect.
glPushMatrix();

glRotate(45.0f, -1.0f, 0.0f, 1.0f);

...does NOT generate. Secondly, I can't find a good angular offset to setup a real ortho scene (45, 60, 90, what?). Can anyone shed any light on this one?

Mac users swear by their computers, PC users swear at their computers. ~Unknown

iSayz
Member
Posts: 283
Joined: 2006.05
Post: #2
Talyn Wrote:Secondly, I can't find a good angular offset to setup a real ortho scene (45, 60, 90, what?). Can anyone shed any light on this one?

Orthographic just means that there's no perspective. If you want an isometric scene, here's a bit from Wikipedia:

Quote:In a similar way an isometric view can be obtained for example in a 3D scene editor. Starting with the camera aligned parallel to the floor and aligned to the coordinate axes, it is first rotated downwards around the horizontal axes by about 35.264Â° as above, and then rotated Â±45Â° around the vertical axes.

35.264 comes from arcsin(tan 30Â°), which is a "correct" isometric projection, but on a computer screen arctan 0.5 (26.565Â°) is often used instead of 30Â° (so that diagonals go two pixels across for every one pixel up or down. So... I think that means you'd rotate 30Â° down then 45Â° around the Y axis.

I hope that's useful in some way.
Moderator
Posts: 3,591
Joined: 2003.06
Post: #3
I don't quite understand your question about what kind of ortho projection you're trying to setup.

But on the glRotatef thing ...

Code:
`glRotate(45.0f, -1.0f, 0.0f, 1.0f);`

Attempts to rotate 45 degrees around the vector [-1, 0, 1].

glRotatef(angle, axisX, axisY, axisZ) means that if you aren't using axis-angle math of some sort, you should specify 1.0f on only one of the axis parameters to get expected results around one axis at a time.

You should probably do something like this instead:

Code:
```glRotate(-45.0f, 1.0f, 0.0f, 0.0f); // spin on x axis -45 degrees (pitch) glRotate(45.0f, 0.0f, 0.0f, 1.0f); // spin on z axis 45 degrees (roll)```

Do note however that this is an Euler rotation, and will incur gimbal lock if you also add in a third axis:

Code:
`glRotate(45.0f, 0.0f, 1.0f, 0.0f); // spin on y axis 45 degrees (yaw)`
Member
Posts: 215
Joined: 2008.06
Post: #4
maximile Wrote:Orthographic just means that there's no perspective. If you want an isometric scene, here's a bit from Wikipedia:

35.264 comes from arcsin(tan 30Â°), which is a "correct" isometric projection, but on a computer screen arctan 0.5 (26.565Â°) is often used instead of 30Â° (so that diagonals go two pixels across for every one pixel up or down. So... I think that means you'd rotate 30Â° down then 45Â° around the Y axis.

I hope that's useful in some way.

Fantastic! That's is pretty much exactly what I was after, thank you! Though it is less of an issue, how would you do an orthographic scene? Thanks again!

Mac users swear by their computers, PC users swear at their computers. ~Unknown

iSayz
Member
Posts: 215
Joined: 2008.06
Post: #5
AnotherJake Wrote:I don't quite understand your question about what kind of ortho projection you're trying to setup.

But on the glRotatef thing ...

Code:
`glRotate(45.0f, -1.0f, 0.0f, 1.0f);`

Attempts to rotate 45 degrees around the vector [-1, 0, 1].

glRotatef(angle, axisX, axisY, axisZ) means that if you aren't using axis-angle math of some sort, you should specify 1.0f on only one of the axis parameters to get expected results around one axis at a time.

You should probably do something like this instead:

Code:
```glRotate(-45.0f, 1.0f, 0.0f, 0.0f); // spin on x axis -45 degrees (pitch) glRotate(45.0f, 0.0f, 0.0f, 1.0f); // spin on z axis 45 degrees (roll)```

Do note however that this is an Euler rotation, and will incur gimbal lock if you also add in a third axis:

Code:
`glRotate(45.0f, 0.0f, 1.0f, 0.0f); // spin on y axis 45 degrees (yaw)`

OOOOH! That does help to explain. Is there a way to disable vector rotation and simply do matrix transforms instead, or is that something I have to do by hand? Thanks for the explanation.

Mac users swear by their computers, PC users swear at their computers. ~Unknown

iSayz
Member
Posts: 254
Joined: 2005.10
Post: #6
I forget what the calls are, but there are opengl functions to apply a direct matrix transform. One of the alternative methods of doing the rotations to avoid gimbal lock is to use quaternions. There are several threads on this site about them and they aren't too hard to implement, just a bit difficult to understand at first. That being said, if you aren't making multiple accumulating rotations you may be able to avoid gimbal lock with simple Euler rotations, just try it out to see if it works.
Member
Posts: 215
Joined: 2008.06
Post: #7
Blacktiger Wrote:I forget what the calls are, but there are opengl functions to apply a direct matrix transform. One of the alternative methods of doing the rotations to avoid gimbal lock is to use quaternions. There are several threads on this site about them and they aren't too hard to implement, just a bit difficult to understand at first. That being said, if you aren't making multiple accumulating rotations you may be able to avoid gimbal lock with simple Euler rotations, just try it out to see if it works.

I am not familiar with the "gimbal lock" term. I only partially understand what a quaternion is, but that can be remedied with a wikipedia search. What is this gimbal lock?

Mac users swear by their computers, PC users swear at their computers. ~Unknown

iSayz
Moderator
Posts: 3,591
Joined: 2003.06
Post: #8
glMultMatrixf() is what you're looking for if you want to do the transforms using your own matrices and not using glRotatef().

Gimbal lock is hard to describe. Essentially, what it means is that if you rotate + or - 90 degrees on the second rotation, the first and third will be rotating on the same axis. It is a phenomenon related to the fact that the math is restricted to 3 dimensions.

To get past the 3 dimensional math restriction, some dude (in the 1800's I believe, writing the formula on a bridge so he wouldn't forget it?) came up with the idea of artificially rotating things in 4 dimensions -- known as quaternion math. You create an initial quaternion, which is a four component vector (x, y, z, w) from your Euler angles (x, y, z). Then add rotations to your quaternion using special formulas. When you want to get information back out of the quaternion to use with OpenGL, you can either convert the quaternion to a matrix (to be used with glMultMatrixf), or an angle-axis (to be used with glRotatef).
Moderator
Posts: 1,563
Joined: 2003.10
Post: #9
Member
Posts: 215
Joined: 2008.06
Post: #10
Alright, so with the information afforded me by maximile, I am able to create a floor and ceiling using his technique. However, I am stuck on making the rest of the cube. I am using OGL ES in the Simulator and this is my code:

Code:
```- (void)drawView {          const GLfloat squareVertices[] =         {         -0.5f, 0.0f, -0.5f,         0.5f, 0.0f,  -0.5f,         -0.5f, 0.0f,  0.5f,         0.5f, 0.0f,  0.5f,     };          /**     const GLubyte squareColors[] =     {         255, 255,   0, 255,         0,   255, 255, 255,         0,     0,   0,   0,         255,   0, 255, 255,     };      */          const GLfloat squareTextureVerts[] =     {         0.0f, 0.0f,         1.0f, 0.0f,         0.0f, 1.0f,         1.0f, 1.0f     };          [EAGLContext setCurrentContext:context];          glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);     glViewport(0, 0, backingWidth, backingHeight);          glMatrixMode(GL_PROJECTION);     glLoadIdentity();     glOrthof(-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f);     glMatrixMode(GL_MODELVIEW);          glClearColor(0.5f, 0.5f, 0.5f, 1.0f);     glClear(GL_COLOR_BUFFER_BIT);          glEnable(GL_TEXTURE_2D);     glBindTexture(GL_TEXTURE_2D, texture);          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);          glColor4f(1.0f, 1.0f, 1.0f, 1.0f);          //Bottom     glPushMatrix();     glTranslatef(0.0f, -0.5f, 0.0f);     glRotatef(26.565f, -1.0f, 0.0f, 0.0f);     glRotatef(45.0f, 0.0f, 1.0f, 0.0f);     glVertexPointer(3, GL_FLOAT, 0, squareVertices);     glEnableClientState(GL_VERTEX_ARRAY);     glTexCoordPointer(2, GL_FLOAT, 0, squareTextureVerts);     glEnableClientState(GL_TEXTURE_COORD_ARRAY);     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);     glPopMatrix();          //Top     glPushMatrix();     glTranslatef(0.0f, 0.5f, 0.0f);     glRotatef(26.565f, -1.0f, 0.0f, 0.0f);     glRotatef(45.0f, 0.0f, 1.0f, 0.0f);     glVertexPointer(3, GL_FLOAT, 0, squareVertices);     glEnableClientState(GL_VERTEX_ARRAY);     glTexCoordPointer(2, GL_FLOAT, 0, squareTextureVerts);     glEnableClientState(GL_TEXTURE_COORD_ARRAY);     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);     glPopMatrix();          glDisable(GL_TEXTURE_2D);     glColor4f(1.0f, 0.5f, 0.0f, 1.0f);          //Front     glPushMatrix();          glTranslatef(0.0f, 0.0f, 0.5f);     glRotatef(45.0f, 1.0f, 0.0f, 0.0f);     glRotatef(26.565f, 0.0f, 0.0f, -1.0f);     //glRotatef(45.0f, 1.0f, 0.0f, 0.0f);          glVertexPointer(3, GL_FLOAT, 0, squareVertices);     glEnableClientState(GL_VERTEX_ARRAY);     glTexCoordPointer(2, GL_FLOAT, 0, squareTextureVerts);     glEnableClientState(GL_TEXTURE_COORD_ARRAY);     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);     glPopMatrix();          glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);     [context presentRenderbuffer:GL_RENDERBUFFER_OES]; }```

If you run the code, you will see that the "Front" quad is drawn in the center of the screen and is drawn OVER the floor and ceiling quads. What is going on? Thanks.

Mac users swear by their computers, PC users swear at their computers. ~Unknown

iSayz
Member
Posts: 215
Joined: 2008.06
Post: #11
Right...So it seems that some faces will always be drawn on top of others. I have a simple cube drawn in OGL ES, and some faces are opaque, and others are see-through. I have changed draw orders, normal directions, vertex orders (only to find that VBOs are the only way to draw in OGL ES) and still these faces are transparent when other faces are behind them. What is happening?

Mac users swear by their computers, PC users swear at their computers. ~Unknown

iSayz
Moderator
Posts: 3,591
Joined: 2003.06
Post: #12
Talyn Wrote:(only to find that VBOs are the only way to draw in OGL ES)

That's not true at all. You don't have to draw using VBOs.

Did you remember to glEnable(GL_DEPTH_TEST)? Did you remember to also clear the depth buffer?

BTW: quick glance at your code shows that you're enabling client state every time. You don't need to do that. Once a state is set, it stays set until you disable it.
Member
Posts: 215
Joined: 2008.06
Post: #13
AnotherJake Wrote:That's not true at all. You don't have to draw using VBOs.

Did you remember to glEnable(GL_DEPTH_TEST)? Did you remember to also clear the depth buffer?

BTW: quick glance at your code shows that you're enabling client state every time. You don't need to do that. Once a state is set, it stays set until you disable it.

It's true that I did no enable depth testing or clear the depth_buffer_bit. However, upon doing so, it has not changed anything. Thanks for the reminder on the client state. It's hard to keep track of what stays on and what doesn't in between calls. Any idea what's going on?

EDIT: Returned to old code and now it's doing some pretty funky stuff. Get back to you when I've straightened things out.

Mac users swear by their computers, PC users swear at their computers. ~Unknown

iSayz
Member
Posts: 215
Joined: 2008.06
Post: #14
AnotherJake Wrote:That's not true at all. You don't have to draw using VBOs.

Did you remember to glEnable(GL_DEPTH_TEST)? Did you remember to also clear the depth buffer?

BTW: quick glance at your code shows that you're enabling client state every time. You don't need to do that. Once a state is set, it stays set until you disable it.

Alright, so now with depth testing on, my ceiling and floor quads extend ad infinitum into the distance. Here's the new code:

Code:
```const GLfloat squareVertices[] = {         -0.5f, 0.0f, -0.5f,         0.5f, 0.0f,  -0.5f,         -0.5f, 0.0f,  0.5f,         0.5f, 0.0f,  0.5f,     };          /**     const GLubyte squareColors[] = {         255, 255,   0, 255,         0,   255, 255, 255,         0,     0,   0,   0,         255,   0, 255, 255,     };      */          const GLfloat squareTextureVerts[] =     {         0.0f, 0.0f,         1.0f, 0.0f,         0.0f, 1.0f,         1.0f, 1.0f     };          [EAGLContext setCurrentContext:context];          glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);     glViewport(0, 0, backingWidth, backingHeight);          glMatrixMode(GL_PROJECTION);     glLoadIdentity();     glOrthof(-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f);     glMatrixMode(GL_MODELVIEW);          glClearColor(0.5f, 0.5f, 0.5f, 1.0f);     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);          glEnable(GL_DEPTH_TEST);          glEnable(GL_TEXTURE_2D);     glBindTexture(GL_TEXTURE_2D, texture);          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);          //Bottom     glPushMatrix();     glTranslatef(0.0f, -0.5f, 0.0f);     glRotatef(26.565f, -1.0f, 0.0f, 0.0f);     glRotatef(45.0f, 0.0f, 1.0f, 0.0f);     glVertexPointer(3, GL_FLOAT, 0, squareVertices);     glEnableClientState(GL_VERTEX_ARRAY);     glTexCoordPointer(2, GL_FLOAT, 0, squareTextureVerts);     glEnableClientState(GL_TEXTURE_COORD_ARRAY);     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);     glPopMatrix();          //Top     glPushMatrix();     glTranslatef(0.0f, 0.5f, 0.0f);     glRotatef(26.565f, -1.0f, 0.0f, 0.0f);     glRotatef(45.0f, 0.0f, 1.0f, 0.0f);     glVertexPointer(3, GL_FLOAT, 0, squareVertices);     glEnableClientState(GL_VERTEX_ARRAY);     glTexCoordPointer(2, GL_FLOAT, 0, squareTextureVerts);     glEnableClientState(GL_TEXTURE_COORD_ARRAY);     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);     glPopMatrix();          glDisable(GL_TEXTURE_2D);     glColor4f(1.0f, 0.5f, 0.0f, 1.0f);          //Front     glPushMatrix();          glTranslatef(0.0f, 0.0f, 0.5f);     glRotatef(45.0f, 1.0f, 0.0f, 0.0f);     glRotatef(26.565f, 0.0f, 0.0f, -1.0f);     //glRotatef(45.0f, 1.0f, 0.0f, 0.0f);          glVertexPointer(3, GL_FLOAT, 0, squareVertices);     glEnableClientState(GL_VERTEX_ARRAY);     glTexCoordPointer(2, GL_FLOAT, 0, squareTextureVerts);     glEnableClientState(GL_TEXTURE_COORD_ARRAY);     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);     glPopMatrix();          glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);     [context presentRenderbuffer:GL_RENDERBUFFER_OES];```

Mac users swear by their computers, PC users swear at their computers. ~Unknown

iSayz
Sage
Posts: 1,234
Joined: 2002.10
Post: #15
Did you allocate a depth buffer?