Android OpenGl ES 基礎入門知識

2021-02-25 Android 面試官

相信大家都聽過大名鼎鼎的 OpenGL,但可能大多數人沒有實踐使用過,本文就來介紹一下 Android OpenGl ES 的基礎入門知識。

或許你在工作中不會用到,但為你個人成長著想一下,擴展自己的知識廣度,總歸是有利無弊的,你說對吧?

本文分為以下四部分介紹:

建議收藏本文哦~

OpenGL 基礎概念OpenGL

OpenGL 即 Open Graphics Library,是一個功能強大、調用方便的底層圖形庫,它定義了跨程式語言、跨平臺的專業圖形程序接口,可用於二維或三維圖像的處理與渲染。

OpenGL 是跨平臺的,除了它純粹專注的渲染外,其他內容在每個平臺上都要有它的具體實現,比如上下文環境和窗口的管理就交由各個設備自己來完成。

OpenGL ES

OpenGL ES (OpenGL for Embedded Systems)是三維圖形 API OpenGL 的子集,針對手機、PDA 和遊戲主機等嵌入式設備而設計。

Android 對應 OpenGL ES 的版本支持如下:

Android 1.0 開始支持 OpenGL ES 1.0 及 1.1Android 2.2 開始支持 OpenGL ES 2.0Android 4.3 開始支持 OpenGL ES 3.0Android 5.0 開始支持 OpenGL ES 3.1

其中 OpenGL ES 1.0 是以 OpenGL 1.3 規範為基礎的,OpenGL ES 1.1 是以 OpenGL 1.5 規範為基礎的,而 OpenGL ES 2.0 基於 OpenGL 2.0 實現。

2.x 版本相比 1.x 版本有較大差異,1.x 版本為 fixed function pipeline,即固定管線硬體,而 2.x 版本為 programmable pipeline,可編程管線硬體。

固定管線中原本由系統做的一部分工作,在可編程管線中必須需要自己寫程序實現,具體程序為 vertex shader(頂點著色器)和 fragment shader(片元著色器)。

OpenGL 上下文

OpenGL 是一個僅僅關注圖像渲染的圖像接口庫,在渲染過程中它需要將頂點信息、紋理信息、編譯好的著色器等渲染狀態信息存儲起來,而存儲這些信息的數據結構就可以看作 OpenGL 的上下文。

調用任何 OpenGL 函數前,必須已經創建了 OpenGL Context,GL Context 存儲了 OpenGL 的狀態變量以及其他渲染有關的信息。

OpenGL 是個狀態機,有很多狀態變量,是個標準的過程式操作過程,改變狀態會影響後續所有操作,這和面向對象的解耦原則不符,畢竟渲染本身就是個複雜的過程。

OpenGL 採用 Client-Server 模型來解釋 OpenGL 程序,即 Server 存儲 GL Context(可能不止一個),Client 提出渲染請求,Server 給予響應,一般 Server 和 Client 都在我們的 PC 上,但 Server 和 Client 也可以是通過網絡連接。

之後的渲染工作就要依賴這些渲染狀態信息來完成,當一個上下文被銷毀時,它所對應的 OpenGL 渲染工作也將結束。

EGL

在 OpenGL 的設計中,OpenGL 是不負責管理窗口的,窗口的管理交由各個設備自己來完成,具體來講,IOS 平臺上使用 EAGL 提供本地平臺對 OpenGL 的實現,在 Android 平臺上使用 EGL 提供本地平臺對 OpenGL 的實現。

EGL 是 OpenGL ES 和 Android 底層平臺視窗系統之間的接口,在 OpenGL 的輸出與設備屏幕之間架接起一個橋梁,承擔了為 OpenGL 提供上下文環境以及管理窗口的職責。

EGL 為雙緩衝工作模式,即有一個 Back Frame Buffer 和一個 Front Frame Buffer,正常繪製的目標都是 Back Frame Buffer,繪製完成後再調用 eglSwapBuffer API,將繪製完畢的 FrameBuffer 交換到 Front Frame Buffer 並顯示出來。

從代碼層面來看,OpenGL ES 的 opengles 包下定義了平臺無關的繪圖指令,EGL(javax.microedition.khronos.egl)則定義了控制 displays,contexts 以及 surfaces 的統一的平臺接口:

