日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

OpenGL——GPU图形渲染管线

發布時間:2024/1/18 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OpenGL——GPU图形渲染管线 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

OpenGL渲染管線

OpenGL本身并不是一個API,他僅僅是一個由Khronos組織制定并維護的規范;OpenGL規范嚴格規定了每個函數改如何執行,以及他們的輸出值,至于內部具體每個函數是如何實現的,將有OpenGL庫的開發者自行決定。因為OpenGL規范并沒有規定實現的細節,具體的OpenGL庫允許使用不同的實現,只要其功能和結果與規范相匹配。

CPU & GPU

GPU具有高并行結構(highly parallel structure),所以GPU在處理圖形數據和復雜算法方面擁有比CPU更高的效率;CPU大部分面積為控制器和寄存器,與之相比,GPU擁有更多的ALU(邏輯運算單元)用于數據處理,而非數據高速緩存和流控制,這樣的結構適合度密集行為數據進行并行處理;CPU執行計算任務時,一個時刻只處理一個數據,不存在真正意義上的并行(OS教程上的時間輪轉算法),而GPU具有多個處理器核,在一個時刻可以并行處理多個數據。

GPU采用流式并行計算模式,可對每個數據進行獨立的計算,所謂“對數據進行對立計算”,即流內任意元素的計算不依賴于其他同類型數據,例如:計算一個頂點的世界坐標位置,不依賴于其他頂點的位置。而所謂“并行計算”是指“多個數據可以同時被使用,多個數據并行運算的時間和1個數據單獨執行的時間時一樣的”;在提取2D圖像上每個像素點的顏色值,在CPU上運算的C++代碼通過循環語句一次便利像素;而在GPU上,則只需要一個語句就足夠了。

程序的主函數都在CPU上執行,圖形的渲染在GPU上執行,GPU亦可進行通用編程,但這樣的程序也需要在CPU上執行代碼來操控GPU;下圖中PCle的帶寬大約時內存速度的三分之一,這個層次上的性能優化主要思路:

減少程序對PCI傳輸帶寬的占用,增加主程序(CPU)以及著色器(GPU)訪問儲存器的局部性(增加緩存命中率或更多的使用寄存器)

著色器程序在GPU上執行,OpenGL主程序在CPU上執行,主程序向顯存輸入頂點數據,啟動渲染過程,并對渲染過程進行控制;了解到這一點就知道了顯示列表以及glfinish函數存在的原因了:

顯示列表:將一組繪制指令放到GPU上,CPU只要發一條“執行這個顯示列表”這些指令就執行,而不必CPU每次渲染都發送大量指令到GPU,從而節約PCI帶寬(因為PCI總線比顯存慢);

glFinish:讓CPU等待GPU將已發送的渲染指令執行完。

GPU提供了大規模并行機制,特別適合執行高度并行的渲染過程;GPU的線程數可以達到上百萬個或者更多,如何運行如此多的線程,CUDA架構模型如下:

Host和Device分別表示CPU和GPU的編程視圖,基本思路是將線程按兩次層次分組,多個線程(Thread)組成Block,多個Block組成Grid,Grid的存儲模式:

關鍵點是Block內提供了共享存儲;因為多個線程要相互通信,共享存儲模型是最方便快速的通信方式,但對眾多的線程全都提供共享存儲模型會影響效率(并發訪問存儲器,線程有上百萬個之多),CUDA(OpenCL也是類似的)采用一種折衷方式:提供有限的共享存儲編程,Block內提供高速共享存儲,而Block間的通過全局存儲(顯存)的通信要慢的多。這種編程模型和GPU硬件是相對應的:

GPU主要由顯存(Device Memory)和SMs(流多處理器,Stream Multiprocessors)組成,顯卡的好壞基本就取決于有多少個SM了。上述編程模型和GPU模型有對應關系

