輕鬆入門OpenGL ES——圖形渲染管線的那些事

語言: CN / TW / HK

theme: channing-cyan

更多博文,請看音視訊系統學習的浪漫馬車之總目錄

實踐專案: 介紹一個自己剛出爐的安卓音視訊播放錄製開源專案

視訊理論基礎:\ 視訊基礎知識掃盲\ 音視訊開發基礎知識之YUV顏色編碼\ 解析H264視訊編碼原理——從孫藝珍的電影說起(一)\ 解析H264視訊編碼原理——從孫藝珍的電影說起(二)\ H264碼流結構一探究竟

Android平臺MediaCodec系列:\ Android硬編解碼利器MediaCodec解析——從豬肉餐館的故事講起(一)\ Android硬編解碼工具MediaCodec解析——從豬肉餐館的故事講起(二)\ Android硬編解碼工具MediaCodec解析——從豬肉餐館的故事講起(三)

輕鬆入門OpenGL系列
輕鬆入門OpenGL ES——整體工作機制篇(一)

回顧上個系列

上個系列《Android平臺MediaCodec系列》中,已經帶大家好好參觀了MediaCodec這一座“豬肉餐館”,摸清了“老闆”“廚師”們的工作時間流程,然而視訊資料光解碼出來,那也只不過是一堆冰冷的二進位制資料罷了,只有將資料渲染到螢幕上,才能真正讓人感受詩與遠方,體驗看片的快樂~

Android平臺最常用的渲染工具就是大名鼎鼎的OpenGL,行內人士基本多少有聽聞過它的大名,眾多有名的遊戲引擎就是由OpenGL編寫的,所以接下來的渲染系列博文,重點就是講解OpenGL,從0開始講解,目標依然是儘量講清楚講生動,講不容易理解的知識點講透徹。

學習目標

本系列的學習目標就是掌握OpenGL的工作機制,可以通過OpenGL繪製基本圖形以及渲染圖片,最終能夠做出像我的專案UnitedPlayer一樣的視訊動態濾鏡效果: 1. 反色: 在這裡插入圖片描述

  1. 灰度圖: 在這裡插入圖片描述

  2. 閃白: 在這裡插入圖片描述

  3. 縮放: 在這裡插入圖片描述

  4. 靈魂出竅: 在這裡插入圖片描述

  5. 顏色偏移抖動: 在這裡插入圖片描述

看起來還有點炫把哈哈,其實只要掌握了OpenGL基礎,就會發現也不是難事~

當然OpenGL也不是學習的終極目標,畢竟它只是一個工具,以後還是會被其他更優秀的工具取代,我們需要學習的是圖形學知識,這才是OpenGL的核心,才是真正貫穿整個圖形開發始終的祕密武器,所以在本系列中,也會插入一些圖形學基礎知識在其中。

OpenGL

OpenGL是什麼

上面說了那麼多,那麼OpenGL到底是什麼呢? 很多人誤以為OpenGL是一個圖形渲染庫,然而,OpenGL本身並不是一個API庫,它僅僅是一個由Khronos組織制定並維護的規範(Specification)。

以下為著名OpenGL學習網站learnopengl 對OpenGL的介紹:

OpenGL規範嚴格規定了每個函式該如何執行,以及它們的輸出值。至於內部具體每個函式是如何實現(Implement)的,將由OpenGL庫的開發者自行決定(譯註:這裡開發者是指編寫OpenGL庫的人)。因為OpenGL規範並沒有規定實現的細節,具體的OpenGL庫允許使用不同的實現,只要其功能和結果與規範相匹配(亦即,作為使用者不會感受到功能上的差異)。

既然是規範,那就一定有官方的規範文件,這是官方規範文件,是權威的文件,是對OpenGL的各種概念和整個工作機制的詳細論述,也可以當做API文件使用。

規範文件中對OpenGL的定義是:

OpenGL (for “Open Graphics Library”) is a software interface to graphics hard- ware. The interface consists of a set of several hundred procedures and functions that allow a programmer to specify the objects and operations involved in produc- ing high-quality graphical images, specifically color images of three-dimensional objects.

To the programmer, OpenGL is a set of commands that allow the specification of geometric objects in two or three dimensions, together with commands that control how these objects are rendered into the framebuffer.

To the implementor, OpenGL is a set of commands that affect the operation of graphics hardware.

以上屬於“官話”,用通俗的話來講就是:OpenGL就是一個建立在圖形硬體(一般就是gpu)之上的軟體程式設計介面,這些介面有一套官方制定的規範,具體實現由製造商(一般是顯示卡製造商)去實現,而程式設計者通過這些軟體程式設計介面,就可以在計算機中繪製出2D以及3D的圖形。

不同製造商的實現有所差異,比如同一個api:glDrawArrays,規範制定這是一個繪製圖形的api,硬體製造商就必須實現其為繪製圖形api,不允許將其實現為清屏api,不然那就是違反規範,不講武德。

