原帖地址:http://school.ogdev.net/ArticleShow.asp?id=5551&categoryid=5用RenderMonkey 進行shader開發Natalya Tatarchuk3D Application Research GroupATI Research作者:董寶成Email:dongxinzhiemail@163.com 介紹目前3D圖形應用程序開發人員面臨的挑戰主要集中于創建和使用可編程圖形shaders。這些可編程的圖形shaders是將來圖形編程的核心競爭力。有能力創建和使用這些可編程shaders的開發人員將能夠享受所有硬件所提供的高級特性和創建顛覆傳統實時圖形藝術的應用程序。為可幫助開發者充分釋放這些競爭力潛在優勢,ATI開發了一組工具— RenderMonkey 工具集。盡管寫匯編或高級shader語言代碼是開發過程的核心,但shaders遠不止這么簡單。壓縮一個基于shader的效果是一個復雜的任務因為包括捕獲所有包括這些渲染特效系統的狀態。這就導致一個普遍存在于shader開發者之間的問題 — 交換和共性數據不是一件簡單的事。另一個問題是在開發shader程序的工程中它必須與藝術家緊密的交流。由于沒有適合藝術家使用的工具,就造成了開發過程中合作的困難。現在需要的是一個開發環境,他不僅僅適合程序員而且藝術家和游戲設計者也能夠一起合作,從而創造出預想的效果。RenderMonkey就是被設計用來解決這些問題的。用這個工具,我們提供了一個創建shaders的強大的程序員開發環境,它能被作為一個標準的傳輸機制允許開發組之間共享基于shader的特效。我們也提供了一個靈活的,可擴展的框架他能夠非常容易的將自定義的組件集成而且還為以后的工具開發提供了一個基本的固件集。RenderMonkey 能很容易定制和集成到任何開發者的工作流中。RenderMonkey集成開發環境的設計使得將當前的和以后的API結合在一起變得非常容易。這篇文章是關于1.0版本的,他能夠支持DirectX9.0 shader 特效(用匯編和HLSL都行),也支持基于GL2編寫的基于OpenGL的特效。集成開發環境預覽RenderMonkey應用程序接口對那些曾經用過像Microsoft Visual Studio之類的集成開發環境的開發者而言將是非常直觀的。圖1是一個接口渲染一個云特效時的快照。圖1 — 主要應用程序界面這個主要接口有以下幾個組件組成:l 一個編輯特效的工作區視圖l 一個用于顯示編譯結果和來自應用程序的文本信息的輸出窗口l 一個用于預覽被編輯特效的預覽窗口l 另外的編輯模塊還有用于編輯代碼的編輯器和用于shader參數的GUI編輯器。Shader參數能被指定為“藝術家可編輯”標記然后它就能夠用藝術家編輯器模塊進行編輯。創建一個基本的照明特效在這節,我們將創建一個簡單的照明特效在RenderMonkey 的預覽窗口渲染一個明亮的材質。盡管這個簡單計算光照強度的方法來自用于初學者圖形學書籍,但是它作為學習用RenderMonkey 集成開發環境快速開發shader的指南非常好。它還充分展示了用微軟的HLSL開發shader程序的的優雅,我們能用熟悉的光照公式而且用很少的幾行代碼就能夠實現很好的視覺效果。我們將用Phong光照模型來實現這個特效。如果我們仔細研究任何一本圖形學的書籍都能找到計算該光照模型的公式,該公式如下:I = Iambient + Idiffuse + Ispecular (1)每個光照組件貢獻的計算如下:Iambient = Ka*Ia (2)Idifuse = Kd*Id * (N dot L) (3)Ispecular = Ks*Is * (V dot R)n (4)Ka ,Kd ,Ks 分別環境,漫射和鏡面光照的系數。根據我們表面的反射系數,這些參數被指定為范圍在0到1的常量值。如果我們想要一個高反射率的表面,我們要設置Kd和Ks的值接近1。這將產生一個光亮的表面,在光直接照射的地方有一個高強度的高光 。為了模擬一個高吸光率的表面,我們設置反射率的值接近0。 Id是漫反射光照強度,Is是鏡面反射強度,Ia是環境光強度。N,V,R分別為法向量,視向量和反射向量。 n是鏡面反射系數,調整視向量和反射向量的之間的角度值。光澤的表面有一個狹窄的光照范圍(這兩個向量之間的夾角很小),一個以南的表面有寬的反射范圍。因此一個非常光澤模型有一個大的n值(100左右),一個黯淡的表面有一個大概等于0.5的值。我們在像素shader中用公式(2)——(4)來計算該光照模型的每個像素的最終顏色。但首先我們要建立應用程序和特效工作區。運行時數據庫預覽在RenderMonkey 中的每一組視覺特效都被壓縮到一個單獨的XML工作區中。除了紋理和材質存儲在一個單獨的文件中之外,所有這些信息對創建特效都非常關鍵。它使用戶可讀的,而且每一個游戲開發人員都能夠創建自己的轉換工具將RenderMonkey 的文件格式轉換成他們各自的游戲引擎的腳本格式。我們有充分的理由選擇用XML來存儲特效工作區。最重要的,XML是工業標準且不失易用性(RenderMonkey 用微軟的XML剖析器還有其他一些可選的理由)。他表示數據很容易而且是用戶可擴展的。最酷的就是,任何人都能用IE直接打開RenderMonkey的XML文件進行閱讀 — 它只是另一種ASCII文件格式。要創建一個基于shader的特效,我們首先要啟動一個應用程序,它將自動為你創建一個空的工組區。所有和特效有關的數據都會用RenderMonkey的運行時數據格式存儲在該工作區中。每個特效工作區由下列一些元素組成:l 變量節點l 流映射l 模型l 紋理變量l 特效組一個特效組把一系列相關的特效組合在一起。比如,你可能想把所有用一個噪點函數渲染的混亂特效組合在一起,像云,火或等離子。每一個特效組由一個或多個特效節點組成。每一個特效節點用來描述一個單獨的視覺特效。你可能想用一個單獨的過程特效,或用幾個繪制掉用來產生你想要的結果。每個繪制調用可能有下列數據組成:l 一個渲染狀態塊(可選)l 一個頂點shader(必須)l 一個像素shader(必須)l 一個幾何模型參考(必須)l 一個流映射參考(必須)l 一個或多個有有效紋理參考的紋理對象(可選)l 變量節點(可選)所有在RenderMonkey特效工作區涉及到的單獨項目都被指定為節點。工作區視圖特效工作區中的主要窗口就是工作區視圖。他是一個可停靠的窗口,通常位于主界面的左側,它包括一個用于顯示特效數據庫的高級視圖的節點樹。圖2顯示了工作區視圖窗口:圖2.工作區視圖工作區視圖能訪問特效工作區中的所有元素。這樣設計的目的是能根據每個單獨特效之間的共同屬性將他們組合在一起。工作區視圖中有兩個標簽:特效標簽和藝術標簽。特效標簽用于顯示全部的工作區——所有變量和過程。藝術視圖只顯示那些在工作區中被指定了藝術家可編輯標志的變量。程序員用特效標簽開發了一種特效,然后把它交給藝術家,藝術家就能夠簡單的通過調節藝術標簽中的藝術家可編輯變量來調出他們想要的效果。好了,讓我們開始實現我們的特效。如果你在工組區節點處單擊右鍵,將探出一個菜單,然后選擇 Add Effect Group 菜單項。該菜單如圖3所示:圖3 用于添加新的特效組的上下文菜單當你在工組區中添加一個新的特效組的時候,RenderMonkey將自動在你的工作區中添加一些節點。他自動添加一個含有一個過程的特效樣本。該過程中包含一個頂點和像素shader的示例,和一個模型。如果你有一塊ATI RADEON 8500或更好的圖形芯片,你將能在預覽窗口中看見一個紅色的茶壺。如果沒有,你需要把像素shader換成 PS_1_1(我將在后面的文章中教你怎么換)。RenderMonkey也增加一個叫做view_proj_matrix的矩陣變量和一個標準的流映射節點——standard mapping。還增加了一個模型節點。這是你能在功能完善的特效基礎上創建比一個紅色茶壺更好的視覺效果。變量的創建和管理你的任何一個基于shader的特效都要有一些用于當前渲染的參數。在RenderMonkey中這些參數都被指定為變量節點。你能夠在節點樹的任何級別增加你的變量。既然我們已經知道了要在我們的shader中需要一些輸入變量,那么,現在就讓我們加入它們吧。要想加入變量你需要在想要把變量增加到的節點上單擊右鍵,再彈出的菜單中選擇“Add Variable“菜單項。(見圖4)圖4 增加變量然后會彈出如圖5所示的對話框圖5 增加變量對話框你要為你的變量節點選擇一個RenderMonkey支持的數據類型:l 標量(一個簡單的浮點變量)l 向量(4D 浮點變量)l 矩陣(4×4 浮點矩陣)l 顏色(4D 浮點變量,分別用表示 RGBA)l 紋理變量:Ø 2D 紋理貼圖Ø 立方貼圖Ø 體積紋理節點左邊的圖標可以幫你快速的確定節點的類型。例如,矩陣類型左邊會有一個 圖標,而顏色則為 。默認情況下,新創建的標量,向量和矩陣變量沒有被指定為藝術家可編輯,而顏色,紋理,立方貼圖和體積紋理變量則被指定為了藝術家可編輯。你能夠在變量創建時指定該變量是否為藝術家可編輯(在 Add Variable 對話框中指定Artist Editable)。這個標記將決定該變量是否在藝術標簽中顯示。如果你想指定一個以創建的變量為藝術家可編輯的,你可以右鍵單擊該變量然后選擇Artist Variable 菜單項。如果想移除藝術家可編輯屬性,可再次右鍵單擊該變量,然后再次選擇Artist Variable 菜單項即可。一個黃色的小三角圖標江指出該變量是否為藝術家可編輯,如果該變量是藝術家可編輯的則在該變量圖標的左上角就會出現這個黃色的小三角: ,否則沒有。預定義的RenderMonkey 變量你可能已經注意到了,當你在創建一個新的特效組的時候,RenderMonkey 自動為你增加了一個叫做 view_proj_matrix 的矩陣變量。這就是一個預定義變量的例子。與定義的變量是一些常量值,他們在程序運行時就已經被指定好了。而且你不能直接改變它們的值。RenderMonkey為了方便用戶提供了一組預定義的變量:Ø view_proj_matrix: 一個組合了攝像機和投影矩陣的矩陣類型Ø view_matrix: 一個攝像機矩陣Ø inv_view_matrix: 攝像機矩陣的你矩陣Ø proj_matrix: 投影矩陣Ø time: 這是一個向量類型的變量,它提供了當前的時間值,它的值能在RenderMonkey 的優先選擇對話框中修改,其默認值為當前時間值與120調制的值。Ø cos_time: 一個向量類型的變量,它是時間的余弦值Ø sin_time: 一個向量類型的變量,它是時間的正弦值Ø tan_time: 一個向量類型的變量,它是時間的正切值最簡單的添加預定義變量的方法是在 Add Variable 對話框中選擇適當的量類型,然后 Name 下拉列表框中選擇你想要添加的變量的名字。(如圖6所示)注意,你選擇的變量的名字必須與上面選擇的類型一致,否則RenderMonkey將不能將其正確的初始化,因為RenderMonkey從變量的名字和類型兩方面來判定預定義的變量。圖6 選擇預定義的變量與定義的變量在工作區中也很容易辨識,他將在變量類型圖標的左下方有一個綠色的小圖標,如圖 。流映射模塊另一個自動添加到特效工作組中的節點是流映射節點。流映射節點能在工作區的任何地方創建(直接在特效工作區中,直接在特效工作組中,或者在各個過程中)。該節點的作用是綁定數據流到輸入寄存器中供shaders使用。RenderMonkey使用直接來自模型數據來自動產生這個流或者你通過用戶接口來定義流通道,然后由應用程序計算該流。流映射模塊被用來給一個過程裝配幾何模型。要創建一個流映射節點,右鍵單擊一個父節點(一個特效,一個特效工作區或一個特效組)再彈出的菜單中選擇 Add Stream Mapping 菜單項。圖7 是一個在特效工作區中創建一個空的流映射節點的例子。圖7 增加流映射節點一旦你創建了一流映射節點,你就能夠雙擊或右鍵單擊選擇 Edit 調出流映射節點編輯器來編輯該節點,見圖8圖8 流映射節點編輯器我們知道要正確地計算光照,需要頂點的法線和定點的位置。讓我們把它們添加到我們的工作區中。雙擊流映射節點調出流編輯器。我們單擊 Add Channel 按鈕增加一個新的通道。然后選擇想要的輸入寄存器,然后使用法,索引和類型。如果你想刪除一個通道,單擊該通道后面的 X 按鈕。圖9 中我已經增加了一頂點的法線通道,不要忘了把法線通道的類型設置成 FLOAT3。圖9 增加一個法線通道要真正的要流映射起作用,你需要在你的過程中增加一個流映射參考。要增加一個流映射參考,你要確保已經在工作區樹的某個地方創建了一個流映射節點。然后在你想放置該參考的過程節點上單擊右鍵,再彈出的菜單中選擇 Add Stream Mapping Reference菜單項(如圖10 )圖10 在過程中增加一個流映射參考一個新的流映射參考被創建。初始情況下這個參考是沒有連接任何流映射節點的。圖標上紅色的斜杠()表示該參考節點沒有被正確的連接。要正確地連接,右鍵單擊過程中的流映射節點,再彈出的菜單中選者Reference Node 菜單項,然后選擇你要連接的節點名稱(如圖11)。你也可以雙擊流映射參考節點然后將其重命名為流映射節點來直接連接它。圖11 連接一個流映射參考到一個流映射節點為了確定一個過程中流映射的范圍,RenderMonkey 首先要檢查該過程中是否有一個流映射實例。如果在過程中既沒有找到流映射的實例也沒有找到流映射參考,應用程序將到整個工作區中去查找第一個流映射節點或參考。所以你必須考慮放置流映射節點或參考的位置,因為錯誤的使用流映射節點將導致渲染結果的錯誤。如果一個流映射節點被找到且被判定是正確的,將出現一個流映射參考節點的圖標:。注意,圖標中的小箭頭說明這只是一個參考而不是一個真正的流映射節點。在RenderMonkey 中所有的參考節點的圖標上都有一個小箭頭,所以通過它們你可以很容易的找到工作區中的參考節點。模型管理一個特效要通過一個幾何模型才能過表現出來。RenderMonkey用模型和模型參考節點來允許用戶指定哪個模型被渲染。正如你所看到的,再主工作區節點下包含一個模型節點,在過程節點中包含一個模型參考節點。通過一個紅色的小茶壺圖標你能很容易的找到模型節點,和參考模型節點(茶壺下有一個小箭頭,前文已經提到過每個參考節點圖標的左下角都有一個這樣的小箭頭)。要在模型節點中增加一個新的模型,雙擊模型節點再彈出的對話框中原則一個你要添加的模型文件。為了綁定數據流到shaders,RenderMonkey將在一個工程中成對的增加一個模型參考節點和一個流映射參考節點以保證必要的數據在運行時就存在且能即時地將其綁定到流源。管理特效盡管我們在這次練習中不使用任何額外的特效,我們也暫時討論一下關于RenderMonkey中的特效管理。工作區中的每個特效都被用來繪制一單獨的,連續的視覺特效。他有一個或更多的繪制調用組成。要創建一個新的特效,在特效工作組節點上單擊右鍵,再彈出的菜單中選擇Add Effect(見圖12)。圖12 在工作區中增加一個新的特效你能很容易地將一個特效重命名。默認的,RenderMonkey在增加一個新的特效的同時會增加一帶有HLSL頂點和像素shaders的一個單獨的工程節點。要想看到新增的特效節點的效果,你要將該節點設置成活動的。要激活該節點,在該節點上單擊右鍵然后再彈出的菜單中選擇Set as Active Effect。你能很容易的辨認出一個激活的特效節點,因為它將粗體顯示。現在我們已經接近了可編程流水線的核心——shaders自身。RenderMonkey同時支持匯編和高級著色語言shaders。為了增加新的像素或頂點shaders,在你想要將其添加到的特效節點上單擊右鍵,選擇Add Vertex Shader 或Add Pixel Shader。(見圖13)圖13 增加Shaders現在,你要選擇你想要添加的shader的類型。在如圖14的對話框中選擇一種你想要的shader類型(匯編或HLSL)。圖14 增加一個新的Shader單擊OK按鈕增加一個新的shader。通過圖標你能很容易的辨認出Shaders的類型:DirectX匯編語言的頂點shaders的圖標為 ,匯編的像素shaders的圖標為 ;DirectX HLSL的頂點shaders的圖標為 ,像素shaders的圖標為 。RenderMonkey將根據語言自動地選擇合適的shader編輯器。注意,每個過程中只能有一組頂點和像素shaders。如果你想改變一個shader的類型,你需要刪除舊的shader然后增加一個新的。編輯shaders現在我們已經有了一個包含一對shaders的過程,那么現在就讓我們看看實際的代碼吧。要編輯一個shader,雙擊該shader節點,然后RenderMonkey將打開一個適當的shader編輯器。一個單獨的特效中的所有過程都共享一個shader編輯器窗口。圖15顯示了一個shader編輯器用戶界面的快照。圖15 shader 編輯器窗口(HLSL shader)在上面的圖形用戶界面中,shader編輯器有兩個標簽葉;一個用于頂點shader另一個用于像素shader。這個用戶界面根據你選擇的shader類型的變化而變化。圖16 是一個匯編語言shader編輯器用戶界面的快照。圖16 匯編語言shader編輯器窗口要編輯不同過程的shaders,你只需要簡單得選中你想要編輯的過程。頂點和像素shader標簽將被更新為新過程的頂點和像素shader標簽葉。你能用Ctrl和Tab鍵的組合來快速的在頂點和像素shader標簽葉之間切換。頂點shader設置和編輯讓我們在我們地一個過程的頂點shader中增加一些代碼。下表顯示了我們將要增加的代碼。(表1):
表1于計算Phong光照的頂點shader頂點shader變換頂點位置,然后將其輸出。然后她用一個名字為lightDir的shader變量計算了光向量(我們將在我們的創建完成我們的shaders后增加shader昌亮)。他還用RenderMonkey的一個預定義變量——view_matrix計算了頂點,視向量和法向量在視空間的位置,然后將視向量和法向量輸出到像素shader中。在我們實際增加這些代碼之前,讓我們仔細看看RenderMonkey用于編輯HLSL shaders的用戶界面。高級著色語言(HLSL)編輯器包括三部分。在編輯器頂部有一個用于管理shader參數的小裝置。中間的文本編輯器用于顯示HLSL shader的參數聲明。該部分是不可編輯的,他僅被上部管理shader參數的小裝置控制。這樣能有效的保證RenderMonkey的變量節點和紋理對象正確的映射到HLSL參數。底部的窗口用于編輯實際的shader文本(見圖15)。注意,一旦完成了常量和采樣器的映射,你就能將常量編輯器塊最小化取消其前面的鉤選。要映射一個變量節點(向量,顏色,矩陣,或標量)單擊變量名標簽后的箭頭按鈕:再彈出的一個包含了在被編輯的shader范圍內的所有變量節點的菜單中選擇一個你想映射的節點。(圖17) 圖17增加變量到HLSLshaders這是,“name”標簽欄將會變成你選擇的節點的名字。接下來你要點擊“Add ”按鈕將新增加的變量節點加入到聲明塊,且將其映射為一個shader常量。然后,你將在實際的文本聲明中看到該聲明的變量。現在讓我們增加一個光向量,將其映射為我們寫的頂點shader中的一個常量。在特效工作區節點上單擊右鍵然后選擇Add Variable。然后選擇vector變量類型,將其命名為lightDir。若果你愿意也可以不選Artist Editable。單擊OK按鈕將在你的工作區中增加一個新的光向量,你將看到一個像這樣的節點。轉到我們已經打開的頂點shader編輯器,一步一步地將這個光向量映射為一個頂點shader的常量。當你點擊Add按鈕后,聲明塊中將增加一個像這樣的文本——float4 lightDir;我們已將在我們的shader中增加了對一個常量!接下來該shader需要的一個變量是視矩陣。應為它是RenderMonkey的一個預定義變量,所以,你不能直接改變它的值。好了,讓我們在工作區中增加該變量。右擊特效工作區節點選擇Add Variable。選擇Matrix變量類型。你將看到名稱編輯框變成組合框。展開這個組合框,在出現的變量列表中選擇view_matrix。然后單擊OK搞定。你將在工作區中看到這樣一個節點。左下角綠色的小”p”表示它是一個RenderMonkey的預定義變量。根據上述步驟增加這個變量到頂點shader的聲明區。下表列出了聲明塊中的全部變量(順序并不重要):Float4×4 view_proj_matrix: register(c0);Float4 lightDir;Float4×4 view_matrix;現在你能簡單的書寫余下的shader代碼(頂點shader輸出結構聲明和主函數)到shader的文本編輯器窗口。用戶應該已經注意到了,RenderMonkey中將要被映射到高級著色語言中的參數的節點必須有一個合法的名稱。請參考HLSL語言的用戶手冊來了解更多的關于命名規則的信息。默認情況下,一個HLSL shader 的入口函數名為main,(頂點和像素shader中都適用)。如果你想改變入口函數名,在入口點編輯區改變一個你想要的名字即可:.因為每個shader都需要一個編譯目標。所以,我們也需要為它指定一個。默認的,RenderMonkey的 HLSL shaders 提供了vs_1_1和ps_1_4。要改變目標的版本,從目標組合框中的列表中選擇一個你想要的目標。你要為頂點和像素shader分別指定目標。請參考HLSL文檔來了解每個目標。底部的區域用于編輯shader的文本。該文本中至少要包含一個用于指明shader編譯的入口點的函數。這個文本編輯器有HLSL風格的語法顏色。