StencilMaterial.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine.Rendering;
  4. namespace UnityEngine.UI
  5. {
  6. /// <summary>
  7. /// Dynamic material class makes it possible to create custom materials on the fly on a per-Graphic basis,
  8. /// and still have them get cleaned up correctly.
  9. /// </summary>
  10. public static class StencilMaterial
  11. {
  12. private class MatEntry
  13. {
  14. public Material baseMat;
  15. public Material customMat;
  16. public int count;
  17. public int stencilId;
  18. public StencilOp operation = StencilOp.Keep;
  19. public CompareFunction compareFunction = CompareFunction.Always;
  20. public int readMask;
  21. public int writeMask;
  22. public bool useAlphaClip;
  23. public ColorWriteMask colorMask;
  24. }
  25. private static List<MatEntry> m_List = new List<MatEntry>();
  26. [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
  27. [Obsolete("Use Material.Add instead.", true)]
  28. public static Material Add(Material baseMat, int stencilID) { return null; }
  29. /// <summary>
  30. /// Add a new material using the specified base and stencil ID.
  31. /// </summary>
  32. public static Material Add(Material baseMat, int stencilID, StencilOp operation, CompareFunction compareFunction, ColorWriteMask colorWriteMask)
  33. {
  34. return Add(baseMat, stencilID, operation, compareFunction, colorWriteMask, 255, 255);
  35. }
  36. /// <summary>
  37. /// Add a new material using the specified base and stencil ID.
  38. /// </summary>
  39. public static Material Add(Material baseMat, int stencilID, StencilOp operation, CompareFunction compareFunction, ColorWriteMask colorWriteMask, int readMask, int writeMask)
  40. {
  41. if ((stencilID <= 0 && colorWriteMask == ColorWriteMask.All) || baseMat == null)
  42. return baseMat;
  43. if (!baseMat.HasProperty("_Stencil"))
  44. {
  45. Debug.LogWarning("Material " + baseMat.name + " doesn't have _Stencil property", baseMat);
  46. return baseMat;
  47. }
  48. if (!baseMat.HasProperty("_StencilOp"))
  49. {
  50. Debug.LogWarning("Material " + baseMat.name + " doesn't have _StencilOp property", baseMat);
  51. return baseMat;
  52. }
  53. if (!baseMat.HasProperty("_StencilComp"))
  54. {
  55. Debug.LogWarning("Material " + baseMat.name + " doesn't have _StencilComp property", baseMat);
  56. return baseMat;
  57. }
  58. if (!baseMat.HasProperty("_StencilReadMask"))
  59. {
  60. Debug.LogWarning("Material " + baseMat.name + " doesn't have _StencilReadMask property", baseMat);
  61. return baseMat;
  62. }
  63. if (!baseMat.HasProperty("_StencilWriteMask"))
  64. {
  65. Debug.LogWarning("Material " + baseMat.name + " doesn't have _StencilWriteMask property", baseMat);
  66. return baseMat;
  67. }
  68. if (!baseMat.HasProperty("_ColorMask"))
  69. {
  70. Debug.LogWarning("Material " + baseMat.name + " doesn't have _ColorMask property", baseMat);
  71. return baseMat;
  72. }
  73. var listCount = m_List.Count;
  74. for (int i = 0; i < listCount; ++i)
  75. {
  76. MatEntry ent = m_List[i];
  77. if (ent.baseMat == baseMat
  78. && ent.stencilId == stencilID
  79. && ent.operation == operation
  80. && ent.compareFunction == compareFunction
  81. && ent.readMask == readMask
  82. && ent.writeMask == writeMask
  83. && ent.colorMask == colorWriteMask)
  84. {
  85. ++ent.count;
  86. return ent.customMat;
  87. }
  88. }
  89. var newEnt = new MatEntry();
  90. newEnt.count = 1;
  91. newEnt.baseMat = baseMat;
  92. newEnt.customMat = new Material(baseMat);
  93. newEnt.customMat.hideFlags = HideFlags.HideAndDontSave;
  94. newEnt.stencilId = stencilID;
  95. newEnt.operation = operation;
  96. newEnt.compareFunction = compareFunction;
  97. newEnt.readMask = readMask;
  98. newEnt.writeMask = writeMask;
  99. newEnt.colorMask = colorWriteMask;
  100. newEnt.useAlphaClip = operation != StencilOp.Keep && writeMask > 0;
  101. newEnt.customMat.name = string.Format("Stencil Id:{0}, Op:{1}, Comp:{2}, WriteMask:{3}, ReadMask:{4}, ColorMask:{5} AlphaClip:{6} ({7})", stencilID, operation, compareFunction, writeMask, readMask, colorWriteMask, newEnt.useAlphaClip, baseMat.name);
  102. newEnt.customMat.SetInt("_Stencil", stencilID);
  103. newEnt.customMat.SetInt("_StencilOp", (int)operation);
  104. newEnt.customMat.SetInt("_StencilComp", (int)compareFunction);
  105. newEnt.customMat.SetInt("_StencilReadMask", readMask);
  106. newEnt.customMat.SetInt("_StencilWriteMask", writeMask);
  107. newEnt.customMat.SetInt("_ColorMask", (int)colorWriteMask);
  108. newEnt.customMat.SetInt("_UseUIAlphaClip", newEnt.useAlphaClip ? 1 : 0);
  109. if (newEnt.useAlphaClip)
  110. newEnt.customMat.EnableKeyword("UNITY_UI_ALPHACLIP");
  111. else
  112. newEnt.customMat.DisableKeyword("UNITY_UI_ALPHACLIP");
  113. m_List.Add(newEnt);
  114. return newEnt.customMat;
  115. }
  116. /// <summary>
  117. /// Remove an existing material, automatically cleaning it up if it's no longer in use.
  118. /// </summary>
  119. public static void Remove(Material customMat)
  120. {
  121. if (customMat == null)
  122. return;
  123. var listCount = m_List.Count;
  124. for (int i = 0; i < listCount; ++i)
  125. {
  126. MatEntry ent = m_List[i];
  127. if (ent.customMat != customMat)
  128. continue;
  129. if (--ent.count == 0)
  130. {
  131. Misc.DestroyImmediate(ent.customMat);
  132. ent.baseMat = null;
  133. m_List.RemoveAt(i);
  134. }
  135. return;
  136. }
  137. }
  138. public static void ClearAll()
  139. {
  140. var listCount = m_List.Count;
  141. for (int i = 0; i < listCount; ++i)
  142. {
  143. MatEntry ent = m_List[i];
  144. Misc.DestroyImmediate(ent.customMat);
  145. ent.baseMat = null;
  146. }
  147. m_List.Clear();
  148. }
  149. }
  150. }