當前位置:編程學習大全網 - 源碼下載 - OpenGL ES 3.0 (5)坐標系

OpenGL ES 3.0 (5)坐標系

之前關於OpenGLES的文章:

OpenGL ES 2.0顯示圖形(上)

OpenGL ES 2.0顯示圖形(下)

OpenGL ES 3.0概述(1)

OpenGL ES 3.0 (2) GLSL和著色器

OpenGL ES 3.0 (3)紋理

OpenGL ES 3.0 (4)矩陣轉換

在前面的討論中,我們用矩陣的變換來變換所有的頂點。OpenGL ES希望在每個頂點著色器運行後,所有可見的頂點都將是歸壹化的設備坐標(NDC)。也就是說,每個頂點的x,y,z坐標應該在-1.0到1.0之間,超出這個坐標範圍的頂點是看不到的。在開發時,您可以自己設置壹個坐標範圍,然後在頂點著色器中將這些坐標轉換為標準化的設備坐標。然後,這些標準化的設備坐標被傳輸到光柵化器,並被轉換成屏幕上的二維坐標或像素。

將坐標轉換為標準化設備坐標,然後轉換為屏幕坐標的過程通常是逐步進行的。對象的頂點在最終轉換為屏幕坐標之前,將被轉換為多個坐標系。把壹個物體的坐標變換到幾個過渡坐標系的好處是,在這些特定的坐標系中,有些運算或計算更加方便和容易。壹般來說,比較重要的總* * *有五種不同的坐標系:

局部空間(或對象空間)。

世界空間(世界空間)

觀察空間(視圖空間或眼睛空間)。

剪輯空間(剪輯空間)

屏幕空間(屏幕空間)

這是壹個頂點在最終轉化為片段之前需要經歷的所有不同狀態。

為了將坐標從壹個坐標系轉換到另壹個坐標系,需要幾個轉換矩陣,其中最重要的是模型、視圖和投影。頂點坐標從局部空間開始,稱為局部坐標。它會變成世界坐標,視圖坐標,剪輯坐標,最後以屏幕坐標的形式結束。下圖顯示了整個過程以及每個轉換過程所做的工作:

①局部坐標系:物體相對於局部原點的坐標也是物體原點的坐標。

②世界坐標系:世界坐標系在更大的空間範圍內。這些坐標是相對於世界的全局原點的,它們會和其他相對於世界原點的物體放在壹起。

③觀察坐標系:觀察坐標系下的每個坐標都是從相機或觀察者的角度觀察的。

④裁剪坐標系:坐標到達觀測空間後,需要投影到裁剪坐標系。裁剪坐標會處理到-1.0到1.0的範圍內,判斷屏幕上會出現哪些頂點。

⑤屏幕坐標系:用壹個叫Viewport Transform的過程,把裁剪坐標變成屏幕坐標。viewport轉換將-1.0到1.0範圍內的坐標轉換為由glViewport()定義的坐標範圍。最後,轉換後的坐標將被發送到光柵化器並轉換成片段。

以上是各坐標系的通用功能。之所以把頂點變換到不同的空間,是因為在特定的坐標系中,有些操作是有意義的,也更方便。比如需要修改對象時,在局部空間操作更合理;如果要操作壹個物體相對於其他物體的位置,在世界坐標系中這樣做更合理,以此類推。其實也可以定義壹個變換矩陣,直接從局部空間變換到裁剪空間,但是那樣會損失很多靈活性。

局部坐標系空間是指物體所在的坐標系空間,也就是物體壹開始所在的地方。例如,在建模軟件中創建壹個立方體。創建的立方體的原點可能位於(0,0,0),即使它可能在程序中完全不同的位置結束。甚至可以創建所有以(0,0,0)為初始位置的模型,但它們最終會出現在世界的不同地方。因此,模型的所有頂點都在局部系統空間中,並且它們都是對象的局部。

如果把所有的對象都導入到程序中,它們可能都被擠壓在世界的原點(0,0,0),這不是想要的結果。理想情況下,為每個對象定義壹個位置,以便它們可以被放置在更大的世界中。顧名思義,世界空間中的坐標系是指頂點相對於世界的坐標。物體的坐標將從局部空間轉換到世界空間;這種轉換壹般通過模型矩陣來實現。模型矩陣是壹種變換矩陣,它可以通過移動、縮放和旋轉將對象放置在原來的位置或方向。