Display(EGLDisplay) 是對實際顯示設備的抽象Surface(EGLSurface)是對用來存儲圖像的內存區域 FrameBuffer 的抽象,包括 Color Buffer、Stencil Buffer、Depth BufferContext(EGLContext)存儲 OpenGL ES 繪圖的一些狀態信息

使用 EGL 繪圖的一般步驟:

連接 EGLContext 和 EGLSurface斷開並釋放與 EGLSurface 關聯的 EGLContext 對象

一般來說在 Android 平臺上開發 OpenGL ES 應用,無需按照上述步驟來繪製圖形,可以直接使用 GLSurfaceView 控制項,該控制項提供了對 Display、Surface 以及 Context 的管理,大大簡化了開發流程。

OpenGL 紋理

紋理(Texture)是一個 2D 圖片(甚至也有 1D 和 3D 的紋理),它可以用來添加物體的細節;你可以想像紋理是一張繪有磚塊的紙,無縫摺疊貼合到你的 3D 的房子上,這樣你的房子看起來就像有磚牆外表了。

因為我們可以在一張圖片上插入非常多的細節,這樣就可以讓物體非常精細而不用指定額外的頂點。

OpenGL 坐標系理解

OpenGL 要求輸入的頂點坐標都是標準化設備坐標,即每個頂點的 x、y、z 都在 -1 到 1 之間,由標準化設備坐標轉換為屏幕坐標的過程中會經歷變換多個坐標系統,在這些特定的坐標系中,一些操作和計算可以更加方便。

局部坐標

頂點坐標起始於局部空間(Local Space),在這裡稱為局部坐標,是以物體某一點為原點而建立的,該坐標系僅對該物體適用,用來簡化對物體各部分坐標的描述。物體放到場景中時,各部分經歷的坐標變換相同,相對位置不變。

世界坐標

局部坐標通過模型矩陣進行位移、縮放、旋轉,將物體從局部變換到世界空間,並和其他物體一起相對於世界的原點擺放。

觀察坐標

將世界空間坐標轉化為用戶視野前方的坐標,通常是由一系列的位移和旋轉的組合(觀察矩陣)來完成。

裁剪坐標

坐標到達觀察空間之後,通過投影矩陣會將指定範圍內的坐標變換為標準化設備坐標的範圍(-1.0, 1.0),所有在範圍外的坐標會被裁剪掉。

屏幕坐標

將裁剪坐標位於(-1.0, 1.0)範圍的坐標變換到由 glViewport 函數所定義的坐標範圍內,最後變換出來的坐標將會送到光柵器,將其轉化為片段。

OpenGL 渲染管線

OpenGL 渲染管線流程為:

頂點數據 -> 頂點著色器 -> 圖元裝配 -> 幾何著色器 -> 光柵化 -> 片段著色器 -> 逐片段處理 -> 幀緩衝

OpenGL 渲染管線的流程其實就是 OpenGL 引擎渲染圖像的流程,也就是 OpenGL 引擎一步一步的將圖片渲染到屏幕上的過程,渲染管線可以分為以下幾個階段:

1.指定幾何對象

首先要了解幾何圖元的概念,幾何圖元就是點、直線、三角線等幾何對象,在提供了頂點坐標後,還要確定具體要畫的是點、線段還是三角形,這就要確定具體執行的繪製指令。

比如 OpenGL 提供給開發者的繪製方法 glDrawArrays,這個方法的第一個參數就是指定繪製方式,可選值有:

「GL_POINTS」:以點的形式進行繪製,通常用在繪製粒子效果的場景。「GL_LINES」:以線的形式進行繪製,通常用於繪製直線的場景。「GL_TRIANGLE_STRIP」:以三角形的形式進行繪製,所有二維圖像的渲染都會使用這種方式。

具體選用哪一種繪製方式決定了 OpenGL 渲染管線的第一階段應如何去繪製幾何圖元,這就是第一階段指定幾何對象。

2.頂點處理

