unity 烘焙参数 设置_Unity通用渲染管线(URP)系列(九)——点光源和聚光灯
200+篇教程總入口,歡迎收藏:
放牛的星星:[教程匯總+持續更新]Unity從入門到入墳——收藏這一篇就夠了?zhuanlan.zhihu.com本文重點內容:1、支持更多類型的燈光
2、包含實時的點光源和聚光燈
3、為點光源和聚光燈烘焙陰影
4、每個物體限制最多8個其他光源
這是有關創建自定義腳本渲染管道的系列教程的第九部分。它增加了對點光源和聚光燈的實時和烘焙支持,但還沒有實時陰影。
本教程是CatLikeCoding系列的一部分,原文地址見文章底部。本教程使用Unity 2019.2.21f1制作。
點光源和聚光燈的派對1 點光源
到目前為止,我們僅使用了定向光,因為這些光會影響所有事物并且具有無限范圍。而其他光源類型則不同,不會假定它們無限遠,因此它們具有位置并且強度會變化。這需要額外的工作來設置和呈現,這就是我們為此創建單獨代碼的原因。我們從點光源開始,點光源是無限小的點,可以均勻地向所有方向發光。
1.1 其他的燈光數據
與定向燈一樣,我們只能支持有限數量的其他燈光。場景通常包含很多不定向的燈光,因為它們的有效范圍有限。通常,對于任何給定的幀,所有其他光的子集都是可見的。因此,我們可以支持的最大值適用于單個幀,而不適用于整個場景。如果最終我們看到的可見光比最大數量更多,則將被忽略掉。Unity會根據重要性對可見光列表進行排序,因此只要可見光不發生變化,哪些燈被忽略就是一致的。但是,如果確實發生變化(由于相機移動或其他更改),則可能會導致明顯的光過爆的情況。因此,我們不能使用太低的最大值。現在,讓我們同時允許多達64個的其他光源,設置為Lighting中的另一個常量。
就像方向光一樣,我們需要為其他類型的光發送光的數量和光顏色到GPU。而同時,我們還需要發送光的位置。添加著色器屬性名稱和向量數組字段來實現。
在SetupLights中,追蹤其他光數量以及定向光數量。遍歷可見光后,將所有數據發送到GPU。但是,如果我們最終得到零個其他光源,則無需發送數組。而且,現在只包含其他光源而沒有定向光源也很有意義,因此我們也可以跳過發送定向光數組的操作。但不管是不是有光源,我們總是需要將光源數發送出去。
在著色器這邊,定義另一個最大光照值和新的光照數據。
然后定義一個GetOtherLightCount函數,稍后我們將使用它。
1.2 設置點光源
在Lighting中創建一個SetupPointLight方法來設置點光源的顏色和位置。給它與SetupDirectionalLight相同的參數。顏色的設置也是相同的。位置的工作原理類似于方向光的方向,但我們需要本地到世界矩陣的最后一列而不是第三列。
現在,我們還需要調整SetupLights中的循環,以便區分方向光和點光源。一旦達到最大數量的方向光,我們不是像以前一樣再結束循環。相反,我們會跳過方向光繼續循環。對點光源執行相同的操作,同時要考慮其他光源的最大值。讓我們使用switch語句對此進行編程。
1.3 著色
現在,著色器可以使用支持點光源所需的所有數據。要使用它,我們向Light添加一個GetOtherLight函數,其參數與GetDirectionalLight相同。這時,光線的方向會隨每個片元而變化。我們通過將從表面位置到光線的光線歸一化來找到它。因為目前不支持陰影,因此衰減為1。
要應用新的燈光,請在GetLighting中為方向光添加一個循環,然后為所有其他光添加一個循環。盡管循環是分開的,但我們需要為其迭代器變量使用不同的名稱,否則在某些情況下,我們將獲得著色器的編譯器警告。所以我用j代替i作為第二個。
只有點光源,沒有環境光1.4 距離衰減
我們的點光源現在可以工作了,但是它們太亮了。現實中,隨著光遠離其源傳播之后,它會散布開來,變得越來越不集中,因此光越遠,亮度就越低。光線的強度是其中i 為配置強度,d 為距離。
這被稱為平方反比定律。請注意,這意味著在小于1的距離處,強度會變為大于配置的強度。也就是說非常接近燈光的位置變得非常明亮。早先我們推斷,最終使用的光色代表的是從正面照亮的完美白色漫射表面碎片反射時觀察到的光量。對于方向光來說確實如此,但對于其他類型的光,它也專門用于與光之間距離為1的片元。
距離衰減曲線通過計算光的平方來應用距離衰減,并將其倒數用作衰減。為防止潛在的除0操作,請將平方距離的最小值設置為很小的正值。
光隨距離淡化1.5 光范圍
盡管點光源強度現在會迅速衰減,但理論上它們的光仍然會影響所有對象,只是正常時候無法感知。漫反射很快變得不明顯,而鏡面反射在更遠的距離仍然可見。
為了使渲染更真實,我們將使用最大照明范圍參數,超過此范圍我們將使照明強度強制為零。這是不符合現實的,但是這樣設定之后,所有燈光無論距離多遠都總是可視為可見。在增加范圍的情況下,點光源包含在邊界球中,邊界球由其位置和范圍定義。
我們不會突然切斷球體邊界處的光,而是通過應用距離衰減來平滑地將其淡出。Unity的Universal RP和lightmapper的使用
公式,r是光的范圍,所以我們也會使用相同的函數。
距離衰減曲線我們可以將范圍存儲在Light Position的第四個分量位置。以減少著色器的工作量。直接存儲,同樣要避免除0操作。
然后在GetOtherLight中考慮距離衰減。
范圍和距離衰減2 聚光燈
現在,我們來支持聚光燈。點光和聚光燈之間的區別在于,聚光燈的光被限制為圓錐形。實際上,它是一個點光源,該點光源被一個有孔的封閉球包圍。孔的大小決定了光錐的大小。
2.1 方向
聚光燈具有方向和位置,因此向Lighting添加著色器屬性名稱和其他光源方向的數組。
在SetupLights中將新數據發送給GPU。
創建一個SetupSpotLight方法,該方法是SetupPointLight的副本,但它也存儲光的方向。我們可以使用本地到世界矩陣的第三列的求反,類似于定向光。
然后在SetupLights循環中包括一個聚光燈的Case。
在著色器端,將新數據添加到Light中的緩沖區。
并在GetOtherLight中應用spot衰減。我們從簡單地使用spot和光方向的飽和點積開始。這將使光衰減,使其在90°的光點角處達到零,然后照亮所有在燈光前方的物體。
聚光燈2.2 角度
聚光燈有一個角度來控制其光錐的寬度。該角度是從中間開始測量的,因此90°的角度看起來像我們現在的角度。除此之外,還有一個單獨的內角控制光何時開始衰減。Universal RP和lightmapper通過在飽和之前縮放并在點積中添加一些東西來完成此操作,然后對結果求平方。公式大概如下:
,其中d是點乘。
并且
則分別為它們的內角和外角弧度。
角度衰減,內角為0°, 20°, 45°, 70°,外角為90°該函數也可以寫成
,但是通過上面的方式分解,我們可以計算Lighting中的a和b,并通過一個新的點角度數組將它們發送到著色器中。定義數組及其屬性名。
在SetupLights中將數組復制到GPU。
然后在SetupSpotLight中計算值,并將它們存儲在spot angles數組的X和Y分量中。通過VisibleLight結構的spotAngle屬性可以使用外角。但是,對于內角,我們首先需要通過其light屬性檢索Light游戲對象,該對象又具有innerSpotAngle屬性。
為什么內角不存儲在VisibleLight中?可配置的內角是Unity的新增功能。VisibleLight結構可能沒有它,因為它會更改其大小并需要重構Unity內部代碼。
回到著色器,在Light中添加新的數組。
并在GetOtherLight中調整spot衰減。
當前使用的衰減最后,為確保點光源不受角度衰減計算的影響,請將其點角值設置為0和1。
2.3 配置內角角度
聚光燈始終具有可配置的外角,但是在引入Universal RP之前,不存在單獨的內角。結果,默認的燈光檢查器不會暴露內角參數。RP可以進一步修改燈光,因此可以覆蓋燈光的默認檢查器。這是通過創建擴展LightEditor的編輯器腳本并將其賦予CustomEditorForRenderPipeline屬性來完成的。此屬性的第一個參數必須是Light類型。第二個參數必須是我們要覆蓋檢查器的RP資產的類型。讓我們創建一個這樣的腳本,將其命名為CustomLightEditor,并將其放在Custom RP / Editor文件夾中。還給它提供CanEditMultipleObjects,以便它與選定的多個光源一起使用。
要替換檢查器,我們需要重寫OnInspectorGUI方法。但是我們將做最少的工作以暴露內角,因此我們首先調用base方法以正常繪制默認檢查器。
之后,我們檢查是否僅選擇了聚光燈。可以通過一個方便的名為settings的子類屬性來做到這一點,該屬性提供對編輯器選擇的序列化屬性的訪問。用它來檢查我們沒有多種不同的光源類型,并且類型是LightType.Spot。如果是的話,在設置上調用DrawInnerAndOuterSpotAngle以在默認檢查器下方添加一個inner-outer spot angle滑塊。然后,調用ApplyModifiedProperties以應用對該滑塊所做的任何更改。
不同的內角度3 烘焙光和陰影
在本教程中,我們不會涵蓋點光源和聚光燈的實時陰影,但是現在我們先支持烘焙這些光源類型。
3.1 全烘焙
完全烘焙點和聚光燈只需將其Mode設置為Baked即可。請注意,默認情況下,它們的Shadow Type設置為None,因此,如果要將它們與陰影一起烘焙,請將其更改為其他內容。
實時光和烘焙光,只有點光源和聚光燈生效盡管現在已經足以烘焙這些光源,但事實證明它們在烘焙后太亮了。發生這種情況的原因是,默認情況下Unity使用不正確的光衰減,與傳統RP的結果相匹配。
3.2 燈光代理
通過提供一個方法的委托,可以告訴Unity使用不同的衰減,該方法應在Unity在編輯器中執行光照映射之前被調用。為此,請將CustomRenderPipeline轉換為局部類,并在其構造函數的末尾調用當前不存在的InitializeForEditor方法。
然后為它創建另一個特定于編輯器的局部類(就像CameraRenderer一樣),該類為新方法定義了一個默認的模板。除了UnityEngine命名空間外,我們還需要使用Unity.Collections和UnityEngine.Experimental.GlobalIllumination。這將導致LightType發生類型沖突,因此請為其明確使用UnityEngine.LightType。
針對編輯器,我們需要重寫光照貼圖器以解決如何設置其光照數據。通過為它提供方法的委托來完成,該方法將數據從輸入Light數組傳輸到NativeArray
我們還需要為每個光源配置一個LightDataGI結構,并將其添加到output中。我們需要為每種光源類型使用特殊的代碼,因此需要在循環中使用switch語句。默認情況下,我們在燈光數據上調用帶有燈光實例ID的InitNoBake,這指示Unity不烘焙燈光。
接下來,對于每種受支持的光源類型,我們需要構造一個專用的light結構,調用LightmapperUtils.Extract,以light和對該結構的引用作為參數,然后在光源數據上調用Init,并通過引用傳遞該結構。對方向光,點光源,聚光燈和區域光執行此操作。
因為我們尚不支持實時區域光,因此,如果存在,請強制將其light模式設置為烘焙。
現在只是我們必須包含的模板代碼。所有這些的重點是,我們現在可以對所有的燈光設置光數據的falloff類型為 FalloffType.InverseSquared。
要讓Unity調用我們的代碼,請創建一個InitializeForEditor的編輯器版本,該編輯器以我們的委托作為參數來調用Lightmapping.SetDelegate。
當我們的管道被處理時,我們還需要清理并重置委托。這是通過重寫Dispose方法,讓其調用其基本實現以及Lightmapping.ResetDelegate來完成的。
正確的衰減烘焙不幸的是,Unity 2019.2光照貼圖器不支持聚光燈的自定義內衰減角度。可以設置內spot角度,但它會被忽略。
光照貼圖程序可以在更高版本的Unity中使用內Spot角度嗎?
是的,從Unity 2019.3開始,AngularFalloffType存在,你可以執行以下操作:
3.3 陰影遮罩
通過將點光源和聚光燈的Mode設置為Mixed,也可以將它們的陰影烘焙到Mask中。就像方向光一樣,每個光都有一個通道。但是因為它們的范圍有限,所以只要它們不重疊,就有可能多個光源使用相同的通道。因此,Mask可以支持任意數量的光,但每個紋理像素最多只能支持四個。如果在嘗試聲明同一通道時多個光最終重疊,則最不重要的光將被強制為Baked模式,直到不再有沖突為止。
一個點光源和一個聚光燈的陰影遮罩要將陰影遮罩用于點光源和聚光燈,請向Shadows添加ReserveOtherShadows方法。它的工作方式與ReserveDirectionalShadows相似,只是我們只關心陰影遮罩的模式,只需要配置陰影強度和Mask通道。
將陰影數據的著色器屬性名稱和數組添加到Lighting。
在SetupLights中將它發送給GPU。
并在SetupPointLight和SetupSpotLight中配置數據。
在著色器端,向陰影添加一個OtherShadowData結構和GetOtherShadowAttenuation函數。再次,我們使用與定向陰影相同的方法,只是我們只有強度和遮罩通道。如果強度為正,則我們總是調用GetBakedShadow,否則沒有陰影。
在Light中,添加陰影數據并將其分解為GetOtherLight中的衰減。
點光源和聚光燈 烘焙了陰影4 逐物體的光源
當前,將對每個渲染的片元評估所有可見光。這對于方向光源很好,但是對于超出片元范圍的其他光源則是不必要的工作。通常,每個點光或聚光燈只會影響所有片元的一小部分,因此,許多工作都是徒勞無功的,這可能會嚴重影響性能。為了支持許多性能良好的燈光,我們需要以某種方式減少每個片元評估的燈光數量。為此,有多種方法,其中最簡單的方法是使用Unity的per-object光照索引。
這個想法是由Unity確定哪些燈光會影響哪些對象并將此信息發送到GPU。然后,我們可以在渲染每個對象時僅評估相關的燈光,而忽略其余的燈光。因此,燈光是基于每個對象而不是每個片元確定的。通常,這對于小型物體而言效果很好,但對于大型物體而言并不理想,因為如果光線僅影響物體的一小部分,則仍然需要對其整個表面進行評估。另外,可以影響每個物體的光線數量是有限制的,因此大型物體更容易缺少燈光。
由于per-object的光線指標不是理想的,可能會錯過一些燈光,因此我們將其設為可選。這樣,還可以輕松比較視覺效果和性能。
Unity的基于對象的燈光索引代碼是不是中斷過很多次?是的,自Unity 2018以來,它已經被中斷過了好幾次,有時幾個月了,它導致了很多錯誤。這是使其成為可選的另一個原因。
4.1 逐物體的燈光數據
向CameraRenderer.DrawVisibleGeometry添加一個布爾參數,以指示是否應使用lights-per-object模式。如果是,請為圖形設置的每個對象數據啟用PerObjectData.LightData和PerObjectData.LightIndices標志。
必須將相同的參數添加到Render,以便可以將其傳遞到DrawVisibleGeometry。
而且,我們還需要追蹤和傳遞CustomRenderPipeline中的模式,就像其他布爾選項一樣。
最后,將切換選項添加到CustomRenderPipelineAsset。
Lights per object 開啟4.2 過濾燈光索引
Unity只是創建每個對象所有活動光源的列表,并按其重要性大致排序。此列表包括所有燈光,無論它們是否可見,當然包含方向燈光。我們需要清理這些列表,以便僅保留可見的非方向光的索引。我們在Lighting.SetupLights中執行此操作,因此向該方法中添加一個lights-per-object參數,并向Lighting.Setup添加該參數。
然后在camerarder . render中添加模式作為設置參數。
在Lighting.SetupLights中,在循環到可見光之前,請從剔除結果中檢索光索引圖。這是通過使用Allocator.Temp作為參數調用GetLightIndexMap來完成的,這為我們提供了一個臨時的NativeArray
我們僅在使用lights per object時才需要檢索此數據。由于NativeArray是一個結構,因此我們將其初始化為默認值,否則它將不分配任何內容。
我們只需要包含的點光源和聚光燈的索引,應該跳過所有其他類型的光源。通過將所有其他燈光的索引設置為-1來傳達給Unity。我們還需要更改其余燈光的索引以匹配我們的索引。僅在我們檢索Map時設置新索引。
我們還需要消除所有不可見光的索引。如果我們使用lights per object,請執行第二個循環,該循環在第一個循環之后繼續進行。
完成后,我們必須通過在剔除結果上調用SetLightIndexMap將調整后的索引Map發送回Unity。此后不再需要IndexMap,因此我們應該通過在其上調用Dispose來對其進行釋放。
最后,當使用lights per object時,我們將使用不同的著色器變體。通過適當地啟用或禁用_LIGHTS_PER_OBJECT著色器關鍵字來決定。
4.3 使用索引
要使用燈光索引,請將相關的多編譯編譯指示添加到我們的Lit著色器的CustomLit的Pass中。
所需數據是UnityPerDraw緩沖區的一部分,由必須在unity_WorldTransformParams之后直接定義的兩個real4值組成。首先是unity_LightData,它包含其Y分量中的燈光量。之后是unity_LightIndices,它是長度為2的數組。兩個向量的每個通道都包含一個光索引,因此每個對象最多支持八個。
如果定義了_LIGHTS_PER_OBJECT,則對GetLighting中的其他燈光使用替代循環。在這種情況下,可以通過unity_LightData.y找到燈光量,并且必須從unity_LightIndices的適當元素和組件中檢索燈光索引。可以通過將迭代器除以4并通過取模4得到正確的分量來獲得正確的向量。
但是,盡管最多只有8個光索引可用,但是提供的光計數并未考慮此限制。因此,我們必須將循環明確地限制為八個迭代。
是否有緩沖方法不限于每個對象八個燈?曾經有,但是該代碼自Unity 2018.3起已被禁用,并且已從Universal RP中部分刪除。死代碼已經有一年多了,所以我不會再依賴它了。Lights-per-object 沒有開啟和開啟
請注意,啟用Lights-per-object后,GPU實例化效率較低,因為燈光計數和索引列表匹配的對象才會分組。SRP批處理程序不受影響,因為每個對象仍然獲得自己的優化后的DrawCall。
下一章,點光和聚光燈陰影。
本文翻譯自 Jasper Flick的系列教程
總結
以上是生活随笔為你收集整理的unity 烘焙参数 设置_Unity通用渲染管线(URP)系列(九)——点光源和聚光灯的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2个td合成一个td_18个月16个爆款
- 下一篇: 蓝牙 AVRCP 剖析