No Description
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.

GenerationUtils.cs 77KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using UnityEditor.Graphing;
  6. using UnityEditor.ShaderGraph.Internal;
  7. using UnityEngine.Profiling;
  8. using Pool = UnityEngine.Pool;
  9. namespace UnityEditor.ShaderGraph
  10. {
  11. internal static class GenerationUtils
  12. {
  13. const string kErrorString = @"ERROR!";
  14. internal static List<FieldDescriptor> GetActiveFieldsFromConditionals(ConditionalField[] conditionalFields)
  15. {
  16. var fields = new List<FieldDescriptor>();
  17. if (conditionalFields != null)
  18. {
  19. foreach (ConditionalField conditionalField in conditionalFields)
  20. {
  21. if (conditionalField.condition == true)
  22. {
  23. fields.Add(conditionalField.field);
  24. }
  25. }
  26. }
  27. return fields;
  28. }
  29. internal static void GenerateSubShaderTags(Target target, SubShaderDescriptor descriptor, ShaderStringBuilder builder)
  30. {
  31. builder.AppendLine("Tags");
  32. using (builder.BlockScope())
  33. {
  34. // Pipeline tag
  35. if (!string.IsNullOrEmpty(descriptor.pipelineTag))
  36. builder.AppendLine($"\"RenderPipeline\"=\"{descriptor.pipelineTag}\"");
  37. else
  38. builder.AppendLine("// RenderPipeline: <None>");
  39. // Render Type
  40. if (!string.IsNullOrEmpty(descriptor.renderType))
  41. builder.AppendLine($"\"RenderType\"=\"{descriptor.renderType}\"");
  42. else
  43. builder.AppendLine("// RenderType: <None>");
  44. // Custom shader tags.
  45. if (!string.IsNullOrEmpty(descriptor.customTags))
  46. builder.AppendLine(descriptor.customTags);
  47. // Render Queue
  48. if (!string.IsNullOrEmpty(descriptor.renderQueue))
  49. builder.AppendLine($"\"Queue\"=\"{descriptor.renderQueue}\"");
  50. else
  51. builder.AppendLine("// Queue: <None>");
  52. // DisableBatching tag
  53. if (!string.IsNullOrEmpty(descriptor.disableBatchingTag))
  54. builder.AppendLine($"\"DisableBatching\"=\"{descriptor.disableBatchingTag}\"");
  55. else
  56. builder.AppendLine("// DisableBatching: <None>");
  57. // ShaderGraphShader tag (so we can tell what shadergraph built)
  58. builder.AppendLine("\"ShaderGraphShader\"=\"true\"");
  59. if (target is IHasMetadata metadata)
  60. builder.AppendLine($"\"ShaderGraphTargetId\"=\"{metadata.identifier}\"");
  61. // IgnoreProjector
  62. if(!string.IsNullOrEmpty(descriptor.IgnoreProjector))
  63. builder.AppendLine($"\"IgnoreProjector\"=\"{descriptor.IgnoreProjector}\"");
  64. // PreviewType
  65. if(!string.IsNullOrEmpty(descriptor.PreviewType))
  66. builder.AppendLine($"\"PreviewType\"=\"{descriptor.PreviewType}\"");
  67. // CanUseSpriteAtlas
  68. if(!string.IsNullOrEmpty(descriptor.CanUseSpriteAtlas))
  69. builder.AppendLine($"\"CanUseSpriteAtlas\"=\"{descriptor.CanUseSpriteAtlas}\"");
  70. }
  71. }
  72. static bool IsFieldActive(FieldDescriptor field, IActiveFields activeFields, bool isOptional)
  73. {
  74. bool fieldActive = true;
  75. if (!activeFields.Contains(field) && isOptional)
  76. fieldActive = false; //if the field is optional and not inside of active fields
  77. return fieldActive;
  78. }
  79. internal static void GenerateShaderStruct(StructDescriptor shaderStruct, ActiveFields activeFields, bool humanReadable, out ShaderStringBuilder structBuilder)
  80. {
  81. structBuilder = new ShaderStringBuilder(humanReadable: humanReadable);
  82. structBuilder.AppendLine($"struct {shaderStruct.name}");
  83. using (structBuilder.BlockSemicolonScope())
  84. {
  85. foreach (var activeField in GetActiveFieldsAndKeyword(shaderStruct, activeFields))
  86. {
  87. var subscript = activeField.field;
  88. var keywordIfDefs = activeField.keywordIfDefs;
  89. //if field is active:
  90. if (subscript.HasPreprocessor())
  91. structBuilder.AppendLine($"#if {subscript.preprocessor}");
  92. //if in permutation, add permutation ifdef
  93. if (!string.IsNullOrEmpty(keywordIfDefs))
  94. structBuilder.AppendLine(keywordIfDefs);
  95. //check for a semantic, build string if valid
  96. string semantic = subscript.HasSemantic() ? $" : {subscript.semantic}" : string.Empty;
  97. structBuilder.AppendLine($"{subscript.interpolation} {subscript.type} {subscript.name}{semantic};");
  98. //if in permutation, add permutation endif
  99. if (!string.IsNullOrEmpty(keywordIfDefs))
  100. structBuilder.AppendLine("#endif"); //TODO: add debug collector
  101. if (subscript.HasPreprocessor())
  102. structBuilder.AppendLine("#endif");
  103. }
  104. }
  105. }
  106. struct PackedEntry
  107. {
  108. public struct Input
  109. {
  110. public FieldDescriptor field;
  111. public int startChannel;
  112. public int channelCount;
  113. }
  114. public Input[] inputFields;
  115. public FieldDescriptor packedField;
  116. }
  117. static IEnumerable<(FieldDescriptor field, string keywordIfDefs)> GetActiveFieldsAndKeyword(StructDescriptor shaderStruct, ActiveFields activeFields)
  118. {
  119. var activeFieldList = shaderStruct.fields
  120. .Select(currentField =>
  121. {
  122. bool fieldIsActive;
  123. var currentKeywordIfDefs = string.Empty;
  124. if (activeFields.permutationCount > 0)
  125. {
  126. //find all active fields per permutation
  127. var instances = activeFields.allPermutations.instances
  128. .Where(i => IsFieldActive(currentField, i, currentField.subscriptOptions.HasFlag(StructFieldOptions.Optional))).ToList();
  129. fieldIsActive = instances.Count > 0;
  130. if (fieldIsActive)
  131. currentKeywordIfDefs = KeywordUtil.GetKeywordPermutationSetConditional(instances.Select(i => i.permutationIndex).ToList());
  132. }
  133. else
  134. fieldIsActive = IsFieldActive(currentField, activeFields.baseInstance, currentField.subscriptOptions.HasFlag(StructFieldOptions.Optional));
  135. //else just find active fields
  136. if (fieldIsActive)
  137. {
  138. return
  139. (
  140. field: currentField,
  141. keywordIfDefs: currentKeywordIfDefs
  142. );
  143. }
  144. return
  145. (
  146. field: null,
  147. keywordIfDefs: null
  148. );
  149. }).Where(o => o.field != null);
  150. return activeFieldList;
  151. }
  152. static IEnumerable<FieldDescriptor> GetActiveFields(StructDescriptor shaderStruct, ActiveFields activeFields)
  153. {
  154. return GetActiveFieldsAndKeyword(shaderStruct, activeFields).Select(o => o.field);
  155. }
  156. static IEnumerable<FieldDescriptor> GetActiveFields(StructDescriptor shaderStruct, IActiveFields activeFields)
  157. {
  158. var activeFieldList = shaderStruct.fields
  159. .Where(field => IsFieldActive(field, activeFields, field.subscriptOptions.HasFlag(StructFieldOptions.Optional)));
  160. return activeFieldList;
  161. }
  162. static PackedEntry[] GeneratePackingLayout(StructDescriptor shaderStruct, ActiveFields activeFields)
  163. {
  164. var activeFieldList = GetActiveFields(shaderStruct, activeFields);
  165. return GeneratePackingLayout(shaderStruct.name, activeFieldList);
  166. }
  167. static PackedEntry[] GeneratePackingLayout(StructDescriptor shaderStruct, IActiveFields activeFields)
  168. {
  169. var activeFieldList = GetActiveFields(shaderStruct, activeFields);
  170. return GeneratePackingLayout(shaderStruct.name, activeFieldList);
  171. }
  172. static PackedEntry[] GeneratePackingLayout(string baseStructName, IEnumerable<FieldDescriptor> activeFields)
  173. {
  174. const int kPreUnpackable = 0;
  175. const int kPackable = 1;
  176. const int kPostUnpackable = 2;
  177. var fieldCategorized = activeFields
  178. .GroupBy(subscript =>
  179. {
  180. if (subscript.HasPreprocessor())
  181. {
  182. //special case, "UNITY_STEREO_INSTANCING_ENABLED" fields must be packed at the end of the struct because they are system generated semantics
  183. if (subscript.preprocessor.Contains("INSTANCING"))
  184. return kPostUnpackable;
  185. //special case, "SHADER_STAGE_FRAGMENT" fields must be packed at the end of the struct,
  186. //otherwise the vertex output struct will have different semantic ordering than the fragment input struct.
  187. if (subscript.preprocessor.Contains("SHADER_STAGE_FRAGMENT"))
  188. return kPostUnpackable;
  189. return kPreUnpackable;
  190. }
  191. if (subscript.HasSemantic() || subscript.vectorCount == 0)
  192. return kPreUnpackable;
  193. return kPackable;
  194. }).OrderBy(o => o.Key);
  195. var packStructName = "Packed" + baseStructName;
  196. int currentInterpolatorIndex = 0;
  197. var packedEntries = new List<PackedEntry>();
  198. foreach (var collection in fieldCategorized)
  199. {
  200. var packingEnabled = collection.Key == kPackable;
  201. if (packingEnabled)
  202. {
  203. var groupByInterpolator = collection.GroupBy(field => string.IsNullOrEmpty(field.interpolation) ? string.Empty : field.interpolation);
  204. foreach (var collectionInterpolator in groupByInterpolator)
  205. {
  206. //OrderByDescending is stable sort
  207. var elementToPack = collectionInterpolator.OrderByDescending(o => o.vectorCount).ToList();
  208. var totalVectorCount = elementToPack.Sum(o => o.vectorCount);
  209. const bool allowSplitting = true;
  210. #pragma warning disable 162
  211. int maxInterpolatorCount;
  212. if (allowSplitting)
  213. maxInterpolatorCount = ((totalVectorCount + 3) & ~0x03) >> 2;
  214. else
  215. maxInterpolatorCount = elementToPack.Count;
  216. #pragma warning restore 162
  217. var intermediateInterpolator = Enumerable.Range(0, maxInterpolatorCount).Select(_ =>
  218. (
  219. fields : new List<PackedEntry.Input>(),
  220. vectorCount : 0
  221. )
  222. ).ToList();
  223. const int kMaxVectorCount = 4;
  224. //First Pass *without* channel splitting
  225. int itElement = 0;
  226. while (itElement < elementToPack.Count)
  227. {
  228. var currentElement = elementToPack[itElement];
  229. var availableSlotIndex = intermediateInterpolator.FindIndex(o =>
  230. o.vectorCount + currentElement.vectorCount <= kMaxVectorCount);
  231. if (availableSlotIndex != -1)
  232. {
  233. elementToPack.RemoveAt(itElement);
  234. var slot = intermediateInterpolator[availableSlotIndex];
  235. slot.vectorCount += currentElement.vectorCount;
  236. slot.fields.Add(new PackedEntry.Input()
  237. {
  238. field = currentElement,
  239. startChannel = 0,
  240. channelCount = currentElement.vectorCount,
  241. });
  242. intermediateInterpolator[availableSlotIndex] = slot;
  243. }
  244. else
  245. {
  246. itElement++;
  247. }
  248. }
  249. if (!allowSplitting && elementToPack.Count > 0)
  250. throw new InvalidOperationException("Unexpected failure in interpolator packing algorithm.");
  251. //Second Pass *with* channel splitting
  252. foreach (var remainingElement in elementToPack)
  253. {
  254. int currentStartChannel = 0;
  255. while (currentStartChannel < remainingElement.vectorCount)
  256. {
  257. var availableSlotIndex = intermediateInterpolator.FindIndex(o => o.vectorCount < kMaxVectorCount);
  258. if (availableSlotIndex == -1)
  259. throw new InvalidOperationException("Unexpected failure in interpolator packing algorithm.");
  260. var slot = intermediateInterpolator[availableSlotIndex];
  261. var currentChannelCount = Math.Min(kMaxVectorCount - slot.vectorCount, kMaxVectorCount - (remainingElement.vectorCount - currentStartChannel));
  262. slot.vectorCount += currentChannelCount;
  263. slot.fields.Add(new PackedEntry.Input()
  264. {
  265. field = remainingElement,
  266. startChannel = currentStartChannel,
  267. channelCount = currentChannelCount,
  268. });
  269. intermediateInterpolator[availableSlotIndex] = slot;
  270. currentStartChannel += currentChannelCount;
  271. }
  272. }
  273. packedEntries.AddRange(intermediateInterpolator
  274. .Where(o => o.vectorCount > 0)
  275. .Select(o =>
  276. {
  277. var allName = o.fields.Select(f =>
  278. f.channelCount == f.field.vectorCount
  279. ? f.field.name
  280. : f.field.name + ShaderSpliceUtil.GetChannelSwizzle(f.startChannel, f.channelCount));
  281. var name = o.fields.Count == 1
  282. ? allName.First()
  283. : "packed_" + allName.Aggregate((a, b) => $"{a}_{b}");
  284. return new PackedEntry()
  285. {
  286. inputFields = o.fields.ToArray(),
  287. packedField = new FieldDescriptor
  288. (
  289. tag: packStructName,
  290. name: name,
  291. define: string.Empty,
  292. type: $"float{o.vectorCount}",
  293. semantic: $"INTERP{currentInterpolatorIndex++}",
  294. preprocessor: string.Empty,
  295. subscriptOptions: StructFieldOptions.Static,
  296. interpolation: collectionInterpolator.Key
  297. )
  298. };
  299. }));
  300. }
  301. }
  302. else
  303. {
  304. foreach (var field in collection)
  305. {
  306. var inputFields = new[]
  307. {
  308. new PackedEntry.Input()
  309. {
  310. field = field,
  311. channelCount = 0,
  312. startChannel = 0
  313. }
  314. };
  315. //Auto add semantic if needed
  316. if (!field.HasSemantic())
  317. {
  318. var newField = new FieldDescriptor
  319. (
  320. tag: packStructName,
  321. name: field.name,
  322. define: field.define,
  323. type: field.type,
  324. semantic: $"INTERP{currentInterpolatorIndex++}",
  325. preprocessor: field.preprocessor,
  326. subscriptOptions: StructFieldOptions.Static,
  327. interpolation: field.interpolation
  328. );
  329. packedEntries.Add(new()
  330. {
  331. inputFields = inputFields,
  332. packedField = newField
  333. });
  334. }
  335. else
  336. {
  337. packedEntries.Add(new PackedEntry()
  338. {
  339. inputFields = inputFields,
  340. packedField = field
  341. });
  342. }
  343. }
  344. }
  345. }
  346. return packedEntries.ToArray();
  347. }
  348. internal static void GeneratePackedStruct(StructDescriptor shaderStruct, ActiveFields activeFields, out StructDescriptor packStruct)
  349. {
  350. var packingLayout = GeneratePackingLayout(shaderStruct, activeFields);
  351. var packStructName = "Packed" + shaderStruct.name;
  352. packStruct = new StructDescriptor()
  353. {
  354. name = packStructName,
  355. packFields = true,
  356. fields = packingLayout.Select(o => o.packedField).ToArray()
  357. };
  358. }
  359. internal static void GenerateInterpolatorFunctions(StructDescriptor shaderStruct, IActiveFields activeFields, bool humanReadable, out ShaderStringBuilder interpolatorBuilder)
  360. {
  361. //set up function string builders and struct builder
  362. var packBuilder = new ShaderStringBuilder(humanReadable: humanReadable);
  363. var unpackBuilder = new ShaderStringBuilder(humanReadable: humanReadable);
  364. interpolatorBuilder = new ShaderStringBuilder(humanReadable: humanReadable);
  365. string packedStruct = "Packed" + shaderStruct.name;
  366. //declare function headers
  367. packBuilder.AppendLine($"{packedStruct} Pack{shaderStruct.name} ({shaderStruct.name} input)");
  368. packBuilder.AppendLine("{");
  369. packBuilder.IncreaseIndent();
  370. packBuilder.AppendLine($"{packedStruct} output;");
  371. packBuilder.AppendLine($"ZERO_INITIALIZE({packedStruct}, output);");
  372. unpackBuilder.AppendLine($"{shaderStruct.name} Unpack{shaderStruct.name} ({packedStruct} input)");
  373. unpackBuilder.AppendLine("{");
  374. unpackBuilder.IncreaseIndent();
  375. unpackBuilder.AppendLine($"{shaderStruct.name} output;");
  376. var packingLayout = GeneratePackingLayout(shaderStruct, activeFields);
  377. foreach (var packEntry in packingLayout)
  378. {
  379. int firstPackedChannel = 0;
  380. foreach (var input in packEntry.inputFields)
  381. {
  382. if (input.field.HasPreprocessor())
  383. {
  384. packBuilder.AppendLine($"#if {input.field.preprocessor}");
  385. unpackBuilder.AppendLine($"#if {input.field.preprocessor}");
  386. }
  387. var packedChannels = string.Empty;
  388. var unpackedChannel = string.Empty;
  389. if (input.channelCount != 0)
  390. {
  391. if (firstPackedChannel != 0 || input.channelCount != packEntry.packedField.vectorCount)
  392. packedChannels = $".{ShaderSpliceUtil.GetChannelSwizzle(firstPackedChannel, input.channelCount)}";
  393. if (input.startChannel != 0 || input.channelCount != input.field.vectorCount)
  394. unpackedChannel = $".{ShaderSpliceUtil.GetChannelSwizzle(input.startChannel, input.channelCount)}";
  395. }
  396. packBuilder.AppendLine($"output.{packEntry.packedField.name}{packedChannels} = input.{input.field.name}{unpackedChannel};");
  397. unpackBuilder.AppendLine($"output.{input.field.name}{unpackedChannel} = input.{packEntry.packedField.name}{packedChannels};");
  398. firstPackedChannel += input.field.vectorCount;
  399. if (input.field.HasPreprocessor())
  400. {
  401. packBuilder.AppendLine("#endif");
  402. unpackBuilder.AppendLine("#endif");
  403. }
  404. }
  405. }
  406. //close function declarations
  407. packBuilder.AppendLine("return output;");
  408. packBuilder.DecreaseIndent();
  409. packBuilder.AppendLine("}");
  410. packBuilder.AppendNewLine();
  411. unpackBuilder.AppendLine("return output;");
  412. unpackBuilder.DecreaseIndent();
  413. unpackBuilder.AppendLine("}");
  414. unpackBuilder.AppendNewLine();
  415. interpolatorBuilder.Concat(packBuilder);
  416. interpolatorBuilder.Concat(unpackBuilder);
  417. }
  418. internal static void GetUpstreamNodesForShaderPass(AbstractMaterialNode outputNode, PassDescriptor pass, out List<AbstractMaterialNode> vertexNodes, out List<AbstractMaterialNode> pixelNodes)
  419. {
  420. // Traverse Graph Data
  421. vertexNodes = Pool.ListPool<AbstractMaterialNode>.Get();
  422. NodeUtils.DepthFirstCollectNodesFromNode(vertexNodes, outputNode, NodeUtils.IncludeSelf.Include);
  423. pixelNodes = Pool.ListPool<AbstractMaterialNode>.Get();
  424. NodeUtils.DepthFirstCollectNodesFromNode(pixelNodes, outputNode, NodeUtils.IncludeSelf.Include);
  425. }
  426. internal static void GetActiveFieldsAndPermutationsForNodes(PassDescriptor pass,
  427. KeywordCollector keywordCollector, List<AbstractMaterialNode> vertexNodes, List<AbstractMaterialNode> pixelNodes,
  428. bool[] texCoordNeedsDerivs,
  429. List<int>[] vertexNodePermutations, List<int>[] pixelNodePermutations,
  430. ActiveFields activeFields, out ShaderGraphRequirementsPerKeyword graphRequirements)
  431. {
  432. // Initialize requirements
  433. ShaderGraphRequirementsPerKeyword pixelRequirements = new ShaderGraphRequirementsPerKeyword();
  434. ShaderGraphRequirementsPerKeyword vertexRequirements = new ShaderGraphRequirementsPerKeyword();
  435. graphRequirements = new ShaderGraphRequirementsPerKeyword();
  436. // Evaluate all Keyword permutations
  437. if (keywordCollector.permutations.Count > 0)
  438. {
  439. for (int i = 0; i < keywordCollector.permutations.Count; i++)
  440. {
  441. // Get active nodes for this permutation
  442. var localVertexNodes = Pool.HashSetPool<AbstractMaterialNode>.Get();
  443. var localPixelNodes = Pool.HashSetPool<AbstractMaterialNode>.Get();
  444. localVertexNodes.EnsureCapacity(vertexNodes.Count);
  445. localPixelNodes.EnsureCapacity(pixelNodes.Count);
  446. foreach (var vertexNode in vertexNodes)
  447. {
  448. NodeUtils.DepthFirstCollectNodesFromNode(localVertexNodes, vertexNode, NodeUtils.IncludeSelf.Include, keywordCollector.permutations[i]);
  449. }
  450. foreach (var pixelNode in pixelNodes)
  451. {
  452. NodeUtils.DepthFirstCollectNodesFromNode(localPixelNodes, pixelNode, NodeUtils.IncludeSelf.Include, keywordCollector.permutations[i]);
  453. }
  454. // Track each vertex node in this permutation
  455. foreach (AbstractMaterialNode vertexNode in localVertexNodes)
  456. {
  457. int nodeIndex = vertexNodes.IndexOf(vertexNode);
  458. if (vertexNodePermutations[nodeIndex] == null)
  459. vertexNodePermutations[nodeIndex] = new List<int>();
  460. vertexNodePermutations[nodeIndex].Add(i);
  461. }
  462. // Track each pixel node in this permutation
  463. foreach (AbstractMaterialNode pixelNode in localPixelNodes)
  464. {
  465. int nodeIndex = pixelNodes.IndexOf(pixelNode);
  466. if (pixelNodePermutations[nodeIndex] == null)
  467. pixelNodePermutations[nodeIndex] = new List<int>();
  468. pixelNodePermutations[nodeIndex].Add(i);
  469. }
  470. // Get requirements for this permutation
  471. vertexRequirements[i].SetRequirements(ShaderGraphRequirements.FromNodes(localVertexNodes, ShaderStageCapability.Vertex, false, texCoordNeedsDerivs));
  472. pixelRequirements[i].SetRequirements(ShaderGraphRequirements.FromNodes(localPixelNodes, ShaderStageCapability.Fragment, false, texCoordNeedsDerivs));
  473. // Add active fields
  474. var conditionalFields = GetActiveFieldsFromConditionals(GetConditionalFieldsFromPixelRequirements(pixelRequirements[i].requirements));
  475. if (activeFields[i].Contains(Fields.GraphVertex))
  476. {
  477. conditionalFields.AddRange(GetActiveFieldsFromConditionals(GetConditionalFieldsFromVertexRequirements(vertexRequirements[i].requirements)));
  478. }
  479. foreach (var field in conditionalFields)
  480. {
  481. activeFields[i].Add(field);
  482. }
  483. }
  484. }
  485. // No Keywords
  486. else
  487. {
  488. // Get requirements
  489. vertexRequirements.baseInstance.SetRequirements(ShaderGraphRequirements.FromNodes(vertexNodes, ShaderStageCapability.Vertex, false, texCoordNeedsDerivs));
  490. pixelRequirements.baseInstance.SetRequirements(ShaderGraphRequirements.FromNodes(pixelNodes, ShaderStageCapability.Fragment, false, texCoordNeedsDerivs));
  491. // Add active fields
  492. var conditionalFields = GetActiveFieldsFromConditionals(GetConditionalFieldsFromPixelRequirements(pixelRequirements.baseInstance.requirements));
  493. if (activeFields.baseInstance.Contains(Fields.GraphVertex))
  494. {
  495. conditionalFields.AddRange(GetActiveFieldsFromConditionals(GetConditionalFieldsFromVertexRequirements(vertexRequirements.baseInstance.requirements)));
  496. }
  497. foreach (var field in conditionalFields)
  498. {
  499. activeFields.baseInstance.Add(field);
  500. }
  501. }
  502. // Build graph requirements
  503. graphRequirements.UnionWith(pixelRequirements);
  504. graphRequirements.UnionWith(vertexRequirements);
  505. }
  506. static ConditionalField[] GetConditionalFieldsFromVertexRequirements(ShaderGraphRequirements requirements)
  507. {
  508. return new ConditionalField[]
  509. {
  510. new ConditionalField(StructFields.VertexDescriptionInputs.ScreenPosition, requirements.requiresScreenPosition),
  511. new ConditionalField(StructFields.VertexDescriptionInputs.NDCPosition, requirements.requiresNDCPosition),
  512. new ConditionalField(StructFields.VertexDescriptionInputs.PixelPosition, requirements.requiresPixelPosition),
  513. new ConditionalField(StructFields.VertexDescriptionInputs.VertexColor, requirements.requiresVertexColor),
  514. new ConditionalField(StructFields.VertexDescriptionInputs.ObjectSpaceNormal, (requirements.requiresNormal & NeededCoordinateSpace.Object) > 0),
  515. new ConditionalField(StructFields.VertexDescriptionInputs.ViewSpaceNormal, (requirements.requiresNormal & NeededCoordinateSpace.View) > 0),
  516. new ConditionalField(StructFields.VertexDescriptionInputs.WorldSpaceNormal, (requirements.requiresNormal & NeededCoordinateSpace.World) > 0),
  517. new ConditionalField(StructFields.VertexDescriptionInputs.TangentSpaceNormal, (requirements.requiresNormal & NeededCoordinateSpace.Tangent) > 0),
  518. new ConditionalField(StructFields.VertexDescriptionInputs.ObjectSpaceViewDirection, (requirements.requiresViewDir & NeededCoordinateSpace.Object) > 0),
  519. new ConditionalField(StructFields.VertexDescriptionInputs.ViewSpaceViewDirection, (requirements.requiresViewDir & NeededCoordinateSpace.View) > 0),
  520. new ConditionalField(StructFields.VertexDescriptionInputs.WorldSpaceViewDirection, (requirements.requiresViewDir & NeededCoordinateSpace.World) > 0),
  521. new ConditionalField(StructFields.VertexDescriptionInputs.TangentSpaceViewDirection, (requirements.requiresViewDir & NeededCoordinateSpace.Tangent) > 0),
  522. new ConditionalField(StructFields.VertexDescriptionInputs.ObjectSpaceTangent, (requirements.requiresTangent & NeededCoordinateSpace.Object) > 0),
  523. new ConditionalField(StructFields.VertexDescriptionInputs.ViewSpaceTangent, (requirements.requiresTangent & NeededCoordinateSpace.View) > 0),
  524. new ConditionalField(StructFields.VertexDescriptionInputs.WorldSpaceTangent, (requirements.requiresTangent & NeededCoordinateSpace.World) > 0),
  525. new ConditionalField(StructFields.VertexDescriptionInputs.TangentSpaceTangent, (requirements.requiresTangent & NeededCoordinateSpace.Tangent) > 0),
  526. new ConditionalField(StructFields.VertexDescriptionInputs.ObjectSpaceBiTangent, (requirements.requiresBitangent & NeededCoordinateSpace.Object) > 0),
  527. new ConditionalField(StructFields.VertexDescriptionInputs.ViewSpaceBiTangent, (requirements.requiresBitangent & NeededCoordinateSpace.View) > 0),
  528. new ConditionalField(StructFields.VertexDescriptionInputs.WorldSpaceBiTangent, (requirements.requiresBitangent & NeededCoordinateSpace.World) > 0),
  529. new ConditionalField(StructFields.VertexDescriptionInputs.TangentSpaceBiTangent, (requirements.requiresBitangent & NeededCoordinateSpace.Tangent) > 0),
  530. new ConditionalField(StructFields.VertexDescriptionInputs.ObjectSpacePosition, (requirements.requiresPosition & NeededCoordinateSpace.Object) > 0),
  531. new ConditionalField(StructFields.VertexDescriptionInputs.ViewSpacePosition, (requirements.requiresPosition & NeededCoordinateSpace.View) > 0),
  532. new ConditionalField(StructFields.VertexDescriptionInputs.WorldSpacePosition, (requirements.requiresPosition & NeededCoordinateSpace.World) > 0),
  533. new ConditionalField(StructFields.VertexDescriptionInputs.TangentSpacePosition, (requirements.requiresPosition & NeededCoordinateSpace.Tangent) > 0),
  534. new ConditionalField(StructFields.VertexDescriptionInputs.AbsoluteWorldSpacePosition, (requirements.requiresPosition & NeededCoordinateSpace.AbsoluteWorld) > 0),
  535. new ConditionalField(StructFields.VertexDescriptionInputs.ObjectSpacePositionPredisplacement, (requirements.requiresPositionPredisplacement & NeededCoordinateSpace.Object) > 0),
  536. new ConditionalField(StructFields.VertexDescriptionInputs.ViewSpacePositionPredisplacement, (requirements.requiresPositionPredisplacement & NeededCoordinateSpace.View) > 0),
  537. new ConditionalField(StructFields.VertexDescriptionInputs.WorldSpacePositionPredisplacement, (requirements.requiresPositionPredisplacement & NeededCoordinateSpace.World) > 0),
  538. new ConditionalField(StructFields.VertexDescriptionInputs.TangentSpacePositionPredisplacement, (requirements.requiresPositionPredisplacement & NeededCoordinateSpace.Tangent) > 0),
  539. new ConditionalField(StructFields.VertexDescriptionInputs.AbsoluteWorldSpacePositionPredisplacement, (requirements.requiresPositionPredisplacement & NeededCoordinateSpace.AbsoluteWorld) > 0),
  540. new ConditionalField(StructFields.VertexDescriptionInputs.uv0, requirements.requiresMeshUVs.Contains(UVChannel.UV0)),
  541. new ConditionalField(StructFields.VertexDescriptionInputs.uv1, requirements.requiresMeshUVs.Contains(UVChannel.UV1)),
  542. new ConditionalField(StructFields.VertexDescriptionInputs.uv2, requirements.requiresMeshUVs.Contains(UVChannel.UV2)),
  543. new ConditionalField(StructFields.VertexDescriptionInputs.uv3, requirements.requiresMeshUVs.Contains(UVChannel.UV3)),
  544. new ConditionalField(GeneratorDerivativeUtils.uv0Ddx, requirements.requiresMeshUVDerivatives.Contains(UVChannel.UV0)),
  545. new ConditionalField(GeneratorDerivativeUtils.uv0Ddy, requirements.requiresMeshUVDerivatives.Contains(UVChannel.UV0)),
  546. new ConditionalField(GeneratorDerivativeUtils.uv1Ddx, requirements.requiresMeshUVDerivatives.Contains(UVChannel.UV1)),
  547. new ConditionalField(GeneratorDerivativeUtils.uv1Ddy, requirements.requiresMeshUVDerivatives.Contains(UVChannel.UV1)),
  548. new ConditionalField(GeneratorDerivativeUtils.uv2Ddx, requirements.requiresMeshUVDerivatives.Contains(UVChannel.UV2)),
  549. new ConditionalField(GeneratorDerivativeUtils.uv2Ddy, requirements.requiresMeshUVDerivatives.Contains(UVChannel.UV2)),
  550. new ConditionalField(GeneratorDerivativeUtils.uv3Ddx, requirements.requiresMeshUVDerivatives.Contains(UVChannel.UV3)),
  551. new ConditionalField(GeneratorDerivativeUtils.uv3Ddy, requirements.requiresMeshUVDerivatives.Contains(UVChannel.UV3)),
  552. new ConditionalField(StructFields.VertexDescriptionInputs.TimeParameters, requirements.requiresTime),
  553. new ConditionalField(StructFields.VertexDescriptionInputs.BoneWeights, requirements.requiresVertexSkinning),
  554. new ConditionalField(StructFields.VertexDescriptionInputs.BoneIndices, requirements.requiresVertexSkinning),
  555. new ConditionalField(StructFields.VertexDescriptionInputs.VertexID, requirements.requiresVertexID),
  556. new ConditionalField(StructFields.VertexDescriptionInputs.InstanceID, requirements.requiresInstanceID),
  557. new ConditionalField(Fields.ObjectToWorld, requirements.requiresTransforms.Contains(NeededTransform.ObjectToWorld)),
  558. new ConditionalField(Fields.WorldToObject, requirements.requiresTransforms.Contains(NeededTransform.WorldToObject)),
  559. };
  560. }
  561. static ConditionalField[] GetConditionalFieldsFromPixelRequirements(ShaderGraphRequirements requirements)
  562. {
  563. return new ConditionalField[]
  564. {
  565. new ConditionalField(StructFields.SurfaceDescriptionInputs.ScreenPosition, requirements.requiresScreenPosition),
  566. new ConditionalField(StructFields.SurfaceDescriptionInputs.NDCPosition, requirements.requiresNDCPosition),
  567. new ConditionalField(StructFields.SurfaceDescriptionInputs.PixelPosition, requirements.requiresPixelPosition),
  568. new ConditionalField(StructFields.SurfaceDescriptionInputs.VertexColor, requirements.requiresVertexColor),
  569. new ConditionalField(StructFields.SurfaceDescriptionInputs.FaceSign, requirements.requiresFaceSign),
  570. new ConditionalField(StructFields.SurfaceDescriptionInputs.ObjectSpaceNormal, (requirements.requiresNormal & NeededCoordinateSpace.Object) > 0),
  571. new ConditionalField(StructFields.SurfaceDescriptionInputs.ViewSpaceNormal, (requirements.requiresNormal & NeededCoordinateSpace.View) > 0),
  572. new ConditionalField(StructFields.SurfaceDescriptionInputs.WorldSpaceNormal, (requirements.requiresNormal & NeededCoordinateSpace.World) > 0),
  573. new ConditionalField(StructFields.SurfaceDescriptionInputs.TangentSpaceNormal, (requirements.requiresNormal & NeededCoordinateSpace.Tangent) > 0),
  574. new ConditionalField(StructFields.SurfaceDescriptionInputs.ObjectSpaceViewDirection, (requirements.requiresViewDir & NeededCoordinateSpace.Object) > 0),
  575. new ConditionalField(StructFields.SurfaceDescriptionInputs.ViewSpaceViewDirection, (requirements.requiresViewDir & NeededCoordinateSpace.View) > 0),
  576. new ConditionalField(StructFields.SurfaceDescriptionInputs.WorldSpaceViewDirection, (requirements.requiresViewDir & NeededCoordinateSpace.World) > 0),
  577. new ConditionalField(StructFields.SurfaceDescriptionInputs.TangentSpaceViewDirection, (requirements.requiresViewDir & NeededCoordinateSpace.Tangent) > 0),
  578. new ConditionalField(StructFields.SurfaceDescriptionInputs.ObjectSpaceTangent, (requirements.requiresTangent & NeededCoordinateSpace.Object) > 0),
  579. new ConditionalField(StructFields.SurfaceDescriptionInputs.ViewSpaceTangent, (requirements.requiresTangent & NeededCoordinateSpace.View) > 0),
  580. new ConditionalField(StructFields.SurfaceDescriptionInputs.WorldSpaceTangent, (requirements.requiresTangent & NeededCoordinateSpace.World) > 0),
  581. new ConditionalField(StructFields.SurfaceDescriptionInputs.TangentSpaceTangent, (requirements.requiresTangent & NeededCoordinateSpace.Tangent) > 0),
  582. new ConditionalField(StructFields.SurfaceDescriptionInputs.ObjectSpaceBiTangent, (requirements.requiresBitangent & NeededCoordinateSpace.Object) > 0),
  583. new ConditionalField(StructFields.SurfaceDescriptionInputs.ViewSpaceBiTangent, (requirements.requiresBitangent & NeededCoordinateSpace.View) > 0),
  584. new ConditionalField(StructFields.SurfaceDescriptionInputs.WorldSpaceBiTangent, (requirements.requiresBitangent & NeededCoordinateSpace.World) > 0),
  585. new ConditionalField(StructFields.SurfaceDescriptionInputs.TangentSpaceBiTangent, (requirements.requiresBitangent & NeededCoordinateSpace.Tangent) > 0),
  586. new ConditionalField(StructFields.SurfaceDescriptionInputs.ObjectSpacePosition, (requirements.requiresPosition & NeededCoordinateSpace.Object) > 0),
  587. new ConditionalField(StructFields.SurfaceDescriptionInputs.ViewSpacePosition, (requirements.requiresPosition & NeededCoordinateSpace.View) > 0),
  588. new ConditionalField(StructFields.SurfaceDescriptionInputs.WorldSpacePosition, (requirements.requiresPosition & NeededCoordinateSpace.World) > 0),
  589. new ConditionalField(StructFields.SurfaceDescriptionInputs.TangentSpacePosition, (requirements.requiresPosition & NeededCoordinateSpace.Tangent) > 0),
  590. new ConditionalField(StructFields.SurfaceDescriptionInputs.AbsoluteWorldSpacePosition, (requirements.requiresPosition & NeededCoordinateSpace.AbsoluteWorld) > 0),
  591. new ConditionalField(StructFields.SurfaceDescriptionInputs.ObjectSpacePositionPredisplacement, (requirements.requiresPositionPredisplacement & NeededCoordinateSpace.Object) > 0),
  592. new ConditionalField(StructFields.SurfaceDescriptionInputs.ViewSpacePositionPredisplacement, (requirements.requiresPositionPredisplacement & NeededCoordinateSpace.View) > 0),
  593. new ConditionalField(StructFields.SurfaceDescriptionInputs.WorldSpacePositionPredisplacement, (requirements.requiresPositionPredisplacement & NeededCoordinateSpace.World) > 0),
  594. new ConditionalField(StructFields.SurfaceDescriptionInputs.TangentSpacePositionPredisplacement, (requirements.requiresPositionPredisplacement & NeededCoordinateSpace.Tangent) > 0),
  595. new ConditionalField(StructFields.SurfaceDescriptionInputs.AbsoluteWorldSpacePositionPredisplacement, (requirements.requiresPositionPredisplacement & NeededCoordinateSpace.AbsoluteWorld) > 0),
  596. new ConditionalField(StructFields.SurfaceDescriptionInputs.uv0, requirements.requiresMeshUVs.Contains(UVChannel.UV0)),
  597. new ConditionalField(StructFields.SurfaceDescriptionInputs.uv1, requirements.requiresMeshUVs.Contains(UVChannel.UV1)),
  598. new ConditionalField(StructFields.SurfaceDescriptionInputs.uv2, requirements.requiresMeshUVs.Contains(UVChannel.UV2)),
  599. new ConditionalField(StructFields.SurfaceDescriptionInputs.uv3, requirements.requiresMeshUVs.Contains(UVChannel.UV3)),
  600. new ConditionalField(StructFields.SurfaceDescriptionInputs.TimeParameters, requirements.requiresTime),
  601. new ConditionalField(StructFields.SurfaceDescriptionInputs.BoneWeights, requirements.requiresVertexSkinning),
  602. new ConditionalField(StructFields.SurfaceDescriptionInputs.BoneIndices, requirements.requiresVertexSkinning),
  603. new ConditionalField(StructFields.SurfaceDescriptionInputs.VertexID, requirements.requiresVertexID),
  604. new ConditionalField(StructFields.SurfaceDescriptionInputs.InstanceID, requirements.requiresInstanceID),
  605. new ConditionalField(Fields.ObjectToWorld, requirements.requiresTransforms.Contains(NeededTransform.ObjectToWorld)),
  606. new ConditionalField(Fields.WorldToObject, requirements.requiresTransforms.Contains(NeededTransform.WorldToObject)),
  607. };
  608. }
  609. internal static void AddRequiredFields(FieldCollection passRequiredFields, IActiveFieldsSet activeFields)
  610. {
  611. if (passRequiredFields != null)
  612. {
  613. foreach (FieldCollection.Item requiredField in passRequiredFields)
  614. {
  615. activeFields.AddAll(requiredField.field);
  616. }
  617. }
  618. }
  619. internal static void ApplyFieldDependencies(IActiveFields activeFields, DependencyCollection dependencies)
  620. {
  621. // add active fields to queue
  622. Queue<FieldDescriptor> fieldsToPropagate = new Queue<FieldDescriptor>();
  623. foreach (var f in activeFields.fields)
  624. {
  625. fieldsToPropagate.Enqueue(f);
  626. }
  627. // foreach field in queue:
  628. while (fieldsToPropagate.Count > 0)
  629. {
  630. FieldDescriptor field = fieldsToPropagate.Dequeue();
  631. if (activeFields.Contains(field)) // this should always be true
  632. {
  633. if (dependencies == null)
  634. return;
  635. // find all dependencies of field that are not already active
  636. foreach (DependencyCollection.Item d in dependencies.Where(d => (d.dependency.field == field) && !activeFields.Contains(d.dependency.dependsOn)))
  637. {
  638. // activate them and add them to the queue
  639. activeFields.Add(d.dependency.dependsOn);
  640. fieldsToPropagate.Enqueue(d.dependency.dependsOn);
  641. }
  642. }
  643. }
  644. }
  645. internal static List<MaterialSlot> FindMaterialSlotsOnNode(IEnumerable<int> slots, AbstractMaterialNode node)
  646. {
  647. if (slots == null)
  648. return null;
  649. var activeSlots = new List<MaterialSlot>();
  650. foreach (var id in slots)
  651. {
  652. MaterialSlot slot = node.FindSlot<MaterialSlot>(id);
  653. if (slot != null)
  654. {
  655. activeSlots.Add(slot);
  656. }
  657. }
  658. return activeSlots;
  659. }
  660. internal static string AdaptNodeOutput(AbstractMaterialNode node, int outputSlotId, ConcreteSlotValueType convertToType)
  661. {
  662. var outputSlot = node.FindOutputSlot<MaterialSlot>(outputSlotId);
  663. if (outputSlot == null)
  664. return kErrorString;
  665. var convertFromType = outputSlot.concreteValueType;
  666. var rawOutput = node.GetVariableNameForSlot(outputSlotId);
  667. if (convertFromType == convertToType)
  668. return rawOutput;
  669. switch (convertToType)
  670. {
  671. case ConcreteSlotValueType.Boolean:
  672. switch (convertFromType)
  673. {
  674. case ConcreteSlotValueType.Vector1:
  675. return string.Format("((bool) {0})", rawOutput);
  676. case ConcreteSlotValueType.Vector2:
  677. case ConcreteSlotValueType.Vector3:
  678. case ConcreteSlotValueType.Vector4:
  679. return string.Format("((bool) {0}.x)", rawOutput);
  680. default:
  681. return kErrorString;
  682. }
  683. case ConcreteSlotValueType.Vector1:
  684. if (convertFromType == ConcreteSlotValueType.Boolean)
  685. return string.Format("(($precision) {0})", rawOutput);
  686. else
  687. return string.Format("({0}).x", rawOutput);
  688. case ConcreteSlotValueType.Vector2:
  689. switch (convertFromType)
  690. {
  691. case ConcreteSlotValueType.Boolean:
  692. return string.Format("((($precision) {0}).xx)", rawOutput);
  693. case ConcreteSlotValueType.Vector1:
  694. return string.Format("({0}.xx)", rawOutput);
  695. case ConcreteSlotValueType.Vector3:
  696. case ConcreteSlotValueType.Vector4:
  697. return string.Format("({0}.xy)", rawOutput);
  698. default:
  699. return kErrorString;
  700. }
  701. case ConcreteSlotValueType.Vector3:
  702. switch (convertFromType)
  703. {
  704. case ConcreteSlotValueType.Boolean:
  705. return string.Format("((($precision) {0}).xxx)", rawOutput);
  706. case ConcreteSlotValueType.Vector1:
  707. return string.Format("({0}.xxx)", rawOutput);
  708. case ConcreteSlotValueType.Vector2:
  709. return string.Format("($precision3({0}, 0.0))", rawOutput);
  710. case ConcreteSlotValueType.Vector4:
  711. return string.Format("({0}.xyz)", rawOutput);
  712. default:
  713. return kErrorString;
  714. }
  715. case ConcreteSlotValueType.Vector4:
  716. switch (convertFromType)
  717. {
  718. case ConcreteSlotValueType.Boolean:
  719. return string.Format("((($precision) {0}).xxxx)", rawOutput);
  720. case ConcreteSlotValueType.Vector1:
  721. return string.Format("({0}.xxxx)", rawOutput);
  722. case ConcreteSlotValueType.Vector2:
  723. return string.Format("($precision4({0}, 0.0, 1.0))", rawOutput);
  724. case ConcreteSlotValueType.Vector3:
  725. return string.Format("($precision4({0}, 1.0))", rawOutput);
  726. default:
  727. return kErrorString;
  728. }
  729. case ConcreteSlotValueType.Matrix3:
  730. return rawOutput;
  731. case ConcreteSlotValueType.Matrix2:
  732. return rawOutput;
  733. case ConcreteSlotValueType.PropertyConnectionState:
  734. return node.GetConnnectionStateVariableNameForSlot(outputSlotId);
  735. default:
  736. return kErrorString;
  737. }
  738. }
  739. internal static string AdaptNodeOutputForPreview(AbstractMaterialNode node, int outputSlotId)
  740. {
  741. string rawOutput = node.GetVariableNameForSlot(outputSlotId);
  742. return AdaptNodeOutputForPreview(node, outputSlotId, rawOutput);
  743. }
  744. internal static string AdaptNodeOutputForPreview(AbstractMaterialNode node, int slotId, string variableName)
  745. {
  746. var slot = node.FindSlot<MaterialSlot>(slotId);
  747. if (slot == null)
  748. return kErrorString;
  749. var convertFromType = slot.concreteValueType;
  750. // preview is always dimension 4
  751. switch (convertFromType)
  752. {
  753. case ConcreteSlotValueType.Vector1:
  754. return string.Format("half4({0}, {0}, {0}, 1.0)", variableName);
  755. case ConcreteSlotValueType.Vector2:
  756. return string.Format("half4({0}.x, {0}.y, 0.0, 1.0)", variableName);
  757. case ConcreteSlotValueType.Vector3:
  758. return string.Format("half4({0}.x, {0}.y, {0}.z, 1.0)", variableName);
  759. case ConcreteSlotValueType.Vector4:
  760. return string.Format("half4({0}.x, {0}.y, {0}.z, 1.0)", variableName);
  761. case ConcreteSlotValueType.Boolean:
  762. return string.Format("half4({0}, {0}, {0}, 1.0)", variableName);
  763. default:
  764. return "half4(0, 0, 0, 0)";
  765. }
  766. }
  767. static void GenerateSpaceTranslationSurfaceInputs(
  768. NeededCoordinateSpace neededSpaces,
  769. InterpolatorType interpolatorType,
  770. ShaderStringBuilder builder,
  771. string format = "float3 {0};")
  772. {
  773. if ((neededSpaces & NeededCoordinateSpace.Object) > 0)
  774. builder.AppendLine(format, CoordinateSpace.Object.ToVariableName(interpolatorType));
  775. if ((neededSpaces & NeededCoordinateSpace.World) > 0)
  776. builder.AppendLine(format, CoordinateSpace.World.ToVariableName(interpolatorType));
  777. if ((neededSpaces & NeededCoordinateSpace.View) > 0)
  778. builder.AppendLine(format, CoordinateSpace.View.ToVariableName(interpolatorType));
  779. if ((neededSpaces & NeededCoordinateSpace.Tangent) > 0)
  780. builder.AppendLine(format, CoordinateSpace.Tangent.ToVariableName(interpolatorType));
  781. if ((neededSpaces & NeededCoordinateSpace.AbsoluteWorld) > 0)
  782. builder.AppendLine(format, CoordinateSpace.AbsoluteWorld.ToVariableName(interpolatorType));
  783. }
  784. internal static void GeneratePropertiesBlock(ShaderStringBuilder sb, PropertyCollector propertyCollector, KeywordCollector keywordCollector, GenerationMode mode, List<GraphInputData> graphInputs)
  785. {
  786. sb.AppendLine("Properties");
  787. using (sb.BlockScope())
  788. {
  789. if (graphInputs == null || graphInputs.Count == 0)
  790. {
  791. foreach (var prop in propertyCollector.properties.Where(x => x.shouldGeneratePropertyBlock))
  792. {
  793. prop.AppendPropertyBlockStrings(sb);
  794. }
  795. // Keywords use hardcoded state in preview
  796. // Do not add them to the Property Block
  797. if (mode == GenerationMode.Preview)
  798. return;
  799. foreach (var key in keywordCollector.keywords.Where(x => x.generatePropertyBlock))
  800. {
  801. key.AppendPropertyBlockStrings(sb);
  802. }
  803. }
  804. else
  805. {
  806. var propertyInputs = propertyCollector.properties.Where(x => x.shouldGeneratePropertyBlock).ToList();
  807. var keywordInputs = keywordCollector.keywords.Where(x => x.generatePropertyBlock).ToList();
  808. foreach (var input in graphInputs)
  809. {
  810. if (input.isKeyword && mode != GenerationMode.Preview)
  811. {
  812. var keyword = keywordInputs.FirstOrDefault(x => x.referenceName.CompareTo(input.referenceName) == 0);
  813. if (keyword != null)
  814. {
  815. keyword.AppendPropertyBlockStrings(sb);
  816. keywordInputs.Remove(keyword);
  817. }
  818. }
  819. else if (!input.isKeyword)
  820. {
  821. var property = propertyInputs.FirstOrDefault(x => x.referenceName.CompareTo(input.referenceName) == 0);
  822. if (property != null)
  823. {
  824. property.AppendPropertyBlockStrings(sb);
  825. propertyInputs.Remove(property);
  826. }
  827. }
  828. }
  829. foreach (var property in propertyInputs)
  830. {
  831. property.AppendPropertyBlockStrings(sb);
  832. }
  833. if (mode != GenerationMode.Preview)
  834. {
  835. foreach (var keyword in keywordInputs)
  836. {
  837. keyword.AppendPropertyBlockStrings(sb);
  838. }
  839. }
  840. }
  841. }
  842. }
  843. internal static void GenerateSurfaceInputStruct(ShaderStringBuilder sb, ShaderGraphRequirements requirements, string structName)
  844. {
  845. sb.AppendLine($"struct {structName}");
  846. using (sb.BlockSemicolonScope())
  847. {
  848. GenerateSpaceTranslationSurfaceInputs(requirements.requiresNormal, InterpolatorType.Normal, sb);
  849. GenerateSpaceTranslationSurfaceInputs(requirements.requiresTangent, InterpolatorType.Tangent, sb);
  850. GenerateSpaceTranslationSurfaceInputs(requirements.requiresBitangent, InterpolatorType.BiTangent, sb);
  851. GenerateSpaceTranslationSurfaceInputs(requirements.requiresViewDir, InterpolatorType.ViewDirection, sb);
  852. GenerateSpaceTranslationSurfaceInputs(requirements.requiresPosition, InterpolatorType.Position, sb);
  853. GenerateSpaceTranslationSurfaceInputs(requirements.requiresPositionPredisplacement, InterpolatorType.PositionPredisplacement, sb);
  854. if (requirements.requiresVertexColor)
  855. sb.AppendLine("float4 {0};", ShaderGeneratorNames.VertexColor);
  856. if (requirements.requiresScreenPosition)
  857. sb.AppendLine("float4 {0};", ShaderGeneratorNames.ScreenPosition);
  858. if (requirements.requiresNDCPosition)
  859. sb.AppendLine("float2 {0};", ShaderGeneratorNames.NDCPosition);
  860. if (requirements.requiresPixelPosition)
  861. sb.AppendLine("float2 {0};", ShaderGeneratorNames.PixelPosition);
  862. if (requirements.requiresFaceSign)
  863. sb.AppendLine("float {0};", ShaderGeneratorNames.FaceSign);
  864. foreach (var channel in requirements.requiresMeshUVs.Distinct())
  865. sb.AppendLine("half4 {0};", channel.GetUVName());
  866. if (requirements.requiresTime)
  867. {
  868. sb.AppendLine("float3 {0};", ShaderGeneratorNames.TimeParameters);
  869. }
  870. if (requirements.requiresVertexSkinning)
  871. {
  872. sb.AppendLine("uint4 {0};", ShaderGeneratorNames.BoneIndices);
  873. sb.AppendLine("float4 {0};", ShaderGeneratorNames.BoneWeights);
  874. }
  875. if (requirements.requiresVertexID)
  876. {
  877. sb.AppendLine("uint {0};", ShaderGeneratorNames.VertexID);
  878. }
  879. if (requirements.requiresInstanceID)
  880. {
  881. sb.AppendLine("uint {0};", ShaderGeneratorNames.InstanceID);
  882. }
  883. }
  884. }
  885. internal static void GenerateSurfaceInputTransferCode(ShaderStringBuilder sb, ShaderGraphRequirements requirements, string structName, string variableName)
  886. {
  887. sb.AppendLine($"{structName} {variableName};");
  888. GenerateSpaceTranslationSurfaceInputs(requirements.requiresNormal, InterpolatorType.Normal, sb, $"{variableName}.{{0}} = IN.{{0}};");
  889. GenerateSpaceTranslationSurfaceInputs(requirements.requiresTangent, InterpolatorType.Tangent, sb, $"{variableName}.{{0}} = IN.{{0}};");
  890. GenerateSpaceTranslationSurfaceInputs(requirements.requiresBitangent, InterpolatorType.BiTangent, sb, $"{variableName}.{{0}} = IN.{{0}};");
  891. GenerateSpaceTranslationSurfaceInputs(requirements.requiresViewDir, InterpolatorType.ViewDirection, sb, $"{variableName}.{{0}} = IN.{{0}};");
  892. GenerateSpaceTranslationSurfaceInputs(requirements.requiresPosition, InterpolatorType.Position, sb, $"{variableName}.{{0}} = IN.{{0}};");
  893. GenerateSpaceTranslationSurfaceInputs(requirements.requiresPositionPredisplacement, InterpolatorType.PositionPredisplacement, sb, $"{variableName}.{{0}} = IN.{{0}};");
  894. if (requirements.requiresVertexColor)
  895. sb.AppendLine($"{variableName}.{ShaderGeneratorNames.VertexColor} = IN.{ShaderGeneratorNames.VertexColor};");
  896. if (requirements.requiresScreenPosition)
  897. sb.AppendLine($"{variableName}.{ShaderGeneratorNames.ScreenPosition} = IN.{ShaderGeneratorNames.ScreenPosition};");
  898. if (requirements.requiresNDCPosition)
  899. sb.AppendLine($"{variableName}.{ShaderGeneratorNames.NDCPosition} = IN.{ShaderGeneratorNames.NDCPosition};");
  900. if (requirements.requiresPixelPosition)
  901. sb.AppendLine($"{variableName}.{ShaderGeneratorNames.PixelPosition} = IN.{ShaderGeneratorNames.PixelPosition};");
  902. if (requirements.requiresFaceSign)
  903. sb.AppendLine($"{variableName}.{ShaderGeneratorNames.FaceSign} = IN.{ShaderGeneratorNames.FaceSign};");
  904. foreach (var channel in requirements.requiresMeshUVs.Distinct())
  905. sb.AppendLine($"{variableName}.{channel.GetUVName()} = IN.{channel.GetUVName()};");
  906. if (requirements.requiresTime)
  907. {
  908. sb.AppendLine($"{variableName}.{ShaderGeneratorNames.TimeParameters} = IN.{ShaderGeneratorNames.TimeParameters};");
  909. }
  910. if (requirements.requiresVertexSkinning)
  911. {
  912. sb.AppendLine($"{variableName}.{ShaderGeneratorNames.BoneIndices} = IN.{ShaderGeneratorNames.BoneIndices};");
  913. sb.AppendLine($"{variableName}.{ShaderGeneratorNames.BoneWeights} = IN.{ShaderGeneratorNames.BoneWeights};");
  914. }
  915. if (requirements.requiresVertexID)
  916. {
  917. sb.AppendLine($"{variableName}.{ShaderGeneratorNames.VertexID} = IN.{ShaderGeneratorNames.VertexID};");
  918. }
  919. if (requirements.requiresInstanceID)
  920. {
  921. sb.AppendLine($"{variableName}.{ShaderGeneratorNames.InstanceID} = IN.{ShaderGeneratorNames.InstanceID};");
  922. }
  923. }
  924. internal static void GenerateSurfaceDescriptionStruct(ShaderStringBuilder surfaceDescriptionStruct, List<MaterialSlot> slots, string structName = "SurfaceDescription", IActiveFieldsSet activeFields = null, bool isSubgraphOutput = false, bool virtualTextureFeedback = false)
  925. {
  926. surfaceDescriptionStruct.AppendLine("struct {0}", structName);
  927. using (surfaceDescriptionStruct.BlockSemicolonScope())
  928. {
  929. if (slots != null)
  930. {
  931. if (isSubgraphOutput)
  932. {
  933. var firstSlot = slots.FirstOrDefault();
  934. if (firstSlot != null)
  935. {
  936. var hlslName = $"{NodeUtils.GetHLSLSafeName(firstSlot.shaderOutputName)}_{firstSlot.id}";
  937. surfaceDescriptionStruct.AppendLine("{0} {1};", firstSlot.concreteValueType.ToShaderString(firstSlot.owner.concretePrecision), hlslName);
  938. surfaceDescriptionStruct.AppendLine("{0} {1};", ConcreteSlotValueType.Vector4.ToShaderString(firstSlot.owner.concretePrecision), "Out");
  939. }
  940. else
  941. surfaceDescriptionStruct.AppendLine("{0} {1};", ConcreteSlotValueType.Vector4.ToShaderString(ConcretePrecision.Single), "Out");
  942. }
  943. else
  944. {
  945. foreach (var slot in slots)
  946. {
  947. string hlslName = NodeUtils.GetHLSLSafeName(slot.shaderOutputName);
  948. surfaceDescriptionStruct.AppendLine("{0} {1};", slot.concreteValueType.ToShaderString(slot.owner.concretePrecision), hlslName);
  949. if (activeFields != null)
  950. {
  951. var structField = new FieldDescriptor(structName, hlslName, "");
  952. activeFields.AddAll(structField);
  953. }
  954. }
  955. }
  956. }
  957. // TODO: move this into the regular FieldDescriptor system with a conditional, doesn't belong as a special case here
  958. if (virtualTextureFeedback)
  959. {
  960. surfaceDescriptionStruct.AppendLine("{0} {1};", ConcreteSlotValueType.Vector4.ToShaderString(ConcretePrecision.Single), "VTPackedFeedback");
  961. if (!isSubgraphOutput && activeFields != null)
  962. {
  963. var structField = new FieldDescriptor(structName, "VTPackedFeedback", "");
  964. activeFields.AddAll(structField);
  965. }
  966. }
  967. }
  968. }
  969. internal static void GenerateSurfaceDescriptionFunction(
  970. List<AbstractMaterialNode> nodes,
  971. List<int>[] keywordPermutationsPerNode,
  972. AbstractMaterialNode rootNode,
  973. GraphData graph,
  974. ShaderStringBuilder surfaceDescriptionFunction,
  975. FunctionRegistry functionRegistry,
  976. PropertyCollector shaderProperties,
  977. KeywordCollector shaderKeywords,
  978. GenerationMode mode,
  979. string functionName = "PopulateSurfaceData",
  980. string surfaceDescriptionName = "SurfaceDescription",
  981. Vector1ShaderProperty outputIdProperty = null,
  982. IEnumerable<MaterialSlot> slots = null,
  983. string graphInputStructName = "SurfaceDescriptionInputs",
  984. bool virtualTextureFeedback = false)
  985. {
  986. if (graph == null)
  987. return;
  988. graph.CollectShaderProperties(shaderProperties, mode);
  989. if (mode == GenerationMode.VFX)
  990. {
  991. const string k_GraphProperties = "GraphProperties";
  992. surfaceDescriptionFunction.AppendLine(String.Format("{0} {1}(SurfaceDescriptionInputs IN, {2} PROP)", surfaceDescriptionName, functionName, k_GraphProperties), false);
  993. }
  994. else
  995. surfaceDescriptionFunction.AppendLine(String.Format("{0} {1}(SurfaceDescriptionInputs IN)", surfaceDescriptionName, functionName), false);
  996. using (surfaceDescriptionFunction.BlockScope())
  997. {
  998. surfaceDescriptionFunction.AppendLine("{0} surface = ({0})0;", surfaceDescriptionName);
  999. for (int i = 0; i < nodes.Count; i++)
  1000. {
  1001. GenerateDescriptionForNode(nodes[i], keywordPermutationsPerNode[i], functionRegistry, surfaceDescriptionFunction,
  1002. shaderProperties, shaderKeywords,
  1003. graph, mode);
  1004. }
  1005. functionRegistry.builder.currentNode = null;
  1006. surfaceDescriptionFunction.currentNode = null;
  1007. GenerateSurfaceDescriptionRemap(graph, rootNode, slots,
  1008. surfaceDescriptionFunction, mode);
  1009. if (virtualTextureFeedback)
  1010. {
  1011. VirtualTexturingFeedbackUtils.GenerateVirtualTextureFeedback(
  1012. nodes,
  1013. keywordPermutationsPerNode,
  1014. surfaceDescriptionFunction,
  1015. shaderKeywords);
  1016. }
  1017. surfaceDescriptionFunction.AppendLine("return surface;");
  1018. }
  1019. }
  1020. static void GenerateDescriptionForNode(
  1021. AbstractMaterialNode activeNode,
  1022. List<int> keywordPermutations,
  1023. FunctionRegistry functionRegistry,
  1024. ShaderStringBuilder descriptionFunction,
  1025. PropertyCollector shaderProperties,
  1026. KeywordCollector shaderKeywords,
  1027. GraphData graph,
  1028. GenerationMode mode)
  1029. {
  1030. if (activeNode is IGeneratesFunction functionNode)
  1031. {
  1032. functionRegistry.builder.currentNode = activeNode;
  1033. Profiler.BeginSample("GenerateNodeFunction");
  1034. functionNode.GenerateNodeFunction(functionRegistry, mode);
  1035. Profiler.EndSample();
  1036. }
  1037. if (activeNode is IGeneratesBodyCode bodyNode)
  1038. {
  1039. if (keywordPermutations != null)
  1040. descriptionFunction.AppendLine(KeywordUtil.GetKeywordPermutationSetConditional(keywordPermutations));
  1041. descriptionFunction.currentNode = activeNode;
  1042. Profiler.BeginSample("GenerateNodeCode");
  1043. bodyNode.GenerateNodeCode(descriptionFunction, mode);
  1044. Profiler.EndSample();
  1045. descriptionFunction.ReplaceInCurrentMapping(PrecisionUtil.Token, activeNode.concretePrecision.ToShaderString());
  1046. if (keywordPermutations != null)
  1047. descriptionFunction.AppendLine("#endif");
  1048. }
  1049. activeNode.CollectShaderProperties(shaderProperties, mode);
  1050. if (activeNode is SubGraphNode subGraphNode)
  1051. {
  1052. subGraphNode.CollectShaderKeywords(shaderKeywords, mode);
  1053. }
  1054. }
  1055. static void GenerateSurfaceDescriptionRemap(
  1056. GraphData graph,
  1057. AbstractMaterialNode rootNode,
  1058. IEnumerable<MaterialSlot> slots,
  1059. ShaderStringBuilder surfaceDescriptionFunction,
  1060. GenerationMode mode)
  1061. {
  1062. if (rootNode == null)
  1063. {
  1064. foreach (var input in slots)
  1065. {
  1066. if (input != null)
  1067. {
  1068. var node = input.owner;
  1069. var foundEdges = graph.GetEdges(input.slotReference).ToArray();
  1070. var hlslName = NodeUtils.GetHLSLSafeName(input.shaderOutputName);
  1071. if (foundEdges.Any())
  1072. surfaceDescriptionFunction.AppendLine($"surface.{hlslName} = {node.GetSlotValue(input.id, mode, node.concretePrecision)};");
  1073. else
  1074. surfaceDescriptionFunction.AppendLine($"surface.{hlslName} = {input.GetDefaultValue(mode, node.concretePrecision)};");
  1075. }
  1076. }
  1077. }
  1078. else if (rootNode is SubGraphOutputNode)
  1079. {
  1080. var slot = slots.FirstOrDefault();
  1081. if (slot != null)
  1082. {
  1083. var foundEdges = graph.GetEdges(slot.slotReference).ToArray();
  1084. var hlslName = $"{NodeUtils.GetHLSLSafeName(slot.shaderOutputName)}_{slot.id}";
  1085. if (foundEdges.Any())
  1086. surfaceDescriptionFunction.AppendLine($"surface.{hlslName} = {rootNode.GetSlotValue(slot.id, mode, rootNode.concretePrecision)};");
  1087. else
  1088. surfaceDescriptionFunction.AppendLine($"surface.{hlslName} = {slot.GetDefaultValue(mode, rootNode.concretePrecision)};");
  1089. surfaceDescriptionFunction.AppendLine($"surface.Out = all(isfinite(surface.{hlslName})) ? {GenerationUtils.AdaptNodeOutputForPreview(rootNode, slot.id, "surface." + hlslName)} : float4(1.0f, 0.0f, 1.0f, 1.0f);");
  1090. }
  1091. }
  1092. else
  1093. {
  1094. var slot = rootNode.GetOutputSlots<MaterialSlot>().FirstOrDefault();
  1095. if (slot != null)
  1096. {
  1097. string slotValue;
  1098. string previewOutput;
  1099. if (rootNode.isActive)
  1100. {
  1101. slotValue = rootNode.GetSlotValue(slot.id, mode, rootNode.concretePrecision);
  1102. previewOutput = GenerationUtils.AdaptNodeOutputForPreview(rootNode, slot.id);
  1103. }
  1104. else
  1105. {
  1106. slotValue = rootNode.GetSlotValue(slot.id, mode, rootNode.concretePrecision);
  1107. previewOutput = "float4(0.0f, 0.0f, 0.0f, 0.0f)";
  1108. }
  1109. surfaceDescriptionFunction.AppendLine($"surface.Out = all(isfinite({slotValue})) ? {previewOutput} : float4(1.0f, 0.0f, 1.0f, 1.0f);");
  1110. }
  1111. }
  1112. }
  1113. const string k_VertexDescriptionStructName = "VertexDescription";
  1114. internal static void GenerateVertexDescriptionStruct(ShaderStringBuilder builder, List<MaterialSlot> slots, string structName = k_VertexDescriptionStructName, IActiveFieldsSet activeFields = null)
  1115. {
  1116. builder.AppendLine("struct {0}", structName);
  1117. using (builder.BlockSemicolonScope())
  1118. {
  1119. foreach (var slot in slots)
  1120. {
  1121. string hlslName = NodeUtils.ConvertToValidHLSLIdentifier(slot.shaderOutputName);
  1122. builder.AppendLine("{0} {1};", slot.concreteValueType.ToShaderString(slot.owner.concretePrecision), hlslName);
  1123. if (activeFields != null)
  1124. {
  1125. var structField = new FieldDescriptor(structName, hlslName, "");
  1126. activeFields.AddAll(structField);
  1127. }
  1128. }
  1129. }
  1130. }
  1131. internal static void GenerateVertexDescriptionFunction(
  1132. GraphData graph,
  1133. ShaderStringBuilder builder,
  1134. FunctionRegistry functionRegistry,
  1135. PropertyCollector shaderProperties,
  1136. KeywordCollector shaderKeywords,
  1137. GenerationMode mode,
  1138. AbstractMaterialNode rootNode,
  1139. List<AbstractMaterialNode> nodes,
  1140. List<int>[] keywordPermutationsPerNode,
  1141. List<MaterialSlot> slots,
  1142. string graphInputStructName = "VertexDescriptionInputs",
  1143. string functionName = "PopulateVertexData",
  1144. string graphOutputStructName = k_VertexDescriptionStructName)
  1145. {
  1146. if (graph == null)
  1147. return;
  1148. graph.CollectShaderProperties(shaderProperties, mode);
  1149. if (mode == GenerationMode.VFX)
  1150. {
  1151. const string k_GraphProperties = "GraphProperties";
  1152. builder.AppendLine("{0} {1}({2} IN, {3} PROP)", graphOutputStructName, functionName, graphInputStructName, k_GraphProperties);
  1153. }
  1154. else
  1155. builder.AppendLine("{0} {1}({2} IN)", graphOutputStructName, functionName, graphInputStructName);
  1156. using (builder.BlockScope())
  1157. {
  1158. builder.AppendLine("{0} description = ({0})0;", graphOutputStructName);
  1159. Profiler.BeginSample("GenerateNodeDescriptions");
  1160. for (int i = 0; i < nodes.Count; i++)
  1161. {
  1162. GenerateDescriptionForNode(nodes[i], keywordPermutationsPerNode[i], functionRegistry, builder,
  1163. shaderProperties, shaderKeywords,
  1164. graph, mode);
  1165. }
  1166. Profiler.EndSample();
  1167. functionRegistry.builder.currentNode = null;
  1168. builder.currentNode = null;
  1169. if (slots.Count != 0)
  1170. {
  1171. foreach (var slot in slots)
  1172. {
  1173. var isSlotConnected = graph.GetEdges(slot.slotReference).Any();
  1174. var slotName = NodeUtils.ConvertToValidHLSLIdentifier(slot.shaderOutputName);
  1175. var slotValue = isSlotConnected ?
  1176. ((AbstractMaterialNode)slot.owner).GetSlotValue(slot.id, mode, slot.owner.concretePrecision) : slot.GetDefaultValue(mode, slot.owner.concretePrecision);
  1177. builder.AppendLine("description.{0} = {1};", slotName, slotValue);
  1178. }
  1179. }
  1180. builder.AppendLine("return description;");
  1181. }
  1182. }
  1183. internal static string GetSpliceCommand(string command, string token)
  1184. {
  1185. return !string.IsNullOrEmpty(command) ? command : $"// {token}: <None>";
  1186. }
  1187. internal static string GetDefaultTemplatePath(string templateName)
  1188. {
  1189. var basePath = "Packages/com.unity.shadergraph/Editor/Generation/Templates/";
  1190. string templatePath = Path.Combine(basePath, templateName);
  1191. if (File.Exists(templatePath))
  1192. return templatePath;
  1193. throw new FileNotFoundException(string.Format(@"Cannot find a template with name ""{0}"".", templateName));
  1194. }
  1195. internal static string[] defaultDefaultSharedTemplateDirectories = new string[]
  1196. {
  1197. "Packages/com.unity.shadergraph/Editor/Generation/Templates"
  1198. };
  1199. internal static string[] GetDefaultSharedTemplateDirectories()
  1200. {
  1201. return defaultDefaultSharedTemplateDirectories;
  1202. }
  1203. // Returns null if no 'CustomEditor "___"' line should be added, otherwise the name of the ShaderGUI class.
  1204. // Note that it's okay to add an "invalid" ShaderGUI (no class found) as Unity will simply take no action if that's the case, unless if its BaseShaderGUI.
  1205. public static string FinalCustomEditorString(ICanChangeShaderGUI canChangeShaderGUI)
  1206. {
  1207. string finalOverrideName = canChangeShaderGUI.ShaderGUIOverride;
  1208. if (string.IsNullOrEmpty(finalOverrideName))
  1209. return null;
  1210. // Do not add to the final shader if the base ShaderGUI is wanted, as errors will occur.
  1211. if (finalOverrideName.Equals("BaseShaderGUI") || finalOverrideName.Equals("UnityEditor.BaseShaderGUI"))
  1212. return null;
  1213. return finalOverrideName;
  1214. }
  1215. }
  1216. }