1. 程式人生 > >CryEngine3渲染引擎剖析

CryEngine3渲染引擎剖析

這個帖可能在這兒發比較奇怪,不過我是一個信仰黑客精神的程式設計師,也非常支援KlayGE的研發,希望發一些我的原創資料,和作者,以及KlayGE的作用者交流,甚至有一些麻煩的問題,也希望作者可以解答,如果KlayGE的研發能夠涉及到這些東西,那就最好了。
作為一個剛從業不久的引擎開發人員,為了能快速有效地提高自己引擎的渲染質量,使用了各種辦法來解析Cryengine的渲染手法。在此我將以專業的視角來與您分享我的經驗和成果。如果您也是專業的圖形程式設計師,希望與您一起討論,解讀這款令人驚歎的引擎,如果您是一個剛剛入門的新人或者愛好者,這將成為您不可多得的原創中文資料。
Cryengine是目前最難窺探的引擎沒有之一,比起在中國氾濫的虛幻和GB的原始碼,Cryengine也顯得神祕得多,很少有人說自己有這款引擎,哪怕只有一個Eval。雖然有教育免費版,但是據我所知,也只有北大才申請到了授權。花了500W左右買了授權的好像也只有暢遊和久遊。但是越是如此,這款引擎的魅力越讓人無法抗拒。當我有PerfHUD,PIX這樣的分析工具時,我如何能不想著去拆解這個神祕又神奇的引擎呢。


Crysis所伴隨的往往是最高畫質的讚美和硬體殺手的批評,但是,我覺得即使這樣,Cryengine仍然可以稱為當今世界上優化最好,負載最大的引擎。其實引擎的設計追求的主要是負載能力,追求畫面的應該是遊戲。但是反過來,擁有最大的畫面質量,沒有引擎的強大負載,肯定是做不到的。任何引擎可以被美術用成硬體殺手,但是能在同樣的情況下,跑出Crysis那樣的畫面的引擎肯定有著強大的負載能力。
Cryengine優化的出彩之處主要有以下幾個方面:
1材質排序:從PerfHUD的結果來看,Cryengine對DXAPI的呼叫是最為簡潔的,如此多的材質,卻只有如此簡潔的狀態切換過程,不能不令人讚歎,相比之下,OGRE或者GB之類的三流引擎做得就要差得多。材質排序已經被做到了極至,從這裡省下來的時間,成為了Crysis如此複雜的巨集大場景的基礎。

2技術選擇:這是我最佩服Crytek的一點,如此多的次世代渲染技術,竟然每個都如此地和諧,兼顧著效能與效果。我研究了它的好多渲染手法,真是深有感觸,為啥能如此恰當地選擇技術呢?後來看了它們LPV的一篇Paper中有這樣一個預算 

這從恍然大悟。原來他們竟如此專業,預先做了這樣的評估,難怪技術都被優化得如此高效,和諧。
3.瑕疵優化:這個通常被人忽略,或者被人認為是錯的。很多人都覺得寧願速度慢一點,也要求技術沒有瑕疵。其實,這是不對的。瑕不掩瑜,在Crysis如此震撼的效果面前,有幾個會對它技術的瑕疵非常關注,覺得不能忍受呢?但是在Cryengine中,所有的瑕疵都換來了寶貴的時間,以至它能對一個遊戲新增如此多的渲染技術,以達到Crysis的效果。


有了這些與眾不同,使Cryengine變得如此另類,以及怪物般的負載能力。當然有人要說,Cryengine不是最快的,因為相同速度的情況下,虛幻的畫面可能更好。對,確實,虛幻的Irradiance技術提供了一個廉價的GI效果,但是,這個東西帶來的限制卻讓虛幻完全沒有能力大幅度改變場景光照,因為主光源是預先渲染好的。這個東西在Cryengine3中已經被支援了,同時候還有了LPV這個神奇的動態GI。這樣說的話,Crysis所追求的全動態場景的理念其實也是逼真臨場體驗的一部分,當然需要更多的效能開銷了。也就是因為Crysis有晝夜變化,才帶來了這種前所未有的臨場他體驗。
接下來,我要對Crysis所使用的渲染技術進行一些細緻的剖析,當然也帶著一些不理解的問題,希望大牛們能給我一些建議和幫助。

