FlipbookNode.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEditor.Graphing;
  4. using UnityEditor.ShaderGraph.Drawing.Controls;
  5. using UnityEditor.ShaderGraph.Internal;
  6. using UnityEngine;
  7. namespace UnityEditor.ShaderGraph
  8. {
  9. [Title("UV", "Flipbook")]
  10. class FlipbookNode : AbstractMaterialNode, IGeneratesBodyCode, IGeneratesFunction, IMayRequireMeshUV
  11. {
  12. public FlipbookNode()
  13. {
  14. name = "Flipbook";
  15. UpdateNodeAfterDeserialization();
  16. }
  17. const int UVSlotId = 0;
  18. const int WidthSlotId = 1;
  19. const int HeightSlotId = 2;
  20. const int TileSlotId = 3;
  21. const int OutputSlotId = 4;
  22. const string kUVSlotName = "UV";
  23. const string kWidthSlotName = "Width";
  24. const string kHeightSlotName = "Height";
  25. const string kTileSlotName = "Tile";
  26. const string kOutputSlotName = "Out";
  27. public override bool hasPreview
  28. {
  29. get { return true; }
  30. }
  31. string GetFunctionName()
  32. {
  33. return $"Unity_Flipbook_{concretePrecision.ToShaderString()}";
  34. }
  35. public sealed override void UpdateNodeAfterDeserialization()
  36. {
  37. AddSlot(new UVMaterialSlot(UVSlotId, kUVSlotName, kUVSlotName, UVChannel.UV0));
  38. AddSlot(new Vector1MaterialSlot(WidthSlotId, kWidthSlotName, kWidthSlotName, SlotType.Input, 1));
  39. AddSlot(new Vector1MaterialSlot(HeightSlotId, kHeightSlotName, kHeightSlotName, SlotType.Input, 1));
  40. AddSlot(new Vector1MaterialSlot(TileSlotId, kTileSlotName, kTileSlotName, SlotType.Input, 0));
  41. AddSlot(new Vector2MaterialSlot(OutputSlotId, kOutputSlotName, kOutputSlotName, SlotType.Output, Vector2.zero));
  42. RemoveSlotsNameNotMatching(new[] { UVSlotId, WidthSlotId, HeightSlotId, TileSlotId, OutputSlotId });
  43. }
  44. [SerializeField]
  45. private bool m_InvertX = false;
  46. [ToggleControl("Invert X")]
  47. public ToggleData invertX
  48. {
  49. get { return new ToggleData(m_InvertX); }
  50. set
  51. {
  52. if (m_InvertX == value.isOn)
  53. return;
  54. m_InvertX = value.isOn;
  55. Dirty(ModificationScope.Node);
  56. }
  57. }
  58. [SerializeField]
  59. private bool m_InvertY = true;
  60. [ToggleControl("Invert Y")]
  61. public ToggleData invertY
  62. {
  63. get { return new ToggleData(m_InvertY); }
  64. set
  65. {
  66. if (m_InvertY == value.isOn)
  67. return;
  68. m_InvertY = value.isOn;
  69. Dirty(ModificationScope.Node);
  70. }
  71. }
  72. public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
  73. {
  74. var uvValue = GetSlotValue(UVSlotId, generationMode);
  75. var widthValue = GetSlotValue(WidthSlotId, generationMode);
  76. var heightValue = GetSlotValue(HeightSlotId, generationMode);
  77. var tileValue = GetSlotValue(TileSlotId, generationMode);
  78. var outputValue = GetSlotValue(OutputSlotId, generationMode);
  79. sb.AppendLine("{0} {1};", FindOutputSlot<MaterialSlot>(OutputSlotId).concreteValueType.ToShaderString(), GetVariableNameForSlot(OutputSlotId));
  80. if (!generationMode.IsPreview())
  81. {
  82. sb.AppendLine("$precision2 _{0}_Invert = $precision2 ({1}, {2});", GetVariableNameForNode(), invertX.isOn ? 1 : 0, invertY.isOn ? 1 : 0);
  83. }
  84. sb.AppendLine("{0}({1}, {2}, {3}, {4}, _{5}_Invert, {6});", GetFunctionName(), uvValue, widthValue, heightValue, tileValue, GetVariableNameForNode(), outputValue);
  85. }
  86. public override void CollectPreviewMaterialProperties(List<PreviewProperty> properties)
  87. {
  88. base.CollectPreviewMaterialProperties(properties);
  89. properties.Add(new PreviewProperty(PropertyType.Vector2)
  90. {
  91. name = string.Format("_{0}_Invert", GetVariableNameForNode()),
  92. vector4Value = new Vector2(invertX.isOn ? 1 : 0, invertY.isOn ? 1 : 0)
  93. });
  94. }
  95. public override void CollectShaderProperties(PropertyCollector properties, GenerationMode generationMode)
  96. {
  97. if (!generationMode.IsPreview())
  98. return;
  99. base.CollectShaderProperties(properties, generationMode);
  100. properties.AddShaderProperty(new Vector2ShaderProperty()
  101. {
  102. overrideReferenceName = string.Format("_{0}_Invert", GetVariableNameForNode()),
  103. generatePropertyBlock = false
  104. });
  105. }
  106. public void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode)
  107. {
  108. registry.ProvideFunction(GetFunctionName(), s =>
  109. {
  110. s.AppendLine("void {0} ({1} UV, {2} Width, {3} Height, {4} Tile, $precision2 Invert, out {5} Out)",
  111. GetFunctionName(),
  112. FindInputSlot<MaterialSlot>(UVSlotId).concreteValueType.ToShaderString(),
  113. FindInputSlot<MaterialSlot>(WidthSlotId).concreteValueType.ToShaderString(),
  114. FindInputSlot<MaterialSlot>(HeightSlotId).concreteValueType.ToShaderString(),
  115. FindInputSlot<MaterialSlot>(TileSlotId).concreteValueType.ToShaderString(),
  116. FindOutputSlot<MaterialSlot>(OutputSlotId).concreteValueType.ToShaderString());
  117. using (s.BlockScope())
  118. {
  119. s.AppendLine("Tile = fmod(Tile, Width*Height);");
  120. s.AppendLine("$precision2 tileCount = $precision2(1.0, 1.0) / $precision2(Width, Height);");
  121. s.AppendLine("$precision tileY = abs(Invert.y * Height - (floor(Tile * tileCount.x) + Invert.y * 1));");
  122. s.AppendLine("$precision tileX = abs(Invert.x * Width - ((Tile - Width * floor(Tile * tileCount.x)) + Invert.x * 1));");
  123. s.AppendLine("Out = (UV + $precision2(tileX, tileY)) * tileCount;");
  124. }
  125. });
  126. }
  127. public bool RequiresMeshUV(UVChannel channel, ShaderStageCapability stageCapability)
  128. {
  129. using (var tempSlots = PooledList<MaterialSlot>.Get())
  130. {
  131. GetInputSlots(tempSlots);
  132. foreach (var slot in tempSlots)
  133. {
  134. if (slot.RequiresMeshUV(channel))
  135. return true;
  136. }
  137. return false;
  138. }
  139. }
  140. }
  141. }