前言:NVIDIA Gelato、Tesla、CUDA是一股對傳統基於CPU的渲染器挑戰的力量。GPU在諸多方面具有軟體實現無可比擬的優勢比如光柵化部分,遮擋剔除,以及潛在的並行計算能力,但是編程性實在缺少基於CPU的自由度,所以在相當的一段時間內還無法充分發揮效能。本文討論了下基於GPU、CPU這種混合體系下的渲染器架構,相當思路也是Gelato所採用的。
聲明:本文所採用的插圖資料如果沒有註明原作者等均收集自那些論文原作者的網站以及他們的Paper,根據ACM著作權聲明禁止作為商業使用只可以用於教學活動,轉載時必須保留原作者的名字以及出處。感謝Henryxu先生,沒有他的個人ACM帳號我不可能接觸到這麼多的資料。轉載請附上我的連絡方式。我的連絡方式是 南京林業大學242信箱 周波收 zhoubo22(at)hotmail(dot)com Mobile : 13four51eight13six91
離線渲染與即時渲染的最大不同在於,前者是近似於忽略效能的照片級渲染,Shader的代碼數以萬行,紋理尺寸高達上G,導致的結果,一個是我們可以看到亂真的火爆電影場面,另一個就是渲染時間。雖然硬體在不斷的發展,Render Farm(以下簡稱RF)在不斷的更新,可是為了達到理想中的效果,即使已經有了20年發展曆程的渲染器(主要是Pixar RenderMan與mental ray,以下簡稱RM與MR),每一幀的渲染對硬體資源的需求依舊是無止境——加勒比海盜3中的情境平均每一幀需要大約70小時,況且ILM使用的RF肯定不會差,應該是最好的。對於電影工業這種與娛樂市場緊密結合的行業來說,時間就是金錢,也許,明天也許就是dealine。
GPU的優勢在於高度的並行機制,極其快速的光柵化組件。但是它也是個這樣的工廠:所有的原始材料必須同時投入這個黑盒,執行的時候不能中斷過程也不可見。所以我們很自然的想到可以使用它來做基本的光柵化操作。但是如果想直接使用GPU渲染幾何體這幾乎是不可能做到的,首先是GPU的渲染能力有限,其次在於直接光柵化的品質太差。
Occlusion Query
對於一個擁有數量級多物體的情境,我們在渲染前一定要進行遮擋查詢,只將我們感興趣的物體留在螢幕上,其餘的可以不需要載入記憶體。因為在現代渲染器的時間都耗費在Shading上,也就是一堆簡單的加加減減的數學操作上,但是計算數量相當的巨大,而不是光線求交,光線求交只是效能耗費極少的一部分。在CPU上我們有些方法可以計算物體的包圍盒是否在攝像機的Frustrum裡(這個詞見過許多版本,從錐台到平截頭體的都有,乾脆我就不說它了),或者是軟體光柵化的方式判斷是否可見。對於GPU來說,最簡單的莫非於使用OpenGL的ARB_occlusion_query進行查詢。對於GPU這樣的裝置來說最好的工作方式就是給它一大堆資料而不要任何“回報”——回讀操作Readback。使用圖形管線的這個功能只是給它一大堆不需要著色的立方體,而返回的僅僅是每個立方體將在螢幕上出現的象素數目,很自然的,當返回的數字為0那麼就知道這個物體不會在螢幕上出現。記住,NVIDIA的硬體可以以雙倍的速度渲染深度。有的人可能會疑問,這樣一股腦兒的把資料交給GPU效率高嗎?答案是,高。因為即使是基於CPU的軟體渲染器依然要經過這樣的一步。Gelato就是使用了這個來判斷物體是否會在螢幕上出現。至於如何使用ARB_occlusion_query大家可以去參考NVIDIA的OpenGL Sepcifiction以及NVSDK中的範例來學習。
Antialiasing Shading
為什麼RM或者MR渲染的畫面好像沒有鋸齒?因為它們都使用了Supersampling或者類似的技術,根據使用者設定的Rate數值決定實際渲染的Bucket解析度,一般是從4x到16x,使用過濾器過濾後就縮小為我們設定的Bucket的大小。為什麼RM的記憶體佔用率很小?因為它每次只鑲嵌一小部分物體將它們打散為多邊形,而且Geometry Cache可以多達5級。為什麼RM使用的是頂點著色可以達到這樣的效果而GPU如果用Per Vertex的光照方式得到的畫面是那麼的醜陋?因為它的微多邊形比象素還要小的多,所以在這些micropolygon上進行Shading要比在Pixel上Shading還要精細的多。
類似的,NVIDIA Gelato依舊是需要對幾何體模型進行鑲嵌,最後產生Grid,這樣每個二次面片就可以當作一個GL_QUADS讓OpenGL的管線去做光柵化等等操作。由於此時每個頂點都足夠精細,所以此時Per Vertex的光照計算就可以滿足要求。當Dicing Rate與Shading Rate不同的時候,此時資料就不在是針對每個頂點的。Gelato將資料裝入FP32紋理中進行操作,可惜硬體還無法對這樣的紋理格式做過濾,所以渲染品質比起軟體的實現會有大約15%的差距。
隨後就是超級採樣Super Sampling,和隨機採樣Stochastic Sampling。對於GPU來說,根本不存在實現底層隨機採樣的可能。因為GPU硬體的光柵化部分是專有而且封閉的,而軟體的實現卻可以在CPU上自由發揮。所以使用Accumulation操作來類比是完全可行的。比如這個圖,出現在《GPU GEMS2》中,也在Larry Gritz的siggraph 2007的Talk中出現過。
上邊是規則採樣,下面是隨機採樣,樣本數目從左至右依次為1、4、16、32。
Motion Blur and Depth Of Field
一提到MB就應該想到空間內基於幾何體的MB,而不是即時渲染所使用的那種基於螢幕空間的MB。Gelato的MB實現包括Vertex Motion與Per-Pixel Time Sampling來實現MB與DOF。
MB與DOF使用Vertex Buffer Object避免多次資料上傳,所有的Accumulation的操作都是在GPU上完成以避免回讀。使用Vertex Shader實現Model View Projection變換、插值,針對每個Pass的每個象素計算相應的鏡頭參數。操作是針對整個Bucket進行的,當提高Pass的數目後可以有效減少失真。Gelato自動的根據當前渲染的需要選擇合適的Pass數目,這樣可以有效提高整體效能。
Transpancy
一個詞,深度剝離Depth Peeling。
深度剝離是為了處理透明物體的渲染而發明的技術,原始的版本可以在NVIDIA Developer網站上找到。說白了就是用Multi Pass的方式逐層的把後面透明的、但是被剔除的層給疊加到現有的畫面上。但是GPU到現在為止依舊不支援FP32精度的Alpha Bleeding,況且,透明效果有些時候是留給後期人員製作的。
微軟亞洲研究院有篇Paper叫做《Multi-Layer Depth Peeling via Fragment Sort》,使用了GPU的MRT能力加速產生深度剝離圖層,比原始方法提高了一倍左右的效率。具體詳情可以去相應網站去找資料。
Interactive Relighting
無庸置疑,電影動畫的創作是一門藝術,而藝術家在製作的時候往往非常迫切的需要看到自己打的燈光在實際情境中效果如何,所以我們需要提供一種輔助的Relighting工具讓藝術家指導自己的創作。有些朋友可能會問,難道不能預先渲染一些幀查看效果麼。是的,這樣可以,但是這樣浪費了時間,而且很多東西是不需要渲染的,比如完全模糊消除鋸齒的陰影,精確的DOF效果,這些統統都是不需要的,藝術家往往只需要去看他所感興趣的物體的光照效果,其它的一概忽略,所以Relighting工具需要提供這樣的迅速以及自由度。Relighting系統的發展也是走過了一個階段,其中不乏世界頂級工作室與大學的合作。
| |
A Fast Relighting Engine for Interactive Cinematic Lighting Design from Stanford University |
| |
Lpics: a Hybrid Hardware-Accelerated Relighting Engine for Computer Cinematography from Pixar Studio |
| |
appeared in the Siggraph 2006 Direct-to-Indirect Transfer for Cinematic Relighting from Conell University Dartmouth College |
| |
appeared in the Siggraph 2007 The Lightspeed Automatic Interactive Lighting Preview System from MIT CSAIL, Industrial Light & Magic, Tippett Studio |
從最新的那片Paper看來,使用GPU加速的Relighting已經成為主流趨勢,它的流水線如所示,
這其中牽涉到的最複雜的部分莫過於Shader的翻譯,其次才是Scene的解析。為什麼說Shader的翻譯是最複雜的,因為這和GPU本身的限制有關。在一部電影中所使用的Shader一般都有幾萬行,單純一個物體的渲染就是有大量的幾何體、Shader以及Texture。由此導致的結果是,很多RenderMan能跑的,渲染時間上能夠忍受的Shader將無法在GPU上執行,我們需要簡化以及修改RenderMan Shader,翻譯為GPU所能執行的Shader,GLSL、HLSL或者是CgFX等Shading Language。其次才是幾何體的簡化。由於我們一般來說只是預覽一個物體的光照效果,其它的操作比如光線跟蹤等一般來說是不需要的,所以就需要為高精細的模型做適當的簡化,讓GPU可以輕鬆的處理為Render Target,然後再著色。這種方式類似於Defered Shading延遲著色,不過它準備的材料要比即時渲染多的多了,BRDF資料等等都需要準備好,這樣我們才能看到一個與真實結果差不多的。如那個酷酷的大黃鋒。(有時我想,未來硬體提高了後,即時渲染是不是也可以使用類似於Relighting的思路,真正達到電影層級的效果)
Shading
事實上,最複雜的部分莫過於Shading部分,尤其是當希望CPU與GPU整合的時候。有些OP在GPU上操作非常快,比如算術運算、三角函數等等,但是其它的一些OP,比如RenderMan中的gether與trace,在GPU上是根本無法使用的。有些朋友可能會問:早就有基於GPU的Raytracer了。是的,不錯,但是對於surface shader來說,所有的執行過程應該是連續的,不可以打斷的,而且對於這些OP的調用也不是間間單單的計算,而是需要回到CPU層次上,檢查光線與物體包圍盒的相交情況,然後再將命中的物體傳入GPU管線計算求交,而且根據我們希望返回的數值來看,很有可能是迭代Shading的過程。所以,對於簡簡單單的一個光線跟蹤來說,需要三個任意:起始點任意、方向任意、返回數值任意,所以,開發一款使用GPU加速的電影級渲染器,除了硬體廠商比如NVIDIA,其它的廠商極難從底層的加速做起。
結論
GPU是個好資源,可是非常的棘手。我是希望從編譯器層次考慮,實現一個虛擬機器解釋執行編譯後的Shader代碼或者是基於偽彙編層次的最佳化,將部分拆解為PTX與CPU OP來順序執行,保證上下文一致性不被破壞,而且效能有所提高。當GPU工作的時候,CPU可以空閑下來,這樣CPU也可以進行Shading工作,這樣就實現了加速,當然不苛求加速比,這也是諸多開源渲染器無法立足的原因,單純的對RT部分最佳化而忽略了製作方面的需求,這樣就成為了一個玩具而不是工業產品。所以我決定把今後的分析時間放在GPU加速的Shading的、光柵化組件的使用技術,而不是純粹的光線跟蹤。