0

研究这本书OpenGL SuperBible fram Addison-Wesley,我读到:
每次调用 glTranslate 在模型视图矩阵上都是累积的,
这是什么意思?
这是否意味着例如此代码:

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)不从原点?

这是真的glScalefglRotatef
例如这段代码:

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

首先把一个1x1x1长方体变成一个立方体2x3x4,然后把这个立方体变成6x12x20一个?
最后,这段代码是否意味着绕 x 轴旋转 75 度?

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

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

3 回答 3

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

这就是调用这些函数时幕后发生的所有事情。

于 2013-08-27T18:48:18.290 回答
0

OpenGL 保留了一个模型视图矩阵,该矩阵将顶点的坐标相乘。每次调用平移、旋转、缩放等都会将该矩阵乘以右边。因此,如果您有:

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

结果将首先将您的顶点平移 4,5,0,然后再平移 2,3,0。在内部,这将按如下方式工作: 1. modelView 矩阵将是标识。2. 当前的模型视图矩阵(身份)将与具有值(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 的转换堆栈系统感兴趣。

于 2013-08-27T18:38:07.537 回答
0

请特别注意包含以下描述的 OpenGL API 函数:“does ... to current ...”。

OpenGL 是一个美化的状态机,诸如绑定对象和矩阵(在传统 OpenGL 中)之类的东西会保留它们的状态。当您调用glTranslatef (...)它时,当前矩阵(由矩阵模式和矩阵堆栈的顶部定义)相乘。除非您发出或修改矩阵堆栈,glLoadMatrixf (...)否则每次调用它时都会简单地累积。 将用它的身份替换当前矩阵:glLoadIdentity (...)glTranslatef (...)


glLoadIdentity (...)

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

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

于 2013-08-27T20:06:54.513 回答