Block總是在一個SM上執行,Block內部的共享存儲模型由SM硬件的共享存儲器提供。線程層次上性能優化的主要思路是:盡量使 Kernel 代碼(每個線程,尤其是同一個 Block 內的線程)具有相同的執行路徑(即分支跳轉情況盡量相同),以充分利用GPU訪存及代碼執行方面的并行機制。

OpenGL也定義的自己的執行模型(用 Compute Shader 進行通用計算),和CUDA執行模型非常類似;在OpenGL概念中,CUDA的Grid變成了Dispatch,Block變成了Work Group,Thread變成了Invocation,同樣,Dispatch可以由三維索引的Work Group組成,Work Group可以由三維索引的Invocation組成。

固定渲染管線

早期的OpenGL使用立即渲染模式(Immediate mode,也就是固定渲染管線),這個模式下繪制圖形很方便。OpenGL大多數功能都被庫隱藏起來,開發者很少能控制OpenGL如何進行計算的自由。

?

現代可編程渲染管線

OpenGL實現了我們通常所說的“渲染管線”,他是一系列數據處理過程,并且將應用程序的數據轉換到最終渲染的圖像;OpenGL首先接受用戶提供的幾何數據(頂點和幾何圖元),并且將它輸入到一系列著色器階段進行處理,包括:頂點著色,細分著色,以及最后的幾何著色,然后將他送入光柵化單元,光柵化單元負責對所有剪切區域內的圖元生成片元數據,然后對每個生成的片元都執行一個片元著色器。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?圖形渲染管線的每個階段的抽象展示

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?上圖來自(GPU Programming And Cg Language Primer 1rd Edition)

? ? ? ? ? ? ? ? ??

?

準備傳輸數據,將數據傳輸到OpenGL

因為應用程序階段運行于CPU上,開發者可以對其全面掌控。因些,開發者可完全決定其實現并在之后對其修改以提高運行效率。在這里的改變亦能影響后面階段的運行效率。但如一些應用程序階段的算法和設定可能減少將被渲染的多邊形。

在應用程序階段的最后步驟,將被渲染的幾何體會輸入到頂點著色器。這些幾何體都是繪制圖元,例如點、線和三角形等最后將輸出到屏幕(或者被輸出設備所用)。這是應用程序階段中最重要的任務。

這階段的實現是以軟件為基礎,這導致到不像其他階段那樣,被析分為多個子階段。但是為了提升運行效率,該階段經常并行運行在多個處理器核心上。在中央處理器設計方面說,這叫超標量體系結構,因為它能夠在同一階段同一時間內運行數個運算步驟。

通常在這階段實現的運算步驟是碰撞檢查。當一關于兩物體的碰撞檢測出來后,反應將會被生成并發送到碰撞的對象和力反饋設備上,應用程序階段亦是處理包括鍵 盤、鼠標、頭盔等設備輸入的地方。跟據不同的輸入,作出不同的反應。該階段的其它步驟包括紋理動畫或者一些不運行在其它階段的計算。一些加速算法,例如層次化視圖平截體裁剪亦是在此處實現。

我們需要通過緩沖對象來存儲頂點數據(位置,紋理坐標,法線等),它會在GPU內存(通常被稱為顯存)中儲存大量頂點數據。使用這些緩沖對象的好處是我們可以一次性的發送一大批數據到顯卡上,而不是每個頂點發送一次。從CPU把數據發送到顯卡相對較慢,所以只要可能我們都要嘗試盡量一次性發送盡可能多的數據。當數據發送至顯卡的內存中后,頂點著色器幾乎能立即訪問頂點,這是個非常快的過程。

將緩存數據初始化完畢之后,可以通過OpenGL的一個繪制命令來請求渲染幾何圖元。

頂點著色器

為了實現逼真的場景,僅渲染對象的形狀和位置是不足夠的,它們的外觀亦需要模擬。這些描述包括第每對象材質,以及光源照射對象產生的特效。模擬材質和光源的方法有很多種,包括從最簡單的顏色到精細的物理特性描述。

