顯示具有 09160011_葉正聖 標籤的文章。 顯示所有文章
顯示具有 09160011_葉正聖 標籤的文章。 顯示所有文章

2022年5月24日 星期二

熱血小葉老師的圖學筆記 Week14

 # Week14

電腦圖學 Week14 2022-05-24

1. 寫檔、讀檔

2. 關節、做動畫

3. 計時器 glutTimerFunc(時間, timer, 參數t)

4. 播放聲音


## step01-1

step01-1_為了記錄動畫的動作,我們需要寫檔。fopen()開檔, fprintf()寫檔, fclose()關檔


write 寫檔 File Output (記錄)

0. File-New-Empty File, 存檔到 week14-1_fprintf 目錄裡的 week14-1.cpp

1. fopen() 開啟檔案 `FILE * fout = fopen("檔名", "w+");`

2. printf() => fprintf() File Output

3. fclose() 關閉檔案


```cpp

///Week14-1.cpp step01-1

#include <stdio.h>

int main()

{///檔案指標 fout  開啟檔案(檔名, write模式)

    FILE * fout = fopen("file.txt", "w+");

     printf(     "Hello World\n");

    fprintf(fout,"Hello World\n");

    fclose(fout);///關閉檔案

}

```


## step01-2

step01-2_再加上讀檔,使用fscanf()來讀檔,要小心變數要有&在前面


read 讀檔 File Input 

0. File-New-EMpty File, 存檔到 week14-2_fprintf_fscanf 目錄裡的 week14-2.cpp

1. 把剛剛 week14-1.cpp 拿來用

2. 另外一組  `FILE * fin = fopen("檔名", "r");`

3. scanf() => fscanf() File Input

4. fclose()


```cpp

///Week14-2.cpp step01-2

#include <stdio.h>

int main()

{

    FILE * fout = fopen("file.txt", "w+");

    fprintf(fout,"3.1415926\n");

    fclose(fout);///關閉檔案


    float angle=0;

    FILE * fin = fopen("file.txt", "r");

    fscanf(fin, "%f", &angle ); ///沒加&會當掉

    printf("讀到了角度:%f", angle);

    fclose(fin);

}

```


## step01-3

step01-3_有了前面檔案的基礎,接下來把上週week13_rect_many_TRT 拿來改裝, 加上寫檔案的功能, 先把FILE指標fout=NULL還沒開啟,在void myWrite()裡面如果fout沒開好,就fopen(),接下來用for迴圈印出20個角度的值(到小黑、也到檔案),我們還沒有fclose()


把上週的程式 week13_rect_many_TRT 拿來改

0. File-New-Project, GLUT專案 week14_angles_fprintf

1. 將 week13_rect_many_TRT 的 main.cpp 內容copy過來

2. 加上 `FILE * fout=NULL;`

3. 加上 void myWrite() 裡面有fopen() 及 for迴圈裡 fprintf()

4. 在 motion()裡, 呼叫 myWrite()


```cpp

///week14_angles_fprintf 改自 week13_rect_many_TRT

#include <GL/glut.h>

#include <stdio.h>

float angle[20], oldX=0;

int angleID=0;

FILE * fout = NULL;

void myWrite(){

    if( fout == NULL ) fout = fopen("file.txt", "w+");


    for(int i=0; i<20; i++){

        printf("%.1f ", angle[i] );///小黑印出來

        fprintf(fout, "%.1f ", angle[i] );///檔案印出來

    }///這裡老師沒有fclose

}

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;

}

void mouse(int button, int state, int x, int y){

    oldX = x;

}

void motion(int x, int y){

    angle[angleID] += (x-oldX);

    myWrite();

    oldX = x;

    glutPostRedisplay();///��GLUT���e�e�� Re display

}

//下略

```


## step02-1

step02-1_又是新的專案。copy前一步程式myWrite()可以寫檔, 現在再加上myRead(), 並且在keyboard()裡如果按下r鍵,就會讀一行資料。一直按著r就會一直讀資料,並且glutPostRedisplay()持續重畫更新


要做動畫囉!!!

0. File-New-Project, GLUT專案 week14_angles_fprintf_fscanf

