ShaderKeyword.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. using System;
  2. using System.Linq;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. using UnityEditor.ShaderGraph.Internal;
  6. namespace UnityEditor.ShaderGraph
  7. {
  8. [Serializable]
  9. class ShaderKeyword : ShaderInput
  10. {
  11. public const string kVariantLimitWarning = "Graph is generating too many variants. Either delete Keywords, reduce Keyword variants or increase the Shader Variant Limit in Preferences > Shader Graph.";
  12. public ShaderKeyword()
  13. {
  14. }
  15. public ShaderKeyword(KeywordType keywordType)
  16. {
  17. this.displayName = keywordType.ToString();
  18. this.keywordType = keywordType;
  19. // Add sensible default entries for Enum type
  20. if(keywordType == KeywordType.Enum)
  21. {
  22. m_Entries = new List<KeywordEntry>();
  23. m_Entries.Add(new KeywordEntry(1, "A", "A"));
  24. m_Entries.Add(new KeywordEntry(2, "B", "B"));
  25. m_Entries.Add(new KeywordEntry(3, "C", "C"));
  26. }
  27. }
  28. public static ShaderKeyword Create(KeywordDescriptor descriptor)
  29. {
  30. if(descriptor.entries != null)
  31. {
  32. for(int i = 0; i < descriptor.entries.Length; i++)
  33. {
  34. if(descriptor.entries[i].id == -1)
  35. descriptor.entries[i].id = i + 1;
  36. }
  37. }
  38. return new ShaderKeyword()
  39. {
  40. m_IsExposable = false,
  41. m_IsEditable = false,
  42. displayName = descriptor.displayName,
  43. overrideReferenceName = descriptor.referenceName,
  44. keywordType = descriptor.type,
  45. keywordDefinition = descriptor.definition,
  46. keywordScope = descriptor.scope,
  47. value = descriptor.value,
  48. entries = descriptor.entries.ToList(),
  49. };
  50. }
  51. [SerializeField]
  52. private KeywordType m_KeywordType = KeywordType.Boolean;
  53. public KeywordType keywordType
  54. {
  55. get => m_KeywordType;
  56. set => m_KeywordType = value;
  57. }
  58. [SerializeField]
  59. private KeywordDefinition m_KeywordDefinition = KeywordDefinition.ShaderFeature;
  60. public KeywordDefinition keywordDefinition
  61. {
  62. get => m_KeywordDefinition;
  63. set => m_KeywordDefinition = value;
  64. }
  65. [SerializeField]
  66. private KeywordScope m_KeywordScope = KeywordScope.Local;
  67. public KeywordScope keywordScope
  68. {
  69. get => m_KeywordScope;
  70. set => m_KeywordScope = value;
  71. }
  72. [SerializeField]
  73. private List<KeywordEntry> m_Entries;
  74. public List<KeywordEntry> entries
  75. {
  76. get => m_Entries;
  77. set => m_Entries = value;
  78. }
  79. [SerializeField]
  80. private int m_Value;
  81. public int value
  82. {
  83. get => m_Value;
  84. set => m_Value = value;
  85. }
  86. [SerializeField]
  87. private bool m_IsEditable = true;
  88. public bool isEditable
  89. {
  90. get => m_IsEditable;
  91. set => m_IsEditable = value;
  92. }
  93. [SerializeField]
  94. private bool m_IsExposable = true;
  95. internal override bool isExposable => m_IsExposable
  96. && (keywordType == KeywordType.Enum || referenceName.EndsWith("_ON"));
  97. internal override bool isRenamable => isEditable;
  98. internal override ConcreteSlotValueType concreteShaderValueType => keywordType.ToConcreteSlotValueType();
  99. public override string GetDefaultReferenceName()
  100. {
  101. // _ON suffix is required for exposing Boolean type to Material
  102. var suffix = string.Empty;
  103. if(keywordType == KeywordType.Boolean)
  104. {
  105. suffix = "_ON";
  106. }
  107. return $"{keywordType.ToString()}_{GuidEncoder.Encode(guid)}{suffix}".ToUpper();
  108. }
  109. public string GetPropertyBlockString()
  110. {
  111. switch(keywordType)
  112. {
  113. case KeywordType.Enum:
  114. string enumTagString = $"[KeywordEnum({string.Join(", ", entries.Select(x => x.displayName))})]";
  115. return $"{enumTagString}{referenceName}(\"{displayName}\", Float) = {value}";
  116. case KeywordType.Boolean:
  117. // Reference name must be appended with _ON but must be removed when generating block
  118. if(referenceName.EndsWith("_ON"))
  119. return $"[Toggle]{referenceName.Remove(referenceName.Length - 3, 3)}(\"{displayName}\", Float) = {value}";
  120. else
  121. return string.Empty;
  122. default:
  123. throw new ArgumentOutOfRangeException();
  124. }
  125. }
  126. public string GetKeywordDeclarationString()
  127. {
  128. // Predefined keywords do not need to be defined
  129. if(keywordDefinition == KeywordDefinition.Predefined)
  130. return string.Empty;
  131. // Get definition type using scope
  132. string scopeString = keywordScope == KeywordScope.Local ? "_local" : string.Empty;
  133. string definitionString = $"{keywordDefinition.ToDeclarationString()}{scopeString}";
  134. switch(keywordType)
  135. {
  136. case KeywordType.Boolean:
  137. return $"#pragma {definitionString} _ {referenceName}";
  138. case KeywordType.Enum:
  139. var enumEntryDefinitions = entries.Select(x => $"{referenceName}_{x.referenceName}");
  140. string enumEntriesString = string.Join(" ", enumEntryDefinitions);
  141. return $"#pragma {definitionString} {enumEntriesString}";
  142. default:
  143. throw new ArgumentOutOfRangeException();
  144. }
  145. }
  146. public string GetKeywordPreviewDeclarationString()
  147. {
  148. switch(keywordType)
  149. {
  150. case KeywordType.Boolean:
  151. return value == 1 ? $"#define {referenceName}" : string.Empty;
  152. case KeywordType.Enum:
  153. return $"#define {referenceName}_{entries[value].referenceName}";
  154. default:
  155. throw new ArgumentOutOfRangeException();
  156. }
  157. }
  158. internal override ShaderInput Copy()
  159. {
  160. // Keywords copy reference name
  161. // This is because keywords are copied between graphs
  162. // When copying dependent nodes
  163. return new ShaderKeyword()
  164. {
  165. displayName = displayName,
  166. overrideReferenceName = overrideReferenceName,
  167. generatePropertyBlock = generatePropertyBlock,
  168. m_IsExposable = isExposable,
  169. isEditable = isEditable,
  170. keywordType = keywordType,
  171. keywordDefinition = keywordDefinition,
  172. keywordScope = keywordScope,
  173. entries = entries
  174. };
  175. }
  176. }
  177. }