《盜墓筆記》使用的這套技術,讓美術可以在場景中任意使用燈光
以下是演講實錄,有節選:
大家好!感謝大家今天來參加我的技術分享。我叫袁晟,是一名技術美術,來自上海遊族網路。今天要給大家分享的題目是我們在《盜墓筆記》這個專案中使用的光影技術。
我的分享大概分為這樣幾個部分。首先介紹一下專案的需求和挑戰,然後介紹一下專案中所使用的光照技術,最後是小節。
《盜墓筆記》這個專案是在2018年提出的,flag是MMORPG、次世代、大世界,以及手遊。當時美術同學給我們提出的需求是這樣的:首先它有地上場景,大家可以看到以下兩幅畫面,畫中有非常多的光影效果,比如說太陽穿過樹葉,還有一些鏡頭的光影效果。美術給的關鍵詞一個是現代與唯美感的大世界,還有一個就是氛圍。
其次是地下場景,大家知道《盜墓筆記》這個專案中的地下場景是非常多的,所以室內的環境也很重要。美術這邊對於室內環境的要求是具有真實感,但是並不要求是一個非常大的奇觀。
在渲染品質上,他們給了兩個競品,一個是Bungie的《命運》,另一個是《守望先鋒》(見下圖)。其實兩款產品都不是手遊專案,都是PC專案。所以我認為美術同學的意思是希望光影是儘量真實的,同時,它的材質可能在真實的基礎上需要一定的風格化。
《命運》
《守望先鋒》
所以,最後根據美術的需求,我大概做了這樣一些總結。
產品需求方面場景包括地上和地下,場景尺寸除了主城地上的那些部分,其他地下的場景可能不會太大。
畫面風格這塊需要是寫實材質的,但是材質略帶一些風格化。
材質表現這塊應該是PBS的材質,題材可能包括現代、古典以及自然。
我們認為最大的挑戰是美術一開始提出來的詞“氛圍”,因為這個詞比較抽象,所以我試圖使用一些技術詞彙進行了轉變。我們需要光源環境、體積光、體積霧以及一系列的後處理來營造“氛圍”,因此我們也需要一個能夠提供相應處理的工具。
在技術選型這邊,因為這個專案是兩年以前立項的,當時Unity的版本是2017和2018,我們選擇了一個相對更新的Unity 2018。Unity 2018給我們提供的功能,比如SRP、Vulkan等,我們也會具體考慮是否適合使用,後面我會具體地講SRP。在API這邊,因為兩年以前根據渠道商提供給我們的裝置分佈情況,幾乎沒有ESR的情況,大概只有8%,所以我們OpenGLES這塊定的是3.0。
其實我們一開始是非常希望能夠使用Vulkan的,但是當時比較糾結,最後還是沒有在這個專案中使用。
我們來聊一下光照。
對我們來說,挑戰最大的部分還是室內和夜晚的照明。為什麼?因為我們在手機遊戲產品中可能往往使用的是一個方向光,用Lightmap(光照貼圖)的形式來做。但是在室內和夜晚的照明場景中,主光是分開的。這一是因為沒有一個像太陽這樣的統一光源,二是因為它的主光是按照區域劃分的。比如下面這張圖中間的光來自於上面一個方形的空隙,這個空隙就成為它的室外燈光的主光,邊上的火把又成為這個柱子的主光。
第三個就是在這樣一個場景中可能我們需要使用不同型別的輔助光源來烘托氣氛,比如點光、面光,或者是聚光燈,因為地下場景總體上還是比較黑的。這個時候,如果我們使用一個方向光就很容易把整個場景打亮,所以我們相對而言會更多地依靠間接光照,這樣就不會讓畫面顯得太髒或者是太悶。
這邊是《古墓麗影》的一張遊戲截圖,可以看到它的畫面是非常有層次感的,遠處的火堆和一些室外的日光灑下來,環境中有非常棒的空氣感,而且整個場景是沒有死黑的部分的,非常有層次感,非常通透。這是我們美術希望能夠實現的一個效果。
《古墓麗影》
講完需求和挑戰,我們看一下比較傳統的光照技術。
這邊先簡單介紹一下,一般來說比較傳統的光照有是前向和延時兩種。前向渲染方向,Unity提供了兩種解決方案,一種是BuiltIn RP,一種是LWRP(2019版本開始更名為URP通用渲染管線)。
目前,場景複雜度對於前向渲染中光照的影響非常大,它的複雜度是燈光數量×物件數量,所以如果使用BuiltIn RP drawcall就會非常高。當然,Unity提供另外一種URP,它把多個燈的資訊同時傳到一個pass裡面去,所以它可以在一個pass裡面把光照全部算完,它的drawcall就降到物體的數量,但是其實這部分光照資訊仍然要在Shader中進行計算的,所以這部分的算力還是由GPU承擔了。
另外一種是延時渲染,Unity提供的是HDRP(高清渲染管線),該功能目前還是沒有辦法在手機上使用的。最下面我寫了兩個問號,現在還是有一些方式、一些手段允許我們使用one-pass的deffered,這種方式可能需要使用Metal或者是Vulkan這樣比較新的API才能實現。它可以讓你的MRT產生的G-Buffer只留在tile memory上,而不是要寫到shared memory裡。所以,這就是我們非常糾結的一點,因為我們專案一開始就沒有選擇使用Vulkan,所以這個方案基本上早期就被否了。
我們看一下在《盜墓筆記》中使用的光照方案。
我們的靜態物體基本上使用的是Lightmap進行光照,動態物體和角色我們使用的是Light Probe,植被使用的是Light Probe+Directional AO。
這邊可以看到這樣一個場景,裡面有非常多的光照,主光通過天窗投下來,來自於室外,它的場景裡還有非常多的壁燈和其他的輔助光源。由於燈非常多,一般來說我們需要使用延時渲染去做,主要是在主機或者是PC上面。但是通過我們的方法,目前在手機中能跑到60幀以上。
這裡面演示的是角色在不同環境裡移動的時候受到環境的影響,比如說這個地方偏藍,它可以受到自然光的影響。
再往前走,前面有一個稍微亮點的地方,角色會變亮,角色的受光方向基本上也是和環境一致的。這個是比較類似於延時渲染或者是實時光照的情況,但是基本上完全是烘焙的。
這是另外一個場景,是《盜墓筆記》中比較經典的地下場景。
我們可以看到這種地下場景一般是比較暗的,我們不希望這些暗都是死黑的,所以使用了間接光照給它進行打亮的。這裡面我使用了一個手電筒,它是一個動態光,其他的光都是完全烘焙的。像這些地方周圍的環境對於Normal和高的表現是比較友好的。
像這樣一個場景我們雖然沒有使用實時光照,但是它的光照效果跟使用實時光照的效果是非常接近的。
再來看一下效能的情況。首先這邊看到在剛才的場景中這邊的Batch大概是173,因為這個場景相對比較複雜,還有一些NPC在場景當中。
這樣一個鏡頭從上往下看基本上所有的東西都會加入到計算當中,加入到drawcall當中,這個時候的Batch大概是180。
這個場景相對比較簡單,裡面沒有NPC,道具比較少,而且草都是用Instance去繪製的,所以Batch又降得比較低,只有109。
另外一個鏡頭,這個場景看得比較遠,它是150以下,146。
所以說整個繪製過程中其實沒有用到實時光,drawcall也是完全壓制住了。
我們使用的光照技術是AHD光照,顧名思義,A就是Ambient,環境光的意思,H是Highlight,高光的顏色,它裡面指的是主光的顏色,D就是Directional,指的是主光的方向。AHD相當於把一個畫素的入射光的光照拆分為兩項:一個是Ambient項,一個是Directional項。而Directional 項由兩個參數列示,一個是主光的顏色,第二個是主光的方向。然後我們把主光的顏色和方向從完整的入射光裡面去除掉,剩下的部分我們都稱為Ambient項。
比如說除了主光以外的一些輔助光源或者是間接光照,我們都是稱為Ambient Light。
由此,我們把這樣一個入射的光照拆成這樣一個表達形式。這邊的I(n)的意思是一個畫素的入射光照,它拆成了Ca,Ca表示的是環境的光照顏色,這邊的Cd表示的是主光的顏色,這邊的cosin就是一個基本的光照係數。
這種形式把比較複雜的光照變成了一個相對比較簡單的形式,同時,由於拿到了主光的方向和顏色,所以我們可以在此基礎上進行高光的計算。
AHD並非是一個新技術,它只是比較小眾。2013年的時候當時的Last of us和2016年的Call of Duty都使用了這個技術。
Last of us(2013年)
Call of Duty(2016年)
使用AHD來做的Lightmap,如下圖,這張是實時光照的情況,上面有一些法線,所以表現了比較多的細節。如果我們把這塊石頭進行Lightmap烘焙,它就會比較平。這是因為我們一般的Lightmap是沒有辦法把Normal以及高光資訊烘焙到Lightmap上的。
如果是使用了AHD的Lightmap,它就能把高光、法線所有的PBR用到的資料都能完整地用Lightmap記錄,然後還原出來。如下圖。
AHD光照它有什麼問題呢?首先我們知道它分了三項,也就是Ambient的顏色和主光的顏色,這兩張是HDR的,還有主光的方向,這張是LDR的。總共有三張Lightmap,這個我們肯定不能接受,所以常見的AHD是需要進行壓縮的。
我們把這三項,兩張HDR、一張LDR壓縮成右邊的這樣一個係數,就是標量和方向是一張LDR,還有一張Iz(一張HDR),這兩張是可以合成一張的,最後變成兩張貼圖。
Iz一般是什麼?我們的Lightmap是怎麼計算的?
它是把頂點光照作為法線,把頂點的法線帶入進行計算的。所以這邊的z項表示的是頂點法線,而不是一般我們認為的畫素法線。所以,它可以把整個這項變成這樣一個形式:Ca+max(0,z (dot) d)Cd。可以看到Ca和Cd還是原來的,只是中間這一項變了。這個Iz就可以用傳統Lightmap的顏色表示了。所以,這個對傳統的Lightmap工具比較友好。
另外,我們看這邊的係數是什麼意思?
我們有另外一個假設,我們認為環境的顏色和Lightmap得到的顏色是正比關係,也就是說它的色相是不會變的,所以我們可以把環境的顏色的luminous求出來和Lightmap的luminous求出來進行一個比值。我只要記錄這個比值,就可以從Lightmap的顏色拿到環境項的顏色。所以,一般來說我們會對AHD進行這樣的壓縮去儲存。
我們知道怎麼做以後,後面就是怎麼在Unity中去實現。
我們知道Unity中已經有一個東西叫Directional Lightmap。它的設計初衷並不是為了實現AHD的,但是它也能夠幫助我們實現這些東西。根據解碼,我們發現需要的幾個最重要的引數在Lightmap中已經有了,比如說Iz,係數,方向。Directional Lightmap的w項我們是不需要的,後面可以把它優化掉。所以,整個Directional Lightmap是可以直接用來作AHD計算的。
後面比較簡單,我們只需要進行一些加減乘除就可以簡單地拿到它最後的結果。
最後的效果是這樣的,我們可以通過這張Lightmap的顏色以及一張Directional Lightmap,不需要任何實時光照就可以計算出漫反射、高光等。因為我們是PBR的渲染,所以我們還需要AO和IBL,合成為最終的結果。
這個是基於Lightmap的做法,當然這個還比較簡單。
第二部分是動態物體,由於動態物體沒有辦法使用Lightmap,我們需要使用的是Light Probe。目前,Light Probe是使用球諧來儲存的,它能完整地計算Directional和Ambient的資訊,但是無法計算高光。所以如果我們能從Light Probe中把AHD三項完整地拿出來,就可以和場景一樣進行計算。
從下圖我們可以看到最終的效果是,當角色在場景中自然走動的時候,他會受到環境的影響,比如從亮走到暗,或者是從暗走到光照以下,它都會因為環境的變化、高光方向以及光照方向相應地進行轉變。
為了拿到一個完整的SH9的資訊,我們是這樣記錄的。通常Radiance我們會投影到球諧的式子中,大概是這樣一個形式。我們記錄的係數是這邊L項,我們把這個稱為Row SH,假如說這個地方只需要使用一個二階的球諧,一共要記錄9個float 3,也就是9個顏色。
但是在Unity的Light Probe中儲存的式子是不一樣的,它是這樣一個形式。它比我們需要的形式多了這樣一些係數,比如π分之一,還有這邊的A。它是什麼意思呢?
因為Unity最後記錄的是一個Lambert表面的Radiance資料,所以說對於Lambert表面的BRDF是π分之一,後面的A是cosin在球諧上的投影,投影的具體形式是這個樣子的。
所以,如果同樣使用一個二階的SH儲存光照資訊,它所存下來的係數是這樣的形式,也就是π分之一,AxL,它比我們希望的形式多了兩個係數。當然它的資料同樣是存在9個顏色資料裡面的。
舉個例子,假如說我們是一個一階的,中間一個求,Unity會儲存的形式相當於這樣一段,我這邊畫的橙色的一段。而我們需要的可能是中間黃色的一段。我們把Unity存的東西稱為縮放過的球諧係數。
Unity這樣處理明顯是希望通過離線計算把一些不需要的乘法先在離線環境中計算掉,這樣在實時計算的時候就可以比較簡單地往下做,而不需要再計算這些東西。
Unity把這些東西在球諧的9個係數上進行乘法,完成以後就可以再往下傳到Shader裡面去。
這邊9個float 3一共27個資料,而Unity的傳法是7個float4的資料,所以一共28個槽,這邊還多一個。
這邊有一些小的點是什麼呢?大家可以看到在這邊第六項其實是cosin平方減1,把它展開的話這邊多了一個常數項。所以把這個常數項和鄰接的合併到一起,因為鄰接也是個常數。它把這個-1扔過去,剩下的cosin項就留在原來的地方。
所以,這邊B通道乘的是cosin部分,而A通道是鄰接的加上剛才的常數。
在Shader中使用就非常簡單了,把Normal乘以剛才的球諧係數,就可以得到光照結果。
當然,它只能拿到Diffuse和Ambient項,所以,我們接下來還要繼續處理。我們需要從它那邊得到完整的AHD。想要得到完整的AHD,首先就要先把縮放的球諧變換回原始的球諧,把這些係數都給拆掉。
第二步我們需要解出主光的方向。首先可以把球諧函式看作一個球面函式的和。我們的目標是要從這個球面函式得到它的最大值,假如說我是一個一階的球諧,也就是一個常數項和三個係陣列成的,把後面經過整理變成一個點積。我們的目標是讓這個項變成最大值。我的做法就是讓這個點積等於1,因為cosin最大值是1。這邊就很容易得到Omega的方向,就是這樣一個式子。
因為球諧中儲存的是單位向量,所以我們接下來還需要計算出方向光的模。這邊因為計算比較複雜,時間有限,我就不在這個地方展開了。我們可以參考ppsloan的論文裡面對這個進行完整的求解,它的模等於17分之16π。
http://www.ppsloan.org/publications/StupidSH36.pdf
拿到這個係數以後,我們後面就可以求後面的兩項:一個是A項,就是Ambient的顏色和一個C項,也就是主光顏色。我們這邊使用的方法是最小二分法,我們需要把AHD的展開式,C×L項+A×LA項,這個就是AHD的形式。剪掉後面的LE就是我們從Unity給我們烘的球諧中得出RowSH的那一項。所以,我們給它相減,求方差,再對它進行偏導求極值、求誤差最小的情況,就可以通過這種方法求到它的A和C的預估。
這邊有一個小的點,我們這邊使用的是white,因為球諧一共有9個顏色,所以我其實有兩種方法。第一個是RGB三個通道分別求三個不同的方向,三個不同的主光顏色。但是這個方法就會要求我在後面的實時計算中進行三次的光照計算,這顯然不太划算,所以我們用了另外一種,對每個顏色進行luminous計算,求它的明度,對它的明度求最大方向以及最大方向的顏色。
這邊為什麼有兩個L呢?這個地方是為了後面要球諧投影的展開。這邊很容易理解,因為它是一個方向的,所以這個方向在球諧上的投影,當然這裡面還帶了一個cosin。
因為它是一個Ambient項,Ambient項是個常數,所以它只有一個係數,2根號π。所以這邊就把它進行球諧的投影,方向在球諧上的投影我們記住是大寫的D。Ambient項在球諧上的投影我們記住是大寫的A。Unity給我們提供的RowSH我們記住是大寫的E。這樣在球諧上投影以後我們就可以最終通過求解這個方程知道C和A等於多少。
後面的計算就相對比較簡單,只需要把C和A算出來就可以了。
最複雜的部分已經結束了。後面就是要把Light Probe在場景裡面進行佈置。我們這裡是使用Houdini進行佈置的。我們把場景的碰撞體導到Houdini裡面,用Houdini對它進行計算。
這邊看到的黑的點是Houdini進行完的球諧的Light Probe的位置。
使用Collision Box為Houdini的輸入
再把這個東西通過Houdini的工具HDA,插入到Unity裡面去。這樣我們就可以使用這個工具直接在Unity裡面進行計算。
這個是計算的結果,這些點最後都會轉化成Light Probe的球。
我們為什麼使用Houdini做這個東西?
當然第一個原因是因為自動化比較簡單,第二個原因是,大家如果用過球諧的共振,就會發現如果點的分佈是均勻的話經常會在牆壁或者是門洞這些地方出現漏光,而實際上當出現這種情況的時候我們需要美術在門洞或者牆壁的地方增加細分,然後去把這個漏光修掉。但是如果使用Houdini的話就比較容易,因為這個完整的碰撞體拿到以後,我們知道哪裡是牆,哪裡是門洞,所以我們就可以在相應的位置上改變它分佈的力度,就比較容易去處理這個問題。
最後一部分就是Directional AO,比如植被或者是表面拓撲比較複雜的模型。如果我們使用Lightmap對此類模型進行計算,非常耗Lightmap的畫素,一般來說沒有辦法很好地表現。所以我們最終還是使用的Light Probe對它進行的光照。但是,這個地方如果只使用LightProbe,它容易變得比較平,因為LightProbe的取樣只有一個點,所以這個地方就使用了另外一個方法,Directional AO,進行額外的計算,讓它產生一個正確的自陰影。
這是Directional AO(簡稱DAO)的一個效果。這邊只顯示DAO的黑白。大家可以看到這個場景的燈光是來自於某個特定的方向,所以這棵樹的受光面白一點,被遮擋的地方黑一點。當我們旋轉這棵樹的時候,這個光照是會實時地發生變化的,它永遠是被光遮擋的地方會變成黑色。
整個計算相對來說比較簡單,並不需要我們額外的用傳統的方法去存AO或者是Shadowmap。
我們求解DAO的思路比較簡單,因為DAO是一個球面函式,所以我們可以把這個球面函式也投影到球諧上。DAO是個高頻資訊,所以我們需要使用高階的SH,我們這邊使用的是三階的。我們把SH的係數拿到以後儲存到這個模型的頂點色上,然後在實時運算的時候把這些資訊拿回來進行還原。
這個是最後的效果。左邊是沒有DAO的效果,大家可以看到比較平,右邊是有DAO的效果,所以可以看到會有一個自陰影的明暗的狀態。
無 Directional AO
Directional AO
最後我就簡單總結一下我們這個技術的優點和缺點。
首先,使用了AHD以後我們比較大的優點是可以通過離線的方式把光照資訊完整地儲存到Lightmap和Light Probe上。這樣執行的時候我們只需要計算一次高光就可以了。同時,我們的drawcall就會降為物體的數量,與燈光的數量無關。我們可以把間接光照的資訊完整地保留下來,並且在實時烘焙的時候將它還原。我們可以使用一些比較複雜的燈光,比如說面光、體積光或者其他一些東西。
缺點,我這邊簡單寫了兩個。一個是Lightmap需要兩張:一張是標準的Lightmap,一張是Directional,需要Light Probe。另外一個它是需要依賴烘焙,無法實時編輯,這是它比較大的一個缺點。還有一個缺點就是我的燈光位置不能移動,也因為它是烘焙的。
我們在這個專案中使用這套技術最大的好處是,它不限制美術在創作中對燈光的使用,美術可以在任何場景中任意地發揮。下圖這樣的場景大概打了幾十個燈,比較複雜的場景中美術打了300多個燈。這些燈在我們的實時計算量上都是看不見的,因為都是離線計算。同時,我們可以把間接光照拿回來的,所以相對來說比較廉價。從效果來說也基本上和使用實時光照是類似的。
好的,我的分享就到此為止。謝謝大家。
來源:Unity官方平臺
原文:https://mp.weixin.qq.com/s/f0CRNRDzLNJwa1ll3FILvg
相關文章
- 《盜墓筆記》從歐美轉戰港澳臺!盜墓題材會成為新的引爆點嗎?筆記
- AR技術可以在哪些場合被使用?
- AR技術在藝術展館中的使用效果
- 【盜墓筆記】圖解使用fat-aar方式在AndroidStudio中打包巢狀第三方aar的aar筆記圖解Android巢狀
- 雲原生技術在離線交付場景中的實踐
- 圖技術在美團外賣下的場景化應用及探索
- 極光筆記|極光推送在APICloud平臺的使用教程筆記APICloud
- Billboards 技術在Unity 中的幾種使用方法Unity
- 正道的光之真正讓人佩服的技術
- Debias 技術在金融推薦場景下的應用
- 淺析WebRTC技術在智慧園區影片管理場景中的應用Web
- 廣告深度預估技術在美團到店場景下的突破與暢想
- 從《盜墓筆記》到《琅琊榜》,"中國漫威"如何打造超級IP?筆記
- CSS技術筆記CSS筆記
- 『技術分享』-- 使用極光 IM 構建聊天功能
- 雲渲染技術的兩種場景還在傻傻分不清?
- i 技術會筆記 | Druid在愛奇藝的實踐和技術演進筆記UI
- 資料湖Iceberg技術在小米的落地與場景應用
- 基於 HTML5 WebGL 的 3D 場景中的燈光效果HTMLWeb3D
- 努力一下,還是可以成為技術美術(TA)的
- 天美F1技術美術專家:技術美術的未來前景如何?
- JMeter MQTT 在連線測試場景中的使用JMeterMQQT
- 《淘寶技術這十年》讀書筆記筆記
- Redis管道技術的使用Redis
- tsv檔案在大資料技術棧裡的應用場景大資料
- 低延時音影片技術在OPPO雲渲染場景的應用
- Redis 中 HyperLogLog 的使用場景Redis
- Redis 中 BitMap 的使用場景Redis
- 遊戲技術美術之<技術&美術>知識構成遊戲
- 全息投影技術所適用的場景分析
- VMware Bitfusion GPU共享技術的應用場景GPU
- 【DB筆試面試185】在Oracle中,如何讓普通使用者可以TRUNCATE其他使用者的表?筆試面試Oracle
- 【技術面對面】基於場景圖的多物體影像生成技術
- 天美高階TA:淺談大世界場景自動生成技術
- 美顏美妝SDK技術,讓美麗觸手可及
- 多模態人物識別技術及其在愛奇藝視訊場景中的應用
- 美團上市的技術思考:一般企業都用的到這些技術!
- 家電造車:技術向左,場景向右