(每次调用 glTranslate 在模型视图矩阵上都是累积的)这是啥意思以及如何禁用此功能?
Posted
技术标签:
【中文标题】(每次调用 glTranslate 在模型视图矩阵上都是累积的)这是啥意思以及如何禁用此功能?【英文标题】:(each call to glTranslate is cumulative on the modelview matrix) what does it mean and how to disable this feature?(每次调用 glTranslate 在模型视图矩阵上都是累积的)这是什么意思以及如何禁用此功能? 【发布时间】:2013-08-27 16:05:20 【问题描述】:学习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)
,而不是再次从原点?
glScalef
和 glRotatef
也是这样吗?
例如这段代码:
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);
【问题讨论】:
【参考方案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;
这就是调用这些函数时幕后发生的所有事情。
【讨论】:
【参考方案2】:OpenGl 保留一个模型视图矩阵,该矩阵将您的顶点坐标相乘。每次调用平移、旋转、缩放等都会将该矩阵乘以右边。所以如果你有:
glLoadIdentity();
glTranslatef(2.0,3.0,0);
glTranslatef(4.0,5.0,0);
结果将首先将您的顶点平移 4,5,0,然后再平移 2,3,0。在内部,这将按如下方式工作: 1.模型视图矩阵将是身份。 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的转换堆栈系统。
【讨论】:
【参考方案3】:特别注意包含以下描述的 OpenGL API 函数:“does ... to the current ...”。
OpenGL 是一个美化的状态机,诸如绑定对象和矩阵(在旧版 OpenGL 中)之类的东西会保留它们的状态。当您调用 glTranslatef (...)
时,它会乘以当前矩阵(由矩阵模式和矩阵堆栈的 top 定义)。除非您发出glLoadMatrixf (...)
、glLoadIdentity (...)
或修改矩阵堆栈,否则glTranslatef (...)
将在您每次调用时简单地累加。
glLoadIdentity (...)
将用它的身份替换 当前 矩阵:
1, 0, 0, 0
0, 1, 0, 0
0, 0, 1, 0
0, 0, 0, 1
如果您每帧都设置变换矩阵,通常需要您执行此操作。否则,您的所有转换都将与之前的状态相关(尽管有时这是需要的)。
【讨论】:
以上是关于(每次调用 glTranslate 在模型视图矩阵上都是累积的)这是啥意思以及如何禁用此功能?的主要内容,如果未能解决你的问题,请参考以下文章