星际2的一些技术特性
生活随笔
收集整理的這篇文章主要介紹了
星际2的一些技术特性
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
原文鏈接:http://ati.amd.com/developer/SIGGRAPH08/Chapter05-Filion-StarCraftII.pdf
我們的引擎需要處理兩種截然不同的游戲場景,一種是普通的戰略模式,而另一種則是劇情模式。在戰略模式下,相機通常都高高在上,俯視全局,玩家所關注的主要是整體策略,而不是游戲的細枝末梢,絕大部分的游戲物件在屏幕都只是覆蓋了少量的像素,所以游戲物件可以只使用很少的頂點數量,便可達到理想的畫面效果。而劇情模式則不同,玩家需要從第一人稱模式下來觀察游戲世界,更加身臨其境,能更多的注意到場景的細節,這樣我們就需要更加精細的美術資源來增強玩家的體驗。從技術上來說,這兩種模式有著截然不同的性質,比如戰略模式的渲染,需要繪制很多次才能完成一個畫面(看到的游戲物件實在太多),但每個單一游戲物件都不要很精細;而劇情模式下,場景所需要的繪制次數很少,但每個游戲物件都需要仔細渲染,因為玩家能在近距離觀察到它們。接下來將闡述如何在技術上實現這些要求。
基于屏幕的特效 星際2圖形引擎設計的一個很重要的目標就是要能在劇情模式下體現出復雜的光照環境,現在我們回想一下魔獸爭霸3吧,任意時刻一個物體只能受及其有限的燈光影響,這導致了在切換影響物體燈光的時候,物體的光照效果會有明顯的突變,因此在魔獸爭霸3很少使用動態光源。而且使用傳統的3D渲染方法會極大的提高場景的繪制次數,試想一下場景中有一隊星艦,每個星艦上都有很多閃爍的燈光,這些燈光會影響星際自身以及其周圍的其他艦艇,在這種情況下,星艦不得不一艘一艘的渲染,因為每艘星艦的燈光環境都不一樣,使得GPU效率非常低下。因為我們的分塊地形是通過復雜的方法將多層地貌混合而成,傳統的繪制方式也會給地形系統的渲染帶來嚴重問題。
而解決以上問題的方法,最好就是延遲著色(deferred ?shading),其原理就是先將所有物體先光柵化成像素,然后將每個像素的深度值、法線和一些與光照無關的顏色緩沖起來,等待后續進行像素光照著色。你可能會說使用這種技術的優勢還很難說,畢竟也帶來很多的負面問題,比如緩沖這么多數據是要消耗很多顯存和帶寬的,另外還要增加很多次緩沖采樣,是的,你說的都沒錯,但這項技術給我們帶來的最大好處就是讓圖形計算量與場景復雜性從原來的指數關系變為線性關系,也是說不管我們給畫面加什么樣的后期特效,其消耗都是固定的,與場景復雜度無關,不管場景中有500個還是5個物件,在特效處理中的負擔都差不多,因為所有特效都是針對像素而不是物件的。
在RTS游戲中保持低的繪制次數相當的重要,因此我們希望能在一次繪制中講盡可能多的信息緩沖到顯存中,大多數硬件支持的MRT數量為4,每個RT通道數量為4,這樣我們就有16個通道來存儲我們需要的信息,星際2種我們是這樣使用這些通道的: 1。不受燈光影響的顏色分量,比如自發光、環境貼圖和光照貼圖(環境光照顏色)。 2。深度信息 3。像素法線 4。如果使用靜態環境遮擋,則保存每個像素的環境遮擋值,如果使用屏幕空間的環境遮擋,那么預生成的環境這樣貼圖就忽略掉了。 5。漫反射材質 6。鏡面反射材質 需要提醒一下的是,DX9下MRTS的尺寸和位深必須都相同,當然一部分硬件支持MRT的獨立寫功能,我們也會利用這些特性來盡可能避免那些沒有用到的BIT來占用帶寬。在星際2中我們使用了HDR效果,這樣所有緩沖的4個通道必須是16位浮點格式,當然使用高精度格式的數據能很好的避免精度問題,而且象素著色器也用不著對數據進行解碼了,但很不幸的是,每個緩沖都必須使用4*16的格式,這樣我們每個象素的輸出帶寬就增加到24字節了(可能作者沒有考慮Specular項),但馬上我們就要覺得這樣的犧牲對于它帶來的靈活性是完全值得的。
一般渲染的物體都是不透明的,延遲著色的最大問題在于透明的處理,后面我們會講到如何解決這個問題。我們的地形是多層的,各層的法線,漫反射和高光都是混合到緩沖的,但只有地形的最底層渲染時會寫深度值。緩沖起來的各種值被用來實現各種各樣的特效,比如深度值用在了光照,體積霧,動態環境光遮擋,智能位移,景深,投影器,邊緣檢測和厚度測量;法線用在動態環境光遮擋計算中;漫反射材質和高光材質用來計算光照。
延遲著色
星際2中只有局部燈光才使用延遲著色,如具有一定影響范圍的點光源和聚光燈,一般全場景光照使用傳統的方式先進行渲染,因為全場景光(比如日光)會照射到所有模型上,這樣使用延遲著色的話沒有太多好處,實際上,因為需要再次對緩沖進行采樣,延遲著色的效率在這種情況下反而更低。 傳統著色和延遲著色效果其實都是一樣的,只不過延遲著色將光照作為一個后處理特效來進行,這樣對于復雜光照環境,延遲著色擁有更高的效率,因為使用延遲著色的話,光照計算他所影響到的象素上進行,而且在SM3.0中能更加高效的取得象素的3D空間坐標,因為PS3.0中新加入一個寄存器,光柵單元用來向里填充本象素在緩沖中的x,y坐標,這樣我們能很快的通過象素的Z值求出這個象素的相機空間坐標: float2 vViewPos.xy = float2( x, y ) * float2( 2.0f, -2.0f ) / float2( w, h ) + float2( -1.0f, 1.0f ); vViewPos.zw = float2( 1.0f, 1.0f ); vViewPos.xyz = vViewPos.xyz * fSampledDepth; float3 vWorldPos = mul( p_mInvViewTransform, vViewPos ).xyz; (我覺得原文可能是錯的,如果有朋友看出我的錯誤,請馬上指正,部分項與原文對照如下) INTERPOLANT_VPOS = float2( x, y ) p_vCameraNearSize = 1.0f p_vRecipRenderTargetSize = float2( w, h )
模板測試,Early-Z和Early-Stencil 我們需要一個相當高效的方法來找出屏幕上屬于某一燈光影響范圍的象素,很自然我們想到了Z TEST 和STENCIL TEST,可以用STENCIL TEST將光照范圍后面的象素給剔除掉,用Z TEST將 光照范圍前面的象素剔除掉。原文并沒有詳細的說明如何做到這點,我根據自己對DEFERRED SHADING和SHADOW VOLUME的了解,估計他應該是按如下方法做的: 1。首先看下圖2-0,用3個不同顏色的矩形表示3個不同的場景物體,黃圈表示燈光照射范圍,綠色物體在光源照射范圍的前面,不受燈光影響,紅色位于燈光照射范圍之內,是受影響的,深藍色的物體位于光照范圍之后,也不受影響。 2。首先讓所有場景渲染到相關的緩沖中,建立起Z,NORMAL,COLOR等數據。 3。For 所有 Light a:關閉Color Write,Z Write. 設置Stencil測試總是成功,設置D3DRS_STENCILZFAIL為D3DSTENCILOP_INCR,設置Z為 D3DCMP_LESS,繪制光照閉合凸體的backface,這樣就能在模板中標出所有位于凸體背面之前的象素,如圖2-1 b:正式進行光照著色,設置Stencil測試為D3DCMP_EQUAL,REF值為1,Z測試為D3DCMP_LESS,繪制光照閉合凸體的Frontface,此時early stencil和early z就開始發揮作用了,首先early z會將所有位于燈光照射范圍之前的所有象素剔除掉,留下的結果如圖2-2中黃色線圈中的部分;early stencil則會將后面深藍色物體的所有象素剔除掉,如圖2-3中黃線圍成的范圍內象素,只留下a步驟中生成在stencil buffer中的紅色部分象素范圍中的象素,這最后留下的象素才會正式進入象素著色器,進行光照計算。 以上闡述的都是相機在光照范圍之外時的算法,當相機在某個燈光照射范圍內的話,只需要簡單繪制包圍體的backface就OK了。暴雪放了一張復雜光源的圖如下,可以想象下如果使用傳統方法渲染,我們的shader和光照范圍判斷會有多復雜.
SSAO屏幕空間內的環境光遮擋 這東西很久以前就有論文,只不過最近讓CRYSIS發揚光大,一炮走紅,其作用就是讓場景明暗更柔和些(其實是錯誤的),給人一種有全局光照的錯覺。大概做法是這樣的,按特定方法采樣屏幕中指定象素周圍的指定象素點的深度值,然后用特定方法對采樣結果進行估算,得到一個遮擋值,最關鍵的地方就是如何采樣,如何評估采樣值。不過先順便說下,SSAO有著先天的不足,因為采樣的點都是可見SURFACE上的,那么就意味著不能正常評估不可見SURFACE產生的遮擋影響,但因為AO表現出來的就是低頻特性,所以這個缺陷對最終效果影響不大。 怎樣進行采樣最好? 我相信很多人都自己實現過一些AO,但最終效果都不如人意,比如明暗顆粒感太重,即使進行了BLUR也無法滿足我們對美的欲望,現在機會來了,讓我看看星際大概是怎么做的吧。首先我們必須提一下3D空間中AO MAP的計算,其原理是對物體表面法線正方向的半球空間進行若干光線跟蹤,對各跟蹤結果進行取權計算,為了在SSAO中得到一個與其近似的效果,我們采用同樣方法,先計算出給定pixel的視空間坐標(前面有講到),然后以此坐標為基點,在周圍選擇8~32個點進行采樣,然后將采樣點的相機空間坐標投影回屏幕坐標,對深度緩沖進行采樣,最后得到采樣點的深度值,再進行后續計算。最大的問題是如何選擇采樣點,選擇得不得法會導致最后的AO圖噪點嚴重,為了盡量避免缺陷,星際2中采用了隨機采樣方式,先生成一砣隨機向量,并存儲在紋理中,注意隨機向量的個數并不一定要與象素數量相等,在生成AO圖時,在象素著色器中對此紋理采樣,會得到一個經過插值的隨機法向量,我在通過PS 常量寄存器器傳入X(8~32)個隨機向量,再使用前面得到的向量對這X個向量進行反射,這樣我們就得到了X個偽隨機向量了,傳入的X個向量的模在0.5~1之間,而不是0~1,是為了防止采樣點過于集中在測試點附近,而且這X個向量的模受一個可以由美工調節的變量進行縮放,這樣美工就可以控制采樣范圍了。
可能現在你很多疑問,為什么要從外界傳入X個隨機向量,而不在PS中產生?為什么X個向量要用一個預生成的隨機向量進行反射?為什么這個用來鏡象的向量不是象素法線,而要額外隨機生成?有很多困惑,折磨著我們,讓我們寢食難安,但很遺憾,原文并沒有顯式的進行解釋,而馬上我就要對這些奇怪的做法做出非官方的揣測,如有不滿盡可指正。
為什么不直接在PS中產生隨機向量? AO的隨機是有2個硬性要求的,第一點,每個象素的采樣點必須都是互相隨機,互不相同的。因為每個象素點在3D空間中的位置都互不相同,要做到隨機,必須對每一個測試點的采樣位置都不一樣才能最大的減少最后形成的程序化噪聲,讓顆粒盡可能分散在整個屏幕上,而不要過分集中;第二點,同一象素在不同幀中必須有相同的采樣點,這點就很顯然了,否則會導致場景沒有變化,畫面卻還明暗閃爍不停。根據以上兩點,在PS中隨機生成向量來采樣是不可能的,或者是實現起來效率低下特別復雜。
為什么X個向量要用一個預生成的隨機向量進行反射? 這個我覺得意圖很明顯,就是為了滿足以上提到的第一個要求,讓每個象素的采樣點都互相隨機,否則每個象素都使用相同的采樣模式,又會產生噪聲聚集的情況。星際2使用的方法是用一個隨機向量(從隨機紋理中取出),對其他傳人向量進行反射來達到這個目的,很顯然反射計算量很小,而且隨機效果很好,當然你也可以把傳入的向量與隨機向量進行加乘減等任意操作,只要能隨機化就行。
為什么這個用來鏡象的向量不是象素法線,而要額外隨機生成? 這個我就不太有把握了,但其實在采樣中,法線是有很大作用的,就是對穿到物體內部的隨機采樣向量進行反向,因為采樣需要在法線正方向半球內進行,采到物體內部是絕對錯誤的。可能使用法線來打亂每個象素的采樣向量,隨機度還不夠吧。
如何對采樣得到的深度值進行評估? 好了,現在我們知道大概如何進行采樣了,接下來再看最后一個關鍵點,采樣評估。按常理,離測試點近的采樣點顯然對測試點遮擋得更多,實際上遮擋與距離的平方成反比,但為了讓評估更具隨意性,我們讓美工來控制遮擋系數與距離的關系,但無論如何,這個關系有幾個不可違背的特性: 1。如果采樣點的深度大于測試點的深度,那么這個采樣點給予測試點的遮擋為0,因為測試點在采樣點的后方了。 2。距離越近,遮擋越多。 3。當距離大到一定程度時,遮擋要降為0。
遮擋函數的曲線,大概就如下圖所示,我們可以把這個函數做成一個1維紋理,在PS中使用。
我們還可以進一步對AO MAP 進行優化,如利用高斯模糊進一步消除顆粒感,但這個高斯模糊需要做些特殊處理,因為不能簡單的把黑的白的到處揉擦,AO MAP的明暗是有空間關系的,比如桌子上的暗絕對不能BLUR到旁邊站著的人的身上,因為壓根他們空間位置前后距離很遠,沒什么關系,所以我們BLUR的時候會取采樣點和目標點的深度很法線測試下,如果距離太遠或者兩點法線夾角太大那么采樣點的權重就要變0,最后高斯模糊總權重要重新計算,以保證能正確的對結果歸一化。
最后還有點頭痛的問題需要解決。因為采樣向量是在相機空間中定義的,那就意味著當相機走近物體時,向量在屏幕上的投影會變長,一旦采樣點延伸到屏幕之外那就完蛋了,因為屏幕之外的深度我們壓根就沒有。渲染一個比顯示更大的區域很顯然不能很好的解決問題,比較簡單的解決方案是,如果采樣到屏幕之外就返回一個巨大的深度值,這樣能保證這個采樣點不會對測試點產生任何影響,我們可以通過使用紋理采樣的BORD模式達到這個目的。
為了防止當過度靠近物體,破壞SSAO效果,我們必須在SSAO屏幕空間中限制采樣范圍,如果相機距離物體太近,那么它的SSAO采樣點延伸太遠,SSAO區域一致性約束被違反,這樣讓噪聲不至于太明顯。另外還有一個解決方法就是根據采樣區域大小來決定采樣數量,但會嚴重影響幀率,放棄。 (SSAO area consistency constraint is violated確實是我沒能想明白到底是怎么回事,我就照字翻了,我的理解是這樣的,SSAO ?area 應該為影響指定象素AO的空間區域,這個區域在你走近物體時,在3D空間中的體積是基本保持不變的,但如果你走得特別近了,這個區域的投影已經超出屏幕范圍,現在就必須violate這個SSAO area的consistency,比如對采樣向量進行縮小,讓采樣點回到屏幕空間中。MGD,還是懂的人來解釋下吧) SSAO性能分析 SSAO最大的性能瓶頸在于采樣,隨機的采樣會嚴重破壞了GPU紋理緩沖系統的連續性,而且采樣的紋理區域大小也直接影響紋理緩沖的性能,因此我們可以只使用1/4尺寸的深度緩沖來提高性能。如果采樣區域變大,那么犄角旮旯里的黑暗部分會變得更加柔和,現在我們就遇到了兩難的問題,美術既需要在場景中的旮旯明暗對比強烈,又需要平坦部分擁有大范圍采樣的柔和效果。為了達到這個要求,我們將SSAO采樣點分成2組,一組在小范圍內采樣,使用變化劇烈的深度-遮擋函數,另一組使用大范圍采樣,使用比較平坦的深度-遮擋函數,2組采樣各自計算遮擋因子,最終我們使用遮擋比較大的那個。
景深效果
其實在Shawn Hargreaves的PPT中提到過最終的解決方案應該是depth peeling來實現順序無關的alpha混合,不過據說效率很“驚人”,目前來說也就算了,但不排除N年后GPU更快了再拿出來用哦,原理類似的還有woo shadow mapping,相關知識請到GOOGLE搜論文看看。
一些疑問: 雖然后處理引擎是發展趨勢,但也還存在幾個比較麻煩的問題需要解決 1。ALPHA的完美解決方案 2。對于特殊光照材質的支持,比如一個人的頭發,服裝,皮膚肯定是采用不同的光照方法渲染的,頭發是各相異性的,服裝是漫反射的,皮膚是帶SSS的,如何知道每個象素采用哪種著色方式是非常重要的,從畫面上開SC2好象沒能很好的解決這個問題,比如蟲族應該是表面看上去濕轆轆的有黏液,人族應該是粗糙鍍層的金屬表面居多,神族物件看上應該是閃閃發亮反光率很高的材質,現在所有的物體看上去象橡皮泥捏的一樣,特別是戰略模式下尤為明顯。
?? ?我一直認為后處理技術將會被越來越多的游戲所重用,星際2的出爐在一定程度上驗證了這點,把光照,陰影都移到后處理中去,這給場景渲染帶來最大的靈活性,當然也帶來了很多難以克服的問題。翻譯這篇文章的主要目的是讓自己熟悉這些技術,并留下一點筆記,順便賞析一下星際2的技術魅力:)。(這片文章的英文敘述方式簡直讓我嘔吐,如果按原文思路來翻譯,只會讓讀者也嘔吐,原諒我改變了原文敘述順序,有偏好原文者請參看英文原版)
最早我們就決定讓GPU來更多的負載畫面效果計算,而讓CPU解放出來,最主要的原因是,在星際2中玩家可以生成和操縱數量巨大的游戲物件,這樣就需要有更多的CPU資源用來計算海量AI和管理龐大的系統資源。GPU主要的負載源于像素著色器,而不是頂點著色器,因為我們的引擎使用盡可能少的繪制次數及頂點數量,而且現代GPU架構對于一次渲染上百萬的頂點簡直就是小菜一碟;相比之下,因為我的游戲使用了延遲著色,像素著色器負擔著幾乎所有的美術效果。使用延遲著色的優勢就在于能使像素重繪率始終保持在一個很低的水平,像素著色器的負載能基本保持恒定不變,而不受場景復雜度的劇烈影響。我們的引擎需要處理兩種截然不同的游戲場景,一種是普通的戰略模式,而另一種則是劇情模式。在戰略模式下,相機通常都高高在上,俯視全局,玩家所關注的主要是整體策略,而不是游戲的細枝末梢,絕大部分的游戲物件在屏幕都只是覆蓋了少量的像素,所以游戲物件可以只使用很少的頂點數量,便可達到理想的畫面效果。而劇情模式則不同,玩家需要從第一人稱模式下來觀察游戲世界,更加身臨其境,能更多的注意到場景的細節,這樣我們就需要更加精細的美術資源來增強玩家的體驗。從技術上來說,這兩種模式有著截然不同的性質,比如戰略模式的渲染,需要繪制很多次才能完成一個畫面(看到的游戲物件實在太多),但每個單一游戲物件都不要很精細;而劇情模式下,場景所需要的繪制次數很少,但每個游戲物件都需要仔細渲染,因為玩家能在近距離觀察到它們。接下來將闡述如何在技術上實現這些要求。
基于屏幕的特效 星際2圖形引擎設計的一個很重要的目標就是要能在劇情模式下體現出復雜的光照環境,現在我們回想一下魔獸爭霸3吧,任意時刻一個物體只能受及其有限的燈光影響,這導致了在切換影響物體燈光的時候,物體的光照效果會有明顯的突變,因此在魔獸爭霸3很少使用動態光源。而且使用傳統的3D渲染方法會極大的提高場景的繪制次數,試想一下場景中有一隊星艦,每個星艦上都有很多閃爍的燈光,這些燈光會影響星際自身以及其周圍的其他艦艇,在這種情況下,星艦不得不一艘一艘的渲染,因為每艘星艦的燈光環境都不一樣,使得GPU效率非常低下。因為我們的分塊地形是通過復雜的方法將多層地貌混合而成,傳統的繪制方式也會給地形系統的渲染帶來嚴重問題。
而解決以上問題的方法,最好就是延遲著色(deferred ?shading),其原理就是先將所有物體先光柵化成像素,然后將每個像素的深度值、法線和一些與光照無關的顏色緩沖起來,等待后續進行像素光照著色。你可能會說使用這種技術的優勢還很難說,畢竟也帶來很多的負面問題,比如緩沖這么多數據是要消耗很多顯存和帶寬的,另外還要增加很多次緩沖采樣,是的,你說的都沒錯,但這項技術給我們帶來的最大好處就是讓圖形計算量與場景復雜性從原來的指數關系變為線性關系,也是說不管我們給畫面加什么樣的后期特效,其消耗都是固定的,與場景復雜度無關,不管場景中有500個還是5個物件,在特效處理中的負擔都差不多,因為所有特效都是針對像素而不是物件的。
在RTS游戲中保持低的繪制次數相當的重要,因此我們希望能在一次繪制中講盡可能多的信息緩沖到顯存中,大多數硬件支持的MRT數量為4,每個RT通道數量為4,這樣我們就有16個通道來存儲我們需要的信息,星際2種我們是這樣使用這些通道的: 1。不受燈光影響的顏色分量,比如自發光、環境貼圖和光照貼圖(環境光照顏色)。 2。深度信息 3。像素法線 4。如果使用靜態環境遮擋,則保存每個像素的環境遮擋值,如果使用屏幕空間的環境遮擋,那么預生成的環境這樣貼圖就忽略掉了。 5。漫反射材質 6。鏡面反射材質 需要提醒一下的是,DX9下MRTS的尺寸和位深必須都相同,當然一部分硬件支持MRT的獨立寫功能,我們也會利用這些特性來盡可能避免那些沒有用到的BIT來占用帶寬。在星際2中我們使用了HDR效果,這樣所有緩沖的4個通道必須是16位浮點格式,當然使用高精度格式的數據能很好的避免精度問題,而且象素著色器也用不著對數據進行解碼了,但很不幸的是,每個緩沖都必須使用4*16的格式,這樣我們每個象素的輸出帶寬就增加到24字節了(可能作者沒有考慮Specular項),但馬上我們就要覺得這樣的犧牲對于它帶來的靈活性是完全值得的。
一般渲染的物體都是不透明的,延遲著色的最大問題在于透明的處理,后面我們會講到如何解決這個問題。我們的地形是多層的,各層的法線,漫反射和高光都是混合到緩沖的,但只有地形的最底層渲染時會寫深度值。緩沖起來的各種值被用來實現各種各樣的特效,比如深度值用在了光照,體積霧,動態環境光遮擋,智能位移,景深,投影器,邊緣檢測和厚度測量;法線用在動態環境光遮擋計算中;漫反射材質和高光材質用來計算光照。
延遲著色
星際2中只有局部燈光才使用延遲著色,如具有一定影響范圍的點光源和聚光燈,一般全場景光照使用傳統的方式先進行渲染,因為全場景光(比如日光)會照射到所有模型上,這樣使用延遲著色的話沒有太多好處,實際上,因為需要再次對緩沖進行采樣,延遲著色的效率在這種情況下反而更低。 傳統著色和延遲著色效果其實都是一樣的,只不過延遲著色將光照作為一個后處理特效來進行,這樣對于復雜光照環境,延遲著色擁有更高的效率,因為使用延遲著色的話,光照計算他所影響到的象素上進行,而且在SM3.0中能更加高效的取得象素的3D空間坐標,因為PS3.0中新加入一個寄存器,光柵單元用來向里填充本象素在緩沖中的x,y坐標,這樣我們能很快的通過象素的Z值求出這個象素的相機空間坐標: float2 vViewPos.xy = float2( x, y ) * float2( 2.0f, -2.0f ) / float2( w, h ) + float2( -1.0f, 1.0f ); vViewPos.zw = float2( 1.0f, 1.0f ); vViewPos.xyz = vViewPos.xyz * fSampledDepth; float3 vWorldPos = mul( p_mInvViewTransform, vViewPos ).xyz; (我覺得原文可能是錯的,如果有朋友看出我的錯誤,請馬上指正,部分項與原文對照如下) INTERPOLANT_VPOS = float2( x, y ) p_vCameraNearSize = 1.0f p_vRecipRenderTargetSize = float2( w, h )
模板測試,Early-Z和Early-Stencil 我們需要一個相當高效的方法來找出屏幕上屬于某一燈光影響范圍的象素,很自然我們想到了Z TEST 和STENCIL TEST,可以用STENCIL TEST將光照范圍后面的象素給剔除掉,用Z TEST將 光照范圍前面的象素剔除掉。原文并沒有詳細的說明如何做到這點,我根據自己對DEFERRED SHADING和SHADOW VOLUME的了解,估計他應該是按如下方法做的: 1。首先看下圖2-0,用3個不同顏色的矩形表示3個不同的場景物體,黃圈表示燈光照射范圍,綠色物體在光源照射范圍的前面,不受燈光影響,紅色位于燈光照射范圍之內,是受影響的,深藍色的物體位于光照范圍之后,也不受影響。 2。首先讓所有場景渲染到相關的緩沖中,建立起Z,NORMAL,COLOR等數據。 3。For 所有 Light a:關閉Color Write,Z Write. 設置Stencil測試總是成功,設置D3DRS_STENCILZFAIL為D3DSTENCILOP_INCR,設置Z為 D3DCMP_LESS,繪制光照閉合凸體的backface,這樣就能在模板中標出所有位于凸體背面之前的象素,如圖2-1 b:正式進行光照著色,設置Stencil測試為D3DCMP_EQUAL,REF值為1,Z測試為D3DCMP_LESS,繪制光照閉合凸體的Frontface,此時early stencil和early z就開始發揮作用了,首先early z會將所有位于燈光照射范圍之前的所有象素剔除掉,留下的結果如圖2-2中黃色線圈中的部分;early stencil則會將后面深藍色物體的所有象素剔除掉,如圖2-3中黃線圍成的范圍內象素,只留下a步驟中生成在stencil buffer中的紅色部分象素范圍中的象素,這最后留下的象素才會正式進入象素著色器,進行光照計算。 以上闡述的都是相機在光照范圍之外時的算法,當相機在某個燈光照射范圍內的話,只需要簡單繪制包圍體的backface就OK了。暴雪放了一張復雜光源的圖如下,可以想象下如果使用傳統方法渲染,我們的shader和光照范圍判斷會有多復雜.
SSAO屏幕空間內的環境光遮擋 這東西很久以前就有論文,只不過最近讓CRYSIS發揚光大,一炮走紅,其作用就是讓場景明暗更柔和些(其實是錯誤的),給人一種有全局光照的錯覺。大概做法是這樣的,按特定方法采樣屏幕中指定象素周圍的指定象素點的深度值,然后用特定方法對采樣結果進行估算,得到一個遮擋值,最關鍵的地方就是如何采樣,如何評估采樣值。不過先順便說下,SSAO有著先天的不足,因為采樣的點都是可見SURFACE上的,那么就意味著不能正常評估不可見SURFACE產生的遮擋影響,但因為AO表現出來的就是低頻特性,所以這個缺陷對最終效果影響不大。 怎樣進行采樣最好? 我相信很多人都自己實現過一些AO,但最終效果都不如人意,比如明暗顆粒感太重,即使進行了BLUR也無法滿足我們對美的欲望,現在機會來了,讓我看看星際大概是怎么做的吧。首先我們必須提一下3D空間中AO MAP的計算,其原理是對物體表面法線正方向的半球空間進行若干光線跟蹤,對各跟蹤結果進行取權計算,為了在SSAO中得到一個與其近似的效果,我們采用同樣方法,先計算出給定pixel的視空間坐標(前面有講到),然后以此坐標為基點,在周圍選擇8~32個點進行采樣,然后將采樣點的相機空間坐標投影回屏幕坐標,對深度緩沖進行采樣,最后得到采樣點的深度值,再進行后續計算。最大的問題是如何選擇采樣點,選擇得不得法會導致最后的AO圖噪點嚴重,為了盡量避免缺陷,星際2中采用了隨機采樣方式,先生成一砣隨機向量,并存儲在紋理中,注意隨機向量的個數并不一定要與象素數量相等,在生成AO圖時,在象素著色器中對此紋理采樣,會得到一個經過插值的隨機法向量,我在通過PS 常量寄存器器傳入X(8~32)個隨機向量,再使用前面得到的向量對這X個向量進行反射,這樣我們就得到了X個偽隨機向量了,傳入的X個向量的模在0.5~1之間,而不是0~1,是為了防止采樣點過于集中在測試點附近,而且這X個向量的模受一個可以由美工調節的變量進行縮放,這樣美工就可以控制采樣范圍了。
可能現在你很多疑問,為什么要從外界傳入X個隨機向量,而不在PS中產生?為什么X個向量要用一個預生成的隨機向量進行反射?為什么這個用來鏡象的向量不是象素法線,而要額外隨機生成?有很多困惑,折磨著我們,讓我們寢食難安,但很遺憾,原文并沒有顯式的進行解釋,而馬上我就要對這些奇怪的做法做出非官方的揣測,如有不滿盡可指正。
為什么不直接在PS中產生隨機向量? AO的隨機是有2個硬性要求的,第一點,每個象素的采樣點必須都是互相隨機,互不相同的。因為每個象素點在3D空間中的位置都互不相同,要做到隨機,必須對每一個測試點的采樣位置都不一樣才能最大的減少最后形成的程序化噪聲,讓顆粒盡可能分散在整個屏幕上,而不要過分集中;第二點,同一象素在不同幀中必須有相同的采樣點,這點就很顯然了,否則會導致場景沒有變化,畫面卻還明暗閃爍不停。根據以上兩點,在PS中隨機生成向量來采樣是不可能的,或者是實現起來效率低下特別復雜。
為什么X個向量要用一個預生成的隨機向量進行反射? 這個我覺得意圖很明顯,就是為了滿足以上提到的第一個要求,讓每個象素的采樣點都互相隨機,否則每個象素都使用相同的采樣模式,又會產生噪聲聚集的情況。星際2使用的方法是用一個隨機向量(從隨機紋理中取出),對其他傳人向量進行反射來達到這個目的,很顯然反射計算量很小,而且隨機效果很好,當然你也可以把傳入的向量與隨機向量進行加乘減等任意操作,只要能隨機化就行。
為什么這個用來鏡象的向量不是象素法線,而要額外隨機生成? 這個我就不太有把握了,但其實在采樣中,法線是有很大作用的,就是對穿到物體內部的隨機采樣向量進行反向,因為采樣需要在法線正方向半球內進行,采到物體內部是絕對錯誤的。可能使用法線來打亂每個象素的采樣向量,隨機度還不夠吧。
如何對采樣得到的深度值進行評估? 好了,現在我們知道大概如何進行采樣了,接下來再看最后一個關鍵點,采樣評估。按常理,離測試點近的采樣點顯然對測試點遮擋得更多,實際上遮擋與距離的平方成反比,但為了讓評估更具隨意性,我們讓美工來控制遮擋系數與距離的關系,但無論如何,這個關系有幾個不可違背的特性: 1。如果采樣點的深度大于測試點的深度,那么這個采樣點給予測試點的遮擋為0,因為測試點在采樣點的后方了。 2。距離越近,遮擋越多。 3。當距離大到一定程度時,遮擋要降為0。
遮擋函數的曲線,大概就如下圖所示,我們可以把這個函數做成一個1維紋理,在PS中使用。
我們還可以進一步對AO MAP 進行優化,如利用高斯模糊進一步消除顆粒感,但這個高斯模糊需要做些特殊處理,因為不能簡單的把黑的白的到處揉擦,AO MAP的明暗是有空間關系的,比如桌子上的暗絕對不能BLUR到旁邊站著的人的身上,因為壓根他們空間位置前后距離很遠,沒什么關系,所以我們BLUR的時候會取采樣點和目標點的深度很法線測試下,如果距離太遠或者兩點法線夾角太大那么采樣點的權重就要變0,最后高斯模糊總權重要重新計算,以保證能正確的對結果歸一化。
最后還有點頭痛的問題需要解決。因為采樣向量是在相機空間中定義的,那就意味著當相機走近物體時,向量在屏幕上的投影會變長,一旦采樣點延伸到屏幕之外那就完蛋了,因為屏幕之外的深度我們壓根就沒有。渲染一個比顯示更大的區域很顯然不能很好的解決問題,比較簡單的解決方案是,如果采樣到屏幕之外就返回一個巨大的深度值,這樣能保證這個采樣點不會對測試點產生任何影響,我們可以通過使用紋理采樣的BORD模式達到這個目的。
為了防止當過度靠近物體,破壞SSAO效果,我們必須在SSAO屏幕空間中限制采樣范圍,如果相機距離物體太近,那么它的SSAO采樣點延伸太遠,SSAO區域一致性約束被違反,這樣讓噪聲不至于太明顯。另外還有一個解決方法就是根據采樣區域大小來決定采樣數量,但會嚴重影響幀率,放棄。 (SSAO area consistency constraint is violated確實是我沒能想明白到底是怎么回事,我就照字翻了,我的理解是這樣的,SSAO ?area 應該為影響指定象素AO的空間區域,這個區域在你走近物體時,在3D空間中的體積是基本保持不變的,但如果你走得特別近了,這個區域的投影已經超出屏幕范圍,現在就必須violate這個SSAO area的consistency,比如對采樣向量進行縮小,讓采樣點回到屏幕空間中。MGD,還是懂的人來解釋下吧) SSAO性能分析 SSAO最大的性能瓶頸在于采樣,隨機的采樣會嚴重破壞了GPU紋理緩沖系統的連續性,而且采樣的紋理區域大小也直接影響紋理緩沖的性能,因此我們可以只使用1/4尺寸的深度緩沖來提高性能。如果采樣區域變大,那么犄角旮旯里的黑暗部分會變得更加柔和,現在我們就遇到了兩難的問題,美術既需要在場景中的旮旯明暗對比強烈,又需要平坦部分擁有大范圍采樣的柔和效果。為了達到這個要求,我們將SSAO采樣點分成2組,一組在小范圍內采樣,使用變化劇烈的深度-遮擋函數,另一組使用大范圍采樣,使用比較平坦的深度-遮擋函數,2組采樣各自計算遮擋因子,最終我們使用遮擋比較大的那個。
景深效果
?? ?在延遲著色中,每幀都需要產生深度值緩沖和法線緩沖,既然產生了我們就要有效的加以利用,比如在我們的劇情模式下用得特別頻繁的景深特效。接下來我們將討論在實現景深效果過程中所碰到的問題以及如何解決它們.
其實在Shawn Hargreaves的PPT中提到過最終的解決方案應該是depth peeling來實現順序無關的alpha混合,不過據說效率很“驚人”,目前來說也就算了,但不排除N年后GPU更快了再拿出來用哦,原理類似的還有woo shadow mapping,相關知識請到GOOGLE搜論文看看。
一些疑問: 雖然后處理引擎是發展趨勢,但也還存在幾個比較麻煩的問題需要解決 1。ALPHA的完美解決方案 2。對于特殊光照材質的支持,比如一個人的頭發,服裝,皮膚肯定是采用不同的光照方法渲染的,頭發是各相異性的,服裝是漫反射的,皮膚是帶SSS的,如何知道每個象素采用哪種著色方式是非常重要的,從畫面上開SC2好象沒能很好的解決這個問題,比如蟲族應該是表面看上去濕轆轆的有黏液,人族應該是粗糙鍍層的金屬表面居多,神族物件看上應該是閃閃發亮反光率很高的材質,現在所有的物體看上去象橡皮泥捏的一樣,特別是戰略模式下尤為明顯。
3。還有一些雜碎,比如反射,陰影等。
(機器問題,圖片貼不上,隨后再補)
通過技術分析,得到一個結論,如果效果全開,星際2一定是相當的費機器,想買電腦的朋友,可以等等看
轉載于:https://www.cnblogs.com/effulgent/archive/2008/12/08/1350332.html
總結
以上是生活随笔為你收集整理的星际2的一些技术特性的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: asp.net控件开发基础(1)
- 下一篇: [原]请留心asp:Image控件中的I