《GPU編程與CG語(yǔ)言之陽(yáng)春白雪下里巴人》- 第三章(Shader Language)

第03章 Shader Language

我們?nèi)家獜那拜吅屯厡W(xué)習(xí)到一些東西。就連最大的天才,如果想單憑他所特有的內(nèi)在自我去對(duì)付一切,他也決不會(huì)有多大成就。
                                 ------ 歌德

In the last year I have never had to write a single HLSL/GLSL shader. Bottom line, I can't think of any reason NOT to use CG.
  Shader Language, 稱為著色語(yǔ)言,Shader 在英語(yǔ)中的意思是陰影、顏色深淺的意思,Wikipedia 上對(duì) Shader Language 的解釋為“The job of a surface shading procedure is to choose a color for each pixel on a surface, incorporating any variations in color of the surface itself and the effects of lights that shine on the surface(Marc Olano)”, 即,Shader Language 基于物體本身屬性和光照條件,計(jì)算每個(gè)像素的顏色值。
  實(shí)際上這種解釋具有明顯的時(shí)代局限性,在 GPU 編程發(fā)展的早期,Shader Language 的提出目標(biāo)是加強(qiáng)對(duì)圖形處理算法的控制,所以對(duì)該語(yǔ)言的定義亦針對(duì)于此。但對(duì)這技術(shù)的進(jìn)步,目前的 Shader Language 早已經(jīng)用于通用計(jì)算研究。
  Shader Language 被定為為高級(jí)語(yǔ)言,如,GLSL 的全稱是“High Level Shading Language”,Cg 語(yǔ)言的全稱為“C for Graphic”,并且這兩種 Shader Language 的語(yǔ)法設(shè)計(jì)非常類似于 C 語(yǔ)言。不過高級(jí)語(yǔ)言的一個(gè)重要特性是“獨(dú)立于硬件”,在這一方面 Shader Language 暫時(shí)還做不到,Shader Language 完全依賴于 GPU 架構(gòu),這一特征在現(xiàn)階段是非常明顯的!任意一種 Shader Language 都必須基于圖形硬件,所以 GPU 編程技術(shù)的發(fā)展本質(zhì)上還是圖形硬件的發(fā)展。在 Shader Language 存在之前,展示基于圖形硬件的編程能力只能靠低級(jí)的匯編語(yǔ)言。
  目前,Shader Language 的發(fā)展方向是設(shè)計(jì)出編輯性方面可以和C++\JAVA相比的高級(jí)語(yǔ)言,“賦予程序員靈活而方便的編程方式”,并“盡可能的控制渲染過程”同時(shí)“利用圖形硬件的并行性,提高算法的效率”。Shader Language 目前主要有 3 種語(yǔ)言:基于 OpenGL 的GLSL,基于 Direct3D 的HLSL,還有 NVIDIA 公司的 Cg 語(yǔ)言。
  本章的目的是闡述 Shader Language 的基本原理和運(yùn)行流程,首先從硬件的角度對(duì) Programmable Vertex Processor(可編程頂點(diǎn)處理器,又稱為頂點(diǎn)著色器)和Programmable Fragment Processor(可編程片斷處理器,又稱為片斷著色器)的作用進(jìn)行闡述,然后再此基礎(chǔ)上對(duì) Vertex Program 和 Fragment Program 進(jìn)行具體論述,最后對(duì) GLSL、HLSL 和 Cg 進(jìn)行比較。

3.1 Shader Language 原理

使用 Shader Language 編寫的程序稱之為 Shader Program (著色程序)。著色程序分為兩類:vertex shader program (頂點(diǎn)著色程序)和 fragment shader program (片斷著色程序)。為了清楚的解釋頂點(diǎn)著色和片斷著色的含義,我們首先從闡述 GPU 上的兩個(gè)組件開始:Programmable Vertex Processor(可編程頂點(diǎn)處理器,又稱為頂點(diǎn)著色器)和 Programmable Fragment Processor(可編程片斷處理器,又稱為片斷著色器)。文獻(xiàn)【2】第 1.2.4 節(jié)中論述到:
  The Vertex and Fragment processing broken out into programmable units. The Programmable vertex processor is the hardware unit that runs your Cg Vertex programs, whereas the programmable fragment processor is the unit that runs your Cg fragment programs.
  這段話的含義是:頂點(diǎn)和片斷處理器被分離成可編程單元,可編程頂點(diǎn)處理器是一個(gè)硬件單元,可以運(yùn)行頂點(diǎn)程序,而可編程片段處理器則一個(gè)可以運(yùn)行片段程序的單元。
  頂點(diǎn)和片段處理器都擁有非常強(qiáng)大的并行計(jì)算能力,并且非常擅長(zhǎng)于矩陣(不高于 4 階)計(jì)算,片段處理器還可以高速查詢紋理信息(目前頂點(diǎn)處理器還不行,這是頂點(diǎn)處理器的一個(gè)發(fā)展方向)。
  如上所述,頂點(diǎn)程序運(yùn)行在頂點(diǎn)處理器上,片段程序運(yùn)行在片斷處理器上,那么他們究竟控制了 GPU 渲染的哪個(gè)過程。圖 8 展示了可編程圖形渲染管線。


圖8.png

對(duì)比上一章圖 3 中的 GPU 渲染管線,可以看出,頂點(diǎn)著色器控制頂點(diǎn)坐標(biāo)轉(zhuǎn)換過程;片段著色器控制像素顏色計(jì)算過程。這樣區(qū)分出頂點(diǎn)著色器程序和片段著色器程序的各自分工;Vertex Program 負(fù)責(zé)頂點(diǎn)坐標(biāo)轉(zhuǎn)換;Fragment Program 負(fù)責(zé)像素顏色計(jì)算;前者的輸出是后者的輸入。
  圖 9 展示了現(xiàn)階段可編程圖形硬件的輸入\輸出。輸入寄存器存放輸入的圖元信息;輸出寄存器存放處理后的圖元信息;紋理 Buffer 存放紋理數(shù)據(jù),目前大多數(shù)的可編程圖形硬件只支持片段處理器處理紋理;從外部宿主程序輸入的常量放在常量寄存器中;臨時(shí)寄存器存放著色程序在執(zhí)行過程中產(chǎn)生的臨時(shí)數(shù)據(jù)。


圖9.png

3.2 Vertex Shader Program

Vertex Shader Program(頂點(diǎn)著色程序)和 Fragment Shader Program(片段著色程序)分別被 Programmable Vertex Processor(可編程頂點(diǎn)處理器)和 Programmable Fragment Processo (可編程片段處理器)所執(zhí)行。
  頂點(diǎn)著色程序從 GPU 前端模塊(寄存器)中提取圖元信息(頂點(diǎn)位置、法向量、紋理坐標(biāo)等),并完成頂點(diǎn)坐標(biāo)空間轉(zhuǎn)換、法向量空間轉(zhuǎn)換、光照計(jì)算等操作,最后將計(jì)算好的數(shù)據(jù)傳送到指定寄存器中;然后片段著色程序從中獲取需要的數(shù)據(jù),通常為“紋理坐標(biāo)、光照信息等”,并根據(jù)這些信息以及從應(yīng)用程序傳遞的紋理信息(如果有的話)進(jìn)行每個(gè)片斷的顏色計(jì)算,最后將處理后的數(shù)據(jù)送到光柵操作模塊。
  圖 10 展示了在頂點(diǎn)著色器和像素著色器的數(shù)據(jù)處理流程。在應(yīng)用程序中設(shè)定的圖元信息(頂點(diǎn)位置坐標(biāo)、顏色、紋理坐標(biāo)等)傳遞到 Vertex Buffer 中;紋理信息傳遞到 Texture Buffer 中。其中虛線表示目前還沒有實(shí)現(xiàn)的數(shù)據(jù)傳遞。當(dāng)前的頂點(diǎn)程序還不能處理紋理信息,紋理信息只能在片斷程序中讀入。
  頂點(diǎn)著色程序與片斷著色程序通常是同時(shí)存在,相互配合,前者的輸出作為后者的輸入。不過,也可以只有頂點(diǎn)著色程序。如果只有頂點(diǎn)著色程序,那么只對(duì)輸入的頂點(diǎn)進(jìn)行操作,而頂點(diǎn)內(nèi)部的點(diǎn)則按照硬件默認(rèn)的方式自動(dòng)插值。例如,輸入一個(gè)三角面片,頂點(diǎn)著色程序?qū)ζ溥M(jìn)行 Phong 光照計(jì)算,只計(jì)算三個(gè)頂點(diǎn)的光照顏色,而三角面片內(nèi)部點(diǎn)的顏色按照硬件默認(rèn)的算法(Gourand 明暗處理或者快速 Phong 明暗處理)進(jìn)行插值,如果圖形硬件比較先進(jìn),默認(rèn)的處理算法較好(快速 Phong 明暗處理),則效果也會(huì)較好;如果圖形硬件使用 Gourand 明暗處理算法,則會(huì)出現(xiàn)馬赫帶效應(yīng)(條帶花)。