Crysis是用Cryengine2製作的,Cryengine3無幸窺見,在這裡,先說說確切的Cryengine2的渲染過程。
眾所周知Cryengine2,沒有使用DeferredShading,所以無法支援太多的光源,主要渲染圍繞著陽光進行,而且使用了非常複雜的PixelShader來實現漂亮的材質,所以ZPass預渲染就變得很必要,不然會有很多無用象素被複雜的PixelShader渲染,當然這個和DeferredShading一樣,無法支援Blend,所以只有兩種,普通和AlphaTest。渲染ZPass為了開啟PreZ,肯定要進行排序,先渲染普通物體,後渲染帶AlphaTest(當然是使用Shader的Texkill來進行,沒有狀態切換)的物體。其實標準的ZPass應該是不需要ColorWrite的,但是Crysis利用這個機會,輸出了深度到一張R32F,因為視距為八公里,乘一個0.000125對映到[0,1],天空為2。有了深度的G-Buffer,其實就已經可以做很多事了,除了光照外很多的後處理都可以用這張深度緩衝來進行。有了深度後,會先進行AO計算,然後陰影,這都是螢幕空間的計算,然後渲染每個物體都會對這兩張圖進行取樣。AO是一張RGBA,R通道用來存SSAO的結果,G通道用來存2.5DTerrainAO的結果。然後進行一次Blur。陰影是有個Mask的,平行光一般是R,剩下三個通道,大概可以存放三個點光源或者SpotLight吧。然後就是對一張R16G16B16A16F進行HR的高範圍渲染。這回DepthFunc已經是Equal了,因為深度已經完全填充。當然,為了PreZ,還是先普通後AlphaTest,然後會看到大量的碎片,因為Z檢測會擋掉大量畫素。所有著色畫素加起來也幾乎就是螢幕畫素了,除非有兩個三角形有點是同Depth的Fighting狀態,當然可能性很低。完成後會進行Blend渲染,主要是粒子,玻璃之類的東西。結束後,就要進行HDRToneMap和HDRHighLightBloom了。完成後,接下來有一個EdgeAA,當然除此之外應該還有抗齒過程,只是除錯時肯定是要關掉的。EdgeAA是個抗齒的後處理,只使用Depth來提取邊緣。然後還有個Glow,大概會把火焰之類的Bloom加大吧。在這之後,就是SunShaft,來加上漂亮的Ray和Beam,最後會進行ColorGrading,完成渲染的最後一步,這樣,就能看到Crysis的畫面了。這樣說是不是有些籠統呢?沒關係,如果大家喜歡,我還會繼續深入剖析Cryengine渲染的一些技術點,來解讀震撼畫面背後的故事。今天有點晚了先寫到這兒了。
  睡前再寫一些看了KlayGE後的感想,KlayGE是一款我很喜歡的開源引擎。對於開源引擎來說,沒有強大的資金支援,很難開發出像商業引擎那樣功能強大的實用引擎。KlayGE這樣研究一些新鮮的API,支援OGL3或4,DX11,以及一些好玩的技術的實現,卻是真正有幫助的。它的字型演算法的設計真的是非常的獨到,讓我非常震撼,我正在想有什麼辦法能使縮小時更清晰。像Ogre,Irrlicht那種引擎中既見不到強大的實用性,又沒有這樣的看點,我個人還是比較無愛的。KlayGE最近又出了FFT的水,對於只能看到SigGraph1999的我來說,還是非常有幫助的,記得上回Ogre有個水體外掛,也做了FFT的波動,不過實時CPU刷頂點做法還是有點過了,這了新的Demo看,真的挺興奮的。
