暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DropdownNode.cs 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEngine;
  5. using UnityEditor.Graphing;
  6. using UnityEditor.ShaderGraph.Drawing;
  7. using UnityEditor.ShaderGraph.Serialization;
  8. namespace UnityEditor.ShaderGraph
  9. {
  10. [Serializable]
  11. [Title("Utility", "Dropdown")]
  12. class DropdownNode : AbstractMaterialNode, IOnAssetEnabled, IGeneratesBodyCode, IShaderInputObserver
  13. {
  14. internal const int k_MinEnumEntries = 2;
  15. public DropdownNode()
  16. {
  17. UpdateNodeAfterDeserialization();
  18. }
  19. [SerializeField]
  20. JsonRef<ShaderDropdown> m_Dropdown;
  21. public ShaderDropdown dropdown
  22. {
  23. get { return m_Dropdown; }
  24. set
  25. {
  26. if (m_Dropdown == value)
  27. return;
  28. m_Dropdown = value;
  29. UpdateNode();
  30. Dirty(ModificationScope.Topological);
  31. }
  32. }
  33. public override bool canSetPrecision => false;
  34. public override bool hasPreview => true;
  35. public const int OutputSlotId = 0;
  36. public override bool allowedInMainGraph { get => false; }
  37. public void UpdateNodeDisplayName(string newDisplayName)
  38. {
  39. MaterialSlot foundSlot = FindSlot<MaterialSlot>(OutputSlotId);
  40. if (foundSlot != null)
  41. foundSlot.displayName = newDisplayName;
  42. }
  43. public void OnEnable()
  44. {
  45. UpdateNode();
  46. }
  47. public void UpdateNode()
  48. {
  49. name = dropdown.displayName;
  50. UpdatePorts();
  51. }
  52. void UpdatePorts()
  53. {
  54. // Get slots
  55. List<MaterialSlot> inputSlots = new List<MaterialSlot>();
  56. GetInputSlots(inputSlots);
  57. // Store the edges
  58. Dictionary<MaterialSlot, List<IEdge>> edgeDict = new Dictionary<MaterialSlot, List<IEdge>>();
  59. foreach (MaterialSlot slot in inputSlots)
  60. edgeDict.Add(slot, (List<IEdge>)slot.owner.owner.GetEdges(slot.slotReference));
  61. // Remove old slots
  62. for (int i = 0; i < inputSlots.Count; i++)
  63. {
  64. RemoveSlot(inputSlots[i].id);
  65. }
  66. // Add output slot
  67. AddSlot(new DynamicVectorMaterialSlot(OutputSlotId, "Out", "Out", SlotType.Output, Vector4.zero));
  68. // Add input slots
  69. int[] slotIds = new int[dropdown.entries.Count + 1];
  70. slotIds[dropdown.entries.Count] = OutputSlotId;
  71. for (int i = 0; i < dropdown.entries.Count; i++)
  72. {
  73. // Get slot based on entry id
  74. MaterialSlot slot = inputSlots.Where(x =>
  75. x.id == dropdown.entries[i].id &&
  76. x.RawDisplayName() == dropdown.entries[i].displayName &&
  77. x.shaderOutputName == dropdown.entries[i].displayName).FirstOrDefault();
  78. if (slot == null)
  79. {
  80. slot = new DynamicVectorMaterialSlot(dropdown.entries[i].id, dropdown.entries[i].displayName, dropdown.entries[i].displayName, SlotType.Input, Vector4.zero);
  81. }
  82. AddSlot(slot);
  83. slotIds[i] = dropdown.entries[i].id;
  84. }
  85. RemoveSlotsNameNotMatching(slotIds);
  86. // Reconnect the edges
  87. foreach (KeyValuePair<MaterialSlot, List<IEdge>> entry in edgeDict)
  88. {
  89. foreach (IEdge edge in entry.Value)
  90. {
  91. owner.Connect(edge.outputSlot, edge.inputSlot);
  92. }
  93. }
  94. ValidateNode();
  95. }
  96. public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
  97. {
  98. var outputSlot = FindOutputSlot<MaterialSlot>(OutputSlotId);
  99. bool isGeneratingSubgraph = owner.isSubGraph && (generationMode != GenerationMode.Preview);
  100. if (generationMode == GenerationMode.Preview || !isGeneratingSubgraph)
  101. {
  102. sb.AppendLine(string.Format($"{outputSlot.concreteValueType.ToShaderString()} {GetVariableNameForSlot(OutputSlotId)};"));
  103. var value = GetSlotValue(GetSlotIdForActiveSelection(), generationMode);
  104. sb.AppendLine(string.Format($"{GetVariableNameForSlot(OutputSlotId)} = {value};"));
  105. }
  106. else
  107. {
  108. // Iterate all entries in the dropdown
  109. for (int i = 0; i < dropdown.entries.Count; i++)
  110. {
  111. if (i == 0)
  112. {
  113. sb.AppendLine(string.Format($"{outputSlot.concreteValueType.ToShaderString()} {GetVariableNameForSlot(OutputSlotId)};"));
  114. sb.AppendLine($"if ({m_Dropdown.value.referenceName} == {i})");
  115. }
  116. else
  117. {
  118. sb.AppendLine($"else if ({m_Dropdown.value.referenceName} == {i})");
  119. }
  120. {
  121. sb.AppendLine("{");
  122. sb.IncreaseIndent();
  123. var value = GetSlotValue(GetSlotIdForPermutation(new KeyValuePair<ShaderDropdown, int>(dropdown, i)), generationMode);
  124. sb.AppendLine(string.Format($"{GetVariableNameForSlot(OutputSlotId)} = {value};"));
  125. sb.DecreaseIndent();
  126. sb.AppendLine("}");
  127. }
  128. if (i == dropdown.entries.Count - 1)
  129. {
  130. sb.AppendLine($"else");
  131. sb.AppendLine("{");
  132. sb.IncreaseIndent();
  133. var value = GetSlotValue(GetSlotIdForPermutation(new KeyValuePair<ShaderDropdown, int>(dropdown, 0)), generationMode);
  134. sb.AppendLine(string.Format($"{GetVariableNameForSlot(OutputSlotId)} = {value};"));
  135. sb.DecreaseIndent();
  136. sb.AppendLine("}");
  137. }
  138. }
  139. }
  140. }
  141. public int GetSlotIdForPermutation(KeyValuePair<ShaderDropdown, int> permutation)
  142. {
  143. return permutation.Key.entries[permutation.Value].id;
  144. }
  145. public int GetSlotIdForActiveSelection()
  146. {
  147. return dropdown.entries[dropdown.value].id;
  148. }
  149. protected override void CalculateNodeHasError()
  150. {
  151. if (dropdown == null || !owner.dropdowns.Any(x => x == dropdown))
  152. {
  153. owner.AddConcretizationError(objectId, "Dropdown Node has no associated dropdown.");
  154. hasError = true;
  155. }
  156. }
  157. public void OnShaderInputUpdated(ModificationScope modificationScope)
  158. {
  159. UpdateNode();
  160. Dirty(modificationScope);
  161. if(modificationScope == ModificationScope.Layout)
  162. UpdateNodeDisplayName(dropdown.displayName);
  163. }
  164. }
  165. }