【UnrealEngine4】藍圖-材質的數據傳輸與偽ComputePipeline

祝祖國母親生日快樂。

也各位讀者節日快樂。

上一次文章提到了體積數據的渲染方式和Tri-Planar的免UV著色技巧,根據目標,余將在國慶期間分享完全基於藍圖和材質,由NS方程驅動的流體模擬的方式與技巧。本期文章需要用到之前的體數據(其實也可以不用,不過最好是把之前提到的內容都實現了較好,如果實現不了,可以對文章進行降維(即鄙人將介紹三維形式的解算方案,各位可以簡單地修改為二維的形式,實際上,難度也會降低一個等級)

為了使每一期的文章都有東西可以實現,我決定每一篇文章都把理論上的內容與可實現的內容結合。實際上,寫下這類文章確實很累,如果僅僅只是介紹理論知識,大可把論文翻譯為可閱讀的中文即可,出於最開始的目的是為了使所有虛幻的用戶能體驗一下藍圖能達到的極限,能理解藍圖可以怎麼樣使用到極致,鄙人才打算寫下這一系列文章。

鄙人無欲無求,不求因文章而富貴,也不求聞達於各位知乎的大神(畢竟文章確是多有紕漏),只求各位用戶與學者,在看過我分享的經驗之後能有所得,文章受點贊已是最大的榮幸。

耳有人議鄙人之文非本人之作,鄙人實則痛心疾首。全系列文章沒有抄襲外文一個字元,皆本人筆墨(從余蹩腳的語文水平足以看出),為此我也誤會了一些讀者的好意,實在抱歉。望各位不計前嫌,Haters能洗心革面,不要揪著場景是否熟悉、內容是否抄襲不放(最後重申一次我沒有抄襲,沒有代筆),共同交流技術,分享經驗,共同學習,共同進步。

鄙人亦自知自己廢話之多,對於技術之外的事,各位權當看故事,以技術和思想為重就好。

回顧一下文章目錄:

一.【UnrealEngine4】距離場的使用技巧與應用

二.材質中的偽體素

1.【UnrealEngine4】材質系統中的偽三維紋理

2.【UnrealEngine4】體渲染和Tri-Planar Mapping

三.在虛幻四中基於NS方程的流體模擬

1.藍圖與材質的數據傳輸與偽ComputePipeline(本文)

2.NS方程的解析和實際模擬

四.metaball 的原理與在材質中的實現

五.在虛幻四中 path tracing

1.相機內參、簡單物體變換信息的處理

2.path tracing的解析,temporal的思路

3.在材質中進行path tracing

六、透明物體的渲染/造假技巧

以後根據實際情況做稍微的改動。

為什麼本期文章還用之前的場景做封面:我沒有其他好看的圖了。

本一期文章將為後面的重頭戲作鋪墊,介紹一下用藍圖怎麼和材質進行數據交換,怎麼模擬虛幻沒有暴露的Compute的Pipeline.因為現在是假期,因此理論性較強的部分會在後期再提到。鄙人的文章仍然會注重思路,至於嚴謹性的問題,也歡迎各位提出(是需要詳細、通俗解析,還是需要更學術的解析)。思想思路是很重要的,且甚於演算法。

下面是正文的正文。

一.用RenderTarget進行數據傳輸

二.偽Compute Pipeline

三.Ping Pong

一.用RenderTarget進行數據傳輸

首先先看看這個metaball。(就是本人上傳的了)

用純藍圖和材質實現metaball的用戶並不多

(如果要說有的話,虛幻官方實現了一個類似的。但是他的溶球數目是不可調的,而且是硬編碼的,不能任意數目球融合(我研讀了一下他的介紹視頻,推測得出的結論))

用c++實現的基於體素的Metaball也曾見到過,不過僅用藍圖和材質才是本文的目的。

要實現接下來文章要講的所有東西,都基於本文的技巧。

關鍵問題經梳理可以得到:

1.藍圖裡有 N 個溶球的數據(位置、大小、溶度(就是控制溶球軟硬程度的,我編的一個名詞)

2.材質里需要這 N 個球的數據,對他們構成的隱式表面進行RayMarch

3.利用光照模型進行渲染

1.中是很容易實現的。在藍圖裡面事實上只是一個結構體的數組(或者多個數組)

2.,對於虛幻一般的材質流程,是無法實現的。虛幻的材質中提供了一個個Parameter來傳輸數據,這相當於單個變數。但是根據需求1.,需要把「數組」傳輸至材質。

如果是在Vulkan裡面,我比較喜歡把數據包裝成VertexBuffer的數據,讀取起來比較方便。事實上,類比一般編程可以得到,所需要的其實是一個可以被材質讀取的「數據池」。整理到這裡,已經比較清晰了。在材質中能勝任數據池角色的特性,非Texture莫屬了。

一張貼圖,類似一個數據池,而數據就分布在每個像素裡面。暫且不管數據分布如何,再整理一下藉助貼圖藍圖到材質數據傳輸的思路:

1.for each N 個球,得到當前球的數據

2.將數據寫入一個Texture T

3.材質里讀取 T ,還原 N 個球的數據

現在只需要把2.實現,就完成了整個需求。根據上一節講到的體素數據注入的方法,同樣的可以應用到這裡來。但是為了靈活,這一次需要用到這個函數

(這是連串操作,具體使用方法比較簡單,不作贅述)這個函數會將材質 M_{0} 根據參數繪製到 T 的指定位置上。而 M_{0} ,通常可以是很簡單的一個材質,只需要有一個Parameter控制當前繪製顏色,輸出至自發光即可:

(事實上。。自發光只能輸出三通道的數據。因此這裡要注意的是,只有範圍為 [0,1]^{3} 的數據可以被寫入到RT中)

整理一下:

1.for each N 個球,得到當前球的數據

2.設置 M_{0}

3.繪製數據至 T

4.材質里讀取 T ,還原 N 個球的數據

事實上,和之前講的類似,數據排布方式完全可以自定義的。需要注意的是,材質中輸出到RT的數據只有RGB三通道,A將會被丟棄。且輸出類型為unorm,即0-1的數據(精度由RT決定,上面也提到了一下,重要的事情說兩遍),因此鄙人在此提供兩種數據存儲結構的思路:

1.多張貼圖方案(類似多個數組,每個數組類型不同)

儲存結構是這樣的:

還是拿溶球舉例,相同色調示意同一個球中的不同數據。

2.單貼圖,結構硬編碼的方案(相當於結構體數組)

相同色調示意同一個球中的不同數據。細線與粗線共同劃分像素(例如圖中實際解析度為4*4,但是只能儲存2*2個溶球的數據)

兩種方法各有利有弊。

然後就可以把一系列數據從藍圖傳輸到材質了。

二.偽Compute Pipeline

之所以提到這個,是因為後面流體模擬的文章需要用到這個。首先需要知道Compute Shader的用途,這裡鄙人不作贅述。光靠藍圖和材質,在虛幻中是無法使用通用計算這一功能的。但是如果您有看鄙人之前的文章,就可以知道是有辦法可以模擬的。

首先,為什麼需要通用計算。舉個例子,如果是繪製一張2D的貼圖,在Vulkan里大可用Vertex&Fragment直接輸出結果。如果是繪製一張3D的貼圖,Compute Shader就可以方便繪製更新,而且涉及複雜運算(比如解線性方程),且有並行策略,Compute Shader是很有優勢的。

啊,再舉個例子,比如我有一萬個粒子,如果我僅用cpu去計算他們的物理,是很愚蠢的,儘管運算速度快,但是卻是單線程(通常情況下,不要較真)運算,而且結果還要重新Copy到特定Region 才能供GPU使用。如果一開始分配一個數據空間,直接在Compute Shader里運算,那麼完成的數據不僅可以繼續在下一階段使用,而且能佔據大量數據吞吐量的優勢。

拿glsl(Spv)舉例,Compute Shader通常包括

1.一個 I=Ix*Iy*Iz 的線程數。

2.ImageLoad,ImageStore兩個常用函數

3.當前線程序號 xyz

類比材質和藍圖可用的功能,給出該管線和著色器的替代方案:

1.利用一中的函數創建一個解析度乘積(總像素數)為 I 的RT,調用材質。這樣就能在材質里有一個 I 的循環。

2.ImageLoad~採樣貼圖。而需要注意的是,Store只能輸出到一張貼圖,且只有三通道,且沒有RW(read write)這種操作。而且採樣貼圖帶硬體加速的插值,可以通過前面文章提到的修改為不插值模式。

3.材質中可獲取TextureCoordination,通過簡單變換可得到線程序號。

舉個例子。

Metaball的位置更新。數據量不多,通常幾十個小球。如果使用藍圖,幀數會驟減(可以嘗試)如果按照上面說的辦法,可以得到:

https://www.zhihu.com/video/898172802937544704

實時在材質中進行位置運算而更新的位置數據。

當然,後面也會經常用到這種辦法。包括前一次文章提到的體素數據的注入方式,實際上也與此類似。之所以加上一個「偽」字,是因為這種非標準的做法,的確是一種偽物。不過本系列的文章就是以這種技巧為目的而分享交流經驗而存在的。

簡單運用:

既可以用藍圖傳輸N個點光源的數據,也可以用材質來更新計算點光源的數據,最後在材質中讀取,對Unlit的材質進行著色。這是非硬編碼的,無論是光源數目還是任意一個光源的參數都是在運行中可以調整的。(溶球同理,不過鑒於鄙人之前沒有解析解析怎麼渲染隱式表面,本文就先用最簡單的形式代替)

本次文章留一個作業:

1.用藍圖隨機生成一些位置(光源),用藍圖傳遞數據給材質,對unlit的材質進行正確著色,要求光源數目可改動,任意光源參數可調。

2.用藍圖隨機生成一些位置(光源),用藍圖傳遞數據給材質,用偽ComputePipeline對光源位置進行更新,對unlit的材質進行正確著色,要求光源數目可改動,任意光源參數可調,且光源位置每幀能夠正確更新。

大概花費5分鐘即可完成。這也是後面文章一定會用到的方法,如果跳過了,後面的內容可能會無法實現。。。

效果大概如下

https://www.zhihu.com/video/898215256684371968

三.Ping Pong

此PingPong不是國球乒乓。。而是一種常用來實現兩個buffer的數據交替存取的演算法。

在後面解線性方程的時候會常用到這個演算法。在這裡先講一下。

基本需求:由貼圖A和一系列參數,經過多次迭代運算得到結果

考慮到虛幻中材質不支持RW的Texture,這裡需要用PingPong的演算法來解決這一類問題。

設每一次迭代運算函數為F,結果為R

1.準備A,B兩張貼圖,一個標記(Bool),初始為A,其中A貼圖為原始數據,B貼圖為空

2.標記為A:B=F(A)

標記為B:A=F(B)

3.重複步驟2. 若干次,

標記為A:R=F(A)

標記為B:R=F(B)

4.輸出結果R

這樣交替在AB之間儲存當時迭代的結果,省空間的同時,也滿足了需求。具體在後期NS方程解算器中解線性方程的時候會用到。

另外需要在材質中建立一個拷貝函數:

用作貼圖之間的拷貝或者覆蓋。

實現PingPong的藍圖比較繁雜,這裡就不上圖片了。用一個Select(選擇)就可以根據標記選擇Src(源)和Dst(目標)。下一篇文章有機會會盡量詳細介紹。

下一講的畫風大概如下:

每個函數拆開大概長這樣:

還沒有包括一系列為了Compute的材質。總而言之,技巧上的東西鄙人在這一講已經完全解析完畢。合理使用,一定可以達到很好的效果。下一講,將解析流體模擬的內容。作業記得完成哦(大霧)

照例放一些有趣的圖片和視頻:

一個之前寫的純藍圖&材質的體素化。用來做物理正確的次表面散射十分有效。

一些Trick拼湊而成的透明的次表面散射材質。。拿來做泳圈感覺不錯。

好,本期的文章到此結束了,感謝閱讀。

鄙人不才,對很多東西理解尚不夠透徹,對圖形學也僅僅有一點點了解,文章僅僅為了分享經驗交流心得,拋磚引玉,見笑大方了。如有紕漏,望斧正。

參考文獻:


推薦閱讀:

【《Real-Time Rendering 3rd》 提煉總結】(二) 第二章 · 圖形渲染管線 The Graphics Rendering Pipeline
反向路徑採樣在MLT演算法中的運用
虛幻引擎學習之路:相機圖像後處理
VRay for SketchUp工業產品表現之煤油燈
VRay for SketchUp環境阻光(AO)的簡介與應用

TAG:渲染 | 虚幻引擎 | 计算机图形学 |