2023年5月25日 星期四

小葉老師一步步教圖學 Week15 攝影機(投影、運鏡)

 Week15

電腦圖學 2023-05-25 Week15

1. 主題: 攝影機 Camera

2. 主題: 投影、運鏡 gluPerspective(), gluLookAt()

3. 期末作品


step01-1

step01-1_今天要教 Camera, 所以把 jsyeh.org 的 3dcg10 裡,把 windows.zip 及 data.zip 解壓縮好, 便可以把 Projection.exe 範例跑來看看。首先先了解 gluLookAt()這個「運鏡」相關的9個參數。前3個參數, 是 eye 眼睛的位置, 中間3個參數center是你要看的中心點的座標。最後3個參數up比較奇怪, 是拿相機時,相機的畫面上向,是向著哪個方向, 這也決定是橫拍、直拍的關鍵。

jsyeh.org/3dcg10

windows.zip

data.zip




























step01-2

step01-2_要開GLUT專案 week15-1_gluLookAt, 有了GitHub的幫忙, 程式直接放在我們的2023graphicsb倉庫裡,使用 之前 Final_Project的 freeglut 目錄, 就不用安裝 freeglut了。程式裡,把 main()裡面加 glutMotionFunc(motion) 註冊motion()函式, 前面則是寫好motion()函式, 裡面會算出 eyeX 及 eyeY 的值, 再照著移動 gluLookAt()裡的眼睛位置, 並更新畫面。


安裝 Git, 開 Git Bash

cd desktop      進入桌面

git clone https://github.com/.../2023graphicsb

cd 2023graphics 進入你的倉庫目錄(重要)

start .         開檔案總管


接下來, 開你的專案, 並增加程式


```cpp=124

///前略

///Week15-1_gluLookAt 專案, 在 int main()之前, 加入 void motion()

float eyeX = 0, eyeY = 0; ///week15_step01_2

void motion(int x, int y) { ///week15_step01_2 加 motion()

    eyeX = 3*(x-320)/320.0; ///week15_step01_2 算出eyeX的座標

    eyeY = 3*(240-y)/240.0; ///week15_step01_2 算出eyeY的座標

    glLoadIdentity(); ///week15_step01_2 還原成最開始的 單位矩陣

    gluLookAt(eyeX, eyeY, -3,    0, 0, -6,   0, 1, 0);///week15_step01_2

    ///試試運鏡  eye位置        中間主角    up向量

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

}

/* Program entry point */

int main(int argc, char *argv[])

{

    glutInit(&argc, argv);

    glutInitWindowSize(640,480); ///step請注意這裡,有 640x480的視窗

    glutInitWindowPosition(10,10);

    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);


    glutCreateWindow("GLUT Shapes");


    glutMotionFunc(motion); ///week15_step01_2 加 motion()

    glutReshapeFunc(resize);

    glutDisplayFunc(display);

    glutKeyboardFunc(key);

    glutIdleFunc(idle);

//下略

```




















step02-1

step02-1_接下來嘗試在課本範例,修改 投影, 分別試垂直投影glOrtho(), 還有透視投影 glFrustum() gluPerspective(), 其中 glOrtho() 是預設的投影, glFrustum()會變成有角度張開的感覺, gluPerspective()的參數比較容易設定。


gluPerspective(fovy, aspect, zNear, zFar);

fov: field of view (y方向) 視野的張開的角度

aspect: aspect ratio 長寬比

zNear 

zFar















step02-2

step02-2_接下來寫程式, GLUT專案 week15-2_gluPerspective 裡面要試 glOrtho() glFrustum() gluPerspective()。先照著glFrustum()的參數,改成 glOrtho()時, 太大了看不到全貌, 所以把左右下上的範圍加大3倍, 便能看到正正的圖形。接下來改用 gluPerspective(60, ar, 0.01, 1000) 又可以看到另外一種透視投影的畫面, 參數比較好理解。

```cpp

static void resize(int width, int height)///week15_step02_2

{   ///week15_step02_2 aspective ratio 長寬比

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


    glViewport(0, 0, width, height); ///week15_step02_2 設定視窗的範圍


    glMatrixMode(GL_PROJECTION); ///week15_step02_2 切換成投影矩陣

    glLoadIdentity(); ///week15_step02_2 設成單位矩陣

    ///glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);

    ///glOrtho(-ar*3, ar*3, -1.0*3, 1.0*3, 2.0, 100.0); ///week15_step02_2

    gluPerspective(60, ar, 0.01, 1000); ///week15_step02_2


    glMatrixMode(GL_MODELVIEW); ///week15_step02_2 切換成 model view 矩陣

    glLoadIdentity(); ///week15_step02_2 設成單位矩陣

}

```


















step02-3

step02-3_工作到一半, 記得備份到 GitHub


準備備份

File-Save everything

git status 紅色

git add .  加進帳冊

git status 綠色


確認修改

git config --global user.email jsyeh@gmail.com

git config --global user.name jsyeh

git commit -m week15


推送上雲端

git push





step03-1

step03-1_今天最後一個GLUT小專案week15-3_gluPerspective_gluLookAt, 裡面先把 10行 GLUT程式準備好, 然後加上 今天第一節課教的 motion()函式, 在裡面改變 gluLookAt()的值。

```cpp

///week15-3_gluPerspective_gluLookAt

#include <GL/glut.h>

void display() {

    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);


    glutSolidTeapot( 0.3 );

    glutSwapBuffers();

}

void motion(int x, int y) {

    glLoadIdentity();

    float eyeX = (x-150)/150.0,  eyeY = (150-y)/150.0;

    gluLookAt(eyeX,eyeY,1,  0,0,0,  0,1,0);

    glutPostRedisplay();

}

int main(int argc, char** argv)

{

    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_DOUBLE|GLUT_DEPTH);

    glutCreateWindow("week115");


    glutMotionFunc(motion);///step03-1

    glutDisplayFunc(display);


    glutMainLoop();

}

```