1. copy前一個版本的程式來修改

2. 要寫 void myRead() 

3. keyboard()裡, 按下 'r' 呼叫 myRead()


```cpp

FILE * fout = NULL, * fin = NULL;

void myWrite(){///每呼叫一次myWrite()

    if( fout == NULL ) fout = fopen("file.txt", "w+");


    for(int i=0; i<20; i++){

        printf("%.1f ", angle[i] );///小黑印出來

        fprintf(fout, "%.1f ", angle[i] );///檔案印出來

    }///印出20個數字

    printf("\n");///每呼叫一次, 小黑跳行

    fprintf(fout, "\n");///每呼叫一次, 檔案也跳行

}///這裡老師沒有fclose

void myRead(){

    if( fout != NULL ) { fclose(fout); fout=NULL; }

    if( fin == NULL ) fin = fopen("file.txt", "r");

    for(int i=0; i<20; i++){

        fscanf(fin, "%f", &angle[i] );

    }

    glutPostRedisplay();///重畫畫面

}

void keyboard(unsigned char key, int x, int y){

    if( key=='r' ) myRead();

    if( key=='0' ) angleID=0;

    if( key=='1' ) angleID=1;

    if( key=='2' ) angleID=2;

    if( key=='3' ) angleID=3;

}

```


## step02-2

step02-2_有同學遇到目錄的問題,所以老師教大家 GLUT專案 freeglut.dll 歷史餘毒的問題, 解釋 What Why How 如何解決, 就是安裝 Notepad++ 後, 便可以修改 .cbp CodeBlocks專案檔, 把裡面的working_dir=右邊雙引號裡改成小數點,就會用專案的這個目錄。只是要記得把桌面的freeglut的bin的freeglut.dll也放到你的專案目錄中


很奇怪, 我們為什麼產生的檔案file.txt放在奇怪的目錄 C:\Users\user\Desktop\freeglut\gin 好奇怪!!! 想要放在程式專案的那個目錄!!

0. What! 好奇怪!!! file.txt放在奇怪的目錄 

1. Why? 原來是歷史餘毒 GLUT專案 需要 freeglut.dll 所以 working_dir被設到 freeglut\bin 裡面

2. How? 在 .cbp CodeBlocks Project 檔裡, 有 working_dir的設定 工作執行的目錄

3. 使用 Notepad++ 把 .cbp 的 working_dir="....."  改 working_dir="." 小數點

4. Notepad++存檔後, CodeBlocks Reload它, 便成功了!!!!

5. 小心 歷史餘毒 freeglut.dll 要再修正, 放到week14_angles_fprintf_fscanf 程式專案的同目錄, 再執行時, 便可以 mouse motion 動動動, 按r重播,而且file.txt 也放在你的程式專案目錄囉!!!


沒裝 Notepad++ 的, 快去下載台灣人 Don Ho 侯今吾先生寫的 Notepad++


## step03-1


glutTimerFunc() 計時器

```

rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr

rrrrrrrr

rrrrrrrrrrrrrrrrrrrrrrrrrrr

rrrrrrrrrrrr

rrrrrrrrrrrrrrrrrrrr

rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr

要看你的keyboard的速度,每個人的電腦設定會不同!

```

0. File-New-Project, GLUT專案 week14_timer

1. void timer(int t) 寫 timer函式

2. glutTimerFunc( 等多久, timer, t參數 );

3. 其他就是 GLUT 的10行程式碼!!


```cpp

///Week14_timer 每天早晨, 老師 05:50 鬧鐘響

///起床,閉著眼,再設定 05:53鬧鐘,再睡

///起床,閉著眼,再設定 05:56鬧鐘,再睡

///...

///起床,閉著眼,再設定 07:50鬧鐘...嚇死了..

#include <GL/glut.h>

#include <stdio.h>

void timer(int t){

    printf("起床,現在時間: %d\n", t);

}

void display(){

}

int main(int argc, char** argv)

{

    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH);

    glutCreateWindow("week14 timer");

    ///班代一次全部設好,不用那麼麻煩

    glutTimerFunc(1000, timer, 1);

    glutTimerFunc(2000, timer, 2);

    glutTimerFunc(3000, timer, 3);

    glutTimerFunc(4000, timer, 4);

    glutTimerFunc(5000, timer, 5);

    glutDisplayFunc(display);

    glutMainLoop();

}

```