其實這樣的規範類似我們以前接觸過得Java虛擬機器規範,通過規範額約束,在各種硬體製造商中統一了標準,也對程式設計者隔離了具體硬體實現,使得程式設計者只需要學習一套開發的api。

常見的學習困難

說起學習OpenGL,可能是很多初學者的夢魘,入門各種困難層出不窮,畫一個最基本的三角形就能把人折騰得夠嗆,這裡我也將曾經學習碰到的坎梳理一下,相信很多人學習過程中也曾碰過這些坎:

  • OpenGL學習資料太少,網上的資料零碎不成系統,讓人很難理解OpenGL的工作機制。(learnopengl 可以說是網上最好的學習網站了,講得非常詳細和系統,不過我個人覺得它其實對於初學者來說還是不夠友好,講得比較抽象不夠通俗易懂。)

  • OpenGL的api設計比較反人類,特別是對於像寫慣了Java的開發者來說,OpenGL的api真的是太難用了,很囉嗦,各種繫結和解綁能把人搞暈。

  • OpenGL的api經常不理解是什麼意思,在網上也查不到api的解釋。

  • OpenGL的著色器怎麼工作的不好理解,而且不能除錯,光是解決編譯問題就夠嗆。

在這個系列我也努力解決這些學習痛點,讓初學者可以比較“柔順絲滑”地入門,而即使是老司機也能在這裡有所收穫,所有解惑。

OpenGL工作機制

學習OpenGL首當其衝的就是要清楚它的工作機制,它不像平時做Android應用開發那樣,只要幾個api理解就差不多可以做一個功能開發了,OpenGL需要的是大局觀,我們要像一位將軍一樣,在戰役中統攬大局,把整個處理流程搞清楚,才能指定好戰略,才能“拿下”OpenGL,而這裡的“大局”,指的就是OpenGL的圖形渲染管線。上一章說的學習困難中提到的很難理解OpenGL工作機制,很大程度就是對圖形渲染管線缺乏清晰的理解

圖形渲染管線

想象以下,現在如果需要你在螢幕上繪製一個三角形,你會怎麼做呢?

第一步需要什麼呢?當然是確定三角形三個頂點的位置,於是你操作者滑鼠在三個地方先畫了三個點,然後自己量了一下,位置角度完美,自己不由自主點了點頭,三個頂點如下圖所示:

1657427782386.png

第二步,那當然是將三個點用線段連起來了,於是你拿起滑鼠,很快將三個點刷刷連起來:

1657427966396.png

第三步,你覺得這樣的三角形太過於單調,於是準備給三角形上色,因為是在螢幕上的,而螢幕本質是一個個畫素顯示顏色的,所以上色之前要先確定好哪些畫素是屬於三角形的,於是你叫計算機把屬於三角形內部的畫素一個個圈出來

1657428300765.png

第四步,你想畫一個比較炫的三角形,所以想給每個畫素都上不同的顏色,於是你給一個個畫素精心上色

1657428450120.png

於是一個很漂亮的三角形就呈現在眼前了,你回想畫三角形的幾個步驟,發現整個過程和車間流水線有一點相似之處。

和車間的生產流水線類似,OpenGL中也存在這樣一條流水線在默默地工作,每一個崗位都在默默勤勞地工作,當然,OpenGL要畫一個圖形,需要的步驟肯定是要比上面你畫三角形複雜很多,畢竟人家可是要畫各種非常複雜的3D場景的

以下為OpenGL的圖形渲染管線,圖來自learn OpenGL

image.png

一言以蔽之,OpenGL圖形渲染管線,就是將輸入的3D的座標,轉化為顯示在螢幕上的2D的畫素的一個處理流程。

整個渲染管線的每個“工序”依次是:

頂點著色器——圖元裝配——幾何著色器——光柵化——片段著色器——測試與混合

每個“工序”的輸出都可以作為向下一個“工序”的輸入,那麼接下來,就來詳細說明這幾個步驟:

首先不得不提到的一個很重要的東西叫做著色器(shader)。

早期的OpenGL使用立即渲染模式(Immediate mode,也就是固定渲染管線),固定渲染管線就是隻可配置(configurable)的管線。這個模式下繪製圖形很方便。OpenGL的大多數功能都被庫隱藏起來,開發者很少有控制OpenGL如何進行計算的自由。而開發者迫切希望能有更多的靈活性。隨著時間推移,規範越來越靈活,開發者對繪圖細節有了更多的掌控,現代OpenGL轉變為可程式設計渲染管線,把很多部分從可配置改為可程式設計(programmable)。

著色器

首先不得不提的就是著色器,著色器就是一段執行在GPU中的程式,這段程式由開發者編寫,所以說為開發者提供了很大的靈活度和可掌控度。現在OpenGL主要有三種著色器,分別為頂點著色器、幾何著色器、片段著色器,其中頂點著色器和片段著色器為開發者必須提供,幾何著色器為可選提供。

1.頂點著色器(Vertex Shader)