有一點想問下作者,你的DeferredShading為啥不支援HW的AA呢,而使用一個後處理來進行?DX10開始,MRT不是已經可以AA了嗎?難道還有什麼障礙?
最後發張我現在自己渲染的圖,雖然比Crysis差不少,但是渲染技術是差不多的。其實如果時間允許,我真是想自己操刀寫個引擎,把Ogre改成這樣真不是一般的麻煩,Ogre的渲染體系太古典了,不太適應現代的技術,搞得我動不動接管過來調DX,不然要麼效能莫名其妙地不見,要麼就是乾脆無法實現。不過因為DX9,使用了DeferredShading後只能用後處理來抗齒,其實可以用超級取樣,但是捨不得那效能啊。Ogre的材質系統不靈活,導致我一怒之下統一使用了線性過濾,材質糊糊的很不爽。下一步,可能就是要嘗試下LPV了,畢竟GI還是很令人Happy的

繼續更新啦,首先談談Cryengine的地形技術。地形技術是Cryengine的一個較為核心的技術,為了實現八公里的超遠視距,地形經過了比較細緻的優化。Cryengine的地形主要使用的資料結構仍然是高度圖,並且在Cryengine2中可以看到,它所支援的尺寸非常有限,好像也不是動態載入技術的無縫大場景。為此為特地下了Crysis的Sandbox一探究竟。Cryengine的地形Lod時並沒有Morph的過渡而是直接突變,這讓我很驚呀,一般地,地形Lod時的突變會非常刺眼以至於讓人難以接受,但是在Crysis中,我卻完全無法意識到這一點,反覆擺弄它的場景後發現,原來是超高密度的植被覆蓋使得地形的跳動完全被植被所遮擋,植被同樣也在不體地突變,所以一般只能感覺到植被Lod時的突變,而無法感覺到地形Lod時的突變。因為不需要Morph,Cryengine地形的靈活性就體現出來了,它可以切到最小隻有2M*2M一個單元,但是越遠,繪製的實際單元還是有所合併,具體LOD的細節仍然沒有完全搞清楚,如果哪位大牛知道,希望能夠不吝地告訴我,不勝感激啊。但是有一點是很清楚,它的LOD是有根據視覺複雜度和距離兩個標準來決定網格精度的,我貼一張Wireframe先: 


可以看到,網格精度並不是均勻地由近到遠遞減的,而是以地塊視覺複雜度為權值的遞減,期間有相當多的補面,以保證沒有T型接縫。不過由於不需要Morph,跨級LOD之間的補面變得相對容易。
除了LOD外,地表材質也是Cryengine的一個比較出眾的特性,Crysis的地表材質細節之豐富,絕對是目前絕無僅有的,但是支援它使用如此多材質的地表細節技術,卻是Cryengine的一個特殊做法帶來的。Cryengine並沒有使用什麼四層混合,而是按單層來劃分的。當一層材質被刷到地形上的時候,Cryengine會生成一個材質的覆蓋範圍,也就是說每一個材質繪製時都有獨立的IB區段,這樣最大的好處是每個層都可以使用獨立的渲染技術,而不會影響其它層,比如有parallax的地形層只有很少的一兩個,但是混在其它層中卻讓地形細節有了整體的提升。還有就是因為地形距離有八公里,所以不可能都使用Blend的Tiling細節,在細節的幾百米範圍之外,就切換成只有一張的預生成大紋理,VirtualTexture技術在這裡得到了應用。在同時使用了Tiling和VirtualTexture的情況下,Cryengine的地形遠近都有很好的細節表現,同時效能上也能夠支撐起八公里的視距。
當然Cryengine的地形技術中還有個神奇的Voxel技術。Voxel其實是個很古老的概念,應用到地形中應該是三角洲的時候。不過那時的Voxel技術不是很適應現在的圖形管線,Cryengine只是使用了那Voxel作為一部分特殊地形的資料儲存,最後用了某種演算法,生成了與高度圖Terrain無縫連線的Mesh,使得懸崖,山洞可以在引擎中用Terrain實現。通常要做這些往往都使用模型,而不同的系統使用起來很容易產生接縫。這就是Crysis地貌如此豐富的原因。
不過Voxel的生成演算法,我還沒有想到,或者看到,很想知道有什麼好辦法來實現這個。不知道龔敏敏大大是否有這方面的辦法,或者有見過關於這個的文獻。如果KlayGE能整合一個類似的演算法,那就最好了。

