[一] 目的
在 openGL 中,3D 畫面是透過計算畫出模擬人的位置往某個特定的方向看,
所看某個物體的樣貌,而更進階的,為了朔造出不僅能讓人看某個東西所得
的影像,還能更進一步的移動人的位置,而看不一定的角度和畫面,這一篇
主要就是在講怎麼用 openGL 的函式庫達成
在 3D 的畫面中移動,有兩種方法,第一種,移動整個場景,但是不移動眼
睛所在的位置及眼睛所看的地方;第二種,移動眼睛所在的位置及眼睛所看
的地方,但是場景不移動。
[二] 移動場景,不移動眼睛座標及視角
1. 想法: 當前後移動時,非常簡單,修改場景中所有的物體的 z 值就可以達成;
當要換方向看時,應該要讓場景中所有物體繞著眼睛所在的方向進行公轉,
公轉方法可以看上一篇
(p.s) 當看的方向改變時,移動方向也應該改變,
此時只要算 sin 和 cos 就可以得到各方向的移動距離囉
2. 因為這個比較簡單,所以就不寫 pseudo code 惹 XD
[三] 不移動場景,移動眼睛座標及視角
1. 想法: 首先,先將眼睛看的位置(position)放在離眼睛(eye)距離 1 的地方,當前
後移動時,將 eye 和 position 的 z 值同時加減 1 即可,一樣的,當看的方
向不同時,一樣要算 sin 和 cos,才能得到正確的各方向移動位置;而當
視角改變時,則是應該固定 eye 的位置,用 sin 和 cos 去調整 position 即可
2. 這 pseudo code 反而太麻煩,不想寫 = =
2013年12月17日 星期二
[openGL] 公轉與自轉
以下介紹內容直接用太陽系的概念,所以誰繞誰轉,誰要自轉就不解釋了 XD
1. 目的: 物體或模型繞著某個點轉 (通常是原點)
2. 想法: 在 openGL 的函式庫中,glRotate*() 是繞著原點轉的,所以我們應該先計算
出將太陽移動至原點的距離,而後讓整個太陽系的所有物體都依照這個距離移動,
再讓地球旋轉,最後再將物體移回原來的位置
(p.s) 測試過後,openGL 的 rotate 並不會像之前實作一樣讓整個單位向量跑掉,所以可以這樣做
3. pseudo code:
// 畫地球
glPushMatrix();
glTranslate(dx, dy, dz);
glRotate(angle, ...);
glTranslate(-dx, -dy, -dz);
... draw earth ...
glPopMatrix();
//畫月亮
glPushMatrix();
glTranslate(dx2, dy2, dz2);
glRotate(angle, ...);
glTranslate(-dx2, -dy2, -dz2);
... draw moon ...
glPopMatrix();
//畫太陽
... draw sun ...
//dx, dy, dz 是將 sun 移動到原點各方向所需要的距離
//dx2, dy2, dz2 是將 earth 移動到原點各方向所需要的距離
[一] 公轉
1. 目的: 物體或模型繞著某個點轉 (通常是原點)
2. 想法: 在 openGL 的函式庫中,glRotate*() 是繞著原點轉的,所以我們應該先計算
出將太陽移動至原點的距離,而後讓整個太陽系的所有物體都依照這個距離移動,
再讓地球旋轉,最後再將物體移回原來的位置
(p.s) 測試過後,openGL 的 rotate 並不會像之前實作一樣讓整個單位向量跑掉,所以可以這樣做
3. pseudo code:
// 畫地球
glPushMatrix();
glTranslate(dx, dy, dz);
glRotate(angle, ...);
glTranslate(-dx, -dy, -dz);
... draw earth ...
glPopMatrix();
//畫月亮
glPushMatrix();
glTranslate(dx2, dy2, dz2);
glRotate(angle, ...);
glTranslate(-dx2, -dy2, -dz2);
... draw moon ...
glPopMatrix();
//畫太陽
... draw sun ...
//dx, dy, dz 是將 sun 移動到原點各方向所需要的距離
//dx2, dy2, dz2 是將 earth 移動到原點各方向所需要的距離
[二] 自轉
1. 目的: 物體或模型繞著某個點轉 (通常是自己的中心點)
2. 想法: 用跟上面一樣的概念,所以要自轉的物體,一樣要先旋轉的中心點移動到坐標系中
的原點處,而後旋轉在移回原來的位置
3. pseudo code:
// 讓地球又公轉又自轉
glPushMatrix();
glTranslate(dx, dy, dz);
glRotate(angle, ...);
glTranslate(-dx, -dy, -dz);
glTranslate(dx2, dy2, dz2);
glRotate(angle, ...);
glTranslate(-dx2, -dy2, -dz2);
... draw earth ...
glPopMatrix();
//dx, dy, dz 是將 sun 移動到原點各方向所需要的距離
//dx2, dy2, dz2 是將 earth 移動到原點各方向所需要的距離
2. 想法: 用跟上面一樣的概念,所以要自轉的物體,一樣要先旋轉的中心點移動到坐標系中
的原點處,而後旋轉在移回原來的位置
3. pseudo code:
// 讓地球又公轉又自轉
glPushMatrix();
glTranslate(dx, dy, dz);
glRotate(angle, ...);
glTranslate(-dx, -dy, -dz);
glTranslate(dx2, dy2, dz2);
glRotate(angle, ...);
glTranslate(-dx2, -dy2, -dz2);
... draw earth ...
glPopMatrix();
//dx, dy, dz 是將 sun 移動到原點各方向所需要的距離
//dx2, dy2, dz2 是將 earth 移動到原點各方向所需要的距離
2013年12月9日 星期一
[openGL] glPushMatrix() 和 glPopMatrix()
首先,先說明一下,網路上查關於 openGL 的內容,常常會提到 CM,CM 是 Current Matrix 的簡寫,也就是目前 matrix 內的內容。
要了解的話,可以先從最下面「 [三] 例子」,開始看。
[一] glPushMatrix()
1. 功能: 將 CM push 到 stack 中,而依不同的機器 stack 可以存放 matrix 的數量有所不同
2. 目的: 為了各種原因,保存目前的 CM,等待之後再進行使用 (下面有原因的例子)
[二] glPopMatrix()
1. 功能: pop 出 stack 中的 matrix,並且把現在的 CM 取代掉
2. 目的: 一樣也是為了各種原因,把之前儲存在 stack 中的 matrix,讀回來繼續使用
[三] 例子
1.
glTranslated(0, 10, 0);
... draw A ...
glPushMatrix();
glRotatef(90, 0, 1, 0);
... draw B ...
glPopMatrix();
... draw C ...
: A 、 B、C 三個都會平行 y 軸移動 10 單位,只是 B 還會繞 y 軸旋轉 90 度
: 在畫完 A 之後,CM 中保存著往 y 方向移動 10 的內容,之後 glPushMatrix() 把這
個 CM 存進 stack 中,而第四行再把目前的 CM 旋轉 90 度,在畫完 B 之後,
glPopMatrix() 把 stack 中向 y 方向移動 10 的內容讀取出來把目前有移動又有旋轉的
CM 取代掉,因此 C 就只有移動了
2.
glTranslated(0, 10, 0);
... draw A ...
glPushMatrix();
glLoadIdentity();
glRotatef(90, 0, 1, 0);
... draw B ...
glPopMatrix();
... draw C ...
: A、C 三個都會平行 y 軸移動 10 單位,B 只會繞 y 軸旋轉 90 度
: 跟上面例子不同之處,在於 glPushMatrix() 之後,有多做一個 glLoadIdentity() 的動作,
因為目前的 CM 就變回最剛開始的單位矩陣,什麼動作都沒有做,因此,
B 就只有對 y 軸旋轉 90 度,之後把之前的 matrix pop回來,則現在的 CM 就有了
移動的內容,而他對 C 做運算之後,C也有了移動的
[總結]
有時候可能需要把目前移動、旋轉等等的資訊記錄起來,把其他運算做完之後,
再把原本存起來的資訊讀回來繼續使用,這時候就可以使用 glPushMatrix()、glPopMatrix(),
(例如最近在做的小小賽車遊戲,因為是讀取 .obj 檔來使用,所以每一個模型面向的方向、
位置等等都要再重新做設定,但是除了每一個模型自己旋轉移動到正確的位置外,
也要能夠跟著其他模型大家一起旋轉,就非常需要這種功能)
要了解的話,可以先從最下面「 [三] 例子」,開始看。
[一] glPushMatrix()
1. 功能: 將 CM push 到 stack 中,而依不同的機器 stack 可以存放 matrix 的數量有所不同
2. 目的: 為了各種原因,保存目前的 CM,等待之後再進行使用 (下面有原因的例子)
[二] glPopMatrix()
1. 功能: pop 出 stack 中的 matrix,並且把現在的 CM 取代掉
2. 目的: 一樣也是為了各種原因,把之前儲存在 stack 中的 matrix,讀回來繼續使用
[三] 例子
1.
glTranslated(0, 10, 0);
... draw A ...
glPushMatrix();
glRotatef(90, 0, 1, 0);
... draw B ...
glPopMatrix();
... draw C ...
: A 、 B、C 三個都會平行 y 軸移動 10 單位,只是 B 還會繞 y 軸旋轉 90 度
: 在畫完 A 之後,CM 中保存著往 y 方向移動 10 的內容,之後 glPushMatrix() 把這
個 CM 存進 stack 中,而第四行再把目前的 CM 旋轉 90 度,在畫完 B 之後,
glPopMatrix() 把 stack 中向 y 方向移動 10 的內容讀取出來把目前有移動又有旋轉的
CM 取代掉,因此 C 就只有移動了
2.
glTranslated(0, 10, 0);
... draw A ...
glPushMatrix();
glLoadIdentity();
glRotatef(90, 0, 1, 0);
... draw B ...
glPopMatrix();
... draw C ...
: A、C 三個都會平行 y 軸移動 10 單位,B 只會繞 y 軸旋轉 90 度
: 跟上面例子不同之處,在於 glPushMatrix() 之後,有多做一個 glLoadIdentity() 的動作,
因為目前的 CM 就變回最剛開始的單位矩陣,什麼動作都沒有做,因此,
B 就只有對 y 軸旋轉 90 度,之後把之前的 matrix pop回來,則現在的 CM 就有了
移動的內容,而他對 C 做運算之後,C也有了移動的
[總結]
有時候可能需要把目前移動、旋轉等等的資訊記錄起來,把其他運算做完之後,
再把原本存起來的資訊讀回來繼續使用,這時候就可以使用 glPushMatrix()、glPopMatrix(),
(例如最近在做的小小賽車遊戲,因為是讀取 .obj 檔來使用,所以每一個模型面向的方向、
位置等等都要再重新做設定,但是除了每一個模型自己旋轉移動到正確的位置外,
也要能夠跟著其他模型大家一起旋轉,就非常需要這種功能)
訂閱:
文章 (Atom)