二维图形学的变换-平移、旋转、缩放 OpenGL
来源:互联网 发布:第一次穿情趣内衣 知乎 编辑:程序博客网 时间:2024/05/05 11:53
这里实现的是多点画多边形,然后把这个多边形进行二维的变换。
首先,多点画多边形,为了方便起见,我直接调用了Opengl的库函数。其次,就是如何进行多边形的二维变换。在这里我有两种方法。第一种是直接根据数学三角等公式推断得到结果。第二种方法是用矩阵相乘的方法。
先讲第一种:
平移
假如我要平移a到b的位置:
那么操作就是:把这个多边形的n个顶点从一个位置移动到另外一个位置,然后重新生成平移后的多边形。(顶点知道了,那么就可以直接重新绘制多边形了)
大致代码就是:
Void translate2D(int x,int y){//x,y表示平移x、y的距离
For(int i=0;i<n;i++){
顶点[i].x=顶点[i].x+x;
顶点[i].y=顶点[i].y+y;
}
DrawPolygon();//这里表示重新绘制多边形
}
旋转(可以绕任意中心点旋转)
旋转原理:我们可以通过应用标准的三角等式得到旋转后的坐标。
根据上图,利用三角形的数学公式可以直接得出旋转后的公式:
伪代码如下:
Void rotate2D(int x,int y,double theta){//x,y为旋转的中心,theta为旋转的角度
For(inti=0;i<n;i++){
顶点[i].x=x+(顶点[i].x-x)*cos(theta)-(顶点[i].y-y)*sin(theta);
顶点[i].y=y+(顶点[i].x-x)*sin(theta)+(顶点[i].y-y)*cos(theta);
}
DrawPolygon();//这里表示重新绘制多边形
}
二维缩放(基于一个固定点缩放)
简单缩放可以直接通过将缩放系数sx,sy与对应x,y坐标相乘:x’=x*sx,y’=y*sy
当然,我们需要在一个固定点进行缩放,那么就需要我们选择一个在缩放变换后不改变位置的点,来控制缩放后对象的位置。
得到的公式则是:
其中sx,sy属于缩放系数。0~1表示缩小,>1表示放大
伪代码:
Void scale2D(int x,int y,float sx,float sy){//x,y表示固定坐标,sx,sy为缩放系数
For(inti=0;i<n;i++){
顶点[i].x=顶点[i].x*sx+x*(1-sx);
顶点[i].y=顶点[i].y*sy+y*(1-sy);
}
DrawPolygon();//这里表示重新绘制多边形
}
第二种方法(矩阵相乘):
二维平移矩阵:
二维旋转矩阵:绕坐标系原点的而为旋转变换方程可以表示成矩阵形式:
x’,y’表示变换后的坐标。
如果要基于某个基准点旋转,则:
1.平移对象使基准点位置移动到坐标原点
2.绕坐标原点旋转
3.平移对象使基准点回到原始位置
矩阵公式则是:
二维缩放矩阵:(也是基于原点)
如何要基于某个固定点进行缩放,那么就需要二维复合变换矩阵。
基于某个固定点缩放原理:其实就是先平移然后再缩放,最后再返回到原点。
于是有:
上述矩阵就是基于某个固定点的缩放。
必须注意的是:复合矩阵求值的顺序一定不能交换,除非某些情况譬如连续两次旋转或者连续两次平移等等。
为什么需要用复合矩阵相乘?而不直接一次一次的变换得到结果呢?
因为直接进行复合矩阵的计算会减少乘法和加法次数。具体详解就不在此叙述。
来看最终完整版代码:
#include<gl/glut.h>#include<iostream>#include<cmath>#include<vector>#pragma comment(linker,"/subsystem:\"Windows\"/entry:\"mainCRTStartup\"")#define PI 3.14159265358//q,w,e,r分别为平移,绘制多边形,旋转,缩放#define TRANSLATE 0#define DRAWPOLYGON 1#define ROTATE 2#define SCALE 3int tran_x,tran_y;int _xtmp,_ytmp;//作为缩放变量用int mode=DRAWPOLYGON;//默认为绘制模式using namespace std;const int winwidth=800;const int winheight=640;struct position{ double x; double y;};typedef GLfloat Matrix3x3[3][3];Matrix3x3 matComposite;//复合矩阵vector<position> xy;position tmp;void DrawPolygon();void dragmouse(int x,int y);void mymouse(int button,int state,int x,int y);void myKeyboard(unsignedchar key,int x,int y);void myKeyboardUp(unsignedchar key,int x,int y);//设置为单位矩阵voidmatrix3x3SetIdentity(Matrix3x3mat){ GLint row,col; for(row=0;row<3;row++){ for(col=0;col<3;col++) mat[row][col]=(row==col); }}void init(){ glClearColor(1.0,1.0,1.0,1.0);//设置绘制窗口颜色为白色 glClear(GL_COLOR_BUFFER_BIT);//清除窗口显示内容 /*设置为投影类型模式和其他观察参数*/ glPointSize(3.0f); glColor3f(1.0,0.0,0.0);//设置颜色为红 glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0,winwidth,winheight,0); matrix3x3SetIdentity(matComposite);} //矩阵相乘void matrixpreMultiply(Matrix3x3m1,Matrix3x3m2){ GLint row,col; Matrix3x3 tmp; for(row=0;row<3;row++){ for(col=0;col<3;col++){ tmp[row][col]=m1[row][0]*m2[0][col]+m1[row][1]* m2[1][col]+m1[row][2]*m2[2][col]; } } for(row=0;row<3;row++){ for(col=0;col<3;col++){ m2[row][col]=tmp[row][col]; } }}//平移void translate2D(GLfloattx,GLfloatty){ Matrix3x3 matTransl; matrix3x3SetIdentity(matTransl);//设置为单位矩阵 matTransl[0][2]=tx; matTransl[1][2]=ty; matrixpreMultiply(matTransl,matComposite); }//旋转void rotate2D(intx,inty,floattheta){ theta=theta/180*PI; Matrix3x3 matRot; matrix3x3SetIdentity(matRot); matRot[0][0]=cos(theta); matRot[0][1]=-sin(theta); matRot[0][2]=x*(1-cos(theta))+y*sin(theta); matRot[1][0]=sin(theta); matRot[1][1]=cos(theta); matRot[1][2]=y*(1-cos(theta))-x*sin(theta); matrixpreMultiply(matRot,matComposite);} //缩放void scale2D(GLfloatsx,GLfloatsy,intx,inty){ Matrix3x3 matScale; matrix3x3SetIdentity(matScale); matScale[0][0]=sx; matScale[0][2]=(1-sx)*x; matScale[1][1]=sy; matScale[1][2]=(1-sy)*y; matrixpreMultiply(matScale,matComposite);}//复合矩阵void transformVerts2D(){ GLfloat tmp; for(int i=0;i<xy.size();i++){ tmp=matComposite[0][0]*xy[i].x+matComposite[0][1]*xy[i].y+matComposite[0][2]; xy[i].y=matComposite[1][0]*xy[i].x+matComposite[1][1]*xy[i].y+matComposite[1][2]; xy[i].x=tmp; } DrawPolygon(); matrix3x3SetIdentity(matComposite);} //绘制多边形void DrawPolygon(){// glEnable(GL_POLYGON_STIPPLE); glPolygonMode(GL_BACK,GL_LINE);//设置反面为线性模式 glPolygonMode(GL_FRONT,GL_LINE);//设置正面为线性模式 glClear(GL_COLOR_BUFFER_BIT);//清除窗口显示内容 glBegin(GL_POLYGON); for(unsignedint i=0;i<xy.size();i++){ glVertex2f(xy[i].x,xy[i].y); } glEnd(); glFlush();} //鼠标拖动void dragmouse(intx,inty){ float ssx=1,ssy=1; switch (mode) { //q,w,e,r case TRANSLATE: translate2D(x-tran_x,y-tran_y); transformVerts2D(); tran_x=x; tran_y=y; break; case DRAWPOLYGON: break; case ROTATE: if(x<=_xtmp&&y>=_ytmp) rotate2D(tran_x,tran_y,-8); else rotate2D(tran_x,tran_y,8); transformVerts2D(); _xtmp=x; _ytmp=y; break; case SCALE: /*不等比例缩放*/ if(x>_xtmp){ ssx+=0.01f; } else if(x<_xtmp&&ssx>0){ ssx-=0.01f; } if(y<_ytmp){ ssy+=0.01f; } else if(y>_ytmp&&ssy>0){ ssy-=0.01f; } /*等比例缩放 if(x<=_xtmp&&y>=_ytmp){ ssx-=0.01f; ssy-=0.01f; }else{ ssx+=0.01f; ssy+=0.01f; }*/ scale2D(ssx,ssy,tran_x,tran_y); transformVerts2D(); _xtmp=x; _ytmp=y; break; default: break; } } //鼠标监听void mymouse(intbutton,intstate,intx,inty){ if(button==GLUT_LEFT_BUTTON &&state==GLUT_DOWN){ switch (mode) { //q,w,e,r case TRANSLATE: tran_x=x; tran_y=y; break; case DRAWPOLYGON: tmp.x=x; tmp.y=y; xy.push_back(tmp); DrawPolygon(); break; case ROTATE: tran_x=x; tran_y=y; _xtmp=x; _ytmp=y; break; case SCALE: tran_x=x; tran_y=y; break; default: break; } } }//键盘监听void myKeyboard(unsignedcharkey,intx,inty){ //清空删除 if(key=='a'){ glClear(GL_COLOR_BUFFER_BIT);//清除窗口显示内容 glFlush(); xy.clear(); } } void myKeyboardUp(unsignedcharkey,intx,inty){ switch (key) { case 'q':mode=TRANSLATE; break; case 'w':mode=DRAWPOLYGON; break; case 'e':mode=ROTATE; break; case 'r':mode=SCALE; break; default: break; }}void myDisplay(){ glFlush();}void mymenu(intid){ if(id==0) mode=0; else if(id==1) mode=1; else if(id==2) mode=2; else if(id==3) mode=3;} int main(intargc,char**argv){ glutInit(&argc,argv);//初始化 glutInitDisplayMode(GLUT_SINGLE |GLUT_RGB);//设置绘制模式 glutInitWindowPosition(500,300); glutInitWindowSize(winwidth,winheight); glutCreateWindow("二维图形的变换");//创建窗口 int id=glutCreateMenu(mymenu); glutAddMenuEntry("平移",0); glutAddMenuEntry("绘制多边形",1); glutAddMenuEntry("旋转",2); glutAddMenuEntry("缩放",3); glutAttachMenu(GLUT_RIGHT_BUTTON); init(); glutDisplayFunc(myDisplay); glutMouseFunc(mymouse);//鼠标监听回调函数 glutMotionFunc(dragmouse);//鼠标拖动 glutKeyboardFunc(myKeyboard);//键盘监听 glutKeyboardUpFunc(myKeyboardUp);//键盘弹起状态 glutMainLoop();}
上述默认是绘制模式,如果需要平移,按一下键盘Q,然后按住鼠标左键拖动就可以平移,旋转,缩放也是一样的道理。
最终结果自己运行去吧~O(∩_∩)O哈哈~
以上代码我用的是VS2012+OpenGL环境运行。可以正确运行。
- 二维图形学的变换-平移、旋转、缩放 OpenGL
- OpenGL坐标变换 平移,缩放与旋转
- 计算机图形学之二维平移旋转缩放代码
- perl-opengl基本图形操作-缩放,二维旋转,二维平移
- openGL 矩阵的旋转-平移-缩放
- [OpenGL] 桌子的平移、旋转和缩放
- 计算机图形学 学习笔记(七):二维图形变换:平移,比例,旋转,坐标变换等
- OpenGL中的平移旋转缩放
- OpenGL之旋转、平移、缩放
- opengl中平移、旋转、缩放
- OpenGL-旋转平移与缩放
- 计算机图形学 几何图形变换算法(缩放、旋转和平移) C语言编写
- 矩阵变换与图片平移,旋转,缩放的原理
- 为什么坐标变换的顺序必须是: 缩放->旋转->平移
- 为什么坐标变换的顺序必须是缩放----旋转---平移
- 【C#/WPF】Image图片的Transform变换:平移、缩放、旋转
- vtkPolyData 的空间变换(平移、旋转、缩放)
- view仿射变换 缩放 旋转 平移
- Linux下最快速共享目录的方法
- 项目管理具体内容
- lintcode,搜索二维矩阵 II
- 比较著名的国外科技网站(推荐)
- Android自定义View的数独游戏
- 二维图形学的变换-平移、旋转、缩放 OpenGL
- 大华视频监控软件
- 建立自己的封装库(三)
- uva 11624 Fire!(bfs)
- leetcode367: Valid Perfect Square
- MySQL技术内幕 InnoDB存储引擎(二)
- ES6 Promise对象的学习笔记
- 第15周OJ-4
- 需求为纲 产品为王 极米担当行业领头羊的秘密