決定光和材質特效的操作稱為著色。它包括了計算不同點的著色方程。典型的某些這類的計算運行在幾何階段的模型頂點數組上,另外一些則運行在逐象素的光珊化階段。各類的材質數據,例如點所在位置,法向量,顏色或其它著色方程需用到的數值信息,可儲存在每個頂點中。頂點著色的結果(這可能是顏色,向量,紋理坐標或其它種類的著色數據)會被送進光珊化階段去插值。

著色階段通常被認為是發生在世界空間。在實踐中,有時則將相應的實體(例如攝像機和光源)變換到其它空間(例如模型或視覺空間)并在那運行計算更為方便。因為如果所有包含在著色計算中的對象均被變換到同一空間,則光源、攝像機和模型的相對關系是保留的。

在 openGL? 編程中頂點著色器是必須的,對繪制命令傳輸的每個頂點,OpenGL都會調用一個頂點著色器來處理頂點相關數據,頂點著色器的功能如下:

  • 使用模型視圖矩陣和投影矩陣進行頂點位置變換
  • 法線變換,法線工規范化
  • 紋理坐標生成和變換
  • 計算每個頂點的光照
  • 顏色計算

標準化設備坐標(Normalized Device Coordinates, NDC)

一旦你的頂點坐標已經在頂點著色器中處理過,它們就應該是標準化設備坐標了,標準化設備坐標是一個x、y和z值在-1.0到1.0的一小段空間。任何落在范圍外的坐標都會被丟棄/裁剪,不會顯示在你的屏幕上。下面你會看到我們定義的在標準化設備坐標中的三角形(忽略z軸):

與通常的屏幕坐標不同,y軸正方向為向上,(0, 0)坐標是這個圖像的中心,而不是左上角。最終你希望所有(變換過的)坐標都在這個坐標空間中,否則它們就不可見了。

你的標準化設備坐標接著會變換為屏幕空間坐標(Screen-space Coordinates),這是使用你通過glViewport函數提供的數據,進行視口變換(Viewport Transform)完成的。所得的屏幕空間坐標又會被變換為片段輸入到片段著色器中。

細分著色器

在頂點著色器中操作幾何圖元數據,還是有一些局限性:在運行是無法創建新的幾何體(頂點著色器只是在處理當前頂點的過程中對其關聯的數據進行更新,甚至無法做到對圖元中其他的頂點數據進行訪問)。

細分著色在OpenGL 中有兩個著色階段,用來生成幾何圖元的模型網格;在頂點著色階段,需要設置所有的線段或者三角形來構成處理的模型;而在細分著色器階段首先要指定面片,也就是頂點的有序列表;當渲染面片的時候,將首先執行細分控制著色器處理面片頂點,并設置面片中要生成多少幾何數據;當細分控制著色器結束之后,第二個著色器(即細分計算著色器)將負責把生成網格的頂點放置到細分坐標指定的位置,并且將他們發送搭配光柵化階段,或者發送給幾何著色器進行更多的處理。

幾何著色器

幾何著色器輸入是一系列頂點組成的完整的圖元,并且這些輸入全部是數組形式,通常來說這些輸入數據來自于頂點著色器;不過如果激活細分著色器,那么幾何著色器的輸入將來自細分計算著色器的結果;因為幾何著色器的每個請求都負責處理一個完整的圖元,所以可以訪問這個圖元的所有頂點,進而實現一些專門的技巧。

除了增強多頂點的訪問屬性之外,幾何著色器還可以控制輸出數據的數量(如果輸出的總量為0,那么幾何體將被裁剪;如果輸出的頂點數比原始圖元要多,那么相當于進行了幾何體的細化操作);幾何著色器還可以產生和輸入數據不同的輸出圖元類型(即在管線中改變幾何體的類型);幾何著色器還可以和 transform feedback 共同使用,將輸入的頂點數據流切分為多個子數據流。

圖元裝配

頂點處理或者頂點著色器的輸出是一些列變換后的位于Clip坐標系的頂點,這些頂點首先根據頂點之間的連接關系(點、線、多邊形)進行圖元裝配

