openGL中使用的是右手坐標系
- 右手坐標系:伸開右手,大拇指指向X軸正方向,食指指向Y軸正方向,其他三個手指指向Z軸正方向
-
左手坐標系:伸開左手,大拇指指向X軸正方向,食指指向Y軸正方向,其他三個手指指向Z軸正方向
兩者的區別主要是兩者Z軸的方向是相反的
左右手坐標系
一、坐標系
openGL中主要的幾種坐標系
-
世界坐標系
以屏幕中心為原點(0,0,0),當你面對屏幕時,右邊是X正軸,上方是Y軸正軸,屏幕指向你的方向為Z軸正軸。窗口范圍是從(-1,1),即屏幕左下角坐標為(-1,-1,0),右上角坐標為(1,1,0)。我們用這個坐標系描述物體及光源的位置
將物體放到場景中(平移、旋轉等),這些操作就是坐標變換。openGL中提供了glTranslate / glScale / glRotate 三條坐標變換命令,利用變換矩陣運算命令,則可以實現任意復雜的坐標變換 -
慣性坐標系
由世界坐標系和物體坐標系聯合理解
是物體坐標系的旋轉,只是一個中間狀態的描述,方便物體坐標系切換到世界坐標系 -
物體坐標系/局部空間坐標系
是以物體某一點為原點建立的坐標,該坐標僅對該物體適用,用來簡化對物體各部分坐標的描述。物體放到場景中時,各部分經歷的坐標變換相同,相對位置不變,可以視為一個整體 -
攝像機坐標系:觀察者坐標系
以觀察者為原點,視線的方向為Z軸的正方向。openGL管道會將世界坐標先變換到觀察者坐標,然后進行裁剪。只有視線范圍內的場景才會進行下一步的計算
坐標變換過程
openGL在每次頂點著色后,可見頂點都是標準化設備坐標,即每個頂點的x、y、z值都應該在-1到1之間,超出這個范圍的頂點是不可見的
將坐標轉換為標準化設備坐標,接著再轉換為屏幕坐標的過程是分步進行的,這個過程中,物體的頂點在最終轉換為屏幕坐標之前還會被轉換到多個坐標系統。在這些過度的特定坐標系中,一些操作或運算更加方便。
變換矩陣
為了將坐標從一個坐標系變換到另一個,我們需要用到幾個變換矩陣,常用有模型(Model)、觀察(View)、投影(Projection)三個矩陣
坐標變換矩陣棧
棧頂是當前坐標變換矩陣,進入openGL管道的每個坐標都會先乘以這個矩陣,結果才是對應點在具體場景中的世界坐標。openGL中的坐標變換是通過矩陣運算完成的。變換中的矩陣乘法是叉乘,結果中包含方向,不符合交換律。
物體頂點的起始坐標是局部坐標,之后會轉換為世界坐標、觀察者坐標、裁剪坐標,最后以屏幕坐標的形式結束。可以參考下面這張圖
二、坐標空間
局部空間
指的是物體所在的坐標空間,即對象最開始所在的地方,相對于這個物體來說是局部的
世界空間
是指物體的頂點相對于世界的坐標空間,物體分散在世界上擺放,則物體的坐標會從局部空間變換到世界空間。該變換是由模型矩陣(Model Matrix)實現的
- 模型矩陣 Model Matrix
是一種變換矩陣,可以通過對物體進行位移、縮放、旋轉來將它置于它該在的位置和朝向。可以想象為你想一把椅子放在一個房間內,需要先將它縮小(它在局部空間中太大了),并將它移動到房間的某個位置,然后在y軸上往左右旋轉一點以擺放整齊。就是將局部坐標變換到場景/世界中的不同位置
觀測空間/觀察空間
觀察空間也被稱為openGL的攝像機Camera,所以有時候也稱為攝像機空間(Camera space) 或視覺空間(Eye space)。觀察空間是將世界空間坐標轉換為用戶視野前方的坐標而產生的結果。也就是說,觀察空間,就是從攝像機的視角所觀察到的空間。
而這通常是由一系列的位移和旋轉的組合來完成的,平移/旋轉場景從而使特定的對象被變換到了攝像機的前方。
這些組合在一起的變換通常存儲在一個 觀察矩陣(View Matrix) 里,它被用來將世界坐標變換到觀察空間。
裁剪空間
- 裁剪過程
一個頂點著色器運行的最后,openGL希望所有的坐標都能落在一個特定的范圍內(-1,1),任何在這個范圍外的點都應該被裁剪(Clipped)掉。被Clipped的就會被忽略,余下的坐標就將變為屏幕上可見的片段。這個空間稱為裁剪空間
為了將頂點坐標從觀察者坐標變換到裁剪空間,我們需要定義一個投影矩陣(Projection Matrix),它可以指定一個范圍的坐標,投影矩陣會將在這個指定范圍內的坐標變換為標準化設備坐標的范圍(-1,1),所有在范圍外的坐標不會被映射在-1到1的范圍之間,所以會被裁剪掉
比如在每個維度上的-1000到1000,裁剪之后,坐標(12400,500,700)將是不可見的,因為其x坐標超出了范圍(大于1000),它被轉換為一個大于1的標準化設備坐標,所以被裁剪掉了
投影:將特定范圍內的坐標轉換為標準化設備坐標系的過程,稱為投影
平截頭體Frustum:由投影矩陣創建的觀察箱被稱為平接頭體,每個出現在平截頭體范圍內的坐標都會最終出現在用戶的屏幕上。(不太理解,是不是類似一個圓錐或圓柱,從中間用刀切開,那個切面的范圍,就相當于平截頭體???) - 透視除法 Perspective Division
一旦所有頂點被變換到裁剪空間,透視除法將會執行。這個過程中我們將位置向量的x,y,z分量分別除以向量的齊次分量w(深度)
透視除法是將4D裁剪空間坐標變換為3D標準化設備坐標的過程。這一步會在每一個頂點著色器運行的最后被自動執行。
之后,最終的坐標會被映射到屏幕空間中(使用glViewport中的設定),并被變換成片段
將觀察坐標變換為裁剪坐標的投影矩陣可以分為兩種不同的形式:正投影矩陣(Orthographic Projection Matrix)或透視投影矩陣(Perspective Projection Matrix)
投影方式
透視投影
現實生活中,離觀察者越遠的東西看起來越小,這個現象稱之為透視(Perspective)
openGL中的透視效果是由透視矩陣實現的。這個透視矩陣將給定的平截頭體范圍映射到裁剪空間,除此之外還修改了每個頂點坐標的w(深度)值,從而使得離觀察者越遠的頂點坐標的w分量越大。被變換到裁剪空間的坐標都會在-w到w之間。所以,一旦坐標在裁剪空間內之后,透視除法就會被應用到裁剪空間坐標上
正投影
當使用正投影時,每一個頂點坐標都會直接映射到裁剪空間中而不經過任何精細的透視除法(它仍然會進行透視除法,只不過w分量沒有被改變,保持為1,所以不起作用)
三、將坐標系統組合在一起
我們為上述的每一個步驟都創建了一個變化矩陣:模型矩陣、觀察矩陣、投影矩陣,一個頂點坐標將會根據以下過程被變換到裁剪坐標
Vclip = Mpro * Mview * Mmodel * Vlocal
這一系列的矩陣變換需要從右向左,依次是M V P。最后的頂點應該被賦值到頂點著色器中的gl_Position,openGL會自動進行透視除法和裁剪
視口變換:openGL對裁剪坐標執行透視除法從而將它們變換到標準化設備坐標,然后openGL會使用glViewPort內部的參數來將標準化設備坐標映射到屏幕坐標,每個坐標都關聯了屏幕上的一個點,這個過程稱為視口變換
上述過程,裁剪之前的坐標變換可以由開發者參與,裁剪和裁剪后續的動作,是系統完成的
參考:
https://blog.csdn.net/meegomeego/article/details/8686816
https://www.cnblogs.com/tandier/p/8110977.html