(七)unity自帶的着色器源碼剖析之——————Unity3D的全局光照和陰影:中篇(光照探針和反射探針)

一、光照探針照明的細節

 1.1 光照探針照明概述

使用光照貼圖可以大幅度提升場景渲染的真實程度,但缺點是光照貼圖無法作用在非靜態的物體上,所以看上去運動的物體和場景就顯得恨不協調。爲了解決這個問題,使用光照探針(probe lighting)技術模擬使用光照貼圖的效果。光照探針大致原理:在某一光照探針的所在位置點上對光照信息進行採樣,然後從該光照探針相鄰的其他光照探針的位置上對光照信息進行採樣,把這些採樣得到的光照信息進行插值運算,便可算出這些光照探針之間某個位置的光照信息。在運行期這些插值的速度很快,可以達到實時渲染的要求。利用光照探針技術可以避免運動的物體的光照效果和整個使用靜態光照貼圖的場景不協調的感覺。

光照探針照明是一種能夠快速而近似地模擬實際光照效果的技術。這種技術適用於類似遊戲等需要實時渲染的應用場合,在這些應用中光照探針通常被應用在人物角色或者一些動態的物體上;還可以向使用了LOD技術的靜態場景提供在渲染不同細節的場景時所需要的光照信息。光照探針技術在運行時的性能很高效,並且它用到的光照信息在運行之前快速地被預計算出來。

從實現技術角度來說,光照探針照明技術對照亮在3D空間中某一個指定點的光照信息在運行前的預計算階段進行採樣,然後把這些信息通過球諧函數進行編譯打包存儲。在遊戲運行時,通過着色器程序可以把這些光照信息編碼快速地重建出光照原始效果。Unity通過Light Probe組件實現光照探針照明技術的。

類似於光照貼圖,光照探針也存儲了場景中照明信息。不同在於光照貼圖存儲的是光線照射到場景物體表面的照明信息,而光探針則存儲的是穿過場景中空白空間的光線信息。使用光照探針照明技術會有一些限制,例如要處理光的高頻信息,球諧函數的階數就要增大,而當提升階數時所需要的性能耗費也會逐步提升。因此Unity在編碼打包光照信息時用的函數都是低階球諧函數,即會忽略光的一些高頻信息。目前Unity使用了三階球諧函數進行處理。

在3D空間中的一個位置點上,因爲有且只使用一個球面表達式用於描述光照,所以光照探針照明技術不適合用於描述光線穿過一個很大的物體時的情況。在這種情況下光照會發生很大變動,從而無法精準地進行模擬。另一個限制就是,因爲球諧函數是在一個球面上對光照信息進行編碼,所以對於一個大型的有着平坦表面的物體,或者是一個有着凹面的物體,光照探針照明技術也是不適用的,如果想在一個大的物體上應用光照探針照明技術,則需要使用Light Probe Proxy Volume組件輔助實現。

光照探針可以用來存儲進入探針所在點的所有照明信息,也可以只存儲由場景內的其他物體表面傳遞過來的間接照明信息。在shader裏使用方式也很靈活,即可以在頂點着色器中用來進行逐頂點光照計算,也可以在片元着色器中結合法線貼圖進行逐片元光照計算,甚至可以在頂點着色器中對光探針提供的間接照明部分進行逐頂點光照計算,在片元着色器中結合法線貼圖對直接照明部分進行逐像素的光照計算。

1.2 在場景中佈置光照探針

光照探針組件不能直接掛接到一個遊戲對象上,通常需要依賴光探針組(light probe group)組件掛接。光探針組組件可以掛在場景中任意一個遊戲對象。當向場景中添加一個光探針組遊戲對象時,場景中黃色小球表示的就是光探針。這些光探針可以在編輯器被編輯,也可以指定它們的位置、數量等。在場景中光探針要達到一定數量才能被正確烘焙。

最簡單的光探針佈局方式是將光探針排列成一個規則的3D網格樣式,這樣的設置方式簡單高效,但是會消耗大量內存,因爲每一個光探針本質上是一個球形的、記錄了當前採樣點周圍環境的紋理圖像。並且如果一片區域的照明信息都差不多,要麼就沒有必要使用大量光照探針。光探針一般用於照明效果突然改變的場合,如從一個較爲明亮的區域進入一個較爲陰暗的區域。

