MatrixSplitNode.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEngine;
  5. using UnityEditor.Graphing;
  6. using UnityEditor.ShaderGraph.Drawing.Controls;
  7. namespace UnityEditor.ShaderGraph
  8. {
  9. enum MatrixAxis
  10. {
  11. Row,
  12. Column
  13. }
  14. [Title("Math", "Matrix", "Matrix Split")]
  15. class MatrixSplitNode : AbstractMaterialNode, IGeneratesBodyCode
  16. {
  17. const string kInputSlotName = "In";
  18. const string kOutputSlotM0Name = "M0";
  19. const string kOutputSlotM1Name = "M1";
  20. const string kOutputSlotM2Name = "M2";
  21. const string kOutputSlotM3Name = "M3";
  22. public const int InputSlotId = 0;
  23. public const int OutputSlotRId = 1;
  24. public const int OutputSlotGId = 2;
  25. public const int OutputSlotBId = 3;
  26. public const int OutputSlotAId = 4;
  27. public MatrixSplitNode()
  28. {
  29. name = "Matrix Split";
  30. UpdateNodeAfterDeserialization();
  31. }
  32. [SerializeField]
  33. MatrixAxis m_Axis;
  34. [EnumControl("")]
  35. MatrixAxis axis
  36. {
  37. get { return m_Axis; }
  38. set
  39. {
  40. if (m_Axis.Equals(value))
  41. return;
  42. m_Axis = value;
  43. Dirty(ModificationScope.Graph);
  44. }
  45. }
  46. static string[] s_ComponentList = new string[4] { "r", "g", "b", "a" };
  47. public sealed override void UpdateNodeAfterDeserialization()
  48. {
  49. AddSlot(new DynamicMatrixMaterialSlot(InputSlotId, kInputSlotName, kInputSlotName, SlotType.Input));
  50. AddSlot(new DynamicVectorMaterialSlot(OutputSlotRId, kOutputSlotM0Name, kOutputSlotM0Name, SlotType.Output, Vector4.zero));
  51. AddSlot(new DynamicVectorMaterialSlot(OutputSlotGId, kOutputSlotM1Name, kOutputSlotM1Name, SlotType.Output, Vector4.zero));
  52. AddSlot(new DynamicVectorMaterialSlot(OutputSlotBId, kOutputSlotM2Name, kOutputSlotM2Name, SlotType.Output, Vector4.zero));
  53. AddSlot(new DynamicVectorMaterialSlot(OutputSlotAId, kOutputSlotM3Name, kOutputSlotM3Name, SlotType.Output, Vector4.zero));
  54. RemoveSlotsNameNotMatching(new int[] { InputSlotId, OutputSlotRId, OutputSlotGId, OutputSlotBId, OutputSlotAId });
  55. }
  56. static int[] s_OutputSlots = {OutputSlotRId, OutputSlotGId, OutputSlotBId, OutputSlotAId};
  57. public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
  58. {
  59. var inputValue = GetSlotValue(InputSlotId, generationMode);
  60. var inputSlot = FindInputSlot<MaterialSlot>(InputSlotId);
  61. var numInputRows = 0;
  62. bool useIndentity = false;
  63. if (inputSlot != null)
  64. {
  65. numInputRows = SlotValueHelper.GetMatrixDimension(inputSlot.concreteValueType);
  66. if (numInputRows > 4)
  67. numInputRows = 0;
  68. if (!owner.GetEdges(inputSlot.slotReference).Any())
  69. {
  70. numInputRows = 0;
  71. useIndentity = true;
  72. }
  73. }
  74. int concreteRowCount = useIndentity ? 2 : numInputRows;
  75. for (var r = 0; r < 4; r++)
  76. {
  77. string outputValue;
  78. if (r >= numInputRows)
  79. {
  80. outputValue = string.Format("$precision{0}(", concreteRowCount);
  81. for (int c = 0; c < concreteRowCount; c++)
  82. {
  83. if (c != 0)
  84. outputValue += ", ";
  85. outputValue += Matrix4x4.identity.GetRow(r)[c];
  86. }
  87. outputValue += ")";
  88. }
  89. else
  90. {
  91. switch (m_Axis)
  92. {
  93. case MatrixAxis.Column:
  94. outputValue = string.Format("$precision{0}(", numInputRows);
  95. for (int c = 0; c < numInputRows; c++)
  96. {
  97. if (c != 0)
  98. outputValue += ", ";
  99. outputValue += string.Format("{0}[{1}].{2}", inputValue, c, s_ComponentList[r]);
  100. }
  101. outputValue += ")";
  102. break;
  103. default:
  104. outputValue = string.Format("{0}[{1}]", inputValue, r);
  105. break;
  106. }
  107. }
  108. sb.AppendLine(string.Format("$precision{0} {1} = {2};", concreteRowCount, GetVariableNameForSlot(s_OutputSlots[r]), outputValue));
  109. }
  110. }
  111. public override void ValidateNode()
  112. {
  113. var isInError = false;
  114. var errorMessage = k_validationErrorMessage;
  115. var dynamicInputSlotsToCompare = DictionaryPool<DynamicVectorMaterialSlot, ConcreteSlotValueType>.Get();
  116. var skippedDynamicSlots = ListPool<DynamicVectorMaterialSlot>.Get();
  117. var dynamicMatrixInputSlotsToCompare = DictionaryPool<DynamicMatrixMaterialSlot, ConcreteSlotValueType>.Get();
  118. var skippedDynamicMatrixSlots = ListPool<DynamicMatrixMaterialSlot>.Get();
  119. // iterate the input slots
  120. using (var tempSlots = PooledList<MaterialSlot>.Get())
  121. {
  122. GetInputSlots(tempSlots);
  123. foreach (var inputSlot in tempSlots)
  124. {
  125. inputSlot.hasError = false;
  126. // if there is a connection
  127. var edges = owner.GetEdges(inputSlot.slotReference).ToList();
  128. if (!edges.Any())
  129. {
  130. if (inputSlot is DynamicVectorMaterialSlot)
  131. skippedDynamicSlots.Add(inputSlot as DynamicVectorMaterialSlot);
  132. if (inputSlot is DynamicMatrixMaterialSlot)
  133. skippedDynamicMatrixSlots.Add(inputSlot as DynamicMatrixMaterialSlot);
  134. continue;
  135. }
  136. // get the output details
  137. var outputSlotRef = edges[0].outputSlot;
  138. var outputNode = owner.GetNodeFromGuid(outputSlotRef.nodeGuid);
  139. if (outputNode == null)
  140. continue;
  141. var outputSlot = outputNode.FindOutputSlot<MaterialSlot>(outputSlotRef.slotId);
  142. if (outputSlot == null)
  143. continue;
  144. if (outputSlot.hasError)
  145. {
  146. inputSlot.hasError = true;
  147. continue;
  148. }
  149. var outputConcreteType = outputSlot.concreteValueType;
  150. // dynamic input... depends on output from other node.
  151. // we need to compare ALL dynamic inputs to make sure they
  152. // are compatable.
  153. if (inputSlot is DynamicVectorMaterialSlot)
  154. {
  155. dynamicInputSlotsToCompare.Add((DynamicVectorMaterialSlot)inputSlot, outputConcreteType);
  156. continue;
  157. }
  158. else if (inputSlot is DynamicMatrixMaterialSlot)
  159. {
  160. dynamicMatrixInputSlotsToCompare.Add((DynamicMatrixMaterialSlot)inputSlot, outputConcreteType);
  161. continue;
  162. }
  163. }
  164. // and now dynamic matrices
  165. var dynamicMatrixType = ConvertDynamicMatrixInputTypeToConcrete(dynamicMatrixInputSlotsToCompare.Values);
  166. foreach (var dynamicKvP in dynamicMatrixInputSlotsToCompare)
  167. dynamicKvP.Key.SetConcreteType(dynamicMatrixType);
  168. foreach (var skippedSlot in skippedDynamicMatrixSlots)
  169. skippedSlot.SetConcreteType(dynamicMatrixType);
  170. // we can now figure out the dynamic slotType
  171. // from here set all the
  172. var dynamicType = SlotValueHelper.ConvertMatrixToVectorType(dynamicMatrixType);
  173. foreach (var dynamicKvP in dynamicInputSlotsToCompare)
  174. dynamicKvP.Key.SetConcreteType(dynamicType);
  175. foreach (var skippedSlot in skippedDynamicSlots)
  176. skippedSlot.SetConcreteType(dynamicType);
  177. tempSlots.Clear();
  178. GetInputSlots(tempSlots);
  179. var inputError = tempSlots.Any(x => x.hasError);
  180. // configure the output slots now
  181. // their slotType will either be the default output slotType
  182. // or the above dynanic slotType for dynamic nodes
  183. // or error if there is an input error
  184. tempSlots.Clear();
  185. GetOutputSlots(tempSlots);
  186. foreach (var outputSlot in tempSlots)
  187. {
  188. outputSlot.hasError = false;
  189. if (inputError)
  190. {
  191. outputSlot.hasError = true;
  192. continue;
  193. }
  194. if (outputSlot is DynamicVectorMaterialSlot)
  195. {
  196. (outputSlot as DynamicVectorMaterialSlot).SetConcreteType(dynamicType);
  197. continue;
  198. }
  199. else if (outputSlot is DynamicMatrixMaterialSlot)
  200. {
  201. (outputSlot as DynamicMatrixMaterialSlot).SetConcreteType(dynamicMatrixType);
  202. continue;
  203. }
  204. }
  205. isInError |= inputError;
  206. tempSlots.Clear();
  207. GetOutputSlots(tempSlots);
  208. isInError |= tempSlots.Any(x => x.hasError);
  209. }
  210. isInError |= CalculateNodeHasError(ref errorMessage);
  211. isInError |= ValidateConcretePrecision(ref errorMessage);
  212. hasError = isInError;
  213. if (isInError)
  214. {
  215. ((GraphData) owner).AddValidationError(tempId, errorMessage);
  216. }
  217. else
  218. {
  219. ++version;
  220. }
  221. ListPool<DynamicVectorMaterialSlot>.Release(skippedDynamicSlots);
  222. DictionaryPool<DynamicVectorMaterialSlot, ConcreteSlotValueType>.Release(dynamicInputSlotsToCompare);
  223. ListPool<DynamicMatrixMaterialSlot>.Release(skippedDynamicMatrixSlots);
  224. DictionaryPool<DynamicMatrixMaterialSlot, ConcreteSlotValueType>.Release(dynamicMatrixInputSlotsToCompare);
  225. }
  226. }
  227. }