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