2017年10月5日 星期四

楊喻文的學習手札 20171005

week04


移動、選轉、縮放
Translate, Rotate, Scale

事前提要:
1. 要注意電腦上的codeblocks上面是有裝圖學要用的MinGW編譯環境,並且將相關設定都設好
2.今日會用到的指令:translate, rotate, scale, push, pop (後兩個為stack和queue的概念)

今日目標:
運用5行程式碼達到今日要教的指令!
🚀其中會用到的概念會與三角函數矩陣有關係!

➧任務一:
按照第一周freeglut的設定好之後,編譯並執行main.cpp
可以看到原本的圖就已經具備轉動的能力


➧任務二:
更改diaplay()函式,更改前三個實體選轉物體的程式
改成茶壺狀並且再更改顏色

➔原本第一個實心紅色球體的程式碼:
glPushMatrix();  ///push和pop
        glTranslated(-2.4,1.2,-6); 
          ///d代表double,兩倍浮點數,也可以用f表示一般浮點數
        glRotated(60,1,0,0);
        glRotated(a,0,0,1);
        glutSolidSphere(1,slices,stacks); ///實心球體
glPopMatrix();

///其他關於物體的程式碼還有:

glutSolidCone(1,1,slices,stacks); ///實心椎狀體
glutSolidTorus(0.2,0.8,slices,stacks); ///實心甜甜圈

➪更改之後(第一張圓球加茶壺、顏色):
glPushMatrix();
        glTranslated(-2.4,1.2,-6);
        glRotated(60,1,0,0);
        glRotated(a,0,0,1);
        glColor3f(0,0,1);
        glutSolidTeapot(1);
        glutSolidSphere(1,slices,stacks);
glPopMatrix();


⇑可以看到全部變成藍色的了
(但是因為茶壺的圖形有點障礙,所以不是很可以明顯的表現出選轉的樣子,會轉得很奇怪)

➱把前三個也都改掉:


⇑一堆長得很奇怪,旋轉的也很奇怪的茶壺

➽為什麼旋轉需要兩行程式碼呢?

首先要記住一個訣竅,就是下面程式碼要理解是要由後往前看的 (越接近,影響越大)

例如:他是一個實心球體,是茶壺狀的,顏色是藍色的,旋轉方式是....移動方式是...
    glPushMatrix();
        glTranslated(-2.4,1.2,-6); 
                    ///(x, y, z)
        glRotated(60,1,0,0); //固定角度的選轉
        glRotated(a,0,0,1); //隨著時間一直選轉 因為a=t*90.0,而t是時間
        glColor3f(0,0,1);
        glutSolidTeapot(1);
        glutSolidSphere(1,slices,stacks);
    glPopMatrix();

➽那glRotated(60,1,0,0);中的數字又代表甚麼呢?
這行代表的意思是繞著x軸選轉60度
意即:glRotated(角度,x軸,y軸,z軸);

看一下把固定角度旋轉砍掉,只留下不斷旋轉,並且旋轉軸換位置的話會怎麼轉:
程式碼如左,結果圖如右
      
第一張圖以x軸不斷旋轉,第二張圖以y軸不斷旋轉,第三張圖以z軸不斷旋轉
*如果是同時以x軸和y軸去旋轉的話,他就會以斜斜的角度去旋轉(下圖左藍色)

*轉轉方式類似於用一個竹籤戳破中間的選轉
*旋轉軸是z的話,代表他是從螢幕射向自己,然後逆時針旋轉(右手座標系統)




➽那為什麼需要兩行rotate?
第一行固定旋轉類似於固定一個角度(擺POSE),而第二行則是以旋轉軸下去不斷旋轉
但是最多不要寫旋轉超過兩行

➽再來偷偷看一下t到底是甚麼:
const double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
從上面可以看出來t就是每一秒鐘的變化

➽來做個縮放
glScaled(0.2, 0.2, 0.2); ///(x分量, y分量, z分量) 可以不等量
這行是表示原本的0.2倍大,所以下圖可以看到原本該一樣大的茶壺變得很小


glScaled(2, 2, 2);
改成放大兩倍,下圖看到茶壺大到畫面放不下了


glScaled(2, 0.4, 1.3);
用不同倍率的話,圖片就變成奇怪的圖形


看一下縮放的矩陣:


➽來試試移動
glTranslated(-2.4,1.2,-6); ➠ glTranslated(0,0,-9);



這個矩陣裡面把移動、縮放和選轉都放在裡面了!


旋轉矩陣


2d旋轉矩陣的算法



*電腦圖學中有一部很有名的電影:駭客任務 The Matrix,其中有一個很有名的叫bullet time


Stack

push & pop



因為任何運算都是在push和pop中運作,所以樓上的可以不影響樓下的
push備份拿出去,pop是還原拿回來
不然會世界大亂,顯示不出東西!

    glPushMatrix();
        glTranslated(0,1.2,-6);
        glRotated(60,0,1,0);
        glRotated(a,0,1,0);
        glColor3f(1,0,1);
        glutSolidTeapot(1);
        glutSolidCone(1,1,slices,stacks);
    glPopMatrix();


現在要把整個改成可以用滑鼠去移動茶壺

跟把大象放進去是一樣的道理,滑鼠按下去,滑鼠移動,滑鼠放開,就好了

程式碼:

#include <GL/glut.h> //為了OPENGL的3D功能
#include <stdio.h>
float dx=0, dy=0, dz=0;//我要畫的3D位置
int oldx=0, oldy=0, oldz=0;//舊的位置

void display()//glutDisplayFunc(display)的顯示函式
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ;
    //清畫面,不然會見鬼(註1)
    glPushMatrix();//備份矩陣
        glTranslatef(dx, dy, dz);//移動
        glutSolidTeapot(0.3);
    glPopMatrix();//還原矩陣

    glutSwapBuffers();  ///vs. glFlush() //重新交換顯示畫面


}
void motion(int x, int y) //用來拖曳移動
{
    dx += (x-oldx)/150.0;
    dy += -(y-oldy)/150.0; //因為座標上下顛倒,所以要加-
    oldx=x; //新舊交換
    oldy=y; //新的移動完成之後立即變舊的(交棒)
    glutPostRedisplay(); //貼 便利貼,請電腦要 重新畫畫面
    printf("%f %f\n", dx, dy); //只是印一下座標參考用,可以不要寫
}

void mouse(int button, int state, int x, int y) //滑鼠按下去
{
    if(state==GLUT_DOWN){oldx=x; oldy=y;}//按下去時,要記錄在哪裡開始
    if(state==GLUT_UP){printf("彈起來了\n");}//滑鼠放開的時候會記錄
}

int main(int argc, char **argv)
{

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
    glutCreateWindow("Week04");

    glutDisplayFunc(display);

    glutMouseFunc(mouse);//之後會教
    glutMotionFunc(motion);

    glutMainLoop();
}


註一:所謂見不見鬼

不見鬼,乾淨溜溜😄                vs                見鬼,鬼影幢幢💀
                  


下周會把程式碼重教,然後讓大家可以自己創作出一個屬於自己的放大縮小移動的程式

小常識:
*小駱駝命名法:因為駱駝有駝峰駝谷,所以有動作gl後面就會接動作,在接上浮點數
Ex:glTranslatef

沒有留言:

張貼留言