(each call to glTranslate is cumulative on the modelview matrix) what does it mean and how to disable this feature?

833 views Asked by At

Studying the book OpenGL SuperBible fram Addison-Wesley, I read:
each call to glTranslate is cumulative on the modelview matrix
what does it mean?
Does it mean that for example this code:

glTranslatef(2.0,3.0,0);
glTranslatef(4.0,5.0,0);  

first moves an object that is on the origin to the point (2,3,0) and then translates it from the (2,3,0) to (2+4,3+5,0+0) = (6,8,0) not from the origin again?

Is this true about glScalef and glRotatef too?
for example this code:

glScalef(2.0,3.0,4.0);
glScalef(3.0,4.0,5.0);  

first turn a 1x1x1 cuboid to a 2x3x4 cubic rectangle and then turns this cubic rectangle to a 6x12x20 one?
And at last, Does this code mean that a total 75 degrees rotation around the x-axis?

glRotatef(30.0,1,0,0);
glRotatef(45.0,1,0,0);  

the most importantant: Does calling glLoadIdentity() before each call of these functions cancels these feature?
I mean Do you think this code assures that each time translates will be done from the origin? , scale changes will be done from the initial state?

void COpenGLControl::ZoomToFullExtent()
{
float zoom1 = (float)oglWindowWidth/(float)ImageWidth;
float zoom2 = (float)oglWindowHeight/(float)ImageHeight;
m_fZoom = min(zoom1,zoom2);
m_fZoomInverse = 1/m_fZoom;
m_fPosX = 0;
m_fPosY = 0;
OnDraw(NULL);
}  

void COpenGLControl::FixedZoomIn()
{
m_fZoom = 2*m_fZoom;
m_fZoomInverse = 1/m_fZoom;
OnDraw(NULL);
}

void COpenGLControl::FixedZoomOut()
{
m_fZoom = 0.5*m_fZoom;
m_fZoomInverse = 1/m_fZoom;
OnDraw(NULL);
}

void COpenGLControl::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if (WantToPan)
{
    if (m_fLastX < 0.0f && m_fLastY < 0.0f)
    {
        m_fLastX = (float)point.x;
        m_fLastY = (float)point.y;
    }
    diffX = (int)(point.x - m_fLastX);
    diffY = (int)(point.y - m_fLastY);
    m_fLastX = (float)point.x;
    m_fLastY = (float)point.y;
    if (nFlags & MK_MBUTTON)
    {
        m_fPosX += (float)0.2f*m_fZoomInverse*diffX;
        m_fPosY += (float)0.2f*m_fZoomInverse*diffY;
    }
    OnDraw(NULL);
}
CWnd::OnMouseMove(nFlags, point);
}  

void COpenGLControl::OnDraw(CDC *pDC)
{
// TODO: Camera controls
wglMakeCurrent(hdc,hrc);
glLoadIdentity();
gluLookAt(0,0,1,0,0,0,0,1,0);
glScalef(m_fZoom,m_fZoom,1.0);
glTranslatef(m_fPosX, m_fPosY, 0.0f);
wglMakeCurrent(NULL, NULL);
}
3

There are 3 answers

0
Andon M. Coleman On

Pay special attention to OpenGL API functions that include the description: "does ... to the current ...".

OpenGL is a glorified state machine, and things like bound objects and matrices (in legacy OpenGL) retain their state. When you make a call to glTranslatef (...) it multiplies the current matrix (defined by the matrix mode and the top of your matrix stack). Unless you issue glLoadMatrixf (...), glLoadIdentity (...) or modify the matrix stack, glTranslatef (...) will simply accumulate everytime you call it.


glLoadIdentity (...) will replace the current matrix with its identity:

    1, 0, 0, 0
    0, 1, 0, 0
    0, 0, 1, 0
    0, 0, 0, 1

If you setup your transform matrices every frame, it is generally required that you do this. Otherwise, all of your transformations will be relative to the previous state (though this is sometimes desired).

0
pabaldonedo On

OpenGl keeps a modelView matrix which multiply the coordinates of your vertices. Every call to translate, rotate, scale etc will multiply this matrix by the right. So if you have:

glLoadIdentity();
glTranslatef(2.0,3.0,0);
glTranslatef(4.0,5.0,0);  

The result will be first translating your vertices by 4,5,0 and then by 2,3,0. Internally, this will work as follows: 1. the modelView matrix will be the identity. 2. the current modelView matrix (the identity) will be right multiplied by the translation matrix with values ( 4, 5, 0) for more details see (http://en.wikipedia.org/wiki/Translation_%28geometry%29) 3. the current modelViewmatrix (the one of step 2) will be right multiplied by the second translation matrix.

In your example of scaling:

glScalef(2.0,3.0,4.0);
glScalef(3.0,4.0,5.0);  

It will be equivalent to first turn the 1x1x1 cuboid into a 3x4x5 cuboid and then into a 6x12x20. In the roation case, first rotate 45 degrees and then 30.

To your question about the use of glLoadIdentity(), the modelView matrix will be the identity independently from the previous value of the matrix.

You may also be interested in checking the transformation stack system of opengl.

0
datenwolf On

glTranslate, glScale, glRotate don't act on "objects" (whatever a object is. OpenGL doesn't know what a "object" is, it only knows points, lines and triangles).

In old fixed function OpenGL you have a couple of matrix stacks. A stack is a data structure similar to a list, with two operations push and pop. You can in fact derive it from a list:

stack : list;

void stack::push() {
    this->append( copy(this->last_element) );
}

void stack::pop() {
    this->drop( this->last_element );
}

Projection and modelview are the most oftenly used ones. There's always one particular matrix stack active for manipulation. glMatrixMode selects which one; think of it as a reference.

stack<mat4x4> modelview;
stack<mat4x4> projection;
stack<mat4x4> *M;

void glMatrixMode(mode) {
    switch(mode) {
    case GL_MODELVIEW:
        M = &modelview; break;

    case GL_PROJECTION:
        M = &projection; break;
    }
}

void glPushMatrix() {
    M->push();
}

void glPopMatrix() {
    M->pop();
}

The OpenGL fixed function matrix manipulation functions act in place on top element of the active matrix stack (M).

void glLoadIdentity() {
    M->last_element = identity_matrix;
}

void glTranslate(x,y,z) {
    /* make a translation matrix and R-multiply in place */
    mat4x4 T = translate_matrix(x,y,z);
    M->last_element = M->last_element * T;
}

void glScale(x,y,z) {
    /* make a scaling matrix and R-multiply in place */
    mat4x4 S = scaling_matrix(x,y,z);
    M->last_element = M->last_element * S;
}

void glRotate(a,x,y,z) {
    /* make a rotation matrix and R-multiply in place */
    mat4x4 R = rotation_matrix(a,x,y,z);
    M->last_element = M->last_element * R;
}

And that's all that's happening behind the curtain when calling those functions.