--- tags: c tutor --- # 2021電腦圖學 相關筆記 - [2021電腦圖學](https://hackmd.io/@jsyeh/2021graphics) - [2022電腦圖學](https://hackmd.io/@jsyeh/2022graphics) - [OpenGL範例](https://hackmd.io/@jsyeh/opengl) ## Week17 1. 複習(上週)關節動畫、存讀檔 2. 整學期總複習 3. 主題: 攝影機(沒教到,就不教這部分) 4. 期末作品(約需20小時)第18週展示 5. 檢查Blog, 成績計算 ```C++ #include <GL/glut.h> void display(){ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glutSolidTeapot( 0.3 ); glutSwapBuffers(); } int main( int argc, char ** argv ) { glutInit( &argc, argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_DEPTH); glutCreateWindow("week17 review"); glutDisplayFunc(display); glutMainLoop(); } ``` 放大視窗(預設300x300) 移動視窗(預設會照著前一個位置往下移一點點) ```C++ glutInitWindowSize(500,500); glutInitWindowPosition(700,0); ``` 色彩: glClearColor() glColor3f() ``` void display(){ glClearColor( 1,0,0,0);///用來Clear的Color 用紅色 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f( 1,1,0 ); glutSolidTeapot( 0.3 ); glutSwapBuffers(); } ``` ```C++ #include <GL/glut.h> void display(){ glClearColor( 1,0,0,0);///用來Clear的Color 用紅色 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f( 1,1,0 ); glutSolidTeapot( 0.3 ); glutSwapBuffers(); } int main( int argc, char ** argv ) { glutInit( &argc, argv); glutInitWindowSize(500,500); glutInitWindowPosition(700,200); glutInitDisplayMode(GLUT_DOUBLE|GLUT_DEPTH); glutCreateWindow("week17 review"); glutDisplayFunc(display); glutMainLoop(); } ``` 打光試看看(可從 GLUT 範例拿來用) 打光陣列 ```C++ const GLfloat light_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; const GLfloat light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat light_position[] = { 2.0f, 5.0f, 5.0f, 0.0f }; const GLfloat mat_ambient[] = { 0.7f, 0.7f, 0.7f, 1.0f }; const GLfloat mat_diffuse[] = { 0.8f, 0.8f, 0.8f, 1.0f }; const GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat high_shininess[] = { 100.0f }; ``` 同時要有打光的函式, 在 main()呼叫 ```C++ glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glEnable(GL_LIGHT0); glEnable(GL_NORMALIZE); glEnable(GL_COLOR_MATERIAL); glEnable(GL_LIGHTING); glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess); ``` ## step01 試著整合上面 ```C++ #include <GL/glut.h> void display(){ glClearColor( 1,0,0,0);///用來Clear的Color 用紅色 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f( 1,1,0 ); glutSolidTeapot( 0.3 ); glutSwapBuffers(); } const GLfloat light_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; const GLfloat light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat light_position[] = { 2.0f, 5.0f, -5.0f, 0.0f }; const GLfloat mat_ambient[] = { 0.7f, 0.7f, 0.7f, 1.0f }; const GLfloat mat_diffuse[] = { 0.8f, 0.8f, 0.8f, 1.0f }; const GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat high_shininess[] = { 100.0f }; int main( int argc, char ** argv ) { glutInit( &argc, argv); glutInitWindowSize(300,300); glutInitWindowPosition(700,200); glutInitDisplayMode(GLUT_DOUBLE|GLUT_DEPTH); glutCreateWindow("week17 review"); glutDisplayFunc(display); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glEnable(GL_LIGHT0); glEnable(GL_NORMALIZE); glEnable(GL_COLOR_MATERIAL); glEnable(GL_LIGHTING); glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess); glutMainLoop(); } ``` 解決 T-R-T的問題 先把身體註解掉,T-R-T只留下最下面的T ```C++ void display(){ glClearColor( 1,0,0,0);///用來Clear的Color 用紅色 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glColor3f( 1,1,0 ); //glutSolidTeapot( 0.3 );///身體先註解掉身體,只看手臂 glPushMatrix(); //glTranslatef();///(3)再把轉動中的手臂,掛到肩上 //glRotatef();///(2)再轉動它 glTranslatef(-.3, .1, 0);///(1)移動旋轉中心,放正中心 glutSolidTeapot(0.3);///左手臂 glPopMatrix(); glPopMatrix(); glutSwapBuffers(); } ``` 再把 R弄好, 再把 T 及身體都放出來 ```C++ float angle=90; void display(){ glClearColor( 1,0,0,0);///用來Clear的Color 用紅色 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glColor3f( 1,1,0 ); glutSolidTeapot( 0.3 );///身體先註解掉身體,只看手臂 glPushMatrix(); glTranslatef(-.3, 0, 0);///(3)再把轉動中的手臂,掛到肩上 glRotatef(angle, 0,0,1);///(2)再轉動它 glTranslatef(-.3, .1, 0);///(1)移動旋轉中心,放正中心 glutSolidTeapot(0.3);///左手臂 glPopMatrix(); glPopMatrix(); glutSwapBuffers(); } ``` 接下來要用 mouse motion 讓它可以轉起來 ```C++ float oldX=0; void mouse(int button, int state, int x, int y){ oldX = x; } void motion( int x, int y ){ angle += x-oldX; oldX = x;//小心,不要漏掉了 glutPostRedisplay();///重畫畫面 } ``` ```C++ int main( int argc, char ** argv ) { glutInit( &argc, argv); glutInitWindowSize(300,300); glutInitWindowPosition(700,200); glutInitDisplayMode(GLUT_DOUBLE|GLUT_DEPTH); glutCreateWindow("week17 review"); glutMouseFunc(mouse); glutMotionFunc(motion); glutDisplayFunc(display); //... } ``` ## step02 用 mouse() motion() 讓關節動起來 ```C++ #include <GL/glut.h> float angle=90; float oldX=0; void mouse(int button, int state, int x, int y){ oldX = x; } void motion( int x, int y ){ angle += x-oldX; oldX = x; glutPostRedisplay();///重畫畫面 } void display(){ glClearColor( 1,0,0,0);///用來Clear的Color 用紅色 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glColor3f( 1,1,0 ); glutSolidTeapot( 0.3 );///身體先註解掉身體,只看手臂 glPushMatrix(); glTranslatef(-.3, 0, 0);///(3)再把轉動中的手臂,掛到肩上 glRotatef(angle, 0,0,1);///(2)再轉動它 glTranslatef(-.3, .1, 0);///(1)移動旋轉中心,放正中心 glutSolidTeapot(0.3);///左手臂 glPopMatrix(); glPopMatrix(); glutSwapBuffers(); } const GLfloat light_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; const GLfloat light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat light_position[] = { 2.0f, 5.0f, -5.0f, 0.0f }; const GLfloat mat_ambient[] = { 0.7f, 0.7f, 0.7f, 1.0f }; const GLfloat mat_diffuse[] = { 0.8f, 0.8f, 0.8f, 1.0f }; const GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat high_shininess[] = { 100.0f }; int main( int argc, char ** argv ) { glutInit( &argc, argv); glutInitWindowSize(300,300); glutInitWindowPosition(700,200); glutInitDisplayMode(GLUT_DOUBLE|GLUT_DEPTH); glutCreateWindow("week17 review"); glutMouseFunc(mouse); glutMotionFunc(motion); glutDisplayFunc(display); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glEnable(GL_LIGHT0); glEnable(GL_NORMALIZE); glEnable(GL_COLOR_MATERIAL); glEnable(GL_LIGHTING); glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess); glutMainLoop(); } ``` ## Step03 keyboard() 可切換關節 & 存檔讀檔 ```C++ float angle[20]={};///先都設成0 int angleID=0;///現在要動的關節是誰? void keyboard(unsigned char key, int x, int y){ if(key=='0') angleID=0; if(key=='1') angleID=1; if(key=='2') angleID=2; if(key=='3') angleID=3; if(key=='4') angleID=4; if(key=='5') angleID=5; if(key=='6') angleID=6; }///如果關節很多, 可能要用迴圈來讓程式只要2行 for(int i=0; i<10; i++) ///可能也要用到英文字母 ``` ```C++ int main( int argc, char ** argv ) { glutInit( &argc, argv); glutInitWindowSize(300,300); glutInitWindowPosition(700,200); glutInitDisplayMode(GLUT_DOUBLE|GLUT_DEPTH); glutCreateWindow("week17 review"); glutKeyboardFunc(keyboard);//要有這行, 註冊 keyboard() glutMouseFunc(mouse); glutMotionFunc(motion); glutDisplayFunc(display); ``` ```C++ void motion( int x, int y ){ angle[angleID] += x-oldX;///0: angle[0], 1: angle[1].. oldX = x; glutPostRedisplay();///重畫畫面 } ``` ```C++ void display(){ glClearColor( 1,0,0,0);///用來Clear的Color 用紅色 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glColor3f( 1,1,0 ); glutSolidTeapot( 0.3 );///身體先註解掉身體,只看手臂 glPushMatrix(); glTranslatef(-.3, 0, 0);///(3)再把轉動中的手臂,掛到肩上 glRotatef(angle[0], 0,0,1);///(2)再轉動它 glTranslatef(-.3, .1, 0);///(1)移動旋轉中心,放正中心 glutSolidTeapot(0.3);///左手臂 glPushMatrix(); glTranslatef(-.3, 0, 0);///(3)再把轉動中的手臂,掛到肩上 glRotatef(angle[1], 0,0,1);///(2)再轉動它 glTranslatef(-.3, 0, 0);///(1)移動旋轉中心,放正中心 glutSolidTeapot(0.3);///左手肘 glPopMatrix(); glPopMatrix(); glPopMatrix(); glutSwapBuffers(); } ``` 右半邊,也照著做出來 ```C++ void display(){ glClearColor( 1,0,0,0);///用來Clear的Color 用紅色 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glColor3f( 1,1,0 ); glutSolidTeapot( 0.3 );///身體先註解掉身體,只看手臂 glPushMatrix();///左半邊 glTranslatef(-.3, 0, 0);///(3)再把轉動中的手臂,掛到肩上 glRotatef(angle[0], 0,0,1);///(2)再轉動它 glTranslatef(-.3, .1, 0);///(1)移動旋轉中心,放正中心 glutSolidTeapot(0.3);///左手臂 glPushMatrix(); glTranslatef(-.3, 0, 0);///(3)再把轉動中的手臂,掛到肩上 glRotatef(angle[1], 0,0,1);///(2)再轉動它 glTranslatef(-.3, 0, 0);///(1)移動旋轉中心,放正中心 glutSolidTeapot(0.3);///左手肘 glPopMatrix(); glPopMatrix(); glPushMatrix();///右半邊 glTranslatef(+.3, 0, 0);///(3)再把轉動中的手臂,掛到肩上 glRotatef(angle[2], 0,0,1);///(2)再轉動它 glTranslatef(+.3, .1, 0);///(1)移動旋轉中心,放正中心 glutSolidTeapot(0.3);///右手臂 glPushMatrix(); glTranslatef(+.3, 0, 0);///(3)再把轉動中的手臂,掛到肩上 glRotatef(angle[3], 0,0,1);///(2)再轉動它 glTranslatef(+.3, 0, 0);///(1)移動旋轉中心,放正中心 glutSolidTeapot(0.3);///右手肘 glPopMatrix(); glPopMatrix(); glPopMatrix(); glutSwapBuffers(); } ``` ## step04 存檔、讀檔 ```C++ #include <stdio.h> FILE * fout = NULL; FILE * fin = NULL; ``` ```C++ void keyboard(unsigned char key, int x, int y){ if(key=='0') angleID=0; if(key=='1') angleID=1; if(key=='2') angleID=2; if(key=='3') angleID=3; if(key=='4') angleID=4; if(key=='5') angleID=5; if(key=='6') angleID=6; if(key=='s'){///存檔 if( fout==NULL ) fout = fopen("angle.txt", "w+"); for(int i=0; i<20; i++) fprintf(fout, "%.2f ", angle[i]); fprintf(fout, "\n"); printf("save angle.txt\n"); }else if(key=='r'){///讀檔 (不能和存檔同時做,因angle.txt不能開2次) if( fin==NULL ) fin = fopen("angle.txt", "r"); for(int i=0; i<20; i++) fscanf(fin, "%f", &angle[i]); glutPostRedisplay();///重畫畫面 printf("read angle.txt\n"); } } ``` 完整程式 ```C++ #include <GL/glut.h> #include <stdio.h> FILE * fout = NULL; FILE * fin = NULL; float angle[20]={};///先都設成0 int angleID=0;///現在要動的關節是誰? void keyboard(unsigned char key, int x, int y){ if(key=='0') angleID=0; if(key=='1') angleID=1; if(key=='2') angleID=2; if(key=='3') angleID=3; if(key=='4') angleID=4; if(key=='5') angleID=5; if(key=='6') angleID=6; if(key=='s'){///存檔 if( fout==NULL ) fout = fopen("angle.txt", "w+"); for(int i=0; i<20; i++) fprintf(fout, "%.2f ", angle[i]); fprintf(fout, "\n"); printf("save angle.txt\n"); }else if(key=='r'){///讀檔 (不能和存檔同時做,因angle.txt不能開2次) if( fin==NULL ) fin = fopen("angle.txt", "r"); for(int i=0; i<20; i++) fscanf(fin, "%f", &angle[i]); glutPostRedisplay();///重畫畫面 printf("read angle.txt\n"); } }///如果關節很多, 可能要用迴圈來讓程式只要2行 for(int i=0; i<10; i++) ///可能也要用到英文字母 float oldX=0; void mouse(int button, int state, int x, int y){ oldX = x; } void motion( int x, int y ){ angle[angleID] += x-oldX;///0: angle[0], 1: angle[1].. oldX = x; glutPostRedisplay();///重畫畫面 } void display(){ glClearColor( 1,0,0,0);///用來Clear的Color 用紅色 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glColor3f( 1,1,0 ); glutSolidTeapot( 0.3 );///身體先註解掉身體,只看手臂 glPushMatrix();///左半邊 glTranslatef(-.3, 0, 0);///(3)再把轉動中的手臂,掛到肩上 glRotatef(angle[0], 0,0,1);///(2)再轉動它 glTranslatef(-.3, .1, 0);///(1)移動旋轉中心,放正中心 glutSolidTeapot(0.3);///左手臂 glPushMatrix(); glTranslatef(-.3, 0, 0);///(3)再把轉動中的手臂,掛到肩上 glRotatef(angle[1], 0,0,1);///(2)再轉動它 glTranslatef(-.3, 0, 0);///(1)移動旋轉中心,放正中心 glutSolidTeapot(0.3);///左手肘 glPopMatrix(); glPopMatrix(); glPushMatrix();///右半邊 glTranslatef(+.3, 0, 0);///(3)再把轉動中的手臂,掛到肩上 glRotatef(angle[2], 0,0,1);///(2)再轉動它 glTranslatef(+.3, .1, 0);///(1)移動旋轉中心,放正中心 glutSolidTeapot(0.3);///右手臂 glPushMatrix(); glTranslatef(+.3, 0, 0);///(3)再把轉動中的手臂,掛到肩上 glRotatef(angle[3], 0,0,1);///(2)再轉動它 glTranslatef(+.3, 0, 0);///(1)移動旋轉中心,放正中心 glutSolidTeapot(0.3);///右手肘 glPopMatrix(); glPopMatrix(); glPopMatrix(); glutSwapBuffers(); } const GLfloat light_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; const GLfloat light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat light_position[] = { 2.0f, 5.0f, -5.0f, 0.0f }; const GLfloat mat_ambient[] = { 0.7f, 0.7f, 0.7f, 1.0f }; const GLfloat mat_diffuse[] = { 0.8f, 0.8f, 0.8f, 1.0f }; const GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat high_shininess[] = { 100.0f }; int main( int argc, char ** argv ) { glutInit( &argc, argv); glutInitWindowSize(300,300); glutInitWindowPosition(700,200); glutInitDisplayMode(GLUT_DOUBLE|GLUT_DEPTH); glutCreateWindow("week17 review"); glutKeyboardFunc(keyboard); glutMouseFunc(mouse); glutMotionFunc(motion); glutDisplayFunc(display); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glEnable(GL_LIGHT0); glEnable(GL_NORMALIZE); glEnable(GL_COLOR_MATERIAL); glEnable(GL_LIGHTING); glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess); glutMainLoop(); } ``` ## step05 要做動畫、內插 ```C++ void timer(int t){ glutTimerFunc( 500, timer, t+1); if( fin==NULL ) fin = fopen("angle.txt", "r"); for(int i=0; i<20; i++) fscanf(fin, "%f", &angle[i]); glutPostRedisplay();///重畫畫面 printf("read angle.txt\n"); } ``` ```C++ void keyboard(unsigned char key, int x, int y){ if(key=='0') angleID=0; if(key=='1') angleID=1; if(key=='2') angleID=2; if(key=='3') angleID=3; if(key=='4') angleID=4; if(key=='5') angleID=5; if(key=='6') angleID=6; if(key=='p'){///Play播放 glutTimerFunc(0, timer, 0);///一開始的第1個timer } ``` 它就會開始動囉!!! 但是, 想要動得更順, 利用 alpha 來內插 ```C++ #include <GL/glut.h> #include <stdio.h> FILE * fout = NULL; FILE * fin = NULL; float angle[20]={}, angleOld[20], angleNew[20];///先都設成0 int angleID=0;///現在要動的關節是誰? void timer(int t){ glutTimerFunc( 50, timer, t+1); if(t%10==0){ for(int i=0; i<20; i++) angleOld[i] = angleNew[i]; if( fin==NULL ) fin = fopen("angle.txt", "r"); for(int i=0; i<20; i++) fscanf(fin, "%f", &angleNew[i]); printf("read angle.txt\n"); } float alpha = (t%10)/10.0;///介於 0.0 - 1.0 之間 for(int i=0; i<20; i++) angle[i] = alpha*angleNew[i]+(1-alpha)*angleOld[i]; glutPostRedisplay();///重畫畫面 } ``` 全部的程式碼 ```C++ #include <GL/glut.h> #include <stdio.h> FILE * fout = NULL; FILE * fin = NULL; float angle[20]={}, angleOld[20], angleNew[20];///先都設成0 int angleID=0;///現在要動的關節是誰? void timer(int t){ glutTimerFunc( 20, timer, t+1); if(t%25==0){ for(int i=0; i<20; i++) angleOld[i] = angleNew[i]; if( fin==NULL ) fin = fopen("angle.txt", "r"); for(int i=0; i<20; i++) fscanf(fin, "%f", &angleNew[i]); printf("read angle.txt\n"); } float alpha = (t%25)/25.0;///介於 0.0 舊 - 1.0 新 之間 (請代入 0, 0.5, 1 觀察) for(int i=0; i<20; i++) angle[i] = alpha*angleNew[i]+(1-alpha)*angleOld[i]; glutPostRedisplay();///重畫畫面 } void keyboard(unsigned char key, int x, int y){ if(key=='0') angleID=0; if(key=='1') angleID=1; if(key=='2') angleID=2; if(key=='3') angleID=3; if(key=='4') angleID=4; if(key=='5') angleID=5; if(key=='6') angleID=6; if(key=='p'){///Play播放 glutTimerFunc(0, timer, 0);///一開始的第1個timer } if(key=='s'){///存檔 if( fout==NULL ) fout = fopen("angle.txt", "w+"); for(int i=0; i<20; i++) fprintf(fout, "%.2f ", angle[i]); fprintf(fout, "\n"); printf("save angle.txt\n"); }else if(key=='r'){///讀檔 (不能和存檔同時做,因angle.txt不能開2次) if( fin==NULL ) fin = fopen("angle.txt", "r"); for(int i=0; i<20; i++) fscanf(fin, "%f", &angle[i]); glutPostRedisplay();///重畫畫面 printf("read angle.txt\n"); } }///如果關節很多, 可能要用迴圈來讓程式只要2行 for(int i=0; i<10; i++) ///可能也要用到英文字母 float oldX=0; void mouse(int button, int state, int x, int y){ oldX = x; } void motion( int x, int y ){ angle[angleID] += x-oldX;///0: angle[0], 1: angle[1].. oldX = x; glutPostRedisplay();///重畫畫面 } void display(){ glClearColor( 1,0,0,0);///用來Clear的Color 用紅色 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glColor3f( 1,1,0 ); glutSolidTeapot( 0.3 );///身體先註解掉身體,只看手臂 glPushMatrix();///左半邊 glTranslatef(-.3, 0, 0);///(3)再把轉動中的手臂,掛到肩上 glRotatef(angle[0], 0,0,1);///(2)再轉動它 glTranslatef(-.3, .1, 0);///(1)移動旋轉中心,放正中心 glutSolidTeapot(0.3);///左手臂 glPushMatrix(); glTranslatef(-.3, 0, 0);///(3)再把轉動中的手臂,掛到肩上 glRotatef(angle[1], 0,0,1);///(2)再轉動它 glTranslatef(-.3, 0, 0);///(1)移動旋轉中心,放正中心 glutSolidTeapot(0.3);///左手肘 glPopMatrix(); glPopMatrix(); glPushMatrix();///右半邊 glTranslatef(+.3, 0, 0);///(3)再把轉動中的手臂,掛到肩上 glRotatef(angle[2], 0,0,1);///(2)再轉動它 glTranslatef(+.3, .1, 0);///(1)移動旋轉中心,放正中心 glutSolidTeapot(0.3);///右手臂 glPushMatrix(); glTranslatef(+.3, 0, 0);///(3)再把轉動中的手臂,掛到肩上 glRotatef(angle[3], 0,0,1);///(2)再轉動它 glTranslatef(+.3, 0, 0);///(1)移動旋轉中心,放正中心 glutSolidTeapot(0.3);///右手肘 glPopMatrix(); glPopMatrix(); glPopMatrix(); glutSwapBuffers(); } const GLfloat light_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; const GLfloat light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat light_position[] = { 2.0f, 5.0f, -5.0f, 0.0f }; const GLfloat mat_ambient[] = { 0.7f, 0.7f, 0.7f, 1.0f }; const GLfloat mat_diffuse[] = { 0.8f, 0.8f, 0.8f, 1.0f }; const GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat high_shininess[] = { 100.0f }; int main( int argc, char ** argv ) { glutInit( &argc, argv); glutInitWindowSize(300,300); glutInitWindowPosition(700,200); glutInitDisplayMode(GLUT_DOUBLE|GLUT_DEPTH); glutCreateWindow("week17 review"); glutKeyboardFunc(keyboard); glutMouseFunc(mouse); glutMotionFunc(motion); glutDisplayFunc(display); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glEnable(GL_LIGHT0); glEnable(GL_NORMALIZE); glEnable(GL_COLOR_MATERIAL); glEnable(GL_LIGHTING); glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess); glutMainLoop(); } ``` 記得要有 angle.txt 要有內容, 才會內插(會動哦) ``` -54.00 -63.00 48.00 70.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 45.00 32.00 -38.00 -40.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 -54.00 -63.00 48.00 70.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 45.00 32.00 -38.00 -40.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 -54.00 -63.00 48.00 70.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 45.00 32.00 -38.00 -40.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 -54.00 -63.00 48.00 70.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 45.00 32.00 -38.00 -40.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 -54.00 -63.00 48.00 70.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 45.00 32.00 -38.00 -40.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 -54.00 -63.00 48.00 70.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 45.00 32.00 -38.00 -40.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 -54.00 -63.00 48.00 70.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 45.00 32.00 -38.00 -40.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 -54.00 -63.00 48.00 70.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 45.00 32.00 -38.00 -40.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 ``` ## step06 貼圖、模型 先從簡單的開始 ```C++ #include <GL/glut.h> void display(){ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glutSolidTeapot( 0.3 ); glutSwapBuffers(); } int main( int argc, char ** argv ) { glutInit( &argc, argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_DEPTH); glutCreateWindow("week17 review"); glutDisplayFunc(display); glutMainLoop(); } ``` 貼圖三部曲: 1. 安裝 OpenCV 2.1 裝在預設目錄 C:\OpenCV2.1 要記得 PATH 要加起來 C:\OpenCV2.1\bin 也準備好 2. CodeBlocks 要重開, CodeBlocks 的 Setting-Compiler 的 include 和 link 的 3個咒語弄好 3. 開始寫程式 ```C++ #include <opencv/highgui.h> IplImage * img = NULL; ``` 在 main() ```C++ int main( int argc, char ** argv ) { img = cvLoadImage("background.png");///小心,要是.cpp的專案,才能簡單寫程式 cvShowImage("img", img);///秀圖 cvWaitKey(0);///等按任意鍵,才能繼續 ``` 小心, 檔案要放在工作的執行目錄, 才會正確秀出來。 所以, 我們需要用 Notepad++ 把 CodeBlocks Project .cbp檔開起來 (week17_review.cbp), 把 working_dir 換成小數點, 再 reload 重開, 便可以成功的讀入檔案。 小心: freeglut.dll 也要 copy 過去, 才不會出現錯誤 ```C++ #include <GL/glut.h> #include <opencv/highgui.h> IplImage * img = NULL; void display(){ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glutSolidTeapot( 0.3 ); glutSwapBuffers(); } int main( int argc, char ** argv ) { img = cvLoadImage("background.png");///小心,要是.cpp的專案,才能簡單寫程式 cvShowImage("img", img);///秀圖 cvWaitKey(0);///等按任意鍵,才能繼續 glutInit( &argc, argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_DEPTH); glutCreateWindow("week17 review"); glutDisplayFunc(display); glutMainLoop(); } ``` 但是現在要做 [Week08貼圖](https://hackmd.io/@jsyeh/opengl#Week08) ```C++ #include <opencv/highgui.h> ///使用 OpenCV 2.1 比較簡單, 只要用 High GUI 即可 #include <opencv/cv.h> #include <GL/glut.h> GLuint id1, id2; ///TODO:增加2個 貼圖ID int myTexture(char * filename) { IplImage * img = cvLoadImage(filename); ///OpenCV讀圖 cvCvtColor(img,img, CV_BGR2RGB); ///OpenCV轉色彩 (需要cv.h) glEnable(GL_TEXTURE_2D); ///1. 開啟貼圖功能 GLuint id; ///準備一個 unsigned int 整數, 叫 貼圖ID glGenTextures(1, &id); /// 產生Generate 貼圖ID glBindTexture(GL_TEXTURE_2D, id); ///綁定bind 貼圖ID glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); /// 貼圖參數, 超過包裝的範圖T, 就重覆貼圖 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); /// 貼圖參數, 超過包裝的範圖S, 就重覆貼圖 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); /// 貼圖參數, 放大時的內插, 用最近點 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); /// 貼圖參數, 縮小時的內插, 用最近點 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img->width, img->height, 0, GL_RGB, GL_UNSIGNED_BYTE, img->imageData); return id; } void display(){ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glutSolidTeapot( 0.3 ); glutSwapBuffers(); } int main( int argc, char ** argv ) { glutInit( &argc, argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_DEPTH); glutCreateWindow("week17 review"); glutDisplayFunc(display); id2 = myTexture("background.png"); glEnable(GL_DEPTH_TEST);///3D的深度測試功能要開起來,3D才會正確 glutMainLoop(); } ``` ## Week16 ## Week15 ## Week08 ------ - 期中考 - 複習: 貼圖 Texture, 貼圖設定、OpenCV讀圖 - 主題: 打光 Lighting 如果想要很多張貼圖, 請先把圖檔準備好 (in 你的執行目錄) 然後利用 ```C++ GLuint id1, id2;//外面宣告2個 貼圖ID ``` 在 glutMainLoop()之前, 讀入2張圖, 把圖檔讀入/貼圖ID也記下來。 ```C++ id1 = myTexture("檔名1.jpg"); id2 = myTexture("檔名2.jpg"); ``` 要使用時, 利用`glBindTexture()`來切換貼圖 ```C++ glBindTexture(GL_TEXTURE_2D, id1);//切換貼圖ID 畫你的這一個圖 glBindTexture(GL_TEXTURE_2D, id2);//切換貼圖ID 畫你的另一個圖 ``` 另外, 要正確秀出 3D 時, 除了 GLUT_DEPTH 之外, 還要用 glEnable(GL_DEPTH_TEST) 開啟3D深度測試的功能。 ```C++ #include <opencv/highgui.h> ///使用 OpenCV 2.1 比較簡單, 只要用 High GUI 即可 #include <opencv/cv.h> #include <GL/glut.h> GLuint id1, id2; ///TODO:增加2個 貼圖ID int myTexture(char * filename) { IplImage * img = cvLoadImage(filename); ///OpenCV讀圖 cvCvtColor(img,img, CV_BGR2RGB); ///OpenCV轉色彩 (需要cv.h) glEnable(GL_TEXTURE_2D); ///1. 開啟貼圖功能 GLuint id; ///準備一個 unsigned int 整數, 叫 貼圖ID glGenTextures(1, &id); /// 產生Generate 貼圖ID glBindTexture(GL_TEXTURE_2D, id); ///綁定bind 貼圖ID glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); /// 貼圖參數, 超過包裝的範圖T, 就重覆貼圖 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); /// 貼圖參數, 超過包裝的範圖S, 就重覆貼圖 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); /// 貼圖參數, 放大時的內插, 用最近點 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); /// 貼圖參數, 縮小時的內插, 用最近點 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img->width, img->height, 0, GL_RGB, GL_UNSIGNED_BYTE, img->imageData); return id; } void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBindTexture(GL_TEXTURE_2D, id1); glutSolidTeapot(0.3); glBindTexture(GL_TEXTURE_2D, id2); glBegin(GL_POLYGON); glTexCoord2f( 0, 0 ); glVertex2f( -1, -1 ); glTexCoord2f( 0, 1 ); glVertex2f( -1, +1 ); glTexCoord2f( 1, 1 ); glVertex2f( +1, +1 ); glTexCoord2f( 1, 0 ); glVertex2f( +1, -1 ); glEnd(); glutSwapBuffers(); } int main(int argc, char** argv) { glutInit( &argc, argv ); glutInitDisplayMode( GLUT_DOUBLE | GLUT_DEPTH ); glutCreateWindow(" Week08 "); glutDisplayFunc(display); id1 = myTexture("puipui.jpg"); id2 = myTexture("bg.jpg"); glEnable(GL_DEPTH_TEST); glutMainLoop(); } ``` 打光的陣列, 放在 main() 前面 ```C++ const GLfloat light_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; const GLfloat light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat light_position[] = { 2.0f, 5.0f, -5.0f, 0.0f }; const GLfloat mat_ambient[] = { 0.7f, 0.7f, 0.7f, 1.0f }; const GLfloat mat_diffuse[] = { 0.8f, 0.8f, 0.8f, 1.0f }; const GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat high_shininess[] = { 100.0f }; ``` 打光的設定, 放在 glutMainLoop()之前 ```C++ ///下面是 glutMainLoop()之前,要把打光的函式呼叫、設定 glEnable(GL_LIGHT0); glEnable(GL_NORMALIZE); glEnable(GL_COLOR_MATERIAL); glEnable(GL_LIGHTING); glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess); ``` Week07 ------ 二甲要教 Texture, 期中考試 glTexCoord2f(tx,ty) - 主題: 貼圖 Texture - 主題: OpenCV讀圖 - 主題: 貼圖設定 - (加分)HW3 旋轉2-3關節 2個班的作業(秀出全部的圖) https://hackmd.io/@jsyeh/opengl ==== ```C++ #include <opencv/highgui.h> ///使用 OpenCV 2.1 比較簡單, 只要用 High GUI 即可 #include <opencv/cv.h> #include <GL/glut.h> void init() { IplImage * img = cvLoadImage("puipui.jpg"); ///OpenCV讀圖 cvCvtColor(img,img, CV_BGR2RGB); ///OpenCV轉色彩 (需要cv.h) glEnable(GL_TEXTURE_2D); ///1. 開啟貼圖功能 GLuint id; ///準備一個 unsigned int 整數, 叫 貼圖ID glGenTextures(1, &id); /// 產生Generate 貼圖ID glBindTexture(GL_TEXTURE_2D, id); ///綁定bind 貼圖ID glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); /// 貼圖參數, 超過包裝的範圖T, 就重覆貼圖 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); /// 貼圖參數, 超過包裝的範圖S, 就重覆貼圖 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); /// 貼圖參數, 放大時的內插, 用最近點 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); /// 貼圖參數, 縮小時的內插, 用最近點 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img->width, img->height, 0, GL_RGB, GL_UNSIGNED_BYTE, img->imageData); } ///最後一行最難/最重要, 所貼圖影像的資料都設定好 ``` ```C++ #include <opencv/highgui.h> ///使用 OpenCV 2.1 比較簡單, 只要用 High GUI 即可 #include <opencv/cv.h> #include <GL/glut.h> GLUquadric * quad;///TODO: Quad void init()///copy 自 http://hackmd.io/@jsyeh/opengl { IplImage * img = cvLoadImage("earth.jpg"); ///OpenCV讀圖 cvCvtColor(img,img, CV_BGR2RGB); ///OpenCV轉色彩 (需要cv.h) glEnable(GL_TEXTURE_2D); ///1. 開啟貼圖功能 GLuint id; ///準備一個 unsigned int 整數, 叫 貼圖ID glGenTextures(1, &id); /// 產生Generate 貼圖ID glBindTexture(GL_TEXTURE_2D, id); ///綁定bind 貼圖ID glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); /// 貼圖參數, 超過包裝的範圖T, 就重覆貼圖 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); /// 貼圖參數, 超過包裝的範圖S, 就重覆貼圖 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); /// 貼圖參數, 放大時的內插, 用最近點 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); /// 貼圖參數, 縮小時的內插, 用最近點 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img->width, img->height, 0, GL_RGB, GL_UNSIGNED_BYTE, img->imageData); quad = gluNewQuadric();///TODO: Quad } ///最後一行最難/最重要, 所貼圖影像的資料都設定好 float angle=0;///TODO: void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix();///自動轉很帥///TODO: glRotatef(90, 1,0,0);///TODO: glRotatef(angle, 0,0,1);///自動轉很帥///TODO: gluQuadricTexture(quad, 1);///TODO: gluSphere(quad, 0.5, 30, 30);///glutSolidTeapot(0.3);///TODO: glPopMatrix();///自動轉很帥///TODO: ///glutSolidTeapot(0.3); glutSwapBuffers(); angle++;///TODO: } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH); glutCreateWindow("week07 texture"); glutDisplayFunc(display); glutIdleFunc(display);///TODO: glEnable(GL_DEPTH_TEST);///TODO: 有3D的深度測試(前面會蓋掉後面) init();///上面把OpenGL都設好後, 才設定 OpenCV 的貼圖到 OpenGL上面 glutMainLoop(); } ``` Week06 ------ 主題: T-R-T 關節轉動 Week05 ------ 主題: 先移動再轉動 vs. 先轉動再移動, 矩陣 Week04 ------ 主題: 移動、旋轉、放大縮小, github整理 Week03 ------ 主題: mouse, 移動, github Week02 ------ 點線面 Week01 ------ 程式開發環境 [.](https://drive.google.com/file/d/0ByYbu0zjxrp1SVZvME1jcTlHRVE/view?usp=sharing)