## step03-2

step03-2_timer最後面其實可再設定下一個timer出現的時機, 便能源源不絕的有timer定時叫起來


期末作品30秒,每秒30格, 900個timer有點麻煩, 程式應該自動一點

函式呼叫函式, 好像很帥!!! 但再改造一下, 


```cpp

void timer(int t){

printf("我起床囉! %d\n", t);

//做我的事

glutTimerFunc(1000, timer, t);//要倒下去睡之前, 再設一個鬧鐘

}

```


## step03-2

step03-3_接下來可以在 timer()裡面定時播放聲音哦,只要PlaySound()並事先將do.wav檔準備好, 再include mmsystem.h 便可以順利播放 PlaySound(檔名, NULL, SND_ASYNC);


播放聲音 PlaySound() 請先下載 do.wav

1. 繼續改 week14_timer_one_by_one 

2. #include <mmsystem.h>

3. PlaySound("do.wav", NULL, SND_ASYNC); 


```cpp

void timer(int t){

printf("我起床囉! %d\n", t);

PlaySound("do.wav", NULL, SND_ASYNC); 

glutTimerFunc(2000, timer, t+1 );

}

```


0. Git Bash

1. cd desktop (或你對應的目錄)

2. git clone https://github.com/jsyeh/2022graphics1 

(你可能重覆了, 沒關係: (1) 砍掉重clone, (2) 繼續用)


3. cd 2022graphics1

4. git pull (從雲端拉下最新的版本)

(接下來, 把你的 week14 的一堆程式放上去)


5. git status (紅色的檔案)

git add .

git status (綠色的檔案)


6. git commit -m "add week14"

7. git push


2022年5月17日 星期二

熱血小葉老師的圖學筆記 Week13

 

Week13

step01-1

step01-1_利用 glRectf(x1,y1, x2,y2) 想簡化程式,示範TRT的觀念

glRectf(x1,y1, x2,y2) 方塊

  1. File-New-Project, GLUT專案, week13_rect_TRT
  2. 貼上 GLUT 10行程式,不用茶壼, 改 glRectf()
#include <GL/glut.h>
void display()
{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glRectf( 0.3, 0.5,  -0.3, -0.5);///四邊形
    glutSwapBuffers();
}
int main(int argc, char**argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowSize(600,600);
    glutCreateWindow("week13 rect TRT");

    glutDisplayFunc(display);

    glutMainLoop();
}

step01-2

step01-2_接下來,再把紅色的手臂準備好, 同時把 T-R-T 的程式放好, 讓大家了解程式的架構

想把手加上去,而且要讓它可以轉動

  1. 另一個小方塊 加點色彩
  2. 準備好TRT程式碼
void display()
{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glColor3f(1,1,1);///白色的
    glRectf( 0.3, 0.5,  -0.3, -0.5);///身體,四邊形
    glPushMatrix();
        ///glTranslatef(x, y, z);//(3)把手臂掛回身體
        ///glRotatef(angle, 0,0,1);//(2)旋轉 對z軸轉
        ///glTransaltef(x2, y2, z2);//(1)把手臂的旋轉中心,放中心
        glColor3f(1,0,0);///紅色的
        glRectf( 0.3, 0.5,  0.7, 0.3);
    glPopMatrix();
    glutSwapBuffers();
}

step01-3

step01-3_接下來我們依序把 T-R-T 慢慢寫出來。(1)先寫最下面的T,把手臂的旋轉中心放到世界的中心, (2) float angle=45 轉動45度,可以看到手臂在肚臍的地方轉45度, (3) 最上面的T把手臂再掛回原本的位置, 完成

先把旋轉中心放在正中心 把 (0.3 0.4) 移到 (0 0) glTranslatef(-0.3, -0.4, 0);

再把旋轉做好

最後再掛回身體的手臂位置

