Newbie question:Translation and vertex coordinates

Okay, so this is my second time trying graphical programming. The last time was in directx. Since my move to linux, it makes sense for me to now try opengl.

Anyway, I have a problem. What I basically want to do before I go any further is translate, for example, a quad. But I want to translate it after a rotation, but translate it so that it moves along a forward facing line. So if untranslated, say, it would move upward. Then if I rotated it 45 degrees, it would translate along that the same line, rotated 45 degrees. Basically so I have a front end that the quad/triangle moves towards. Imagine asteriods.

I am half-way through taking A-level further-mathematics, so I understand matrices and matrix transformations well (dot and cross product, triple scalar product, eigenvectors, equations, intersections and angles of lines and planes etc).

As a result I would think to approach this by finding the direction of the line I want to move it along (find the difference of two vertices along the line I want to move it along) and multiplying this to move it. However, I don’t know how to access the coordinates of the vertices after translation.

I am starting out from the code::blocks auto-generated project code:

/* A simple program to show how to set up an X window for OpenGL rendering.
 * X86 compilation: gcc -o -L/usr/X11/lib   main main.c -lGL -lX11
 * X64 compilation: gcc -o -L/usr/X11/lib64 main main.c -lGL -lX11
 */
#include <stdio.h>
#include <stdlib.h>

#include <GL/glx.h>    /* this includes the necessary X headers */
#include <GL/gl.h>

#include <X11/X.h>    /* X11 constant (e.g. TrueColor) */
#include <X11/keysym.h>

static int snglBuf[] = {GLX_RGBA, GLX_DEPTH_SIZE, 16, None};
static int dblBuf[]  = {GLX_RGBA, GLX_DEPTH_SIZE, 16, GLX_DOUBLEBUFFER, None};

Display   *dpy;
Window     win;
GLfloat    xAngle = 42.0, yAngle = 82.0, zAngle = 112.0;
GLboolean  doubleBuffer = GL_TRUE;