目前Unity3D引擎還不支持所有平面化的光探針組,即光探針不能平坦分佈在一個水平面上,光探針之間在垂直方向上需要有高度差。

1.3 使用光照探針

光照探針在進行插值計算時,需要用空間中的一點來表示這個接受光線的網格位置,一般地都會使用網格包圍盒的中心位置。當然也可以自定義一個接受光線的位置,方法是把場景中的一個遊戲對象的Transform屬性賦值給MeshRenderer組件中的Light Probe Anchor屬性即可。如果一系列在外觀上是連接在一起的,但實質上是相互獨立的,由多個MeshRender一一對應的網格。用這些網格各自的包圍盒中心點當做插值計算點時,光照效果就會在其接縫處斷開,樣子將顯得很突兀,這種使用第三方遊戲對象的Transform作爲插值計算點的方式,就是解決這個問題最好方法。

1.4 光探針代理體

5.4版本後Unity增加了一個光探針代理體(light probe proxy volume,LPPV)的新功能。光探針代理體是一個“解決無法直接使用光探針技術去處理的大型動態的遊戲對象的問題”的組件,如下圖:

Bounding Box Mode屬性用於設置光探針代理體所佔據範圍的邊界,它有3個選項:

Automatic Local:默認屬性,會在遊戲對象自身的局部空間內計算代理體的邊界,經過插值的光探針位置將在這個範圍內產生。如果當前的光探針代理體組件所在的遊戲對象沒有同時綁定有Render子類組件,將會在這個代理體的作用範圍自動生成一個默認包圍盒以對應之。包圍盒會涵蓋當前的Renderer,以及選定了Use Proxy Volume選項的那些子游戲對象中的Renderer所佔據的範圍。

Automatic World:和Automatic Local的屬性類似,當選用此項時,會基於世界空間計算代理體的邊界。

Custom:此模式能讓用戶在編輯器界面上定義代理體的邊界大小。此模式和Automatic Local模式類似,都是在遊戲對象自身的局部空間中設置的。因此需要用戶自行確保當前遊戲對象及其帶有Renderer組件,且啓用了Use Proxy Volume選項的子游戲對象都被自定義的包圍盒給包含住。

Resolution Mode屬性用來指定光探針代理體中的光探針的分佈密度,它有如下兩個選項:

Automatic:默認選項,配合Density屬性,指定了每單位長度中,在x、y、z軸上的光探針的數量計算。所以光探針具體的數量,在指定了Density屬性之後,就取決於邊界的大小。

Custom:自定義,用下拉菜單來設置x、y、z軸上每個光探針的個數。個數從1開始,以2的次方遞增,最大到32。

要啓用光探針代理組件,則需要一個掛上了Renderer子類組件,如MeshRender組件的遊戲對象,並且光探針代理體組件最好和Renderer子類組件掛接在同一個遊戲對象上,如果不是掛接在同一個遊戲對象上,就需要在Renderer組件所在遊戲對象的Inspector面板上顯示地指定引用了哪個光探針代理體,如下圖所示:

二、 反射用光探針

當使用標準着色器時,每一個材質都會有一定程度的高光鏡面反射,以及對周圍環境的環境映射。在硬件性能無法使用實時光線追蹤的情況下,需要預先計算環境的渲染結果緩存到一個立方體貼圖中,然後在運行期根據當前的視點把貼圖中的內容貼到待渲染物體的表面,以產生環境映射效果。

反射探針(reflection probe)動態地產生周圍環境的貼圖,以產生環境映射的效果,要創建一個反射用光探針,可以通過選擇GameObject|Light|Reflection Probe命令,生成一個帶有ReflectionProbe組件的遊戲對象。

反射探針通過渲染立方體貼圖來捕獲環境景象,這意味着它會對場景進行6次渲染,立方體貼圖的每個面渲染一次,默認情況下,其類型設置爲烘焙模式,即將ReflectionProbe組件在Inspector面板上的Type屬性設置爲Baked。ReflectionProbe組件的Type屬性有3個可選項:

1.Baked:在編輯階段生成一個存儲了光探針周圍環境景象的立方體貼圖。設置爲Baked類型的反射探針只能對場景中標記爲Reflection Probe Static的遊戲對象進行取景烘焙,一旦烘焙完成後,立方體貼圖就不會發生變化,所以不會受物體位置的實時變化的影響。還可以像攝像機一樣,指定反射探針的Culling Mask屬性和Clipping Planes屬性將不需要烘焙到貼圖的遊戲對象剔除。