很希望看到KlayGE的VirtualTexture和GI。目前我也正在整理一些解決方案,有這樣的參考真的很不錯哈。我可能考慮把LightMass和一種實時GI解決方案整合到無縫場景中。
接下來繼續更新
Cryengine的陰影是我最喜歡的一個Cryengine的解決方案,它的科學性,實用性,讓我很震撼。在目前的硬體條件下,Cryengine的陰影系統是一個比較完美的實時陰影解決方案。首先要說明的一點是,Cryengine2雖然不是DeferredShading,但是仍然有深度圖可用,所以可以在螢幕空間計算陰影,這樣能為PCF節省非常多的取樣,與VSM相比,取樣次數會更少。這樣就有了下面的結論:PCF適用於實時性較高的陰影取樣,因為一次取樣的次數較少,而VSM更適用於低頻更新的陰影,因為VSM可以預取樣,取樣完之後就能很快地生成陰影,這樣的話,只要陰影不更新,VSM就不需要再取樣。有了以上的思想,就有了Cryengine的陰影解決方案。首先用四張1024大的D24S8作為PSSM的四層,據我目測,PSSM的距離大概在200-300之間,由於遠處的物件通常是在較濃的霧裡,所以,其實遠處陰影對畫面的增益會較弱,近的陰影距離讓Cryengine的四層1024圖都獲得了相當高的陰影清晰度。這四層陰影也並非實時更新,Cryengine對這陰影進行了控頻,不過遊戲中並未感覺到,只是Cryengine3在GDC2009的那段視訊中,很明顯看到了控頻的痕跡。VSM則被用來渲染地形的陰影,眾所周知,WOW的地形沒有陰影,一開始我還以為這是對的,後來才發現原來WOW的光不會動,所以在陰影不被拉長的情況下,這樣的陰影還是可以接受的,但是如果需要陽光動態變化,甚至拉到很長,沒有陰影的地形會讓物件的陰影騰空,相當難看,所以渲染地形的陰影還是有必要的。但是地形的陰影一般比較模糊,因為距離比較遠,所以PCF對於地形來說,陰影邊緣太過生硬,所以Cryengine選擇了用VSM,在一張1024的R16G16F上渲染地形,然後進行一次Blur,由於地形的陰影渲染範圍很大,再加上地形靜止不動,和光線變化較慢的特點,地形的陰影更新頻率非常低,這樣,地形陰影渲染的開銷就會比較小。在渲染地形陰影的同時,Cryengine還加上了雲陰影,使得陰影非常完整,逼真。VSM使用半精度其實是非常冒險的,VSM不像PCF,利用統計學演算法的VSM如果有完美的實數,將會是無比完美的,可惜,浮點的精度有限,想要VSM的陰影有一個模糊的邊緣,高精度很必要。通常都使用32位的浮點,半精度會引起近處非常明顯的條狀失真。不過Cryengine的這個失真仍然存在,只不過並不是很明顯,主要原因有以下兩點,第一,地形本身是個低頻細節的模型,所以陰影距離通常都比較遠,第二,Cryengine使用的陰影距離近,所以,本身深度範圍都小,所以精度自然就會比較高,浮點數嘛。所以Cryengine很有效地利用PCF和VSM模擬出了非常高效完美的陰影。這個解決方案目前也被我一直在使用。
關於取樣,一般,PCF的取樣是不如VSM的,原因是PCF是一個比較出來的二值結果,無法利用MipMap,線性取樣和AA之類的預取樣,這也正是VSM的優勢,但是在DX9中,有個HWShadowMap的解決方案,利用透視校正的取樣,可以利用線性過濾,一次取樣即可得到4次差值的PCF,而在這個基礎上進行多次取樣,就可以得到非常柔和的效果。一般的,在動畫或光發生改變時,陰影很容易發生抖動,這種抖動是非常刺眼的,這是由於被取樣的紋理本身的鋸齒抖動造成的。想要解決這個問題,一般就兩種,VSM可以利用AA來解決,而PCF則利用隨機取樣。隨機取樣之所以不容易感覺抖動是因為高頻的抖動不容易被人眼察覺的關係。GPU2上就有一篇文章描述一種隨機取樣方法,不過GPU上的取樣方法比較原始,所以實用性並不強,Cryengine使隨機取樣到了一個新的境界。首先,GPU上說的方法是連續取樣一張隨機紋理,來得到隨機的資訊,但是這顯然是種浪費,因為一次取樣就可以得到隨機了。Cryengine所用的方法是預生成一個圓形分佈的取樣點集,然後取樣一次隨機紋理,隨機紋理上記錄的是這個點集的旋轉角度,這樣的話,一次隨機取樣,就能使所有點都隨之改變。而且也正是這些圖形分佈的點的旋轉,使得陰影邊緣更柔和了。GPU上的方法,隨機取樣的UV是螢幕空間的,這樣的隨機取樣點抖動很快很頻繁,而且容易被察覺到螢幕空間相關。Cryengine則是使用了一個光空間透視較正的辦法,得到一個只與遠近及角度相關的隨機紋理UV,這可以把抖動降低。經過了上面的改進,Cryengine的陰影取樣效果非常不錯,雖然比不上SAVSM,但是比起以往的PCF陰影效果強了太多,把隨機取樣推到了一個新的高度。
關於ShadowPass,PSSM需要把陰影存在四個SM中,那麼取樣就會遇到用幾個PASS的問題,像WOW,直接取樣四張圖,肯定會造成無效取樣,效能會比較低,而GB則使用一張大圖來存,通過變換來定位,再取樣,而Cryengine用了另一種方法,使用模板,模板可以分別提取每層需要的畫素,然後進行取樣,四個Pass得到最終的陰影,理論上來說,全屏的陰影,應該是這個效能最優,因為取樣的圖更小,又沒有重複取樣的浪費。
以下是我使用這個解決方案得到的結果,因為引擎和時間的關係,我沒有做陰影距離,所以是全距離陰影,我的視距為400米,我用了2048X4的PSSM,和2048G32R32F的地形陰影。因為我這個距離,地形陰影用半精度會出現嚴重的精度不足的VSM失真,所以沒有辦法,Cryengine在這個距離上是掐得相當準的,稍有偏差,就會導致無法接受的失真。


