1 // Computer Graphics: HW3
2 // 3D Transformation:
3
4
5 #include <iostream>
6 #include <string>
7 #include <cstdlib>
8 #include <cmath>
9 #include <cstdio>
10 #include <vector>
11 #include <gl/glut.h>
12 #include <iomanip>
13 #include <fstream>
14
15 using namespace std;
16
17 const int dimension = 4;
18 const double PI = acos(-1);
19 const double eps = 0.0000001;
20
21 //定义向量
22 struct vec {
23 float x;
24 float y;
25 float z;
26 vec(float _x=0, float _y=0, float _z=0):x(_x), y(_y), z(_z){}
27 };
28
29 //向量的叉乘并化为单位向量
30 vec cross(vec a, vec b)
31 {
32 vec res;
33 res.x = a.y * b.z - b.y * a.z;
34 res.y = -(a.x * b.z - b.x * a.z);
35 res.z = a.x * b.y - b.x * a.y;
36 float l = sqrt(res.x*res.x+res.y*res.y+res.z*res.z);
37 res.x = res.x / l;
38 res.y = res.y / l;
39 res.z = res.z / l;
40 return res;
41 }
42
43 //定义多边形的点
44 struct poly_point {
45 float x;
46 float y;
47 float z;
48 float w;
49 poly_point(){ x=0; y=0; z=0; w=1;}
50 poly_point(float _x, float _y, float _z, float _w=1){ x=_x; y=_y; z=_z; w=_w;}
51 };
52
53 //定义矩阵用作变换操作
54 struct mat {
55 float m[4][4];
56 mat()
57 {
58 memset(m,0,sizeof(m));
59 m[0][0]=m[1][1]=m[2][2]=m[3][3]=1;
60 }
61 void reset_mat()
62 {
63 memset(m,0,sizeof(m));
64 m[0][0]=m[1][1]=m[2][2]=m[3][3]=1;
65 }
66 };
67
68 //新建各种变换矩阵,初始化为单位矩阵
69 mat T,S,R,Rx,Ry,Rz,Sh,TM, M,GRM,EM,Mirrorx, PM, WTVM;
70
71 //重载*号实现矩阵乘法
72 mat operator * (mat a, mat b)
73 {
74 mat c;
75 memset(c.m,0,sizeof(c.m)); //注意要先初始化为0
76 for(int i=0; i<dimension; i++)
77 for(int j=0; j<dimension; j++)
78 for(int k=0; k<dimension; k++)
79 c.m[i][j] += (a.m[i][k]*b.m[k][j]);
80 return c;
81 }
82
83 //定义矩阵乘以向量
84 poly_point mat_mul_vec(mat t, poly_point pp)
85 {
86 poly_point res;
87 res.x = t.m[0][0]*pp.x+t.m[0][1]*pp.y+t.m[0][2]*pp.z+t.m[0][3]*pp.w;
88 res.y = t.m[1][0]*pp.x+t.m[1][1]*pp.y+t.m[1][2]*pp.z+t.m[1][3]*pp.w;
89 res.z = t.m[2][0]*pp.x+t.m[2][1]*pp.y+t.m[2][2]*pp.z+t.m[2][3]*pp.w;
90 res.w = t.m[3][0]*pp.x+t.m[3][1]*pp.y+t.m[3][2]*pp.z+t.m[3][3]*pp.w;
91 return res;
92 }
93 //输出矩阵用作测试
94 void print_mat(mat M)
95 {
96 for(int i=0; i<dimension; i++)
97 {
98 for(int j=0; j<dimension; j++)
99 printf("%.2lf ", M.m[i][j]);
100 printf("\n");
101 }
102 printf("\n");
103 }
104
105 int num_tm=0; //记录输入object的个数
106 poly_point poly_vertex[10][2000], observe[10][2000]; //保存原来的输入的多边形的点,保存经历所有变换后的点用于输出
107 int poly_face[4000][4]; //保存多边形的面用于画线
108 string file_name; //读取asc文件的文件名
109 float VL,VR,VB,VT; //viewport的坐标
110 float Near, Far, FOV; //求PM投影矩阵用到的参数
111 int height, width, n; //n为多边形组成每个面的点的个数
112 int num_vertex, num_face; //记录输入的多边形的点的个数和面的个数
113 void displayFunc(void);
114 void ReadInput(bool& IsExit);
115
116 //hw3
117 void scale(float sx, float sy, float sz); //scale放缩变换
118 void rotate(float rx, float ry, float rz, int i=0); //rotate旋转变换
119 void translate(float tx, float ty, float tz); //translate平移变换
120 void reset();
121 //获得EM和PM矩阵
122 void observer(float PX, float PY, float PZ, float CX, float CY, float CZ, float Tilt, float Near, float Far, float FOV);
123 void view(float VL, float VR, float VB, float VT); //获得WTVM矩阵
124 void display(); //做observer和viewport变换并画点
125 void read_asc_file(); //读取asc文件
126 void transform(mat t); //输入一个矩阵,对poly_vertex里的每个点做一次变换
127 void projection(float AR, float Near, float Far, float FOV);//投影变换,即获得PM矩阵
128 void per_div(); //perspective divide
129 void transform_observe(mat t); //对observe中的每个点进行矩阵变换
130 void DrawWindow(); //画框框
131 void print_mat(mat t); //输出矩阵测试
132 void print(); //输出点测试
133
134 //hw1中已经实现的函数
135 void drawDot(int x, int y, float r, float g, float b);
136 void drawLine1(int x0, int x1, int y0, int y1, bool xy_interchange);
137 void drawLine2(int x0, int x1, int y0, int y1, bool xy_interchange);
138 void drawLine3(int x0, int x1, int y0, int y1, bool xy_interchange);
139 void drawLine4(int x0, int x1, int y0, int y1, bool xy_interchange);
140 void DrawLines_4(int x1, int y1, int x2, int y2);
141
142 void myKeyboard(unsigned char key, int x, int y)
143 {
144 cout << "KEYYYY" << endl;
145 switch(key) {
146 // Draw dots with 'd' or 'D'
147 case 'q':
148 case 'Q':
149 //glutMouseFunc(Mymouse);
150 exit(0);
151 break;
152 }
153 }
154 void ReadInput(bool& IsExit)
155 {
156 float sx,sy,sz, tx,ty,tz, rx,ry,rz;
157 float PX, PY, PZ, CX, CY, CZ, Tilt;
158 string command,comment;
159 cin>>command;
160 if (command=="scale")
161 {
162 cout<<command<<endl;
163 cin>>sx>>sy>>sz;
164 scale(sx,sy,sz);
165 }
166 else if (command=="rotate")
167 {
168 cout<<command<<endl;
169 cin>>rx>>ry>>rz;
170 rotate(rx,ry,rz,0);
171 }
172 else if (command=="translate")
173 {
174 cout<<command<<endl;
175 cin>>tx>>ty>>tz;
176 translate(tx,ty,tz);
177 }
178 else if (command=="reset")
179 {
180 cout<<command<<endl;
181 //reset();
182 }
183 else if (command=="observer")
184 {
185 cout<<command<<endl;
186 cin>>PX>>PY>>PZ>>CX>>CY>>CZ>>Tilt>>Near>>Far>>FOV;
187 observer(PX,PY,PZ,CX,CY,CZ,Tilt,Near,Far,FOV);
188 }
189 else if (command=="viewport")
190 {
191 cout<<command<<endl;
192 cin>>VL>>VR>>VB>>VT;
193 view(VL,VR,VB,VT);
194 }
195 else if (command=="end")
196 {
197 cout<<command<<endl;
198 IsExit=true;
199 //exit(0);
200 }
201 else if (command=="#")
202 {
203 getline(cin, comment);
204 }
205 else if (command=="display")
206 {
207 cout<<command<<endl;
208 display();
209 }
210 else if (command=="object")
211 {
212 cout<<command<<endl;
213 cin >> file_name;
214 read_asc_file();
215 }
216 }
217
218
219 // Display function
220 void displayFunc(void){
221
222 freopen("test.in", "r", stdin);
223 bool IsExit;
224 IsExit=false;
225 // clear the entire window to the background color
226 glClear(GL_COLOR_BUFFER_BIT);
227 while (!IsExit)
228 {
229 glClearColor(0.0, 0.0, 0.0, 0.0);
230 // redraw();
231 // draw the contents!!! Iterate your object's data structure!
232 // flush the queue to actually paint the dots on the opengl window
233 glFlush();
234 ReadInput(IsExit);
235 }
236 // infile.close();
237 //exit(0);
238 }
239
240
241 // Main
242 void main(int ac, char** av) {
243 //initial();
244
245 int winSizeX, winSizeY;
246 string name;
247
248 if(ac == 3) {
249 winSizeX = atoi(av[1]);
250 winSizeY = atoi(av[2]);
251 // cout<<"Done";
252 }
253 else { // default window size
254 winSizeX = 800;
255 winSizeY = 600;
256
257 }
258
259
260 // cout<<"Please input file name:"<<endl;
261 // cin>>name;
262 // infile.open(name.c_str());
263 // exit(0);
264 // infile.open("inp3.txt");
265 // infile.open(av[1]);
266 width = winSizeX;
267 height = winSizeY;
268
269 // initialize OpenGL utility toolkit (glut)
270 glutInit(&ac, av);
271
272 // single disply and RGB color mapping
273 glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // set display mode
274 glutInitWindowSize(winSizeX, winSizeY); // set window size
275 glutInitWindowPosition(0, 0); // set window position on screen
276 glutCreateWindow("Lab2 Window"); // set window title
277
278 // set up the mouse and keyboard callback functions
279 // register the keyboard action function
280 glutKeyboardFunc(myKeyboard);
281 // displayFunc is called whenever there is a need to redisplay the window,
282 // e.g., when the window is exposed from under another window or when the window is de-iconified
283 glutDisplayFunc(displayFunc); // register the redraw function
284
285 // set background color
286 glClearColor(0.0, 0.0, 0.0, 0.0); // set the background to black
287 glClear(GL_COLOR_BUFFER_BIT); // clear the buffer
288
289 // misc setup
290 glMatrixMode(GL_PROJECTION); // setup coordinate system
291 glLoadIdentity();
292 gluOrtho2D(0, winSizeX, 0, winSizeY);
293 glShadeModel(GL_FLAT);
294 glFlush();
295 glutMainLoop();
296 }
297
298
299 void scale(float sx, float sy, float sz)
300 {
301 S.m[0][0]=sx; S.m[1][1]=sy; S.m[2][2]=sz;
302 TM=S*TM;
303 }
304 void rotate(float rx, float ry, float rz, int i)
305 {
306 if(i == 0)
307 {
308 rx = rx * PI / 180.0; ry = ry * PI / 180.0; rz = rz * PI / 180.0;
309 }
310 Rx.m[1][1]=cos(rx); Rx.m[2][2]=cos(rx); Rx.m[1][2]=-sin(rx); Rx.m[2][1]=sin(rx);
311 Ry.m[0][0]=cos(ry); Ry.m[2][2]=cos(ry); Ry.m[0][2]=sin(ry); Ry.m[2][0]=-sin(ry);
312 Rz.m[0][0]=cos(rz); Rz.m[1][1]=cos(rz); Rz.m[0][1]=-sin(rz); Rz.m[1][0]=sin(rz);
313 R = Rz*Ry*Rz;
314 TM=R*TM;
315 }
316 void translate(float tx, float ty, float tz)
317 {
318 T.m[0][3]=tx; T.m[1][3]=ty; T.m[2][3]=tz;
319 TM=T*TM;
320 }
321 void reset()
322 {
323 /*T.reset_mat(),S.reset_mat(),R.reset_mat(),Rx.reset_mat(),Ry.reset_mat(),Rz.reset_mat(),
324 Sh.reset_mat(),TM.reset_mat(), M.reset_mat(),GRM.reset_mat(),EM.reset_mat(),Mirrorx.reset_mat(),
325 PM.reset_mat(), WTVM.reset_mat();*/
326 for(int j=0; j<num_tm; j++)
327 {
328 for(int i=1; i<=num_vertex; i++)
329 {
330 observe[j][i].x = poly_vertex[j][i].x;
331 observe[j][i].y = poly_vertex[j][i].y;
332 observe[j][i].z = poly_vertex[j][i].z;
333 }
334 }
335
336 }
337 void observer(float PX, float PY, float PZ, float CX, float CY, float CZ, float Tilt, float Near, float Far, float FOV)
338 {
339 //GRM
340 translate(-PX,-PY,-PZ);
341 //print_mat(T);
342 float x = CX-PX;
343 float y = CY-PY;
344 float z = CZ-PZ;
345 //Tilt=Tilt*PI/180.0;
346 float l=sqrt(x*x+y*y+z*z);
347 vec v(x,y,z);
348 vec t(0,1,sin(Tilt*PI/180.0));
349 vec v3;
350 v3.x = v.x/l; v3.y = v.y/l; v3.z = v.z/l;
351 vec v1=cross(v,t);
352 vec v2=cross(v1,v3);
353 GRM.m[0][0]=v1.x; GRM.m[0][1]=v1.y; GRM.m[0][2]=v1.z;
354 GRM.m[1][0]=v2.x; GRM.m[1][1]=v2.y; GRM.m[1][2]=v2.z;
355 GRM.m[2][0]=v3.x; GRM.m[2][1]=v3.y; GRM.m[2][2]=v3.z;
356 //GRM.m[1][2]=-0.71;
357 //float ry = abs(asin(x/sqrt(x*x+y*y+z*z)));
358 /*float ry = abs(asin(x/sqrt(x*x+y*y+z*z)));
359 float rx = atan(y/sqrt(pow(x,2.0)+pow(z,2.0)));
360 float rz = Tilt*PI/180.0;
361
362 rotate(rx,ry,rz,1);
363 print_mat(Ry);
364 print_mat(Rx);
365 print_mat(Rz);
366 Mirrorx.m[0][0]=-1;
367 GRM = Mirrorx*Rz*Rx*Ry;*/
368 //GRM.m[1][1]=0.71;
369 //GRM.m[1][2]=-0.71;
370 //GRM.m[2][1]=-0.71;
371 //GRM.m[2][2]=-0.71;
372 //Mirrorx.m[0][0]=-1;
373 printf("GRM\n");
374 print_mat(GRM);
375 EM = Mirrorx*GRM*T;
376 //print_mat(EM);
377 transform_observe(EM);
378 //print();
379
380 //projection(1.33,Near,Far,FOV);
381 }
382 void view(float VL, float VR, float VB, float VT)
383 {
384 DrawWindow();
385 float WL=-1, WR=1, WB=-1, WT=1;
386 translate(-WL, -WB, 0);
387 WTVM = T * WTVM;
388 scale((VR-VL)/(WR-WL), (VT-VB)/(WT-WB), 1);
389 WTVM = S * WTVM;
390 translate(VL, VB, 0);
391 WTVM = T * WTVM;
392 printf("WTVM\n");
393 print_mat(WTVM);
394 //transform_observe(WTVM);
395
396 }
397 void display()
398 {
399 projection((VR-VL)/(VT-VB),Near,Far,FOV);
400 transform_observe(WTVM);
401 cout << "num_tm: " << num_tm << endl;
402 //cout << num_vertex << " " << num_face << endl;
403 //print();
404 for(int k=0; k<num_tm; k++)
405 {
406 for(int i=0; i<num_face; i++)
407 {
408 for(int j=0; j<n-1; j++)
409 DrawLines_4(observe[k][poly_face[i][j]].x, observe[k][poly_face[i][j]].y, observe[k][poly_face[i][j+1]].x, observe[k][poly_face[i][j+1]].y);
410 DrawLines_4(observe[k][poly_face[i][n-1]].x, observe[k][poly_face[i][n-1]].y, observe[k][poly_face[i][0]].x, observe[k][poly_face[i][0]].y);
411 }
412 }
413 reset();
414 EM.reset_mat();
415 PM.reset_mat();
416 WTVM.reset_mat();
417 }
418 void read_asc_file()
419 {
420 num_tm++;
421 cout << file_name << endl;
422 ifstream fin(file_name);
423 fin >> num_vertex >> num_face;
424 cout << num_vertex << " " << num_face << endl;
425 // read vertex one by one
426 for(int i=1; i<=num_vertex; i++)
427 {
428 fin >> poly_vertex[num_tm-1][i].x >> poly_vertex[num_tm-1][i].y >> poly_vertex[num_tm-1][i].z;
429 }
430 // read face one by one
431 for(int i=0; i<num_face; i++)
432 {
433 fin >> n;
434 for(int j=0; j<n; j++)
435 fin >> poly_face[i][j];
436 }
437
438 transform(TM);//
439 reset();
440 TM.reset_mat();
441
442 //print();
443 }
444
445 void transform(mat t)
446 {
447 for(int i=1; i<=num_vertex; i++)
448 poly_vertex[num_tm-1][i] = mat_mul_vec(t, poly_vertex[num_tm-1][i]);
449 }
450 void transform_observe(mat t)
451 {
452 for(int j=0; j<num_tm; j++)
453 {
454 for(int i=1; i<=num_vertex; i++)
455 observe[j][i] = mat_mul_vec(t, observe[j][i]);
456 }
457 }
458
459 void projection(float AR, float Near, float Far, float FOV)
460 {
461 //PM
462 FOV=FOV*PI/180.0;
463 float Y=Far*tan(FOV);
464 float H=Near*tan(FOV);
465 PM.m[1][1]=AR;
466 PM.m[2][2]=Y/(Y-H)*tan(FOV);
467 PM.m[2][3]=Y*H/(H-Y)*tan(FOV);
468 PM.m[3][2]=tan(FOV);
469 PM.m[3][3]=0;
470 /*PM.m[1][1]=AR;
471 PM.m[2][2]=0.58;
472 PM.m[3][2]=0.58;
473 PM.m[3][3]=0;*
474 PM.m[2][3]=-0.58;*/
475 print_mat(PM);
476 transform_observe(PM);
477
478 per_div(); //
479 }
480
481 void per_div()
482 {
483 for(int j=0; j<num_tm; j++)
484 {
485 for(int i=1; i<=num_vertex; i++)
486 {
487 observe[j][i].x /= observe[j][i].w;
488 observe[j][i].y /= observe[j][i].w;
489 observe[j][i].z /= observe[j][i].w;
490 observe[j][i].w /= observe[j][i].w;
491 }
492 }
493
494 }
495
496 void DrawWindow()
497 {
498 DrawLines_4(VL, VB, VR, VB);
499 DrawLines_4(VR, VB, VR, VT);
500 DrawLines_4(VR, VT, VL, VT);
501 DrawLines_4(VL, VT, VL, VB);
502 }
503
504 void print()
505 {
506 for(int j=0; j<num_tm; j++)
507 {
508 for(int i=1; i<=num_vertex; i++)
509 cout << poly_vertex[j][i].x << " " << poly_vertex[j][i].y << " " << poly_vertex[j][i].z << endl;
510 }
511 }
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548 //////////////////////////////////////////////////////////////////////////////////////hw1///////////////////////////////////////////////////////////
549 void DrawLines_4(int x1, int y1, int x2, int y2) //判断画哪一种线
550 {
551 if(x1 >= x2)
552 {
553 if(y1 >= y2)
554 {
555 swap(x1, x2);
556 swap(y1, y2);
557 if((y2-y1) >= (x2-x1))
558 drawLine2(x1, y1, x2, y2, 1);
559 else
560 drawLine1(x1, y1, x2, y2, 1);
561 }
562 else
563 {
564 if((y2-y1) >= (x1-x2))
565 drawLine3(x1, y1, x2, y2, 1);
566 else
567 drawLine4(x2, y2, x1, y1, 1);
568 }
569 }
570 else
571 {
572 if(y2 >= y1)
573 {
574 if((y2-y1) <= (x2-x1))
575 drawLine1(x1, y1, x2, y2, 1);
576 else
577 drawLine2(x1, y1, x2, y2, 1);
578 }
579 else
580 {
581 if((y1-y2) <= (x2-x1))
582 drawLine4(x1, y1, x2, y2, 1);
583 else
584 drawLine3(x2, y2, x1, y1, 1);
585 }
586 }
587
588 glFlush();
589 }
590
591 // draw a dot at location with integer coordinates (x,y), and with color (r,g,b)
592 void drawDot(int x, int y, float r, float g, float b)
593 {
594 glBegin(GL_POINTS);
595
596 // set the color of dot
597 glColor3f(r, g, b);
598
599 // invert height because the opengl origin is at top-left instead of bottom-left
600 glVertex2i(x , height-y);
601
602 glEnd();
603 }
604
605 // Draw line for dx>0 and dy>0
606 void drawLine1(int x1, int y1, int x2, int y2, bool xy_interchange) //0-45度
607 {
608 //cout << "Drawing Line1!" << endl;
609 int x = x1;
610 int y = y1;
611
612 int a = y2 - y1;
613 int b = x1 - x2;
614 int d = 2 * a + b;
615 int IncE = 2 * a;
616 int IncNE = 2 * (a + b);
617
618 while(x <= x2)
619 {
620 if(d <= 0)
621 {
622 x++;
623 d += IncE;
624 }
625 else
626 {
627 x++;
628 y++;
629 d += IncNE;
630 }
631 drawDot(x, height-y, 0.0, 0.0, 10.0);
632
633 }
634 }
635
636 // Draw line for dx>0 and dy<0
637 void drawLine2(int x1, int y1, int x2, int y2, bool xy_interchange) //45-90度
638 {
639 //cout << "Drawing Line2!" << endl;
640 //转换为0-45度的情况
641 swap(x2, y2);
642 swap(x1, y1);
643
644 int x = x1;
645 int y = y1;
646
647 int a = y2 - y1;
648 int b = x1 - x2;
649 int d = 2 * a + b;
650 int IncE = 2 * a;
651 int IncNE = 2 * (a + b);
652
653 while(x <= x2)
654 {
655 if(d <= 0)
656 {
657 x++;
658 d += IncE;
659 }
660 else
661 {
662 x++;
663 y++;
664 d += IncNE;
665 }
666 drawDot(y, height-x, 0.0, 0.0, 10.0);
667
668 }
669 }
670
671 // Draw line for dx<0 and dy>0
672 void drawLine3(int x1, int y1, int x2, int y2, bool xy_interchange) //90-135度
673 {
674 //cout << "Drawing Line3!" << endl;
675 swap(x2, y2);
676 swap(x1, y1);
677 y1 = -y1;
678 y2 = -y2;
679 int x = x1;
680 int y = y1;
681
682 int a = y2 - y1;
683 int b = x1 - x2;
684 int d = 2 * a + b;
685 int IncE = 2 * a;
686 int IncNE = 2 * (a + b);
687
688 while(x <= x2)
689 {
690 if(d <= 0)
691 {
692 x++;
693 d += IncE;
694 }
695 else
696 {
697 x++;
698 y++;
699 d += IncNE;
700 }
701 drawDot(-y, height-x, 0.0, 0.0, 10.0);
702
703 }
704 }
705
706 // Draw line for dx<0 and dy>0
707 void drawLine4(int x1, int y1, int x2, int y2, bool xy_interchange) //135-180度
708 {
709 //cout << "Drawing Line4!" << endl;
710 y1 = -y1;
711 y2 = -y2;
712 int x = x1;
713 int y = y1;
714
715 int a = y2 - y1;
716 int b = x1 - x2;
717 int d = 2 * a + b;
718 int IncE = 2 * a;
719 int IncNE = 2 * (a + b);
720
721 while(x <= x2)
722 {
723 if(d <= 0)
724 {
725 x++;
726 d += IncE;
727 }
728 else
729 {
730 x++;
731 y++;
732 d += IncNE;
733 }
734 drawDot(x, height+y, 0.0, 0.0, 10.0);
735
736 }
737 }