step03-2

step03-2_Final_Project拿來改一改, 先把 float angle=0; 改成 float angle[20] = {}; 陣列, 再把 每個關節的 angle 改成對應的 angle[0] angle[1] angle[2] angle[3] 等。最後 motion()裡, 改變 angle[ID] += x - oldX; 便能專心改特定關節的 angle[i] 的值。之後用 for迴圈再備份到硬碟裡。

```cpp

///week15_03_03 要把我們的關節angle,變成陣列

/// float angle; 改成 float angle[20] = {} ;

///之後的 angle[0], angle[1] angle[2]

/// motion裡, 有改變 angle值, 換成 angle[ID]


///Final_Project 之後都用同一個程式,來進行 Final Project

#include <stdio.h> ///要檔案的Input/Output

#include <GL/glut.h>

#include "glm.h" ///week13_step02-2

///week13_step02-2 再把 glm.cpp 在左邊 Add files 加進去

GLMmodel * head = NULL;///week13_step02-2

GLMmodel * body = NULL;///week13_step02-2

GLMmodel * uparmR = NULL;

GLMmodel * lowarmR = NULL;

int show[4] = {1,1,1,1}; ///week14_step03_1 都秀出來 ///week13_step03-1

int ID = 3; ///week14_step03_1 設定關節 ID

float teapotX = 0, teapotY = 0;

float angle[20] = {};///week15_03_03

///float angle = 0;

FILE * fout = NULL;///step02-1

FILE * fin = NULL;///step02-2

void keyboard(unsigned char key, int x, int y) {///week13_step03-1

    if(key=='0') ID = 0; ///week14_step03_1 ///show[0] = ! show[0];///week13_step03-1

    if(key=='1') ID = 1; ///week14_step03_1 ///show[1] = ! show[1];///week13_step03-1

    if(key=='2') ID = 2; ///week14_step03_1 ///show[2] = ! show[2];///week13_step03-1

    if(key=='3') ID = 3; ///week14_step03_1 ///show[3] = ! show[3];///week13_step03-1

    glutPostRedisplay();///week13_step03-1

}///week13_step03-1

void display()

{

    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    if(head==NULL){///week13_step02-2

        head = glmReadOBJ("model/head.obj");///week13_step02-2

        body = glmReadOBJ("model/body.obj");

        uparmR = glmReadOBJ("model/uparmR.obj");

        lowarmR = glmReadOBJ("model/lowarmR.obj");

        ///glmUnitize(head); ///week13_step02-2 之後會改

    }///week13_step02-2

    glPushMatrix();

        glScalef(0.3, 0.3, 0.3);///week13_step02-3

        glPushMatrix();///week13_step03-2

            ///glTranslatef(teapotX, teapotY, 0); ///week13_step03-2


            if(ID==0) glColor3f(1,0,0);///week14_step03_1 秀紅色

            else glColor3f(1,1,1);///week14_step03_1 秀白色

            if(show[0]) glmDraw(head, GLM_MATERIAL);///week13_step02-3

        glPopMatrix();///week13_step03-2


        if(ID==1) glColor3f(1,0,0);///week14_step03_1 秀紅色

        else glColor3f(1,1,1);///week14_step03_1 秀白色

        if(show[1]) glmDraw(body, GLM_MATERIAL);///week13_step02-2


        glPushMatrix(); ///week14_step03_2

            ///glTranslatef(teapotX, teapotY, 0); ///week14_step03_2 要設定 TRT

            glTranslatef(-1.360000, +0.500000, 0); ///week14_step03_2

            glRotatef(angle[2], 0, 0, 1); ///week14_step03_2

            glTranslatef(1.360000, -0.500000, 0); ///week14_step03_2


            if(ID==2) glColor3f(1,0,0);///week14_step03_1 秀紅色

            else glColor3f(1,1,1);///week14_step03_1 秀白色

            if(show[2]) glmDraw(uparmR, GLM_MATERIAL);///week13_step02-3


            glPushMatrix();  ///week14_step03_2

                ///glTranslatef(teapotX, teapotY, 0); ///week14_step03_2 要設定 TRT

                glTranslatef(-1.959999, +0.080000, 0);

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

                glTranslatef(1.959999, -0.080000, 0);


                if(ID==3) glColor3f(1,0,0);///week14_step03_1 秀紅色

                else glColor3f(1,1,1);///week14_step03_1 秀白色

                if(show[3]) glmDraw(lowarmR, GLM_MATERIAL);///week13_step02-3

            glPopMatrix();  ///week14_step03_2

        glPopMatrix(); ///week14_step03_2



    glPopMatrix();

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

    glutSolidTeapot( 0.02 ); ///week14_step03_2

    glutSwapBuffers();

}

int oldX=0, oldY=0; ///week13_step03-2

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

    if(state==GLUT_DOWN){

        oldX = x;

        oldY = y;

    }

}

void motion(int x, int y) { ///week13_step03-2

    teapotX += (x - oldX)/150.0*3;

    teapotY -= (y - oldY)/150.0*3;

    printf("glTranslatef(%f, %f, 0);\n", teapotX, teapotY); ///week14_step03_2

    angle[ID] += x-oldX; ///week15_step03_03

    oldX = x;

    oldY = y;

    glutPostRedisplay();

}

int main(int argc, char** argv)

{

    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH);

    glutCreateWindow("week12");


    glutMotionFunc(motion); ///week13_step03-2

    glutDisplayFunc(display);

    glutKeyboardFunc(keyboard);

    glutMouseFunc(mouse);


    glutMainLoop();

}

```














沒有留言:

張貼留言