Go Mobile 例子 basic 源碼分析

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

OpenGL ES(OpenGL for Embedded Systems)是 OpenGL 三維圖形API的子集,針對手機、PDA和遊戲主機等嵌入式裝置而設計。該API由Khronos集團定義推廣,Khronos是一個圖形軟硬體行業協會,該協會主要關注圖形和多媒體方面的開放標準。

go 的 golang.org/x/mobile/gl 這個包 是基於OpenGL ES 2了, 文檔在: https://godoc.org/golang.org/x/mobile/gl 

Khronos的api文檔在https://www.khronos.org/opengles/sdk/docs/man/ 

 

以 gomobile 的例子中的 basic 例子(源碼在:https://github.com/golang/mobile/tree/master/example)為例,它的執行效果如下,

注意這是在不同長寬比下 mac 下執行效果, 放大或者縮小視窗大小,這個三角形會按照比率做自動變化。

 

源碼分析如下:

三角形座標定義:

Vertex (頂點)

頂點是3D建模時用到的最小構成元素,頂點定義為兩條或是多條邊交會的地方。在3D模型中一個頂點可以為多條邊,面或是多邊形所共用。一個頂點也可以代表一個點光源或是Camera的位置。

定義了三角形的三個頂點和對應的代碼實現:

這裡把float的座標轉換成 byte數組,它將會傳入OpenGl ES的圖形處理流程中。

這裡定義的不是固定像素尺寸,而是相對螢幕大小的尺寸(螢幕大小是2*2,具體原因後面解釋)。

使用 OpenGL 畫圖形需要定義的項

使用OpenGL ES 2.0畫一個定義好的形狀需要較多代碼,因為你需要提供很多圖形渲染流程的細節。具體而言,你必須定義如下幾項:

  • 頂點著色器(Vertex Shader):用來渲染形狀頂點的OpenGL ES代碼。
  • 片段著色器(Fragment Shader):使用顏色或紋理渲染形狀表面的OpenGL ES代碼。
  • 程式(Program):一個OpenGL ES對象,包含了你希望用來繪製一個或更多圖形所要用到的著色器。

你需要至少一個頂點著色器來繪製一個形狀,以及一個片段著色器為該形狀上色。這些著色器必須被編譯然後添加到一個OpenGL ES Program當中,並利用它來繪製形狀。

程式(Program)

 

為了繪製你的圖形,你必須編譯著色器代碼,將它們添加至一個OpenGL ES Program對象中,然後執行連結。在你的繪製對象時,上述步驟就只執行一次。

這裡的頂點著色器和片段著色器的具體含義後面分析。

著色器包含了OpenGL Shading Language(GLSL)代碼,它必須先被編譯然後才能在OpenGL環境中使用。要編譯這些代碼,需要在你的渲染器類中建立一個輔助方法,我們可以看到 gomobile 幫我們把這個方法封裝在CreateProgram 中了 :

下面代碼是 golang.org/x/mobile/exp/gl/glutil 的代碼。

 

Note:編譯OpenGL ES著色器及連結操作對於CPU周期和處理時間而言,消耗是巨大的,所以你應該避免重複執行這些事情。你應該在構建你的應用時,確保它們只被建立了一次,並且緩衝以備後續使用。

 

傳值給OpenGL

儘管我們已經有了資料,OpenGL並不能直接使用它們。OpenGL對它能讀取的記憶體有些限制。你可以按需分配你的頂點資料,但是這些記憶體對OpenGL並不直接可見。因此,第一步就是分配OpenGL可見的記憶體,並填充我們的資料。這是通過緩衝對象(buffer object,以下簡稱BO)來實現的。
一個緩衝對象,是一個線性數組形式的記憶體,由OpenGL根據使用者要求管理和分配。這塊記憶體的內容可由使用者控制,但是使用者也僅能間接地控制。可以把buffer object當做GPU記憶體中的數組。
GPU可以快速讀取它,因此在它裡面儲存資料有效能優勢。

前面我們已經有了頂點資料,問題是它在我們的RAM中而不是OpenGL的記憶體中。要把他搬到OpenGL的記憶體,需要做上面三行代碼:

第一行,建立buffer object。這時候我們還未給他分配任何空間。

第二行,BindBuffer函數將建立的BO綁定到ARRAY_BUFFER上下文中。

第三行,我們通過BufferData函數完成OpenGL中分配空間+資料拷貝的工作。

當這個函數執行完後,BO中就有了頂點資料了。這個函數最後的參數可以是下面值:

  • STATIC_DRAW 儲存的資料內容只被程式定義一次,GL繪製命令可以使用多次。本文執行個體代碼用的是這個。
  • DYNAMIC_DRAW 儲存的資料內容將被程式重複定義,GL繪製命令可以使用多次。

後面我們看到 triangleData 再也沒有被傳遞給 OpenGL 過,就是因為這個參數的讓後面複用了。

管道開關

有了頂點的定義,下面一步就是如何將它們傳給OpenGL ES庫,OpenGL ES提供一個成為”管道Pipeline”的機制,這個管道定義了一些“開關”來控制OpenGL ES支援的某些功能,預設情況這些功能是關閉的,如果需要使用OpenGL ES的這些功能,需要明確告知OpenGL “管道”開啟所需功能。

 

對於這個樣本,需要告訴OpenGL庫開啟 Vertex buffer以便使用頂點座標Buffer。

要注意的使用完某個功能之後,要關閉這個功能以免影響後續操作:

 

頂點著色器

這個例子中的 vertexShader 就是 頂點著色器

這裡的 version 100 是 Android、iOS、WebGL 使用的 OpenGL ES 2.0 對應的GLSL ES版本。參考: http://blog.csdn.net/u013467442/article/details/46765335 

uniform vec2 offset;
attribute vec4 position;

是兩個輸入參數,uniform 標示唯讀、attribute 標示專用於頂點著色器,唯讀。

vec2 標示只包含2個浮點的向量,vec4標示包含4個浮點的向量。

gl_Position是頂點著色器裁切空間輸出的位置向量。如果你想讓螢幕上渲染出東西gl_Position必須使用。否則我們什麼都看不到。

注意 gl_Position 的座標系跟手機螢幕座標像素的座標系不一樣。它的座標系是 右手座標系統。 詳見後面。

 

頂點著色器 position 賦值

GLSL 中的position (attribute 類型)是模型的原始座標,即這裡的 triangleData,

go中 position  變數則是這個位置指標。

對應代碼如下:

glctx.GetAttribLocation  返回指定屬性變數的位置。

returns the location of an attribute variable.
在 GetAttribLocation 這個函數這裡完成了映射捆綁。
 

賦值代碼在下面:

有關這個函數的聲明如下:

直接給 VertexAttribPointer 賦值是不支援的, 你需要使用 BindBuffer 綁定資料緩衝區,然後用 BufferData 來填充數值。本例子在初始化時賦值用了標示 STATIC_DRAW  , 即後面可以複用這個賦值。

Direct use of VertexAttribPointer to load data into OpenGL is not supported via the Go bindings. Instead, use BindBuffer with an ARRAY_BUFFER and then fill it using BufferData.

The stride argument specifies the byte offset between consecutive vertex attributes.

 

offset 的賦值

GLSL  中 offset 只是 uniform 的類型, 這樣的賦值就簡單多了。

建立 go 跟 openGL 的關聯指標

賦值,直接賦值,沒有上面 position 那麼多彎彎繞。

 

頂點的位置計算

計算中用到的幾個值:

1、touchX、touchY  觸點位置。

預設 touchX、touchY 是在螢幕的正中央,當有 touch 事件發生時,則是螢幕的對應位置。 以螢幕的實際像素為準。

螢幕的座標系如,左上方為原點,向右是X軸,向下是Y軸。

2、sz.WidthPx、sz.HeightPx  螢幕的實際大小尺寸。

對應座標也如。 WidthPx 是寬度、 HeightPx   是長度。

3、傳遞入 OpenGL 的 offset 值

offset.x 相對螢幕寬度的觸點位置 touchX/float32(sz.WidthPx)

offset.y 項目螢幕高度的觸點位置 touchY/float32(sz.HeightPx)

它們的值都是 0-1 之間。

4、傳遞入 OpenGL 的 position 值。

這個值就是 triangleData 的值,只是傳遞方法有點繞。

5、OpenGL 實際運算的 offset4

這裡要做座標體系的轉換。

vec4 offset4 = vec4(2.0*offset.x-1.0, 1.0-2.0*offset.y, 0, 0);

x 放大2倍,

 

我們會把下面這個基於像素的座標系(長寬 0到1)

轉換成下面OpenGL的座標系(OpenGL中使用, 長寬 -1到1)。

轉換的演算法就是上面的,2倍減一, 由於Y軸涉及到翻轉,再外面加一個負數。

6、OpenGL 的實際位置

在offset4位置畫模型,就是模型的具體實際位置。

gl_Position = position + offset4;

注意,這裡我們畫的三角形 top left 點 是上面的,而不是向下, 模型我們直接就用的 OpenGL的這個座標系。

由於座標系是從 -1到 1, 長度 0.4 就是 1/5 , 我們可以看到畫出來的三角形, 長寬 分別是螢幕尺寸的 1/5.

 

片段著色器

映像顏色的設定

fragmentShader

就是片段著色器

precision用來確定預設精度修飾符,precision mediump float; 基本相當於中等精度。

參考: http://blog.csdn.net/wangyuchun_799/article/details/7752322

uniform vec4 color  唯讀,4個浮點的向量 color。
所畫圖的顏色賦值過程

綁定關係

在應用啟動時,完成綁定關係


 

賦值

每次需要繪畫時,賦值。
 
 

Render (渲染)

我們已定義好了多邊形,下面就要瞭解如和使用OpenGL ES的API來繪製(渲染)這個多邊形了。OpenGL ES提供了兩類方法來繪製一個空間幾何圖形:

DrawArrays 使用VetexBuffer 來繪製,頂點的順序由vertexBuffer中的順序指定。

DrawElements 可以重新定義頂點的順序,頂點的順序由indices Buffer 指定。

前面我們已定義裡頂點數組,因此我們將採用 DrawArrays  來繪製多邊形。

同樣的頂點,可以定義的幾何圖形可以有所不同,比如三個頂點,可以代表三個獨立的點,也可以表示一個三角形,這就需要使用mode參數 來指明所需繪製的幾何圖形的基本類型。

有關各個 mode 的幾何類型請參考: http://www.imobilebbs.com/wordpress/archives/1512

 

Coordinate System座標系

OpenGL使用了右手座標系統,右手座標系判斷方法:在空間直角座標系中,讓右手拇指指向x軸的正方向,食指指向y軸的正方向,如果中指能指向z軸的正方向,則稱這個座標係為右手直角座標系。

 

座標轉換

OpenGL 繪圖過程中涉及到 座標系的轉換, 類似。

圖來自: http://zhangwenli.com/blog/2015/08/28/opengl-matrix-transformations/

 

使用e.External 避免多次刷屏繪畫

if glctx == nil || e.External {
    // As we are actively painting as fast as
    // we can (usually 60 FPS), skip any paint
    // events sent by the system.
    continue
}

 

顯示 fps 調試資訊

參考資料:

package gl 文檔
https://godoc.org/golang.org/x/mobile/gl

Android OpenGL ES 開發教程 從入門到精通   這裡講的是 OpenGL ES 1.1的知識
http://blog.csdn.net/mapdigit/article/details/7526556

繪製形狀
http://hukai.me/android-training-course-in-chinese/graphics/opengl/draw.html

OpenGL ES2 學習教程4——Shader語言
https://segmentfault.com/a/1190000004410579

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.