![使用shader最大的好處是每一步的渲染管道都可自定義支_第1頁](http://file3.renrendoc.com/fileroot_temp3/2022-2/24/00e0d8c1-88cc-49cc-9981-db9e7579762d/00e0d8c1-88cc-49cc-9981-db9e7579762d1.gif)
![使用shader最大的好處是每一步的渲染管道都可自定義支_第2頁](http://file3.renrendoc.com/fileroot_temp3/2022-2/24/00e0d8c1-88cc-49cc-9981-db9e7579762d/00e0d8c1-88cc-49cc-9981-db9e7579762d2.gif)
![使用shader最大的好處是每一步的渲染管道都可自定義支_第3頁](http://file3.renrendoc.com/fileroot_temp3/2022-2/24/00e0d8c1-88cc-49cc-9981-db9e7579762d/00e0d8c1-88cc-49cc-9981-db9e7579762d3.gif)
![使用shader最大的好處是每一步的渲染管道都可自定義支_第4頁](http://file3.renrendoc.com/fileroot_temp3/2022-2/24/00e0d8c1-88cc-49cc-9981-db9e7579762d/00e0d8c1-88cc-49cc-9981-db9e7579762d4.gif)
![使用shader最大的好處是每一步的渲染管道都可自定義支_第5頁](http://file3.renrendoc.com/fileroot_temp3/2022-2/24/00e0d8c1-88cc-49cc-9981-db9e7579762d/00e0d8c1-88cc-49cc-9981-db9e7579762d5.gif)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、概覽使用shader最大的好處是每一步的渲染管道都可自定義。支持Pixel Shader版本1.1 (GeForce 3 )你你有8條指令可用,更靈活且允許實現(xiàn)更多的功能(在上一章的normalize和pow方法只適用于Pixel Shader 2.0)和更多的指令(最多96個,但一些方法需要一個以上的指令) 。Pixel shader 允許更好的流控制,這意味著您可以更好地條指令。就算你有16、24或32個像素shader并行處理器,當繪制上百萬個像素時,仍要花很多時間來為每個像素執(zhí)行許多指令,新的NVIDIA 8800 GTX的圖形卡甚至有128個shader處理器。有時候當一個像素不受燈
2、光影響或不在陰影里,你可以跳過復雜的計算,通過這種形式,您仍然可以實現(xiàn)漂亮的Pixel Shader的效果,但在現(xiàn)實中最新的游戲只需支持Pixel Shader 2.0,因為它是支持許多圖形卡;最典型的游戲不支持較昂貴的圖形硬件。與Direct3D 10(2006年初)一同推出,第一個支持它的圖形硬件是2006年年底發(fā)布的GeForce 8800,但Direct3D的10只適用于Vista而且硬件相當昂貴。還需要一段時間。xna允許更多的指令,并提出了幾何shader(可以在頂點和像素shader執(zhí)行前添加幾何數(shù)據(jù))。所有的Shader流處理器被統(tǒng)一在一起,這意味著有不再是8個頂點處理器和16
3、個像素處理器,而是統(tǒng)一128 個shader處理器通用于幾何,頂點和像素shader,這對如位移映射之類的effect很有用。在2007年,您可以期望一些很酷的演示,可能直到2008年或稍后才會使用幾何shader。為您接下去要制作的游戲中會使用到Normal Mapping(法線映射) shaders,對表面有很多的結(jié)構(gòu)和小細節(jié)的物體,比如管道,電纜這些需要用上百萬的才能顯示所有細節(jié)的情況,使用Normal Mapping(法線映射) shaders能大大改善三維物體的表現(xiàn)(見圖7-1)。你能經(jīng)常在網(wǎng)上看到一些Normal Mapping的例子that compare totally rid
4、iculous looking objects and bad textures with a super high resolution Normal Mapped object。我試著use real object from a real game(這本書后面的Racer游戲會用到),因為diffuse紋理有一點陰影效果,所以沒有Normal Mapping效果也不錯。通過這種方式,您可以不使用Normal Mapping,但物體看上去仍不錯。使用Normal Mapping能使物體看起來更好,即使只有1000多邊形,看起來也非常平滑。圖7-1 想要得到更好的效果還能使用Parallax
5、Mapping(視差映射),Offset Mapping或Displacement Mapping(位移映射, Shader Model 4支持,但代價昂貴)。這些技術(shù)較為復雜,除了diffuse貼圖和Normal Map貼圖外還需要額外的height map(高度圖)。但使用Normal Mapping已經(jīng)足夠好了。如果您有一塊帶shader功能的圖形卡,Normal Mapping并不難實現(xiàn)。在老的GeForce 3 (shader1.1版)也能工作,就現(xiàn)今的硬件可以更好地實現(xiàn)反光,效果會更好。通過前一章的學習你已經(jīng)有了基本的基礎(chǔ),包括如何創(chuàng)造shader、如何轉(zhuǎn)換頂點、像素如何最終顯示在
6、屏幕上。Normal Mapping 需要額外的紋理。diffuse紋理是用來顯示基本的材質(zhì),顏色等等。Normal Map紋理通過提供頂點向量添加更多的3D細節(jié)。圖7-2 請注意,如果您打開仙人掌的三維模型的貼圖,會發(fā)現(xiàn)上去不同,這是因為正Normal Map是壓縮的,并已經(jīng)被Alpha和紅色通道反轉(zhuǎn),這樣可以在沒失去很多細節(jié)的前提下把紋理壓縮至1:4,看起來仍不錯。More details about this technique in a second - just remember that internally the Normal Map texture looks like th
7、e texture in 圖7-2;the compressed version just stores the data differently。計算每個像素的光線是要用到Normal Mapping 紋理中的數(shù)據(jù),Normal Map中的每一個像素代表了多邊形表面的法線向量。這一數(shù)據(jù)是儲存在正切空間,可參見圖7-4。從貼圖中的顏色數(shù)據(jù)獲得法線向量要用到公式(見圖7-3),Normal Map中的RGB顏色數(shù)據(jù)以浮點數(shù)的形式被用在公式里,要將RGB顏色數(shù)據(jù)轉(zhuǎn)換成浮點數(shù),只需除以255,這在Pixel Shader里是自動完成的。比起位圖文件的字節(jié)數(shù)據(jù),浮點數(shù)更容易使用。Normal Map中
8、最多的顏色是淡藍(RGB 128,128,255),這意味著大多數(shù)向量是向上的,即vector3(0,0,1)。如果整個紋理都是淺藍色的,這意味著每個向量都朝上,那么,Normal Map將沒有任何效果。這些Normal Map像素通常存放在切線空間,這意味著法線數(shù)據(jù)和多邊形表面是有聯(lián)系的。這是所謂的切空間,通過每個頂點的切線和binormal向量你才能建立切線矩陣,而binormal可以通過叉乘法線向量和切線向量得到(見圖7-4) 。在上一章,你只有每一點的位置,法線和紋理坐標數(shù)據(jù),這些數(shù)據(jù)對Normal Mapping來說是不夠的,您至少需要每個頂點的切線矢量去建立這個切線矩陣,如果沒有切
9、線數(shù)據(jù)的話Normal Mapping 圖像顯示將不正確。你可以把切向和binormal 向量看成指向下一個頂點x和y方向的向量, but they are still octagonal (in a 90 degree angle) to the normal vector。這意味著,即使您的三維模型沒有任何切線數(shù)據(jù),您也可以遍歷所有頂點自己創(chuàng)建(不容易,但是可行的)。問題問題是,往往頂點可用于一個以上的多邊形,有時紋理坐標合并得也不好。對diffuse mapping來說這問題不大,因為您只使用法線向量計算光線,但如果你通過切線空間轉(zhuǎn)換每個像素的法線,就要求數(shù)據(jù)必須配合。這意味最好在三維程
10、序中生成切線數(shù)據(jù),三維程序知道如何在Normal Mapping shader中更好地使用哪些切線和輸出法線。在vertex shader中你只能訪問到目前您正在處理的頂點,而不能訪問下一個頂點,或建立一個新的向量指向下一個頂點。這意味著,將有效的切線數(shù)據(jù)傳送到vertex shader(頂點著色引擎)是很重要的。如果你只是定義了支持切線的vertex input structure,也不意味著應(yīng)用程序能夠處理有效的切線數(shù)據(jù)。通常您在內(nèi)容管道有.x或.fbx文件,它沒有任何切線的數(shù)據(jù)(見圖7-5 )。圖7-5這意味著你僅有法線數(shù)據(jù)而沒有切線數(shù)據(jù),這樣就無法為Normal Mapping創(chuàng)建切線
11、空間。對于簡單的對象比如這個蘋果問題不大,但如何模型有更多的曲線和紋理坐標就會出現(xiàn)顯示錯誤。圖7-6顯示的就是切線錯誤的蘋果模型。圖7-6學習了以上知識后你就可以開始處理3D模型和shader了。Asteroids(小行星)!錯誤的游戲,或者是什么呢?要建立一個象圖7-1一樣的3D模型并不容易,一個精細模型,可能會有幾百萬的多邊形,建模往往會花掉很多時間,你可能還會花很多時間優(yōu)化shader以便能讓您的游戲引擎能在同一時間內(nèi)高幀速率顯示許多對象。為了簡化問題,你將只使用一些很酷的小行星模型,其中有幾百萬多邊形的精細版本,也有1000多個多邊形的低精度版本。這些模型將被用于在下一章的Rocket
12、 Commander游戲。為了進一步優(yōu)化性能,也制作了500,200,甚至50個多邊形的小行星,Normal Maps在高低精度版本中都能用。在性能測試中200個多邊形的版本是最有效率的,它幾乎和50個多邊形版本的一樣快,但看起來更好。500個多邊形的版本不見得看好多少,特別是對低端電腦上用時較長,。因此,我們使用1000個多邊形和200個多邊形版本的小行星(見圖7-7)。 圖7-8顯示了小行星使用的三個紋理。因為所有小行星模型使用parallax mapping shader(視差映射著色),您需要為每個對象建立一個diffuse(散射),normal(法線),height(高度)貼圖。正如
13、前面所提到的,法線貼圖被壓縮,這意味著將看到紅色而不是默認的藍色法線貼圖。壓縮的法線貼圖是紅色的是因為紅色通道完全是白色、而儲存在原始紅色通道中的Alpha通道是不可見。更多詳情請參閱下一章的 shader和打開Normal Mapping 紋理。 我在2005年寫了一個名為normalmapcompressor的小工具(見圖7-9),可以從我的博客上下載。它可以用來壓縮Normal Mapping 紋理,你將可節(jié)省75的磁盤和紋理空間,而質(zhì)量下降得很少。這是真的很酷,在使用Normal Mapping或parallax mapping時可解決很多顯卡內(nèi)存不足引起的問題。而在過去,你只有dif
14、fuse紋理和小如128128,256256的分辨率,有時512512更常見。 7-9 以每通道(rgba)32位、未經(jīng)壓縮位圖的形式儲存的分辨率為128128的紋理要占128*128*4個字節(jié)=64KB的空間,而同樣尺寸壓縮為dxt1 DDS的文件只有8kB大小,一個JPG文件只有約5到10KB。256 256分辨率大小則為128128的四倍(未壓縮256KB,dxt1為32KB,JPEG格式約20KB),若512512,再次四倍,即便如此,未壓縮的貼圖大小也僅有1MB。 但今天的紋理尺寸普遍都有10241024, 20482048,甚至40964096更為常見。即使你只用10241024的
15、貼圖,未壓縮diffuse貼圖也要占用4MB的空間,因為你也需要Normal Mapping貼圖和height貼圖實現(xiàn)Shader效果,只是一個單一的紋理就要高達12MB的空間。如果您的游戲使用了數(shù)百個不同的紋理,這是完全不切實際的。你必須使用壓縮紋理和只有加載需要的數(shù)據(jù)。這就是為什么console游戲往往會重新加載關(guān)卡的數(shù)據(jù)和一般不要使用非常高的紋理,如果不這樣做,對Xbox 360和老的顯卡來說會消耗太多顯存,。diffuse紋理可以很容易地壓縮為dxt1,rgba節(jié)省8倍空間,RGB可節(jié)省6倍。如果您使用需要Alpha數(shù)據(jù)的透明物體,您可以使用dxt5,比起未壓縮rgba數(shù)據(jù)可節(jié)省4倍。
16、你也許會說“為什么不使用.jpg或.png文件?”“好,您可以為節(jié)省磁盤空間使用.jpg文件,但在顯存中仍需要解壓縮文件并將其存儲在顯存中。使用dds文件的好處是因為DXT格式更好地兼容了今天的圖形硬件和節(jié)省顯存。對Normal Maps來說,最主要的問題是DXT壓縮算法是針對顏色數(shù)據(jù)設(shè)計的,綠色通道占用大部分的壓縮空間,因為綠色的顏色更明顯。藍色通道對Normal Maps并不重要,因為它通常是十分明亮的,(見圖7-3) ,但紅色通道經(jīng)過dxt1壓縮后看起來就像crap,中,你不能再次將法線歸一化,許多情況下向量長度將完全錯誤,Normal Map的照明看起來有錯誤,而且很暗(見圖7-10)
17、。圖7-10It is really hard to explain without switching the compression on and off,屏幕上視覺效果的不同非常明顯。Normalmap compressor通過dxt5和將紅色通道儲存在Alpha通道內(nèi)的方法解決了這個問題,因為紅色通道都是白的,這使得綠色和藍色有更好一點的壓縮比。In the shader you just have to switch the red and alpha channel and you are good to go。如果你仔細觀察normalmap compressor (圖7-9),
18、你可以看到,紅色通道具有最高的variation(左側(cè)的imformation面板),這意味著紅色通道具有最不同的顏色觀和variation。藍色通道通常很低。對于diffuse貼圖和高度貼圖,您可以使用dxt1。如果你只是使用Normal Mapping,你不需要高度貼圖,可以節(jié)省更多的顯存。現(xiàn)在10241024的diffuse貼圖只需要512KB,1MB用于法線(dxt5需要兩倍多的空間),和可選的512 KB的高度貼圖,如果需要,如果您使用mip-mapping,還要增加25的空間。用去22.5 MB空間,看起來就能與未壓縮10241024的12 MB大小的紋理幾乎一樣好了。使用Norm
19、al Mapping或parallax mapping效果往往看上去太銳化,你可以像我在Rocket Commander游戲中的那樣,用512 512的紋理代替1024 1024的紋理,能避免銳化問題。令人吃驚的是,Rocket Commander游戲包括兩個音道,許多聲音效果,5個小行星模型,五個item模型,火箭模型等,紋理和特殊效果和四個關(guān)卡,只有不到10MB(譯者注:?源文件有60MB,安裝文件16MB)。對Xbox 360再大一點,因為不能播放mp3文件,但它還是很不錯,以少于15 MB大小的支持19201080的分辨率( HDTV ),比大多數(shù)Xbox 360上的商業(yè)游戲看起來更清
20、晰。接下來的章節(jié),本書會繼續(xù)討論如何使用為自定義的三維數(shù)據(jù)使用Normal Mapping效果,使用Normal Map后圖像看起來很棒,而且因為使用了壓縮技術(shù)并沒用占據(jù)太多的紋理空間。7.2Shader如何運行?現(xiàn)在讓我們開始使用寫代碼,先在FX Composer (見第6章介紹)中設(shè)計Shader,這里將使用前一節(jié)圖7-8的小行星的紋理。如果您愿意,您可以按照下面所描述的步驟,象上一章的simple shader一樣編寫自己的Normal Map shader。法線映射是一個相當酷的效果,但微調(diào)要占用大量的時間。你可以給模型的藝術(shù)家留下一些調(diào)整選項,編寫一些不同的Normal Map sh
21、ader以便可以選擇為哪個材質(zhì)使用哪個效果。舉例來說,金屬應(yīng)該和石頭或木材材質(zhì)看起來有很大不同。打開FX Composer 及normalmapping.fx文件,shader文件的布局類似于simpleshader.fx文件,但您可以使用更多的注釋。這本書以后的shader中都使用了類似的文件結(jié)構(gòu)?;疚募季质牵?l 注釋和Shader說明l 矩陣(world,worldviewproj,viewinverse)l 其他的全局變量如時間、測試值等l 材質(zhì)數(shù)據(jù),首先是材質(zhì)的顏色,然后是所有使用的材質(zhì)與采樣器l 頂點結(jié)構(gòu),最重要的是vertexinput結(jié)構(gòu),通常使用你已經(jīng)定義在引擎中的tan
22、gentvertex,通常使用如 /-的注釋行為每個technique分隔數(shù)據(jù)塊。l Vertex Shaderl Pixel Shaderl Technique將shader合在一起,通常使用相同的頂點shader。 為了簡單,我只解釋本書接下來游戲都用到的Normal Mapping 效果的頂點和像素shader,在這本書里被命名為specular20,還有一個Technique被稱為specular,它以同樣的方式工作在Shader Model 1.1,由于Pixel Shader 1.1有8條指令的限制,一些功能被關(guān)閉或減弱。 打開shader文件后請瀏覽一下文件頭和參數(shù),基本結(jié)構(gòu)和上
23、一章的simpleshader.fx是相似的。與上一章vertexinput格式看起來很類似,但它多了切線數(shù)據(jù)。在之前您已經(jīng)遇到了.x和.fbx文件的問題,在這一章中后面將加以解決。假設(shè)現(xiàn)在您有有效的切線數(shù)據(jù)可用于shader。幸運的是FX Composer總能為標準的測試對象(如球,茶壺,立方體等等)給出有效的切線數(shù)據(jù)。/ Vertex input structure (used for ALL techniques here!)struct VertexInput float3 pos : POSITION; float2 texCoord : TEXCOORD0; float3 norm
24、al : NORMAL; float3 tangent : TANGENT;在simpleshader.fx您只需開始編碼,一旦運行正常就無需重構(gòu)Shader的代碼了。聽起自不錯,但你shader寫得越多,您會越想重用代碼。一個方法是直接在shader文件中定義最常用的方法:/ Common functionsfloat4 TransformPosition(float3 pos)/float4 pos) return mul(mul(float4(pos.xyz, 1), world), viewProj); / TransformPosition(.)float3 GetWorldPos(
25、float3 pos) return mul(float4(pos, 1), world).xyz; / GetWorldPos(.)float3 GetCameraPos() return viewInverse3.xyz; / GetCameraPos()float3 CalcNormalVector(float3 nor) return normalize(mul(nor, (float3x3)world); / CalcNormalVector(.)/ Get light directionfloat3 GetLightDir() return lightDir; / GetLight
26、Dir()float3x3 ComputeTangentMatrix(float3 tangent, float3 normal) / Compute the 3x3 tranform from tangent space to object space float3x3 worldToTangentSpace; worldToTangentSpace0 = mul(cross(normal, tangent), world); worldToTangentSpace1 = mul(tangent, world); worldToTangentSpace2 = mul(normal, worl
27、d); return worldToTangentSpace; / ComputeTangentMatrix(.)另一種方式類似于C + +的頭文件,在單獨的fxh文件中儲存方法,參數(shù)和常量。我不喜歡這種方法,因為FX Composer 只能一次使用一個源文件,在游戲你仍要改變很多代碼。第一個函數(shù)是transformposition,它將頂點shader中的3D頂點位置轉(zhuǎn)化到屏幕。除了無需再合并worldviewproj矩陣,transformposition的工作方式類似于上一章。不過你用一個世界矩陣來代替,但viewproj矩陣是新的。將world矩陣與viewproj矩陣相乘你會再次獲得
28、worldviewproj矩陣,這一步不在代碼而在shader中執(zhí)行是因為這樣做可以節(jié)省你一個的頂點shader指令。將world矩陣從worldviewproj矩陣分離出來能讓你只關(guān)心單個矩陣。Shader 中使用的數(shù)據(jù)越多,花費的時間越長,如果你重復設(shè)置參數(shù)和開始shader將明顯拖慢游戲。只建立Shader一次,然后批量改變數(shù)以千計的物體的世界矩陣要好得多,您可以一次建立一個存儲了20個或更多的世界矩陣的數(shù)組,然后遍歷全部,這項技術(shù)叫instancing,我用在了下面的shooter游戲中以優(yōu)化性能(如果很多對象使用相同的Shader)。在較早版本的Rocket Commander游戲中
29、我也用過,也支持固定功能管道,但要在所有的Shader模型( 1.1,2.0和3.0 )中正常工作代價不菲。不過沒關(guān)系,在優(yōu)化了所以其他Shader后性能很好。其他輔助方法相當簡單,瀏覽后你應(yīng)該很快就能弄懂,除了最后一個,這是用來建立我曾談及的切線空間矩陣的。再次看一下圖7-4和7-5,看看是哪個向量。calculatetangentmatrix在頂點shader引擎中(如所有其他輔助方法),用來計算每個頂點的切線與法線向量。從vertexinput結(jié)構(gòu)可以看出,Binormal向量從叉乘法線和切線向量獲得。您可以用您的右手重建這個矩陣中指是法線向量,食指是切線向量,拇指代表binormal向
30、量,binormal向量是中指和食指的叉乘,因此互成90度夾角。切線空間矩陣對快速將法線和光線的方向從世界空間向轉(zhuǎn)化到切線空間是非常有用的,對Pixel Shader Normal Mapping計算也是必須的。您需要切線空間矩陣的原因是要確保所有向量在同一個空間。這個空間是直接指向多邊形的頂部和方向向上(即z方向),就像法線向量的X和Y描述切線和binormal一樣。使用切線空間是Pixel Shader中最容易和最快的方法,你必須獲得正確的binormal和切線order去構(gòu)建切線空間矩陣。此order和binormal的叉乘也能被轉(zhuǎn)化成左手坐標系。使用單元測試以計算出哪個方式是正確的;您
31、也可以看一下原始版本Rocket Commander游戲(左手系)中的shader,看一看與XNA版本(右手系)的區(qū)別。Vertex shaders和矩陣借助于所有輔助方法,現(xiàn)在應(yīng)該可以很容易地編寫頂點shader了。首先你應(yīng)該定義vertexoutput結(jié)構(gòu)。我這里只解釋的Pixel Shader 2.0版本,因為支持Pixel Shader 1.1版本太復雜,并使用了很多匯編代碼,已超出了本書的范圍。如果你真的想支持的Pixel Shader 1.1,建議你找一本關(guān)于shader的書,以了解更多shader的細節(jié)和shader匯編語言,我推薦Programming Vertex and P
32、ixel Shader,GPU Gems,或Shader X系列。Shader專家Wolfgang Engel參與了上面幾本書的編寫,你可以從這幾本書中學到很多在以后幾年內(nèi)很多專業(yè)人士都會用到的shader技巧。Shader的知識如此之多導致誕生了一個新的程序員職業(yè):shader程序員。 如果你在一個很小的團隊,所有編程必須自己完成,這可能是一個麻煩,你要學習很多而你只有很少的時間,而且技術(shù)的發(fā)展又是如此之快。那就盡量保持簡單,只使用最簡單的Shader Model, XNA不支持固定功能的管道,也不支持Direct3D10的Shader Model 4.0,有些游戲制作人認為不太好,但這樣您
33、可以專注于創(chuàng)造Pixel Shader 2.0 shader(或可能使用的Pixel Shader 3.0)。您的頂點結(jié)構(gòu)需要屏幕上的空間坐標,往往還要紋理坐標,這樣,diffuse和Normal貼圖才可正確使用。請注意,在Pixel Shader 1.1中您必須復制紋理坐標,因為每個紋理頂點的輸入在Pixel shader只能使用一次,這是Pixel Shader 1.1許多問題之一,您也不可以歸一化(normalize)或使用冪(pow),也難以解壓被壓縮的法線貼圖。幸運的是,這里你再也不用去考慮。/ vertex shader output structurestruct VertexO
34、utput_Specular20 float4 pos : POSITION; float2 texCoord : TEXCOORD0; float3 lightVec : TEXCOORD1; float3 viewVec : TEXCOORD2;lightVec和viewVec變量只是幫助Pixel Shader計算得比較簡單一點。照明計算基本上和前一章是一樣的,但這次,你必須計算出切線空間的所有向量,因為比起將所有切線空間向量轉(zhuǎn)化到世界空間,在切線空間中比較容易工作。這是有道理的,因為像素比頂點多很多。通過一個復雜的矩陣運算轉(zhuǎn)換每一個像素會很緩慢,而只轉(zhuǎn)換光線方向和看到的向量所花時間不多
35、??匆幌抡麄€頂點shader代碼。重要的是worldtotangentspace矩陣的使用,它是由前面看到的computetangentmatrix方法計算得來的:/ Vertex shader functionVertexOutput_Specular20 VS_Specular20(VertexInput In) VertexOutput_Specular20 Out = (VertexOutput_Specular20) 0; Out.pos = TransformPosition(In.pos); / We can duplicate texture coordinates for d
36、iffuse and Normal Map / in the Pixel Shader 2.0. Out.texCoord = In.texCoord; / Compute the 3x3 tranform from tangent space to object space float3x3 worldToTangentSpace = ComputeTangentMatrix(In.tangent, In.normal); float3 worldEyePos = GetCameraPos(); float3 worldVertPos = GetWorldPos(In.pos); / Tra
37、nsform light vector and pass it as a color (clamped from 0 to 1) / For ps_2_0 we dont need to clamp from 0 to 1 Out.lightVec = normalize(mul(worldToTangentSpace, GetLightDir(); Out.viewVec = mul(worldToTangentSpace, worldEyePos - worldVertPos); / And pass everything to the pixel shader return Out; /
38、 VS_Specular20(.)支持Pixel Shader和優(yōu)化現(xiàn)在Pixel Shader獲取vertex output并計算出每個像素的光線。首先你必須diffuse和 Normal貼圖的顏色。Diffuse貼圖有RGB值,如果您使用Alpha混合也許還有Alpha值。從壓縮的Normal貼圖獲得法線向量更復雜。如果您還記得以前使用normalmapcompressor壓縮法線貼圖,您大概可以想到,你應(yīng)該交換紅色和Alpha通道而使RGB數(shù)據(jù)有效、作為XYZ向量再次可用。第一步使用了所謂的swizzle從一個紋理或shader register中獲取rgba或xyzw數(shù)據(jù)并改變順序。舉
39、例來說,abgr顛倒了rgba的順序。對于您的情況,您所需要的只是Alpha通道(x)和綠色(y)和藍(z)的通道,所以這里你使用.agb swizzle。然后您使用前面介紹的公式得到浮點型的顏色值,即將向量的值減去0.5再除以0.5 ,這是和先乘以2再減去1是一樣的(因為0.5*2是1)。為解決任何其他的壓縮錯誤,您再次將向量歸一化,需要一條額外的Pixel Shader指示,但它是值得的。/ Pixel Shader functionfloat4 PS_Specular20(VertexOutput_Specular20 In) : COLOR / Grab texture data fl
40、oat4 diffuseTexture = tex2D(diffuseTextureSampler, In.texCoord); float3 normalVector = (2.0 * tex2D(normalTextureSampler, In.texCoord).agb) - 1.0; / Normalize normal to fix blocky errors normalVector = normalize(normalVector); / Additionally normalize the vectors float3 lightVector = In.lightVec;/no
41、t needed: normalize(In.lightVec); float3 viewVector = normalize(In.viewVec); / For ps_2_0 we dont need to unpack the vectors to -1 - 1 / Compute the angle to the light float bump = saturate(dot(normalVector, lightVector); / Specular factor float3 reflect = normalize(2 * bump * normalVector - lightVe
42、ctor); float spec = pow(saturate(dot(reflect, viewVector), shininess); /return spec; float4 ambDiffColor = ambientColor + bump * diffuseColor; return diffuseTexture * ambDiffColor + bump * spec * specularColor * diffuseTexture.a; / PS_Specular20(.)通過normal vector (仍然在切線空間),現(xiàn)在您可以計算所有的照明。光線向量和view向量在v
43、ertexoutput_specular20結(jié)構(gòu)中。光線向量在每一個頂點和像素中是相同的,因為只使用了定向光源,但當靠近渲染的對象時view矢量可能有很大不同。圖7-11再次表明為什么重新歸一化view矢量是很重要的。對Normal 映射更重要,因為你為每個像素計算光線而通過Normal貼圖中的變量,從這個像素到另一個像素向量變化是很大的。 圖7-11你使用和上一章計算diffuse顏色的方法計算bump值。對每一個指向光線的法線您使用較亮的顏色,反之則較暗。法線矢量和光線矢量都在切線空間,這樣基本公式保持不變。您可以測試simpleshader.fx文件中的簡單的燈光效果,然后用Normal
44、映射重新組合,這很酷,因為即使這個shader更復雜,基本的照明計算仍然是簡單的和可改變的。如果你看看下個章節(jié)的Normal Mapping 和parallax mapping,您會看到只有在這您要改動,其余的Normal Mapping shader保持不變。 最后,在將顏色組合在一起前你必須計算鏡面高光的顏色。您還沒有half vector,但你有view vector在切線空間,你知道法線的指向。代碼使用了一個簡化公式:只減從光線向量中減去2倍法線向量生成一個偽歸一化的half vector。在simpleshader.fx頂點shader中做這種計算若放在像素shader中會很占資源,
45、使用上面的簡化方法Normal Mapping shader效果也不錯,half vector是否精確并無大礙。重要的是冪(pow)方法,它產(chǎn)生光澤效果,你可以調(diào)整每一種材質(zhì)的shininess和specularcolor的值,因為它們極大地影響了最終的輸出效果(見圖7-12)。 圖7-12最后把顏色混在一起可能看起來有點奇怪。頭兩行是相當容易理解。首先,您由diffuse顏色值和bump值將環(huán)境光混合在一起,這個操作在Shader中只需一條指令,這也是為什么這樣寫代碼的原因。接著,鏡面高光顏色是乘以高光顏色值,這顯示高光,仍由bump值和diffusecolor Alpha值得到。如果背離光
46、線,bump值確保鏡面高光值會變得較暗,如果使用透明紋理,diffuse color Alpha值可以幫助減弱鏡面高光的值?,F(xiàn)在你必須在FX Composer中得到Normal Mapping Shader,你可以試著改變顏色值或不同的貼圖或參數(shù)。接來來你要學習如何在應(yīng)用程序得到正確的切線數(shù)據(jù)和能力,以及如何輕松地導入模型文件。Shadereffect類 你使用兩章前介紹的shadereffect類來渲染shader。上一章已涵蓋了基礎(chǔ)知識,現(xiàn)在你唯一要做的就是增加更多的參數(shù),而其他功能保持不變(見圖7-13)。你還使用了類似于第五章LineManage類中Render方法去渲染3D數(shù)據(jù)。 圖
47、7-13渲染3D數(shù)據(jù)你不光需要3D幾何數(shù)據(jù)和渲染代碼,還需要材質(zhì)參數(shù),包括材質(zhì)顏色和貼圖。為了更好地管理這些數(shù)據(jù),這里使用一個新的輔助類Material.cs(見圖7-14)儲存所有的材質(zhì)數(shù)據(jù)。 圖7-14Shadereffect的setparameters方法將Material類作為參數(shù),并把它傳遞給Render方法。通過這種方式你能方便地設(shè)置材質(zhì),而無需自己設(shè)置所有的effect參數(shù)。通過新的類你能容易地編寫單元測試,讓上一章的蘋果支持Normal mapping.fx Shader。另外你也能通過加載小行星的diffuse和Normal貼圖來改變小行星的材質(zhì),以測試您的新Material
48、類。 TangentVertex格式在單元測試之前,你還需要VertexInput結(jié)構(gòu)。不像第6章的VertexPositionNormalTexture結(jié)構(gòu),XNA沒有包含切線數(shù)據(jù)的預定義結(jié)構(gòu),你必須自己定義。以下TangentVertex類(見圖7-15)用來定義normalmapping.fx和所有Shader中要用到的VertexInput結(jié)構(gòu)。圖7-15定義結(jié)構(gòu)中的字段并沒有什么特別,只需定義你需要的四種數(shù)據(jù)類型:pos(位置),normal(法線),tangent(切線)和UV texture coordinates(UV紋理坐標):/ / Position/ public Vec
49、tor3 pos;/ / Texture coordinates/ public Vector2 uv;/ / Normal/ public Vector3 normal;/ / Tangent/ public Vector3 tangent;有些頂點緩沖器需要您指定結(jié)構(gòu)大小。在MDX中你可以通過使用Direct3dx或unsafe代碼的sizeof方法實現(xiàn),但在xna中沒這么簡單,你必須自己定義大小。/ / Stride size, in XNA called SizeInBytes./ public static int SizeInBytes get / 4 bytes per floa
50、t: / 3 floats pos, 2 floats uv, 3 floats normal and 3 float tangent. return 4 * (3 + 2 + 3 + 3); / get / StrideSize結(jié)構(gòu)的其余部分是相當簡單的,唯一一個從外部得到的字段是Vertex Declaration,它由自定義代碼生成:#region Generate vertex declaration/ / public static readonly VertexElement VertexElements = GenerateVertexElements();/ / Vertex
51、declaration for vertex buffers./ public static VertexDeclaration VertexDeclaration = new VertexDeclaration(BaseGame.Device, VertexElements);/ / Generate vertex declaration/ private static VertexElement GenerateVertexElements() VertexElement decl = new VertexElement / Construct new vertex declaration
52、 with tangent info / First the normal stuff (we should already have that) new VertexElement(0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0), new VertexElement(0, 12, VertexElementFormat.Vector2, VertexElementMethod.Default, VertexElementUsage.TextureCo
53、ordinate, 0), new VertexElement(0, 20, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Normal, 0), / And now the tangent new VertexElement(0, 32, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Tangent, 0), ; return decl; / GenerateVertexElem
54、ents()VertexElement使用下列參數(shù)按順序定義了3D數(shù)據(jù)的聲明:l Stream(第一個參數(shù)):通常設(shè)為0,如果您有多個頂點緩沖流才需另外設(shè)置,這挺復雜。l Offset(第二個參數(shù)):從流開始算起的偏移量(以字節(jié)為單位)。計算離結(jié)構(gòu)起點有多少字節(jié),浮點數(shù)、整數(shù)和dwords占用4個字節(jié)。l 頂點元素格式(第三個參數(shù)):定義使用哪種類型的數(shù)據(jù),和Shader中的VertexInput使用相同的名稱。通常使用vector2,vector3,vector4。整數(shù)或浮點數(shù)類型,通常只用于蒙皮和骨骼動畫。l 頂點單元方法:使用默認值。也允許UV和Lookup,但不是經(jīng)常用到。l 頂點元素
55、usage:數(shù)據(jù)類型如何使用?與你定義的Shader語義類似。你應(yīng)該始終設(shè)置使用的數(shù)據(jù)類型,因為如果和Shader中的順序不一樣,數(shù)據(jù)將根據(jù)usage類型重新排序,如果您不定義切線,VertexInput數(shù)據(jù)可能會一團糟,格式不匹配的話XNA會報錯。l 最后,您指定usage索引,不過你可能不需要使用這些數(shù)據(jù),只需把它設(shè)置為0。Normal Mapping單元測試 通常你會先寫單元測試,你已經(jīng)在上一章中有了Shader的單元測試?,F(xiàn)在你需要首先定義您的新的Shader如何工作并弄清楚哪些類是必需的。現(xiàn)在寫Shader單元測試更容易。請注意,你無需在shadereffect中編寫任何測試代碼,因為在device初始化
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025-2030全球桌面排版系統(tǒng)行業(yè)調(diào)研及趨勢分析報告
- 2025-2030全球醫(yī)療設(shè)備安全解決方案行業(yè)調(diào)研及趨勢分析報告
- 2025年全球及中國一次性甲狀腺穿刺器行業(yè)頭部企業(yè)市場占有率及排名調(diào)研報告
- 2025-2030全球亞歷山大變石激光器行業(yè)調(diào)研及趨勢分析報告
- 2025廣州市農(nóng)村集體經(jīng)濟承包合同管理規(guī)定
- 勞務(wù)派遣合同協(xié)議模板范本
- 2025地區(qū)展柜、物料定作布展合同
- 個人連帶擔保合同
- 房屋場地租賃合同
- 砌筑勞務(wù)分包合同范本
- 《中國古代寓言》導讀(課件)2023-2024學年統(tǒng)編版語文三年級下冊
- 五年級上冊計算題大全1000題帶答案
- 工程建設(shè)行業(yè)標準內(nèi)置保溫現(xiàn)澆混凝土復合剪力墻技術(shù)規(guī)程
- 液壓動力元件-柱塞泵課件講解
- 人教版五年級上冊數(shù)學脫式計算100題及答案
- 屋面細石混凝土保護層施工方案及方法
- 2024年1月山西省高三年級適應(yīng)性調(diào)研測試(一模)理科綜合試卷(含答案)
- 110kv各類型變壓器的計算單
- 5A+Chapter+1+Changes+at+home+課件(新思維小學英語)
- 安徽省2023年中考數(shù)學試卷(附答案)
- 護工(陪護)培訓教材(完整版)資料
評論
0/150
提交評論