第一個階段是頂點著色器,主要用於確定繪製圖形的形狀。接收外部傳入的頂點資料,根據需要對頂點資料進行變換處理之後,再將頂點資料傳入下一個階段圖元裝配。另外也接收外部傳進來的顏色值以及紋理取樣器,然後再傳遞給下一個階段——圖元裝配處理。

1657427782386.png

每個頂點著色器只接收處理一個頂點座標有多少個頂點就會執行多少次。關於頂點著色器,後面博文還會重點細講

2.圖元裝配

接下來的階段是圖元裝配,接收頂點著色器的輸出資料,將頂點著色器傳來的頂點資料組裝為圖元,就如上面畫三角形中所說的將三角形三個頂點連線起來,具體連線方式需要開發者指定。所謂圖元,指的就是點、線、三角形等幾何圖形。另外,圖元裝配階段還會將超出螢幕的頂點座標進行裁剪,裁剪之後,頂點座標被轉化為螢幕座標,之後將圖元資料傳遞給管線的下一個階段——光柵化(幾何著色器為非必須階段,這裡入門就暫時不講了)

1657427966396.png

3.光柵化

接下來的階段是光柵化,拿到圖元裝配傳遞過來的圖元資料,光柵化要做的就是將一個圖元轉化為一張二維的圖片,而這張圖片由若干個片段(fragment)組成(可以當做將這張圖拆解為一個個類似螢幕上畫素的小片段),片段可以近似看成畫素,但是又略有不同,一個片段包含渲染該片段所需要的位置、顏色和深度的全部資訊。

1657428300765.png

光柵化完成之後,就把每個片段傳給片段著色器1657452209669.png

4.片段著色器

接下來的階段是片段著色器, 這是另外一個必須有的重要著色器,也是最後一個可以通過程式設計來控制螢幕是上顯示顏色的階段(後面的混合測試階段還可以改變片段的顏色),在這個階段主要是計算是片段的顏色。這裡每個片段著色器接收一個片段資料的輸入,所以有幾個片段就會執行所少次,根據具體需要靈活設定該片段的顏色。然後片段資料就被傳遞到下一個階段測試與混合

1657428450120.png

5.測試和混合

接下來的階段是測試和混合,這個階段的測試是專門用來丟棄一些不需要顯示的片段的,其中測試主要包含深度測試模板測試

1.深度測試是在顯示3D圖形的時候,根據片段的深度來防止被阻擋的面渲染到其它面的前面。這裡是OpenGL內部維護一個深度緩衝,儲存這一幀中深度最小的片段的深度,然後對螢幕同一個位置的其他片段的深度再進行比較,深度比緩衝中大的片段則丟棄,直到找到深度最小的片段,就將其顯示出來。

2.模板緩衝區是用於控制螢幕需要顯示的內容,螢幕大小決定了模板緩衝區大小;模板測試基於模板緩衝區,從而讓我們完成想要的效果。模板測試類似於“與”運算:

圖來自 模板測試 image.png

上圖可以看出,模板就是每個片段位置有0也有1,然後和緩衝中的影象資料對應片段進行類似與運算,也類似與拿一個遮罩罩住,只留下1的對應片段顯示出來。

3.混合則是帶有透明度的片段,在這個階段會與顯示在它背後的片段的顏色按照透明度進行疊加行成新的顏色,通俗講就是形成透明物體的效果。

圖來自混合 image.png

由圖可以看出,通過混合,右邊的窗戶既有部分自己的顏色,又有窗戶裡面物體的部分顏色,就是兩者透明度按照比例疊加的結果。

於是走完整個渲染管線流程,就會看到在螢幕中渲染出3D世界的影象了。

讓我們再回顧下這條“流水線”做了什麼: 首先我們傳入了圖形的頂點資料,然後OpenGL內部會自動將頂點連成圖形,然後再將圖形內的區域切成一個個小片段,然後給每個小片段自由上色,最後把被擋住的或者我們不想顯示的區域的下片段丟棄,並且對有透明度的片段進行前後片段顏色的混合

圖形渲染管線學習的意義

為什麼理解這條渲染管線很重要呢?因為如果沒有理解好這條渲染管線,後面學習著色器的時候,會遇到很多不理解的東西,比如資料是怎麼從頂點著色器傳遞到片段著色器的,或者可能著色器程式碼都能看懂,就是完全不知道這樣寫能做什麼。所以著色器的程式不能單獨來看,一定要放在整個渲染管線裡面來看,就會有撥雲見日的感覺。

總結

本文主要介紹了OpenGL是什麼的概念,並主要針對圖形渲染管線的每個步驟進行比較詳細的闡述。 介於篇幅關係,太長的篇幅容易導致讀者不易消化理解,也容易看困,本篇博文就先寫到這,工作機制流程還有下半場,敬請關注~

參考

《OpenGL規範文件》
learn opengl
《OpenGL超級寶典第五版》
《OpenGL程式設計指南第8八版》

原創不易,如果覺得本文對自己有幫助,別忘了隨手點贊和關注,這也是我創作的最大動力~