OPENGL坐標系可分為:世界坐標系和當前繪圖坐標系。
世界坐標系:在OpenGL中,世界坐標系是以屏幕中心為原點(0, 0, 0),且是始終不變的。你面對屏幕,你的右邊是x正軸,上面是y正軸,屏幕指向你的為z正軸。長度單位這樣來定:窗口范圍按此單位恰好是(-1,-1)到(1,1),即屏幕左下角坐標為(-1,-1),右上角坐標為(1,1)。
當前繪圖坐標系:是繪制物體時的坐標系。程序剛初始化時,世界坐標系和當前繪圖坐標系是重合的。當用glTranslatef(),glScalef(), glRotatef()等對當前繪圖坐標系進行平移、伸縮、旋轉變換之后,世界坐標系和當前繪圖坐標系不再重合。注意,這里的平移旋轉是將當前繪圖坐標系看做一個整體在世界坐標系中進行旋轉平移。然后,改變以后,再用glVertex3f()等繪圖函數繪圖時,都是在當前繪圖坐標系進行繪圖,所有的函數參數也都是相對當前繪圖坐標系來講的。
齊次坐標
只講三維的情況啊
向量空間中,只有標量和向量
向量 + 向量 = 向量
標量 * 向量 = 向量
三維向量空間中,可以視任意一組線性無關的向量為基
基 V = [ v1 , v2 , v3 ]
其他向量可以用一個三維的元組來表示
向量 a = [ A1 , A2 , A3 ]
于是 向量 a = A1 * v2 + A2 * v2 + A3 * v3
僅有向量是無法表示幾何的,至少要有點吧
一般認為點的表示也是一個三維的元組
點 b = [ B1 , B2 , B3 ]
這樣就無法區分點和向量了,咋辦?
仿射空間
仿射空間中,基稱為標架,由三個向量和一個點組成
標架 V = [ v1 , v2 , v3 , p ]
仿射空間的運算
向量+ 向量 = 向量
標量 * 向量 = 向量
點 + 向量 = 點
PS:可以看到,點與向量的和為另一個點,其實也可以認為向量記錄的是點的運動,記錄著一個點轉換到另一個點的信息
于是
向量 a = [ a1 , a2 , a3 , 0 ]
點 b = [ b1 , b2 , b3 , 1 ]
即
a = a1 * v1 + a2 * v2 + a3 * v3 , 確實是向量
b = b1 * v1 + b2 * v2 + b3 * v3 + p
b = 向量 + p = 點
勉強區分開了哈
還有問題
點p和向量v1v2v3怎么確定?它們的值又是在那種標架或基下的?
所以討論了再多,這個標架其實還是對應我們普通的三維坐標系才顯得平易近人,即
點p為原點
v1 v2 v3 分別對應三個坐標軸 [1,0,0]、[0,1,0]、[0,0,1]
只不過我還告訴你,對于任意一個點和任意三個線性無關的向量v1 v2 v3,其都可以當作一個標架。因為三個線性無關的向量就可以表示出任意一個向量,再有一個點為基礎,就可以表示任意一個點
所以想OpenGL中就默認,其世界坐標系對應的仿射空間,p為原點,v1v2v3為坐標軸
但是相機坐標系就不是了,因為啥?因為相機可以移動啊,可以改變朝向和正向,這些都影響著相機坐標系。單就移動來說:
相機的默認位置是在世界坐標系的原點,移動了之后就不是了啊
那么你在相機的位置看世界坐標系上的點,那些點的坐標表示就應該轉換到相機坐標系上來,才對應著我們真正應該看到的點的位置
還是寫寫坐標系比較實在
坐標系
世界坐標系
世界坐標系的標架
相機坐標系
相機默認的位置為世界坐標系原點,朝向是Z軸的負方向,正向是Y軸的正方向
考慮相機
位置就是相機的位置,也就是從哪里去觀察這個世界
朝向就是相機對準的方向
正向就是相機該放在這個位置、對準了方向后,該怎么擺。比如一般我們拍照,豎著擺拍出來的就是豎著的照片,橫著擺就是橫著的照片。
而這些參數其實也是在世界坐標系下表示的
默認的相機坐標系
移動相機之后,相機的位置、朝向、正向就改變了
但頂點的數據還是對應著的世界坐標系,而我們要生成圖片是依賴于相機的,所以我們要把頂點轉換到相機坐標系下才行,這就是視圖的轉換。
視圖轉換后頂點的表示就是相對于相機坐標系,但其標架在邏輯上依然是 原點+三個坐標軸
裁剪坐標系
這還只是相機的外部參數,我們還需要確定
那一塊的三維區域內的點,我才會拍下來,才會用來生成圖像,即我需要規定一塊“視景體”來確定拍照的范圍
是否需要透視效果等等其他
還是講坐標變換比較實在
坐標變換
OpenGL主要有兩個矩陣,模型視圖矩陣和投影矩陣
模型視圖矩陣
對世界坐標系下頂點的變化操作,如平移、旋轉、縮放(模型)都是對頂點的變化,而相機的位置、朝向、正向的改變(視圖)也需要頂點從相對于世界坐標系下轉換到相對于相機坐標系,這兩種雖然是不同的改變但都是對頂點的操作,所以可以用一個矩陣來記錄
就是說只要在原先點的基礎上左乘平移矩陣,就可以把點的坐標進行平移變換
記平移矩陣 T 為 T(dx,dy,dz),
旋轉
先考慮繞Z軸旋轉的情況,正向的旋轉為右手大拇指朝向Z軸正向時,其余手指的朝向(逆時針)
繞Z軸旋轉至改變X和Y坐標
縮放,就是在原坐標的基礎上乘以某個倍數
縮放矩陣
視圖矩陣,將以世界坐標系原點為(0,0,0)點的世界坐標系下的頂點轉換到以相機位置為(0,0,0)的相機坐標系下。
頂點和相機之間真正相對位置是不變的,只不過我們原先頂點的坐標表示是在世界坐標系下,而我們需要的是相機坐標系下的坐標表示。所以這里只是做坐標變換,即同一個頂點在不同坐標系下其坐標表示是不同的。
從默認的相機位置可以看到,默認的相機坐標系和世界坐標系是重合的,即不需要轉換,其實也就是相當于視圖矩陣是單位矩陣而已
而改變了相機的位置、朝向和正向之后,視圖矩陣才會真正的發揮作用,乘上的效果就是讓世界坐標系下的頂點轉換到相機坐標系下
OnenGL通過gluLookAt函數來改變相機的外部參數
gluLookAt( Tx , Ty , Tz , Ox , Oy , Oz , Vx , Vy , Vz )
Tx Ty Tz 為相機的位置
Ox Oy Oz 為相機朝向的點
Vx Vy Vz 為相機的正向
考慮相機的三個向量
n為相機朝向的方向向量
v為相機的正向向量
u為二者叉乘的向量
要求:n和v為互相垂直,nuv三者均為單位向量(只表方向)
那么可以看出這三個向量和相機坐標系的關系
并且我們還知道相機的位置 Tx Ty Tz
對于頂點
首先我們把相機移動到世界坐標系的原點,但因為我們要對頂點的數據進行修改,所以就要對頂點乘上 T( -Tx , -Ty , -Tz )這樣一個平移矩陣。這樣以來頂點移動到了就是以相機位置為原點的坐標系下
再求這個頂點在相機坐標系下的三個坐標的值。借助我們得出的 u,v,n三個向量,這三個向量分別對應了相機坐標系的三個坐標軸,所以要求坐標的值也就是看以這個頂點為終點、相機位置為起點的向量和nuv這三個單位向量的點積,相當于乘上這樣一個矩陣
然后我們得到了坐標的值嗎?還沒有。因為 向量n和坐標軸z的正向是相反的,向量u和坐標軸x的正向是相反的,所以我們還需要再乘上一個矩陣來調整
于是我們最終用來把世界坐標系下的點轉換到相機坐標系下的視圖矩陣就是
投影矩陣
模型操作對頂點進行變換,其還是在世界坐標系下
視圖操作將頂點轉換到相機坐標系下
但這二者都是對頂點進行變換,所以只需要一個模型-視圖矩陣來維護就可以了
那么投影矩陣就需要另外一個內存空間來維護
因為我們已經把頂點轉換到了相機坐標系下,所以我們設置視景體就以相機坐標系來設置
只會glOrtho的矩陣,即正交投影。其視景體是一個方形的區域。
glOrtho( left , right , bottom , top , near , far )
left,right分別對應了x=left和x=right這兩個平面
bottom和top分別對應了y=bottom和y=top這兩個平面
near和far分別對應了z=-near和z=-far兩個平面
這里取負,主要是因為相機的朝向是z的負方向,這樣才會使視景體落在相機的前面
投影矩陣要做的事情,就是一個“規范化”
即根據視景體的范圍,對頂點進行平移、放縮,使原先在視景體內的點都落在以原點為中心、邊長為2的規范化正方體內
這樣做的好處就是規范,之后的裁剪、光照等等操作都在一個統一的規范下進行
注意到我們放縮的時候,對于Z坐標的放縮多了一個負號,這也就意味著所有的點在規范化正方體內是Z坐標的負號是相反的
這也就意味著,我們要去“看”規范化正方體內的物體的時候,應該從Z軸的負無窮遠看向原點,即方向應該是Z的正向
這一步得到的點的坐標,我們稱其位于裁剪坐標系
評論
查看更多