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}