聊聊LightProbe原理實現以及對LightProbe資料的修改

quxing10086發表於2018-05-06

0x00 前言

最近工作比較忙,所以文章已經很久沒有更新了。這篇小文的主題也是在出差的高鐵上想到,因為最近和一些朋友聊天,發現他們中很多人的專案中都使用了多個實時光源。細問之下主要是某些物體,例如角色,在烘焙後的場景中顯得不夠突出,為了突出角色所以加入了更多的實時光源。但事實上這可能並非一個很好的選擇。

0x01 間接光還是直接光

下面這張圖片演示了只有直接光照以及加上了間接光照之後的對比。
GI_comparison_1.png
可以看到,直接光照抵達不到的地方的黑暗的部分要通過間接光照來照亮,而不是為了提高暗部的亮度再加一盞實時燈光。
事實上,如果場景中有大量的燈光——例如如果在上圖中為室內增加大量補光來提高室內亮度——
還會造成場景中的明暗對比降低,畫面顯得更“平”。
這也是很多朋友的專案中場景中存在的一個比較常見的問題,即亮度不夠燈光補。補著補著才發現,整個場景已經充斥了太多的燈光了,而場景也因此整體很亮,沒有了明暗對比,結果就是視覺效果平的不真實。
相信各位也一定想到了,亮度不夠燈光補這個思路的另一個實踐——場景內的角色不夠亮時也選擇使用一個燈光來給角色補光——同樣存在著和之前所說的一樣的問題。
那麼怎麼提亮角色才更加合理一些呢?(雖然提亮角色這件事本身就不符合物理規則,但是為了遊戲效果顯然存在這樣的需求)。如上圖所示那樣,利用間接光來照亮物體是一個不錯的思路,不夠亮?提高間接光的亮度。
在Unity中如何給動態物體提供間接光?這就引出了下面的主角——LightProbe。

0x02 LightProbe的核心

LightProbe主要解決了如何在動態物件和角色上使用烘焙的照明資訊。
其實LightProbe的核心就是球面亮度訊號編碼和重建。
Light-Probe-Interpolation-Using-Tetrahedral

如果大家瞭解訊號處理方面的知識的話,就會知道只要訊號滿足一定條件,就可以分解為一系列正弦諧波的和,諧波頻率以倍頻增長,這就是所謂的傅立葉級數。
而lightprobe也採用了類似的思路,使用了球諧函式來對該球面上的亮度訊號進行編碼。

同樣的,一個原始的亮度訊號也可以分解為一系列帶縮放引數的基函式之和,而我們只需要知道這些基函式的縮放係數就可以在執行時快速的重建原始的亮度訊號了。
Spherical_Harmonics.png

但是有一個問題,那就是如果要完美的重建原始光照訊號的話,顯然需要很多很多甚至是無窮項球諧函式。但是好在LightProbe中儲存的主要是一些低頻的光照資訊,換句話說,它沒有高頻率變化,所以如果我們通過丟棄所有更高的頻率來壓縮球體上的頻域資料,沒有人會注意到。所以這裡我們可以只取有限的低頻諧函式。

在Unity中,烘焙GI的LightProbe採用了3階球諧函式(9個引數),實時GI中的LightProbe採用了2階球諧函式(4個引數)。
OK,訊號編碼的問題解決了,另一個問題即在執行時如何重建亮度訊號。其實使用lightprobe的開銷很低,因為只需要將縮放係數與其對應的基函式相乘之後再求和的結果就是近似的原始訊號。

接下來我來看看一個Unity中的LightProbe中儲存了哪些資料吧。
螢幕快照 2018-04-20 下午12.23.56.png

在Unity中,我們可以使用指令碼將場景內的LightProbe儲存為一個Asset,並且只要保證使用文字格式進行序列化,我們就可以直接檢視其資料內容了。

AssetDatabase.CreateAsset(Instantiate(LightmapSettings.lightProbes), "Assets/lightProbe.asset");