Cryengine中的AO是SSAO第一次被應用到遊戲中,一才就炒熱了實時間接光照。Cryengine的AO技術並不是目前效果最好的,但是它的Blur卻是最快的,也就是因為超快的Blur,使得它可以應用FullAO,而不是HalfAO,因為FullAO的使用,葉子或者草之類的高頻物體的AO變得比較好,所以總體來說,也算是個不錯的AO解決方案。因為Cryengine的渲染體系是沒有Normal可用的,所以僅Depth取樣所得到的AO或多或少會有一些問題,所以只能說,這個是目前僅深度AO中,較好的效果,因為它的全域性性非常強,這得益於演算法中會根據距離來縮放射線長度,所以Cryengine的AO非常顯眼,不像有些AO的效果離遠了就容易被忽略。Cryengine的AO是全精度計算的,這可能會導致比較大的開銷,所以Cryengine對取樣進行了優化,主取樣使用螢幕原大小的圖,然後對周圍取樣時候則用了縮小後的Half圖,這節省了一些取樣時間,也引起了一個豎條狀的失真,這個可以在Crysis中見到,雪天的門口比較明顯。隨機圖方面,Cryengine用了一張4*4的圖,一共16種,這使得它的雜點非常難看,但是卻給BlurAO帶來了便利,因為只需要四次取樣,加上線性過濾,就能得到完全平滑的AO效果了,這比起Nvidia的HBAO要快得多。不過這樣的AO仍然有比較多的缺點,比如角色的後面容易黑,低多邊形鑲嵌的痕跡明顯,還有就是Blur後會造成象素的偏差,所以Crysis中也容易看到AO中有亮邊,但這不影響這個AO全域性性好的特點。不過具體如何,還是仁者見仁。我使用這個AO方案是因為草葉之類的高頻物件表現相對好的原因。
Cryengine還有個預計算的TerrainAO,我暫時還沒有機會去看。
下面發兩張我的結果:


