0x00 前言
最近工作比較忙子姜,所以文章已經(jīng)很久沒有更新了。這篇小文的主題也是在出差的高鐵上想到驯鳖,因為最近和一些朋友聊天闲询,發(fā)現(xiàn)他們中很多人的項目中都使用了多個實時光源。細(xì)問之下主要是某些物體浅辙,例如角色扭弧,在烘焙后的場景中顯得不夠突出,為了突出角色所以加入了更多的實時光源记舆。但事實上這可能并非一個很好的選擇鸽捻。
0x01 間接光還是直接光
下面這張圖片演示了只有直接光照以及加上了間接光照之后的對比。
可以看到泽腮,直接光照抵達不到的地方的黑暗的部分要通過間接光照來照亮御蒲,而不是為了提高暗部的亮度再加一盞實時燈光。
事實上诊赊,如果場景中有大量的燈光——例如如果在上圖中為室內(nèi)增加大量補光來提高室內(nèi)亮度——
還會造成場景中的明暗對比降低厚满,畫面顯得更“平”。
這也是很多朋友的項目中場景中存在的一個比較常見的問題碧磅,即亮度不夠燈光補碘箍。補著補著才發(fā)現(xiàn),整個場景已經(jīng)充斥了太多的燈光了鲸郊,而場景也因此整體很亮丰榴,沒有了明暗對比,結(jié)果就是視覺效果平的不真實秆撮。
相信各位也一定想到了四濒,亮度不夠燈光補這個思路的另一個實踐——場景內(nèi)的角色不夠亮?xí)r也選擇使用一個燈光來給角色補光——同樣存在著和之前所說的一樣的問題。
那么怎么提亮角色才更加合理一些呢职辨?(雖然提亮角色這件事本身就不符合物理規(guī)則盗蟆,但是為了游戲效果顯然存在這樣的需求)。如上圖所示那樣拨匆,利用間接光來照亮物體是一個不錯的思路姆涩,不夠亮?提高間接光的亮度惭每。
在Unity中如何給動態(tài)物體提供間接光?這就引出了下面的主角——LightProbe。
0x02 LightProbe的核心
LightProbe主要解決了如何在動態(tài)對象和角色上使用烘焙的照明信息台腥。
其實LightProbe的核心就是球面亮度信號編碼和重建宏赘。
如果大家了解信號處理方面的知識的話,就會知道只要信號滿足一定條件黎侈,就可以分解為一系列正弦諧波的和察署,諧波頻率以倍頻增長,這就是所謂的傅立葉級數(shù)峻汉。
而lightprobe也采用了類似的思路贴汪,使用了球諧函數(shù)來對該球面上的亮度信號進行編碼。
同樣的休吠,一個原始的亮度信號也可以分解為一系列帶縮放參數(shù)的基函數(shù)之和扳埂,而我們只需要知道這些基函數(shù)的縮放系數(shù)就可以在運行時快速的重建原始的亮度信號了。
但是有一個問題瘤礁,那就是如果要完美的重建原始光照信號的話阳懂,顯然需要很多很多甚至是無窮項球諧函數(shù)。但是好在LightProbe中保存的主要是一些低頻的光照信息柜思,換句話說岩调,它沒有高頻率變化,所以如果我們通過丟棄所有更高的頻率來壓縮球體上的頻域數(shù)據(jù)赡盘,沒有人會注意到号枕。所以這里我們可以只取有限的低頻諧函數(shù)。
在Unity中陨享,烘焙GI的LightProbe采用了3階球諧函數(shù)(9個參數(shù))葱淳,實時GI中的LightProbe采用了2階球諧函數(shù)(4個參數(shù))。
OK,信號編碼的問題解決了,另一個問題即在運行時如何重建亮度信號否副。其實使用lightprobe的開銷很低噩茄,因為只需要將縮放系數(shù)與其對應(yīng)的基函數(shù)相乘之后再求和的結(jié)果就是近似的原始信號。
接下來我來看看一個Unity中的LightProbe中保存了哪些數(shù)據(jù)吧觅玻。
在Unity中,我們可以使用腳本將場景內(nèi)的LightProbe保存為一個Asset,并且只要保證使用文本格式進行序列化唁毒,我們就可以直接查看其數(shù)據(jù)內(nèi)容了。
AssetDatabase.CreateAsset(Instantiate(LightmapSettings.lightProbes), "Assets/lightProbe.asset");
首先能夠注意到的是“m_Tetrahedra”部分星爪。
這個其實就是在運行時LightProbe插值時需要用到的四面體數(shù)據(jù)浆西。因為如果要進行插值,顯然要知道需要哪幾個點來插值顽腾,同時還需要知道每個點的權(quán)重各是多少近零。
在Unity中會根據(jù)角色所在的位置诺核,選擇四面體,然后使用組成四面體的點進行插值久信,當(dāng)然還可以確定每個點的權(quán)重窖杀。
在靠后的位置,我們還可以找到烘焙后的球諧函數(shù)的系數(shù)裙士。
可以看到9個參數(shù)3個通道所以每一個點總共有27個float數(shù)據(jù)入客。
綜上,可以看到在使用LightProbe時腿椎,計算開銷并不大桌硫,相對來說比較大的開銷主要來自對內(nèi)存的占用。
0x03 修改LightProbe數(shù)據(jù) 提亮角色
ok啃炸,簡單介紹了一下LightProbe的原理以及實現(xiàn)铆隘。下面我們還是回到最初的問題,那么怎么提亮一個場景內(nèi)的角色才更加合理一些呢肮帐?
事實上我們可以通過修改烘焙后的LightProbe的數(shù)據(jù)來實現(xiàn)這樣的需求咖驮。
可以看到上圖中,角色已經(jīng)和場景融為了一體训枢。雖然這樣更加真實和符合物理規(guī)則托修,但是我想對很多人來說這顯然不是一個好的效果。角色還是能更加突出的好恒界。
好在Unity提供了獲取烘焙后的LightProbe數(shù)據(jù)的接口:
var probes = LightmapSettings.lightProbes.bakedProbes;
bakedProbes內(nèi)保存的是一堆“SphericalHarmonicsL2”對象睦刃,只要修改SphericalHarmonicsL2的縮放比例就可以修改LightProbe所提供的亮度了。
除了修改亮度之外十酣,有時我們也會想讓角色有不同的環(huán)境光效果涩拙,以更加突出角色。這時我們就可以通過SphericalHarmonicsL2中定義的AddAmbientLight方法來實現(xiàn)了:
probe.AddAmbientLight(color);
提亮和修改環(huán)境色之后耸采,我們的角色在場景中就成了下面這樣兴泥。比實時光更加自然和開銷更低。
當(dāng)然虾宇,這里只是拋磚引玉搓彻,歡迎大家來討論。
相關(guān)的腳本嘱朽,可以在這里獲刃癖帷:
https://github.com/chenjd/LightProbeEditor
ref:
https://en.wikipedia.org/wiki/Delaunay_triangulation
https://www.gdcvault.com/play/1015312/Light-Probe-Interpolation-Using-Tetrahedral
https://en.wikipedia.org/wiki/Spherical_harmonics