2022年6月7日 星期二

雪⛄電腦圖學筆記16~

2022/5/31 第十六周 

主題 : 內插動作、攝影機、運鏡

1. alpha內插公式 ---> alpha: 0.0~1.0

(1) angle= alpha*新 + (1+alpha)*舊

ex: alpha= 0       => 舊

      alpha= 1       => 新

      alpha=  0.5   => 半舊半新



2. 改上週程式 加上內插

(1) new-file-project : week16_interpolation,複製week15_angles_TRT_angle程式碼

(2) 加上內插函式: 動作可以看起來更流暢

---> myInterpolate() : 將每個角度去做alpha運算,讓動作看起來變流暢

---> keyBoard() : t=0時,會去運算alpha= (t%30) / 30.0 ,alpha介於 0.0~1.0

                         : t=30時,又變成0

---> myRead(): 新舊角度交換,並且重畫畫面

程式碼:

#include <GL/glut.h>

#include <stdio.h>

float angle[20], oldX=0;

int angleID=0; ///0號關節,1號關節...

FILE * fout = NULL, * fin = NULL;   ///f out、f in

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]);///檔案印出來

    }

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

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

}

float NewAngle[20],OldAngle[20];

void myRead(){

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

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

    for(int i=0; i<20; i++){ ///因為下面關節20個,所以要開陣列大小20(第4行)

        OldAngle[i] = NewAngle[i]; ///原來是新的,變舊的

        fscanf(fin, "%f", &NewAngle[i]); ///讀到新的角度

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

    }

    glutPostRedisplay();///重畫畫面

}


void myInterpolate(float alpha){ ///角度內插: 動作看起來變流暢

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

        angle[i] =alpha * NewAngle[i] + (1-alpha) * OldAngle[i];

    }

}

int t=0;

void keyboard(unsigned char key, int x, int y)///鍵盤按數字

{

    if(key=='p'){ ///可以播放儲存在file.txt的動作

        if(t%30==0) myRead(); ///新舊交換時,呼叫myRead()

        myInterpolate( (t%30) / 30.0 ); ///alpha介於 0.0~1.0

        glutPostRedisplay();///重畫畫面

        t++;

    }

    if(key=='s') myWrite();///調好動作,才save存檔

    if(key=='r') myRead(); ///一直按著r才能播放

    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重畫畫面

}


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,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);

            glRotatef(angle[1],0,0,1);

            glTranslatef(-0.7,-0.4,0);

            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[2],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);

            glRotatef(angle[3],0,0,1);

            glTranslatef(+0.7,-0.4,0);

            glColor3f(0,1,0);///綠色

        glRectf(-0.7, 0.5,-1.0, 0.3);///左下手臂


        glPopMatrix();


    glPopMatrix();


    glutSwapBuffers();

}


int main(int argc, char** argv)

{

    glutInit(&argc, argv);

    glutInitDisplayMode( GLUT_DOUBLE | GLUT_DEPTH);

    ///glutInitWindowSize(600,600);

    glutCreateWindow("week13 rect TRT TRT");


    glutKeyboardFunc(keyboard);

    glutMouseFunc(mouse);

    glutMotionFunc(motion);

    glutDisplayFunc(display);


    glutMainLoop();


}



3. 變成全自動播放: 按一次p就可以播放

程式碼:

#include <GL/glut.h>

#include <stdio.h>

float angle[20], oldX=0;

int angleID=0; ///0號關節,1號關節...

FILE * fout = NULL, * fin = NULL;   ///f out、f in

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]);///檔案印出來

    }

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

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

}

float NewAngle[20],OldAngle[20];

void myRead(){

    if( fout != NULL ){ fclose(fout); fout=NULL; } ///按下r時,fout不是空的就關掉他並清除

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

    for(int i=0; i<20; i++){ ///因為下面關節20個,所以要開陣列大小20(第4行)

        OldAngle[i] = NewAngle[i];///原來是新的,變舊的

        fscanf(fin, "%f", &NewAngle[i]);///讀到新的角度

        ///fscanf(fin, "%f", &angle[i]); ///讀入剛剛寫入的角度

    }

    glutPostRedisplay();///重畫畫面

}


void myInterpolate(float alpha){///內插: 動作看起來變流暢

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

        angle[i] =alpha * NewAngle[i] + (1-alpha) * OldAngle[i];

    }

}

///int t=0;

void timer(int t){

    if(t%50==0) myRead();

    myInterpolate((t%50)/50.0);

    glutPostRedisplay();

    glutTimerFunc(20, timer, t+1);

}

void keyboard(unsigned char key, int x, int y)///鍵盤按數字