不論上面的幾何圖元是如何指定的,所有的幾何數據都將會通過這個階段。這個階段的操作內容有:根據模型視圖(即根據幾何圖元創建的物體)和投影矩陣進行變換來改變頂點的位置,根據紋理坐標與紋理矩陣來改變紋理坐標的位置,如果設計三維的渲染,還要處理光照計算和法線變換。

關鍵的操作就是頂點坐標變換及光照處理,每個頂點是分別單獨處理的。這個階段所接受的數據是每個頂點的屬性特徵,輸出的則是變換後的頂點數據。

3.圖元組裝

在頂點處理之後,頂點的全部屬性都已經被確定。在這個階段頂點將會根據應用程式設定的圖元規則如 GL_POINTS 、GL_TRIANGLES(三角形) 等被組裝成圖元。

4.珊格化操作

在圖元組裝後會傳遞過來圖元數據,到目前為止,這些圖元信息還只是頂點而已:頂點處都還沒有「像素點」、直線段端點之間是空的、多邊形的邊和內部也是空的,光柵化的任務就是構造這些。

這個階段會將圖元數據分解成更小的單元並對應於幀緩衝區的各個像素,這些單元稱為片元,一個片元可能包含窗口顏色、紋理坐標等屬性。

片元的屬性則是圖元上的頂點數據等經過插值而確定的,這就是珊格化操作,也就是確定好每一個片元是什麼。

5.片元處理

珊格化操作構造了像素點,這個階段就是處理這些像素點,根據自己的業務處理(比如提亮、飽和度調節、對比度調節、高斯模糊等)來變換這個片元的顏色。

6.逐片段處理

進行剪切、Alpha 測試、 模版測試、深度測試、混合等處理,這些操作將會最後影響其在幀緩衝區的顏色值。

7.幀緩衝操作

此階段主要執行幀緩衝的寫入操作,也是渲染管線的最後一步,負責將最終的像素點寫到幀緩衝區。

上面提到 OpenGL ES 2.0 版本相比之前版本,提供了可編程的著色器來代替 1.x 版本渲染管線的某些階段,具體為:

Vertex Shader(頂點著色器)用於替換頂點處理階段Fragment Shader(片元著色器)用於替換片元處理階段OpenGL 著色語言

OpenGL 著色語言 GLSL 全稱為 OpenGL Shading Language,是為了實現著色器的功能而向開發人員提供的一種開發語言,語法與 C 語言類似,下面分為以下幾點來學習 GLSL:

1.基本數據類型int:帶符號的整數,signed integerfloat:帶符號的浮點數,signed scalarbvec2、bvec3、bvec4:n-維布爾向量ivec2、ivec3、ivec4:n-維整數向量mat2、mat3、mat4:2x2、3x3、4x4 浮點數矩陣

其中 float 可指定精度:

2.變量修飾符none:(默認的可省略)本地變量,可讀可寫,函數的輸入參數既是這種類型attribute:用於保存頂點或法線數據,它可以在數據緩衝區中讀取數據,僅能用於頂點著色器uniform:在運行時 shader 無法改變 uniform 變量,一般用來放置程序傳遞給 shader 的變換矩陣,材質,光照參數等等,可用於頂點著色器和片元著色器varying:用於修飾從頂點著色器向片元著色器傳遞的變量

要注意全局變量限制符只能為 const、attribute、uniform 和 varying 中的某一個,不可複合。

3.內置變量

GLSL 程序使用一些特殊的內置變量與硬體進行溝通,他們大致分成兩種,一種是 input 類型,他負責向硬體(渲染管線)發送數據;另一種是 output 類型,負責向程序回傳數據,以便編程時需要。

頂點著色器中 output 類型的內置變量如下:

highp vec4  gl_Position:放置頂點坐標信息mediump float gl_PointSize:需要繪製點的大小,(只在gl.POINTS模式下有效)

片元著色器中 input 類型的內置變量如下:

mediump vec4 gl_FragCoord;:片元在 framebuffer 畫面的相對位置bool gl_FrontFacing:標誌當前圖元是不是正面圖元的一部分mediump vec2 gl_PointCoord:經過插值計算後的紋理坐標,點的範圍是0.0到1.0

片元著色器中 output 類型的內置變量如下:

mediump vec4 gl_FragColor:設置當前片點的顏色mediump vec4 gl_FragData[n]:設置當前片點的顏色,使用glDrawBuffers數據數組4.內置常量

