Keine Beschreibung
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

PropertyNode.cs 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. using System;
  2. using System.Linq;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. using UnityEditor.Graphing;
  6. using UnityEditor.ShaderGraph.Drawing;
  7. using UnityEditor.ShaderGraph.Internal;
  8. using UnityEditor.ShaderGraph.Serialization;
  9. namespace UnityEditor.ShaderGraph
  10. {
  11. [Serializable]
  12. [Title("Input", "Property")]
  13. class PropertyNode : AbstractMaterialNode, IGeneratesBodyCode, IOnAssetEnabled, IShaderInputObserver
  14. {
  15. public PropertyNode()
  16. {
  17. name = "Property";
  18. UpdateNodeAfterDeserialization();
  19. }
  20. // Property-Types
  21. public override string documentationURL => UnityEngine.Rendering.ShaderGraph.Documentation.GetPageLink("Property-Types");
  22. public override void UpdateNodeAfterDeserialization()
  23. {
  24. base.UpdateNodeAfterDeserialization();
  25. if (owner == null)
  26. return;
  27. if (property is Vector1ShaderProperty vector1ShaderProperty && vector1ShaderProperty.floatType == FloatType.Slider)
  28. {
  29. // Previously, the Slider vector1 property allowed the min value to be greater than the max
  30. // We no longer want to support that behavior so if such a property is encountered, swap the values
  31. if (vector1ShaderProperty.rangeValues.x > vector1ShaderProperty.rangeValues.y)
  32. {
  33. vector1ShaderProperty.rangeValues = new Vector2(vector1ShaderProperty.rangeValues.y, vector1ShaderProperty.rangeValues.x);
  34. Dirty(ModificationScope.Graph);
  35. }
  36. }
  37. }
  38. [SerializeField]
  39. JsonRef<AbstractShaderProperty> m_Property;
  40. public AbstractShaderProperty property
  41. {
  42. get { return m_Property; }
  43. set
  44. {
  45. if (m_Property == value)
  46. return;
  47. m_Property = value;
  48. AddOutputSlot();
  49. Dirty(ModificationScope.Topological);
  50. }
  51. }
  52. // this node's precision is always controlled by the property precision
  53. public override bool canSetPrecision => false;
  54. public void UpdateNodeDisplayName(string newDisplayName)
  55. {
  56. MaterialSlot foundSlot = FindSlot<MaterialSlot>(OutputSlotId);
  57. if (foundSlot != null)
  58. foundSlot.displayName = newDisplayName;
  59. }
  60. public void OnEnable()
  61. {
  62. AddOutputSlot();
  63. }
  64. public const int OutputSlotId = 0;
  65. void AddOutputSlot()
  66. {
  67. if (property is MultiJsonInternal.UnknownShaderPropertyType uspt)
  68. {
  69. // keep existing slots, don't modify them
  70. return;
  71. }
  72. switch (property.concreteShaderValueType)
  73. {
  74. case ConcreteSlotValueType.Boolean:
  75. AddSlot(new BooleanMaterialSlot(OutputSlotId, property.displayName, "Out", SlotType.Output, false));
  76. RemoveSlotsNameNotMatching(new[] { OutputSlotId });
  77. break;
  78. case ConcreteSlotValueType.Vector1:
  79. AddSlot(new Vector1MaterialSlot(OutputSlotId, property.displayName, "Out", SlotType.Output, 0));
  80. RemoveSlotsNameNotMatching(new[] { OutputSlotId });
  81. break;
  82. case ConcreteSlotValueType.Vector2:
  83. AddSlot(new Vector2MaterialSlot(OutputSlotId, property.displayName, "Out", SlotType.Output, Vector4.zero));
  84. RemoveSlotsNameNotMatching(new[] { OutputSlotId });
  85. break;
  86. case ConcreteSlotValueType.Vector3:
  87. AddSlot(new Vector3MaterialSlot(OutputSlotId, property.displayName, "Out", SlotType.Output, Vector4.zero));
  88. RemoveSlotsNameNotMatching(new[] { OutputSlotId });
  89. break;
  90. case ConcreteSlotValueType.Vector4:
  91. AddSlot(new Vector4MaterialSlot(OutputSlotId, property.displayName, "Out", SlotType.Output, Vector4.zero));
  92. RemoveSlotsNameNotMatching(new[] { OutputSlotId });
  93. break;
  94. case ConcreteSlotValueType.Matrix2:
  95. AddSlot(new Matrix2MaterialSlot(OutputSlotId, property.displayName, "Out", SlotType.Output));
  96. RemoveSlotsNameNotMatching(new[] { OutputSlotId });
  97. break;
  98. case ConcreteSlotValueType.Matrix3:
  99. AddSlot(new Matrix3MaterialSlot(OutputSlotId, property.displayName, "Out", SlotType.Output));
  100. RemoveSlotsNameNotMatching(new[] { OutputSlotId });
  101. break;
  102. case ConcreteSlotValueType.Matrix4:
  103. AddSlot(new Matrix4MaterialSlot(OutputSlotId, property.displayName, "Out", SlotType.Output));
  104. RemoveSlotsNameNotMatching(new[] { OutputSlotId });
  105. break;
  106. case ConcreteSlotValueType.Texture2D:
  107. AddSlot(new Texture2DMaterialSlot(OutputSlotId, property.displayName, "Out", SlotType.Output));
  108. RemoveSlotsNameNotMatching(new[] { OutputSlotId });
  109. break;
  110. case ConcreteSlotValueType.Texture2DArray:
  111. AddSlot(new Texture2DArrayMaterialSlot(OutputSlotId, property.displayName, "Out", SlotType.Output));
  112. RemoveSlotsNameNotMatching(new[] { OutputSlotId });
  113. break;
  114. case ConcreteSlotValueType.Texture3D:
  115. AddSlot(new Texture3DMaterialSlot(OutputSlotId, property.displayName, "Out", SlotType.Output));
  116. RemoveSlotsNameNotMatching(new[] { OutputSlotId });
  117. break;
  118. case ConcreteSlotValueType.Cubemap:
  119. AddSlot(new CubemapMaterialSlot(OutputSlotId, property.displayName, "Out", SlotType.Output));
  120. RemoveSlotsNameNotMatching(new[] { OutputSlotId });
  121. break;
  122. case ConcreteSlotValueType.SamplerState:
  123. AddSlot(new SamplerStateMaterialSlot(OutputSlotId, property.displayName, "Out", SlotType.Output));
  124. RemoveSlotsNameNotMatching(new[] { OutputSlotId });
  125. break;
  126. case ConcreteSlotValueType.Gradient:
  127. AddSlot(new GradientMaterialSlot(OutputSlotId, property.displayName, "Out", SlotType.Output));
  128. RemoveSlotsNameNotMatching(new[] { OutputSlotId });
  129. break;
  130. case ConcreteSlotValueType.VirtualTexture:
  131. AddSlot(new VirtualTextureMaterialSlot(OutputSlotId, property.displayName, "Out", SlotType.Output));
  132. RemoveSlotsNameNotMatching(new[] { OutputSlotId });
  133. break;
  134. default:
  135. throw new ArgumentOutOfRangeException();
  136. }
  137. }
  138. public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode mode)
  139. {
  140. // preview is always generating a full shader, even when previewing within a subgraph
  141. bool isGeneratingSubgraph = owner.isSubGraph && (mode != GenerationMode.Preview);
  142. switch (property.propertyType)
  143. {
  144. case PropertyType.Boolean:
  145. sb.AppendLine($"$precision {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
  146. break;
  147. case PropertyType.Float:
  148. sb.AppendLine($"$precision {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
  149. break;
  150. case PropertyType.Vector2:
  151. sb.AppendLine($"$precision2 {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
  152. break;
  153. case PropertyType.Vector3:
  154. sb.AppendLine($"$precision3 {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
  155. break;
  156. case PropertyType.Vector4:
  157. sb.AppendLine($"$precision4 {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
  158. break;
  159. case PropertyType.Color:
  160. switch (property.sgVersion)
  161. {
  162. case 0:
  163. case 2:
  164. sb.AppendLine($"$precision4 {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
  165. break;
  166. case 1:
  167. case 3:
  168. //Exposed color properties get put into the correct space automagikally by Unity UNLESS tagged as HDR, then they just get passed in as is.
  169. //for consistency with other places in the editor, we assume HDR colors are in linear space, and correct for gamma space here
  170. if ((property as ColorShaderProperty).colorMode == ColorMode.HDR)
  171. {
  172. sb.AppendLine($"$precision4 {GetVariableNameForSlot(OutputSlotId)} = IsGammaSpace() ? LinearToSRGB({property.GetHLSLVariableName(isGeneratingSubgraph, mode)}) : {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
  173. }
  174. else
  175. {
  176. sb.AppendLine($"$precision4 {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
  177. }
  178. break;
  179. default:
  180. throw new Exception($"Unknown Color Property Version on property {property.displayName}");
  181. }
  182. break;
  183. case PropertyType.Matrix2:
  184. sb.AppendLine($"$precision2x2 {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
  185. break;
  186. case PropertyType.Matrix3:
  187. sb.AppendLine($"$precision3x3 {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
  188. break;
  189. case PropertyType.Matrix4:
  190. sb.AppendLine($"$precision4x4 {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
  191. break;
  192. case PropertyType.Texture2D:
  193. sb.AppendLine($"UnityTexture2D {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
  194. break;
  195. case PropertyType.Texture3D:
  196. sb.AppendLine($"UnityTexture3D {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
  197. break;
  198. case PropertyType.Texture2DArray:
  199. sb.AppendLine($"UnityTexture2DArray {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
  200. break;
  201. case PropertyType.Cubemap:
  202. sb.AppendLine($"UnityTextureCube {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
  203. break;
  204. case PropertyType.SamplerState:
  205. sb.AppendLine($"UnitySamplerState {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
  206. break;
  207. case PropertyType.Gradient:
  208. if (mode == GenerationMode.Preview)
  209. sb.AppendLine($"Gradient {GetVariableNameForSlot(OutputSlotId)} = {GradientUtil.GetGradientForPreview(property.GetHLSLVariableName(isGeneratingSubgraph, mode))};");
  210. else
  211. sb.AppendLine($"Gradient {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
  212. break;
  213. }
  214. if (property.isConnectionTestable)
  215. {
  216. // If in a subgraph, the value will be read from a function parameter.
  217. // If generating preview mode code, we always inline the value, according to code gen requirements.
  218. // The parent graph always sets the explicit value to be passed to a subgraph function.
  219. sb.AppendLine("bool {0} = {1};", GetConnectionStateVariableNameForSlot(OutputSlotId), (mode == GenerationMode.Preview || !isGeneratingSubgraph) ? (IsSlotConnected(OutputSlotId) ? "true" : "false") : property.GetConnectionStateHLSLVariableName());
  220. }
  221. }
  222. public override string GetVariableNameForSlot(int slotId)
  223. {
  224. // TODO: we should switch VirtualTexture away from the macro-based variables and towards using the same approach as Texture2D
  225. switch (property.propertyType)
  226. {
  227. case PropertyType.VirtualTexture:
  228. return property.GetHLSLVariableName(owner.isSubGraph, GenerationMode.ForReals);
  229. }
  230. return base.GetVariableNameForSlot(slotId);
  231. }
  232. public string GetConnectionStateVariableNameForSlot(int slotId)
  233. {
  234. return ShaderInput.GetConnectionStateVariableName(GetVariableNameForSlot(slotId));
  235. }
  236. protected override void CalculateNodeHasError()
  237. {
  238. if (property == null || !owner.properties.Any(x => x == property))
  239. {
  240. owner.AddConcretizationError(objectId, "Property Node has no associated Blackboard property.");
  241. }
  242. else if (property is MultiJsonInternal.UnknownShaderPropertyType)
  243. {
  244. owner.AddValidationError(objectId, "Property is of unknown type, a package may be missing.", Rendering.ShaderCompilerMessageSeverity.Warning);
  245. }
  246. }
  247. public override void UpdatePrecision(List<MaterialSlot> inputSlots)
  248. {
  249. // Get precision from Property
  250. if (property == null)
  251. {
  252. owner.AddConcretizationError(objectId, string.Format("No matching poperty found on owner for node {0}", objectId));
  253. hasError = true;
  254. return;
  255. }
  256. // this node's precision is always controlled by the property precision
  257. precision = property.precision;
  258. graphPrecision = precision.ToGraphPrecision(GraphPrecision.Graph);
  259. concretePrecision = graphPrecision.ToConcrete(owner.graphDefaultConcretePrecision);
  260. }
  261. public void OnShaderInputUpdated(ModificationScope modificationScope)
  262. {
  263. if(modificationScope == ModificationScope.Layout)
  264. UpdateNodeDisplayName(property.displayName);
  265. Dirty(modificationScope);
  266. }
  267. }
  268. }