我的結論是遠處,以及草葉表現較好,不過如果有Normal的話,還是非常大的改進餘地。
KlayGE中的AO是不是和DX中的HDAO差不多啊?感覺那個AO可以鉤出非常細節的AO線,但是全域性表現不如這個,怪不得叫HDAO,如果能配上一些低頻的AO的話,應該會更好看一些。Nvidia的HBAO效果也挺好的,就是Blur老是出現點,但是可以比較好的解決低多邊形鑲嵌的痕跡,所以還是不錯的解決方案。將來我會再嘗試做個更好一些的AO,目前這個仍然沒有十分讓人滿意的方案。

最近我分別使用了下Cryengine和Unreal的編輯器,相比之下,Unreal的編輯器要更專業一些,雖然Cryengine很強大,但是並不一定就是最為成功的商業引擎。Unreal的材質聯結器使得Unreal效果的擴充套件性要好很多,Cryengine相比之下也只是擁有更強大的內建渲染功能,作為一款引擎,與Unreal的積累上仍然存在一些差距。當然說到效果,比起Lightmass所展現出的靜態GI,Cryengine也沒有辦法弄出相應的動態解決方案。目前還是會有很多人覺得虛幻的室內效果更為完美,即使那要以犧牲動態光影為代價。

我繼續更新,為迴應[url=space.php?uid=4025]kuguoxin198[/url] 之前問的OC,我先在這裡面簡單說一下Cryengine中OC的理念,其實我也是這麼想的,只不過GPU精粹上的說法和這個大相徑庭,不過看到Cryengine的做法後,我像是有了靠山一般,很心安理得地也這麼做了。當然,我說的OC是指Query的OC,其它使用CPU的OC方法不在這裡面討論。Query和回讀差不多,都需要等待顯示卡指令執行完成,才能得到結果,如果在當幀瘋狂查詢,那OC會直接給予幀率毀滅性打擊。GPU精粹上有一種優化OC的方案,但是這個方案只是減少了幀中查詢的數目,並沒有解決查詢直接導致處理器空閒的問題,所以得到的效能增益非常有限,如果用這種方案來做一個遊戲的話,場景規模會有相當大的限制。Cryengine的OC還是在我的意料之中,它在幀頭,也就是Begin之後進行查詢,這樣的好處是,因為Begin已經等待顯示卡完成所有操作了,所以在Begin之後的查詢就會相當迅速,不會因為同步白白浪費寶貴的CPU週期。得到結果後已經晚了一幀了,可以在渲染的時候直接應用,當然也可以等到下一幀場景管理器Cull的時候大幅度減輕CPU負載,不過那樣的話,OC結果就需要延遲應用兩幀,Cryengine可能是兩種中的一種,我個人猜測應該是延兩幀的,畢竟寶貴的CPU對Cryengine來說可是要計算幾乎全部次世代物理的,在場景規模和視距都如此巨大的情況下,節省下這些資源是很有必要的。這時有人就會發現了,那不是會出現結果錯誤的情況,兩幀的會比一幀的更嚴重。事實也確實如此,但這就是我之前提到過的瑕疵優化,有如此可觀的效能提升,即使有瑕疵,仍然是合算的,因為畢竟OC的錯誤並不是無法接受的。原因有以下幾點:
1.想要在同代硬體上加大場景規模,很多LOD的技術都會引起跳動和突變,有些遠處的東西本來就會突然消失,OC導致的消失只不過是增多了會消失的機會罷了。
2.本來就要使用非常粗糙甚至刻意加大的模型代理來OC,這種粗糙會反過來減少OC錯誤的機會,所以OC錯誤可以很大程度地被減小,有特別刺眼的消失只要加大代理就行了。
3.相機的高速移動機會並不是很多。
4.事實證明了Crysis瘋狂的跳動突變完全被場大規模的場景以及超高規格的細節所掩蓋了。
我們對OC的需求是在最低幀率至少不降的前提下,可以較為可觀地提高平均幀率,最完美是能同時解放GPU和CPU,而不是完美的無縫。下面發圖來大致看下Cryengine的OC結果。