Phong著色法,三維電腦圖像的繪圖技巧之一,結(jié)合了多邊形物體表面反射光的亮度,并以特定位置的表面法線作為像素參考值,以插值方式來(lái)估計(jì)其他位置像素的色值。

這個(gè)方法由美國(guó)越南裔學(xué)者裴祥風(fēng)發(fā)明,于1973年的博士論文首度發(fā)表。
  Phong著色法與Gouraud著色法比較,Phong著色法的效果更逼真,能夠提供更好的光滑曲面的近似值。Phong著色法假設(shè)一個(gè)平滑變化的曲面為一矢量。在對(duì)于有較小的高光曲線區(qū)的反射模型,例如PHONG模型時(shí),Phong著色法比Gouraud著色法更優(yōu)。但運(yùn)算程序也比前者為復(fù)雜。Gouraud著色法在遇到在較大的多邊形模型中央有高光曲線區(qū)時(shí)會(huì)產(chǎn)生嚴(yán)重的問題。因?yàn)檫@些高光曲線區(qū)在多邊形的頂點(diǎn)處會(huì)產(chǎn)生缺失,而Gouraud著色法是基于頂點(diǎn)的顏色的,這些高光曲線區(qū)會(huì)從多邊形的內(nèi)部缺失。這個(gè)問題在Phong著色法中得到了解決。不同于通過多邊形差值的Gouraud著色法,Phong著色法中一個(gè)矢量是從多邊形頂點(diǎn)的法線到多邊形表面進(jìn)行差值的。為了或得到最后的像素顏色,面的法線被差值,應(yīng)用于一個(gè)反射模型。由于Phong著色法需要逐像素點(diǎn)進(jìn)行計(jì)算,因此運(yùn)算量遠(yuǎn)大于Gouraud著色法。

所謂“馬赫帶效應(yīng)(Mach band effect)”是指視覺的主觀感受在亮度有變化的地方出現(xiàn)虛幻的明亮或黑暗的條紋,馬赫帶效應(yīng)的出現(xiàn)是人類的視覺系統(tǒng)造成的。生理學(xué)對(duì)馬赫帶效應(yīng)的解釋是:人類的視覺系統(tǒng)有增強(qiáng)邊緣對(duì)比度的機(jī)制。

而片段著色程序是對(duì)每個(gè)片段進(jìn)行獨(dú)立的顏色計(jì)算,并且算法由自己編寫,不但可控性好,而且可以達(dá)到更好的效果。
  由于 GPU 對(duì)數(shù)據(jù)進(jìn)行并行處理,所以每個(gè)數(shù)據(jù)都會(huì)執(zhí)行一次 Shader 程序。即,每個(gè)頂點(diǎn)數(shù)據(jù)都會(huì)執(zhí)行一次頂點(diǎn)程序;每個(gè)片段都會(huì)執(zhí)行一次片段程序。


圖10.png

3.3 Fragment Shader Program

片段著色程序?qū)γ總€(gè)片段進(jìn)行獨(dú)立的顏色計(jì)算,最后輸出顏色值的就是該片段最終顯示的顏色??梢赃@樣說,頂點(diǎn)著色程序主要進(jìn)行幾何方面的運(yùn)算,而片段著色程序主要針對(duì)最終的顏色值進(jìn)行計(jì)算。
  片段著色程序還有一個(gè)突出的特點(diǎn)是:擁有檢索紋理的能力。對(duì)于 GPU 而言,紋理等價(jià)于數(shù)組,這意味著。如果做通用計(jì)算,例如數(shù)組排序、字符串檢索等,就必須使用到片段著色程序。讓頂點(diǎn)著色器也擁有檢索紋理的能力,是目前的一個(gè)研究方向。
  附:什么是片段?片段和像素有什么不一樣?所謂片段就是所有的三維頂點(diǎn)在光柵化之后的數(shù)據(jù)集合,這些數(shù)據(jù)還沒有經(jīng)過深度值比較,而屏幕顯示的像素都是經(jīng)過深度比較的。

3.4 CG VS GLSL VS HLSL

