SharpGL学习笔记(二) 模型变换(几何变换)
(二) 模型变换
模形变换就是指的在世界坐标系中(world space)做“移动”,“旋转", "缩放"三种操作。
首先要说明的,在Opengl中,是用4x4矩阵进行坐标变换,OpenGL的4x4矩阵是按列排列的,就像下面这样。
所谓的模型变换,就是对这个矩阵进行变换。
描述三维世界你就得先设计三维模形。 在设计三维模形的时候,它是们于模形坐标系中的,最终它会放置到世界坐标系统中,如果这个模形设计时处理的好的话,放到世界坐标系中时默认就是模形的中心定位于世界坐标系统的中心处。
这里有一个延伸的知识点:模形放置到世界坐标系时中心不位于世界坐标系中心处,是怎么回事?有什么后果? 这个以后我们会做一个扩展性的讨论。
上面说的是导入其它设计软件制作的模形,比如3dsMax制作的模形的情况。如果我们自己用代码画的模形,自然是默认就位于世界坐标系统的中心。
这个世界坐标系,就像下图一样:
X轴箭头方向为正,反过来为负
Y轴箭头方向为正,反过来为负
Z轴箭头方向正好指向我们的眼睛,因此图上只是个小点,看不见,它负方向向屏幕里面。
而下图中的三维体的中心就刚好们于这个世界坐标系的中心。
下面的演示代码在世界坐标系统中画出一个三角形,再对它做一些变换操作。
1 using System; 2 using System.Windows.Forms; 3 using SharpGL; 4 5 namespace blankTest 6 { 7 public partial class Form1 : Form 8 { 9 private int mtype = 0; 10 public Form1() 11 { 12 InitializeComponent(); 13 14 } 15 16 private void Form1_Load(object sender, EventArgs e) 17 { 18 19 } 20 21 private void openGLControl1_OpenGLInitialized(object sender, EventArgs e) 22 { 23 24 } 25 26 private void openGLControl1_Resize(object sender, EventArgs e) 27 { 28 29 } 30 31 private void openGLControl1_OpenGLDraw(object sender, PaintEventArgs e) 32 { 33 SharpGL.OpenGL gl = this.openGLControl1.OpenGL; 34 35 gl.ClearColor(0, 0, 0, 1); 36 gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); 37 38 switch (mtype) 39 { 40 case 0: 41 translateSample(gl); 42 break; 43 case 1: 44 rotateSample(gl); 45 break; 46 case 2: 47 scaleSample(gl); 48 break; 49 } 50 51 gl.Finish(); 52 gl.Flush(); 53 } 54 55 private void scaleSample(SharpGL.OpenGL gl) 56 { 57 gl.LoadIdentity(); 58 gl.Scale(1f, 1f, 1f); 59 gl.Translate(0, 0, -9f); 60 drawPT(gl); 61 62 gl.LoadIdentity(); 63 gl.Scale(5f, 1f, 1f); 64 gl.Translate(0, 1, -9f); 65 drawPT(gl); 66 } 67 68 private void rotateSample(SharpGL.OpenGL gl) 69 { 70 gl.LoadIdentity(); 71 gl.Rotate(0,0, 45); 72 gl.Translate(0, 0, -8f); 73 drawPT(gl); 74 75 gl.Rotate(0, 0, 45); 76 gl.Translate(-1, 1,0f); 77 drawPT(gl); 78 } 79 80 private void translateSample(SharpGL.OpenGL gl) 81 { 82 gl.LoadIdentity(); 83 gl.Translate(0f, 0f, -3f); 84 drawPT(gl); 85 86 gl.LoadIdentity(); 87 gl.Translate(0f, 1f, -3f); 88 drawPT(gl); 89 } 90 91 private void drawPT(SharpGL.OpenGL gl) 92 { 93 gl.PointSize(5f); 94 gl.Begin(OpenGL.GL_TRIANGLES); 95 { 96 gl.Vertex(0.0f, 0f, 0.0f); 97 gl.Vertex(-1.0f, -1f, 0.0f); 98 gl.Vertex(1.0f, -1f, 0.0f); 99 } 100 gl.End(); 101 } 102 103 private void btnTranslate_Click(object sender, EventArgs e) 104 { 105 switch (((Button)sender).Name) 106 { 107 case "btnTranslate": 108 mtype = 0; 109 break; 110 case "btnRotate": 111 mtype = 1; 112 break; 113 case "btnScale": 114 mtype = 2; 115 break; 116 } 117 } 118 119 } 120 }
三个函数translateSample(), rotateSample(),scaleSample() 分别演示”平移“,”旋转“,”缩放”。
我们来谈谈一些重点的地方:
在“平移”函数中,如果没有gl.LoadIdentity()函数复位坐标系统到原点位置,那么执行结果会不同,第二条gl.Translate(0f,1f,-3f)将会是相对于上一条gl.Translate的位置(0f,0f,-3f)移动。
而每次绘制三角形之前做一次gl.LoadIdentity(), 相当于每次绘图时的中心点坐标都从原点算起。
private void translateSample(SharpGL.OpenGL gl) { gl.LoadIdentity(); gl.Translate(0f, 0f, -3f); drawPT(gl); gl.LoadIdentity(); gl.Translate(0f, 1f, -3f); drawPT(gl); }
gl.Translate中的Z轴设置为0,则物体不可见,因为这时候画出来的三角形,贴着世界坐标系的Z轴。就像你的眼睛贴跟它零距离一般。
你可以想象成摄像机位于世界坐标系统(0,0,0), 走向Z轴的负方向。
为了说明白这点,博主画了个示意图如下:
图中的栅格面就代表了世界坐标系平面,两条相互垂直的粗黑线就是世界坐标系的XY轴, 你的眼睛会正对着这个世界坐标系平面看.
现在三维box的底面(红色面)正好贴在世界坐标系的Z轴为0的深度上。相当于你的眼睛跟物体零距离. 因此你得把这个Box向Z轴的负方向走上-1个或者更多个,才可以看见这个Box.
这段程序的运行效果如下:
平移
旋转
缩放
原创文章,出自"博客园, 猪悟能'S博客" : http://www.cnblogs.com/hackpig/