天天看點

《OpenGL ES應用開發實踐指南:Android卷》—— 3.4 做最後的拼接

本節書摘來自華章出版社《opengl es應用開發實踐指南:android卷》一 書中的第3章,第3.4節,作者:(美)kevin brothaler ,更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。

我們在前兩章中用了很大篇幅為這個應用打下了很好的基礎:我們學習了如何使用屬性數組定義一個物體的結構,也學習了如何建立着色器、加載并編譯它們,以及把它們連結起來形成一個opengl的程式。

現在是時候在這個基礎上開始建構并把它們拼接起來了。在下面的幾個步驟裡,我們就要把這些部分拼在一起,并準備好把第一個版本的空氣曲棍球桌子畫到螢幕上。

在開始使用opengl的程式之前,我們首先應該驗證一下它,看看這個程式對于目前的opengl狀态是不是有效的。根據opengl es 2.0的文檔,它也給opengl提供了一種方法讓我們知道為什麼目前的程式可能是低效率的、無法運作,等等。

讓我們在shaderhelper中加入如下代碼:

《OpenGL ES應用開發實踐指南:Android卷》—— 3.4 做最後的拼接

我們調用glvalidateprogram()來驗證這個程式,然後用gl_validata_status作為參數調用glgetproramiv()方法檢查其結果。如果opengl有什麼有用的資訊要透露,這些資訊會顯示在程式日志裡,是以我們也用glgetprograminfolog () 把日志列印出來。

在開始使用這個程式之前,我們應該驗證它,并且我們應該隻有在開發或調試應用的時候才去驗證它。讓我們在onsurfacecreated()的結尾處加入如下代碼:

《OpenGL ES應用開發實踐指南:Android卷》—— 3.4 做最後的拼接

隻有日志需要打開時,它才會調用我們早前定義的驗證代碼。下一步我們應該做的就是使用曾花費了很大力氣建立的opengl程式。在onsurfacecreated()結尾處加入如下代碼:

《OpenGL ES應用開發實踐指南:Android卷》—— 3.4 做最後的拼接

調用gluseprogram()告訴opengl在繪制任何東西到螢幕上的時候要使用這裡定義的程式。

下一步是獲得我們早前在着色器中定義的uniform的位置。當opengl把着色器連結成一個程式的時候,它實際上用一個位置編号把片段着色器中定義的每個uniform都關聯起來了。這些位置編号用來給着色器發送資料,并且我們需要u_color的位置,以便我們可以在要繪畫的時候設定顔色。

讓我們快速看一下片段着色器:

《OpenGL ES應用開發實踐指南:Android卷》—— 3.4 做最後的拼接
《OpenGL ES應用開發實踐指南:Android卷》—— 3.4 做最後的拼接

在這個着色器裡,我們已經定義了一個稱為u_color的uniform,并在main()中把這個uniform的值賦給了gl_fragcolor。我們要使用這個uniform設定将要繪制的東西的顔色;我們要繪制一張桌子、一個中間分隔線和兩個木槌,并且我們要使用不同的顔色繪制它們。

讓我們在airhockeyrenderer的頂部加入如下定義:

《OpenGL ES應用開發實踐指南:Android卷》—— 3.4 做最後的拼接

我們已經為這個uniform的名字建立了一個常量和一個用來容納它在opengl程式對象中的位置的變量。uniform的位置并不是事先指定的,是以,一旦程式連結成功了,我們就要查詢這個位置。一個uniform的位置在一個程式對象中是唯一的:即使在兩個不同的程式中使用了相同的uniform名字,也不意味着它們使用相同的位置。

在onsurfacecreated()結尾處加入如下代碼:

《OpenGL ES應用開發實踐指南:Android卷》—— 3.4 做最後的拼接

我們調用glgetuniformlocation()擷取uniform的位置,并把這個位置存入ucolorlocation;當我們稍後要更新這個uniform值的時候,我們會使用它。

像uniform一樣,在使用屬性之前我們也要獲得它們的位置。我們可以讓opengl自動給這些屬性配置設定位置編号,或者在着色器被連結到一起之前,可以通過調用glbindattriblocation()由我們自己給它們配置設定位置編号。我們要讓opengl自動配置設定這些屬性位置,因為它使代碼更容易管理。

讓我們在airhockeyrender頂部加入如下定義:

《OpenGL ES應用開發實踐指南:Android卷》—— 3.4 做最後的拼接

一旦着色器被連結在一起了,我們就隻需要加入一些代碼去擷取屬性位置。在onsurfacecreated()結尾處加入如下代碼:

《OpenGL ES應用開發實踐指南:Android卷》—— 3.4 做最後的拼接

調用glgetattriblocation()擷取屬性的位置。有了這個位置,就能告訴opengl到哪裡去找到這個屬性對應的資料了。

下一步是要告訴opengl到哪裡找到屬性a_position對應的資料。

在onsurfacecreated()的結尾處加入如下代碼:

《OpenGL ES應用開發實踐指南:Android卷》—— 3.4 做最後的拼接

回到本章的開始處,我們建立了一個浮點數數組,這些浮點數表示組成空氣曲棍球桌子的頂點的位置;我們在本地記憶體中建立了一個緩沖區,稱為vertexdata,并把這些位置複制到這個緩沖區内。

在我們告訴opengl從這個緩沖區中讀取資料之前,需要確定它會從開頭處開始讀取資料,而不是中間或者結尾處。每個緩沖區都有一個内部的指針,可以通過調用position(int)移動它,并且當opengl從緩沖區中讀取時,它會從這個位置開始讀取。為了保證它一定從最開頭處開始讀取,我們調用position(0)把位置設在資料的開頭處。

然後我們調用glvertexattribpointer()告訴opengl,它可以在緩沖區vertexdata中找到a_position對應的資料。這是一個非常重要的函數,是以,讓我們仔細看一下每個參數傳遞了什麼(見表3-1)。

《OpenGL ES應用開發實踐指南:Android卷》—— 3.4 做最後的拼接

傳遞不正确的參數給glvertexattribpointer()會導緻奇怪的結果,甚至導緻程式崩潰。這種崩潰還很難跟蹤,是以,我不是言過其實,獲得正确的參數是非常重要的。

調用了glvertexattribpointer()之後,opengl就知道在哪裡讀取屬性a_position的資料了。

盡管我們已經把資料屬性連結起來了,在開始繪制之前,我們還需要調用glenablevertexattribarray()使能這個屬性。在glvertexattribpointer()調用之後加入如下代碼:

《OpenGL ES應用開發實踐指南:Android卷》—— 3.4 做最後的拼接

通過這最後一個調用,opengl現在就知道去哪裡尋找它所需要的資料了。

在這一節裡,我們取得了u_color(uniform)及a_position(屬性)的位置;每個變量都有一個位置,并且opengl将使用這些位置,而不是直接使用這些變量的名字;之後,我們調用glvertexattribpointer()告訴opengl,它可以從vertexdata找到屬性a_position的資料。

繼續閱讀