第一章:繪制管線 OpenGL的誕生有很長時間了,讀過互聯網上成百上千的文檔后,很難明確哪一部分是老的內容,哪一部分在現代圖形硬件上仍然可以繼續使用。是時候對如今仍在使用的OpenGL做一次新的介紹了。 什么是OpenGL Wikipedia 對OpenGL的用途和歷史做了一個全面的回顧,但是這里我還是簡要的總結一下。在現代的體系中,OpenGL是一個和可編程GPU進行交互的跨平臺程序庫,用于繪制實時3D圖形。在游戲、CAD和數據可視化程序中被廣泛使用。OpenGL最早出現在90年代,是作為一個跨平臺SGI專用圖形庫的標準,SGI專用圖形庫用于在其高端工作站上驅動圖形硬件。 幾年以后,GLQuake和3dfx的Voodoo圖形加速卡漸成主流,OpenGL也成為除了Microsoft專用Direct3d程序庫以外,用于操作普通PC機上圖形加速卡的又一個標準。近幾年來,Khronos組織管理OpenGL標準,不斷更新使之可以支持現代可編程GPU,并通過OpenGL ES和WebGL將它擴展至移動和網絡領域。OpenGL 3拋棄了那些老版本中變得混亂的過時特性,讓OpenGL越發精簡流暢。 最近的另一個發展是通用GPU(GPGPU)庫,包括NVIDIA的CUDA技術和Khronos的OpenCL。這些庫通過一種類C語言,增加了數據并行特性,讓GPU能用于普通計算,而不必在OpenGL的圖形框架之下。然而,這些GPGPU的框架并沒有取代OpenGL;因為他們的主要目的不是圖形編程,它們只是提供了訪問GPU的運算單元,而忽視專用的圖形硬件。雖然這樣做是可行的,但作為OpenGL的配件,支持CUDA和OpenCL既可以分享GPU與OpenGL的內存緩沖區,又可以在GPGPU程序和圖形管線之間傳遞數據。 GPGPU不在本次介紹之列,我的重點是使用OpenGL完成圖形(編程)。 對于這些教程,假設你已經是一個程序員,知道C語言,但之前不一定見過OpenGL或進行圖形編程。了解一些基本的代數和幾何知識將有很大的幫助。我會覆蓋OpenGL 2.0避免討論在OpenGL 3或者OpenGL ES中不推薦或者拋棄的任何API。在講完基礎知識以后,我會談談OpenGL 3和4的一些新功能。除了OpenGL,我將使用兩個輔助庫:GLUT(GL實用工具包),它提供了一個跨平臺的OpenGL和窗口系統接口,GLEW(GL擴展),它簡化了不同版本的OpenGL及其擴展。 從哪里獲得OpenGL, Glut 和Glew OpenGL的標準以某種形式存在于MacOS X,Windows和大多數Linux發行版中。如果你想繼續學習這些教程,你需要確保你的OpenGL實現支持至少2.0。 MacOS X系統即使圖形卡驅動程序不提供,也能通過軟件實現OpenGL 2.0。在Windows上,取決于你的圖形卡驅動程序提供OpenGL 2或更高版本。你可以使用RealTech免費的OpenGL擴展查看器,看看你的驅動程序所支持的OpenGL版本。近4年來NVIDIA和AMD發行的圖形卡所提供的驅動至少支持OpenGL 2.0。Intel板載圖形卡以及老的顯卡用戶沒有那么幸運。對于后者,Mesa提供了一個開源、跨平臺的OpenGL 2.1軟件實現,在Windows和幾乎所有的Unix平臺上都可以運行。 Mesa是最常見的Linux中OpenGL實現,它和X服務使用“直接渲染接口”(DRI)通過圖形硬件與OpenGL交互。你可以通過運行一個xterm的glxinfo命令來查看您的DRI驅動程序是否支持OpenGL 2.0。如果不支持,你可以禁用該驅動程序,使用Mesa的軟件實現。 nVidia對于他們自己的GPU也提供專有的針對Linux的OpenGL實現,對于目前的NVidia圖形卡,都能支持OpenGL 2.0或以后更高版本。 要安裝GLUT和GLEW,在它們各自的網站上找到二進制包。MacOS X預裝了GLUT。大多數Linux發行版都可以在其打包系統資源得到GLUT和GLEW。對于GLUT你可能還需要開啟你的發行版中 “非自由”套件庫選項,因為它的許可并不是技術開源。如果你對它要求很高,有一個開源的GLUT克隆:OpenGLUT可以使用。(譯者注:我沒有linux的編程經驗,有不準確的請見諒) 如果你是一位經驗豐富的C語言程序員,你應該能夠安裝這些庫,并讓他們在你的開發環境中順暢工作。在我們開始編寫代碼之前,我要講一些籠統的概念。在這第一章,我要解釋圖形管線和數據流的繪制工作。在下一章,我們將編寫一個簡單的“Hello World”程序,將圖像文件繪制到屏幕上,顯示該管線是如何工作的。 圖形管線 早期的實時三維,三角形是場景繪制的一切。雖然現代圖形處理器可以執行各種花哨的效果來掩蓋這個秘密,但在所有的效果之下,三角形仍然是GPU工作的介質。 OpenGL的圖形管線反映了這一點:主程序填充OpenGL頂點數組管理的內存緩沖區,這些頂點投影到屏幕空間并組裝成三角形,通過光柵化生成像素大小的片元,然后片元被分配顏色值并繪制到幀緩沖區。現代圖形處理器可以使用著色器來實現“投影到屏幕空間”和“分配顏色值”獲取靈活性。讓我們來看看每個階段的細節: 頂點和圖元數組 渲染工作通過管線中一個或者多個填充著頂點屬性值的頂點緩沖區開始,這些屬性用于頂點著色器的輸入。常見的頂點屬性包括在三維空間的頂點位置,一個或多個紋理坐標集合,紋理坐標用于將頂點映射到一個或者多個紋理的采樣點。這一系列提供數據給繪制工作的頂點緩沖區即稱之為頂點數組。當繪制任務提交時,我們提供一個額外的圖元數組到頂點數組中,即一個索引數組,用來選擇哪些頂點進入繪制管線。索引值的順序還可以控制以后頂點如何裝配成三角形。 統一狀態和紋理 繪制任務也有統一的渲染工作狀態,它在管線的每一個可編程階段都提供了一系列共享的只讀值。這使得著色器程序在頂點和片元之間能保持參數不改變。統一的狀態包括紋理,可以是能被著色器采樣的一維,二維,或三維數組。顧名思義,紋理通常用來將圖片映射到表面上,它們也可以用來作為預先計算函數的查找表,或作為各種效果的數據集。 頂點著色器 GPU從頂點數組中讀取每一個選擇的頂點,通過頂點著色器來執行它,頂點著色器是將一系列頂點屬性作為輸入并輸出一系列新屬性的程序,這些屬性稱之為變量,用于提交給光柵化處理。在頂點著色器中至少要計算屏幕空間頂點的投影位置。頂點著色器也可以產生其他的輸出變量,比如顏色、紋理坐標,用于光柵化為混合連接頂點的三角形表面。 三角形裝配 GPU連接投影后頂點來組建三角形。它通過圖元數組所指示的順序講頂點組織成“三個頂點”的結合。頂點可以被組織為幾種不同的方式: 以每三個元素作為一個獨立的三角形。 設為一個三角形條帶,重用三角形的最后兩個頂點,作為下一個三角形的前兩個頂點。 設為三角形扇面,連接的第一個元素到后面的每一對元素。 該圖顯示了三種不同模式的行為。條帶和扇面在第一個三角形之后的每一個三角形都只需要一個新的索引就能構建,平衡了圖元數組中獨立三角形的靈活性和額外的存儲效率。 光柵化 光柵化處理每一個三角形,裁切或者丟棄屏幕之外三角形,將可見的三角形分割成像素大小的片元。如上所述,頂點著色器的輸出也被插值,并光柵化到每一個三角形的表面,同時將每一個片元之間光滑過度。例如,如果頂點著色器分配每個頂點一個顏色值,光柵化將融合像素化表面的顏色,如圖所示。 片元著色器 生成的片元提交給另一個稱為片元著色器的程序。片元著色器接收到頂點著色器輸出的變量,通過光柵化作為輸入進行插值。它輸出顏色和深度值,然后進入幀緩存進行繪制。普通片元著色器操作包括紋理映射和光照處理。由于片元著色器對每一個像素的繪制獨立運行,它可以執行最復雜的特殊效果,同時它也是圖形管線中對性能最敏感的部分。 幀緩存,測試和混合 幀緩存的是渲染工作輸出的最終目的地。除了OpenGL給你的用于繪制到屏幕上的默認幀緩存以外,現代的OpenGL實現可以讓你繪制到離屏的幀緩存對象或者紋理上。這些紋理可以被用來作為其他渲染工作的輸入。幀緩存不僅僅是一個單一的二維圖像,除了一個或多個顏色緩沖區,幀緩存可以擁有一個深度緩沖區或者模板緩沖區,這兩種緩沖區在片元繪制到幀緩沖區之前對其進行過濾。深度測試將放置在已繪制片元之后的片元丟棄,模板測試使用形狀將緩沖區對象的可繪制部分繪制到模板緩沖區中。片元將它們的顏色值和“覆蓋”的顏色值進行混合,最終的顏色、深度和模板值繪制到相應的緩沖區中。 結論 這就是你在OpenGL中調用“繪制”方法時,數據從頂點緩存到幀緩存的過程。渲染一個場景通常涉及多個繪制工作,變換紋理、其他的統一狀態或者階段之間的著色器,以及使用幀緩存的深度和模板緩沖區來結合每個階段的繪制結果。現在我們已經覆蓋了三維渲染一般的數據流過程,我們可以寫一個簡單的程序,看看OpenGL中這一切是如何發生的。在整個教程的過程中,我很想知道您的反饋意見,如果有幫助請告知我,或者這些對你沒有任何意義。 |