Download presentation
Presentation is loading. Please wait.
1
第6章 图形几何变换
2
本章目标 学习如何使图形运动 平移变换、旋转变换和放缩 学会复杂变换的分解与合成 学会使用OpenGL的几何变换函数
3
主要内容 数学基础 二维几何变换 齐次坐标 复合变换 其它变换 三维几何变换 图形对象的几何变换 OpenGL的几何变换函数
4
6.1 数学基础 矢量(vector) 连接两个点的有向线段。又称向量 行向量和列向量两种表示 矢量和
5
6.1 数学基础 矢量的数乘 矢量的点积 运算 性质
6
6.1 数学基础 矢量的长度 单位矢量 矢量间的夹角 矢量的叉积 右手法则
7
6.1 数学基础 矩阵(Matrix) m×n 阶矩阵 n阶方阵(m=n) 单位矩阵 n阶方阵,对角线元素为1, 其它元素为0
8
6.1 数学基础 矩阵(续) 行向量与列向量 矩阵的加法 当m=1时,A退化为行向量[a11, a12, …, a1n]
当n=1时, A退化为列向量[a11, a21, …, am1]T 矩阵的加法 A=(aij)m×n,B=(bij) m×n A与B的和记为A+B 性质:结合律和交换律
9
6.1 数学基础 矩阵(续) 矩阵的数乘 矩阵的乘法 性质:结合律和分配律(不满足交换律)
10
6.1 数学基础 矩阵(续) 矩阵的转置 矩阵的逆 n阶方阵A是可逆的,若存在另一个n阶方阵B,使得
AB=BA=In,称B是A的逆阵,记为B=A-1
11
6.2 二维几何变换 平移变换 (translation transformation)
6.2 二维几何变换 平移变换 (translation transformation) 将点P(x, y)在x轴方向、y轴方向分别平移距离tx,ty,得到点P´(x׳, y׳),则 矩阵表示: 记为:T(tx , ty)
12
6.2 二维几何变换 旋转变换(rotation transformation) 如 点P(x, y)的极坐标表示
6.2 二维几何变换 旋转变换(rotation transformation) 如 点P(x, y)的极坐标表示 (r为P 到原点的距离) 绕坐标原点(称为参照点,基准点)旋转角度θ (逆时针为正,顺时针为负)
13
6.2 二维几何变换 旋转变换(续) 记为:R(θ) 矩阵表示为:
14
6.2 二维几何变换 放缩变换(scaling transformation)
6.2 二维几何变换 放缩变换(scaling transformation) 将点P(x, y)在x方向, y方向分别放缩 sx 和 sy 倍,得到点P´(x׳, y׳) 以坐标原点为放缩参照(基准)点 不仅改变了物体的大小和形状,也改变了它离原点的距离 记为:S(sx, sy)
15
6.2 二维几何变换 利用矩阵计算变换后的坐标时,平移、旋转和放缩变换分别为: 运算不统一,如何统一运算?
16
6.3 齐次坐标 为什么需要齐次坐标? 计算多次不同变换时,分别利用矩阵计算各变换导致计算量大 运算表示形式不统一
平移为“+” 旋转和放缩为“·” 统一运算形式后,可以先合成变换运算的矩阵,再作用于图形对象
17
6.3 齐次坐标 定义 Homogeneous Coordinate (x,y)点对应的齐次坐标定义为
18
6.3 齐次坐标 二维变换的矩阵表示 平移变换 旋转变换
19
6.3 齐次坐标 放缩变换 变换具有统一表示形式的优点 便于变换合成 连续变换时,可以先得到变换的矩阵 便于硬件实现
20
6.3 齐次坐标 变换的性质 平移和旋转变换具有可加性 放缩变换具有可乘性
21
6.3 齐次坐标 逆变换 逆平移变换:正平移距离tx,ty 逆旋转变换:旋转角度为θ
22
6.3 齐次坐标 逆放缩变换:放缩系数为sx和sy
23
6.4 复合变换 变换合成 方法:连续变换时,先计算变换矩阵,再计算坐标 优点: (1)提高了对图形依次做多次变换的运算效率
如:图形上有n个顶点Pi,如果依次施加的变换为T,R,那么顶点Pi 变换后的坐标为 每个顶点需要2次矩阵相乘 只需要1次矩阵相乘
24
6.4 复合变换 变换合成 (续) 复合变换 (2)提供构造复杂变换的方法 Composite transformation 多个变换的组合
变换合成 (续) (2)提供构造复杂变换的方法 对图形作较复杂的变换时,不直接去计算这个变换,而是将其先分解成多个基本变换,再合成总的变换 复合变换 Composite transformation 多个变换的组合 可通过单个变换矩阵来计算矩阵乘积
25
复合平移变换 连续平移变换 平移向量为(t1x,t1y)和(t2x,t2y) 点P 经变换为P´,则有 复合矩阵
26
复合旋转变换 连续旋转 P 经连续旋转角度分别为 1 和 2 后 连续旋转具有相加性
27
复合放缩变换 连续放缩 连续放缩因子分别为:(s1x, s1y) 和 (s2x, s2y)
28
6.4.4 二维基准点旋转 关于任意参照点 的旋转变换 步骤:(1)平移对象使参照(基准)点移到原点(2)绕坐标原点旋转(3)平移对象使基准点回到原始位置
29
6.4.5 二维基准点放缩 4.3.2 扫描线算法 关于任意参照点 的放缩变换
关于任意参照点 的放缩变换 步骤:(1)平移对象使基准点与坐标原点重合(2)放缩变换(3)反向平移使得基准点回到初始位置 4.3.2 扫描线算法
30
6.4.6 小结 变换合成时,矩阵相乘的顺序 单次变换:列向量表示点 复合变换:先作用的放在连乘的右端,后作用的放在连 乘的左端
点表示成行向量呢?
31
6.5 其它变换 对称变换(反射变换、镜像变换:reflection) 关于 x 轴的对称变换 关于 y 轴的对称变换
32
6.5 其它变换 关于任意轴的对称变换 平移(tx, ty)使l 过坐标原点,记为T1 旋转,记R1 对称, 记SYx 旋转-,记 R2
6.5 其它变换 关于任意轴的对称变换 平移(tx, ty)使l 过坐标原点,记为T1 旋转,记R1 对称, 记SYx 旋转-,记 R2 平移(-tx, -ty), 记T2 总变换:T2•R2 • SYx•R1 •T1
33
6.5 其它变换 错切变换(shear) 依赖轴:坐标保持不变的坐标轴,又称参考轴 方向轴:余下的坐标轴 1、以y 轴为依赖轴的错切变换
6.5 其它变换 错切变换(shear) 依赖轴:坐标保持不变的坐标轴,又称参考轴 方向轴:余下的坐标轴 1、以y 轴为依赖轴的错切变换 (1)以 y = 0为参考轴(坐标保持不变) shx为沿x轴移动的距离
34
6.5 其它变换 (2)以 y = yref 为参考轴 x׳ = x + shx ( y – yref) y׳ = y
35
6.5 其它变换 2、以x轴为依赖轴的错切变换
36
6.5 其它变换 仿射变换 affine transformation 二维线性变换的一般形式 特点:保持平行线间的平行关系
6.5 其它变换 仿射变换 affine transformation 二维线性变换的一般形式 平移,旋转,放缩,对称和错切是特例 特点:保持平行线间的平行关系
37
6.5 其它变换 例:证明二维复合变换的矩阵总能表示为: 证明:
38
6.6 三维几何变换 三维齐次坐标 右手坐标系 (x, y, z)点对应的齐次坐标为 标准齐次坐标(x, y, z, 1) 旋转方向
6.6 三维几何变换 三维齐次坐标 (x, y, z)点对应的齐次坐标为 标准齐次坐标(x, y, z, 1) 右手坐标系 旋转方向 当拇指与坐标轴同向时, 四指所指方向为绕该轴的 正旋转方向
39
6.6 三维几何变换 平移变换 位移量:(tx, ty , tz) 放缩变换 参照点为坐标原点
40
6.6 三维几何变换 旋转变换 绕x轴 绕y轴 y x z
41
6.6 三维几何变换 绕z轴 错切变换 以z为依赖轴 y x z
42
6.6 三维几何变换 对称变换 关于坐标平面 xy 的对称变换 其它坐标平面类似
43
6.6 三维几何变换 三维几何变换的一般形式 (1)前三行和前三列对应旋转和放缩变换 (2)第四列的前三个元素对应平移变换
6.6 三维几何变换 三维几何变换的一般形式 (1)前三行和前三列对应旋转和放缩变换 (2)第四列的前三个元素对应平移变换 (3)第四行前三个元素对应投影变换
44
6.6 三维几何变换 思考题:绕任意轴旋转 思路:将矢量 P1P2 变换后与坐标轴重合,再用基本旋转变换实现旋转,再逆变换到原位置 步骤:
6.6 三维几何变换 思考题:绕任意轴旋转 思路:将矢量 P1P2 变换后与坐标轴重合,再用基本旋转变换实现旋转,再逆变换到原位置 步骤: 先平移,将 P1 平移到坐标原点 绕 y 和 z 轴旋转使矢量 P1P2 与 x 轴重和 。。。 α β
45
6.7 图形对象的几何变换 图形对象 方法 前提 点,线段,多边形,圆,字符 先生成点集,再对其中的点进行变换 对参数变换
6.7 图形对象的几何变换 图形对象 点,线段,多边形,圆,字符 方法 先生成点集,再对其中的点进行变换 运算量大 对参数变换 线段:两个端点 多边形:各顶点 圆:圆心和半径 前提 图形对象的几何表示是否发生变化?
46
6.8 OpenGL几何变换函数 说明 基本几何变换函数 在核心库中,每种几何变换是一个独立的函数 所有变换都是在三维坐标系中定义
平移函数:glTranslate{fd}(tx, ty, tz) 对二维变换而言,取tz=0 旋转函数:glRotate{fd}(theta, vx, vy, vz) 向量(vx, vy, vz)为通过坐标原点旋转轴 theta为旋转角的度数 放缩函数:glScale{fd}(sx, sy, sz) 相对坐标原点的缩放 当参数为负时,相对于平面反射变换
47
6.8 OpenGL几何变换函数 例程序 6-1 注意: 几何变换矩阵只有1个 void display (void) {
glColor3f (0.0, 0.0, 1.0); glRecti (20, 50, 100, 80); glColor3f (1.0, 0.0, 0.0); glTranslatef (-120.0, -40.0, 0.0); glRecti (20, 50, 100, 80); glLoadIdentity ( ); glColor3f (1.0, 0.0, 1.0); glRotatef (135.0, 0.0, 0.0, 1.0);glRecti (20, 50, 100, 80); glLoadIdentity ( ); glColor3f ( 0.0, 1.0,0.0); glScalef (0.5, -1.0, 1.0); glRecti (20, 50, 100, 80); glColor3f(0,0,0); glLoadIdentity ( ); glBegin(GL_LINES); glVertex2i(0,-Y/2+5); glVertex2i(0,Y/2-5); glVertex2i(X/2-5,0); glVertex2i(-X/2+5,0); glEnd(); glutSwapBuffers(); } 例程序 6-1 注意: 几何变换矩阵只有1个
48
6.8 OpenGL几何变换函数 例6-1(续) #include <gl/glut.h>
#include <stdlib.h> #include <math.h> int X=0,Y=0; void Reshape(int width, int height) { glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(-width/2, width/2, -height/2, height/2); glMatrixMode(GL_MODELVIEW);//定义模型观察变换矩阵 glClear (GL_COLOR_BUFFER_BIT); X=width, Y=height; } 例6-1(续) void init (void) { glClearColor (1.0, 1.0, 1.0, 0.0); glMatrixMode(GL_PROJECTION); gluOrtho2D(0.0, 250.0, 0.0, 250.0); }
49
6.8 OpenGL几何变换函数 例6-1(续) int main(int argc, char** argv) {
glutInit(&argc, argv); glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize (250, 250); glutInitWindowPosition (300, 300); glutCreateWindow ("Transformation"); init (); glutDisplayFunc(display); glutReshapeFunc(Reshape); glutMainLoop(); return 0; }
50
6.8 OpenGL几何变换函数 矩阵操作 矩阵栈 模型观察矩阵:glMatrixMode(GL_MODELVIEW)
建立当前观察矩阵 还有两种方式:纹理和颜色模式,默认为观察模式 设置当前矩阵为单位矩阵:glLoadIdentity() 矩阵栈 4种:观察、投影、纹理和颜色 初始状态下,每栈仅包含一单位栈 压栈:glPushMatrix() 出栈:glPopMatrix()
51
6.8 OpenGL几何变换函数 例6-2 机器人 手臂 #include <GL/glut.h>
#define BASE_HEIGHT 2.0 #define BASE_RADIUS 1.0 #define LOWER_ARM_HEIGHT 5.0 #define LOWER_ARM_WIDTH 0.5 #define UPPER_ARM_HEIGHT 5.0 #define UPPER_ARM_WIDTH 0.5 typedef float point[3]; GLfloat theta[] = {0.0,0.0,0.0}; GLint axis = 0; GLUquadricObj *p; /* pointer to quadric(二次曲面) object */ void myinit() { glClearColor(1.0, 1.0, 1.0, 1.0); glColor3f(1.0, 0.0, 0.0); p=gluNewQuadric(); /* allocate quadric object */ gluQuadricDrawStyle(p, GLU_LINE); /* render it as wireframe */ } 例6-2 机器人 手臂
52
6.8 OpenGL几何变换函数 例6-2(续) void base()
{ glPushMatrix();/* rotate cylinder to align with y axis */ glRotatef(-90.0, 1.0, 0.0, 0.0);/* cyliner aligned with z axis*/ gluCylinder(p, BASE_RADIUS, BASE_RADIUS, BASE_HEIGHT, 5, 5); glPopMatrix(); } void upper_arm() { glPushMatrix(); glTranslatef(0.0, 0.5*UPPER_ARM_HEIGHT, 0.0); glScalef(UPPER_ARM_WIDTH, UPPER_ARM_HEIGHT, UPPER_ARM_WIDTH); glutWireCube(1.0); glPopMatrix(); void lower_arm() { glPushMatrix(); glTranslatef(0.0, 0.5*LOWER_ARM_HEIGHT, 0.0); glScalef( LOWER_ARM_WIDTH, LOWER_ARM_HEIGHT, LOWER_ARM_WIDTH); glutWireCube(1.0);
53
6.8 OpenGL几何变换函数 void display(void)
{/* Accumulate ModelView Matrix as we traverse tree */ glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); glColor3f(1.0, 0.0, 0.0); glRotatef(theta[0], 0.0, 1.0, 0.0); base(); glTranslatef(0.0, BASE_HEIGHT, 0.0); glRotatef(theta[1], 0.0, 0.0, 1.0); lower_arm(); glTranslatef(0.0, LOWER_ARM_HEIGHT, 0.0); glRotatef(theta[2], 0.0, 0.0, 1.0); upper_arm(); glutSwapBuffers(); } void mouse(int btn, int state, int x, int y) {/* left button increase joint angle, right button decreases it */ if(btn==GLUT_LEFT_BUTTON && state == GLUT_DOWN) {theta[axis] += 5.0; if( theta[axis] > ) theta[axis] -= 360.0;} if(btn==GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {theta[axis] -= 5.0; if( theta[axis] < ) theta[axis] += 360.0;} display();}
54
6.8 OpenGL几何变换函数 void menu(int id)
{/* menu selects which angle to change or whether to quit */ if(id == 1 ) axis=0; if(id == 2) axis=1; if(id == 3 ) axis=2; if(id ==4 ) exit(0); } void myReshape(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-10.0, 10.0, -5.0 * (GLfloat) h / (GLfloat) w, 15.0 * (GLfloat) h / (GLfloat) w, -10.0, 10.0); else glOrtho(-10.0 * (GLfloat) w / (GLfloat) h, 10.0 * (GLfloat) w / (GLfloat) h, -5.0, 15.0, -10.0, 10.0); glMatrixMode(GL_MODELVIEW);
55
6.8 OpenGL几何变换函数 void main(int argc, char **argv) {
glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500); glutCreateWindow("robot"); myinit(); glutReshapeFunc(myReshape); glutDisplayFunc(display); glutMouseFunc(mouse); glutCreateMenu(menu); glutAddMenuEntry("base", 1); glutAddMenuEntry("lower arm", 2); glutAddMenuEntry("upper arm", 3); glutAddMenuEntry("quit", 4); glutAttachMenu(GLUT_MIDDLE_BUTTON); glutMainLoop(); }
56
6.8 OpenGL几何变换函数 使用双缓冲 空闲函数(回调函数) 重绘制函数
以GLUT_DOUBLE为参数调用glutInitDisplayMode,设置双缓存的窗口模式 在显示回调函数的最后调用glutSwapBuffers()函数 空闲函数(回调函数) 定义:如 void spinCube() 功能:程序不受用户干预时执行spinCube()函数 注册:glutIdleFunc(spinCube) (在main函数中调用) 重绘制函数 glutPostRedisplay()
57
6.8 OpenGL几何变换函数 例6-3:旋转的立方体 8个顶点的颜色不同 不停地旋转 鼠标控制改变方向
#include <stdlib.h> #include <GL/glut.h> //定义顶点坐标和颜色 GLfloat vertices[][3] = {{-1.0,-1.0,-1.0},{1.0,-1.0,-1.0}, {1.0,1.0,-1.0}, {-1.0,1.0,-1.0}, {-1.0,-1.0,1.0}, {1.0,-1.0,1.0}, {1.0,1.0,1.0}, {-1.0,1.0,1.0}}; GLfloat colors[][3] = {{0.0,0.0,0.0},{1.0,0.0,0.0}, {1.0,1.0,0.0}, {0.0,1.0,0.0}, {0.0,0.0,1.0}, {1.0,0.0,1.0}, {1.0,1.0,1.0}, {0.0,1.0,1.0}};
58
6.8 OpenGL几何变换函数 void polygon(int a, int b, int c , int d)
{/* draw a polygon via list of vertices */ glBegin(GL_POLYGON); glColor3fv(colors[a]); glVertex3fv(vertices[a]); glColor3fv(colors[b]); glVertex3fv(vertices[b]); glColor3fv(colors[c]); glVertex3fv(vertices[c]); glColor3fv(colors[d]); glVertex3fv(vertices[d]); glEnd(); } void colorcube(void){/* map vertices to faces */ polygon(0,3,2,1); polygon(2,3,7,6); polygon(0,4,7,3); polygon(1,2,6,5); polygon(4,5,6,7); polygon(0,1,5,4);
59
6.8 OpenGL几何变换函数 static GLfloat theta[] = {0.0,0.0,0.0};
static GLint axis = 2; void display(void) { /* display callback, clear frame buffer and z buffer, rotate cube and draw, swap buffers */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glRotatef(theta[0], 1.0, 0.0, 0.0); glRotatef(theta[1], 0.0, 1.0, 0.0); glRotatef(theta[2], 0.0, 0.0, 1.0); colorcube(); glutSwapBuffers(); } void spinCube() {/* Idle callback, spin cube 2 degrees about selected axis */ theta[axis] += 2.0; if( theta[axis] > ) theta[axis] -= 360.0; /* display(); */ glutPostRedisplay();
60
6.8 OpenGL几何变换函数 void mouse(int btn, int state, int x, int y)
{/* mouse callback, selects an axis about which to rotate */ if(btn==GLUT_LEFT_BUTTON && state == GLUT_DOWN) axis = 0; if(btn==GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) axis = 1; if(btn==GLUT_RIGHT_BUTTON && state == GLUT_DOWN) axis = 2; } void myReshape(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-2.0, 2.0, -2.0 * (GLfloat) h / (GLfloat) w, 2.0 * (GLfloat) h / (GLfloat) w, -10.0, 10.0); else glOrtho(-2.0 * (GLfloat) w / (GLfloat) h, 2.0 * (GLfloat) w / (GLfloat) h, -2.0, 2.0, -10.0, 10.0); glMatrixMode(GL_MODELVIEW);
61
6.8 OpenGL几何变换函数 void main (int argc, char **argv) {
/* need both double buffering and z buffer */ glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE |GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500); glutCreateWindow("colorcube"); glutReshapeFunc(myReshape); glutDisplayFunc(display); glutIdleFunc(spinCube); glutMouseFunc(mouse); glEnable(GL_DEPTH_TEST); /* Enable hidden--surface--removal */ glutMainLoop(); }
62
6.8 OpenGL几何变换函数 矩阵运算 获取当前几何变换矩阵glGetDoublev(GL_MODELVIEW_MATRIX, modelview); modelview为16个元素的实数, 如定义为:GLdouble modelview[16]; 可以用来计算图形变换后的坐标(如多边形顶点坐标) 矩阵相乘:当前矩阵与给定矩阵相乘 void glMultMatrixd( const GLdouble *m );
63
小结 5种基本变换 复合变换 OpenGL几何变换的应用 平移,旋转,放缩,对称,错切 矩阵表示 限制条件 分解与复合
能根据具体问题计算复杂变换的矩阵 OpenGL几何变换的应用 变换函数 矩阵
64
作业 1、在坐标系Oxyz中,计算将矢量P(1,1,1)Q(2,2,2)变换到矢量P’(0,0,0) Q’(0,0,1)的变换矩阵
2、假设有一条从 P1 到 P2 的直线上的任意一点 P,证明对任何复合变换,变换后的点 P 都在 P1 和 P2 之间。
65
上机题一:补充 图形元素的平移、缩放和旋转功能 图形拾取 平移(新位置的定义) 缩放(大小缩放,关于图形的重心) 旋转(绕图形的重心)
旋转90度 选中
Similar presentations