2.Realtime:在運行時生成並更新立方體貼圖,此時對場景中游戲對象進行取景生成時就不僅限於靜態的了。這種比較費性能,刷新光照探針以更新貼圖內容也需要較長耗時,所以可以通過設置Refresh Mode屬性和Time Slicing屬性以控制刷新的時機和頻率。這種模式下也可以通過指定反射用光探針的Culling Mask屬性和Clipping planes屬性將不需要烘焙的遊戲對象剔除。

3.Custom:此模式類似於Baked,在編輯階段生成一個存儲光照探針周圍環境景象的立方體貼圖。但如果此時Dynamic Objects複選框被選中,則沒有標記爲Reflection Probe Static的遊戲對象也能被烘焙到貼圖中。另外,此模式下也可以直接指定一張立方體貼圖作爲渲染用的環境景象。

當一個遊戲對象橫跨了多個反射用光探針時,並且綁定在此遊戲對象上的Mesh Renderer組件上的Reflection Probes屬性項的值不爲Off時,Mesh Renderer組件會自動把遊戲對象所觸及的所有反射探針添加到一個它維護的內部數組中:

Mesh Renderer組件的Reflection Probes選項有4中使用反射探針的方法:

Off:表示不使用反射探針。

Simple:表示只使用內部數組中Weight值最大的反射探針。

Blend Probes:將啓用反射探針,且遊戲對象所佔空間如果和多個反射探針的作用域重疊,則混合只發生在光照探針之間。這種模式適用於室內環境。如果遊戲對象附近沒有反射探針,渲染器將使用天空盒作爲默認反射,但默認反射和反射探針之間不會混合。

Blend Probes and Skybox:將啓用反射探針,且遊戲對象所佔空間如果和多個反射探針的作用區域重疊,則混合能發生在光照探針之間或者光探針與天空盒之間,這種模式適用於室外環境。

Reflection組件有很多屬性暴露出來可供用戶調整:

Importance:此值將影響一個Mesh Renderer組件存儲在內部數組中的多個反射探針它們各自權重值(Weight屬性)的混合比例。當一個遊戲對象處在多個反射探針所框定的作用域時,首先會考慮每個反射探針的Importance屬性值,然後在此基礎上纔會考慮每個反射探針與該遊戲對象之間重疊區域的體積大小。也就是說,Importance屬性值的優先級高於重疊區域體積的計算。

Box Size:用來框定該反射探針的作用範圍立方體的長寬高值,進入此範圍的帶有MeshRenderer組件的遊戲對象會自動和這個反射探針產生關聯。當反射探針Box Projection開啓時,此Box Size屬性值會影響該反射探針的立方體貼圖的貼圖映射效果。

Box Offset:反射探針的作用範圍立方體的中心點相對於其自身transform屬性中的Position值的偏移量。當選中Box Projection時,Probe Origin屬性值會影響該反射探針立方體貼圖的貼圖映射效果。

Box Projection:一般情況下,立方體貼圖上對場景景象進行反射的內容,是假設無限遠的地方都能反射過來並且形成圖像的,並且被反射的物體與該反射探針的距離發生改變時,貼圖中的反射內容不會發生改變。這個特性一般只適用室外場景,而室內場景則要啓用Box projection選項。此選項在shader model3.0及以上可用。允許反射探針僅反射場景中有限距離內的物體,且這些物體與本光照探針的距離發生變化時,反射圖案的內容也同樣發生變化。

ShadowDistance:此參數決定了離光照探針多遠的陰影的陰影將會被反射進立方體紋理貼圖中,此值的特效和Quality Settings面板中的Shadow Distance屬性一樣,數值越小,能反射進貼圖內容中的陰影就越少,如果設置爲0則完全不反射陰影到貼圖內容中。

爲了反射出實際環境,反射探針首先要對天空盒的立方體貼圖進行採樣,這個立方體貼圖就是unity_SpecCube0變量,除了這個變量,unity還提供了一個給反射探針使用的數據,該反射探針使用的立方體貼圖是unity_SpecCube1變量,引擎可以對這兩個反射探針的數據進行混合。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章