聊聊LightProbe原理實現以及對LightProbe數據的修改


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

當然,這里只是拋磚引玉,歡迎大家來討論。
相關的腳本,可以在這里獲取:
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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM