ChannelMaskNode.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. using System;
  2. using UnityEngine;
  3. using UnityEditor.Graphing;
  4. using UnityEditor.ShaderGraph.Drawing.Controls;
  5. namespace UnityEditor.ShaderGraph
  6. {
  7. enum TextureChannel
  8. {
  9. Red,
  10. Green,
  11. Blue,
  12. Alpha
  13. }
  14. [Title("Artistic", "Mask", "Channel Mask")]
  15. class ChannelMaskNode : AbstractMaterialNode, IGeneratesBodyCode, IGeneratesFunction
  16. {
  17. public ChannelMaskNode()
  18. {
  19. name = "Channel Mask";
  20. UpdateNodeAfterDeserialization();
  21. }
  22. const int InputSlotId = 0;
  23. const int OutputSlotId = 1;
  24. const string kInputSlotName = "In";
  25. const string kOutputSlotName = "Out";
  26. public override bool hasPreview
  27. {
  28. get { return true; }
  29. }
  30. string GetFunctionName()
  31. {
  32. string channelSum = "None";
  33. if (channelMask != 0)
  34. {
  35. bool red = (channelMask & 1) != 0;
  36. bool green = (channelMask & 2) != 0;
  37. bool blue = (channelMask & 4) != 0;
  38. bool alpha = (channelMask & 8) != 0;
  39. channelSum = string.Format("{0}{1}{2}{3}", red ? "Red" : "", green ? "Green" : "", blue ? "Blue" : "", alpha ? "Alpha" : "");
  40. }
  41. return $"Unity_ChannelMask_{channelSum}_{FindSlot<MaterialSlot>(OutputSlotId).concreteValueType.ToShaderString(concretePrecision)}";
  42. }
  43. public sealed override void UpdateNodeAfterDeserialization()
  44. {
  45. AddSlot(new DynamicVectorMaterialSlot(InputSlotId, kInputSlotName, kInputSlotName, SlotType.Input, Vector3.zero));
  46. AddSlot(new DynamicVectorMaterialSlot(OutputSlotId, kOutputSlotName, kOutputSlotName, SlotType.Output, Vector3.zero));
  47. RemoveSlotsNameNotMatching(new[] { InputSlotId, OutputSlotId });
  48. }
  49. public TextureChannel channel;
  50. [SerializeField]
  51. private int m_ChannelMask = -1;
  52. [ChannelEnumMaskControl("Channels")]
  53. public int channelMask
  54. {
  55. get { return m_ChannelMask; }
  56. set
  57. {
  58. if (m_ChannelMask == value)
  59. return;
  60. m_ChannelMask = value;
  61. Dirty(ModificationScope.Graph);
  62. }
  63. }
  64. void ValidateChannelCount()
  65. {
  66. int channelCount = SlotValueHelper.GetChannelCount(FindSlot<MaterialSlot>(InputSlotId).concreteValueType);
  67. if (channelMask >= 1 << channelCount)
  68. channelMask = -1;
  69. }
  70. string GetFunctionPrototype(string argIn, string argOut)
  71. {
  72. return string.Format("void {0} ({1} {2}, out {3} {4})"
  73. , GetFunctionName()
  74. , FindInputSlot<DynamicVectorMaterialSlot>(InputSlotId).concreteValueType.ToShaderString()
  75. , argIn
  76. , FindOutputSlot<DynamicVectorMaterialSlot>(OutputSlotId).concreteValueType.ToShaderString()
  77. , argOut);
  78. }
  79. public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
  80. {
  81. ValidateChannelCount();
  82. string inputValue = GetSlotValue(InputSlotId, generationMode);
  83. string outputValue = GetSlotValue(OutputSlotId, generationMode);
  84. sb.AppendLine(string.Format("{0} {1};", FindInputSlot<MaterialSlot>(InputSlotId).concreteValueType.ToShaderString(), GetVariableNameForSlot(OutputSlotId)));
  85. sb.AppendLine(GetFunctionCallBody(inputValue, outputValue));
  86. }
  87. string GetFunctionCallBody(string inputValue, string outputValue)
  88. {
  89. return GetFunctionName() + " (" + inputValue + ", " + outputValue + ");";
  90. }
  91. public void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode)
  92. {
  93. ValidateChannelCount();
  94. registry.ProvideFunction(GetFunctionName(), s =>
  95. {
  96. int channelCount = SlotValueHelper.GetChannelCount(FindSlot<MaterialSlot>(InputSlotId).concreteValueType);
  97. s.AppendLine(GetFunctionPrototype("In", "Out"));
  98. using (s.BlockScope())
  99. {
  100. if (channelMask == 0)
  101. s.AppendLine("Out = 0;");
  102. else if (channelMask == -1)
  103. s.AppendLine("Out = In;");
  104. else
  105. {
  106. bool red = (channelMask & 1) != 0;
  107. bool green = (channelMask & 2) != 0;
  108. bool blue = (channelMask & 4) != 0;
  109. bool alpha = (channelMask & 8) != 0;
  110. switch (channelCount)
  111. {
  112. case 1:
  113. s.AppendLine("Out = In.r;");
  114. break;
  115. case 2:
  116. s.AppendLine(string.Format("Out = $precision2({0}, {1});",
  117. red ? "In.r" : "0", green ? "In.g" : "0"));
  118. break;
  119. case 3:
  120. s.AppendLine(string.Format("Out = $precision3({0}, {1}, {2});",
  121. red ? "In.r" : "0", green ? "In.g" : "0", blue ? "In.b" : "0"));
  122. break;
  123. case 4:
  124. s.AppendLine(string.Format("Out = $precision4({0}, {1}, {2}, {3});",
  125. red ? "In.r" : "0", green ? "In.g" : "0", blue ? "In.b" : "0", alpha ? "In.a" : "0"));
  126. break;
  127. default:
  128. throw new ArgumentOutOfRangeException();
  129. }
  130. }
  131. }
  132. });
  133. }
  134. }
  135. }