從圖中可見,其實OC並不是那麼精確的,太精確的OC反而對效能無益。目前好像有個OC引擎叫Umbra,可能這方面會比Crytek做得更精一些。

接下來說一下HDR,HDR可以說是Cryengine的一個強項,也可以說Cryengine把HDR的效果推到了前所未有的高度,總之Cryengine如此照片的渲染結果和它的HDR關係最為密切。
眾所周知,HDR是近年來最熱門的技術之一,引擎如果不能很好地支援HDR一定會被劃出一流引擎的行列。Cryengine1和Unreal3都相繼支援了這個在當時象徵著未來的革命性技術。HDR和Bloom有著本質的區別,雖然很多人會覺得差不多,但是HDR比Bloom多出的部分才是HDR的精髓。就算說HDR才是現世代(幾年前的次世代)頂級渲染技術的根本也不為過。真實的光照會帶來幾十幾百倍的亮度差距,而用以顯示的裝置卻只能有一個固定有限的亮度範圍,用有限的LR(低範圍)裝置來表現HR(高範圍)的世界是一項挑戰,最終我們需要一種技術把HR動態地對映到LR的裝置上,這就是HDR。照片就是這種效果的典範,照片一樣是LR(低範圍)這與遊戲中的情況一樣,為啥我們卻能覺得照片的還原度更好,是因為照片有個曝光的過程,通常看到的照片就是曝光較好情況,而如果自己拍攝,經常會遇到曝光不好的情況,曝光其實就是一種HDR的對映過程,人眼也有類似的過程。而對於LR無法表現的超高亮,通常是以光暈的形式出現,這並不是誰定的,而是人眼這樣的感光裝置在識別世界的時候自然形成的,看到照片的光暈會覺得很亮其實是人腦的潛在暗示。當然人眼的範圍比起顯示裝置要高得多了,所以HDR的目標就是往照片靠近。由此HDR最關鍵的技術就是ToneMap,沒有ToneMap就不叫HDR。ToneMap並不是那麼容易,而且經常出現的方法效果都是非常不理想的,這個可以參考DXDemo中HDR相關的內容,這樣的ToneMap效果根本就沒有辦法實用。Cryengine2在這個方面有了個非常大的突破,這使得Cryengine的渲染效果如此接近照片,以致難以辨認。

PS:Amazing!


