MaterialQuality.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. using System;
  2. using UnityEngine;
  3. using UnityEngine.Rendering;
  4. namespace Utilities
  5. {
  6. /// <summary>
  7. /// Material quality flags.
  8. /// </summary>
  9. [Flags]
  10. public enum MaterialQuality
  11. {
  12. /// <summary>Low Material Quality.</summary>
  13. Low = 1 << 0,
  14. /// <summary>Medium Material Quality.</summary>
  15. Medium = 1 << 1,
  16. /// <summary>High Material Quality.</summary>
  17. High = 1 << 2
  18. }
  19. /// <summary>
  20. /// Material Quality utility class.
  21. /// </summary>
  22. public static class MaterialQualityUtilities
  23. {
  24. /// <summary>
  25. /// Keywords strings for Material Quality levels.
  26. /// </summary>
  27. public static string[] KeywordNames =
  28. {
  29. "MATERIAL_QUALITY_LOW",
  30. "MATERIAL_QUALITY_MEDIUM",
  31. "MATERIAL_QUALITY_HIGH",
  32. };
  33. /// <summary>
  34. /// String representation of the MaterialQuality enum.
  35. /// </summary>
  36. public static string[] EnumNames = Enum.GetNames(typeof(MaterialQuality));
  37. /// <summary>
  38. /// Keywords for Material Quality levels.
  39. /// </summary>
  40. public static ShaderKeyword[] Keywords =
  41. {
  42. new ShaderKeyword(KeywordNames[0]),
  43. new ShaderKeyword(KeywordNames[1]),
  44. new ShaderKeyword(KeywordNames[2]),
  45. };
  46. /// <summary>
  47. /// Returns the highest available quality level in a MaterialQuality bitfield.
  48. /// </summary>
  49. /// <param name="levels">Input MaterialQuality bitfield.</param>
  50. /// <returns>The highest available quality level.</returns>
  51. public static MaterialQuality GetHighestQuality(this MaterialQuality levels)
  52. {
  53. for (var i = Keywords.Length - 1; i >= 0; --i)
  54. {
  55. var level = (MaterialQuality) (1 << i);
  56. if ((levels & level) != 0)
  57. return level;
  58. }
  59. return 0;
  60. }
  61. /// <summary>
  62. /// Returns the closest available quality level in a MaterialQuality bitfield.
  63. /// </summary>
  64. /// <param name="availableLevels">Available MaterialQuality bitfield.</param>
  65. /// <param name="requestedLevel">Input MaterialQuality level.</param>
  66. /// <returns>The closest available quality level.</returns>
  67. public static MaterialQuality GetClosestQuality(this MaterialQuality availableLevels, MaterialQuality requestedLevel)
  68. {
  69. // Special fallback when there are no available quality levels. Needs to match in the shader stripping code
  70. if (availableLevels == 0)
  71. return MaterialQuality.Low;
  72. // First we want to find the closest available quality level below the requested one.
  73. int requestedLevelIndex = ToFirstIndex(requestedLevel);
  74. MaterialQuality chosenQuality = (MaterialQuality)0;
  75. for (int i = requestedLevelIndex; i >= 0; --i)
  76. {
  77. var level = FromIndex(i);
  78. if ((level & availableLevels) != 0)
  79. {
  80. chosenQuality = level;
  81. break;
  82. }
  83. }
  84. if (chosenQuality != 0)
  85. return chosenQuality;
  86. // If none is found then we fallback to the closest above.
  87. for (var i = requestedLevelIndex + 1; i < Keywords.Length; ++i)
  88. {
  89. var level = FromIndex(i);
  90. var diff = Math.Abs(requestedLevel - level);
  91. if ((level & availableLevels) != 0)
  92. {
  93. chosenQuality = level;
  94. break;
  95. }
  96. }
  97. Debug.Assert(chosenQuality != 0);
  98. return chosenQuality;
  99. }
  100. /// <summary>
  101. /// Set the global keyword for the provided MaterialQuality.
  102. /// </summary>
  103. /// <param name="level">MaterialQuality level to set the keyword for.</param>
  104. public static void SetGlobalShaderKeywords(this MaterialQuality level)
  105. {
  106. for (var i = 0; i < KeywordNames.Length; ++i)
  107. {
  108. if ((level & (MaterialQuality) (1 << i)) != 0)
  109. Shader.EnableKeyword(KeywordNames[i]);
  110. else
  111. Shader.DisableKeyword(KeywordNames[i]);
  112. }
  113. }
  114. /// <summary>
  115. /// Set the global keyword for the provided MaterialQuality.
  116. /// </summary>
  117. /// <param name="level">MaterialQuality level to set the keyword for.</param>
  118. /// <param name="cmd">Command Buffer used to setup the keyword.</param>
  119. public static void SetGlobalShaderKeywords(this MaterialQuality level, CommandBuffer cmd)
  120. {
  121. for (var i = 0; i < KeywordNames.Length; ++i)
  122. {
  123. if ((level & (MaterialQuality)(1 << i)) != 0)
  124. cmd.EnableShaderKeyword(KeywordNames[i]);
  125. else
  126. cmd.DisableShaderKeyword(KeywordNames[i]);
  127. }
  128. }
  129. /// <summary>
  130. /// Returns the index (in the MaterialQuality enum) of the first available level.
  131. /// </summary>
  132. /// <param name="level">MaterialQuality bitfield.</param>
  133. /// <returns>The index of the first available level.</returns>
  134. public static int ToFirstIndex(this MaterialQuality level)
  135. {
  136. for (var i = 0; i < KeywordNames.Length; ++i)
  137. {
  138. if ((level & (MaterialQuality) (1 << i)) != 0)
  139. return i;
  140. }
  141. return -1;
  142. }
  143. /// <summary>
  144. /// Returns the enum equivalent of the index in the MaterialQuality enum list.
  145. /// </summary>
  146. /// <param name="index">Index of the material quality.</param>
  147. /// <returns>The equivalent enum.</returns>
  148. public static MaterialQuality FromIndex(int index) => (MaterialQuality) (1 << index);
  149. }
  150. }