剪切

圖元裝配之后是剪切(Clipping),見文獻[1]2.22,下面是裁剪公式(文獻[1]第142頁):

多邊形的裁剪可能產生新的頂點,這些的點的顏色值以及紋理坐標等值要被插值。除了默認的xyz分別為±1的正方體的六個面的裁剪面,用戶可以指定額外的裁剪面:glClipPlane(GL_CLIP_PLANE0[1,2,...],double eqn[4]),glEnable/Disable(GL_CLIP_DISTANCE0[1,2,...]),注意指定的值會被乘以當前模型視圖矩陣的逆,乘完得到的值在視覺坐標系中進行裁剪(同從頂點視覺坐標自動生成紋理坐標的參數)。

裁剪之后是透視除法(Perspective Division):

透視除法之后是視口變換(Viewport Transformation):

視口變換同時也將原來z坐標縮放到[0,1]變成Depth值,深度值默認在[0,1]且值越小離攝像機越近,可以指定深度值范圍:glDepthRange(GLclampd n,GLclampd f),其中GLclampd[f]類型表示值將被鉗位到[0,1]),視口變換完成后的圖元將進入光柵化階段。

光柵化

到目前為止,管線里的數據都是頂點,經過圖元裝配之后,哪些頂點就是一個點、哪兩個頂點是直線段、哪三個或更多頂點是一個三角形或多邊形,這些圖元信息都已經知道了,但它們還是只是頂點而已:頂點處都還沒有“像素點”、直線段端點之間是空的、多邊形的邊和內部也是空的,光柵化的任務就是構造這些。由于已經經過了視口變換,光柵化是在二維(附帶深度值)的屏幕坐標系(Window Space)中進行的。

光柵化有兩個任務:1.確定圖元包含哪些由整數坐標確定的“小方塊”(和屏幕像素對應,現在還不能叫片斷,光柵化完成后才能叫片斷),2.確定這些小方塊的Depth值和Color值(從圖片頂點的Depth和Color插值得到),這些顏色后來可能被其他如紋理操作修改。如下圖:

光柵化在對多邊形圖元進行“方塊化”之前,要給出多邊形是front-facing還是back-facing(正面還是背面,點和直線只有正面),這是根據多邊形頂點的環繞方向確定的(是順時針還是逆時針,默認逆時針為front-facing,可由glFrontFace(GL_CCW[CW])控制)。正背面判斷結果將用于選擇是用頂點的正面顏色還是背面顏色來對片斷顏色進行插值。隨后如果glIsEnabled(GL_CULL_FACE)為真,對于方向和glCullFace(GL_FRONT[BACK])的參數相同的多邊形圖元,將被剔除,即直接跳過光柵化的后續操作。另外,光柵化除了直接對多邊形進行填充這種方式之外,還可以只構造邊或只有點,這由glPolyMode(GL_FRONT[BACK,FRONT_AND_BACK],GL_FILL[LINE,POINT])控制。

這里強調一下光柵化判斷正背面和正背面光照的區別,前者是對圖元的操作并依據頂點環繞方向(一個多邊形圖元有多個頂點,也就有多個法向量,這些向量可能不同,所以不可能依據法向量來判斷圖元朝向),后者是對頂點的操作并依據頂點的法向量。舉個例子,如果一個三角形按照頂點環繞的右手法則方向的反方向指定法向量,并且法向量朝物體外側,當光照為單面光照時,因為光柵化判斷為背面的多邊形圖元其片斷用頂點背面光照顏色進行插值,單面光照下,和頂點正面光照顏色相同,所以沒有問題,但當光照為雙面光照時,圖元的沿法向量這邊的“光照正面”卻是光柵化依據頂點環繞方面判斷的“光柵化背面”,這時,我們將看到一個灰色的好像沒有光照一樣的東西,從而得不到結果。所以,對三角形或多邊形的由頂點法向量確定的正面(三個或更多頂點法向量確定的正面一致,指這個面)要和光柵化用頂點環繞方面的正面相同,這樣才不會出現意想不到的效果。