對比Unreal3中HDR的效果與Cryengine我發現,Unreal3的ToneMap範圍很小,從室內出門的時候才稍稍能感覺到,而Cryengine2的ToneMap卻有異常誇張的作用,往往臺起頭,地面就會變成幾乎黑色。如此大範圍的ToneMap使得Cryengine真正把做到了HDR,並且比起HDRLighting那樣灰濛濛的還原,Cryengine的還原使得場景異常豔麗,HDR的魅力被Cryengine發揮了出來。對於那些看多了被Bloom搞得飽和度過高的場景而噁心的朋友來說,Cryengine版HDR的舒適自然則尤為明顯。飽和度高的豔給人噁心暈菜的感覺,降底飽和度也是HDR的一個非常大的作用,但通常見到的HDR總是把場景變得不那麼豔了,Cryengine版的HDR則打破了這個,讓人眼前一亮。Cryengine帶給我們的驚豔大部分都是因為這樣的HDR如此地豔。
經過分析,我瞭解了Cryengine版HDR的過人之處,再一次深深感嘆日爾曼民族的強大。Cryengine的HDR並沒有使用ToneMapping文獻中描述的ToneMap公式。線性的ToneMap不單還原差,而且會非常明顯地削弱對比度,使得場景非常平,而沒有生氣,其次,即使用了Lwhite作為門限來提升對比度,但過低的門限會造成曝過過度,過高呢,仍然無法解決對比度削弱的問題,這也就是為什麼DX的HDRLighting無法實用的原因。不過Cryengine則使用了更好的ToneMap方法,稱為ExpToneMap,其實這個也早就出來了,就是沒人實實在在地去實現罷了。顧名思義,ExpToneMap會漸漸擠壓遠離平均亮度的顏色,而且擠壓非勻速,這就產生了有很趣的效果,而且這能很好地同時擠壓亮與暗的顏色,使得有效果的對比度能夠很好地還原,再也不會出現平均顏色的結果了。不過,光有ExpToneMap是不夠的,有心的人可以注意到,Cryengine的Bloom也非常真實,比起虛幻巨大的光暈,Cryengine的Bloom層次更多,效果更好。事實確實如此,Bloom在Cryengine中是被強化的,Bloom分成兩部分,一是BrightPassBloom,二是ExtraGlow。先說BrightPassBloom,這個就是一般HDR中的Bloom,但是Cryengine中的實現卻非常不同,Cryengine中一共用了6個GaussianBlur,加上兩次HalfSample,一次BrightPass,一次FinalMerge,總共是十個批次,而且每個Buffer都是64位的,所以Cryengine花了非常多的資源用於Bloom的生成,當然結果是喜人的。把1/2 1/4 1/8的三層GaussianBlur的結果疊加,出現了一個非常有層次的Bloom,而且在ToneMap之前就新增進HR的顏色中,這樣有效地防止了Bloom提高過多的飽和度,使Bloom看起來非常有層次。ExtraGlow也是如此,三層疊加,區別是ExtraGlow是LR的,用於處理一些特殊材質的物件的Bloom。這才有了Cryengine最終的效果。
值得一提的是,需要有正常的HDR效果,擁有HDR的天空是非常重要的。如果做靜態天空的話,可以去下到HDR的天空盒,動態天空的話,需要計算大氣散射。Cryengine的大氣散射計算過程是看不見的,所以我自己做了一個,方法就是Siggraph1993的文獻中說的。最終才得到了Cryengine般喜人的效果。HDR花了我很久,但是從我修改OGRE的曲線來看,HDR的完成一次性把我的渲染特性提升了一個檔次,可見效果有多麼顯著。
以下是我早期的截圖,很好地說明了HDRToneMap的過程,可以看到,整個過程的色彩還原都是非常好的。

接下來說說ColorGrading,ColorGrading其實是一堆的濾鏡效果的集合,裡面用了許多相當實用的濾鏡。在引擎渲染的最後使用一些濾鏡可以很好地使畫面適合實際需要,使得渲染結果更加容易控制。這樣的理念非常值得推薦,所有所有都圍繞著ArtistFriend進行。其中有一個效果值得一提,就是ColorSharping,計算方法竟然是把Scene - SceneBlur*d,d為一個很小的值。也不知道誰發明的這方法,減去模糊的部分,突出細節。


經過數次的濾鏡處理,渲染結果還是有比較不錯的變化


在我的渲染中也添加了這樣的特性,效果挺不錯,據說Cryengine3加強了這個效果,不知道又加入了什麼好玩的東西。

在1024x768的情況下,他的四點是
0.000928,0.000326
-0.000244,0.001250
-0.000937,-0.000326
0.000244,-0.001250
當然是線上性取樣的情況下進行的,另外SunShaft也利用了這個Kernel進行Blur。
Cryengine的Kernel都是奇形怪狀的,很少有對稱的。

SSAO並沒有帶給Crysis什麼畫質提升,只是彌補了動態場景中缺少間接照明的缺陷,但其效果仍然離虛幻的LightMass很遠。真正讓我們眼前一亮的就是HDR。

AlphaTest和Clip是特殊情況,會直接導致在Clear前EarlyZ失效的,所以一定要排序,而且使用這些的情況下只填充深度無法有雙倍渲染速度的增益。但是由於填充佔用頻寬,所以即使不能雙倍,但開啟Test或者Clip仍然會有效能節省。

意猶未盡,待續啊。。。