頂點和片段着色器
必備知識
熟悉Stage3D API。最好之前使用過VertexBuffer。在繼續這個教程之前一定要先閱讀本系列的第一個教程(Stage3D原理)。
所需軟件
Flash Builder 4.5 Premium (Download trial)
Flash Professional CS5.5 (Download trial)
在本章中,你將對着色器(Shaders)有一個大概的了解。着色器是Stage3D渲染管道的核心。你將學到頂點和片段着色器是個什么東東,它們在3D渲染管道中扮演什么角色以及為什么它們是如此重要。
初識着色器
在本系列教程的上一篇文章:《Stage3D原理》中,你已經了解到Stage3D是如何基於可編程圖形管道工作的。
Stage3D中的可編程圖形管道是非常有用的,因為你可以通過編程來改變渲染行為。這對於以前的固定功能圖形管道來說是一個巨大的進步,固定功能圖形管道只負責把數據交給GPU,GPU接管所有渲染工作,開發者無法控制渲染過程。
然而,這也意味着,為了使用Stage3D,你必須自己編寫一些額外代碼來控制可編程管道。
我們在可編程圖形管道中編寫的小程序被稱為着色器(Shaders)。着色器分為兩種:頂點着色器和片段着色器(也叫像素着色器)。使用Stage3D渲染任何圖形,你都需要至少編寫兩個着色器:一個頂點的,一個片段的,不然你的圖形管線法工作。
着色器是在圖形硬件GPU上運行的小程序,這與在CPU上運行的普通ActionScript代碼不同。這是着色器程序和普通程序之間最重要的區別。
着色器只是在GPU中執行的程序。
在 Stage3D中,着色器被一個叫做Program3D的特殊的Stage3D API封裝(Wrapped)了起來。Program3D提供創建着色器實例的功能,並負責將其傳入GPU,接下來,着色器代碼會被執行,Stage3D API允許ActionScript代碼和着色器程序間的數據流通。
着色器運行起來是非常快的,這並不是在說ActionScipt慢。但是當你運行ActionScript時,因為它是在一個虛擬機里運行的,所以比起原生語言比如C++來說要慢些。所以現在需要3A級游戲都還在用C++編寫。
有史以來第一次,你可以編寫一個對於GPU來說原生的程序,所以它們運行起來跟原生的速度一樣快。
理解着色器在可編程圖形管道中如何工作
可編程圖形管道決定Stage3D內容如何渲染(見圖1)
圖1 可編程圖形管道單元示意圖
回顧一下上面的圖表,注意頂點和片段着色器是如何在管道中起決定性作用的。
當 你要渲染一個幾何圖形時,你會用一個VertexBuffer來定義構成幾何圖形的三角形,VertextBuffer中又包含一系列的頂點數據。來自 VertextBuffer中的頂點數據作為輸入傳遞給着色器,在着色器中可以處理這些數據。GPU將頂點着色器的輸出數據組裝為三角形,然后這些三角形 被適當的剪裁以適應用戶視域(viewport),接下來在光柵化單元被處理成一種新的格式:由片段(Fragments)組成的數據格式,片段是一種簡 單的數據格式,每一個片段包含一個三角形在屏幕上能顯示的所有像素。
片段中的數據內容通常由頂點着色器決定。事實上,頂點着色器可以將頂點屬性參數作為自己的輸出。光柵化負責將着色器輸出的頂點數據在三角形上進行顏色插值(interpolate),使片段上的每個像素都得到正確的屬性值。
例 如,有一個Vertex Buffer指定了頂點的顏色作為頂點屬性,其中三角形的兩個頂點被分別被指定為黑色和白色。頂點着色器會將這些頂點顏色數據作為輸出,傳遞給管道中的下 一個處理單元。然后,片段的相對中間部位的某處,會被置為灰色,也就是黑色頂點和白色頂點的中間色。片段中接近白色頂點的像素顏色會亮一些,相反,接近黑 色頂點的像素會暗一些。
接下來,這些插值后未經處理的片段被傳輸給片段着色器,它利用這些數據來完成最終像素顏色的建立。
除了片段着色器接收的片段數據外,你還可以用ActionScript將一些紋理數據傳遞給片段着色器,供片段着色器取樣。
頂點着色器原理
頂點着色器是在GPU上運行的小程序。顧名思義,頂點着色器是用來處理頂點數據的。一個頂點着色器就是一個處理頂點的小程序(老外說話真的很啰嗦!)
一 般來說,可以將幾何圖形頂點數據放在VertexBuffer中,然后將其上傳至GPU。然后,可以用一種着色器語言:例如AGAL來編寫一個頂點着色 器。頂點着色器程序將處理VertextBuffer中的每一個頂點,這就好像在着色器周圍使用了一個for循環,但實際上你根本看不到這個for循環, 如下:
- for (var i:int = 0; i <vertexBuffer.length; i++)
- {
- executeVertexShader(vertexBuffer);
- }
復制代碼
所以,VertexBuffer中的所有頂點都會被處理。
你還可以將常量以常量寄存器的形式傳遞給頂點着色器,每次運行着色器(每次調用Context3D::drawTriangles方法,渲染一個網格)時,都可以傳入一個不同的值,着色器可以根據常量的值來調節它的算法和輸出。
頂 點着色器的輸入是一個或多個頂點屬性(Vertex Attribute)組成的VertexBuffer。VertexBuffer中的頂點應至少指出了頂點的位置屬性,這些位置屬性通常指的是每個3D模 型(每個模型都有其自身的原點)本身的坐標。頂點着色器將這些位置信息轉換為屏幕位置,以便可以正確的顯示。VertexBuffer中可能還包括一些其 它頂點屬性,例如,頂點顏色或紋理UV坐標等。頂點着色器將這些作為輸出(最終經過處理的),以便其可在光柵化單元進行插值,然后作為輸入傳遞給片段着色 器。
頂點着色器常常用來對場景中幾何圖形坐標進行矩陣變換。頂點的坐標作為一個矩陣輸入到頂點着色器中,它會將VertexBuffer中的所有頂點進行矩陣變換。由於使用了硬件加速,這個過程非常高效,大大快於自己用ActionScript編寫的代碼。
讓 人感興趣的時,頂點着色器是完全可編程的,你可以以任何你想要的方式修改幾何圖形。例如,一個典型的骨骼頂點修改的程序:你定義了一組骨骼也就是骨架和其 上的皮膚(網格)。當骨骼旋轉時,由於骨骼和皮膚連在一起,所以皮膚的形狀會跟着變化。那我們如何來實現呢?最好的辦法是將骨骼旋轉(變換)數據傳遞給一 個頂點着色器,讓它來適當的修改皮膚的動畫和變形。
還有一些會用到頂點着色器的應用場景:模擬柔軟紡織品或者可變形對象的表面。用頂點着色器來讓一個網格根據參數的變化從一個形狀變為另一個形狀。
片段着色器原理
就像頂點着色器一樣,片段着色器也是運行在GPU上的小程序。顧名思義,用它來處理片段。它們負責輸出每個三角形像素的最終顏色。
基本上來說,它是這樣運行的:片段着色器將頂點着色器輸出的片段作為輸入,片段的頂點屬性已被光柵化單元進行了插值處理。
片段着色器執行的流程基本上也很像一個循環,如果你能把未經處理的片段想象成某種數據流,就叫片段流吧,片段着色器的處理就像代碼中描述的一樣:
- for (var i:int = 0; i <fragmentStream.length; i++)
- {
- executeFragmentShader(fragmentStream);
- }
復制代碼
片段流之所以稱之為未處理過的,是因為片段着色器還沒有處理它,並計算出在屏幕上顯示的像素的顏色。
片段着色器是可編程管道中的最最核心的部分。其普遍的作用就是計算各種各樣的三角形像素顏色,從為着色頂點圖形(vertex-colored geometries)計算的頂點屬性顏色,和為紋理圖形為計算的紋理及相關的UV紋理坐標。
但 是頂點着色器的功能遠非制造這些簡單的效果。實際上,現代3D游戲中令人驚嘆的3D特效都是用片段着色器來生成的。例如,動態光源效果通常都是由片段着色 器完成。思考一下就會明白,動態光源意味着根據場景中已有的光源計算像素顏色,這與幾何圖形的位置、材料都有很大的關系,所以片段着色器是制作動態光源效 果的不二之選。
像水體環境映射之類的反射特效也都是由片段着色器完成的。片段着色器能生成世界上幾乎所有的光影特效,以上提及的只不過是它的冰山一角。
最后要提一下的是,片段着色器決定了你在屏幕上能看到什么,所以,片段着色器才是影響渲染的核心代碼。
下一步該看哪些內容
在本教程中,你已經學到頂點着色器和片段着色器是如何工作的。這兩個着色器是Stage3DAPI渲染管道中的核心。着色器可以生成各種各樣的3D視覺特效。着色器相關的在線技術文章有很多。本系列的下一個教程將學習AGAL着色器語言。
想要深入着色器的更多細節,我推薦nVidia出版的“GPU Gems”,此書已經免費。其內容並不針對Flash和Stage3D,但是會有助於了解着色器生成特效的相關知識。
GPU Gems: Part I -Natural Effects
GPU Gems2: Part I – Geometric Complexity
作者:Marco Scabia
原文鏈接:http://www.adobe.com/devnet/flashplayer/articles/vertex-fragment-shaders.html