移動、選轉、縮放
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






沒有留言:
張貼留言