[Addon 2017] Stylized VFX in RiME

補之前看的,simonschreibt.de/gat/st

# Fire

這個比較簡單,效果略簡陋,博客里作者分享了UE材質。

主要是靠兩張紋理,一張控制基本形狀和混合顏色,另一張用於擾動紋理製造動態效果:

流程如下,擾動紋理的兩個通道按照不同速率向上滾動,再使用另一張紋理的A通道以及一張漸變圖來作為mask,和原來的紋理坐標相加後作為最後的紋理坐標。需要mask的原因是,A通道可以表現出火的基本形狀,而漸變圖則是為了讓底部火焰保持不動,即擾動值為0:

靠擾動後的紋理坐標去採樣第一張紋理的RG通道,得到的效果如下:

第一張紋理的RG通道負責標識內外兩層火的區域,使用兩種火焰顏色混合疊加之後如下:

作者提到塞爾達裡面的火,也是用了類似的擾動方法,但明顯效果要好多了:

# Smoke

傳統做煙霧的方法是使用粒子,一個很棒的這方面的演講是暴雪做的,我之前也在博客里寫過,candycat1992.github.io/。我之前還寫過另一篇講煙的文章,candycat1992.github.io/,講到幀動畫和一種程序化的渲染方法。Diablo的主要思想是每個particle使用了紋理滾動和混合來實現更好的體積感,這樣整體效果需要的粒子數目就會比較少,減少了大量的overdraw:

另一個例子是給每個粒子算偽光照,法線是核心。每個粒子都是一個面片,可以讓這四個頂點的法線都指向外,來近似模擬球面法線的效果,然後再進行光照計算,這樣也可以有體積感:

但上面的方法都不夠卡通。作者發現在日本動漫里,很多效果都依賴完整的網格,twitter上有一個日本人經常分享這種效果:

作者受到啟發,決定也用網格來做煙。之前也有遊戲這麼做過,不過是靠縮放網格大小來做淡入淡出的:

網格不能直接使用引擎內置的球體,因為它的網格和uv分布非常不均勻。作者使用Max里做的球體網格,並使用spherical mapping生成紋理坐標:

然後是渲染。基本的漫反射渲染看起來太暗太真實,不夠卡通。作者直接在上面加了個0.2,讓整天變亮,只能略微看出有一絲光照效果。然後看一張雜訊紋理,在頂點著色器里對網格進行略微的變形,來增加一些變化。最後,淡入淡出則是依靠alpha test來做消融:

RiME是一個有晝夜變化的遊戲,所以還需要根據時間來實時更新光照顏色:

這種方法並不是完美的,仔細看在淡入淡出的時候會有紋理接縫(這應該是spherical mapping生成紋理坐標的問題,它其實是把六個面均勻地貼在球面上,像立方體那樣,所以普通的那種可平鋪的紋理仍然會有接縫)。當然可以製作一張特殊的紋理來解決這個問題,但作者發現其實在遊戲里幾乎無法察覺到這個問題,因為有很多網格,播放速度也快,所以作者後來就let it go了:

# Waterfall

最後一個也是最有意思的,就是瀑布效果:

在作者做之前,他能搜到的相關資料就只有模仿塞爾達里瀑布的效果,主要是靠片做的:

作者根據原畫對效果進行了拆分,主要有六個部分。一是由水到浪花的過渡,瀑布越往下,浪花越多,瀑布水則越少。二是輪廓問題,瀑布靠近水面的部分會有不規則變化的輪廓,觀察圖中浪花部分,越下面分裂得越厲害。三是透明度,仔細看圖可以發現水的部分其實是半透明的,可以隱約透出後面的圖像,我們都知道半透明有令人頭痛的排序問題。四是隨一整天時間一致變化的渲染效果。五是水面上由於瀑布衝擊而形成的波浪。六是飛濺的水花和下面的漣漪:

作者首先嘗試了使用之前做煙的方法來做水花四濺的效果,但結果並不理想:

下面先講第一個問題如何解決,主要是依靠頂點色。首先對基礎的顏色紋理做一些擾動來得到基本的藍色水效果。那些需要漸變到浪花的部分則是依靠手刷的頂點色(這裡的頂點色只是一個例子,實際遊戲里用的會刷得仔細多了):

作者靠雜訊紋理滾動來得到一個基礎效果,然後靠頂點色來篩選出合適的區域,再加強對比度,結果作為一個mask來混合藍色水和浪花顏色:

然後是輪廓問題。作者引入了更多的網格來支持頂點變形,所以頂部和底部的網格密度比較大。作者還需要更多浪花飛濺的效果。之前提到了靠煙那種方法來實現效果不好:

於是作者又引入了更多的網格。一共四層,三層較小的網格使用了和之前基本一樣的材質,只是去掉了渲染藍色水的部分,只渲染浪花,這樣也可以保持consistant shading:

這樣網格加來加去,數據量就上去了。於是作者用了LOD,最高級別的面片數有18k,離得越遠面前越少:

