Ei kuvausta
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.

SwizzleNode.cs 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using UnityEditor.Graphing;
  4. using UnityEditor.ShaderGraph.Drawing.Controls;
  5. using UnityEngine;
  6. using UnityEditor.Rendering;
  7. namespace UnityEditor.ShaderGraph
  8. {
  9. [Title("Channel", "Swizzle")]
  10. class SwizzleNode : AbstractMaterialNode, IGeneratesBodyCode
  11. {
  12. public SwizzleNode()
  13. {
  14. name = "Swizzle";
  15. synonyms = new string[] { "swap", "reorder", "component mask" };
  16. UpdateNodeAfterDeserialization();
  17. }
  18. const int InputSlotId = 0;
  19. const int OutputSlotId = 1;
  20. const string kInputSlotName = "In";
  21. const string kOutputSlotName = "Out";
  22. public override bool hasPreview
  23. {
  24. get { return true; }
  25. }
  26. [SerializeField]
  27. string _maskInput = "xxxx";
  28. [TextControl("Mask:")]
  29. public string maskInput
  30. {
  31. get { return _maskInput; }
  32. set
  33. {
  34. if (_maskInput.Equals(value))
  35. return;
  36. _maskInput = value;
  37. UpdateNodeAfterDeserialization();
  38. Dirty(ModificationScope.Topological);
  39. }
  40. }
  41. public string convertedMask;
  42. public bool ValidateMaskInput(int InputValueSize)
  43. {
  44. convertedMask = _maskInput.ToLower();
  45. Dictionary<char, char> mask_map = new Dictionary<char, char>
  46. {
  47. {'r', 'x' },
  48. {'g', 'y' },
  49. {'b', 'z' },
  50. {'a', 'w' },
  51. };
  52. bool MaskInputIsValid = true;
  53. char[] MaskChars = convertedMask.ToCharArray();
  54. char[] AllChars = { 'x', 'y', 'z', 'w', 'r', 'g', 'b', 'a' };
  55. List<char> CurrentChars = new List<char>();
  56. for (int i = 0; i < InputValueSize; i++)
  57. {
  58. CurrentChars.Add(AllChars[i]);
  59. CurrentChars.Add(AllChars[i + 4]);
  60. }
  61. foreach (char c in MaskChars)
  62. {
  63. if (!CurrentChars.Contains(c))
  64. {
  65. MaskInputIsValid = false;
  66. }
  67. }
  68. if (MaskChars.Length <= 0 || MaskChars.Length > 4)
  69. {
  70. MaskInputIsValid = false;
  71. }
  72. //Convert "rgba" input to "xyzw" to avoid mismathcing
  73. if (MaskInputIsValid)
  74. {
  75. char[] rgba = { 'r', 'g', 'b', 'a' };
  76. for (int i = 0; i < MaskChars.Length; i++)
  77. {
  78. if (rgba.Contains(MaskChars[i]))
  79. {
  80. MaskChars[i] = mask_map[MaskChars[i]];
  81. }
  82. }
  83. convertedMask = new string(MaskChars);
  84. }
  85. return MaskInputIsValid;
  86. }
  87. public sealed override void UpdateNodeAfterDeserialization()
  88. {
  89. if (_maskInput == null)
  90. _maskInput = "xxxx";
  91. AddSlot(new DynamicVectorMaterialSlot(InputSlotId, kInputSlotName, kInputSlotName, SlotType.Input, Vector4.zero));
  92. switch (_maskInput.Length)
  93. {
  94. case 1:
  95. AddSlot(new Vector1MaterialSlot(OutputSlotId, kOutputSlotName, kOutputSlotName, SlotType.Output, 0));
  96. break;
  97. case 2:
  98. AddSlot(new Vector2MaterialSlot(OutputSlotId, kOutputSlotName, kOutputSlotName, SlotType.Output, Vector2.zero));
  99. break;
  100. case 3:
  101. AddSlot(new Vector3MaterialSlot(OutputSlotId, kOutputSlotName, kOutputSlotName, SlotType.Output, Vector3.zero));
  102. break;
  103. default:
  104. AddSlot(new Vector4MaterialSlot(OutputSlotId, kOutputSlotName, kOutputSlotName, SlotType.Output, Vector4.zero));
  105. break;
  106. }
  107. RemoveSlotsNameNotMatching(new[] { InputSlotId, OutputSlotId });
  108. }
  109. public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
  110. {
  111. var outputSlotType = FindOutputSlot<MaterialSlot>(OutputSlotId).concreteValueType.ToShaderString();
  112. var outputName = GetVariableNameForSlot(OutputSlotId);
  113. var inputValue = GetSlotValue(InputSlotId, generationMode);
  114. var inputValueType = FindInputSlot<MaterialSlot>(InputSlotId).concreteValueType;
  115. var InputValueSize = SlotValueHelper.GetChannelCount(inputValueType);
  116. if (!ValidateMaskInput(InputValueSize))
  117. {
  118. sb.AppendLine(string.Format("{0} {1} = 0;", outputSlotType, outputName));
  119. }
  120. else if(!FindInputSlot<MaterialSlot>(InputSlotId).isConnected)
  121. {
  122. // cannot swizzle off of a float literal, so if there is no upstream connection, it means we have defaulted to a float,
  123. // and the node's initial base case will generate invalid code.
  124. sb.AppendLine("{0} {1} = $precision({2}).{3};", outputSlotType, outputName, inputValue, convertedMask);
  125. }
  126. else
  127. {
  128. sb.AppendLine("{0} {1} = {2}.{3};", outputSlotType, outputName, inputValue, convertedMask);
  129. }
  130. }
  131. public override void ValidateNode()
  132. {
  133. base.ValidateNode();
  134. var inputValueType = FindInputSlot<MaterialSlot>(InputSlotId).concreteValueType;
  135. var InputValueSize = SlotValueHelper.GetChannelCount(inputValueType);
  136. if (!ValidateMaskInput(InputValueSize))
  137. {
  138. owner.AddValidationError(objectId, "Invalid mask for a Vector" + InputValueSize + " input.", ShaderCompilerMessageSeverity.Error);
  139. }
  140. }
  141. public override int latestVersion => 1;
  142. public override void OnAfterMultiDeserialize(string json)
  143. {
  144. //collect texturechannel properties
  145. //get the value
  146. //pass it to maskInput
  147. if (sgVersion < 1)
  148. {
  149. LegacySwizzleChannelData.LegacySwizzleChannel(json, this);
  150. ChangeVersion(1);
  151. UpdateNodeAfterDeserialization();
  152. }
  153. }
  154. public override IEnumerable<int> allowedNodeVersions => new List<int> { 1 };
  155. class LegacySwizzleChannelData
  156. {
  157. //collect texturechannel properties
  158. [SerializeField]
  159. public TextureChannel m_RedChannel;
  160. [SerializeField]
  161. public TextureChannel m_GreenChannel;
  162. [SerializeField]
  163. public TextureChannel m_BlueChannel;
  164. [SerializeField]
  165. public TextureChannel m_AlphaChannel;
  166. public static void LegacySwizzleChannel(string json, SwizzleNode node)
  167. {
  168. Dictionary<TextureChannel, string> s_ComponentList = new Dictionary<TextureChannel, string>
  169. {
  170. {TextureChannel.Red, "r" },
  171. {TextureChannel.Green, "g" },
  172. {TextureChannel.Blue, "b" },
  173. {TextureChannel.Alpha, "a" },
  174. };
  175. var legacySwizzleChannelData = new LegacySwizzleChannelData();
  176. JsonUtility.FromJsonOverwrite(json, legacySwizzleChannelData);
  177. node._maskInput = s_ComponentList[legacySwizzleChannelData.m_RedChannel] + s_ComponentList[legacySwizzleChannelData.m_GreenChannel] + s_ComponentList[legacySwizzleChannelData.m_BlueChannel] + s_ComponentList[legacySwizzleChannelData.m_AlphaChannel];
  178. }
  179. }
  180. }
  181. }