關於 Unity UGUI 中修改 Mask 組件下 Image 等子節點組件的材質無效的問題


  前幾天同事做了一個效果,希望在原本使用了遮罩組件 Mask 的技能圖標(讓技能圖標變成圓形)上在添加一個置灰的功能,但問題來了:因為是動態根據游戲中玩家的條件才動態置灰,以修改 Mask 下子節點 Image 組件的材質來實現的,但是實際上怎么修改也不起作用,呈現出的效果都只停留在第一次運行時的樣子。

  一開始我也以為是 shader 的問題,修改的 property 沒有生效,但是通過各種測試發現 shader 是已經修改成功的了。就是沒有應用上,在查閱了各方資料無效果的情況下只能翻閱 unity 托管在 BitBucket 上的 UI 源碼了(贊一個)。

  先看看 Mask.cs,通過 StencilBuffer 實現遮罩,繼承自 IMaterialModifier,需要實現接口:Material GetModifiedMaterial(Material baseMaterial); 這個接口是用來修改獲取的材質來實現遮罩效果。在各種 MonoBehaviour 改變時都會通過 MaskUtilities 這個靜態類來向所有的子節點發送 Stencil 狀態改變的消息。

  所以想知道為什么材質效果總是維持在第一次啟動執行時,就看看 Mask.OnEnable 里調用的 MaskUtilities.NotifyStencilStateChanged(this); 做了什么。

 1 public static void NotifyStencilStateChanged(Component mask)
 2 {
 3     var components = ListPool<Component>.Get();
 4     mask.GetComponentsInChildren(components);
 5     for (var i = 0; i < components.Count; i++)
 6     {
 7         if (components[i] == null || components[i].gameObject == mask.gameObject)
 8             continue;
 9 
10         var toNotify = components[i] as IMaskable;
11         if (toNotify != null)
12             toNotify.RecalculateMasking();
13     }
14     ListPool<Component>.Release(components);
15 }

  看以上代碼可以得知,Mask 會調用所有子節點中繼承自 IMaskable 組件(Image 繼承 MaskableGraphic, MaskableGraphic 繼承自此)的 RecalculateMasking() 函數。該函數將

 MaskableGraphic 中的  m_ShouldRecalculateStencil 修改為 true,這樣當開始渲染時,每個組件都會被調用 GetModifiedMaterial 以返回一個適用於當前渲染的 材質(有可能會返回一個修改過的拷貝),當 Imange.m_ShouldRecalculateStencil = true 時,會在 GetModifiedMaterial 中返回一個支持 Stencil 的修改過的材質,用於實現 Mask 遮罩效果,所以問題也很明了了,修改 Mask 下的 Image 組件原始的材質是不起作用的,因為實際渲染使用的不是它。

  那么如何修改?只需要自己繼承一個比如 Image 組件,並重載 GetModifiedMaterial 方法,將基類返回材質保存即可,這就是實際渲染使用的材質,當你想修改置灰時,使用這個材質即可。代碼如下:

 1 public class CustomImage : Image
 2 {
 3     public override Material GetModifiedMaterial(Material baseMaterial)
 4     {
 5         Material cModifiedMat = base.GetModifiedMaterial(baseMaterial);
 6         // Do whatever you want with this "cModifiedMat"...
 7         // You can also hold this and process it in your grayscale code.
 8         // ...
 9         return cModifiedMat;
10     }
11 }

  也可以去看看我在 Unity Answer 上對於該問題的回答:http://answers.unity3d.com/questions/1130203/ui-mask-override-my-shaders-custom-property.html

 


免責聲明!

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



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