#include <GL/glut.h>
float angle=45;
void display()
{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glColor3f(1,1,1);///白色的
    glRectf( 0.3, 0.5,  -0.3, -0.5);///身體,四邊形
    glPushMatrix();
        glTranslatef( 0.3,  0.4, 0);///(3)把手臂掛回身體
        glRotatef(angle, 0,0,1);///(2)旋轉 對z軸轉
        glTranslatef(-0.3, -0.4, 0);///(1)把手臂旋轉中心,放中心
        glColor3f(1,0,0);///紅色的
        glRectf( 0.3, 0.5,  0.7, 0.3);
    glPopMatrix();
    glutSwapBuffers();
}

step02-1

step02-1_剛剛的程式最後收尾時,我們利用 mouse motion 來改變它的角度, 要記得glutMouseFunc(mouse)及glutMotionFunc(motion)也要加上去哦.zip

接下來要利用 mouse motion 來旋轉手臂的角度值

#include <GL/glut.h>
float angle=45, 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();///請GLUT重畫畫面 Re display
}
void display()
{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glColor3f(1,1,1);///白色的
    glRectf( 0.3, 0.5,  -0.3, -0.5);///身體,四邊形
    glPushMatrix();
        glTranslatef( 0.3,  0.4, 0);///(3)把手臂掛回身體
        glRotatef(angle, 0,0,1);///(2)旋轉 對z軸轉
        glTranslatef(-0.3, -0.4, 0);///(1)把手臂旋轉中心,放中心
        glColor3f(1,0,0);///紅色的
        glRectf( 0.3, 0.5,  0.7, 0.3);
    glPopMatrix();
    glutSwapBuffers();
}
int main(int argc, char**argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH);
    ///glutInitWindowSize(600,600);
    glutCreateWindow("week13 rect TRT");

    glutMouseFunc(mouse);
    glutMotionFunc(motion);
    glutDisplayFunc(display);

    glutMainLoop();
}

step02-2

step02-2_新開專案week13_rect_TRT_TRT 想要做出2個關節。所以接續前面的程式,先把float angle=0 變回0度, 再增加下面的綠手肘的部分

新開專案 week13_rect_TRT_TRT 做出更多關節

  1. File-New-Project, GLUT專案, week13_rect_TRT_TRT
  2. 把前面的程式拿來用
  3. 要新增的地方, 是第二個關節
///week13_rect_TRT_TRT
#include <GL/glut.h>
float angle=0, 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();///請GLUT重畫畫面 Re display
}
void display()
{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glColor3f(1,1,1);///白色的
    glRectf( 0.3, 0.5,  -0.3, -0.5);///身體,四邊形

    glPushMatrix();
        glTranslatef( 0.3,  0.4, 0);///(3)把手臂掛回身體
        glRotatef(angle, 0,0,1);///(2)旋轉 對z軸轉
        glTranslatef(-0.3, -0.4, 0);///(1)把手臂旋轉中心,放中心
        glColor3f(1,0,0);///紅色的
        glRectf( 0.3, 0.5,  0.7, 0.3);///上手臂

        glPushMatrix();
            ///glTranslatef( x, y, z);
            ///glRotatef(angle, 0,0,1);
            ///glTranslatef(x2,y2,z2);
            glColor3f(0,1,0);///綠色的
            glRectf( 0.7, 0.5, 1.0, 0.3);///下手肘
        glPopMatrix();

    glPopMatrix();

    glutSwapBuffers();
}

step02-3

接下來, 照著把下手肘的T-R-T依序做出來。

void display()
{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glColor3f(1,1,1);///白色的
    glRectf( 0.3, 0.5,  -0.3, -0.5);///身體,四邊形

    glPushMatrix();
        glTranslatef( 0.3,  0.4, 0);///(3)把手臂掛回身體
        glRotatef(angle, 0,0,1);///(2)旋轉 對z軸轉
        glTranslatef(-0.3, -0.4, 0);///(1)把手臂旋轉中心,放中心
        glColor3f(1,0,0);///紅色的
        glRectf( 0.3, 0.5,  0.7, 0.3);///上手臂

        glPushMatrix();
            glTranslatef( 0.7,  0.4, 0);///(3)把手肘掛回剛剛的位置
            glRotatef(angle, 0,0,1);///(2)旋轉
            glTranslatef(-0.7, -0.4, 0);///(1)把手肘旋轉中心,放中心
            glColor3f(0,1,0);///綠色的
            glRectf( 0.7, 0.5, 1.0, 0.3);///下手肘
        glPopMatrix();

    glPopMatrix();

    glutSwapBuffers();
}