GLSL 提供了一些內置的常量,用來說明當前系統的一些特性。有時我們需要針對這些特性,對 shader 程序進行優化,讓程序兼容度更好。

頂點著色器中的內置常量如下:

const mediump int gl_MaxVertexAttribs >= 8:頂點著色器中可用的最大 attributes 數const mediump int gl_MaxVertexUniformVectors >= 128:頂點著色器中可用的最大 uniform vectors 數const mediump int gl_MaxVaryingVectors >= 8:頂點著色器中可用的最大 varying vectors 數const mediump int gl_MaxVertexTextureImageUnits >= 0:頂點著色器中可用的最大紋理單元數const mediump int gl_MaxCombinedTextureImageUnits >= 8:表示最多支持多少個紋理單元

片元著色器中的內置常量如下:

const mediump int gl_MaxTextureImageUnits >= 8:片元著色器中能訪問的最大紋理單元數const mediump int gl_MaxFragmentUniformVectors >= 16:片元著色器中可用的最大 uniform vectors 數const mediump int gl_MaxDrawBuffers = 1:表示可用的 drawBuffers 數,在 OpenGL ES 2.0 中這個值為 1, 在將來的版本可能會有所變化

上面這些值的大小取決於 OpenGL ES 在某設備上的具體實現。

5.內置函數通用函數:abs、floor、min、max 等,參數可傳入 float/vec2/vec3/vec4 類型角度函數:sin、cos 等,參數可傳入 float/vec2/vec3/vec4 類型指數函數:pow、log 等,參數可傳入 float/vec2/vec3/vec4 類型幾何函數:distance、dot 等,參數可傳入 float/vec2/vec3/vec4 類型矩陣函數:matrixCompMult,參數傳入 mat 類型向量函數:lessThan、equal 等,參數可傳入 vec2/vec3/vec4 類型紋理函數:texture2D、texture2DProj 等

