聊聊LightProbe原理實現以及對LightProbe資料的修改
0x00 前言
最近工作比較忙,所以文章已經很久沒有更新了。這篇小文的主題也是在出差的高鐵上想到,因為最近和一些朋友聊天,發現他們中很多人的專案中都使用了多個實時光源。細問之下主要是某些物體,例如角色,在烘焙後的場景中顯得不夠突出,為了突出角色所以加入了更多的實時光源。但事實上這可能並非一個很好的選擇。
0x01 間接光還是直接光
下面這張圖片演示了只有直接光照以及加上了間接光照之後的對比。
可以看到,直接光照抵達不到的地方的黑暗的部分要通過間接光照來照亮,而不是為了提高暗部的亮度再加一盞實時燈光。
事實上,如果場景中有大量的燈光——例如如果在上圖中為室內增加大量補光來提高室內亮度——
還會造成場景中的明暗對比降低,畫面顯得更“平”。
這也是很多朋友的專案中場景中存在的一個比較常見的問題,即亮度不夠燈光補。補著補著才發現,整個場景已經充斥了太多的燈光了,而場景也因此整體很亮,沒有了明暗對比,結果就是視覺效果平的不真實。
相信各位也一定想到了,亮度不夠燈光補這個思路的另一個實踐——場景內的角色不夠亮時也選擇使用一個燈光來給角色補光——同樣存在著和之前所說的一樣的問題。
那麼怎麼提亮角色才更加合理一些呢?(雖然提亮角色這件事本身就不符合物理規則,但是為了遊戲效果顯然存在這樣的需求)。如上圖所示那樣,利用間接光來照亮物體是一個不錯的思路,不夠亮?提高間接光的亮度。
在Unity中如何給動態物體提供間接光?這就引出了下面的主角——LightProbe。
0x02 LightProbe的核心
LightProbe主要解決了如何在動態物件和角色上使用烘焙的照明資訊。
其實LightProbe的核心就是球面亮度訊號編碼和重建。
如果大家瞭解訊號處理方面的知識的話,就會知道只要訊號滿足一定條件,就可以分解為一系列正弦諧波的和,諧波頻率以倍頻增長,這就是所謂的傅立葉級數。
而lightprobe也採用了類似的思路,使用了球諧函式來對該球面上的亮度訊號進行編碼。
同樣的,一個原始的亮度訊號也可以分解為一系列帶縮放引數的基函式之和,而我們只需要知道這些基函式的縮放係數就可以在執行時快速的重建原始的亮度訊號了。
但是有一個問題,那就是如果要完美的重建原始光照訊號的話,顯然需要很多很多甚至是無窮項球諧函式。但是好在LightProbe中儲存的主要是一些低頻的光照資訊,換句話說,它沒有高頻率變化,所以如果我們通過丟棄所有更高的頻率來壓縮球體上的頻域資料,沒有人會注意到。所以這裡我們可以只取有限的低頻諧函式。
在Unity中,烘焙GI的LightProbe採用了3階球諧函式(9個引數),實時GI中的LightProbe採用了2階球諧函式(4個引數)。
OK,訊號編碼的問題解決了,另一個問題即在執行時如何重建亮度訊號。其實使用lightprobe的開銷很低,因為只需要將縮放係數與其對應的基函式相乘之後再求和的結果就是近似的原始訊號。
接下來我來看看一個Unity中的LightProbe中儲存了哪些資料吧。
在Unity中,我們可以使用指令碼將場景內的LightProbe儲存為一個Asset,並且只要保證使用文字格式進行序列化,我們就可以直接檢視其資料內容了。
AssetDatabase.CreateAsset(Instantiate(LightmapSettings.lightProbes), "Assets/lightProbe.asset");
首先能夠注意到的是“m_Tetrahedra”部分。
這個其實就是在執行時LightProbe插值時需要用到的四面體資料。因為如果要進行插值,顯然要知道需要哪幾個點來插值,同時還需要知道每個點的權重各是多少。
在Unity中會根據角色所在的位置,選擇四面體,然後使用組成四面體的點進行插值,當然還可以確定每個點的權重。
在靠後的位置,我們還可以找到烘焙後的球諧函式的係數。
可以看到9個引數3個通道所以每一個點總共有27個float資料。
綜上,可以看到在使用LightProbe時,計算開銷並不大,相對來說比較大的開銷主要來自對記憶體的佔用。
0x03 修改LightProbe資料 提亮角色
ok,簡單介紹了一下LightProbe的原理以及實現。下面我們還是回到最初的問題,那麼怎麼提亮一個場景內的角色才更加合理一些呢?
事實上我們可以通過修改烘焙後的LightProbe的資料來實現這樣的需求。
可以看到上圖中,角色已經和場景融為了一體。雖然這樣更加真實和符合物理規則,但是我想對很多人來說這顯然不是一個好的效果。角色還是能更加突出的好。
好在Unity提供了獲取烘焙後的LightProbe資料的介面:
var probes = LightmapSettings.lightProbes.bakedProbes;
bakedProbes內儲存的是一堆“SphericalHarmonicsL2”物件,只要修改SphericalHarmonicsL2的縮放比例就可以修改LightProbe所提供的亮度了。
除了修改亮度之外,有時我們也會想讓角色有不同的環境光效果,以更加突出角色。這時我們就可以通過SphericalHarmonicsL2中定義的AddAmbientLight方法來實現了:
probe.AddAmbientLight(color);
提亮和修改環境色之後,我們的角色在場景中就成了下面這樣。比實時光更加自然和開銷更低。
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/
相關文章
- 【面試題】能聊聊你對CAS的理解以及其底層實現原理可以嗎?面試題
- 堆的原理以及實現O(lgn)
- Synchronized的實現原理以及優化synchronized優化
- 紅黑樹的原理以及實現
- 節流原理以及實現
- 聊聊keep-alive元件的使用及其實現原理Keep-Alive元件
- 【Mysql核心技術】聊聊事務的實現原理MySql
- 購物車原理以及實現
- Redis快取何以一枝獨秀?(2) —— 聊聊Redis的資料過期、資料淘汰以及資料持久化的實現機制Redis快取持久化
- Threadlocal的使用以及實現原理總結thread
- 聊聊Seata分散式解決方案AT模式的實現原理分散式模式
- 聊聊 TokenBucket 限流器的基本原理及實現
- 點陣圖(bitmap)原理以及實現
- 防抖原理以及簡單實現
- sql server 2005 資料修改的內部原理SQLServer
- Promise的祕密(Promise原理解析以及實現)Promise
- 資料庫連線池的實現及原理資料庫
- vue資料雙向繫結的實現原理Vue
- 資料庫分散式事務的實現原理!資料庫分散式
- 前端動畫實現以及原理淺析前端動畫
- 聊聊如何實現一個支援鍵值對的SPI
- 聊聊微前端的原理和實踐前端
- 雙向資料繫結實現原理
- 【資料結構】ArrayList原理及實現資料結構
- 資料庫實現原理#4(Hash Join)資料庫
- 幾種排序演算法的原理以及 Java 實現排序演算法Java
- Java實現Web操作介面以及返回資料的翻譯JavaWeb
- Thunk程式的實現原理以及在iOS中的應用iOS
- vue響應式資料的實現原理解析Vue
- Redis的五大資料型別實現原理Redis大資料資料型別
- OpenMP task construct 實現原理以及原始碼分析Struct原始碼
- OpenMP Sections Construct 實現原理以及原始碼分析Struct原始碼
- 資料庫實現原理#1(Nested Loop Join)資料庫OOP
- 資料庫實現原理#3(Merge Join).md資料庫
- 聊聊lodash的debounce實現
- uniapp 實現個人資訊的修改APP
- 萬字長文:聊聊幾種主流Docker網路的實現原理Docker
- 微信域名檢測的機制原理以及實現方式