step03-1

step03-1_接下來是今天的最後一個專案 week13_rect_many_TRT, 要做出更多的關節。利用左右對稱的原則,複製 glPushMatrix()...glPopMatrix() 的程式碼, 再把x座標正負修改, 便完成鏡射了

新的專案 week13_rect_many_TRT 再寫新的程式碼

void display()
{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glColor3f(1,1,1);///白色的
    glRectf( 0.3, 0.5,  -0.3, -0.5);///身體,四邊形

    glPushMatrix(); ///右半部
        glTranslatef( 0.3,  0.4, 0);///(3)把手臂掛回身體
        glRotatef(angle, 0,0,1);///(2)旋轉 對z軸轉
        glTranslatef(-0.3, -0.4, 0);///(1)把手臂旋轉中心,放中心
        glColor3f(1,0,0);///紅色的
        glRectf( 0.3, 0.5,  0.7, 0.3);///右上手臂

        glPushMatrix();
            glTranslatef( 0.7,  0.4, 0);///(3)把手肘掛回剛剛的位置
            glRotatef(angle, 0,0,1);///(2)旋轉
            glTranslatef(-0.7, -0.4, 0);///(1)把手肘旋轉中心,放中心
            glColor3f(0,1,0);///綠色的
            glRectf( 0.7, 0.5, 1.0, 0.3);///右下手肘
        glPopMatrix();
    glPopMatrix();

    glPushMatrix(); ///左半部
        glTranslatef(-0.3,  0.4, 0);///(3)把手臂掛回身體
        glRotatef(angle, 0,0,1);///(2)旋轉 對z軸轉
        glTranslatef(+0.3, -0.4, 0);///(1)把手臂旋轉中心,放中心
        glColor3f(1,0,0);///紅色的
        glRectf(-0.3, 0.5, -0.7, 0.3);///左上手臂

        glPushMatrix();
            glTranslatef(-0.7,  0.4, 0);///(3)把手肘掛回剛剛的位置
            glRotatef(angle, 0,0,1);///(2)旋轉
            glTranslatef(+0.7, -0.4, 0);///(1)把手肘旋轉中心,放中心
            glColor3f(0,1,0);///綠色的
            glRectf(-0.7, 0.5,-1.0, 0.3);///左下手肘
        glPopMatrix();
    glPopMatrix();
    glutSwapBuffers();
}

step03-2

step03-2_最後可以使用鍵盤keyboard()來切換 angleID, 之後可以用 angle[angleID] 來修改對應的關節, 比如 angleID=0時, 會動到angle[0] 的關節

如果只有一個角度 angle 沒有辦法 要幾個角度? 20個 float angle=0; float angle[20]; 改完後, 要全部的 angle都改

很多關節, 可用keyboard()切換

float angle[20], oldX=0;
int angleID=0; ///0號關節, 1號關節, 2號關節, 3號關節
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;
}
void mouse(int button, int state, int x, int y){
    oldX = x;
}
void motion(int x, int y){
    angle[angleID] += (x-oldX);
    oldX = x;
    glutPostRedisplay();///請GLUT重畫畫面 Re display
}

記得 main() 要加上 glutKeyboardFunc(keyboard);

step03-3

step03-3_今天課程結束。有同學在網路上問到作業要如何用許多的關節轉動, 老師用同學的例子做示範, 先把程式碼重覆的地方用函式來簡化, 接下來便是用今天教的許多TRT來完成身體各關節的轉動。

VERY BEAUTIFUL, VERY POWERFUL

一.     一樣先安裝且設定好freeglut,OpecCV, 開啟CodeBlocks建立新專案 week11_gundam,                 把 MyGundam.zip下載解壓縮後的data資料夾放到freeglut/bin裡面 把week09_openc...