cg作业.docx
- 文档编号:8685377
- 上传时间:2023-02-01
- 格式:DOCX
- 页数:14
- 大小:98.09KB
cg作业.docx
《cg作业.docx》由会员分享,可在线阅读,更多相关《cg作业.docx(14页珍藏版)》请在冰豆网上搜索。
cg作业
Transformation(包括比例,对称,错切,平移,旋转)
程序实例
对一个三维的六方体图形进行绕x轴旋转45度变换。
具体操作:
(1)、输入维数为3;
(2)、输入顶点数为6;
(3)、输入各个坐标:
(0,0,0),(0,1,0),(1,0,0),(0,0,1)(0,1,1)(1,1,1);
(4)、输入变换模式:
此例是旋转,输入5;
(5)、输入旋转轴,此处输入1;
(6)、输入旋转度数:
45。
最后回车得到结果。
Transformation源程序如下
#include
#include
#defineN50
#defineM3.14159265
voiderwei();
voidsanwei();
voidmain()
{intw;printf("请输入是几维图形变换:
二维
(2)或三维(3):
scanf("%d",&w);
if(w==2)erwei();
else
if(w==3)sanwei();
}
voiderwei()
{floata[3][3]={{1,0,0},{0,1,0},{0,0,1}};
intii,k,h;");
floatb[N][2];
printf("请输入图形定点个数:
);
scanf("%d",&k);
printf("请输入顶点坐标:
\n");
for(ii=0;ii scanf("%f,%f",&b[ii][0], &b[ii][1]); printf("请输入变换模式: 比例 (1),对称 (2),错切(3),平移(4),旋转(5): ");scanf("%d",&h); if(h==1) {intm,n;printf("请输入比例因子(x,y): "); scanf("%d,%d",&m,&n); a[0][0]=m;a[1][1]=n; } Else if(h==2) {intch; printf("请输入对称轴: x (1)或y (2): "); scanf("%d",&ch); if(ch==1)a[1][1]=-1; if(ch==2)a[0][0]=-1;} else if(h==3) {intr;floatf; printf("请输入错切轴x (1)或y (2)和错切因子a(b): "); scanf("%d,%f",&r,&f);if(r==1)a[1][0]=f;"); if(r==2)a[0][1]=f; } Else if(h==4) {floati,j;printf("请输入平移坐标(x,y): "); scanf("%f,%f",&i,&j);a[2][0]=i;a[2][1]=j;} else if(h==5) {floatg;printf("请输入旋转角度(度): "); scanf("%f",&g); g=M*g/180; a[0][0]=cos(g);a[0][1]=sin(g);a[1][0]=-sin(g);a[1][1]=cos(g);} printf("经过变换后的坐标为: \n"); for(ii=0;ii printf("%.2f,%.2f\n",b[ii][0]*a[0][0]+b[ii][1]*a[1][0]+a[2][0],b[ii][0]*a[0][1]+b[ii][1]*a[1][1]+a[2][1]);} voidsanwei() {floata[4][4]={{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}}; floatc[N][3],x1,y1,z1;inth,q,jj;printf("请输入三维图形的顶点个数: "); scanf("%d",&q); printf("请输入顶点坐标: \n"); for(jj=0;jj scanf("%f,%f,%f",&c[jj][0],&c[jj][1],&c[jj][2]); printf("请输入变换模式: 比例 (1),对称 (2),错切(3),平移(4),旋转(5): "); scanf("%d",&h);if(h==1) {intl,m,n; printf("请输入比例因子(x,y,z): "); scanf("%d,%d,%d",&l,&m,&n);a[0][0]=l;a[1][1]=m;a[2][2]=n;} else if(h==2) {intch;printf("请输入对称面: xy (1),yz (2),zx(3): "); scanf("%d",&ch);if(ch==1) a[2][2]=-1;if(ch==2)a[0][0]=-1; if(ch==3)a[1][1]=-1;} else if(h==3) {intstr;floato,p;printf("请输入错切面: xy (1),yz (2),zx(3): "); scanf("%d",&str);printf("请输入错切因子(a,b): scanf("%f,%f",&o,&p); if(str==1) {a[1][0]=o;a[2][0]=p;a[0][1]=o;a[2][1]=p;} If(str==2) {a[0][1]=o;a[2][1]=p;a[0][2]=o;a[1][2]=p;} if(str==3) {a[1][0]=o;a[2][0]=p;a[0][2]=o;a[1][2]=p;} } "); Else if(h==4) {floatr,s,t; printf("请输入平移坐标(x,y,z): "); scanf("%f,%f,%f",&r,&s,&t);a[3][0]=r;a[3][1]=s;a[3][2]=t;} else if(h==5) {inte;floatdu;printf("请输入旋转轴,x轴 (1),y轴 (2),z轴(3): "); scanf("%d",&e); printf("请输入旋转角度(度): scanf("%f",&du);"); du=M*du/180; if(e==1) {a[1][1]=cos(du);a[2][1]=-sin(du);a[1][2]=sin(du);a[2][2]=cos(du);} if(e==2){a[0][0]=cos(du);a[2][0]=-sin(du);a[0][2]=sin(du);a[2][2]=cos(du);} if(e==3){a[0][0]=cos(du);a[1][0]=-sin(du);a[0][1]=sin(du);a[1][1]=cos(du);}} printf("经变换后坐标为: \n"); for(jj=0;jj {x1=c[jj][0]*a[0][0]+c[jj][1]*a[1][0]+c[jj][2]*a[2][0]+a[3][0]; y1=c[jj][0]*a[0][1]+c[jj][1]*a[1][1]+c[jj][2]*a[2][1]+a[3][1]; z1=c[jj][0]*a[0][2]+c[jj][1]*a[1][2]+c[jj][2]*a[2][2]+a[3][2]; printf("%.2f,%.2f,%.2f\n",x1,y1,z1); } } 其中程序中由黄色标记部分即体现齐次坐标思想 在齐次坐标系中,n维空间的位置矢量,用n+1维矢量表示,即二维空间的位置矢量用三维矢量表示。 一个二维位置矢量[xy]用齐次坐标表示即为 [xyh],其中的h为附加坐标,是一个不为零的参数。 一个二维点的齐次坐标表示不是唯一的,如二维点[2010]可以有[20101],[40202],[60403],…等无穷组齐次坐标。 通过对齐次坐标的规范化,即用各坐标分别除以附加坐标,得到一个规范化 坐标[xy1],也就是将h转化为1。 通过二维点的齐次坐标表示,把二维图形的点集矩阵扩充为n×3阶矩阵。 这样,点集矩阵就可以同变换矩阵进行乘法运算了: (2)、二维齐次变换矩阵 为了使二维变换矩阵具有更多的功能,可将3×2阶变换矩阵进一步扩充为3×3阶矩阵,其各元素的功能和几何意义各不相同,可以分割成四块: 2×2阶矩阵 可以实现图形的比例、对称、错切、旋转等变换;1×2阶矩阵[lm]可以实现图形的平移变换其中 ;2×1阶矩阵[pq]T可以实现图形的透视变换;而[s]可以实现图形的全比例变换。 Bezier程序 /*程序实现根据鼠标输入的点进行Bezier曲线的绘制,程序中鼠标 *输入点的个数是可以手动改动的,此程序中输入点的最大值设置为. *同时,程序实现了键盘的交互,用来控制程序运行过程中的退出、重画等 */ #include intW,H;//屏幕的大小 intN=-1;//贝赛尔曲线的幂次 GLfloatBfunc[15]={0.0};//Bernstein多项式的值的数组 GLfloatpoint[15][2]={0.0};//存储控制点的坐标 voidInit() { //设置清除颜色为白色 glClearColor(1.0f,1.0f,1.0f,1.0f); } voidChangeSize(intw,inth) { GLfloatnRange=1.0f; if(h==0)h=1; glViewport(0,0,w,h); W=w; H=h; glMatrixMode(GL_PROJECTION); glLoadIdentity(); //设置修剪空间 if(w<=h) glOrtho(0.0,0.0,-nRange*h/w,nRange*h/w,0.0,0.0); else glOrtho(-nRange*w/h,nRange*w/h,0.0,0.0,0.0,0.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } voidBezier() { inti,j,t; GLfloatu; //使用的绘制点坐标 GLfloatDPoint1[2]; GLfloatDPoint2[2]; //先将第一个控制点赋给第二个点,为后面的循环做准备 for(i=0;i<2;i++) DPoint2[i]=point[0][i]; glClear(GL_COLOR_BUFFER_BIT); //设置控制点的颜色 glColor3f(1.0f,0.0f,0.0f); //设置控制点的大小 glPointSize(5); //绘制控制点 glBegin(GL_POINTS); for(i=0;i<=N;i++) { glVertex2fv(point[i]); } glEnd(); //设置连接控制点线的颜色 glColor3f(0.0f,0.0f,0.0f); //设置连线的宽度 glLineWidth(3); //绘制连线 glBegin(GL_LINE_STRIP); for(i=0;i<=N;i++) glVertex2fv(point[i]); glEnd(); //设置Bezier曲线的颜色 glColor3f(1.0f,0.0f,0.0f); //设置线宽 glLineWidth (2); for(i=0;i<=1000;i++) { //获得u值 u=i/1000.0; //初始化Bfunc数组 for(t=0;t<=N;t++) Bfunc[t]=1.0; //第一个点的坐标等于第二个点的坐标,方便下面的绘制 DPoint1[0]=DPoint2[0]; DPoint1[1]=DPoint2[1]; //将第二个坐标的x,y设置为 DPoint2[0]=0.0; DPoint2[1]=0.0; //循环、递推计算Bezier基函数的值 for(j=0;j<=N;j++) { if(j==0) { //V0处的Bezier基函数 Bfunc[j]=1; for(t=N;t>j;t--) Bfunc[j]=Bfunc[j]*(1-u); } else { if(i! =1000) Bfunc[j]=(1.0*(N-j+1)/j)*(u/(1-u))*Bfunc[j-1]; else { //Bfunc[N]处的Bezier基函数 if(j==N) for(t=0;t Bfunc[j]=Bfunc[j]*u; else Bfunc[j]=0.0; } } //获得第二个点的坐标值 DPoint2[0]=DPoint2[0]+Bfunc[j]*point[j][0]; DPoint2[1]=DPoint2[1]+Bfunc[j]*point[j][1]; } //连接两点 if(N>=1) { glBegin(GL_LINES); glVertex2fv(DPoint1); glVertex2fv(DPoint2); glEnd(); } } glFlush(); } //鼠标事件获得控制点的坐标 voidInitMouse(intbutton,intstate,intx,inty) { //如果不是点击鼠标左键的状态,则不获得坐标值 if(button! =GLUT_LEFT_BUTTON||state! =GLUT_DOWN) return; if(N<14) { N++; //获得鼠标点击的坐标 point[N][0]=(2.0*x)/(float)(W-1)-1.0; point[N][1]=(2.0*(H-y))/(float)(H)-1.0; //重绘 glutPostRedisplay(); } } //键盘响应 voidkeyboard(unsignedcharkey,intx,inty) { switch(key) { //退出运行系统 case'q': case'Q': exit(0); break; //重画曲线 case'c': case'C': N=0; glutPostRedisplay(); break; //刷新 case'e': case'E': glutPostRedisplay(); break; } } voidmain(intargc,char*argv[]) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowPosition(50,100); glutInitWindowSize(800,600); glutCreateWindow("Bezier曲线绘制"); glutReshapeFunc(ChangeSize); Init(); glutDisplayFunc(Bezier); glutMouseFunc(InitMouse); glutKeyboardFunc(keyboard); glutMainLoop(); } 程序流程图 其中被黄色标记的部分体现了 德卡斯特里奥算法的思想。 德卡斯特里奥算法可以计算贝塞尔曲线上的点C(u),u∈[0,1]。 因此,通过给定一组u的值,便可以计算出贝塞尔曲线上的坐标序列,从而绘制出贝塞尔曲线。 德卡斯特里奥算法的基础就是在向量AB上选择一个点C,使得C分向量AB为u: 1-u(也就是∣AC∣: ∣AB∣=u)。 给定点A、B的坐标以及u(u∈[0,1])的值,点C的坐标便为: C=A+(B-A)*u=(1-u)*A+B*u。 定义贝塞尔曲线的控制点Pi编号为0i,其中,0表示是第0次迭代。 当第一、二、三……次迭代时,0将会被1、2、3……替换。 德卡斯特里奥算法的思想如下: 为了计算n次贝塞尔曲线上的点C(u), u∈[0,1],首先将控制点连接形成一条折线00-01-02……0(n-1)-0n。 利用上述方法,计算出折线中每条线段0j-0(j+1)上的一个点1j,使得点1j分该线段的比为u: 1-u。 然后在折线10-11-……-1(n-1)上递归调用该算法,以此类推。 最终,求得最后一个点n0。 德卡斯特里奥证明了,点n0一定是曲线上的点。 如上图,曲线控制点是00、01、02、03、04、05。 线段00-01上取点10,10分该线段的比为u: 1-u,类似地取点11、12、13、14,然后第二次迭代在线段10-11上取点20,点20分该线段的比为u: 1-u,类似地取点21、22、23。 然后进行下一次迭代,依次类推,直到最后在线段40-41上取点50,50是最终惟一的点,也是在曲线上的点。 上述直观的算法描述可以表达成一个计算方法。 首先,将所有给定的控制点排列成一列,在上图中,即为最左边的一列。 每一对相邻的控制点可以伸出两个箭头,分别指向右下方和右上方。 在相邻箭头的交叉处,生成一个新的控制点。 例如,控制点ij和i(j+1)生成新的控制点(i+1)j。 指向右下方的箭头表示乘以(1-u),指向右上方的箭头表示乘以u。 因此,通过第0列,可以求出第1列,然后求出第2列……,最终,在n次迭代后,可以到达惟一的一个点n0,这个点就是曲线上的点。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- cg 作业
![提示](https://static.bdocx.com/images/bang_tan.gif)