void fatalError(char *message)
{
  fprintf(stderr, "main: %s
", message);
  exit(1);
}

void redraw(void)
{
  static GLboolean   displayListInited = GL_FALSE;

  if (displayListInited)
  {
    /* if display list already exists, just execute it */
    glCallList(1);
  }
  else
  {
    /* otherwise compile and execute to create the display list */
    glNewList(1, GL_COMPILE_AND_EXECUTE);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    /* front face */
    glBegin(GL_QUADS);
      glColor3f(0.0, 0.7, 0.1);  /* green */
      glVertex3f(-1.0, 1.0, 1.0);
      glVertex3f(1.0, 1.0, 1.0);
      glVertex3f(1.0, -1.0, 1.0);
      glVertex3f(-1.0, -1.0, 1.0);

      /* back face */
      glColor3f(0.9, 1.0, 0.0);  /* yellow */
      glVertex3f(-1.0, 1.0, -1.0);
      glVertex3f(1.0, 1.0, -1.0);
      glVertex3f(1.0, -1.0, -1.0);
      glVertex3f(-1.0, -1.0, -1.0);

      /* top side face */
      glColor3f(0.2, 0.2, 1.0);  /* blue */
      glVertex3f(-1.0, 1.0, 1.0);
      glVertex3f(1.0, 1.0, 1.0);
      glVertex3f(1.0, 1.0, -1.0);
      glVertex3f(-1.0, 1.0, -1.0);

      /* bottom side face */
      glColor3f(0.7, 0.0, 0.1);  /* red */
      glVertex3f(-1.0, -1.0, 1.0);
      glVertex3f(1.0, -1.0, 1.0);
      glVertex3f(1.0, -1.0, -1.0);
      glVertex3f(-1.0, -1.0, -1.0);
    glEnd();
    glEndList();
    displayListInited = GL_TRUE;
  }
  if (doubleBuffer)
    glXSwapBuffers(dpy, win);/* buffer swap does implicit glFlush */
  else
    glFlush();  /* explicit flush for single buffered case */
}

int main(int argc, char **argv)
{
  XVisualInfo         *vi;
  Colormap             cmap;
  XSetWindowAttributes swa;
  GLXContext           cx;
  XEvent               event;
  GLboolean            needRedraw = GL_FALSE, recalcModelView = GL_TRUE;
  int                  dummy;

  /*** (1) open a connection to the X server ***/

  dpy = XOpenDisplay(NULL);
  if (dpy == NULL)
    fatalError("could not open display");

  /*** (2) make sure OpenGL's GLX extension supported ***/

  if(!glXQueryExtension(dpy, &dummy, &dummy))
    fatalError("X server has no OpenGL GLX extension");

  /*** (3) find an appropriate visual ***/

  /* find an OpenGL-capable RGB visual with depth buffer */
  vi = glXChooseVisual(dpy, DefaultScreen(dpy), dblBuf);
  if (vi == NULL)
  {
    vi = glXChooseVisual(dpy, DefaultScreen(dpy), snglBuf);
    if (vi == NULL) fatalError("no RGB visual with depth buffer");
    doubleBuffer = GL_FALSE;
  }
  if(vi->class != TrueColor)
    fatalError("TrueColor visual required for this program");

  /*** (4) create an OpenGL rendering context  ***/

  /* create an OpenGL rendering context */
  cx = glXCreateContext(dpy, vi, /* no shared dlists */ None,
                        /* direct rendering if possible */ GL_TRUE);
  if (cx == NULL)
    fatalError("could not create rendering context");

  /*** (5) create an X window with the selected visual ***/

  /* create an X colormap since probably not using default visual */
  cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), vi->visual, AllocNone);
  swa.colormap = cmap;
  swa.border_pixel = 0;
  swa.event_mask = KeyPressMask    | ExposureMask
                 | ButtonPressMask | StructureNotifyMask;
  win = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 0, 0,
                      300, 300, 0, vi->depth, InputOutput, vi->visual,
                      CWBorderPixel | CWColormap | CWEventMask, &swa);
  XSetStandardProperties(dpy, win, "main", "main", None,
                         argv, argc, NULL);

  /*** (6) bind the rendering context to the window ***/

  glXMakeCurrent(dpy, win, cx);

  /*** (7) request the X window to be displayed on the screen ***/

  XMapWindow(dpy, win);

  /*** (8) configure the OpenGL context for rendering ***/

  glEnable(GL_DEPTH_TEST); /* enable depth buffering */
  glDepthFunc(GL_LESS);    /* pedantic, GL_LESS is the default */
  glClearDepth(1.0);       /* pedantic, 1.0 is the default */

  /* frame buffer clears should be to black */
  glClearColor(0.0, 0.0, 0.0, 0.0);

  /* set up projection transform */
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 10.0);
  /* establish initial viewport */
  /* pedantic, full window size is default viewport */
  glViewport(0, 0, 300, 300);

  printf( "Press left mouse button to rotate around X axis
" );
  printf( "Press middle mouse button to rotate around Y axis
" );
  printf( "Press right mouse button to rotate around Z axis
" );
  printf( "Press ESC to quit the application
" );

  /*** (9) dispatch X events ***/

  while (1)
  {
    do
    {
      XNextEvent(dpy, &event);
      switch (event.type)
      {
        case KeyPress:
        {
          KeySym     keysym;
          XKeyEvent *kevent;
          char       buffer[1];
          /* It is necessary to convert the keycode to a
           * keysym before checking if it is an escape */
          kevent = (XKeyEvent *) &event;
          if (   (XLookupString((XKeyEvent *)&event,buffer,1,&keysym,NULL) == 1)
              && (keysym == (KeySym)XK_Escape) )
            exit(0);
          break;
        }
        case ButtonPress:
          recalcModelView = GL_TRUE;
          switch (event.xbutton.button)
          {
            case 1: xAngle += 10.0;
              break;
            case 2: yAngle += 10.0;
              break;
            case 3: zAngle += 10.0;
              break;
          }
          break;
        case ConfigureNotify:
          glViewport(0, 0, event.xconfigure.width,
                     event.xconfigure.height);
          /* fall through... */
        case Expose:
          needRedraw = GL_TRUE;
          break;
      }
    } while(XPending(dpy)); /* loop to compress events */

    if (recalcModelView)
    {
      glMatrixMode(GL_MODELVIEW);

      /* reset modelview matrix to the identity matrix */
      glLoadIdentity();

      /* move the camera back three units */
      glTranslatef(0.0, 0.0, -3.0);

      /* rotate by X, Y, and Z angles */
      glRotatef(xAngle, 0.1, 0.0, 0.0);
      glRotatef(yAngle, 0.0, 0.1, 0.0);
      glRotatef(zAngle, 0.0, 0.0, 1.0);

      recalcModelView = GL_FALSE;
      needRedraw = GL_TRUE;
    }
    if (needRedraw)
    {
      redraw();
      needRedraw = GL_FALSE;
    }
  }

  return 0;
}

Am I approaching this the right way? If so, how do I access the vertex coordinates? If not, how would I go about this? I can’t seem to find information about this on the net anywhere, websites just list how to make basic transformations.

Thanks in advance,

Ghaz.

“Am I approaching this the right way? If so, how do I access the vertex coordinates? If not, how would I go about this? I can’t seem to find information about this on the net anywhere, websites just list how to make basic transformations.”

you can’t get the transformed vertices with standard OpenGL transformation. you should have your own matrix class for this written in your language which supports all kinds of matrix operations (transform, transpose, inverse, rotate, scale, translate, …). then if you multiply by your matrix on CPU you can read the value out and work with it. besides, all glScale, glRotate calls are deprectated afaik. there are Plenty of matrix classes outthere just taking one from an open-source 3d engine (take care of row-major/column-major).

So basically, don’t use the built in transformations, but create my own?

Why do you want to have access to the vertices coordinates ? You can, of course, but if your model (say your quad) does not have to change (meaning it remains the same quad), but only translate, rotate, you can do it without modifying vertices.

you can do something like that:


//perspective/modelview init
glPushMatrix();
glTranslatef (where.x,where.y,where.z);
glPushMatrix();
glRotatef (angle,axis.x,axis.y,axis.z);
DrawModel();
glPopMatrix();
glPopMatrix();
...

Ah, I See. I have seen something about push and pop before, but I think I misinterpreted its use. I think I understand it now.

I will look into use pop and push, as well as the making matrix classes.

Thanks for the help!

EDIT: I tried the pop and push method, but it yielded the same results as before… If I rotate it, and then translate it, it still translates in a way as if it had not been rotated.

Am I doing something wrong?

So am I doing something wrong? Should this work? Or am I going to have to make my own matrix transformation classes?

don’t do your own, take some existing classes.

Where would I be able to find such classes? Maybe someone knows of a good one?

Also, once I have done my own transformation, how would I then insert these for the object I am transforming?

Sorry to be such a pain in the neck, but I think once I have this down I will be set for a while.

ANY open-source 3D engine would do, google for them.
matrix is set with glLoadMatrixf.

Okay, thanks.

You are making this problem out to be more difficult than it really is.
The pseudo-code required would be something like:

PushMatrix

Rotate
Translate
Draw_Rectangle

PopMatrix

Try switching the order of Rotate and Translate to see what affect it has.

This works :D, although now the cube rotates around the origin of where it was… I think this will be the last obstacle in this whole translation thing.

I can see why it would rotate like that, I just need a way around it.

How about this …

PushMatrix

Rotate (30, 0,1,0) (or something similar)
Translate
Rotate (-30, 0,1,0)
Draw_Rectangle

PopMatrix

Hmm, that does not seem to work… it just moves around in an odd way.

You should not be using the values I have in my Rotate commands. You should be using the values appropriate to your application. I put 0,1,0 just as an example. You said this ‘almost’ worked when you used just one Rotate command, right? Use that same Rotate command (that almost worked) but with negative the rotation angle in the second call to glRotate. That should work IF I understand what you are trying to do.

Honestly,

glPushMatrix();

      glRotatef(yAngle, 0.0, 1, 0.0);

      glTranslatef(amount, 0, 0);

      glRotatef(-yAngle, 0.0, 1, 0.0);

      recalcModelView = GL_FALSE;
      needRedraw = GL_TRUE;
    }
    if (needRedraw)
    {
      redraw();
      needRedraw = GL_FALSE;
    }
  }
glPopMatrix();

does not work ;/

However, I can understand things I have read elsewhere

Translate
Rotate
-Translate

The idea is to get your axis of rotation to the centre of the object, rotate, then move it back again.

However, this moves in an odd way too.

Hmm, I am slowly thinking my way through this one. What I need to do is move the object back to the origin, rotate it, then move it back. I just need to think of a way to implement this.