首先能夠注意到的是“m_Tetrahedra”部分。
螢幕快照 2018-04-21 上午9.27.39.png
這個其實就是在執行時LightProbe插值時需要用到的四面體資料。因為如果要進行插值,顯然要知道需要哪幾個點來插值,同時還需要知道每個點的權重各是多少。
在Unity中會根據角色所在的位置,選擇四面體,然後使用組成四面體的點進行插值,當然還可以確定每個點的權重。
螢幕快照 2018-04-21 上午9.34.55.png

在靠後的位置,我們還可以找到烘焙後的球諧函式的係數。
螢幕快照 2018-04-21 上午9.48.20.png

可以看到9個引數3個通道所以每一個點總共有27個float資料。
綜上,可以看到在使用LightProbe時,計算開銷並不大,相對來說比較大的開銷主要來自對記憶體的佔用。

0x03 修改LightProbe資料 提亮角色

ok,簡單介紹了一下LightProbe的原理以及實現。下面我們還是回到最初的問題,那麼怎麼提亮一個場景內的角色才更加合理一些呢?
事實上我們可以通過修改烘焙後的LightProbe的資料來實現這樣的需求。
light1.png
可以看到上圖中,角色已經和場景融為了一體。雖然這樣更加真實和符合物理規則,但是我想對很多人來說這顯然不是一個好的效果。角色還是能更加突出的好。
好在Unity提供了獲取烘焙後的LightProbe資料的介面:

  var probes = LightmapSettings.lightProbes.bakedProbes;

bakedProbes內儲存的是一堆“SphericalHarmonicsL2”物件,只要修改SphericalHarmonicsL2的縮放比例就可以修改LightProbe所提供的亮度了。
除了修改亮度之外,有時我們也會想讓角色有不同的環境光效果,以更加突出角色。這時我們就可以通過SphericalHarmonicsL2中定義的AddAmbientLight方法來實現了:

  probe.AddAmbientLight(color);

提亮和修改環境色之後,我們的角色在場景中就成了下面這樣。比實時光更加自然和開銷更低。
light2.png

http://news.tdw5546.cn/
http://news.mtj9347.cn/
http://news.osi0013.cn/
http://news.bjb5476.cn/
http://news.ghk5310.cn/
http://news.xjy3902.cn/
http://news.grp2563.cn/
http://news.lkg4662.cn/
http://news.vwb8311.cn/
http://news.mmw6064.cn/
http://news.cqz7056.cn/
http://news.nlk4583.cn/
http://news.adw2245.cn/
http://news.alj9141.cn/
http://news.vdf1425.cn/
http://news.miv2453.cn/
http://news.vdx0926.cn/
http://news.smc5776.cn/
http://news.ffn3573.cn/
http://news.rdj9135.cn/
http://news.mtu9335.cn/
http://news.gzv8338.cn/
http://news.xum5501.cn/
http://news.jiq1934.cn/
http://news.syh5891.cn/
http://news.yvr8830.cn/
http://news.aua2439.cn/
http://news.ath0401.cn/
http://news.gmx2930.cn/
http://news.pzf7790.cn/
http://news.ass0795.cn/
http://news.mox2684.cn/
http://news.oqc1977.cn/
http://news.bcu6005.cn/
http://news.ajj5951.cn/
http://news.xwt5617.cn/
http://news.rlv0165.cn/
http://news.shg1037.cn/
http://news.akj0836.cn/
http://news.ipc6507.cn/
http://news.kri6555.cn/
http://news.mzj8672.cn/
http://news.azq7227.cn/
http://news.zce9839.cn/
http://news.gjc9646.cn/
http://news.myo1179.cn/
http://news.ogr7085.cn/
http://news.bah1564.cn/
http://news.mjg4415.cn/
http://news.dkk2480.cn/
http://news.qru6126.cn/
http://news.ocs5821.cn/
http://news.wne9476.cn/
http://news.xuh4863.cn/
http://news.icb3050.cn/
http://news.tfe0886.cn/
http://news.xgs5975.cn/

相關文章