相關焦點

  • OpenGl ES 基礎入門知識
    相信大家都聽過大名鼎鼎的 OpenGL,但可能大多數人沒有實踐使用過,本文就來介紹一下 Android OpenGl ES 的基礎入門知識。或許你在工作中不會用到,但為你個人成長著想一下,擴展自己的知識廣度,總歸是有利無弊的,你說對吧?
  • 基於OpenGL ES的深度學習框架編寫
    比如實時摳人像這個case: 對每一幀相機預覽產生的數據,系統將其映射為opengl 的一個external texture,然後需要 計算出一個 mask texture,與原先的texture作混合,顯示出來。
  • android基礎入門
    第一天、android簡介和開發環境的搭建:android的簡介android開發環境搭建android工程的目錄介紹>第一個應用程式——計算器部署到真實手機第二天、android的系統架構和核心模塊簡介:
  • 原創 | 學好opengl走遍天下都不怕系列《基礎篇》
    前言最近本來是想認真學習下《opengl es第三版》這本書,無奈內容過於生澀,有點看不下去,偶遇opengl-tutorial.org
  • OpenGL ES 學習資源分享
    通過看一些博客文章、看一些文章分析,在某些時刻確實是很有幫助的,但總是會存在一些碎片化知識,沒有系統地形成知識網絡,此時掌握的僅僅是技巧。還是要通過系統地去學習某些知識內容,在腦海裡面有個完整的知識體系。這個簡單的道理大家都懂,就不多說了~簡單上手作為程式設計師學習一項內容,最重要的就是 Hello World 了。
  • OpenGL ES 3.0 實例化(Instancing)
    利用內建變量gl_InstanceID在 3D 空間繪製多個位於不同位置的立方體,利用 u_offsets[gl_InstanceID]對當前實例的位置進行偏移,對應的著色器腳本:// vertex shader GLSL#version 300 es                            layout(location = 0) in
  • Shader 入門:GLSL ES(簡介和基本語法)
    歡迎來到我的 Shader 入門系列文章,在本系列文章中我將和大家一起學習 Shader 相關知識,以便於我們閱讀和編寫 Shader。
  • opengl實踐-從零開發遊戲
    作者:愛幹球的RDlearnopengl是一套很棒的opengl教程,深入淺出、有源碼且免費,除了說良心,不知道還能用什麼詞彙來形容這種高水平且善良的公益行為
  • 了不起的 Creator Shader 修仙之路—GLSL ES(簡介和基本語法)
    歡迎來到我的 Shader 入門系列文章,在本系列文章中我將和大家一起學習 Shader 相關知識,以便於我們閱讀和編寫 Shader。
  • Android OpenGL ES 從入門到精通系統性學習教程
    因為在工作中頻繁使用 OpenGL ES 做一些特效、濾鏡之類的效果,加上平時學到的的知識點也比較細碎,就想著去系統地學習下 OpenGL ES 相關開發知識,並將學習過程記錄下來。另外,這個 Android OpenGL ES 極簡教程的主要目的是為下一階段的音視頻開發做準備。一些同學反映,學習這個教程感覺有點門檻。
  • NDK OpenGL ES渲染系列 之 繪製三角形
    前言新的知識學習都是循序漸進的,從基礎到複雜。
  • 海王星 基礎入門知識 By 國家地理,附視頻詳盡解釋
    月球 基礎入門知識 By 國家地理,附視頻詳盡解釋給娃看:地球 基礎入門知識 By 國家地理,附視頻詳盡解釋太陽系 基礎入門知識 Solar System by National Geographic>海王星 基礎入門知識 by National GeographicNeptune is the most distant of the solar system's eight planets.
  • Android OpenGL開發實踐 - 基於OpenGL ES 2.0的Android相機實時圖片塗鴉實現思路
    這篇文章將給大家講解如何在Android系統上基於OpenGL ES 2.0來實現相機實時圖片塗鴉效果,所塗內容跟隨人臉出現、消失、移動、旋轉及縮放,在這裡,我們假設您:在開始講解之前,先簡要介紹一下OpenGL ES 2.0的一些必要的基礎知識
  • 月球 基礎入門知識 By 國家地理,附視頻詳盡解釋
    太陽系 基礎入門知識 Solar System by National Geographic太陽 基礎入門知識 Sun by National Geographic給娃看:星星 基礎入門知識 Stars By 國家地理,附視頻詳盡解釋
  • 天王星 基礎入門知識 By 國家地理,附視頻詳盡解釋
    給娃看:星星 基礎入門知識 Stars By 國家地理,附視頻詳盡解釋月球 基礎入門知識 By 國家地理,附視頻詳盡解釋火星 基礎入門知識 By 國家地理,附視頻詳盡解釋天王星 基礎入門知識 By 國家地理,附視頻詳盡解釋Uranus is a planet beyond convention.
  • OpenGL glfw學習(一)初識,環境,窗口
    GLAD庫比較特殊,進入官網後在網頁上設置自己的opengl版本,點擊GENERATE生成特定的GLAD包,再下載就好。 為方便開發,接下來要組裝一個開發目錄。新建opengl文件夾,將GLFW目錄中的include目錄複製到opengl中去。
  • Android Systrace 基礎知識(5) - SurfaceFlinger 解讀
    簡介: https://www.androidperformance.com/2019/05/28/Android-Systrace-About/[4]Systrace 基礎知識 - Systrace 預備知識: https://www.androidperformance.com/2019/07/23/Android-Systrace-Pre/[5]Systrace
  • 寫給Android開發的Gradle知識體系
    前言老讀者都知道,我的技術博客從2016年開始就沒寫過不成系列的文章,這些系列文章組成了目前Android領域最全面深入的原創知識體系,更恐怖的是這個體系還在不斷的成長,關於這個知識體系可以點擊 閱讀原文 了解。
  • OpenGLES2.0(二)實戰之繪製三角形
    依照官方文檔中的說明,Android中利用OpenGL ES 2.0繪製三角形的步驟為:在AndroidManifest.xml文件中設置使用的OpenGL ES的版本:<uses-feature android:glEsVersion="0x00020000" android
  • Android Systrace 基礎知識(7) - Vsync 解讀
    /2019/05/28/Android-Systrace-About/[2]Systrace 基礎知識 - Systrace 預備知識: https://www.androidperformance.com/2019/07/23/Android-Systrace-Pre/[3]Systrace 基礎知識 - Why 60 fps ?