觀察坐標系空間常被稱為OpenGL ES的相機視角,所以有時也被稱為相機空間或眼睛空間。觀察坐標系空間是將世界空間坐標轉化為用戶視野前方坐標的結果。因此,觀察坐標系空間是從相機視角觀察的空間。這通常是通過壹系列位移和旋轉的組合來完成的,平移/旋轉場景,以便特定的對象在相機前面被變換。這些組合變換通常存儲在視圖矩陣中,該矩陣用於將世界坐標變換到觀察空間中。更詳細的信息將在後面的專門文章中討論。

在頂點著色器的操作結束時,OpenGL ES希望所有坐標都落在特定範圍內,任何超出該範圍的點都應該被裁剪掉。被剪切的坐標將被忽略,因此剩余的坐標將成為屏幕上可見的片段。這也是剪裁坐標系空間名稱的由來。

因為指定-1.0到1.0範圍內的所有可見坐標並不直觀,所以我們將指定自己的坐標集,並將其轉換回標準化的設備坐標系,正如OpenGL ES所期望的那樣。為了將頂點坐標從觀測坐標系空間轉換到裁剪坐標系空間,需要定義壹個投影矩陣,該投影矩陣指定壹個坐標範圍,比如每個維度上的-1000到1000。然後,投影矩陣會將該指定範圍內的坐標轉換為標準化設備坐標的範圍(-1.0,1.0)。範圍之外的所有坐標都不會被映射到-1.0到1.0的範圍內,所以它們會被切掉。在上面投影矩陣指定的範圍內,坐標(1250,500,750)會不可見,因為它的X坐標在範圍之外,換算成大於1.0的標準化設備坐標,所以被裁剪掉。

如果只有壹部分圖元(如三角形)超出了裁剪體積,OpenGL ES會將該三角形重建為壹個或多個三角形,以適應裁剪範圍。

投影矩陣創建的查看框稱為平截頭體,平截頭體內出現的每個坐標最終都會出現在用戶的屏幕上。將特定範圍內的坐標轉換到標準化設備坐標系(並且可以很容易地映射到2D觀測空間坐標)的過程稱為投影,因為可以將3D坐標投影到標準化設備坐標系中,利用投影矩陣可以很容易地將標準化設備坐標系映射到2D。

壹旦所有的頂點都被變換到裁剪空間中,將進行最後的操作-透視除法,其中位置向量的X、Y和Z分量分別被向量的齊次W分量除。透視分割是將4D裁剪空間的坐標轉換為三維標準化設備的坐標的過程。該步驟在每次頂點著色器運行結束時自動執行。在這個階段之後,最終的坐標將被映射到屏幕空間(使用glViewport中的設置)並被轉換成片段。

將觀察坐標轉換為裁剪坐標的投影矩陣可以有兩種不同的形式,每種形式定義壹個不同的截錐。您可以選擇創建正投影矩陣或透視投影矩陣。

正投影矩陣定義了壹個類似立方體的平截頭體盒子,它定義了壹個裁剪空間,這個空間之外的所有頂點都會被裁剪掉。創建正交投影矩陣需要指定可見平截頭體的寬度、高度和長度。將正投影矩陣轉換到裁剪空間後,該平截體中的所有坐標都不會被裁剪掉。它的平截頭體看起來像壹個容器;

上面的平截頭體定義了可見坐標,由寬度、高度、近平面和遠平面指定。出現在近平面之前或遠平面之後的任何坐標都將被剪切掉。正交平截頭體直接將平截頭體內的所有坐標映射到標準化的設備坐標上,因為每個矢量的W分量沒有變化。如果w分量等於1.0,透視分割法則不會改變這個坐標。

要創建正投影矩陣,可以使用android.opengl.Matrix下的內置函數orthoM():

上面的第壹個參數是要變換的矩陣存儲數組,第二個參數距離第壹個參數數組的偏移位置,第三個、第四個、第五個、第六個參數分別對應截斷的左、右、下上邊界,第七個、第八個參數對應近平面和遠平面之間的距離。該投影矩陣將把這些x、y和z值內的坐標轉換成標準化的設備坐標。

映射原理如下:

如上圖所示,裁剪空間中的所有x、y和z分量都線性映射到NDC。只需將矩形體積縮放為立方體,然後將觀測坐標系原點移動到標準化設備坐標原點即可。最終的圖像是標準化後的效果。

正投影矩陣直接將坐標映射到2D平面,即屏幕上,但實際上,直接投影矩陣會產生不真實的結果,因為這種投影沒有考慮透視。所以需要透視投影矩陣來解決這個問題。