最為復雜的紋理在光柵化階段進行,下圖是多重紋理的操作示意(文獻[1]第280頁):

之所以說紋理復雜,在于紋理坐標的計算上,每個片斷要找到一個紋理坐標以索引紋理像素,這個計算看似簡單,但出問題時將產生意想不到的效果,如下圖:

圖中所說的Projective和Real Space坐標就是我們所說的透視除法前后的坐標。

在光柵化對圖元進行“小方塊化”并對“小方塊”進行插值之后,后來的紋理和霧等操作可以由片斷著色器代替,片斷著色器還可以對片斷進行更多計算,如逐片斷光照,處理后的片斷將進入下一步逐片斷處理。

片段著色器

片段著色器是通過編程控制屏幕上顯示顏色;在這個階段,使用著色器來計算片段的最終顏色(盡管在下一階段逐片元操作時可能還會改變顏色一次)和它的深度值;片元著色器非常強大,我們會使用紋理映射的方式,對頂點處理階段所計算的顏色值進行補充;如果我們覺得不應該繼續繪制片段,在片段著色器中我們可以終止這個片元的處理,這一步叫做片元的丟棄(discard)

? ? ??

逐片元操作

光柵化的輸出是一些列片斷(Fragments,這些片斷可能經過片斷著色器處理),片斷被稱為“準像素”,要能想象出屏幕坐標系的一個整數坐標上只有一個像素,但可以前后“堆疊”多個片斷。這些片斷進入逐片斷處理(Per-Fragment Operations),首先進行各種測試(下圖中共5個),每步測試,不通過的片斷將被丟棄從而不能進入后續操作,然后進行一些操作(如混合),最終通過所有處理的片斷將被寫入FrameBuffer用于最終屏幕顯示,這個過程如下圖:

Scissor Test對用戶指定的scissor rectangle進行測試,Alpha Test用片斷Alpha值進行測試(如片斷Alpha值小于設定ref值時通過),Depth Buffer Test和遮擋處理有關(如片斷深度值小于其同坐標的深度緩沖區元素的值時通過),Stencil Test可以根據Stencil或Depth Buffer Test結果分條件更新Stencil Buffer實現很多功能(如zfail時,片斷同坐標的Stencil緩沖區元素加1,zpass時減1,第二遍渲染再設置Stencil test為片斷同坐標Stencil緩沖區元素值為0時通過),如Shadow Volumes算法。上圖中,框下面有小箭頭連接FrameBuffer的說明該測試要訪問或更新FrameBuffer的值。

所有操作均通過的片斷將被寫入FrameBuffer,包括RGBA緩沖、Depth緩沖,注意Stencil緩沖僅用于測試,片斷沒有Stencil值。還有一個緩沖叫做Accumulation Buffer,多用于運動模糊、景深模糊等,但不能直接寫入,而是將RGBA緩沖整幅累積。

這些操作可以用glEnable/glDisable(GL_ALPHA/STENCIL/DEPTH_TEST)、glEnable/glDisable(GL_BLEND)等打開或關閉,對于RGBA, Depth, Stencil Buffer,可以用glColor/Depth/StencilMask(GLboolean/GLuint)進行控制是否可寫。注意,緩沖區使能和緩沖區屏蔽是獨立的,使能控制是否進行測試,如果不進行測試,片斷將直接通過,然后對于通過測試的片斷根據是否屏蔽決定是否更新緩沖區。

?

以上參考:

  • Real Time Rendering 第三版
  • OpenGL 編程指南第8版
  • opengl.org
  • https://learnopengl.com
  • OpenGL ES 3.0 編程指南
  • http://www.cnblogs.com/liangliangh/p/4116164.html
  • GPU編程

總結

以上是生活随笔為你收集整理的OpenGL——GPU图形渲染管线的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。