第三個要解決的是半透明效果。由於遊戲支持角色潛到水下,角色可以透過水麵看外面的世界,此時會有一個擾動的效果。作者為了測試瀑布材質,放了個瀑布材質球在水上。然後吧,作者發現,在UE裡面把瀑布材質的混合模式設為Opaque就一切正常,設成Translucent後就不會被擾動了,看起來感覺這個球是在水下:

作者表示不知道whats going on,於是呢,他就不用半透明了……(⊙…⊙)我不了解UE這方面的機制,猜測是排序的問題,半透明會在渲染擾動紋理之後才渲染,所以不會出現在擾動紋理里,應該可以通過調整渲染隊列來解決(不過UE的自定義可控性可能比較弱?)。後來作者使用了菲涅耳(?實在沒聽清他這句在說啥)和漸變紋理來實現假的次表面散射效果,在從背後觀察瀑布時可以表現出光透過瀑布的,實際還是不透明物體:

作者遇到consistant shading的問題,由於底部浪花和水面上的浪花使用了不同的獨立網格,底部浪花網格大體上是豎直上下的,而底部浪花大體是整體面朝上方,這樣經過光照計算後顏色就不一樣了,像左圖那樣。這個問題可以靠調整法線來解決。作者調整了底部浪花網格中靠近下方的頂點法線,使得越靠近水面的部分法線越向正上方靠近,這樣光照計算後的顏色也就越和水面浪花的結果接近,如右圖:

這種調整法線的方法也常用於渲染草之類的billboard,為了讓草和地面顏色更接近,可以調整billboard的法線,使它們靠上一些:

接下來是水面上的衝擊浪花部分,大體樣子如下:

首長解釋那些高低起伏的浪花部分,這些實際上是若干網格粒子,每個粒子如下,是一個細分程度較高的圓形網格:

之所以細分程度這麼高是因為要對它做頂點動畫,每個粒子隨著它的life time高低起伏(這裡有個小插曲,作者問聽眾有多少使用UE多少使用Unity,看到結果後全場一笑):

這裡也用到了高度圖來淡出網格,隨著粒子逐漸消亡,露出水面的部分也逐漸減少,這可以靠閾值來剔除高度圖來實現:

這種消融的方法也用到過地圖的消散:

把若干這樣高度範圍不同的網格粒子放在一起播放,就可以得到衝擊浪花的效果了。這裡的光影變化僅僅是應用了陰影,而不是靠計算漫反射,因為頂點的位置一直有較大的起伏,所以就沒有演算法線的變化:

飛濺的水花也遇到了consistant shading的問題,左圖是直接使用類似之前做煙的那種方法來做小水花,可以看出來在光照變化的時候它們的顏色和瀑布整體差別較大。作者說原因是粒子的光照解決方案Enlighten的問題,Enlight會為粒子計算間接光照,然後由於某些東西會在某些情況下讓小水花顏色太灰了。解決方法也是靠overwrite水花的法線來解決:

最後是ripple漣漪的實現。作者的靈感來源於早期的塞爾達里的效果:

實現方法也是靠網格,形狀如下:

然後使用一張漣漪形狀的紋理,RG對應了兩層漣漪:

對每個通道使用hard alpha來渲染,再靠時間不斷向外移動旋轉紋理就可以得到基本形狀了:

上面只是一層漣漪,把RG通道都按這樣的方法渲染,並且按照不同的速率滾動紋理就可以得到更豐富的效果:

上面有個問題,就是在邊緣處可以看到不太自然的消融效果,現在是直接就斷掉了。解決方法還是依靠頂點色,來作為一個mask:

最後的效果:

除了用於瀑布,這種方法也用於渲染岸邊的foam效果。岸邊的這些foam也都是單獨的2D面片,由於有的海岸線很長,為了能更好地被距離裁剪(不然一渲染所有的網格都得一起渲染),海岸線部分的foam網格實際被分為了好幾個部分,所以每個部分可以單獨被裁剪:

這些顯示了使用的網格。由於水面會波動,為了讓foam和水面契合,也使用了和下方水面相同的頂點動畫材質節點來移動頂點:

但遇到劇烈波動的水面就會有問題。因為foam使用的網格和水面網格的細分程度不同,所以即便按照相同的邏輯去移動頂點仍然會有網格交叉:

對於這種水面會劇烈運動的情況,作者就換成了decal material來做foam(由於是用相同的水面網格再畫了一遍所以肯定不會交叉穿幫):

# 最後

這次是五句箴言:

紋理坐標擾動是增加動態效果的好幫手,善用法線修改來得到更加細膩的光照效果,以及(小心)增加網格真的很好用。
推薦閱讀:

Ray Marching Ocean
用頂點Shader實現的實時陰影
【GDC2017】Terrain Technology and Tools
讓角色半透明:後期模糊(二)
拓幻圖形學工程師教學手冊(第三講)|一字一字敲出OpenGL學習教程

TAG:計算機圖形學 |