8、事例八: 矩阵堆栈和变换综合
{ 1)、OpenGL的矩阵堆栈指的就是内存中专门用来存放矩阵数据的某块特殊区域。 实际上,在创建、装入、相乘模型变换和投影变换矩阵时,都已用到堆栈操作。一般说来, 矩阵堆栈常用于构造具有继承性的模型,即由一些简单目标构成的复杂模型。 2)、例如,一辆自行车就是由两个轮子、一个三角架及其它一些零部件构成的。它的继承性表现在 当自行车往前走时,首先是前轮旋转,然后整个车身向前平移,接着是后轮旋转,然后整个车身向前 平移,如此进行下去,这样自行车就往前走了。 3)、矩阵堆栈对复杂模型运动过程中的多个变换操作之间的联系与独立十分有利。因为所有矩阵 操作函数如LoadMatrix()、MultMatrix()、LoadIdentity()等只处理当前矩阵或堆栈顶部矩阵,这样 堆栈中下面的其它矩阵就不受影响。堆栈操作函数有以下两个: PushMatrix(void); PopMatrix(void); 第一个函数表示将所有矩阵依次压入堆栈中,顶部矩阵是第二个矩阵的备份;压入的矩阵数不能太多,否则出错。 第二个函数表示弹出堆栈顶部的矩阵,令原第二个矩阵成为顶部矩阵,接受当前操作,故原顶部矩阵 被破坏;当堆栈中仅存一个矩阵时,不能进行弹出操作,否则出错。 我们可以形象地认为glPushMatrix()就是“记住自己在哪”,glPopMatrix()就是“返回自己原来所在地”。 } 这个例子改编自 徐明亮的《OpenGL游戏编程》这本书里的一个例子, 原书例子是C++的代码. namespace sharpGLTest08 { public partial class SharpGLForm : Form { //public float angle; // 机器人绕视点旋转的角度 float[] legAngle = new float[2]; // 腿的当前旋转角度 //float[] armAngle = new float[2]; // 胳膊的当前旋转角度 bool leg1 = true; // 机器人腿的状态,true向前,flase向后 bool leg2 = false; //bool arm1 = true; //bool arm2 = false; private float rotation = 0.0f; public SharpGLForm() { InitializeComponent(); } private void openGLControl_OpenGLDraw(object sender, RenderEventArgs e) { OpenGL gl = openGLControl.OpenGL; gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); gl.LoadIdentity(); //绕y轴旋转 gl.Rotate(rotation, 0.0f, 1.0f, 0.0f); //画网格线 drawGrid(gl); //画机器人 DrawRobot(ref gl, 0, 0, 0); //rtest(ref gl, 0, 0, 0); rotation += 1.0f; } public void DrawRobot(ref OpenGL Gl, float xPos, float yPos, float zPos) { Gl.PushMatrix(); { Gl.Translate(xPos, yPos, zPos); /////绘制各个部分 ////Gl.LoadIdentity(); //DrawHead(ref Gl, 1f, 2f, 0f); // 绘制头部 2*2*2 DrawTorso(ref Gl, 1.5f, 0.0f, 0.0f); //躯干, 3*5*2 //Gl.PushMatrix(); //{ // ///如果胳膊正在向前运动,则递增角度,否则递减角度 // if (arm1) // armAngle[0] = armAngle[0] + 1f; // else // armAngle[0] = armAngle[0] - 1f; // ///如果胳膊达到其最大角度则改变其状态 // if (armAngle[0] >= 15.0f) // arm1 = false; // if (armAngle[0] <= -15.0f) // arm1 = true; // ///平移并旋转后绘制胳膊 // Gl.Translate(0.0f, -0.5f, 0.0f); // Gl.Rotate(armAngle[0], 1.0f, 0.0f, 0.0f); // DrawArm(ref Gl, 2.5f, 0.0f, -0.5f); //胳膊1, 1*4*1 //} //Gl.PopMatrix(); //Gl.PushMatrix(); //{ // if (arm2) // armAngle[1] = armAngle[1] + 1f; // else // armAngle[1] = armAngle[1] - 1f; // if (armAngle[1] >= 15.0f) // arm2 = false; // if (armAngle[1] <= -15.0f) // arm2 = true; // Gl.Translate(0.0f, -0.5f, 0.0f); // Gl.Rotate(armAngle[1], 1.0f, 0.0f, 0.0f); // DrawArm(ref Gl, -1.5f, 0.0f, -0.5f); //胳膊2, 1*4*1 //} //Gl.PopMatrix(); //Gl.PushMatrix(); //{ // ///如果腿正在向前运动,则递增角度,否则递减角度 // if (leg1) // legAngle[0] = legAngle[0] + 1f; // else // legAngle[0] = legAngle[0] - 1f; // ///如果腿达到其最大角度则改变其状态 // if (legAngle[0] >= 15.0f) // leg1 = false; // if (legAngle[0] <= -15.0f) // leg1 = true; // ///平移并旋转后绘制胳膊 // Gl.Translate(0.0f, -0.5f, 0.0f); // Gl.Rotate(legAngle[0], 1.0f, 0.0f, 0.0f); // DrawLeg(ref Gl, -0.5f, -5.0f, -0.5f); //腿部1,1*5*1 //} //Gl.PopMatrix(); //Gl.PushMatrix(); //{ // if (leg2) // legAngle[1] = legAngle[1] + 1f; // else // legAngle[1] = legAngle[1] - 1f; // if (legAngle[1] >= 15.0f) // leg2 = false; // if (legAngle[1] <= -15.0f) // leg2 = true; // Gl.Translate(0.0f, -0.5f, 0.0f); // Gl.Rotate(legAngle[1], 1.0f, 0.0f, 0.0f); // DrawLeg(ref Gl, 1.5f, -5.0f, -0.5f); //腿部2, 1*5*1 //} //Gl.PopMatrix(); } Gl.PopMatrix(); } // 绘制头部 void DrawHead(ref OpenGL Gl, float xPos, float yPos, float zPos) { Gl.PushMatrix(); Gl.Color(1.0f, 1.0f, 1.0f); // 白色 Gl.Translate(xPos, yPos, zPos); Gl.Scale(2.0f, 2.0f, 2.0f); //头部是 2x2x2长方体 DrawCube(ref Gl, 0.0f, 0.0f, 0.0f, false); Gl.PopMatrix(); } // 绘制一个手臂 void DrawArm(ref OpenGL Gl, float xPos, float yPos, float zPos) { Gl.PushMatrix(); Gl.Color(1.0f, 0.0f, 0.0f); /**< 红色 */ Gl.Translate(xPos, yPos, zPos); Gl.Scale(1.0f, 4.0f, 1.0f); /**< 手臂是1x4x1的立方体 */ DrawCube(ref Gl, 0.0f, 0.0f, 0.0f, false); Gl.PopMatrix(); } // 绘制机器人的躯干 void DrawTorso(ref OpenGL Gl, float xPos, float yPos, float zPos) { Gl.PushMatrix(); Gl.Color(0.0f, 0.0f, 1.0f); // 蓝色 Gl.Translate(xPos, yPos, zPos); Gl.Scale(3.0f, 5.0f, 2.0f); // 躯干是3x5x2的长方体 DrawCube(ref Gl, 0.0f, 0.0f, 0.0f, false); Gl.PopMatrix(); } // 绘制一条腿 void DrawLeg(ref OpenGL Gl, float xPos, float yPos, float zPos) { Gl.PushMatrix(); Gl.Color(1.0f, 1.0f, 0.0f); /**< 黄色 */ Gl.Translate(xPos, yPos, zPos); Gl.Scale(1.0f, 5.0f, 1.0f); /**< 腿是1x5x1长方体 */ DrawCube(ref Gl, 0.0f, 0.0f, 0.0f, false); Gl.PopMatrix(); } void drawGrid(OpenGL gl) { //绘制过程 gl.PushAttrib(OpenGL.GL_CURRENT_BIT); //保存当前属性 gl.PushMatrix(); //压入堆栈 gl.Translate(0f, -20f, 0f); gl.Color(0f, 0f, 1f); //在X,Z平面上绘制网格 for (float i = -50; i <= 50; i += 1) { //绘制线 gl.Begin(OpenGL.GL_LINES); { if (i == 0) gl.Color(0f, 1f, 0f); else gl.Color(0f, 0f, 1f); //X轴方向 gl.Vertex(-50f, 0f, i); gl.Vertex(50f, 0f, i); //Z轴方向 gl.Vertex(i, 0f, -50f); gl.Vertex(i, 0f, 50f); } gl.End(); } gl.PopMatrix(); gl.PopAttrib(); } internal void DrawCube(ref OpenGL Gl, float xPos, float yPos, float zPos, bool isLine) { Gl.PushMatrix(); Gl.Translate(xPos, yPos, zPos); if (isLine) Gl.Begin(OpenGL.GL_LINE_STRIP); else Gl.Begin(OpenGL.GL_POLYGON); // 顶面 Gl.Vertex(0.0f, 0.0f, 0.0f); Gl.Vertex(0.0f, 0.0f, -1.0f); Gl.Vertex(-1.0f, 0.0f, -1.0f); Gl.Vertex(-1.0f, 0.0f, 0.0f); // 前面 Gl.Vertex(0.0f, 0.0f, 0.0f); Gl.Vertex(-1.0f, 0.0f, 0.0f); Gl.Vertex(-1.0f, -1.0f, 0.0f); Gl.Vertex(0.0f, -1.0f, 0.0f); // 右面 Gl.Vertex(0.0f, 0.0f, 0.0f); Gl.Vertex(0.0f, -1.0f, 0.0f); Gl.Vertex(0.0f, -1.0f, -1.0f); Gl.Vertex(0.0f, 0.0f, -1.0f); // 左面 Gl.Vertex(-1.0f, 0.0f, 0.0f); Gl.Vertex(-1.0f, 0.0f, -1.0f); Gl.Vertex(-1.0f, -1.0f, -1.0f); Gl.Vertex(-1.0f, -1.0f, 0.0f); // 底面 Gl.Vertex(0.0f, 0.0f, 0.0f); Gl.Vertex(0.0f, -1.0f, -1.0f); Gl.Vertex(-1.0f, -1.0f, -1.0f); Gl.Vertex(-1.0f, -1.0f, 0.0f); // 后面 Gl.Vertex(0.0f, 0.0f, 0.0f); Gl.Vertex(-1.0f, 0.0f, -1.0f); Gl.Vertex(-1.0f, -1.0f, -1.0f); Gl.Vertex(0.0f, -1.0f, -1.0f); Gl.End(); Gl.PopMatrix(); } //测试例子 //public void rtest(ref OpenGL gl, float xPos, float yPos, float zPos) //{ // gl.PushMatrix(); // { // gl.Color(1f, 0f, 0f); // gl.Translate(xPos, yPos, zPos); // gl.Scale(2f, 1f, 1f); // gl.Rotate(45, 1f, 0f, 0f); // DrawCube(ref gl, 0, 0, 0, true); // } // gl.PopMatrix(); // gl.PushMatrix(); // { // gl.Color(0f, 1f, 0f); // gl.Translate(xPos - 2f, yPos, zPos); // DrawCube(ref gl, 0, 0, 0, true); // } // gl.PopMatrix(); //} private void openGLControl_OpenGLInitialized(object sender, EventArgs e) { OpenGL gl = openGLControl.OpenGL; gl.ClearColor(0, 0, 0, 0); } private void openGLControl_Resized(object sender, EventArgs e) { OpenGL gl = openGLControl.OpenGL; gl.MatrixMode(OpenGL.GL_PROJECTION); gl.LoadIdentity(); gl.Perspective(60.0f, (double)Width / (double)Height, 0.01, 100.0); gl.LookAt(-5, 5, 15, 0, 0, 0, 0, 1, 0); gl.MatrixMode(OpenGL.GL_MODELVIEW); } } }
我驰骋天下,守你盛世繁华