CodeFunctionNode.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using JetBrains.Annotations;
  6. using UnityEngine;
  7. using UnityEditor.Graphing;
  8. using UnityEditor.ShaderGraph.Internal;
  9. namespace UnityEditor.ShaderGraph
  10. {
  11. abstract class CodeFunctionNode : AbstractMaterialNode
  12. , IGeneratesBodyCode
  13. , IGeneratesFunction
  14. , IMayRequireNormal
  15. , IMayRequireTangent
  16. , IMayRequireBitangent
  17. , IMayRequireMeshUV
  18. , IMayRequireScreenPosition
  19. , IMayRequireViewDirection
  20. , IMayRequirePosition
  21. , IMayRequireVertexColor
  22. {
  23. [NonSerialized]
  24. private List<SlotAttribute> m_Slots = new List<SlotAttribute>();
  25. public override bool hasPreview
  26. {
  27. get { return true; }
  28. }
  29. protected CodeFunctionNode()
  30. {
  31. UpdateNodeAfterDeserialization();
  32. }
  33. protected struct Boolean
  34. {}
  35. protected struct Vector1
  36. {}
  37. protected struct Texture2D
  38. {}
  39. protected struct Texture2DArray
  40. {}
  41. protected struct Texture3D
  42. {}
  43. protected struct SamplerState
  44. {}
  45. protected struct Gradient
  46. {}
  47. protected struct DynamicDimensionVector
  48. {}
  49. protected struct ColorRGBA
  50. {}
  51. protected struct ColorRGB
  52. {}
  53. protected struct Matrix3x3
  54. {}
  55. protected struct Matrix2x2
  56. {}
  57. protected struct DynamicDimensionMatrix
  58. {}
  59. protected enum Binding
  60. {
  61. None,
  62. ObjectSpaceNormal,
  63. ObjectSpaceTangent,
  64. ObjectSpaceBitangent,
  65. ObjectSpacePosition,
  66. ViewSpaceNormal,
  67. ViewSpaceTangent,
  68. ViewSpaceBitangent,
  69. ViewSpacePosition,
  70. WorldSpaceNormal,
  71. WorldSpaceTangent,
  72. WorldSpaceBitangent,
  73. WorldSpacePosition,
  74. TangentSpaceNormal,
  75. TangentSpaceTangent,
  76. TangentSpaceBitangent,
  77. TangentSpacePosition,
  78. MeshUV0,
  79. MeshUV1,
  80. MeshUV2,
  81. MeshUV3,
  82. ScreenPosition,
  83. ObjectSpaceViewDirection,
  84. ViewSpaceViewDirection,
  85. WorldSpaceViewDirection,
  86. TangentSpaceViewDirection,
  87. VertexColor,
  88. }
  89. [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
  90. protected class SlotAttribute : Attribute
  91. {
  92. public int slotId { get; private set; }
  93. public Binding binding { get; private set; }
  94. public bool hidden { get; private set; }
  95. public Vector4? defaultValue { get; private set; }
  96. public ShaderStageCapability stageCapability { get; private set; }
  97. public SlotAttribute(int mSlotId, Binding mImplicitBinding, ShaderStageCapability mStageCapability = ShaderStageCapability.All)
  98. {
  99. slotId = mSlotId;
  100. binding = mImplicitBinding;
  101. defaultValue = null;
  102. stageCapability = mStageCapability;
  103. }
  104. public SlotAttribute(int mSlotId, Binding mImplicitBinding, bool mHidden, ShaderStageCapability mStageCapability = ShaderStageCapability.All)
  105. {
  106. slotId = mSlotId;
  107. binding = mImplicitBinding;
  108. hidden = mHidden;
  109. defaultValue = null;
  110. stageCapability = mStageCapability;
  111. }
  112. public SlotAttribute(int mSlotId, Binding mImplicitBinding, float defaultX, float defaultY, float defaultZ, float defaultW, ShaderStageCapability mStageCapability = ShaderStageCapability.All)
  113. {
  114. slotId = mSlotId;
  115. binding = mImplicitBinding;
  116. defaultValue = new Vector4(defaultX, defaultY, defaultZ, defaultW);
  117. stageCapability = mStageCapability;
  118. }
  119. }
  120. protected abstract MethodInfo GetFunctionToConvert();
  121. private static SlotValueType ConvertTypeToSlotValueType(ParameterInfo p)
  122. {
  123. Type t = p.ParameterType;
  124. if (p.ParameterType.IsByRef)
  125. t = p.ParameterType.GetElementType();
  126. if (t == typeof(Boolean))
  127. {
  128. return SlotValueType.Boolean;
  129. }
  130. if (t == typeof(Vector1))
  131. {
  132. return SlotValueType.Vector1;
  133. }
  134. if (t == typeof(Vector2))
  135. {
  136. return SlotValueType.Vector2;
  137. }
  138. if (t == typeof(Vector3))
  139. {
  140. return SlotValueType.Vector3;
  141. }
  142. if (t == typeof(Vector4))
  143. {
  144. return SlotValueType.Vector4;
  145. }
  146. if (t == typeof(Color))
  147. {
  148. return SlotValueType.Vector4;
  149. }
  150. if (t == typeof(ColorRGBA))
  151. {
  152. return SlotValueType.Vector4;
  153. }
  154. if (t == typeof(ColorRGB))
  155. {
  156. return SlotValueType.Vector3;
  157. }
  158. if (t == typeof(Texture2D))
  159. {
  160. return SlotValueType.Texture2D;
  161. }
  162. if (t == typeof(Texture2DArray))
  163. {
  164. return SlotValueType.Texture2DArray;
  165. }
  166. if (t == typeof(Texture3D))
  167. {
  168. return SlotValueType.Texture3D;
  169. }
  170. if (t == typeof(Cubemap))
  171. {
  172. return SlotValueType.Cubemap;
  173. }
  174. if (t == typeof(Gradient))
  175. {
  176. return SlotValueType.Gradient;
  177. }
  178. if (t == typeof(SamplerState))
  179. {
  180. return SlotValueType.SamplerState;
  181. }
  182. if (t == typeof(DynamicDimensionVector))
  183. {
  184. return SlotValueType.DynamicVector;
  185. }
  186. if (t == typeof(Matrix4x4))
  187. {
  188. return SlotValueType.Matrix4;
  189. }
  190. if (t == typeof(Matrix3x3))
  191. {
  192. return SlotValueType.Matrix3;
  193. }
  194. if (t == typeof(Matrix2x2))
  195. {
  196. return SlotValueType.Matrix2;
  197. }
  198. if (t == typeof(DynamicDimensionMatrix))
  199. {
  200. return SlotValueType.DynamicMatrix;
  201. }
  202. throw new ArgumentException("Unsupported type " + t);
  203. }
  204. public sealed override void UpdateNodeAfterDeserialization()
  205. {
  206. var method = GetFunctionToConvert();
  207. if (method == null)
  208. throw new ArgumentException("Mapped method is null on node" + this);
  209. if (method.ReturnType != typeof(string))
  210. throw new ArgumentException("Mapped function should return string");
  211. // validate no duplicates
  212. var slotAtributes = method.GetParameters().Select(GetSlotAttribute).ToList();
  213. if (slotAtributes.Any(x => x == null))
  214. throw new ArgumentException("Missing SlotAttribute on " + method.Name);
  215. if (slotAtributes.GroupBy(x => x.slotId).Any(x => x.Count() > 1))
  216. throw new ArgumentException("Duplicate SlotAttribute on " + method.Name);
  217. List<MaterialSlot> slots = new List<MaterialSlot>();
  218. foreach (var par in method.GetParameters())
  219. {
  220. var attribute = GetSlotAttribute(par);
  221. var name = GraphUtil.ConvertCamelCase(par.Name, true);
  222. MaterialSlot s;
  223. if (attribute.binding == Binding.None && !par.IsOut && par.ParameterType == typeof(Color))
  224. s = new ColorRGBAMaterialSlot(attribute.slotId, name, par.Name, SlotType.Input, attribute.defaultValue ?? Vector4.zero, stageCapability: attribute.stageCapability, hidden: attribute.hidden);
  225. else if (attribute.binding == Binding.None && !par.IsOut && par.ParameterType == typeof(ColorRGBA))
  226. s = new ColorRGBAMaterialSlot(attribute.slotId, name, par.Name, SlotType.Input, attribute.defaultValue ?? Vector4.zero, stageCapability: attribute.stageCapability, hidden: attribute.hidden);
  227. else if (attribute.binding == Binding.None && !par.IsOut && par.ParameterType == typeof(ColorRGB))
  228. s = new ColorRGBMaterialSlot(attribute.slotId, name, par.Name, SlotType.Input, attribute.defaultValue ?? Vector4.zero, ColorMode.Default, stageCapability: attribute.stageCapability, hidden: attribute.hidden);
  229. else if (attribute.binding == Binding.None || par.IsOut)
  230. s = MaterialSlot.CreateMaterialSlot(
  231. ConvertTypeToSlotValueType(par),
  232. attribute.slotId,
  233. name,
  234. par.Name,
  235. par.IsOut ? SlotType.Output : SlotType.Input,
  236. attribute.defaultValue ?? Vector4.zero,
  237. shaderStageCapability: attribute.stageCapability,
  238. hidden: attribute.hidden);
  239. else
  240. s = CreateBoundSlot(attribute.binding, attribute.slotId, name, par.Name, attribute.stageCapability, attribute.hidden);
  241. slots.Add(s);
  242. m_Slots.Add(attribute);
  243. }
  244. foreach (var slot in slots)
  245. {
  246. AddSlot(slot);
  247. }
  248. RemoveSlotsNameNotMatching(slots.Select(x => x.id));
  249. }
  250. private static MaterialSlot CreateBoundSlot(Binding attributeBinding, int slotId, string displayName, string shaderOutputName, ShaderStageCapability shaderStageCapability, bool hidden)
  251. {
  252. switch (attributeBinding)
  253. {
  254. case Binding.ObjectSpaceNormal:
  255. return new NormalMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Object, shaderStageCapability);
  256. case Binding.ObjectSpaceTangent:
  257. return new TangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Object, shaderStageCapability);
  258. case Binding.ObjectSpaceBitangent:
  259. return new BitangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Object, shaderStageCapability);
  260. case Binding.ObjectSpacePosition:
  261. return new PositionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Object, shaderStageCapability);
  262. case Binding.ViewSpaceNormal:
  263. return new NormalMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.View, shaderStageCapability);
  264. case Binding.ViewSpaceTangent:
  265. return new TangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.View, shaderStageCapability);
  266. case Binding.ViewSpaceBitangent:
  267. return new BitangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.View, shaderStageCapability);
  268. case Binding.ViewSpacePosition:
  269. return new PositionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.View, shaderStageCapability);
  270. case Binding.WorldSpaceNormal:
  271. return new NormalMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.World, shaderStageCapability);
  272. case Binding.WorldSpaceTangent:
  273. return new TangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.World, shaderStageCapability);
  274. case Binding.WorldSpaceBitangent:
  275. return new BitangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.World, shaderStageCapability);
  276. case Binding.WorldSpacePosition:
  277. return new PositionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.World, shaderStageCapability);
  278. case Binding.TangentSpaceNormal:
  279. return new NormalMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Tangent, shaderStageCapability);
  280. case Binding.TangentSpaceTangent:
  281. return new TangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Tangent, shaderStageCapability);
  282. case Binding.TangentSpaceBitangent:
  283. return new BitangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Tangent, shaderStageCapability);
  284. case Binding.TangentSpacePosition:
  285. return new PositionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Tangent, shaderStageCapability);
  286. case Binding.MeshUV0:
  287. return new UVMaterialSlot(slotId, displayName, shaderOutputName, UVChannel.UV0, shaderStageCapability);
  288. case Binding.MeshUV1:
  289. return new UVMaterialSlot(slotId, displayName, shaderOutputName, UVChannel.UV1, shaderStageCapability);
  290. case Binding.MeshUV2:
  291. return new UVMaterialSlot(slotId, displayName, shaderOutputName, UVChannel.UV2, shaderStageCapability);
  292. case Binding.MeshUV3:
  293. return new UVMaterialSlot(slotId, displayName, shaderOutputName, UVChannel.UV3, shaderStageCapability);
  294. case Binding.ScreenPosition:
  295. return new ScreenPositionMaterialSlot(slotId, displayName, shaderOutputName, ScreenSpaceType.Default, shaderStageCapability);
  296. case Binding.ObjectSpaceViewDirection:
  297. return new ViewDirectionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Object, shaderStageCapability);
  298. case Binding.ViewSpaceViewDirection:
  299. return new ViewDirectionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.View, shaderStageCapability);
  300. case Binding.WorldSpaceViewDirection:
  301. return new ViewDirectionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.World, shaderStageCapability);
  302. case Binding.TangentSpaceViewDirection:
  303. return new ViewDirectionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Tangent, shaderStageCapability);
  304. case Binding.VertexColor:
  305. return new VertexColorMaterialSlot(slotId, displayName, shaderOutputName, shaderStageCapability);
  306. default:
  307. throw new ArgumentOutOfRangeException("attributeBinding", attributeBinding, null);
  308. }
  309. }
  310. public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
  311. {
  312. using (var tempSlots = PooledList<MaterialSlot>.Get())
  313. {
  314. GetOutputSlots(tempSlots);
  315. foreach (var outSlot in tempSlots)
  316. {
  317. sb.AppendLine(outSlot.concreteValueType.ToShaderString() + " " + GetVariableNameForSlot(outSlot.id) + ";");
  318. }
  319. string call = GetFunctionName() + "(";
  320. bool first = true;
  321. tempSlots.Clear();
  322. GetSlots(tempSlots);
  323. tempSlots.Sort((slot1, slot2) => slot1.id.CompareTo(slot2.id));
  324. foreach (var slot in tempSlots)
  325. {
  326. if (!first)
  327. {
  328. call += ", ";
  329. }
  330. first = false;
  331. if (slot.isInputSlot)
  332. call += GetSlotValue(slot.id, generationMode);
  333. else
  334. call += GetVariableNameForSlot(slot.id);
  335. }
  336. call += ");";
  337. sb.AppendLine(call);
  338. }
  339. }
  340. private string GetFunctionName()
  341. {
  342. var function = GetFunctionToConvert();
  343. return function.Name + (function.IsStatic ? string.Empty : "_" + GuidEncoder.Encode(guid)) + "_" + concretePrecision.ToShaderString()
  344. + (this.GetSlots<DynamicVectorMaterialSlot>().Select(s => NodeUtils.GetSlotDimension(s.concreteValueType)).FirstOrDefault() ?? "")
  345. + (this.GetSlots<DynamicMatrixMaterialSlot>().Select(s => NodeUtils.GetSlotDimension(s.concreteValueType)).FirstOrDefault() ?? "");
  346. }
  347. private string GetFunctionHeader()
  348. {
  349. string header = "void " + GetFunctionName() + "(";
  350. using (var tempSlots = PooledList<MaterialSlot>.Get())
  351. {
  352. GetSlots(tempSlots);
  353. tempSlots.Sort((slot1, slot2) => slot1.id.CompareTo(slot2.id));
  354. var first = true;
  355. foreach (var slot in tempSlots)
  356. {
  357. if (!first)
  358. header += ", ";
  359. first = false;
  360. if (slot.isOutputSlot)
  361. header += "out ";
  362. header += slot.concreteValueType.ToShaderString() + " " + slot.shaderOutputName;
  363. }
  364. header += ")";
  365. }
  366. return header;
  367. }
  368. private static object GetDefault(Type type)
  369. {
  370. return type.IsValueType ? Activator.CreateInstance(type) : null;
  371. }
  372. private string GetFunctionBody(MethodInfo info)
  373. {
  374. var args = new List<object>();
  375. foreach (var param in info.GetParameters())
  376. args.Add(GetDefault(param.ParameterType));
  377. var result = info.Invoke(this, args.ToArray()) as string;
  378. if (string.IsNullOrEmpty(result))
  379. return string.Empty;
  380. using (var tempSlots = PooledList<MaterialSlot>.Get())
  381. {
  382. GetSlots(tempSlots);
  383. foreach (var slot in tempSlots)
  384. {
  385. var toReplace = string.Format("{{slot{0}dimension}}", slot.id);
  386. var replacement = NodeUtils.GetSlotDimension(slot.concreteValueType);
  387. result = result.Replace(toReplace, replacement);
  388. }
  389. }
  390. return result;
  391. }
  392. public virtual void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode)
  393. {
  394. registry.ProvideFunction(GetFunctionName(), s =>
  395. {
  396. s.AppendLine(GetFunctionHeader());
  397. var functionBody = GetFunctionBody(GetFunctionToConvert());
  398. var lines = functionBody.Trim('\r', '\n', '\t', ' ');
  399. s.AppendLines(lines);
  400. });
  401. }
  402. private static SlotAttribute GetSlotAttribute([NotNull] ParameterInfo info)
  403. {
  404. var attrs = info.GetCustomAttributes(typeof(SlotAttribute), false).OfType<SlotAttribute>().ToList();
  405. return attrs.FirstOrDefault();
  406. }
  407. public NeededCoordinateSpace RequiresNormal(ShaderStageCapability stageCapability)
  408. {
  409. var binding = NeededCoordinateSpace.None;
  410. using (var tempSlots = PooledList<MaterialSlot>.Get())
  411. {
  412. GetInputSlots(tempSlots);
  413. foreach (var slot in tempSlots)
  414. binding |= slot.RequiresNormal();
  415. return binding;
  416. }
  417. }
  418. public NeededCoordinateSpace RequiresViewDirection(ShaderStageCapability stageCapability)
  419. {
  420. var binding = NeededCoordinateSpace.None;
  421. using (var tempSlots = PooledList<MaterialSlot>.Get())
  422. {
  423. GetInputSlots(tempSlots);
  424. foreach (var slot in tempSlots)
  425. binding |= slot.RequiresViewDirection();
  426. return binding;
  427. }
  428. }
  429. public NeededCoordinateSpace RequiresPosition(ShaderStageCapability stageCapability)
  430. {
  431. using (var tempSlots = PooledList<MaterialSlot>.Get())
  432. {
  433. GetInputSlots(tempSlots);
  434. var binding = NeededCoordinateSpace.None;
  435. foreach (var slot in tempSlots)
  436. binding |= slot.RequiresPosition();
  437. return binding;
  438. }
  439. }
  440. public NeededCoordinateSpace RequiresTangent(ShaderStageCapability stageCapability)
  441. {
  442. using (var tempSlots = PooledList<MaterialSlot>.Get())
  443. {
  444. GetInputSlots(tempSlots);
  445. var binding = NeededCoordinateSpace.None;
  446. foreach (var slot in tempSlots)
  447. binding |= slot.RequiresTangent();
  448. return binding;
  449. }
  450. }
  451. public NeededCoordinateSpace RequiresBitangent(ShaderStageCapability stageCapability)
  452. {
  453. using (var tempSlots = PooledList<MaterialSlot>.Get())
  454. {
  455. GetInputSlots(tempSlots);
  456. var binding = NeededCoordinateSpace.None;
  457. foreach (var slot in tempSlots)
  458. binding |= slot.RequiresBitangent();
  459. return binding;
  460. }
  461. }
  462. public bool RequiresMeshUV(UVChannel channel, ShaderStageCapability stageCapability)
  463. {
  464. using (var tempSlots = PooledList<MaterialSlot>.Get())
  465. {
  466. GetInputSlots(tempSlots);
  467. foreach (var slot in tempSlots)
  468. {
  469. if (slot.RequiresMeshUV(channel))
  470. return true;
  471. }
  472. return false;
  473. }
  474. }
  475. public bool RequiresScreenPosition(ShaderStageCapability stageCapability)
  476. {
  477. using (var tempSlots = PooledList<MaterialSlot>.Get())
  478. {
  479. GetInputSlots(tempSlots);
  480. foreach (var slot in tempSlots)
  481. {
  482. if (slot.RequiresScreenPosition())
  483. return true;
  484. }
  485. return false;
  486. }
  487. }
  488. public bool RequiresVertexColor(ShaderStageCapability stageCapability)
  489. {
  490. using (var tempSlots = PooledList<MaterialSlot>.Get())
  491. {
  492. GetInputSlots(tempSlots);
  493. foreach (var slot in tempSlots)
  494. {
  495. if (slot.RequiresVertexColor())
  496. return true;
  497. }
  498. return false;
  499. }
  500. }
  501. }
  502. }