肉眼的直觀感受是近的大,遠的小,這種視覺效果叫做透視。透視投影就是用透視投影矩陣來模仿肉眼的這種效果。這個透視投影矩陣將給定的視錐範圍映射到裁剪空間,此外,它還修改了每個頂點坐標的W值,使得離觀察者越遠,頂點坐標的W分量越大。轉換到剪輯空間的坐標將在-w到w的範圍內(任何大於此範圍的坐標都將被剪輯)。OpenGL ES要求所有可見坐標都在-1.0到1.0的範圍內,作為頂點著色器的最終輸出。因此,壹旦坐標位於裁剪空間內,透視分割將應用於裁剪空間坐標:

頂點坐標的每個分量都會除以它的w分量,離觀察者越遠,頂點坐標就越小。這也是W組件非常重要的另壹個原因,可以幫助開發者進行透視投影。最終結果坐標位於標準化設備空間中。

在android.opengl.Matrix中,您可以創建壹個透視投影矩陣,如下所示:

perspectiveM()所做的實際上是創建壹個定義視覺空間的大型平截頭體。這個截錐之外的任何東西最終都不會出現在裁剪空間體積中,都會被裁剪掉。透視平截頭體可以看作壹個形狀不均勻的盒子,盒子內部的每壹個坐標都會映射到裁剪空間中的壹個點上。以下是透視平截頭體的圖片:

上述函數的第壹個參數是要轉換的矩陣存儲數組,第二個參數是從第壹個參數數組的偏移位置,第三個參數表示視角。如果您想要壹個真實的觀察效果,其值通常設置為45.0f。第四個參數設置長寬比,這是通過將視口的寬度除以高度獲得的。第三和第四個參數設置平截頭體的近平面和遠平面。通常短距離設置為0.1f,長距離設置為100.0f,近平面和遠平面以及平截頭體中的所有頂點都會被渲染。當透視矩陣的near值設置過大(例如10.0f)時,OpenGL ES會裁剪出靠近攝像頭的坐標(在0.0f到10.0f之間),這就導致了當距離物體太近時視線直接穿過物體的情況。

透視投影到標準化設備坐標的映射原理如下:

在透視投影中,截頭棱錐體中的3D點(觀察坐標)被映射到立方體(NDC)。x坐標範圍從[l,r]到[-1,1],Y坐標範圍從[b,t]到[-1,1]和[-n,-f]到[-65438+]。這裏需要註意的是,OpenGL ES中的觀測坐標是在右手坐標系中定義的,但是NDC使用的是左手坐標系。也就是說,原點處的相機在觀察空間中沿著-Z軸看,但是在NDC中沿著+Z軸看。

上述每個步驟都創建了壹個轉換矩陣:模型矩陣、觀測矩陣和投影矩陣。頂點坐標將根據以下過程轉換為裁剪坐標:

註意矩陣運算的順序是相反的,也就是妳需要從右向左讀矩陣的乘法。最後壹個頂點要賦給頂點著色器中的gl_Position,OpenGLES會自動進行透視分割和裁剪。頂點著色器的輸出要求所有頂點都在剪輯空間中,這正是我們剛才對變換矩陣所做的。然後,OpenGL ES對裁剪坐標執行透視分割,將它們轉換為標準化的設備坐標。OpenGL ES將使用glViewPort內部的參數將標準化的設備坐標映射到屏幕坐標,每個坐標都與屏幕上的壹個點相關聯。

有了之前坐標系的鋪墊,就可以用OpenGL ES正式創建三維物體,而不是之前的二維物體。

首先,創建壹個模型矩陣。這個模型矩陣包括位移、縮放和旋轉操作,這些操作將應用於所有對象的頂點,以將它們轉換到全局世界空間。變換前面文章中顯示的平面,並圍繞X軸旋轉,使其看起來像在地面上。為了與下面兩節保持壹致,模型生成操作放在draw()中,模型矩陣看起來是這樣的:

通過將頂點坐標乘以該模型矩陣,頂點坐標被轉換成世界坐標。原則的平面似乎在地板上,代表著全球世界中的平面。

接下來,您需要創建壹個觀察矩陣。如果妳想在場景中向後移動壹點使物體可見,當妳在世界空間中時,默認的觀察點,也就是相機的位置,在原點(0,0,0)。所以向後移動相機和向前移動整個場景是壹樣的。

