A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using UnityEngine;
5using UnityEditor.Graphing;
6using UnityEditor.ShaderGraph.Internal;
7
8namespace UnityEditor.ShaderGraph
9{
10 [HasDependencies(typeof(MinimalSubGraphNode))]
11 [Title("Utility", "Sub-graph")]
12 class SubGraphNode : AbstractMaterialNode
13 , IGeneratesBodyCode
14 , IOnAssetEnabled
15 , IGeneratesFunction
16 , IMayRequireNormal
17 , IMayRequireTangent
18 , IMayRequireBitangent
19 , IMayRequireMeshUV
20 , IMayRequireScreenPosition
21 , IMayRequireNDCPosition
22 , IMayRequirePixelPosition
23 , IMayRequireViewDirection
24 , IMayRequirePosition
25 , IMayRequirePositionPredisplacement
26 , IMayRequireVertexColor
27 , IMayRequireTime
28 , IMayRequireFaceSign
29 , IMayRequireCameraOpaqueTexture
30 , IMayRequireDepthTexture
31 , IMayRequireVertexSkinning
32 , IMayRequireVertexID
33 , IMayRequireInstanceID
34 , IDisposable
35 {
36 [Serializable]
37 public class MinimalSubGraphNode : IHasDependencies
38 {
39 [SerializeField]
40 string m_SerializedSubGraph = string.Empty;
41
42 public void GetSourceAssetDependencies(AssetCollection assetCollection)
43 {
44 var assetReference = JsonUtility.FromJson<SubGraphAssetReference>(m_SerializedSubGraph);
45 string guidString = assetReference?.subGraph?.guid;
46 if (!string.IsNullOrEmpty(guidString) && GUID.TryParse(guidString, out GUID guid))
47 {
48 // subgraphs are read as artifacts
49 // they also should be pulled into .unitypackages
50 assetCollection.AddAssetDependency(
51 guid,
52 AssetCollection.Flags.ArtifactDependency |
53 AssetCollection.Flags.IsSubGraph |
54 AssetCollection.Flags.IncludeInExportPackage);
55 }
56 }
57 }
58
59 [Serializable]
60 class SubGraphHelper
61 {
62 public SubGraphAsset subGraph;
63 }
64
65 [Serializable]
66 class SubGraphAssetReference
67 {
68 public AssetReference subGraph = default;
69
70 public override string ToString()
71 {
72 return $"subGraph={subGraph}";
73 }
74 }
75
76 [Serializable]
77 class AssetReference
78 {
79 public long fileID = default;
80 public string guid = default;
81 public int type = default;
82
83 public override string ToString()
84 {
85 return $"fileID={fileID}, guid={guid}, type={type}";
86 }
87 }
88
89 [SerializeField]
90 string m_SerializedSubGraph = string.Empty;
91
92 [NonSerialized]
93 SubGraphAsset m_SubGraph; // This should not be accessed directly by most code -- use the asset property instead, and check for NULL! :)
94
95 [SerializeField]
96 List<string> m_PropertyGuids = new List<string>();
97
98 [SerializeField]
99 List<int> m_PropertyIds = new List<int>();
100
101 [SerializeField]
102 List<string> m_Dropdowns = new List<string>();
103
104 [SerializeField]
105 List<string> m_DropdownSelectedEntries = new List<string>();
106
107 public string subGraphGuid
108 {
109 get
110 {
111 var assetReference = JsonUtility.FromJson<SubGraphAssetReference>(m_SerializedSubGraph);
112 return assetReference?.subGraph?.guid;
113 }
114 }
115
116 void LoadSubGraph()
117 {
118 if (m_SubGraph == null)
119 {
120 if (string.IsNullOrEmpty(m_SerializedSubGraph))
121 {
122 return;
123 }
124
125 var graphGuid = subGraphGuid;
126 var assetPath = AssetDatabase.GUIDToAssetPath(graphGuid);
127 if (string.IsNullOrEmpty(assetPath))
128 {
129 // this happens if the editor has never seen the GUID
130 // error will be printed by validation code in this case
131 return;
132 }
133 m_SubGraph = AssetDatabase.LoadAssetAtPath<SubGraphAsset>(assetPath);
134 if (m_SubGraph == null)
135 {
136 // this happens if the editor has seen the GUID, but the file has been deleted since then
137 // error will be printed by validation code in this case
138 return;
139 }
140 m_SubGraph.LoadGraphData();
141 m_SubGraph.LoadDependencyData();
142
143 name = m_SubGraph.name;
144 }
145 }
146
147 public SubGraphAsset asset
148 {
149 get
150 {
151 LoadSubGraph();
152 return m_SubGraph;
153 }
154 set
155 {
156 if (asset == value)
157 return;
158
159 var helper = new SubGraphHelper();
160 helper.subGraph = value;
161 m_SerializedSubGraph = EditorJsonUtility.ToJson(helper, true);
162 m_SubGraph = null;
163 UpdateSlots();
164
165 Dirty(ModificationScope.Topological);
166 }
167 }
168
169 public override bool hasPreview
170 {
171 get { return true; }
172 }
173
174 public override PreviewMode previewMode
175 {
176 get
177 {
178 PreviewMode mode = m_PreviewMode;
179 if ((mode == PreviewMode.Inherit) && (asset != null))
180 mode = asset.previewMode;
181 return mode;
182 }
183 }
184
185 public SubGraphNode()
186 {
187 name = "Sub Graph";
188 }
189
190 public override bool allowedInSubGraph
191 {
192 get { return true; }
193 }
194
195 public override bool canSetPrecision
196 {
197 get { return asset?.subGraphGraphPrecision == GraphPrecision.Graph; }
198 }
199
200 public override void GetInputSlots<T>(MaterialSlot startingSlot, List<T> foundSlots)
201 {
202 var allSlots = new List<T>();
203 GetInputSlots<T>(allSlots);
204 var info = asset?.GetOutputDependencies(startingSlot.RawDisplayName());
205 if (info != null)
206 {
207 foreach (var slot in allSlots)
208 {
209 if (info.ContainsSlot(slot))
210 foundSlots.Add(slot);
211 }
212 }
213 }
214
215 public override void GetOutputSlots<T>(MaterialSlot startingSlot, List<T> foundSlots)
216 {
217 var allSlots = new List<T>();
218 GetOutputSlots<T>(allSlots);
219 var info = asset?.GetInputDependencies(startingSlot.RawDisplayName());
220 if (info != null)
221 {
222 foreach (var slot in allSlots)
223 {
224 if (info.ContainsSlot(slot))
225 foundSlots.Add(slot);
226 }
227 }
228 }
229
230 ShaderStageCapability GetSlotCapability(MaterialSlot slot)
231 {
232 SlotDependencyInfo dependencyInfo;
233 if (slot.isInputSlot)
234 dependencyInfo = asset?.GetInputDependencies(slot.RawDisplayName());
235 else
236 dependencyInfo = asset?.GetOutputDependencies(slot.RawDisplayName());
237
238 if (dependencyInfo != null)
239 return dependencyInfo.capabilities;
240 return ShaderStageCapability.All;
241 }
242
243 public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
244 {
245 var outputGraphPrecision = asset?.outputGraphPrecision ?? GraphPrecision.Single;
246 var outputPrecision = outputGraphPrecision.ToConcrete(concretePrecision);
247
248 if (asset == null || hasError)
249 {
250 var outputSlots = new List<MaterialSlot>();
251 GetOutputSlots(outputSlots);
252
253 foreach (var slot in outputSlots)
254 {
255 sb.AppendLine($"{slot.concreteValueType.ToShaderString(outputPrecision)} {GetVariableNameForSlot(slot.id)} = {slot.GetDefaultValue(GenerationMode.ForReals)};");
256 }
257
258 return;
259 }
260
261 var inputVariableName = $"_{GetVariableNameForNode()}";
262
263 GenerationUtils.GenerateSurfaceInputTransferCode(sb, asset.requirements, asset.inputStructName, inputVariableName);
264
265 // declare output variables
266 foreach (var outSlot in asset.outputs)
267 sb.AppendLine("{0} {1};", outSlot.concreteValueType.ToShaderString(outputPrecision), GetVariableNameForSlot(outSlot.id));
268
269 var arguments = new List<string>();
270 foreach (AbstractShaderProperty prop in asset.inputs)
271 {
272 // setup the property concrete precision (fallback to node concrete precision when it's switchable)
273 prop.SetupConcretePrecision(this.concretePrecision);
274 var inSlotId = m_PropertyIds[m_PropertyGuids.IndexOf(prop.guid.ToString())];
275 arguments.Add(GetSlotValue(inSlotId, generationMode, prop.concretePrecision));
276
277 if (prop.isConnectionTestable)
278 arguments.Add(IsSlotConnected(inSlotId) ? "true" : "false");
279 }
280
281 var dropdowns = asset.dropdowns;
282 foreach (var dropdown in dropdowns)
283 {
284 var name = GetDropdownEntryName(dropdown.referenceName);
285 if (dropdown.ContainsEntry(name))
286 arguments.Add(dropdown.IndexOfName(name).ToString());
287 else
288 arguments.Add(dropdown.value.ToString());
289 }
290
291 // pass surface inputs through
292 arguments.Add(inputVariableName);
293
294 foreach (var outSlot in asset.outputs)
295 arguments.Add(GetVariableNameForSlot(outSlot.id));
296
297 foreach (var feedbackSlot in asset.vtFeedbackVariables)
298 {
299 string feedbackVar = GetVariableNameForNode() + "_" + feedbackSlot;
300 sb.AppendLine("{0} {1};", ConcreteSlotValueType.Vector4.ToShaderString(ConcretePrecision.Single), feedbackVar);
301 arguments.Add(feedbackVar);
302 }
303
304 sb.TryAppendIndentation();
305 sb.Append(asset.functionName);
306 sb.Append("(");
307 bool firstArg = true;
308 foreach (var arg in arguments)
309 {
310 if (!firstArg)
311 sb.Append(", ");
312 firstArg = false;
313 sb.Append(arg);
314 }
315 sb.Append(");");
316 sb.AppendNewLine();
317 }
318
319 public void OnEnable()
320 {
321 UpdateSlots();
322 }
323
324 public bool Reload(HashSet<string> changedFileDependencyGUIDs)
325 {
326 if (!changedFileDependencyGUIDs.Contains(subGraphGuid))
327 {
328 return false;
329 }
330
331 if (asset == null)
332 {
333 // asset missing or deleted
334 return true;
335 }
336
337 if (changedFileDependencyGUIDs.Contains(asset.assetGuid) || asset.descendents.Any(changedFileDependencyGUIDs.Contains))
338 {
339 m_SubGraph = null;
340 UpdateSlots();
341
342 if (hasError)
343 {
344 return true;
345 }
346
347 owner.ClearErrorsForNode(this);
348 ValidateNode();
349 Dirty(ModificationScope.Graph);
350 }
351
352 return true;
353 }
354
355 public override void UpdatePrecision(List<MaterialSlot> inputSlots)
356 {
357 if (asset != null)
358 {
359 if (asset.subGraphGraphPrecision == GraphPrecision.Graph)
360 {
361 // subgraph is defined to be switchable, so use the default behavior to determine precision
362 base.UpdatePrecision(inputSlots);
363 }
364 else
365 {
366 // subgraph sets a specific precision, force that
367 graphPrecision = asset.subGraphGraphPrecision;
368 concretePrecision = graphPrecision.ToConcrete(owner.graphDefaultConcretePrecision);
369 }
370 }
371 else
372 {
373 // no subgraph asset; use default behavior
374 base.UpdatePrecision(inputSlots);
375 }
376 }
377
378 public virtual void UpdateSlots()
379 {
380 var validNames = new List<int>();
381 if (asset == null)
382 {
383 return;
384 }
385
386 var props = asset.inputs;
387 var toFix = new HashSet<(SlotReference from, SlotReference to)>();
388 foreach (var prop in props)
389 {
390 SlotValueType valueType = prop.concreteShaderValueType.ToSlotValueType();
391 var propertyString = prop.guid.ToString();
392 var propertyIndex = m_PropertyGuids.IndexOf(propertyString);
393 if (propertyIndex < 0)
394 {
395 propertyIndex = m_PropertyGuids.Count;
396 m_PropertyGuids.Add(propertyString);
397 m_PropertyIds.Add(prop.guid.GetHashCode());
398 }
399 var id = m_PropertyIds[propertyIndex];
400
401 //for whatever reason, it seems like shader property ids changed between 21.2a17 and 21.2b1
402 //tried tracking it down, couldnt find any reason for it, so we gotta fix it in post (after we deserialize)
403 List<MaterialSlot> inputs = new List<MaterialSlot>();
404 MaterialSlot found = null;
405 GetInputSlots(inputs);
406 foreach (var input in inputs)
407 {
408 if (input.shaderOutputName == prop.referenceName && input.id != id)
409 {
410 found = input;
411 break;
412 }
413 }
414
415 MaterialSlot slot = MaterialSlot.CreateMaterialSlot(valueType, id, prop.displayName, prop.referenceName, SlotType.Input, Vector4.zero, ShaderStageCapability.All);
416
417 // Copy defaults
418 switch (prop.concreteShaderValueType)
419 {
420 case ConcreteSlotValueType.SamplerState:
421 {
422 var tSlot = slot as SamplerStateMaterialSlot;
423 var tProp = prop as SamplerStateShaderProperty;
424 if (tSlot != null && tProp != null)
425 tSlot.defaultSamplerState = tProp.value;
426 }
427 break;
428 case ConcreteSlotValueType.Matrix4:
429 {
430 var tSlot = slot as Matrix4MaterialSlot;
431 var tProp = prop as Matrix4ShaderProperty;
432 if (tSlot != null && tProp != null)
433 tSlot.value = tProp.value;
434 }
435 break;
436 case ConcreteSlotValueType.Matrix3:
437 {
438 var tSlot = slot as Matrix3MaterialSlot;
439 var tProp = prop as Matrix3ShaderProperty;
440 if (tSlot != null && tProp != null)
441 tSlot.value = tProp.value;
442 }
443 break;
444 case ConcreteSlotValueType.Matrix2:
445 {
446 var tSlot = slot as Matrix2MaterialSlot;
447 var tProp = prop as Matrix2ShaderProperty;
448 if (tSlot != null && tProp != null)
449 tSlot.value = tProp.value;
450 }
451 break;
452 case ConcreteSlotValueType.Texture2D:
453 {
454 var tSlot = slot as Texture2DInputMaterialSlot;
455 var tProp = prop as Texture2DShaderProperty;
456 if (tSlot != null && tProp != null)
457
458 tSlot.texture = tProp.value.texture;
459 }
460 break;
461 case ConcreteSlotValueType.Texture2DArray:
462 {
463 var tSlot = slot as Texture2DArrayInputMaterialSlot;
464 var tProp = prop as Texture2DArrayShaderProperty;
465 if (tSlot != null && tProp != null)
466 tSlot.textureArray = tProp.value.textureArray;
467 }
468 break;
469 case ConcreteSlotValueType.Texture3D:
470 {
471 var tSlot = slot as Texture3DInputMaterialSlot;
472 var tProp = prop as Texture3DShaderProperty;
473 if (tSlot != null && tProp != null)
474 tSlot.texture = tProp.value.texture;
475 }
476 break;
477 case ConcreteSlotValueType.Cubemap:
478 {
479 var tSlot = slot as CubemapInputMaterialSlot;
480 var tProp = prop as CubemapShaderProperty;
481 if (tSlot != null && tProp != null)
482 tSlot.cubemap = tProp.value.cubemap;
483 }
484 break;
485 case ConcreteSlotValueType.Gradient:
486 {
487 var tSlot = slot as GradientInputMaterialSlot;
488 var tProp = prop as GradientShaderProperty;
489 if (tSlot != null && tProp != null)
490 tSlot.value = tProp.value;
491 }
492 break;
493 case ConcreteSlotValueType.Vector4:
494 {
495 var tSlot = slot as Vector4MaterialSlot;
496 var vector4Prop = prop as Vector4ShaderProperty;
497 var colorProp = prop as ColorShaderProperty;
498 if (tSlot != null && vector4Prop != null)
499 tSlot.value = vector4Prop.value;
500 else if (tSlot != null && colorProp != null)
501 tSlot.value = colorProp.value;
502 }
503 break;
504 case ConcreteSlotValueType.Vector3:
505 {
506 var tSlot = slot as Vector3MaterialSlot;
507 var tProp = prop as Vector3ShaderProperty;
508 if (tSlot != null && tProp != null)
509 tSlot.value = tProp.value;
510 }
511 break;
512 case ConcreteSlotValueType.Vector2:
513 {
514 var tSlot = slot as Vector2MaterialSlot;
515 var tProp = prop as Vector2ShaderProperty;
516 if (tSlot != null && tProp != null)
517 tSlot.value = tProp.value;
518 }
519 break;
520 case ConcreteSlotValueType.Vector1:
521 {
522 var tSlot = slot as Vector1MaterialSlot;
523 var tProp = prop as Vector1ShaderProperty;
524 if (tSlot != null && tProp != null)
525 tSlot.value = tProp.value;
526 }
527 break;
528 case ConcreteSlotValueType.Boolean:
529 {
530 var tSlot = slot as BooleanMaterialSlot;
531 var tProp = prop as BooleanShaderProperty;
532 if (tSlot != null && tProp != null)
533 tSlot.value = tProp.value;
534 }
535 break;
536 }
537
538 AddSlot(slot);
539 validNames.Add(id);
540
541 if (found != null)
542 {
543 List<IEdge> edges = new List<IEdge>();
544 owner.GetEdges(found.slotReference, edges);
545 foreach (var edge in edges)
546 {
547 toFix.Add((edge.outputSlot, slot.slotReference));
548 }
549 }
550 }
551
552 foreach (var slot in asset.outputs)
553 {
554 var outputStage = GetSlotCapability(slot);
555 var newSlot = MaterialSlot.CreateMaterialSlot(slot.valueType, slot.id, slot.RawDisplayName(),
556 slot.shaderOutputName, SlotType.Output, Vector4.zero, outputStage, slot.hidden);
557 AddSlot(newSlot);
558 validNames.Add(slot.id);
559 }
560
561 RemoveSlotsNameNotMatching(validNames, true);
562
563 // sort slot order to match subgraph property order
564 SetSlotOrder(validNames);
565
566 foreach (var (from, to) in toFix)
567 {
568 //for whatever reason, in this particular error fix, GraphView will incorrectly either add two edgeViews or none
569 //but it does work correctly if we dont notify GraphView of this added edge. Gross.
570 owner.UnnotifyAddedEdge(owner.Connect(from, to));
571 }
572 }
573
574 void ValidateShaderStage()
575 {
576 if (asset != null)
577 {
578 List<MaterialSlot> slots = new List<MaterialSlot>();
579 GetInputSlots(slots);
580 GetOutputSlots(slots);
581
582 foreach (MaterialSlot slot in slots)
583 slot.stageCapability = GetSlotCapability(slot);
584 }
585 }
586
587 public override void ValidateNode()
588 {
589 base.ValidateNode();
590
591 if (asset == null)
592 {
593 hasError = true;
594 var assetGuid = subGraphGuid;
595 var assetPath = string.IsNullOrEmpty(subGraphGuid) ? null : AssetDatabase.GUIDToAssetPath(assetGuid);
596 if (string.IsNullOrEmpty(assetPath))
597 {
598 owner.AddValidationError(objectId, $"Could not find Sub Graph asset with GUID {assetGuid}.");
599 }
600 else
601 {
602 owner.AddValidationError(objectId, $"Could not load Sub Graph asset at \"{assetPath}\" with GUID {assetGuid}.");
603 }
604
605 return;
606 }
607
608 if (owner.isSubGraph && (asset.descendents.Contains(owner.assetGuid) || asset.assetGuid == owner.assetGuid))
609 {
610 hasError = true;
611 owner.AddValidationError(objectId, $"Detected a recursion in Sub Graph asset at \"{AssetDatabase.GUIDToAssetPath(subGraphGuid)}\" with GUID {subGraphGuid}.");
612 }
613 else if (!asset.isValid)
614 {
615 hasError = true;
616 owner.AddValidationError(objectId, $"Sub Graph has errors, asset at \"{AssetDatabase.GUIDToAssetPath(subGraphGuid)}\" with GUID {subGraphGuid}.");
617 }
618 else if (!owner.isSubGraph && owner.activeTargets.Any(x => asset.unsupportedTargets.Contains(x)))
619 {
620 SetOverrideActiveState(ActiveState.ExplicitInactive);
621 owner.AddValidationError(objectId, $"Sub Graph contains nodes that are unsupported by the current active targets, asset at \"{AssetDatabase.GUIDToAssetPath(subGraphGuid)}\" with GUID {subGraphGuid}.");
622 }
623
624 // detect disconnected VT properties, and VT layer count mismatches
625 foreach (var paramProp in asset.inputs)
626 {
627 if (paramProp is VirtualTextureShaderProperty vtProp)
628 {
629 int paramLayerCount = vtProp.value.layers.Count;
630
631 var argSlotId = m_PropertyIds[m_PropertyGuids.IndexOf(paramProp.guid.ToString())]; // yikes
632 if (!IsSlotConnected(argSlotId))
633 {
634 owner.AddValidationError(objectId, $"A VirtualTexture property must be connected to the input slot \"{paramProp.displayName}\"");
635 }
636 else
637 {
638 var argProp = GetSlotProperty(argSlotId) as VirtualTextureShaderProperty;
639 if (argProp != null)
640 {
641 int argLayerCount = argProp.value.layers.Count;
642
643 if (argLayerCount != paramLayerCount)
644 owner.AddValidationError(objectId, $"Input \"{paramProp.displayName}\" has different number of layers from the connected property \"{argProp.displayName}\"");
645 }
646 else
647 {
648 owner.AddValidationError(objectId, $"Input \"{paramProp.displayName}\" is not connected to a valid VirtualTexture property");
649 }
650 }
651
652 break;
653 }
654 }
655
656 ValidateShaderStage();
657 }
658
659 public override void CollectShaderProperties(PropertyCollector visitor, GenerationMode generationMode)
660 {
661 base.CollectShaderProperties(visitor, generationMode);
662
663 if (asset == null)
664 return;
665
666 foreach (var property in asset.nodeProperties)
667 {
668 visitor.AddShaderProperty(property);
669 }
670 }
671
672 public AbstractShaderProperty GetShaderProperty(int id)
673 {
674 var index = m_PropertyIds.IndexOf(id);
675 if (index >= 0)
676 {
677 var guid = m_PropertyGuids[index];
678 return asset?.inputs.Where(x => x.guid.ToString().Equals(guid)).FirstOrDefault();
679 }
680 return null;
681 }
682
683 public void CollectShaderKeywords(KeywordCollector keywords, GenerationMode generationMode)
684 {
685 if (asset == null)
686 return;
687
688 foreach (var keyword in asset.keywords)
689 {
690 keywords.AddShaderKeyword(keyword as ShaderKeyword);
691 }
692 }
693
694 public override void CollectPreviewMaterialProperties(List<PreviewProperty> properties)
695 {
696 base.CollectPreviewMaterialProperties(properties);
697
698 if (asset == null)
699 return;
700
701 foreach (var property in asset.nodeProperties)
702 {
703 properties.Add(property.GetPreviewMaterialProperty());
704 }
705 }
706
707 public virtual void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode)
708 {
709 if (asset == null || hasError)
710 return;
711
712 registry.RequiresIncludes(asset.includes);
713
714 var graphData = registry.builder.currentNode.owner;
715 var graphDefaultConcretePrecision = graphData.graphDefaultConcretePrecision;
716
717 foreach (var function in asset.functions)
718 {
719 var name = function.key;
720 var source = function.value;
721 var graphPrecisionFlags = function.graphPrecisionFlags;
722
723 // the subgraph may use multiple precision variants of this function internally
724 // here we iterate through all the requested precisions and forward those requests out to the graph
725 for (int requestedGraphPrecision = 0; requestedGraphPrecision <= (int)GraphPrecision.Half; requestedGraphPrecision++)
726 {
727 // only provide requested precisions
728 if ((graphPrecisionFlags & (1 << requestedGraphPrecision)) != 0)
729 {
730 // when a function coming from a subgraph asset has a graph precision of "Graph",
731 // that means it is up to the subgraph NODE to decide (i.e. us!)
732 GraphPrecision actualGraphPrecision = (GraphPrecision)requestedGraphPrecision;
733
734 // subgraph asset setting falls back to this node setting (when switchable)
735 actualGraphPrecision = actualGraphPrecision.GraphFallback(this.graphPrecision);
736
737 // which falls back to the graph default concrete precision
738 ConcretePrecision actualConcretePrecision = actualGraphPrecision.ToConcrete(graphDefaultConcretePrecision);
739
740 // forward the function into the current graph
741 registry.ProvideFunction(name, actualGraphPrecision, actualConcretePrecision, sb => sb.AppendLines(source));
742 }
743 }
744 }
745 }
746
747 public NeededCoordinateSpace RequiresNormal(ShaderStageCapability stageCapability)
748 {
749 if (asset == null)
750 return NeededCoordinateSpace.None;
751
752 return asset.requirements.requiresNormal;
753 }
754
755 public bool RequiresMeshUV(UVChannel channel, ShaderStageCapability stageCapability)
756 {
757 if (asset == null)
758 return false;
759
760 return asset.requirements.requiresMeshUVs.Contains(channel);
761 }
762
763 public bool RequiresScreenPosition(ShaderStageCapability stageCapability)
764 {
765 if (asset == null)
766 return false;
767
768 return asset.requirements.requiresScreenPosition;
769 }
770
771 public bool RequiresNDCPosition(ShaderStageCapability stageCapability)
772 {
773 if (asset == null)
774 return false;
775
776 return asset.requirements.requiresNDCPosition;
777 }
778
779 public bool RequiresPixelPosition(ShaderStageCapability stageCapability)
780 {
781 if (asset == null)
782 return false;
783
784 return asset.requirements.requiresPixelPosition;
785 }
786
787 public NeededCoordinateSpace RequiresViewDirection(ShaderStageCapability stageCapability)
788 {
789 if (asset == null)
790 return NeededCoordinateSpace.None;
791
792 return asset.requirements.requiresViewDir;
793 }
794
795 public NeededCoordinateSpace RequiresPosition(ShaderStageCapability stageCapability)
796 {
797 if (asset == null)
798 return NeededCoordinateSpace.None;
799
800 return asset.requirements.requiresPosition;
801 }
802
803 public NeededCoordinateSpace RequiresPositionPredisplacement(ShaderStageCapability stageCapability = ShaderStageCapability.All)
804 {
805 if (asset == null)
806 return NeededCoordinateSpace.None;
807
808 return asset.requirements.requiresPositionPredisplacement;
809 }
810
811 public NeededCoordinateSpace RequiresTangent(ShaderStageCapability stageCapability)
812 {
813 if (asset == null)
814 return NeededCoordinateSpace.None;
815
816 return asset.requirements.requiresTangent;
817 }
818
819 public bool RequiresTime()
820 {
821 if (asset == null)
822 return false;
823
824 return asset.requirements.requiresTime;
825 }
826
827 public bool RequiresFaceSign(ShaderStageCapability stageCapability)
828 {
829 if (asset == null)
830 return false;
831
832 return asset.requirements.requiresFaceSign;
833 }
834
835 public NeededCoordinateSpace RequiresBitangent(ShaderStageCapability stageCapability)
836 {
837 if (asset == null)
838 return NeededCoordinateSpace.None;
839
840 return asset.requirements.requiresBitangent;
841 }
842
843 public bool RequiresVertexColor(ShaderStageCapability stageCapability)
844 {
845 if (asset == null)
846 return false;
847
848 return asset.requirements.requiresVertexColor;
849 }
850
851 public bool RequiresCameraOpaqueTexture(ShaderStageCapability stageCapability)
852 {
853 if (asset == null)
854 return false;
855
856 return asset.requirements.requiresCameraOpaqueTexture;
857 }
858
859 public bool RequiresDepthTexture(ShaderStageCapability stageCapability)
860 {
861 if (asset == null)
862 return false;
863
864 return asset.requirements.requiresDepthTexture;
865 }
866
867 public bool RequiresVertexSkinning(ShaderStageCapability stageCapability)
868 {
869 if (asset == null)
870 return false;
871
872 return asset.requirements.requiresVertexSkinning;
873 }
874
875 public bool RequiresVertexID(ShaderStageCapability stageCapability)
876 {
877 if (asset == null)
878 return false;
879
880 return asset.requirements.requiresVertexID;
881 }
882
883 public bool RequiresInstanceID(ShaderStageCapability stageCapability)
884 {
885 if (asset == null)
886 return false;
887
888 return asset.requirements.requiresInstanceID;
889 }
890
891 public string GetDropdownEntryName(string referenceName)
892 {
893 var index = m_Dropdowns.IndexOf(referenceName);
894 return index >= 0 ? m_DropdownSelectedEntries[index] : string.Empty;
895 }
896
897 public void SetDropdownEntryName(string referenceName, string value)
898 {
899 var index = m_Dropdowns.IndexOf(referenceName);
900 if (index >= 0)
901 {
902 m_DropdownSelectedEntries[index] = value;
903 }
904 else
905 {
906 m_Dropdowns.Add(referenceName);
907 m_DropdownSelectedEntries.Add(value);
908 }
909 }
910
911 public override void Dispose()
912 {
913 base.Dispose();
914 m_SubGraph = null;
915 }
916 }
917}