2

I have some 3D models that I render in OpenGL in a 3D space, and I'm experiencing some headaches in moving the 'character' (that is the camera) with rotations and translation inside this world.

I receive the input (ie the coordinates where to move/the dregrees to turn) from some extern event (image a user input or some data from a GPS+compass device) and the kind of event is rotation OR translation .

I've wrote this method to manage these events:

- (void)moveThePlayerPositionTranslatingLat:(double)translatedLat Long:(double)translatedLong andRotating:(double)degrees{

    [super startDrawingFrame];
    if (degrees != 0)
    {
        glRotatef(degrees, 0, 0, 1);
    }

    if (translatedLat != 0)
    {
        glTranslatef(translatedLat, -translatedLong, 0);
    }

   [self redrawView];
}

Then in redrawView I'm actualy drawing the scene and my models. It is something like:

glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

NSInteger nModels = [models count];

for (NSInteger i = 0; i < nModels; i++) 
{
    MD2Object * mdobj = [models objectAtIndex:i];
    glPushMatrix();
    double * deltas = calloc(sizeof(double),2);

    deltas[0] = currentCoords[0] - mdobj.modelPosition[0];
    deltas[1] = currentCoords[1] - mdobj.modelPosition[1];

    glTranslatef(deltas[0], -deltas[1], 0);

    free(deltas);
    [mdobj setupForRenderGL];
    [mdobj renderGL];   
    [mdobj cleanupAfterRenderGL];
    glPopMatrix();

}
[super drawView];

The problem is that when translation an rotation events are called one after the other: for example when I'm rotating incrementally for some iterations (still around the origin) then I translate and finally rotate again but it appears that the last rotation does not occur around the current (translated) position but around the old one (the old origin). I'm well aware that this happens when the order of transformations is inverted, but I believed that after a drawing the new center of the world was given by the translated system.

What am I missing? How can I fix this? (any reference to OpenGL will be appreciated too)

rano
  • 5,616
  • 4
  • 40
  • 66
  • What's the problem when you reverse the order of transformations? – Kos Nov 15 '10 at 20:24
  • if you do first a glTranslatef() then a glRotatef() you will first rotate the object than translate it , otherwise if the order is inverted you will first translate it then rotate it. Have a look at here http://glprogramming.com/red/chapter03.html – rano Nov 15 '10 at 20:28

2 Answers2

1

It sounds like you have a couple of things that are happening here:

The first is that you need to be aware that rotations occur about the origin. So when you translate then rotate, you are not rotating about what you think is the origin, but the new origin which is T-10 (the origin transformed by the inverse of your translation).

Second, you're making things quite a bit harder than you really need. What you might want to consider instead is to use gluLookAt. You essentially give it a position within your scene and a point in your scene to look at and an 'up' vector and it will set up the scene properly. To use it properly, keep track of where you camera is located, call that vector p, and a vector n (for normal ... indicates the direction you're looking) and u (your up vector). It will make things easier for more advanced features if n and u are orthonormal vectors (i.e. they are orthoginal to each other and have unit length). If you do this, you can compute r = n x u, (your 'right' vector), which will be a normal vector orthoginal to the other two. You then 'look at' p+n and provide the u as the up vector.

Ideally, your n, u and r have some canonical form, for instance:

n = <0, 0, 1>
u = <0, 1, 0>
r = <1, 0, 0>

You then incrementally accumulate your rotations and apply them to the canonical for of your oritentation vectors. You can use either Euler Rotations or Quaternion Rotations to accumulate your rotations (I've come to really appreciate the quaternion approach for a variety of reasons).

andand
  • 17,134
  • 11
  • 53
  • 79
  • Firstly I recognized that I do and additional translation that is not necessary, in fact in the event handler I'm rotating and translating the whole scene (= transforming the view) and in the display mode I'm drawing my objects as if they were in a local coordinates system (calculating the difference from the global player position and theirs and translating by these values). I'd say that if I remove the event one It will behave correctly. – rano Nov 16 '10 at 17:44
1

I would recommend not doing cummulative transformations in the event handler, but internally storing the current values for your transformation and then only transforming once, but I don't know if this is the behaviour that you want.

Pseudocode:

someEvent(lat, long, deg)
{
  currentLat += lat;
  currentLong += long;
  currentDeg += deg;
}

redraw()
{
  glClear()
  glRotatef(currentDeg, 0, 0, 1);
  glTranslatef(currentLat, -currentLong, 0);
  ... // draw stuff
}
Sebastian Negraszus
  • 11,915
  • 7
  • 43
  • 70
  • I see your point it is a way to prevent transformations from overlapping (I guess it would need a glPushMatrix()/glPopMatrix() to isolate each element transformations). By the way if you are talking about performance here, then it is not the case , since at each event I need to redraw the view and the frequency is kept low by using a limited NSOperationQueue – rano Nov 16 '10 at 17:47
  • 1
    Yes, the problem is the overlapping transformations. What you do is something like this: translate a bit, rotate, rotate again, translate, rotate and so on. Each rotation now uses a different rotational center because of the preceding translations. This is, if I get you right, not what you want. So you either have to cummulate the arguments for the transformations and only transform once in the exact order that you want it to be. Or you have to "undo" the previous translations before each rotation (by applying the inverse translation). – Sebastian Negraszus Nov 16 '10 at 18:08