這正是觀察矩陣所做的,以相機運動的相反方向移動整個場景。因為要向後移動,而OpenGL ES是右手坐標系,所以需要沿著Z軸的正方向移動。這是通過沿著z軸的負方向平移場景來實現的。會給我們壹種倒退的感覺。這裏的觀察矩陣如下:

最後要做的是定義壹個投影矩陣。在場景中使用透視投影,因此像這樣聲明壹個投影矩陣:

既然已經創建了變換矩陣,就應該將它們傳遞到著色器中。首先,在頂點著色器中聲明三個統壹的變換矩陣,並將它們乘以頂點坐標:

您還應該將矩陣傳遞到著色器中,這通常在每次渲染叠代中完成,因為變換矩陣經常變化:

經過這樣的操作,利用模型、觀測和投影矩陣對頂點坐標進行了變換,最終效果如下:

到目前為止,雖然它是在三維空間,但它仍然在2D平面上運行。本章將討論渲染立方體的3D效果的實現。首先,壹個* * *需要36個頂點(6個面x每個面有2個三角形,每個三角形有3個頂點)。這36個頂點的位置如下:

讓我們讓壹個立方體隨時間旋轉,同時將頂點數改為36:

這時,妳會得到以下效果:

上面出現的效果確實有點像立方體,但是明顯感覺有問題。應該被覆蓋的立方體的壹些面被繪制在立方體的其他面上。之所以會這樣,是因為OpenGL ES是壹個三角形壹個三角形的繪制立方體的,所以即使之前有,也會覆蓋之前的像素。由於這個原因,壹些三角形將被繪制在其他三角形的上面,盡管它們不應該被覆蓋。OpenGL ES將深度信息存儲在壹個名為Z-buffer的緩沖區中,該緩沖區允許OpenGL ES決定何時覆蓋像素,何時不覆蓋像素。通過使用z-buffer,可以配置OpenGL進行深度測試。

OpenGL ES將其所有深度信息存儲在z緩沖區中,也稱為深度緩沖區。OpenGL ES的窗口管理系統會自動生成這樣壹個緩沖區(就像它也有壹個顏色緩沖區來存儲輸出圖像的顏色壹樣)。深度值作為剪輯的Z值存儲在每個剪輯中。當壹個剪輯想要輸出它的顏色時,OpenGL ES會將其深度值與Z緩沖區進行比較。如果當前剪輯在其他剪輯之後,它將被丟棄,否則將被覆蓋。這個過程叫做深度測試,由OpenGL ES自動完成。

如果妳想確定OpenGL ES真的執行深度測試,妳應該先告訴OpenGL ES妳想啟用深度測試。默認情況下是關閉的。可以通過GLES30.glEnable()函數打開深度測試。GLES30.glEnable()和GLES30glDisable()允許開發人員啟用或禁用OpenGL ES函數。該功能將保持啟用/禁用狀態,直到另壹個調用將其禁用/啟用。現在要啟用深入測試,需要打開GLES30。GL_DEPTH_TEST。

因為使用了深度測試,並且您希望在每次渲染叠代之前清除深度緩沖區,所以前壹幀的深度信息仍然存儲在緩沖區中。就像清除顏色緩沖壹樣,可以通過在glClear()中指定DEPTH_BUFFER_BIT位來清除深度緩沖,別忘了上壹篇文章提到的自動動態刷新需要註釋掉GLSurfaceView的RENDERMODE_WHEN_DIRTY:

效果如下:

現在我想在屏幕上顯示4個立方體。每個立方體看起來都壹樣,不同的是它們在世界上的位置和旋轉角度不同。已經定義了立方體的圖形布局,所以在渲染更多的對象時,不需要改變緩沖區數組和屬性數組。唯壹需要做的就是改變每個物體的模型矩陣,將立方體變換到世界坐標系。

首先,讓我們為每個立方體定義壹個位移向量來指定它在世界空間中的位置。

現在,在循環中,gldrawarrays()被調用了四次,但這壹次在渲染之前,不同的模型矩陣被傳遞到頂點著色器中。遊戲循環中會創建壹個小循環,用不同的模型矩陣渲染物體4次。請註意,每個框還添加了壹點旋轉:

最終效果如下:

  • 上一篇:什麽模擬器可以進快手語音廳
  • 下一篇:JAY的《彩虹》裏有壹句歌詞這樣寫到:“也許時間是壹種解藥;也是我現在正服下的毒藥。”請對這句話談談妳
  • copyright 2024編程學習大全網