{

    if(key=='p'){///可以播放儲存在file.txt的動作

        myRead();

        glutTimerFunc(0, timer, 0);

        ///if(t%30==0) myRead(); ///新舊交換時,呼叫myRead()

        ///myInterpolate( (t%30)/30.0 ); ///alpha介於 0.0~1.0

        ///glutPostRedisplay();///重畫畫面

        ///t++;

    }

    if(key=='s') myWrite();///調好動作,才save存檔

    if(key=='r') myRead(); ///一直按著r才能播放

    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重畫畫面

}


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,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);

            glRotatef(angle[1],0,0,1);

            glTranslatef(-0.7,-0.4,0);

            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[2],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);

            glRotatef(angle[3],0,0,1);

            glTranslatef(+0.7,-0.4,0);

            glColor3f(0,1,0);///綠色

        glRectf(-0.7, 0.5,-1.0, 0.3);///左下手臂


        glPopMatrix();


    glPopMatrix();


    glutSwapBuffers();

}


int main(int argc, char** argv)

{

    glutInit(&argc, argv);

    glutInitDisplayMode( GLUT_DOUBLE | GLUT_DEPTH);

    ///glutInitWindowSize(600,600);

    glutCreateWindow("week13 rect TRT TRT");


    glutKeyboardFunc(keyboard);

    glutMouseFunc(mouse);

    glutMotionFunc(motion);

    glutDisplayFunc(display);

    glutMainLoop();

}


4. 用Projection.exe了解攝影機

(1) 下載範例: windows、data.zip ,projection.exe

(2) eye: 相機的角度要看哪裡(相機看的還是正中心)

     ex: x>0,相機往右移,拍模型的左半邊


     ex: x<0,拍模型的右半邊


     ex: y>0,看模型的正上方


     ex: y<0,看模型的正下方


     center: 相機的正中心要拍哪裡

     ex: y<0,相機正中心拍到腳


     up: 相機拿的方向

     ex: 0, 1, 0 --> 相機直直拍



     ex: 2, 0, 0 --> 相機向右轉90度拍

5. 實作glutLookAt

(1) file-new-project: week16_camera_interpolation_glutLookAt

(2) 30行: aspect ratio 長寬比: ex: 1920*1080(寬*高)、1280*720、16:9、4:3

程式碼: 

const float ar = (float) width / (float) height;

glViewport(0, 0, width, height);

(3) 複製並改造原本的範例

程式碼:

#include <GL/glut.h>

void reshape(int w, int h){ ///不能整數除

    float ar = (float) w / (float) h; ///長寬比值

    glViewport(0, 0, w, h); ///畫面不會變扁

    glMatrixMode(GL_PROJECTION); ///3D-->2D

    glLoadIdentity();

    gluPerspective(60, ar, 0.1, 100);


    glMatrixMode(GL_MODELVIEW); ///3D model+view

    glLoadIdentity();///單位矩陣

    gluLookAt(0, 0, 3,   ///eye :3(z)往左邊一點

              0, 0, 0,   ///center看哪裡

              0, 1, 0 ); ///up向量

}

void display()

{

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glutSolidTeapot(1);

    glutSwapBuffers();

}


int main(int argc, char** argv)

{

    glutInit(&argc, argv);

    glutInitDisplayMode( GLUT_DOUBLE | GLUT_DEPTH);

    glutCreateWindow("week16camera");


    glutDisplayFunc(display);

    glutReshapeFunc(reshape);   ///範例是用resize

    glutMainLoop();

}

---> lookat: 讓相機看正中心reshape: 讓視窗拉大拉小模型不會變形



6. 用滑鼠操控相機相機

#include <GL/glut.h>

void reshape(int w, int h){ ///不能整數除

    float ar = (float) w / (float) h;

    glViewport(0, 0, w, h);

    glMatrixMode(GL_PROJECTION); ///3D-->2D

    glLoadIdentity();

    gluPerspective(60, ar, 0.1, 100);


    glMatrixMode(GL_MODELVIEW); ///3D model+view

    glLoadIdentity();///單位矩陣

    gluLookAt(0, 0, 3,   ///eye

              0, 0, 0,   ///center看哪裡

              0, 1, 0 ); ///up向量

}


void display()

{

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glutSolidTeapot(1);

    glutSwapBuffers();

}


void motion(int x, int y){ ///用滑鼠調整相機看正中心的角度

    glMatrixMode(GL_MODELVIEW);

    glLoadIdentity();///單位矩陣

    gluLookAt((x-150)/150.0, (y-150)/150.0, 3, 

                            ///eye: x:左右滑->相機往左、右看,y:上下滑->相機往上下看

              0, 0, 0,   ///center看哪裡

              0, 1, 0 ); ///up向量

    glutPostRedisplay(); ///請GLUT重畫畫面

}


int main(int argc, char** argv)

{

    glutInit(&argc, argv);

    glutInitDisplayMode( GLUT_DOUBLE | GLUT_DEPTH);

    glutCreateWindow("week16camera");

    glutMotionFunc(motion);


    glutDisplayFunc(display);

    glutReshapeFunc(reshape);///範例是用resize

    glutMainLoop();

}

---> 滑鼠往左滑: 相機往左邊移




沒有留言:

張貼留言

VERY BEAUTIFUL, VERY POWERFUL

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