Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inverting y axis, and setting coordinate system in OpenGL

In OpenGL, I am trying to invert the y axis, and set a specific type of coordinate system just like how Allegro has it. Assuming my window is 640x480, I want the top left of the screen be axis (0, 0), and the bottom right (640, 480). So far, I managed to get the proper coordinate system I want, but I don't know if it is done the proper way. As for flipping the y axis, I was unable to invert it without modifying the coordinate system I currently have. I don't want something hackish only to flip 1 shape. I want it to flip all future shapes I make on the y axis while maintaining the coordinate system. Here is what I have so far.

Initialize:

const GLdouble XSize = 640, YSize = 480;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, XSize, YSize, 0, 1, 1000);
glMatrixMode(GL_MODELVIEW);

Render:

float size = 30;

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0, 0, -500);

glPushMatrix();
glTranslatef(size, size, 0.0f);

glBegin(GL_TRIANGLES);
glColor3f(0.1, 0.3, 0.8);
glVertex3f( 0.0f, size, 0.0f);
glVertex3f(-size,-size, 0.0f);
glVertex3f( size,-size, 0.0f);
glEnd();
glPopMatrix();

Edit:

I figured out that adding glScalef(1, -1, 1); will flip my shape, but I have to include it inside glPushMatrix() of my shapes, and I don't know if this is the proper way to do this or if its a hackish solution.

like image 984
Johnathan Avatar asked May 12 '11 20:05

Johnathan


2 Answers

To change the coordinate system, a scale and a translate are required in that order.

// Initialize OpenGL matrices
void init_gl() {
    const float WIDTH = 640.0f;
    const float HEIGHT = 480.0f;

    const float HALF_WIDTH = WIDTH / 2.0f;
    const float HALF_HEIGHT = HEIGHT / 2.0f;

    // Setup the projection matrix
    glMatrixMode(GL_PROECTION);
    glLoadIDentity();
    glOrtho(0, WIDTH, HEIGHT, 0.0f, 0.0f, 1000.0f);

    // Setup the Allegro-to-view matrix
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(-HALF_WIDTH, HALF_HEIGHT, 0.0f);
    glScalef(1.0f, -1.0f, 1.0f);
}

// Render scene
void render() {
    // Now render using points in Allegro coordinates
    const float size = 30.0f;
    glBegin(GL_TRIANGLES);
    glColor3f(0.1f, 0.3f, 0.8f);
    glVertex3f( 0.0f,  size, 0.0f);
    glVertex3f(-size, -size, 0.0f);
    glVertex3f( size, -size, 0.0f);
    glEnd();
}

Note that glTranslatef comes before glScalef because transformation matrices are multiplied on the right side of the current matrix value. Also, you do not have to set the Allegro-to-view matrix per frame; once during initialization is enough for most use cases. You might, however, push GL_MODELVIEW and apply any model transforms that are necessary.


Here is a conceptual analysis of how this works. The goal is to allow you, the graphics programmer, to specify points using 'Allegro' or desired coordinates, i.e. coordinates where the origin is top-left corner of the orthographic projection (in this case, this relates directly to the screen). To accomplish this, you setup the view matrix GL_MODELVIEW to transform from these desired coordinates to orthographic camera coordinates (also known as view space or eye space).

First, you reorient (scale) the y-axis of desired coordinates to match view coordinates (middle figure). Second, you translate the origin of desired coordinates to match the origin of view coordinates. This translation is made relative to view coordinates (i.e. the origin of view coordinates is half the screen horizontally to the right and half the screen vertically down). This last step is equivalent to transforming points in the opposite direction of the shift.

Symbolically, the scale transforms the point P = (P.x, P.y) to P' = (P.x, -P.y). The translate transforms the point P' to P'' = (P.x - w/2, P.y + h/2) where w is the width of the screen (480px) and h is the height (640px). (Sorry, the final diagram incorrectly switches h and w for P'' because I can't do diagrams on SO very well).

Note that the z-axis points out of the screen since we did not scale it by -1.

The way I prefer to conceptualize changes of coordinate systems (more accurately, change of frames when we include the concept of an origin) is that we're modifying the basis vectors (x, y, etc.) and the origin with subsequent scale, rotation, and translation operations (in that order). This is very similar to the way we conceptualize moving the camera around by applying translations in the opposite direction with which the camera is moving.

Roughly drawn diagram of the two transformations

like image 106
May Oakes Avatar answered Oct 12 '22 23:10

May Oakes


You'd be better off tweaking the projection (think of it as the "camera") in that case.

Check out tzaman's answer here: Modifying OpenGL axis system

like image 37
holtavolt Avatar answered Oct 13 '22 00:10

holtavolt