GL.PushMatrix()和GL.PopMatrix()
https://blog.csdn.net/tyxkzzf/article/details/40907273
OpenGL有三个矩阵堆栈,分别是GL_MODELVIEW(模型视图矩阵堆栈)、GL_PROJECTION(投影矩阵堆栈)、GL_TEXTURE(纹理矩阵堆栈),用法和普通堆栈一样;
这里我们只讲模型视图矩阵堆栈,OpenGL提供了相应的接口:glPushMatirx()和glPopMatrix()。
这个模型视图矩阵堆栈是干嘛用的呢?我们在三维空间中绘制模型,大部分时候需要对模型进行移动、旋转、缩放操作,其实OpenGL移动的不是模型,而是坐标系(效果是一样的啦,就比如你坐在车上,跟你并排的还有一辆车,都是静止不动的,这时候你倒车的效果和旁边那辆车前进的效果是不是一样的)。但是,但空间中有多个模型的时候,这个时候,问题来了,我们怎么确定每个模型都绘制在预期的位置呢?
比如,我们想要绘制太阳系,中间是太阳,静止不动,地球围绕太阳旋转,月亮围绕地球旋转,如下图所示的情景:
image我们首先将坐标系移动到太阳的位置,绘制太阳,再将坐标系移动到地球的位置,绘制地球,然后将坐标系移动到月亮的位置,绘制月亮;如果还有金星、木星、火星呢,他们也都是以太阳为中心旋转,这样子,我们可以绘制完月亮之后再将坐标系回退到绘制地球的时候的坐标系,移动相应的位置,绘制金星,然后再回退或者移动新位置绘制木星。。。。。。这样的操作不但麻烦,而且容易出错(麻烦的东西都比较容易出错,所以要简洁),那怎么办最好呢,其实就是绘制地球、金星、木星、火星等的时候以太阳为坐标原点,在绘制地球之前先把当前的模型视图矩阵压入堆栈中保存下来(glPushMatirx),这样你在进行变换就不会影响到堆栈中的矩阵,这个时候将坐标系移动到地球的位置绘制地球,绘制完成之后将模型视图矩阵堆栈中的栈顶矩阵(就是我们刚才保存的矩阵)弹出(glPopMatrix),恢复原来的坐标系,再压入堆栈,绘制金星,再弹出。。。。。。
可以使用嵌套,即:
绘制太阳
压栈
(栈顶矩阵为太阳对应的模型视图矩阵)
移动坐标系到地球位置
绘制地球
压栈(这里就嵌套了)
(栈顶矩阵为地球地球对应的模型视图矩阵)
移动坐标系到月亮的位置
绘制月亮
压栈(嵌套又见嵌套)
(栈顶局长为月亮对应的模型视图矩阵)
移动坐标系到月亮的月亮(虚构)的位置
绘制月亮的月亮
出栈
(栈顶矩阵恢复为地球地球对应的模型视图矩阵,这时可以绘制第二个月亮了)
出栈
(栈顶矩阵恢复为太阳对应的模型视图矩阵,这时可以绘制金星、木星、火星等等了)
出栈
(栈顶为最初的模型视图矩阵,这时可以绘制太阳2,太阳3.。。。。。。太阳9,后羿射日前)
具体代码为(代码只实现了绘制两个月亮,也是嵌套,没有那么多,原理是一样的)
[cpp] view plaincopy
<embed id="ZeroClipboardMovie_1" src="https://csdnimg.cn/public/highlighter/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="16" height="16" name="ZeroClipboardMovie_1" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=1&width=16&height=16" wmode="transparent" style="box-sizing: border-box; outline: 0px; word-break: break-all;">
<embed id="ZeroClipboardMovie_2" src="https://csdnimg.cn/public/highlighter/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="16" height="16" name="ZeroClipboardMovie_2" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=2&width=16&height=16" wmode="transparent" style="box-sizing: border-box; outline: 0px; word-break: break-all;">
-
// Called to draw scene
-
void RenderScene(void)
-
{
-
// Earth and Moon angle of revolution
-
static float fMoonRot = 0.0f;
-
static float fEarthRot = 0.0f;
-
// Clear the window with current clearing color
-
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
// Save the matrix state and do the rotations
-
glMatrixMode(GL_MODELVIEW);
-
glPushMatrix();
-
// Translate the whole scene out and into view
-
glTranslatef(0.0f, 0.0f, -300.0f);
-
// Set material color, Red
-
// Sun
-
glDisable(GL_LIGHTING);
-
glColor3ub(255, 255, 0);
-
glutSolidSphere(15.0f, 30, 17);
-
glEnable(GL_LIGHTING);
-
// Move the light after we draw the sun!
-
glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
-
// Rotate coordinate system
-
glRotatef(fEarthRot, 0.0f, 1.0f, 0.0f);
-
// Draw the Earth
-
glColor3ub(0,0,255);
-
glTranslatef(105.0f,0.0f,0.0f);
-
glutSolidSphere(15.0f, 30, 17);
-
glPushMatrix();
-
// Rotate from Earth based coordinates and draw Moon
-
glColor3ub(200,200,200);
-
glRotatef(fMoonRot,0.0f, 1.0f, 0.0f);
-
glTranslatef(30.0f, 0.0f, 0.0f);
-
fMoonRot+= 15.0f;
-
if(fMoonRot > 360.0f)
-
fMoonRot = 0.0f;
-
glutSolidSphere(6.0f, 30, 17);
-
glPopMatrix();
-
glColor3ub(100, 250, 0);
-
glRotatef(fMoonRot, 1.0f, 0.0f, 0.0f);
-
glTranslatef(0.0f, 20.0f, 0.0f);
-
glutSolidSphere(6.0f, 30, 17);
-
// Restore the matrix state
-
glPopMatrix(); // Modelview matrix
-
// Step earth orbit 5 degrees
-
fEarthRot += 5.0f;
-
if(fEarthRot > 360.0f)
-
fEarthRot = 0.0f;
-
// Show the image
-
glutSwapBuffers();
-
}
实现效果图:
image image image image[图片上传失败...(image-3bf0d9-1530004894909)]
不过需要注意的是,模型视图矩阵堆栈最大为32个,Windows平台,有数量限制,超出的话将会报错。