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 }
时间: 2024-10-23 16:51:48