Shader Language 目前有 3 種主流語(yǔ)言(其實(shí)現(xiàn)在更多了,該死的蘋果大大對(duì) OpenGL 下手了):基于 OpenGL 的 GLSL(OpenGL Shading Language,也稱為 GLslang),基于 Direct3D 的 HLSL(High Level Shading Language),還有 NVIDIA 公司的 Cg (C for Graphic) 語(yǔ)言。
  GLSL 與 HLSL 分別是基于 OpenGL 和 Direct3D 的接口,兩者不能混用,事實(shí)上 OpenGL 和 Direct3D 一直都是冤家對(duì)頭,曹操和劉備還有一段和平共處的甜美時(shí)光,但是 OpenGL 和 Direct3D 各自的東家則從來(lái)都是爭(zhēng)斗不休。斗爭(zhēng)良久,既然沒有分出勝負(fù),那么必然是兩敗俱傷的局面。
  首先 ATI 系列顯卡對(duì) OpenGL 擴(kuò)展支持不夠,例如我在使用 OSG(Open Scene Graphic)開源圖形引擎時(shí),由于該引擎完全基于 OpenGL,導(dǎo)致其上編寫的 3D 仿真程序在較老的顯卡上常常出現(xiàn)紋理無(wú)法顯示的問題。其次 GLSL 的語(yǔ)法體系自成一家,而 HLSL 和 Cg 語(yǔ)言的語(yǔ)法基本相同,這就意味著,只要學(xué)習(xí) HLSL 和 Cg 中任何一種,就等同于學(xué)習(xí)了兩種語(yǔ)言。不過 OpenGL 畢竟是圖形 API 曾經(jīng)的領(lǐng)袖,通常介紹 OpenGL 都會(huì)附加上一句 “事實(shí)上的工業(yè)標(biāo)準(zhǔn)”,所以在其長(zhǎng)期發(fā)展中積累下的用戶群龐大,這些用戶當(dāng)然會(huì)選擇 GLSL 學(xué)習(xí)。此外,GLSL 集成了 OpenGL 的良好移植性,一度在 unix 等操作系統(tǒng)上獨(dú)領(lǐng)風(fēng)騷(已是曾經(jīng)的往事)。
  微軟的 HLSL 移植性較差,在 Windows 平臺(tái)上可謂一家獨(dú)大,可一出自己的院子(還好院子夠大),就是落地鳳凰不如雞。這一點(diǎn)在很大程度上限制了 HLSL 的推廣和發(fā)展。目前 HLSL 多半都是用于游戲領(lǐng)域。我可以負(fù)責(zé)任的斷言,在 Shader Language 領(lǐng)域,HLSL 可以憑借微軟的老本稱為割據(jù)一方的諸侯,但,絕不可能稱為君臨天下的霸主。這和微軟現(xiàn)在的局面很像,就是一個(gè)被帶刺鮮花簇?fù)碇拇筘?cái)主,富貴已極,寸步難行。
  上面兩個(gè)大佬打得很熱烈,在這種情況下可以用一句俗話來(lái)形容,“鷸蚌相爭(zhēng),漁翁得利”。NVIDIA 是現(xiàn)在當(dāng)之無(wú)愧的顯卡之王(尤其在 AMD 兼并 ATI 之后),是 GPU 編程理論的奠基者,GeForce 系列顯卡早已深入人心,它推出的 Cg 語(yǔ)言已經(jīng)取得了巨大的成功,生生形成了三足鼎立之勢(shì)。NVIDIA 公司深通廣告知道,目前最流行的 GPU 編程精髓一書就出自該公司,書中不但介紹了大量的 GPU 前沿知識(shí),最重要的是大部分都要 Cg 語(yǔ)言實(shí)現(xiàn)。憑借該系列的書籍,NVIDIA 不光確定了在青年學(xué)子間的學(xué)術(shù)地位,而且成功的推廣了 Cg 語(yǔ)言。我本人就是使用 Cg 語(yǔ)言進(jìn)行研發(fā),基于如下理由:
  其一,Cg 是一個(gè)可以被 OpenGL 和 Direct3D 廣泛支持的圖形處理器編程語(yǔ)言。Cg 語(yǔ)言和 OpenGL、DirectX 并不是同一層次的語(yǔ)言,而是 OpenGL 和 DirectX 的上層,即,Cg 程序是運(yùn)行在 OpenGL 和 DirectX 標(biāo)準(zhǔn)頂點(diǎn)和像素著色的基礎(chǔ)上的;
  其二,Cg 語(yǔ)言是 Microsoft 和 NVIDIA 相互協(xié)作在標(biāo)準(zhǔn)硬件光照語(yǔ)言的語(yǔ)法和語(yǔ)義上達(dá)成了一致,文獻(xiàn)【1】在 1.3.1 節(jié)的標(biāo)題就是“Microsoft and NVIDIA's Collaboration to Develop Cg and HLSL”,所以,HLSL 和 Cg 其實(shí)是同一種語(yǔ)言(參見 Cg 教程-可編程實(shí)時(shí)圖形權(quán)威指南 29 頁(yè)的致謝部分)。很多時(shí)候,你會(huì)發(fā)現(xiàn)用 HLSL 寫的代碼可以直接當(dāng)中 Cg 代碼使用。也就是說,Cg 基于知識(shí)聯(lián)盟(Microsoft 和 NVIDIA),且擁有跨平臺(tái)性,選擇 Cg 語(yǔ)言是大勢(shì)所趨。有心的讀者,可以注意市面上當(dāng)前的 GPU 編程方面的書籍,大部分是基于 CG 語(yǔ)言的。(附:Microsoft 和 NVIDIA 聯(lián)手推出 Cg,應(yīng)該是一種經(jīng)濟(jì)和技術(shù)上的雙贏,通過這種方式聯(lián)手打擊 GLSL)。
  此外,Cg,即 C for Graphics,用于圖形的 C 語(yǔ)言,這其實(shí)說明了當(dāng)時(shí)設(shè)計(jì)人員的一個(gè)初衷,就是“讓基于圖形硬件的編程變得和 C 語(yǔ)言編程一樣方便,自由”。正如 C++ 和 Java 的語(yǔ)法是基于 C 的,Cg 語(yǔ)言本身也是基于 C 語(yǔ)言的。如果您使用過 C、C++、Java 其中任意一個(gè),那么 Cg 的語(yǔ)法也是比較容易掌握的。Cg 語(yǔ)言極力保留了 C 語(yǔ)言的大部分語(yǔ)義,力圖讓開發(fā)人員從硬件細(xì)節(jié)中解脫出來(lái),Cg 同時(shí)擁有高級(jí)語(yǔ)言的好處,如代碼的易重用性,可讀性提高等。使用 Cg 還可以實(shí)現(xiàn)動(dòng)畫驅(qū)動(dòng)、通用計(jì)算(排序、查找)等功能。
  在曾經(jīng)的一段時(shí)間中有一種流言:NVIDIA 將要拋棄 Cg 語(yǔ)言。并且在網(wǎng)上關(guān)于 Cg、GLSL、HLSL 的優(yōu)劣討論中,Cg 的跨平臺(tái)性也受到過廣泛的質(zhì)疑。我在 2007 年 12 月參加朱幼虹老師的 OSG 培訓(xùn)班時(shí),他曾專門對(duì) Cg、GLSL、HLSL 進(jìn)行了比較,說道:盡管目前還有一些關(guān)于 Cg 和 GLSL 之間的爭(zhēng)議,不過主流的 3D 圖形廠家都開始支持 Cg 語(yǔ)言。市場(chǎng)經(jīng)濟(jì)的選擇可以說明一切,時(shí)間可以明辨真?zhèn)危?2009 年末,Cg 語(yǔ)言不但沒有被拋棄,而且越來(lái)越受歡迎。
  我在 OGRE 官方論壇上,搜索過有關(guān)使用 Cg 和 HLSL 的討論帖子,套用其中一個(gè)帖子的結(jié)尾語(yǔ)來(lái)結(jié)束本章:

In the last year I hava never had to write a single HLSL/GLSL shader. Bottom line, I can't think of any reason Not to use CG.

3.5 本章小結(jié)

本章首先闡述了著色程序的工作原理,著色程序分為頂點(diǎn)著色器和片段著色器;然后對(duì)三種主流的著色語(yǔ)言,Cg、GLSL、HLSL,進(jìn)行了對(duì)比論證。雖然我本人比較推崇 Cg 語(yǔ)言,但并不排斥 GLSL,事實(shí)上學(xué)習(xí)任意一種語(yǔ)言總會(huì)有用武之地,無(wú)非是“地”的大小有別而已。套用武俠小說中的一句話,語(yǔ)言無(wú)高低,用法有高下。著色程序中的算法才是精髓所在!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容