Unity可编程渲染管线系列(六)透明度(裁剪与淡化 Clipping and Fading)
目錄 | 1 Alpha裁剪 1.1 Alpha貼圖 1.2 紋理化 1.3 丟棄片段 1.4 裁剪陰影 1.5 雙面渲染 1.6 給背面翻轉法線 1.7 可選的裁剪 1.8 Alpha-Test渲染隊列 2 半透明 2.1 混合模式 2.2 透明渲染隊列 2.3 不寫入深度 2.4 雙面材質的半透明 2.5 制作一個雙面mesh 2.6 Alpha-Clipped 陰影 2.7 接受陰影 3 Shader GUI 3.1 投射陰影 3.2 設置著色器屬性 3.3 預設 |
本文重點:
1、執行alpha裁減
2、渲染mesh的兩個面
3、支持不同的混合模式
4、生成雙面mesh
5、根據預設創建ShaderGUI
這是涵蓋Unity的可腳本化渲染管道的教程系列的第六部分。這是關于增加對alpha裁剪和半透明材質的支持。
本教程是CatLikeCoding系列的一部分,原文地址見文章底部。“原創”標識意為原創翻譯而非原創教程。
本教程使用Unity 2018.3.0f2制作。
(混合使用不透明,裁減和淡化的材質,所有都帶有投射和接收陰影)
1 Alpha裁剪
如渲染11透明度中所述,可以通過丟棄基于alpha貼圖的片段來在幾何圖形中切孔。此技術稱為Alpha裁剪,Alpha測試或 (剪切)cutout渲染。除此之外,它與渲染不透明幾何體完全相同。因此,要支持Alpha裁剪,我們只需要調整著色器即可。
1.1 Alpha貼圖
僅當材質的Alpha值在其整個表面變化時,Alpha裁剪才有用。最簡單的方法是使用Alpha貼圖。這有兩種紋理,一種用于正方形幾何體(例如方形和立方體),一種用于球體。
(立方體和球體的alpha貼圖,空白的是原圖,新標簽頁中查看圖片)
導入這些紋理,并指示其Alpha通道代表透明度。它們的RGB通道是均勻的白色,因此不會影響材質的外觀。
(Alpha是透明的)
1.2 紋理化
將一個主紋理屬性添加到“ Lit”著色器。我們將使用它作為反照率和Alpha的源,默認為純白色。
使用適當的紋理,創建兩種新材質,一種用于發光的alpha剪切球體,另一種用于發光的剪切正方形。
(lit clipped square材質)
在Lit include文件中,添加主紋理及其采樣器狀態的聲明。這類似于陰影貼圖,但使用TEXTURE2D和SAMPLER宏。
我們需要UV紋理坐標進行采樣,這是網格數據的一部分。因此,將它們添加到頂點輸入和輸出結構。
要應用紋理的平鋪和偏移,請在UnityPerMaterial緩沖區中添加所需的_MainTex_ST著色器變量。然后,當在LitPassVertex中傳輸UV坐標時,可以使用TRANSFORM_TEX宏。
現在,我們可以使用SAMPLE_TEXTURE2D宏在LitPassFragment中對主貼圖進行采樣,以獲取反照率和Alpha數據,將其與顏色數據相乘。從現在開始,我們還將返回alpha值。現在不需要,但是以后會使用。
1.3 丟棄片段
當片段的alpha值低于某個臨界值時,通過丟棄片段來進行alpha裁剪。截止值位于0到1之間,并且是可配置的,因此請為其添加一個著色器屬性,默認值為?。
將相應的變量添加到UnityPerMaterial緩沖區。然后使用片段的alpha值減去閾值調用clip函數。這將導致所有最終低于閾值的片段被丟棄,這意味著它們不會被渲染。
(alpha裁剪之后的球體和立方體)
現在,將使用具有Alpa材質的對象渲染帶有孔的對象。孔的大小取決于裁剪值。但是,這僅適用于對象表面本身。它們投射的陰影仍然是實體的,因為我們尚未對其進行調整。
1.4 裁剪陰影
剪切陰影的工作方式與lit通道中的剪切完全相同,因此請相應地調整ShadowCaster包含文件。因為最終的alpha值取決于主貼圖和材質顏色,所以我們現在還必須在ShadowCasterPassFragment中對實例化的顏色進行采樣,因此也需要傳遞實例ID。
(剪切陰影)
1.5 雙面渲染
因為僅渲染了幾何圖形的正面,所以我們的Alpha剪切對象缺少背面。當圍繞它們旋轉視圖時,這會顯而易見。而且,它們的陰影與我們看到的并不匹配,因為只有相對于光源的前側會投射陰影。解決方案是渲染幾何圖形的兩面,使我們能夠看到對象表面的內部并使內部表面投射陰影。
渲染哪一側由著色器的剔除模式控制。要么不進行剔除,要么對所有正面三角形進行剔除,要么對所有背面三角形進行剔除。我們可以添加一個浮點著色器屬性,該屬性表示一個枚舉值,默認值為2,對應于通常的背面剔除。
通過將枚舉屬性添加到該屬性,我們可以通過枚舉彈出窗口公開此屬性。可以將所需的枚舉類型作為參數提供,在本例中為UnityEngine.Rendering命名空間中的CullMode。
(禁用剔除)
雖然我們已將其定義為著色器屬性,但著色器程序并未直接使用剔除模式。GPU使用它來決定將哪些三角形傳遞給片段程序以及將哪些三角形丟棄。我們通過著色器遍歷中的Cull語句來控制它。如果我們使用固定的剔除模式,則可以滿足諸如“Cull Off ”之類的要求,但是我們也可以通過編寫Cull [_Cull]使其依賴于著色器屬性。兩次都執行此操作。
(雙面渲染)
1.6 給背面翻轉法線
現在,我們看到了幾何圖形的兩面,但內部照明不正確。通過把我們的材質剔除正面比較容易看出來,讓我們只看到內部。
(只渲染背面,不正確的光照)
事實證明,燈光是翻轉的。亮的地方本應該是暗的,反之亦然。這是因為法向向量是用于外部而不是內部的。因此,渲染背面時,我們必須取反法線向量。
GPU可以告訴片段程序是否著色正面或背面的片段。我們可以通過向LitPassFragment添加一個附加參數來訪問此信息。此參數的類型和語義取決于API,但是我們可以使用Core庫中的FRONT_FACE_TYPE和FRONT_FACE_SEMANTIC宏。同樣,我們可以使用IS_FRONT_VFACE宏根據要處理的是正面還是背面來選擇兩個選項。必要時可使用它來抵消法向矢量。
(背面VS全部 正確的光照)
現在,內部表面已正確著色,單由于自陰影的問題其最終仍比外部更暗。
為什么陰影有時會忽略裁剪(Clip)模式?
渲染陰影時始會終應用剪輯模式。但是,因為對象使用不同的材質,Unity也會主動批處理陰影投射器,并且在這么做時會忽略剪輯模式。這意味著當你混合使用除裁剪模式之外相同的陰影投射器時,整個裁剪將使用哪種裁剪模式是任意的。由于為每個著色器都設置了裁剪模式,所以不能逐示例修改。
你可以通過在渲染陰影時禁用實例化和批處理來避免此問題。但這不是一定成功的,因為具有不同裁剪模式的材質可能具有其他相關特性,這些特性也有所不同,從而阻止了批處理。稍微不同的cutoff值可以防止錯誤的批處理。
1.7 可選的裁剪
使用alpha裁剪時,GPU無法再假定整個三角形都已渲染,這使得某些優化無法實現。因此,最好僅在必要時啟用alpha裁剪。因此,我們將創建兩個著色器變體:一個帶著色器裁剪,一個不帶。可以使用shader關鍵字來做到這一點,就像管道控制是否使用陰影一樣,但這次我們將通過material屬性來控制它。
添加一個toggle屬性,以控制對著色器的剪輯。它必須是浮點數,默認值為零。給它一個Toggle屬性,它將使它顯示為一個復選框。除此之外,可以為屬性提供一個關鍵字,該關鍵字在更改屬性時會啟用或禁用。我們將使用_CLIPPING關鍵字。
(裁剪啟用)
現在,我們可以添加另一個多編譯語句,但是可以預期,此切換不會在運行過程中更改,而只會在編輯素材資源時更改。因此,我們不必總是為這兩個選項生成著色器變體。可以通過使用#pragma shader_feature指令來實現。如果只使用一個切換關鍵字,我們只需列出該關鍵字即可,僅此而已。兩次都執行此操作。
使用shader feature有什么優勢?
無論在編輯器中編譯著色器還是將其放入構建中時,都必須始終包含所有多編譯著色器變體。在Unity編輯器可以確定的范圍內,shader feature替代項僅包括實際需要的變體。這可以大大減少著色器的編譯時間和構建的大小。
使用多重編譯方法的唯一原因是在運行過程中啟用了哪些關鍵字的更改。例如shadow關鍵字,但是如果你在運行過程中配置材質,也可以使用true。
現在,我們可以確保僅在定義_CLIPPING關鍵字的情況下才剪切Lit。
ShadowCaster也是如此。
請注意,我們也可以通過消除UV坐標來進一步優化,但是優化的重要性不大,因此我將不予贅述。同樣,你可以使用著色器特性(shader feature)僅在關閉裁剪時檢查三角形的朝向,這是我沒有介紹的另一種優化。
1.8 Alpha-Test渲染隊列
除了可能丟棄的片段以外,alpha剪切渲染的工作方式與不透明渲染相同,并且可以將兩者混合在一起而不會出現問題。但是由于alpha裁剪會阻止某些GPU優化,因此通常在渲染所有alpha裁剪的對象之前先渲染所有純不透明的對象。這樣可以實現最大程度的GPU優化,隨著更多的最終隱藏在不透明的幾何圖形后面的透明片段,潛在地減少了alpha剪切片段的數量,并且還可以減少批處理數量。所有這些都可以通過簡單地設置alpha裁剪的材質以使用更高的渲染隊列來完成。默認的材質檢查器會顯示隊列,因此我們可以手動更改它。Alpha裁剪材質的默認隊列為2450,與下拉菜單中的AlphaTest選項相對應。
(使用alpha-test 隊列)
2 半透明
如果片段沒有被剪切,則它是完全不透明的。因此,可以使用alpha剪切在對象上切割孔,但它不能表示半透明的表面。在著色器支持半透明之前,我們還有更多工作要做。
2.1 混合模式
當某些東西是半透明的時,它至少會讓部分的光通過。為了讓著色器實現這一點,必須更改片段自身的顏色與之前渲染的顏色混合的方式。可以通過更改著色器的混合模式來實現。
混合模式的控制類似于剔除模式,但具有兩個用于混合新舊顏色的權重選項。第一個稱為源,即我們現在正在渲染的東西,第二個稱為目標,即以前渲染的東西。例如,默認的混合模式是“Blend One Zero ”,這意味著新顏色完全替代舊顏色。
alpha通道也沒有單獨的選項嗎?
有,但是很少使用。如果未明確指定Alpha的混合模式,則將所有四個通道以相同方式混合。
就像剔除一樣,為源和目標混合添加兩個著色器屬性,但BlendMode枚舉類型除外。將其默認值設置為1和0。
僅向lit pass 添加混合聲明。ShadowCaster 通道 僅關心深度,因此混合模式不會對其產生影響。
半透明的最簡單形式是根據其alpha值使片段淡化。這是通過使用源的Alpha作為源的權重,再減去源的Alpha作為目標的權重來完成的。我們可以從下拉菜單中選擇這些選項。對新的淡化材質執行此操作,并關閉它們的剔除。
(混合模式設置為淡入淡出 不正確的結果)
也有很多其他混合模式。大多數很少使用,但有些用于不同類型的透明度。例如,pre-multiplied 混合使用1作為源而不是源的Alpha。這樣就可以保持鏡面反射(以表示玻璃之類的表面),但也需要對著色器進行一些更改,在此不做介紹。
2.2 透明渲染隊列
僅當正在渲染的內容背后有東西時,淡入淡出(fading)才有效。我們的管道已經解決了這個問題,首先呈現不透明隊列,然后呈現天空盒,最后呈現透明隊列。我們的淡入淡出材質只需要使用正確的隊列即可。默認的“Transparent ”選項很好。
(移動透明隊列,仍然不正確)
2.3 不寫入深度
現在,半透明有時可以正常工作,但也會產生奇怪的結果。這里要主要的是,因為我們仍在投射陰影,好像表面是不透明的一樣。發生這種情況是因為我們沒有剔除,所以表面的兩面都被渲染。首先渲染哪個部分取決于網格的三角形順序。當正面的三角形先渲染時,還沒有可與之融合的背面。背面不會被渲染,因為它位于已經渲染的東西后面。
當兩個單獨的透明對象彼此靠近時,也會發生相同的問題。Unity對透明對象進行從前到后排序,這是正確的,但它只能考慮對象位置,而不能考慮形狀。首先繪制的對象的一部分仍可以終止于后來繪制的對象的前面。例如,在場景中放置兩個兩個大部分重疊的四邊形,一個在另一個四邊形上,然后調整視圖,直到最上面的一個首先被渲染。
(上面的四邊形先被繪制)
我們無法避免這種情況,除非仔細控制半透明對象的位置或使用具有不同渲染隊列的材質。如果對象與具有任意三角形順序的雙面材質相交,它將始終會出錯。但是我們可以做的是禁用對透明材質的深度緩沖區的寫入。這樣,首先渲染的內容將永遠不會阻塞隨后渲染的內容。
添加另一個浮動著色器屬性以控制Z編寫,默認情況下該屬性處于啟用狀態。我們可以再次使用切換,但這將始終產生一個關鍵字,而這種情況下我們不需要。因此,我們改為通過編寫[Enum(Off,0,On,1)]使其具有關閉和打開狀態的自定義枚舉。
僅將ZWrite控件添加到lit pass中,這再次與陰影無關。
(不寫入深度緩沖)
現在,即使四邊形的繪制順序不正確,它們也會完全渲染。但是,底部四邊形仍在頂部四邊形之后繪制,因此它仍然不正確。方形的實心陰影讓情況更加惡化。當繪制順序翻轉時,這也非常明顯。這是設計場景時必須牢記的透明渲染的局限性。
2.4 雙面材質的半透明
禁用Z寫入功能后,關閉剔除時始終會渲染對象的內部。但是,繪制順序仍然由網格的三角形順序確定。使用默認的球體和立方體時,一定會產生不正確的結果。
(雙面,不寫入深度緩沖)
對于任意網格,確保首先繪制背面的唯一方法是復制對象并使用兩種材質,一種材質是剔除正面,另一種材質是剔除背面。然后調整渲染隊列,以便首先繪制內部。
(內部和外部分開的對象和材質)
這適用于單個對象,但是當多個這樣的對象在視覺上重疊時無效。在這種情況下,所有外部都會被繪制到所有內部之上。
(立方體的外部在球體里面之上)
2.5 制作一個雙面mesh
渲染雙面半透明表面的最佳方法是使用為此目的專門創建的網格。網格的內部和外部必須包含單獨的三角形,并按順序排列,以便首先繪制內部。即使這樣,這也只能可靠地用于不會在視覺上重疊的凹入對象。
你可以使用單獨的3D建模器創建雙面網格,但是我們也可以在Unity中制作一個簡單的工具來快速生成任何源網格的雙面變體。為此,創建一個靜態DoubleSidedMeshMenuItem類,并將其資產文件放在Editor文件夾中。我們將使用它來將Assets Create Double-Sided Mesh項目添加到Unity的菜單中。這是通過將MenuItem屬性添加到靜態方法,并以所需的項目路徑作為參數來完成的。
這個想法是,用戶首先選擇一個網格,然后激活菜單項,然后我們將創建其雙面等效項。因此,第一步是獲取對選定網格的引用,這是通過Selection.activeObject完成的。如果沒有選定的網格,請指示用戶選擇一個網格并中止。
as是干嘛的?
如果可能,它將強制轉換為指定的類型。否則,結果為null。請注意,這僅適用于引用類型。
我們首先創建網格的內部。通過實例化克隆源網格,檢索其三角形,通過System.Array.Reverse反轉其順序,然后將結果分配回去。翻轉所有三角形的面。
接下來,檢索法線,取反法線,然后將其分配回去。
然后創建一個新的網格并在其上調用CombineMeshes。它的第一個參數是CombineInstance結構的數組,只需要引用相關的網格即可。首先是內部網格,然后是源網格。這樣可以保證先繪制內部三角形。之后是三個布爾參數。第一個必須為true,表示必須將網格合并為單個網格,而不是定義多個子網格。另外兩個是我們不需要的矩陣和光照貼圖數據。
完成后,我們不再需要內部網格,因此請立即銷毀它。
最后,通過調用AssetDatabase.CreateAsset創建一個網格資產。它的第一個參數是組合網格,第二個參數是資產路徑。我們將其簡單地放在資產根文件夾中,并為其賦予與附加了雙面的源網格相同的名稱。路徑和文件名可以通過System.IO.Path.Combine方法進行組合,因此無論你的操作系統使用哪個路徑分隔符,它都可以工作。而且我們需要使用 asset 作為文件擴展名。
現在我們可以選擇任何網格并為其創建雙面變體。你可以通過選擇使用該網格物體的游戲對象并在網格物體渲染器組件中雙擊其引用來選擇默認球體或立方體。生成的資產看起來像導入的網格物體,因為它們是自定義資產,但是可以正常工作。我們可以將這些網格物體用于透明對象,并將淡入淡出材質切換為背面剔除。
(使用雙面網格)
2.6 Alpha-Clipped 陰影
到現在為止,我們都忽略了陰影,因此我們的半透明對象仍會投射陰影就好像自己是不透明一樣。他們也會收到陰影,但這還好。
透明物體可以接收陰影嗎?
是的。接收陰影所需要做的就是確定片段與光源之間是否存在陰影投射器,陰影貼圖會告訴我們。片段是用于不透明表面還是透明表面都無關緊要。話雖如此,Unity不支持與級聯陰影貼圖結合使用的透明表面陰影接收。這是因為Unity在單獨的全屏通道中采樣了級聯的陰影貼圖,該通道依賴于深度緩沖區,因此無法與透明度結合使用。當采樣每個片段的所有陰影時,我們沒有該限制。
陰影貼圖不能表示部分陰影。我們能做的最好的就是使用alpha裁剪的陰影。當前,可以對透明材質啟用Alpha裁剪,但這也會影響表面本身。
(淡入淡出加上裁剪)
只能對陰影執行alpha裁剪。我們可以通過使用三個選項替換裁剪開關來支持這一點:關閉,打開和陰影。首先,關閉當前使用它的所有材料的裁剪,以便清除_CLIPPING關鍵字。然后,使用三個選項作為參數,用KeywordEnum替換切換。
現在你可以重新打開裁剪了。我們這樣做是因為KeywordEnum使用不同的關鍵字。現在使用的關鍵字是通過使用著色器屬性名稱,下劃線,然后每個選項分別大寫而形成的。因此,在光照階段,我們必須更改著色器功能以改為依靠_CLIPPING_ON。
還要調整關鍵字檢查。
ShadowCaster通道現在啟用或設置為陰影時,現在必須使用剪輯。換句話說,它關閉時不應該剪切。我們將為著色器功能使用后一個條件,因此我們僅依靠_CLIPPING_OFF。
因此,我們現在必須檢查是否未定義_CLIPPING_OFF。
這使得透明材質可以投射alpha剪切的陰影。這不是一個完美的匹配,但它易于支持并且在某些情況下可能已經足夠。
(帶有陰影裁減的淡入淡出,cutoff為0.75)
如果不需要,可以關閉每個對象的陰影投射。我們還將應用在以后的每種材質中。
有沒有辦法創建半透明陰影?
Unity的舊版管道具有渲染半透明陰影的選項,如渲染12,半透明陰影中所述。它通過抖動陰影,基于alpha和屏幕空間抖動模式裁剪陰影,依靠過濾來模糊結果來偽造半透明。在某些有限的情況下,它可以產生令人信服的陰影,但總的來說,結果比較糟糕糟糕,以至于無法實際使用。
2.7 接受陰影
透明的表面可以很好地接收陰影,但這可能是不希望的。因此,通過添加鏈接到_RECEIVE_SHADOWS關鍵字的著色器屬性開關(默認情況下處于啟用狀態),使它成為可選的。
將其著色器功能添加到lit pass。
如果未定義_RECEIVE_SHADOWS關鍵字,只需在ShadowAttenuation和CascadedShadowAttenuation中返回1。
進行這些更改后,即使所有材質都啟用了陰影,所有陰影也會消失。發生這種情況是因為向著色器添加新屬性不會自動啟用相關關鍵字。選擇所有材質并切換選項將同步屬性及其關鍵字。相反,當創建新材質時,將立即正確設置其鏈接到屬性的所有關鍵字。
(投射,但是不接受陰影)
3 Shader GUI
雖然現在可以使用我們的著色器創建不透明和透明材質,但我們必須手動選擇正確的混合模式,以及相似的情況處理。Unity的著色器檢查器隱藏了這些詳細信息,而是顯示受支持的表面類型的下拉菜單。通過為材質創建自定義著色器GUI,我們可以做類似的事情。
ShaderGUI定義了一個OnGUI方法,該方法將被調用以創建材質的檢查器。它具有MaterialEditor參數,該參數是跟蹤正在編輯的材質的基礎對象。它還具有一個MaterialProperty數組參數,該參數包含對所選材質的所有著色器屬性的引用。必須重寫此方法才能創建自己的GUI,但是不會替換默認的GUI,只需添加它即可。因此,我們的方法將調用ShaderGUI的 base OnGUI實現。
為什么會有單獨的材料編輯器?
最初,為材質創建自定義檢查器的方法是擴展MaterialEditor。ShaderGUI方法后來出現,并且更加直接和專注于材質。但是,原始的編輯器功能仍用于生成檢查器。它只是調用著色器GUI的適當方法。通過參數提供編輯器,因為直接操縱選定的材質需要它。
要使用我們的自定義GUI,我們必須在我們的Lit著色器中添加一個CustomEditor語句,然后是一個包含類名的字符串。
為了完成我們的自定義工作,我們需要使用編輯器,屬性和選定的材質,因此讓我們跟蹤那些帶有字段的材質。因為我們將支持多材質編輯,所以我們必須處理一系列選定的材質。可以通過編輯器的targets屬性檢索它們。但是,由于編輯器是通用的,所以我們得到一個Object數組,而不是Material數組。
3.1 投射陰影
讓我們開始禁用每種材質的陰影投射。這是通過對所有選定的材質禁用ShadowCaster傳遞來完成的。可以通過遍歷材質數組并在每個數組上調用SetShaderPassEnabled來實現此目的,附帶通道名稱以及是否應啟用它的參數。將該代碼放入帶有通道和啟用狀態作為參數的SetPassEnabled方法中。
foreach如何工作?
這是for循環的方便替代方法。在這種情況下,它與以下代碼相同:
通常,foreach依靠迭代器對象來完成其工作,因此分配臨時內存。但是,在顯式遍歷數組時不會執行此操作。在那種情況下,根據上面的示例,代碼有效地轉換為簡單的for循環。
除此之外,我們需要確定是否啟用陰影投射。我們可以通過在材質上調用GetShaderPassEnabled進行檢查。為此,創建另一個方法,檢查選擇的第一個材質。
但是,如果選擇了多種材質,我們可能會得出不同的結果。我們不能用一個布爾值來表示。因此,讓我們返回一個可為空的布爾值。然后,我們可以遍歷所有其他材質,如果發現不一致,則將返回null。
什么是可空(nullable )類型?
可以通過在類型名稱后面寫一個問號來創建結構類型的可為空的變體。該結構將結構包裝在另一個結構中,該結構具有一個額外的布爾值以指示它是否被認為具有值。因此,它實際上不能設置為null,但是有一種語法糖可以讓我們為它分配null,這將其標記為沒有值。
在我們的例子中,我們最終得到一個具有兩個布爾值的結構,類似于以下代碼,以及自定義賦值運算符:
現在,我們可以創建一個方法,該方法負責顯示用于投射陰影的切換選項。首先,檢查是否啟用了ShadowCaster傳遞。如果沒有得到值,則將EditorGUI.showMixedValue設置為true,以指示輸入控件應繪制其自身的混合值表示形式。我們還必須將啟用狀態設置為某種狀態,可以是任何一種,因此只需使用false。在該方法的最后,我們應該禁用混合值表示。
可以通過調用EditorGUILayout.Toggle顯示帶有Cast Shadows標簽和啟用值的復選框。將其結果分配回啟用狀態。
那只會改變我們的變量。要調整材質,我們必須調用SetPassEnabled。但是我們只能在用戶更改狀態時執行此操作。我們可以通過在切換之前調用EditorGUI.BeginChangeCheck并在切換之后調用EditorGUI.EndChangeCheck來確保這一點。后面的調用返回是否在兩者之間進行了更改。如果是這樣,請調用SetPassEnabled。
因為我們直接更改材質資產,所以不會自動生成撤消步驟。在進行更改之前,需要自己通過在編輯器上使用label參數調用RegisterPropertyChangeUndo來做到這一點。
最后,調用該方法以在OnGUI的末尾顯示切換。這會使切換顯示在材質檢查器的底部。
(沒有投射陰影 逐材質控制)
3.2 設置著色器屬性
從不透明的表面更改為修剪或褪色的表面需要更改多個著色器屬性。我們將通過為需要的屬性添加setter屬性來使此操作變得方便。cull,blend和z-write屬性非常簡單。對屬性使用適當的類型,以其名稱和屬性數組作為參數調用FindProperty,然后將其分配給其floatValue屬性。
剪輯模式和陰影接收屬性需要更多工作,因為它們需要與著色器關鍵字同步。可以通過在材質上調用EnableKeyword為材質啟用關鍵字。禁用它需要調用DisableKeyword。我們必須對所有選定的材質執行此操作。為此創建一個方便的方法,以關鍵字名稱和啟用狀態作為參數。
現在,我們可以添加用于裁剪和陰影接收的setter屬性,并為所有相關關鍵字調用SetKeywordEnabled。還為我們的自定義剪輯模式創建一個枚舉。
我們需要調整的最后一件事是渲染隊列。可以通過設置材質的renderQueue屬性來完成。為此,使用RenderQueue類型添加一個setter屬性,設置所有材質的隊列。
3.3 預設
Unity的著色器僅允許你選擇一些預定義的表面類型,隱藏混合模式,剔除,隊列等的所有詳細信息。我們不會這樣做。相反,我們將添加一些按鈕,允許用戶應用預設。
第一個預設是不透明的,對應于默認的材質設置。為此添加一個方法,該方法首先以Opaque作為其標簽參數調用GUILayout.Button。如果單擊該按鈕,則該方法返回true。如果沒有,則沒有單擊它,我們可以中止該方法。否則,我們將繼續注冊并撤消步驟。
不透明的設置是:不裁剪;背面剔除,零混合,寫入深度,接收陰影,投射陰影并使用幾何隊列。
為片段預設添加另一種方法。唯一的區別是剪輯打開并且使用alpha測試隊列。
但是裁剪可以與雙面渲染結合使用,因此可以添加另一個預設,并剔除掉。
為傳統的淡入淡出材質設置另一個預設。與不透明的預設相比,它使用source-alpha和1減source-alpha混合,不寫入深度,既不接收也不投射陰影,并使用透明隊列。
但是我們的淡入淡出材質可以投射和接收陰影,因此添加另一個啟用投射和接收并使用陰影剪輯模式的預設。
在OnGUI的末尾調用所有預設方法。首先調用EditorGUILayout.Space,在它們和其余的GUI之間添加一些空間。另外,應該很少使用預設按鈕,因此請使用標有“Preset”的折疊將其隱藏。可以通過調用布爾值的EditorEditorGUILayout.Foldout來創建該折頁,該布爾值指示它是否已打開,其后是其標簽,以及是否單擊該標簽(而不只是其圖標)會切換其狀態。跟蹤字段中的折疊狀態,以便可以更改它。如果打開,則顯示預設。
下一個章節是反射。
往期推薦:
Unity可編程渲染管線系列(五)方向陰影(級聯貼圖 Cascaded Maps)
Unity可編程渲染管線系列(四)聚光燈陰影(陰影貼圖)
Unity可編程渲染管線系列(三)光照(單通道 正向渲染)
Unity可編程渲染管線系列(二)自定義著色器(HLSL和核心庫)
歡迎掃描二維碼,查看更多精彩內容。點擊 閱讀原文 可以跳轉原教程。
本文翻譯自 Jasper Flick的系列教程
原文地址:
https://catlikecoding.com/unity/tutorials
總結
以上是生活随笔為你收集整理的Unity可编程渲染管线系列(六)透明度(裁剪与淡化 Clipping and Fading)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 很好的源码软件列表,有助于学习提高 (Z
- 下一篇: 谈移动互联网开发的数据分析和决策思路