(每次调用glTranslate都是在modelview矩阵上累积的)这是什么意思以及如何禁用此功能?

时间:2013-08-27 16:05:20

标签: opengl zoom mouseevent glu glrotate

学习本书OpenGL SuperBible fram Addison-Wesley,我读到:
每次调用glTranslate都是在modelview矩阵上累积的
这是什么意思?
这是否意味着例如这段代码:

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

首先将原点上的对象移动到点(2,3,0),然后再将其从(2,3,0)转换为(2+4,3+5,0+0) = (6,8,0)而不是从原点转换为glScalef

glRotatefglScalef(2.0,3.0,4.0); glScalef(3.0,4.0,5.0); 也是如此吗? 例如这段代码:

1x1x1

首先将2x3x4长方体转换为6x12x20立方矩形,然后将此立方矩形转换为glRotatef(30.0,1,0,0); glRotatef(45.0,1,0,0); 一个? 最后,这段代码是否意味着围绕x轴旋转总共75度?

translates will be done from the origin?

最重要的一点:在每次调用这些函数之前调用glLoadIdentity()会取消这些功能吗?
我的意思是你认为这段代码确保每次都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); }

{{1}}

3 个答案:

答案 0 :(得分:1)

glTranslate,glScale,glRotate不会对“对象”起作用(无论对象是什么.OpenGL不知道“对象”是什么,它只知道点,线和三角形。)

在旧的固定功能OpenGL中,你有几个矩阵堆栈。堆栈是一种类似于列表的数据结构,有两个操作push和pop。实际上,您可以从列表中获取它:

stack : list;

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

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

投影和模型视图是最常用的。总是有一个特定的矩阵堆栈可供操作。 glMatrixMode选择哪一个;把它想象成一个参考。

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();
}

OpenGL固定函数矩阵操作函数在有源矩阵堆栈(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;
}

这就是在调用这些功能时幕后发生的一切。

答案 1 :(得分:0)

OpenGl保留了一个modelView矩阵,它乘以顶点的坐标。每次调用翻译,旋转,缩放等都会将此矩阵乘以右侧。所以如果你有:

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

结果将首先将顶点翻译4,5,0然后翻译2,3,0。在内部,这将工作如下: 1. modelView矩阵将是标识。 2.当前的modelView矩阵(标识)将正确乘以平移矩阵,其值为(4,5,0),详细信息请参见(http://en.wikipedia.org/wiki/Translation_%28geometry%29) 3.当前的modelViewmatrix(步骤2中的一个)将正确乘以第二个转换矩阵。

在缩放示例中:

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

相当于首先将1x1x1长方体转换为3x4x5长方体,然后转换为6x12x20。 在旋转情况下,首先旋转45度然后旋转30度。

关于使用glLoadIdentity()的问题,modelView矩阵将独立于矩阵的先前值。

您可能也有兴趣检查opengl的转换堆栈系统。

答案 2 :(得分:0)

特别注意包含描述的OpenGL API函数:“对... 当前 ......”。

OpenGL是一个美化的状态机,绑定对象和矩阵(在传统OpenGL中)之类的东西保持其状态。当您调用glTranslatef (...)时,它会将当前矩阵(由矩阵模式和矩阵堆栈的 top 定义)相乘。除非您发出glLoadMatrixf (...)glLoadIdentity (...)或修改矩阵堆栈,否则glTranslatef (...)只会在您每次调用时累积。


glLoadIdentity (...)会将当前矩阵替换为其标识:

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

如果每帧设置变换矩阵,通常需要执行此操作。否则,所有转换都将相对于先前的状态(尽管有时需要这样做)。