123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401 |
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using UnityEditor.Graphing;
- using UnityEditor.ShaderGraph.Internal;
- using UnityEngine.Profiling;
- using Pool = UnityEngine.Pool;
-
- namespace UnityEditor.ShaderGraph
- {
- internal static class GenerationUtils
- {
- const string kErrorString = @"ERROR!";
-
- internal static List<FieldDescriptor> GetActiveFieldsFromConditionals(ConditionalField[] conditionalFields)
- {
- var fields = new List<FieldDescriptor>();
- if (conditionalFields != null)
- {
- foreach (ConditionalField conditionalField in conditionalFields)
- {
- if (conditionalField.condition == true)
- {
- fields.Add(conditionalField.field);
- }
- }
- }
-
- return fields;
- }
-
- internal static void GenerateSubShaderTags(Target target, SubShaderDescriptor descriptor, ShaderStringBuilder builder)
- {
- builder.AppendLine("Tags");
- using (builder.BlockScope())
- {
- // Pipeline tag
- if (!string.IsNullOrEmpty(descriptor.pipelineTag))
- builder.AppendLine($"\"RenderPipeline\"=\"{descriptor.pipelineTag}\"");
- else
- builder.AppendLine("// RenderPipeline: <None>");
-
- // Render Type
- if (!string.IsNullOrEmpty(descriptor.renderType))
- builder.AppendLine($"\"RenderType\"=\"{descriptor.renderType}\"");
- else
- builder.AppendLine("// RenderType: <None>");
-
- // Custom shader tags.
- if (!string.IsNullOrEmpty(descriptor.customTags))
- builder.AppendLine(descriptor.customTags);
-
- // Render Queue
- if (!string.IsNullOrEmpty(descriptor.renderQueue))
- builder.AppendLine($"\"Queue\"=\"{descriptor.renderQueue}\"");
- else
- builder.AppendLine("// Queue: <None>");
-
- // DisableBatching tag
- if (!string.IsNullOrEmpty(descriptor.disableBatchingTag))
- builder.AppendLine($"\"DisableBatching\"=\"{descriptor.disableBatchingTag}\"");
- else
- builder.AppendLine("// DisableBatching: <None>");
-
- // ShaderGraphShader tag (so we can tell what shadergraph built)
- builder.AppendLine("\"ShaderGraphShader\"=\"true\"");
-
- if (target is IHasMetadata metadata)
- builder.AppendLine($"\"ShaderGraphTargetId\"=\"{metadata.identifier}\"");
-
- // IgnoreProjector
- if(!string.IsNullOrEmpty(descriptor.IgnoreProjector))
- builder.AppendLine($"\"IgnoreProjector\"=\"{descriptor.IgnoreProjector}\"");
-
- // PreviewType
- if(!string.IsNullOrEmpty(descriptor.PreviewType))
- builder.AppendLine($"\"PreviewType\"=\"{descriptor.PreviewType}\"");
-
- // CanUseSpriteAtlas
- if(!string.IsNullOrEmpty(descriptor.CanUseSpriteAtlas))
- builder.AppendLine($"\"CanUseSpriteAtlas\"=\"{descriptor.CanUseSpriteAtlas}\"");
- }
- }
-
- static bool IsFieldActive(FieldDescriptor field, IActiveFields activeFields, bool isOptional)
- {
- bool fieldActive = true;
- if (!activeFields.Contains(field) && isOptional)
- fieldActive = false; //if the field is optional and not inside of active fields
- return fieldActive;
- }
-
- internal static void GenerateShaderStruct(StructDescriptor shaderStruct, ActiveFields activeFields, bool humanReadable, out ShaderStringBuilder structBuilder)
- {
- structBuilder = new ShaderStringBuilder(humanReadable: humanReadable);
- structBuilder.AppendLine($"struct {shaderStruct.name}");
- using (structBuilder.BlockSemicolonScope())
- {
- foreach (var activeField in GetActiveFieldsAndKeyword(shaderStruct, activeFields))
- {
- var subscript = activeField.field;
- var keywordIfDefs = activeField.keywordIfDefs;
-
- //if field is active:
- if (subscript.HasPreprocessor())
- structBuilder.AppendLine($"#if {subscript.preprocessor}");
-
- //if in permutation, add permutation ifdef
- if (!string.IsNullOrEmpty(keywordIfDefs))
- structBuilder.AppendLine(keywordIfDefs);
-
- //check for a semantic, build string if valid
- string semantic = subscript.HasSemantic() ? $" : {subscript.semantic}" : string.Empty;
- structBuilder.AppendLine($"{subscript.interpolation} {subscript.type} {subscript.name}{semantic};");
-
- //if in permutation, add permutation endif
- if (!string.IsNullOrEmpty(keywordIfDefs))
- structBuilder.AppendLine("#endif"); //TODO: add debug collector
-
- if (subscript.HasPreprocessor())
- structBuilder.AppendLine("#endif");
- }
- }
- }
-
- struct PackedEntry
- {
- public struct Input
- {
- public FieldDescriptor field;
- public int startChannel;
- public int channelCount;
- }
-
- public Input[] inputFields;
- public FieldDescriptor packedField;
- }
-
- static IEnumerable<(FieldDescriptor field, string keywordIfDefs)> GetActiveFieldsAndKeyword(StructDescriptor shaderStruct, ActiveFields activeFields)
- {
- var activeFieldList = shaderStruct.fields
- .Select(currentField =>
- {
- bool fieldIsActive;
- var currentKeywordIfDefs = string.Empty;
-
- if (activeFields.permutationCount > 0)
- {
- //find all active fields per permutation
- var instances = activeFields.allPermutations.instances
- .Where(i => IsFieldActive(currentField, i, currentField.subscriptOptions.HasFlag(StructFieldOptions.Optional))).ToList();
- fieldIsActive = instances.Count > 0;
- if (fieldIsActive)
- currentKeywordIfDefs = KeywordUtil.GetKeywordPermutationSetConditional(instances.Select(i => i.permutationIndex).ToList());
- }
- else
- fieldIsActive = IsFieldActive(currentField, activeFields.baseInstance, currentField.subscriptOptions.HasFlag(StructFieldOptions.Optional));
- //else just find active fields
-
- if (fieldIsActive)
- {
- return
- (
- field: currentField,
- keywordIfDefs: currentKeywordIfDefs
- );
- }
-
- return
- (
- field: null,
- keywordIfDefs: null
- );
- }).Where(o => o.field != null);
- return activeFieldList;
- }
-
- static IEnumerable<FieldDescriptor> GetActiveFields(StructDescriptor shaderStruct, ActiveFields activeFields)
- {
- return GetActiveFieldsAndKeyword(shaderStruct, activeFields).Select(o => o.field);
- }
-
- static IEnumerable<FieldDescriptor> GetActiveFields(StructDescriptor shaderStruct, IActiveFields activeFields)
- {
- var activeFieldList = shaderStruct.fields
- .Where(field => IsFieldActive(field, activeFields, field.subscriptOptions.HasFlag(StructFieldOptions.Optional)));
- return activeFieldList;
- }
-
- static PackedEntry[] GeneratePackingLayout(StructDescriptor shaderStruct, ActiveFields activeFields)
- {
- var activeFieldList = GetActiveFields(shaderStruct, activeFields);
- return GeneratePackingLayout(shaderStruct.name, activeFieldList);
- }
-
- static PackedEntry[] GeneratePackingLayout(StructDescriptor shaderStruct, IActiveFields activeFields)
- {
- var activeFieldList = GetActiveFields(shaderStruct, activeFields);
- return GeneratePackingLayout(shaderStruct.name, activeFieldList);
- }
-
- static PackedEntry[] GeneratePackingLayout(string baseStructName, IEnumerable<FieldDescriptor> activeFields)
- {
- const int kPreUnpackable = 0;
- const int kPackable = 1;
- const int kPostUnpackable = 2;
-
- var fieldCategorized = activeFields
- .GroupBy(subscript =>
- {
- if (subscript.HasPreprocessor())
- {
- //special case, "UNITY_STEREO_INSTANCING_ENABLED" fields must be packed at the end of the struct because they are system generated semantics
- if (subscript.preprocessor.Contains("INSTANCING"))
- return kPostUnpackable;
-
- //special case, "SHADER_STAGE_FRAGMENT" fields must be packed at the end of the struct,
- //otherwise the vertex output struct will have different semantic ordering than the fragment input struct.
- if (subscript.preprocessor.Contains("SHADER_STAGE_FRAGMENT"))
- return kPostUnpackable;
-
- return kPreUnpackable;
- }
-
- if (subscript.HasSemantic() || subscript.vectorCount == 0)
- return kPreUnpackable;
-
- return kPackable;
- }).OrderBy(o => o.Key);
-
- var packStructName = "Packed" + baseStructName;
- int currentInterpolatorIndex = 0;
- var packedEntries = new List<PackedEntry>();
- foreach (var collection in fieldCategorized)
- {
- var packingEnabled = collection.Key == kPackable;
- if (packingEnabled)
- {
- var groupByInterpolator = collection.GroupBy(field => string.IsNullOrEmpty(field.interpolation) ? string.Empty : field.interpolation);
- foreach (var collectionInterpolator in groupByInterpolator)
- {
- //OrderByDescending is stable sort
- var elementToPack = collectionInterpolator.OrderByDescending(o => o.vectorCount).ToList();
- var totalVectorCount = elementToPack.Sum(o => o.vectorCount);
-
- const bool allowSplitting = true;
- #pragma warning disable 162
- int maxInterpolatorCount;
- if (allowSplitting)
- maxInterpolatorCount = ((totalVectorCount + 3) & ~0x03) >> 2;
- else
- maxInterpolatorCount = elementToPack.Count;
- #pragma warning restore 162
-
- var intermediateInterpolator = Enumerable.Range(0, maxInterpolatorCount).Select(_ =>
- (
- fields : new List<PackedEntry.Input>(),
- vectorCount : 0
- )
- ).ToList();
-
- const int kMaxVectorCount = 4;
- //First Pass *without* channel splitting
- int itElement = 0;
- while (itElement < elementToPack.Count)
- {
- var currentElement = elementToPack[itElement];
-
- var availableSlotIndex = intermediateInterpolator.FindIndex(o =>
- o.vectorCount + currentElement.vectorCount <= kMaxVectorCount);
-
- if (availableSlotIndex != -1)
- {
- elementToPack.RemoveAt(itElement);
- var slot = intermediateInterpolator[availableSlotIndex];
- slot.vectorCount += currentElement.vectorCount;
- slot.fields.Add(new PackedEntry.Input()
- {
- field = currentElement,
- startChannel = 0,
- channelCount = currentElement.vectorCount,
- });
- intermediateInterpolator[availableSlotIndex] = slot;
- }
- else
- {
- itElement++;
- }
- }
-
- if (!allowSplitting && elementToPack.Count > 0)
- throw new InvalidOperationException("Unexpected failure in interpolator packing algorithm.");
-
- //Second Pass *with* channel splitting
- foreach (var remainingElement in elementToPack)
- {
- int currentStartChannel = 0;
- while (currentStartChannel < remainingElement.vectorCount)
- {
- var availableSlotIndex = intermediateInterpolator.FindIndex(o => o.vectorCount < kMaxVectorCount);
- if (availableSlotIndex == -1)
- throw new InvalidOperationException("Unexpected failure in interpolator packing algorithm.");
-
- var slot = intermediateInterpolator[availableSlotIndex];
- var currentChannelCount = Math.Min(kMaxVectorCount - slot.vectorCount, kMaxVectorCount - (remainingElement.vectorCount - currentStartChannel));
- slot.vectorCount += currentChannelCount;
- slot.fields.Add(new PackedEntry.Input()
- {
- field = remainingElement,
- startChannel = currentStartChannel,
- channelCount = currentChannelCount,
- });
- intermediateInterpolator[availableSlotIndex] = slot;
- currentStartChannel += currentChannelCount;
- }
- }
-
- packedEntries.AddRange(intermediateInterpolator
- .Where(o => o.vectorCount > 0)
- .Select(o =>
- {
- var allName = o.fields.Select(f =>
- f.channelCount == f.field.vectorCount
- ? f.field.name
- : f.field.name + ShaderSpliceUtil.GetChannelSwizzle(f.startChannel, f.channelCount));
- var name = o.fields.Count == 1
- ? allName.First()
- : "packed_" + allName.Aggregate((a, b) => $"{a}_{b}");
- return new PackedEntry()
- {
- inputFields = o.fields.ToArray(),
- packedField = new FieldDescriptor
- (
- tag: packStructName,
- name: name,
- define: string.Empty,
- type: $"float{o.vectorCount}",
- semantic: $"INTERP{currentInterpolatorIndex++}",
- preprocessor: string.Empty,
- subscriptOptions: StructFieldOptions.Static,
- interpolation: collectionInterpolator.Key
- )
- };
- }));
- }
- }
- else
- {
- foreach (var field in collection)
- {
- var inputFields = new[]
- {
- new PackedEntry.Input()
- {
- field = field,
- channelCount = 0,
- startChannel = 0
- }
- };
-
- //Auto add semantic if needed
- if (!field.HasSemantic())
- {
- var newField = new FieldDescriptor
- (
- tag: packStructName,
- name: field.name,
- define: field.define,
- type: field.type,
- semantic: $"INTERP{currentInterpolatorIndex++}",
- preprocessor: field.preprocessor,
- subscriptOptions: StructFieldOptions.Static,
- interpolation: field.interpolation
- );
- packedEntries.Add(new()
- {
- inputFields = inputFields,
- packedField = newField
- });
- }
- else
- {
- packedEntries.Add(new PackedEntry()
- {
- inputFields = inputFields,
- packedField = field
- });
- }
- }
- }
- }
-
- return packedEntries.ToArray();
- }
-
- internal static void GeneratePackedStruct(StructDescriptor shaderStruct, ActiveFields activeFields, out StructDescriptor packStruct)
- {
- var packingLayout = GeneratePackingLayout(shaderStruct, activeFields);
- var packStructName = "Packed" + shaderStruct.name;
- packStruct = new StructDescriptor()
- {
- name = packStructName,
- packFields = true,
- fields = packingLayout.Select(o => o.packedField).ToArray()
- };
- }
-
- internal static void GenerateInterpolatorFunctions(StructDescriptor shaderStruct, IActiveFields activeFields, bool humanReadable, out ShaderStringBuilder interpolatorBuilder)
- {
- //set up function string builders and struct builder
- var packBuilder = new ShaderStringBuilder(humanReadable: humanReadable);
- var unpackBuilder = new ShaderStringBuilder(humanReadable: humanReadable);
- interpolatorBuilder = new ShaderStringBuilder(humanReadable: humanReadable);
- string packedStruct = "Packed" + shaderStruct.name;
-
- //declare function headers
- packBuilder.AppendLine($"{packedStruct} Pack{shaderStruct.name} ({shaderStruct.name} input)");
- packBuilder.AppendLine("{");
- packBuilder.IncreaseIndent();
- packBuilder.AppendLine($"{packedStruct} output;");
- packBuilder.AppendLine($"ZERO_INITIALIZE({packedStruct}, output);");
-
- unpackBuilder.AppendLine($"{shaderStruct.name} Unpack{shaderStruct.name} ({packedStruct} input)");
- unpackBuilder.AppendLine("{");
- unpackBuilder.IncreaseIndent();
- unpackBuilder.AppendLine($"{shaderStruct.name} output;");
-
- var packingLayout = GeneratePackingLayout(shaderStruct, activeFields);
- foreach (var packEntry in packingLayout)
- {
- int firstPackedChannel = 0;
- foreach (var input in packEntry.inputFields)
- {
- if (input.field.HasPreprocessor())
- {
- packBuilder.AppendLine($"#if {input.field.preprocessor}");
- unpackBuilder.AppendLine($"#if {input.field.preprocessor}");
- }
-
- var packedChannels = string.Empty;
- var unpackedChannel = string.Empty;
- if (input.channelCount != 0)
- {
- if (firstPackedChannel != 0 || input.channelCount != packEntry.packedField.vectorCount)
- packedChannels = $".{ShaderSpliceUtil.GetChannelSwizzle(firstPackedChannel, input.channelCount)}";
- if (input.startChannel != 0 || input.channelCount != input.field.vectorCount)
- unpackedChannel = $".{ShaderSpliceUtil.GetChannelSwizzle(input.startChannel, input.channelCount)}";
- }
-
- packBuilder.AppendLine($"output.{packEntry.packedField.name}{packedChannels} = input.{input.field.name}{unpackedChannel};");
- unpackBuilder.AppendLine($"output.{input.field.name}{unpackedChannel} = input.{packEntry.packedField.name}{packedChannels};");
- firstPackedChannel += input.field.vectorCount;
-
- if (input.field.HasPreprocessor())
- {
- packBuilder.AppendLine("#endif");
- unpackBuilder.AppendLine("#endif");
- }
- }
- }
-
- //close function declarations
- packBuilder.AppendLine("return output;");
- packBuilder.DecreaseIndent();
- packBuilder.AppendLine("}");
- packBuilder.AppendNewLine();
-
- unpackBuilder.AppendLine("return output;");
- unpackBuilder.DecreaseIndent();
- unpackBuilder.AppendLine("}");
- unpackBuilder.AppendNewLine();
-
- interpolatorBuilder.Concat(packBuilder);
- interpolatorBuilder.Concat(unpackBuilder);
- }
-
- internal static void GetUpstreamNodesForShaderPass(AbstractMaterialNode outputNode, PassDescriptor pass, out List<AbstractMaterialNode> vertexNodes, out List<AbstractMaterialNode> pixelNodes)
- {
- // Traverse Graph Data
- vertexNodes = Pool.ListPool<AbstractMaterialNode>.Get();
- NodeUtils.DepthFirstCollectNodesFromNode(vertexNodes, outputNode, NodeUtils.IncludeSelf.Include);
-
- pixelNodes = Pool.ListPool<AbstractMaterialNode>.Get();
- NodeUtils.DepthFirstCollectNodesFromNode(pixelNodes, outputNode, NodeUtils.IncludeSelf.Include);
- }
-
- internal static void GetActiveFieldsAndPermutationsForNodes(PassDescriptor pass,
- KeywordCollector keywordCollector, List<AbstractMaterialNode> vertexNodes, List<AbstractMaterialNode> pixelNodes,
- bool[] texCoordNeedsDerivs,
- List<int>[] vertexNodePermutations, List<int>[] pixelNodePermutations,
- ActiveFields activeFields, out ShaderGraphRequirementsPerKeyword graphRequirements)
- {
- // Initialize requirements
- ShaderGraphRequirementsPerKeyword pixelRequirements = new ShaderGraphRequirementsPerKeyword();
- ShaderGraphRequirementsPerKeyword vertexRequirements = new ShaderGraphRequirementsPerKeyword();
- graphRequirements = new ShaderGraphRequirementsPerKeyword();
-
- // Evaluate all Keyword permutations
- if (keywordCollector.permutations.Count > 0)
- {
- for (int i = 0; i < keywordCollector.permutations.Count; i++)
- {
- // Get active nodes for this permutation
- var localVertexNodes = Pool.HashSetPool<AbstractMaterialNode>.Get();
- var localPixelNodes = Pool.HashSetPool<AbstractMaterialNode>.Get();
-
- localVertexNodes.EnsureCapacity(vertexNodes.Count);
- localPixelNodes.EnsureCapacity(pixelNodes.Count);
-
- foreach (var vertexNode in vertexNodes)
- {
- NodeUtils.DepthFirstCollectNodesFromNode(localVertexNodes, vertexNode, NodeUtils.IncludeSelf.Include, keywordCollector.permutations[i]);
- }
-
- foreach (var pixelNode in pixelNodes)
- {
- NodeUtils.DepthFirstCollectNodesFromNode(localPixelNodes, pixelNode, NodeUtils.IncludeSelf.Include, keywordCollector.permutations[i]);
- }
-
- // Track each vertex node in this permutation
- foreach (AbstractMaterialNode vertexNode in localVertexNodes)
- {
- int nodeIndex = vertexNodes.IndexOf(vertexNode);
-
- if (vertexNodePermutations[nodeIndex] == null)
- vertexNodePermutations[nodeIndex] = new List<int>();
- vertexNodePermutations[nodeIndex].Add(i);
- }
-
- // Track each pixel node in this permutation
- foreach (AbstractMaterialNode pixelNode in localPixelNodes)
- {
- int nodeIndex = pixelNodes.IndexOf(pixelNode);
-
- if (pixelNodePermutations[nodeIndex] == null)
- pixelNodePermutations[nodeIndex] = new List<int>();
- pixelNodePermutations[nodeIndex].Add(i);
- }
-
- // Get requirements for this permutation
- vertexRequirements[i].SetRequirements(ShaderGraphRequirements.FromNodes(localVertexNodes, ShaderStageCapability.Vertex, false, texCoordNeedsDerivs));
- pixelRequirements[i].SetRequirements(ShaderGraphRequirements.FromNodes(localPixelNodes, ShaderStageCapability.Fragment, false, texCoordNeedsDerivs));
-
- // Add active fields
- var conditionalFields = GetActiveFieldsFromConditionals(GetConditionalFieldsFromPixelRequirements(pixelRequirements[i].requirements));
- if (activeFields[i].Contains(Fields.GraphVertex))
- {
- conditionalFields.AddRange(GetActiveFieldsFromConditionals(GetConditionalFieldsFromVertexRequirements(vertexRequirements[i].requirements)));
- }
- foreach (var field in conditionalFields)
- {
- activeFields[i].Add(field);
- }
- }
- }
- // No Keywords
- else
- {
- // Get requirements
- vertexRequirements.baseInstance.SetRequirements(ShaderGraphRequirements.FromNodes(vertexNodes, ShaderStageCapability.Vertex, false, texCoordNeedsDerivs));
- pixelRequirements.baseInstance.SetRequirements(ShaderGraphRequirements.FromNodes(pixelNodes, ShaderStageCapability.Fragment, false, texCoordNeedsDerivs));
-
- // Add active fields
- var conditionalFields = GetActiveFieldsFromConditionals(GetConditionalFieldsFromPixelRequirements(pixelRequirements.baseInstance.requirements));
- if (activeFields.baseInstance.Contains(Fields.GraphVertex))
- {
- conditionalFields.AddRange(GetActiveFieldsFromConditionals(GetConditionalFieldsFromVertexRequirements(vertexRequirements.baseInstance.requirements)));
- }
- foreach (var field in conditionalFields)
- {
- activeFields.baseInstance.Add(field);
- }
- }
-
- // Build graph requirements
- graphRequirements.UnionWith(pixelRequirements);
- graphRequirements.UnionWith(vertexRequirements);
- }
-
- static ConditionalField[] GetConditionalFieldsFromVertexRequirements(ShaderGraphRequirements requirements)
- {
- return new ConditionalField[]
- {
- new ConditionalField(StructFields.VertexDescriptionInputs.ScreenPosition, requirements.requiresScreenPosition),
- new ConditionalField(StructFields.VertexDescriptionInputs.NDCPosition, requirements.requiresNDCPosition),
- new ConditionalField(StructFields.VertexDescriptionInputs.PixelPosition, requirements.requiresPixelPosition),
-
- new ConditionalField(StructFields.VertexDescriptionInputs.VertexColor, requirements.requiresVertexColor),
-
- new ConditionalField(StructFields.VertexDescriptionInputs.ObjectSpaceNormal, (requirements.requiresNormal & NeededCoordinateSpace.Object) > 0),
- new ConditionalField(StructFields.VertexDescriptionInputs.ViewSpaceNormal, (requirements.requiresNormal & NeededCoordinateSpace.View) > 0),
- new ConditionalField(StructFields.VertexDescriptionInputs.WorldSpaceNormal, (requirements.requiresNormal & NeededCoordinateSpace.World) > 0),
- new ConditionalField(StructFields.VertexDescriptionInputs.TangentSpaceNormal, (requirements.requiresNormal & NeededCoordinateSpace.Tangent) > 0),
-
- new ConditionalField(StructFields.VertexDescriptionInputs.ObjectSpaceViewDirection, (requirements.requiresViewDir & NeededCoordinateSpace.Object) > 0),
- new ConditionalField(StructFields.VertexDescriptionInputs.ViewSpaceViewDirection, (requirements.requiresViewDir & NeededCoordinateSpace.View) > 0),
- new ConditionalField(StructFields.VertexDescriptionInputs.WorldSpaceViewDirection, (requirements.requiresViewDir & NeededCoordinateSpace.World) > 0),
- new ConditionalField(StructFields.VertexDescriptionInputs.TangentSpaceViewDirection, (requirements.requiresViewDir & NeededCoordinateSpace.Tangent) > 0),
-
- new ConditionalField(StructFields.VertexDescriptionInputs.ObjectSpaceTangent, (requirements.requiresTangent & NeededCoordinateSpace.Object) > 0),
- new ConditionalField(StructFields.VertexDescriptionInputs.ViewSpaceTangent, (requirements.requiresTangent & NeededCoordinateSpace.View) > 0),
- new ConditionalField(StructFields.VertexDescriptionInputs.WorldSpaceTangent, (requirements.requiresTangent & NeededCoordinateSpace.World) > 0),
- new ConditionalField(StructFields.VertexDescriptionInputs.TangentSpaceTangent, (requirements.requiresTangent & NeededCoordinateSpace.Tangent) > 0),
-
- new ConditionalField(StructFields.VertexDescriptionInputs.ObjectSpaceBiTangent, (requirements.requiresBitangent & NeededCoordinateSpace.Object) > 0),
- new ConditionalField(StructFields.VertexDescriptionInputs.ViewSpaceBiTangent, (requirements.requiresBitangent & NeededCoordinateSpace.View) > 0),
- new ConditionalField(StructFields.VertexDescriptionInputs.WorldSpaceBiTangent, (requirements.requiresBitangent & NeededCoordinateSpace.World) > 0),
- new ConditionalField(StructFields.VertexDescriptionInputs.TangentSpaceBiTangent, (requirements.requiresBitangent & NeededCoordinateSpace.Tangent) > 0),
-
- new ConditionalField(StructFields.VertexDescriptionInputs.ObjectSpacePosition, (requirements.requiresPosition & NeededCoordinateSpace.Object) > 0),
- new ConditionalField(StructFields.VertexDescriptionInputs.ViewSpacePosition, (requirements.requiresPosition & NeededCoordinateSpace.View) > 0),
- new ConditionalField(StructFields.VertexDescriptionInputs.WorldSpacePosition, (requirements.requiresPosition & NeededCoordinateSpace.World) > 0),
- new ConditionalField(StructFields.VertexDescriptionInputs.TangentSpacePosition, (requirements.requiresPosition & NeededCoordinateSpace.Tangent) > 0),
- new ConditionalField(StructFields.VertexDescriptionInputs.AbsoluteWorldSpacePosition, (requirements.requiresPosition & NeededCoordinateSpace.AbsoluteWorld) > 0),
-
- new ConditionalField(StructFields.VertexDescriptionInputs.ObjectSpacePositionPredisplacement, (requirements.requiresPositionPredisplacement & NeededCoordinateSpace.Object) > 0),
- new ConditionalField(StructFields.VertexDescriptionInputs.ViewSpacePositionPredisplacement, (requirements.requiresPositionPredisplacement & NeededCoordinateSpace.View) > 0),
- new ConditionalField(StructFields.VertexDescriptionInputs.WorldSpacePositionPredisplacement, (requirements.requiresPositionPredisplacement & NeededCoordinateSpace.World) > 0),
- new ConditionalField(StructFields.VertexDescriptionInputs.TangentSpacePositionPredisplacement, (requirements.requiresPositionPredisplacement & NeededCoordinateSpace.Tangent) > 0),
- new ConditionalField(StructFields.VertexDescriptionInputs.AbsoluteWorldSpacePositionPredisplacement, (requirements.requiresPositionPredisplacement & NeededCoordinateSpace.AbsoluteWorld) > 0),
-
- new ConditionalField(StructFields.VertexDescriptionInputs.uv0, requirements.requiresMeshUVs.Contains(UVChannel.UV0)),
- new ConditionalField(StructFields.VertexDescriptionInputs.uv1, requirements.requiresMeshUVs.Contains(UVChannel.UV1)),
- new ConditionalField(StructFields.VertexDescriptionInputs.uv2, requirements.requiresMeshUVs.Contains(UVChannel.UV2)),
- new ConditionalField(StructFields.VertexDescriptionInputs.uv3, requirements.requiresMeshUVs.Contains(UVChannel.UV3)),
-
- new ConditionalField(GeneratorDerivativeUtils.uv0Ddx, requirements.requiresMeshUVDerivatives.Contains(UVChannel.UV0)),
- new ConditionalField(GeneratorDerivativeUtils.uv0Ddy, requirements.requiresMeshUVDerivatives.Contains(UVChannel.UV0)),
- new ConditionalField(GeneratorDerivativeUtils.uv1Ddx, requirements.requiresMeshUVDerivatives.Contains(UVChannel.UV1)),
- new ConditionalField(GeneratorDerivativeUtils.uv1Ddy, requirements.requiresMeshUVDerivatives.Contains(UVChannel.UV1)),
- new ConditionalField(GeneratorDerivativeUtils.uv2Ddx, requirements.requiresMeshUVDerivatives.Contains(UVChannel.UV2)),
- new ConditionalField(GeneratorDerivativeUtils.uv2Ddy, requirements.requiresMeshUVDerivatives.Contains(UVChannel.UV2)),
- new ConditionalField(GeneratorDerivativeUtils.uv3Ddx, requirements.requiresMeshUVDerivatives.Contains(UVChannel.UV3)),
- new ConditionalField(GeneratorDerivativeUtils.uv3Ddy, requirements.requiresMeshUVDerivatives.Contains(UVChannel.UV3)),
-
- new ConditionalField(StructFields.VertexDescriptionInputs.TimeParameters, requirements.requiresTime),
-
- new ConditionalField(StructFields.VertexDescriptionInputs.BoneWeights, requirements.requiresVertexSkinning),
- new ConditionalField(StructFields.VertexDescriptionInputs.BoneIndices, requirements.requiresVertexSkinning),
- new ConditionalField(StructFields.VertexDescriptionInputs.VertexID, requirements.requiresVertexID),
- new ConditionalField(StructFields.VertexDescriptionInputs.InstanceID, requirements.requiresInstanceID),
-
- new ConditionalField(Fields.ObjectToWorld, requirements.requiresTransforms.Contains(NeededTransform.ObjectToWorld)),
- new ConditionalField(Fields.WorldToObject, requirements.requiresTransforms.Contains(NeededTransform.WorldToObject)),
- };
- }
-
- static ConditionalField[] GetConditionalFieldsFromPixelRequirements(ShaderGraphRequirements requirements)
- {
- return new ConditionalField[]
- {
- new ConditionalField(StructFields.SurfaceDescriptionInputs.ScreenPosition, requirements.requiresScreenPosition),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.NDCPosition, requirements.requiresNDCPosition),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.PixelPosition, requirements.requiresPixelPosition),
-
- new ConditionalField(StructFields.SurfaceDescriptionInputs.VertexColor, requirements.requiresVertexColor),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.FaceSign, requirements.requiresFaceSign),
-
- new ConditionalField(StructFields.SurfaceDescriptionInputs.ObjectSpaceNormal, (requirements.requiresNormal & NeededCoordinateSpace.Object) > 0),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.ViewSpaceNormal, (requirements.requiresNormal & NeededCoordinateSpace.View) > 0),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.WorldSpaceNormal, (requirements.requiresNormal & NeededCoordinateSpace.World) > 0),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.TangentSpaceNormal, (requirements.requiresNormal & NeededCoordinateSpace.Tangent) > 0),
-
- new ConditionalField(StructFields.SurfaceDescriptionInputs.ObjectSpaceViewDirection, (requirements.requiresViewDir & NeededCoordinateSpace.Object) > 0),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.ViewSpaceViewDirection, (requirements.requiresViewDir & NeededCoordinateSpace.View) > 0),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.WorldSpaceViewDirection, (requirements.requiresViewDir & NeededCoordinateSpace.World) > 0),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.TangentSpaceViewDirection, (requirements.requiresViewDir & NeededCoordinateSpace.Tangent) > 0),
-
- new ConditionalField(StructFields.SurfaceDescriptionInputs.ObjectSpaceTangent, (requirements.requiresTangent & NeededCoordinateSpace.Object) > 0),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.ViewSpaceTangent, (requirements.requiresTangent & NeededCoordinateSpace.View) > 0),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.WorldSpaceTangent, (requirements.requiresTangent & NeededCoordinateSpace.World) > 0),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.TangentSpaceTangent, (requirements.requiresTangent & NeededCoordinateSpace.Tangent) > 0),
-
- new ConditionalField(StructFields.SurfaceDescriptionInputs.ObjectSpaceBiTangent, (requirements.requiresBitangent & NeededCoordinateSpace.Object) > 0),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.ViewSpaceBiTangent, (requirements.requiresBitangent & NeededCoordinateSpace.View) > 0),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.WorldSpaceBiTangent, (requirements.requiresBitangent & NeededCoordinateSpace.World) > 0),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.TangentSpaceBiTangent, (requirements.requiresBitangent & NeededCoordinateSpace.Tangent) > 0),
-
- new ConditionalField(StructFields.SurfaceDescriptionInputs.ObjectSpacePosition, (requirements.requiresPosition & NeededCoordinateSpace.Object) > 0),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.ViewSpacePosition, (requirements.requiresPosition & NeededCoordinateSpace.View) > 0),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.WorldSpacePosition, (requirements.requiresPosition & NeededCoordinateSpace.World) > 0),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.TangentSpacePosition, (requirements.requiresPosition & NeededCoordinateSpace.Tangent) > 0),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.AbsoluteWorldSpacePosition, (requirements.requiresPosition & NeededCoordinateSpace.AbsoluteWorld) > 0),
-
- new ConditionalField(StructFields.SurfaceDescriptionInputs.ObjectSpacePositionPredisplacement, (requirements.requiresPositionPredisplacement & NeededCoordinateSpace.Object) > 0),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.ViewSpacePositionPredisplacement, (requirements.requiresPositionPredisplacement & NeededCoordinateSpace.View) > 0),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.WorldSpacePositionPredisplacement, (requirements.requiresPositionPredisplacement & NeededCoordinateSpace.World) > 0),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.TangentSpacePositionPredisplacement, (requirements.requiresPositionPredisplacement & NeededCoordinateSpace.Tangent) > 0),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.AbsoluteWorldSpacePositionPredisplacement, (requirements.requiresPositionPredisplacement & NeededCoordinateSpace.AbsoluteWorld) > 0),
-
- new ConditionalField(StructFields.SurfaceDescriptionInputs.uv0, requirements.requiresMeshUVs.Contains(UVChannel.UV0)),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.uv1, requirements.requiresMeshUVs.Contains(UVChannel.UV1)),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.uv2, requirements.requiresMeshUVs.Contains(UVChannel.UV2)),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.uv3, requirements.requiresMeshUVs.Contains(UVChannel.UV3)),
-
- new ConditionalField(StructFields.SurfaceDescriptionInputs.TimeParameters, requirements.requiresTime),
-
- new ConditionalField(StructFields.SurfaceDescriptionInputs.BoneWeights, requirements.requiresVertexSkinning),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.BoneIndices, requirements.requiresVertexSkinning),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.VertexID, requirements.requiresVertexID),
- new ConditionalField(StructFields.SurfaceDescriptionInputs.InstanceID, requirements.requiresInstanceID),
-
- new ConditionalField(Fields.ObjectToWorld, requirements.requiresTransforms.Contains(NeededTransform.ObjectToWorld)),
- new ConditionalField(Fields.WorldToObject, requirements.requiresTransforms.Contains(NeededTransform.WorldToObject)),
- };
- }
-
- internal static void AddRequiredFields(FieldCollection passRequiredFields, IActiveFieldsSet activeFields)
- {
- if (passRequiredFields != null)
- {
- foreach (FieldCollection.Item requiredField in passRequiredFields)
- {
- activeFields.AddAll(requiredField.field);
- }
- }
- }
-
- internal static void ApplyFieldDependencies(IActiveFields activeFields, DependencyCollection dependencies)
- {
- // add active fields to queue
- Queue<FieldDescriptor> fieldsToPropagate = new Queue<FieldDescriptor>();
- foreach (var f in activeFields.fields)
- {
- fieldsToPropagate.Enqueue(f);
- }
-
- // foreach field in queue:
- while (fieldsToPropagate.Count > 0)
- {
- FieldDescriptor field = fieldsToPropagate.Dequeue();
- if (activeFields.Contains(field)) // this should always be true
- {
- if (dependencies == null)
- return;
-
- // find all dependencies of field that are not already active
- foreach (DependencyCollection.Item d in dependencies.Where(d => (d.dependency.field == field) && !activeFields.Contains(d.dependency.dependsOn)))
- {
- // activate them and add them to the queue
- activeFields.Add(d.dependency.dependsOn);
- fieldsToPropagate.Enqueue(d.dependency.dependsOn);
- }
- }
- }
- }
-
- internal static List<MaterialSlot> FindMaterialSlotsOnNode(IEnumerable<int> slots, AbstractMaterialNode node)
- {
- if (slots == null)
- return null;
-
- var activeSlots = new List<MaterialSlot>();
- foreach (var id in slots)
- {
- MaterialSlot slot = node.FindSlot<MaterialSlot>(id);
- if (slot != null)
- {
- activeSlots.Add(slot);
- }
- }
- return activeSlots;
- }
-
- internal static string AdaptNodeOutput(AbstractMaterialNode node, int outputSlotId, ConcreteSlotValueType convertToType)
- {
- var outputSlot = node.FindOutputSlot<MaterialSlot>(outputSlotId);
-
- if (outputSlot == null)
- return kErrorString;
-
- var convertFromType = outputSlot.concreteValueType;
- var rawOutput = node.GetVariableNameForSlot(outputSlotId);
- if (convertFromType == convertToType)
- return rawOutput;
-
- switch (convertToType)
- {
- case ConcreteSlotValueType.Boolean:
- switch (convertFromType)
- {
- case ConcreteSlotValueType.Vector1:
- return string.Format("((bool) {0})", rawOutput);
- case ConcreteSlotValueType.Vector2:
- case ConcreteSlotValueType.Vector3:
- case ConcreteSlotValueType.Vector4:
- return string.Format("((bool) {0}.x)", rawOutput);
- default:
- return kErrorString;
- }
- case ConcreteSlotValueType.Vector1:
- if (convertFromType == ConcreteSlotValueType.Boolean)
- return string.Format("(($precision) {0})", rawOutput);
- else
- return string.Format("({0}).x", rawOutput);
- case ConcreteSlotValueType.Vector2:
- switch (convertFromType)
- {
- case ConcreteSlotValueType.Boolean:
- return string.Format("((($precision) {0}).xx)", rawOutput);
- case ConcreteSlotValueType.Vector1:
- return string.Format("({0}.xx)", rawOutput);
- case ConcreteSlotValueType.Vector3:
- case ConcreteSlotValueType.Vector4:
- return string.Format("({0}.xy)", rawOutput);
- default:
- return kErrorString;
- }
- case ConcreteSlotValueType.Vector3:
- switch (convertFromType)
- {
- case ConcreteSlotValueType.Boolean:
- return string.Format("((($precision) {0}).xxx)", rawOutput);
- case ConcreteSlotValueType.Vector1:
- return string.Format("({0}.xxx)", rawOutput);
- case ConcreteSlotValueType.Vector2:
- return string.Format("($precision3({0}, 0.0))", rawOutput);
- case ConcreteSlotValueType.Vector4:
- return string.Format("({0}.xyz)", rawOutput);
- default:
- return kErrorString;
- }
- case ConcreteSlotValueType.Vector4:
- switch (convertFromType)
- {
- case ConcreteSlotValueType.Boolean:
- return string.Format("((($precision) {0}).xxxx)", rawOutput);
- case ConcreteSlotValueType.Vector1:
- return string.Format("({0}.xxxx)", rawOutput);
- case ConcreteSlotValueType.Vector2:
- return string.Format("($precision4({0}, 0.0, 1.0))", rawOutput);
- case ConcreteSlotValueType.Vector3:
- return string.Format("($precision4({0}, 1.0))", rawOutput);
- default:
- return kErrorString;
- }
- case ConcreteSlotValueType.Matrix3:
- return rawOutput;
- case ConcreteSlotValueType.Matrix2:
- return rawOutput;
- case ConcreteSlotValueType.PropertyConnectionState:
- return node.GetConnnectionStateVariableNameForSlot(outputSlotId);
- default:
- return kErrorString;
- }
- }
-
- internal static string AdaptNodeOutputForPreview(AbstractMaterialNode node, int outputSlotId)
- {
- string rawOutput = node.GetVariableNameForSlot(outputSlotId);
- return AdaptNodeOutputForPreview(node, outputSlotId, rawOutput);
- }
-
- internal static string AdaptNodeOutputForPreview(AbstractMaterialNode node, int slotId, string variableName)
- {
- var slot = node.FindSlot<MaterialSlot>(slotId);
-
- if (slot == null)
- return kErrorString;
-
- var convertFromType = slot.concreteValueType;
-
- // preview is always dimension 4
- switch (convertFromType)
- {
- case ConcreteSlotValueType.Vector1:
- return string.Format("half4({0}, {0}, {0}, 1.0)", variableName);
- case ConcreteSlotValueType.Vector2:
- return string.Format("half4({0}.x, {0}.y, 0.0, 1.0)", variableName);
- case ConcreteSlotValueType.Vector3:
- return string.Format("half4({0}.x, {0}.y, {0}.z, 1.0)", variableName);
- case ConcreteSlotValueType.Vector4:
- return string.Format("half4({0}.x, {0}.y, {0}.z, 1.0)", variableName);
- case ConcreteSlotValueType.Boolean:
- return string.Format("half4({0}, {0}, {0}, 1.0)", variableName);
- default:
- return "half4(0, 0, 0, 0)";
- }
- }
-
- static void GenerateSpaceTranslationSurfaceInputs(
- NeededCoordinateSpace neededSpaces,
- InterpolatorType interpolatorType,
- ShaderStringBuilder builder,
- string format = "float3 {0};")
- {
- if ((neededSpaces & NeededCoordinateSpace.Object) > 0)
- builder.AppendLine(format, CoordinateSpace.Object.ToVariableName(interpolatorType));
-
- if ((neededSpaces & NeededCoordinateSpace.World) > 0)
- builder.AppendLine(format, CoordinateSpace.World.ToVariableName(interpolatorType));
-
- if ((neededSpaces & NeededCoordinateSpace.View) > 0)
- builder.AppendLine(format, CoordinateSpace.View.ToVariableName(interpolatorType));
-
- if ((neededSpaces & NeededCoordinateSpace.Tangent) > 0)
- builder.AppendLine(format, CoordinateSpace.Tangent.ToVariableName(interpolatorType));
-
- if ((neededSpaces & NeededCoordinateSpace.AbsoluteWorld) > 0)
- builder.AppendLine(format, CoordinateSpace.AbsoluteWorld.ToVariableName(interpolatorType));
- }
-
- internal static void GeneratePropertiesBlock(ShaderStringBuilder sb, PropertyCollector propertyCollector, KeywordCollector keywordCollector, GenerationMode mode, List<GraphInputData> graphInputs)
- {
- sb.AppendLine("Properties");
- using (sb.BlockScope())
- {
- if (graphInputs == null || graphInputs.Count == 0)
- {
- foreach (var prop in propertyCollector.properties.Where(x => x.shouldGeneratePropertyBlock))
- {
- prop.AppendPropertyBlockStrings(sb);
- }
-
- // Keywords use hardcoded state in preview
- // Do not add them to the Property Block
- if (mode == GenerationMode.Preview)
- return;
-
- foreach (var key in keywordCollector.keywords.Where(x => x.generatePropertyBlock))
- {
- key.AppendPropertyBlockStrings(sb);
- }
- }
- else
- {
- var propertyInputs = propertyCollector.properties.Where(x => x.shouldGeneratePropertyBlock).ToList();
- var keywordInputs = keywordCollector.keywords.Where(x => x.generatePropertyBlock).ToList();
- foreach (var input in graphInputs)
- {
- if (input.isKeyword && mode != GenerationMode.Preview)
- {
- var keyword = keywordInputs.FirstOrDefault(x => x.referenceName.CompareTo(input.referenceName) == 0);
- if (keyword != null)
- {
- keyword.AppendPropertyBlockStrings(sb);
- keywordInputs.Remove(keyword);
- }
- }
- else if (!input.isKeyword)
- {
- var property = propertyInputs.FirstOrDefault(x => x.referenceName.CompareTo(input.referenceName) == 0);
- if (property != null)
- {
- property.AppendPropertyBlockStrings(sb);
- propertyInputs.Remove(property);
- }
- }
- }
-
- foreach (var property in propertyInputs)
- {
- property.AppendPropertyBlockStrings(sb);
- }
-
- if (mode != GenerationMode.Preview)
- {
- foreach (var keyword in keywordInputs)
- {
- keyword.AppendPropertyBlockStrings(sb);
- }
- }
- }
- }
- }
-
- internal static void GenerateSurfaceInputStruct(ShaderStringBuilder sb, ShaderGraphRequirements requirements, string structName)
- {
- sb.AppendLine($"struct {structName}");
- using (sb.BlockSemicolonScope())
- {
- GenerateSpaceTranslationSurfaceInputs(requirements.requiresNormal, InterpolatorType.Normal, sb);
- GenerateSpaceTranslationSurfaceInputs(requirements.requiresTangent, InterpolatorType.Tangent, sb);
- GenerateSpaceTranslationSurfaceInputs(requirements.requiresBitangent, InterpolatorType.BiTangent, sb);
- GenerateSpaceTranslationSurfaceInputs(requirements.requiresViewDir, InterpolatorType.ViewDirection, sb);
- GenerateSpaceTranslationSurfaceInputs(requirements.requiresPosition, InterpolatorType.Position, sb);
- GenerateSpaceTranslationSurfaceInputs(requirements.requiresPositionPredisplacement, InterpolatorType.PositionPredisplacement, sb);
-
- if (requirements.requiresVertexColor)
- sb.AppendLine("float4 {0};", ShaderGeneratorNames.VertexColor);
-
- if (requirements.requiresScreenPosition)
- sb.AppendLine("float4 {0};", ShaderGeneratorNames.ScreenPosition);
-
- if (requirements.requiresNDCPosition)
- sb.AppendLine("float2 {0};", ShaderGeneratorNames.NDCPosition);
-
- if (requirements.requiresPixelPosition)
- sb.AppendLine("float2 {0};", ShaderGeneratorNames.PixelPosition);
-
- if (requirements.requiresFaceSign)
- sb.AppendLine("float {0};", ShaderGeneratorNames.FaceSign);
-
- foreach (var channel in requirements.requiresMeshUVs.Distinct())
- sb.AppendLine("half4 {0};", channel.GetUVName());
-
- if (requirements.requiresTime)
- {
- sb.AppendLine("float3 {0};", ShaderGeneratorNames.TimeParameters);
- }
-
- if (requirements.requiresVertexSkinning)
- {
- sb.AppendLine("uint4 {0};", ShaderGeneratorNames.BoneIndices);
- sb.AppendLine("float4 {0};", ShaderGeneratorNames.BoneWeights);
- }
-
- if (requirements.requiresVertexID)
- {
- sb.AppendLine("uint {0};", ShaderGeneratorNames.VertexID);
- }
-
- if (requirements.requiresInstanceID)
- {
- sb.AppendLine("uint {0};", ShaderGeneratorNames.InstanceID);
- }
- }
- }
-
- internal static void GenerateSurfaceInputTransferCode(ShaderStringBuilder sb, ShaderGraphRequirements requirements, string structName, string variableName)
- {
- sb.AppendLine($"{structName} {variableName};");
-
- GenerateSpaceTranslationSurfaceInputs(requirements.requiresNormal, InterpolatorType.Normal, sb, $"{variableName}.{{0}} = IN.{{0}};");
- GenerateSpaceTranslationSurfaceInputs(requirements.requiresTangent, InterpolatorType.Tangent, sb, $"{variableName}.{{0}} = IN.{{0}};");
- GenerateSpaceTranslationSurfaceInputs(requirements.requiresBitangent, InterpolatorType.BiTangent, sb, $"{variableName}.{{0}} = IN.{{0}};");
- GenerateSpaceTranslationSurfaceInputs(requirements.requiresViewDir, InterpolatorType.ViewDirection, sb, $"{variableName}.{{0}} = IN.{{0}};");
- GenerateSpaceTranslationSurfaceInputs(requirements.requiresPosition, InterpolatorType.Position, sb, $"{variableName}.{{0}} = IN.{{0}};");
- GenerateSpaceTranslationSurfaceInputs(requirements.requiresPositionPredisplacement, InterpolatorType.PositionPredisplacement, sb, $"{variableName}.{{0}} = IN.{{0}};");
-
- if (requirements.requiresVertexColor)
- sb.AppendLine($"{variableName}.{ShaderGeneratorNames.VertexColor} = IN.{ShaderGeneratorNames.VertexColor};");
-
- if (requirements.requiresScreenPosition)
- sb.AppendLine($"{variableName}.{ShaderGeneratorNames.ScreenPosition} = IN.{ShaderGeneratorNames.ScreenPosition};");
-
- if (requirements.requiresNDCPosition)
- sb.AppendLine($"{variableName}.{ShaderGeneratorNames.NDCPosition} = IN.{ShaderGeneratorNames.NDCPosition};");
-
- if (requirements.requiresPixelPosition)
- sb.AppendLine($"{variableName}.{ShaderGeneratorNames.PixelPosition} = IN.{ShaderGeneratorNames.PixelPosition};");
-
- if (requirements.requiresFaceSign)
- sb.AppendLine($"{variableName}.{ShaderGeneratorNames.FaceSign} = IN.{ShaderGeneratorNames.FaceSign};");
-
- foreach (var channel in requirements.requiresMeshUVs.Distinct())
- sb.AppendLine($"{variableName}.{channel.GetUVName()} = IN.{channel.GetUVName()};");
-
- if (requirements.requiresTime)
- {
- sb.AppendLine($"{variableName}.{ShaderGeneratorNames.TimeParameters} = IN.{ShaderGeneratorNames.TimeParameters};");
- }
-
- if (requirements.requiresVertexSkinning)
- {
- sb.AppendLine($"{variableName}.{ShaderGeneratorNames.BoneIndices} = IN.{ShaderGeneratorNames.BoneIndices};");
- sb.AppendLine($"{variableName}.{ShaderGeneratorNames.BoneWeights} = IN.{ShaderGeneratorNames.BoneWeights};");
- }
-
- if (requirements.requiresVertexID)
- {
- sb.AppendLine($"{variableName}.{ShaderGeneratorNames.VertexID} = IN.{ShaderGeneratorNames.VertexID};");
- }
-
- if (requirements.requiresInstanceID)
- {
- sb.AppendLine($"{variableName}.{ShaderGeneratorNames.InstanceID} = IN.{ShaderGeneratorNames.InstanceID};");
- }
- }
-
- internal static void GenerateSurfaceDescriptionStruct(ShaderStringBuilder surfaceDescriptionStruct, List<MaterialSlot> slots, string structName = "SurfaceDescription", IActiveFieldsSet activeFields = null, bool isSubgraphOutput = false, bool virtualTextureFeedback = false)
- {
- surfaceDescriptionStruct.AppendLine("struct {0}", structName);
- using (surfaceDescriptionStruct.BlockSemicolonScope())
- {
- if (slots != null)
- {
- if (isSubgraphOutput)
- {
- var firstSlot = slots.FirstOrDefault();
- if (firstSlot != null)
- {
- var hlslName = $"{NodeUtils.GetHLSLSafeName(firstSlot.shaderOutputName)}_{firstSlot.id}";
- surfaceDescriptionStruct.AppendLine("{0} {1};", firstSlot.concreteValueType.ToShaderString(firstSlot.owner.concretePrecision), hlslName);
- surfaceDescriptionStruct.AppendLine("{0} {1};", ConcreteSlotValueType.Vector4.ToShaderString(firstSlot.owner.concretePrecision), "Out");
- }
- else
- surfaceDescriptionStruct.AppendLine("{0} {1};", ConcreteSlotValueType.Vector4.ToShaderString(ConcretePrecision.Single), "Out");
- }
- else
- {
- foreach (var slot in slots)
- {
- string hlslName = NodeUtils.GetHLSLSafeName(slot.shaderOutputName);
-
- surfaceDescriptionStruct.AppendLine("{0} {1};", slot.concreteValueType.ToShaderString(slot.owner.concretePrecision), hlslName);
-
- if (activeFields != null)
- {
- var structField = new FieldDescriptor(structName, hlslName, "");
- activeFields.AddAll(structField);
- }
- }
- }
- }
-
- // TODO: move this into the regular FieldDescriptor system with a conditional, doesn't belong as a special case here
- if (virtualTextureFeedback)
- {
- surfaceDescriptionStruct.AppendLine("{0} {1};", ConcreteSlotValueType.Vector4.ToShaderString(ConcretePrecision.Single), "VTPackedFeedback");
-
- if (!isSubgraphOutput && activeFields != null)
- {
- var structField = new FieldDescriptor(structName, "VTPackedFeedback", "");
- activeFields.AddAll(structField);
- }
- }
- }
- }
-
- internal static void GenerateSurfaceDescriptionFunction(
- List<AbstractMaterialNode> nodes,
- List<int>[] keywordPermutationsPerNode,
- AbstractMaterialNode rootNode,
- GraphData graph,
- ShaderStringBuilder surfaceDescriptionFunction,
- FunctionRegistry functionRegistry,
- PropertyCollector shaderProperties,
- KeywordCollector shaderKeywords,
- GenerationMode mode,
- string functionName = "PopulateSurfaceData",
- string surfaceDescriptionName = "SurfaceDescription",
- Vector1ShaderProperty outputIdProperty = null,
- IEnumerable<MaterialSlot> slots = null,
- string graphInputStructName = "SurfaceDescriptionInputs",
- bool virtualTextureFeedback = false)
- {
- if (graph == null)
- return;
-
- graph.CollectShaderProperties(shaderProperties, mode);
-
- if (mode == GenerationMode.VFX)
- {
- const string k_GraphProperties = "GraphProperties";
- surfaceDescriptionFunction.AppendLine(String.Format("{0} {1}(SurfaceDescriptionInputs IN, {2} PROP)", surfaceDescriptionName, functionName, k_GraphProperties), false);
- }
- else
- surfaceDescriptionFunction.AppendLine(String.Format("{0} {1}(SurfaceDescriptionInputs IN)", surfaceDescriptionName, functionName), false);
-
- using (surfaceDescriptionFunction.BlockScope())
- {
- surfaceDescriptionFunction.AppendLine("{0} surface = ({0})0;", surfaceDescriptionName);
- for (int i = 0; i < nodes.Count; i++)
- {
- GenerateDescriptionForNode(nodes[i], keywordPermutationsPerNode[i], functionRegistry, surfaceDescriptionFunction,
- shaderProperties, shaderKeywords,
- graph, mode);
- }
-
- functionRegistry.builder.currentNode = null;
- surfaceDescriptionFunction.currentNode = null;
-
- GenerateSurfaceDescriptionRemap(graph, rootNode, slots,
- surfaceDescriptionFunction, mode);
-
- if (virtualTextureFeedback)
- {
- VirtualTexturingFeedbackUtils.GenerateVirtualTextureFeedback(
- nodes,
- keywordPermutationsPerNode,
- surfaceDescriptionFunction,
- shaderKeywords);
- }
-
- surfaceDescriptionFunction.AppendLine("return surface;");
- }
- }
-
- static void GenerateDescriptionForNode(
- AbstractMaterialNode activeNode,
- List<int> keywordPermutations,
- FunctionRegistry functionRegistry,
- ShaderStringBuilder descriptionFunction,
- PropertyCollector shaderProperties,
- KeywordCollector shaderKeywords,
- GraphData graph,
- GenerationMode mode)
- {
- if (activeNode is IGeneratesFunction functionNode)
- {
- functionRegistry.builder.currentNode = activeNode;
- Profiler.BeginSample("GenerateNodeFunction");
- functionNode.GenerateNodeFunction(functionRegistry, mode);
- Profiler.EndSample();
- }
-
- if (activeNode is IGeneratesBodyCode bodyNode)
- {
- if (keywordPermutations != null)
- descriptionFunction.AppendLine(KeywordUtil.GetKeywordPermutationSetConditional(keywordPermutations));
-
- descriptionFunction.currentNode = activeNode;
- Profiler.BeginSample("GenerateNodeCode");
- bodyNode.GenerateNodeCode(descriptionFunction, mode);
- Profiler.EndSample();
- descriptionFunction.ReplaceInCurrentMapping(PrecisionUtil.Token, activeNode.concretePrecision.ToShaderString());
-
- if (keywordPermutations != null)
- descriptionFunction.AppendLine("#endif");
- }
-
- activeNode.CollectShaderProperties(shaderProperties, mode);
-
- if (activeNode is SubGraphNode subGraphNode)
- {
- subGraphNode.CollectShaderKeywords(shaderKeywords, mode);
- }
- }
-
- static void GenerateSurfaceDescriptionRemap(
- GraphData graph,
- AbstractMaterialNode rootNode,
- IEnumerable<MaterialSlot> slots,
- ShaderStringBuilder surfaceDescriptionFunction,
- GenerationMode mode)
- {
- if (rootNode == null)
- {
- foreach (var input in slots)
- {
- if (input != null)
- {
- var node = input.owner;
- var foundEdges = graph.GetEdges(input.slotReference).ToArray();
- var hlslName = NodeUtils.GetHLSLSafeName(input.shaderOutputName);
- if (foundEdges.Any())
- surfaceDescriptionFunction.AppendLine($"surface.{hlslName} = {node.GetSlotValue(input.id, mode, node.concretePrecision)};");
- else
- surfaceDescriptionFunction.AppendLine($"surface.{hlslName} = {input.GetDefaultValue(mode, node.concretePrecision)};");
- }
- }
- }
- else if (rootNode is SubGraphOutputNode)
- {
- var slot = slots.FirstOrDefault();
- if (slot != null)
- {
- var foundEdges = graph.GetEdges(slot.slotReference).ToArray();
- var hlslName = $"{NodeUtils.GetHLSLSafeName(slot.shaderOutputName)}_{slot.id}";
- if (foundEdges.Any())
- surfaceDescriptionFunction.AppendLine($"surface.{hlslName} = {rootNode.GetSlotValue(slot.id, mode, rootNode.concretePrecision)};");
- else
- surfaceDescriptionFunction.AppendLine($"surface.{hlslName} = {slot.GetDefaultValue(mode, rootNode.concretePrecision)};");
- surfaceDescriptionFunction.AppendLine($"surface.Out = all(isfinite(surface.{hlslName})) ? {GenerationUtils.AdaptNodeOutputForPreview(rootNode, slot.id, "surface." + hlslName)} : float4(1.0f, 0.0f, 1.0f, 1.0f);");
- }
- }
- else
- {
- var slot = rootNode.GetOutputSlots<MaterialSlot>().FirstOrDefault();
- if (slot != null)
- {
- string slotValue;
- string previewOutput;
- if (rootNode.isActive)
- {
- slotValue = rootNode.GetSlotValue(slot.id, mode, rootNode.concretePrecision);
- previewOutput = GenerationUtils.AdaptNodeOutputForPreview(rootNode, slot.id);
- }
- else
- {
- slotValue = rootNode.GetSlotValue(slot.id, mode, rootNode.concretePrecision);
- previewOutput = "float4(0.0f, 0.0f, 0.0f, 0.0f)";
- }
- surfaceDescriptionFunction.AppendLine($"surface.Out = all(isfinite({slotValue})) ? {previewOutput} : float4(1.0f, 0.0f, 1.0f, 1.0f);");
- }
- }
- }
-
- const string k_VertexDescriptionStructName = "VertexDescription";
- internal static void GenerateVertexDescriptionStruct(ShaderStringBuilder builder, List<MaterialSlot> slots, string structName = k_VertexDescriptionStructName, IActiveFieldsSet activeFields = null)
- {
- builder.AppendLine("struct {0}", structName);
- using (builder.BlockSemicolonScope())
- {
- foreach (var slot in slots)
- {
- string hlslName = NodeUtils.ConvertToValidHLSLIdentifier(slot.shaderOutputName);
- builder.AppendLine("{0} {1};", slot.concreteValueType.ToShaderString(slot.owner.concretePrecision), hlslName);
-
- if (activeFields != null)
- {
- var structField = new FieldDescriptor(structName, hlslName, "");
- activeFields.AddAll(structField);
- }
- }
- }
- }
-
- internal static void GenerateVertexDescriptionFunction(
- GraphData graph,
- ShaderStringBuilder builder,
- FunctionRegistry functionRegistry,
- PropertyCollector shaderProperties,
- KeywordCollector shaderKeywords,
- GenerationMode mode,
- AbstractMaterialNode rootNode,
- List<AbstractMaterialNode> nodes,
- List<int>[] keywordPermutationsPerNode,
- List<MaterialSlot> slots,
- string graphInputStructName = "VertexDescriptionInputs",
- string functionName = "PopulateVertexData",
- string graphOutputStructName = k_VertexDescriptionStructName)
- {
- if (graph == null)
- return;
-
- graph.CollectShaderProperties(shaderProperties, mode);
-
- if (mode == GenerationMode.VFX)
- {
- const string k_GraphProperties = "GraphProperties";
- builder.AppendLine("{0} {1}({2} IN, {3} PROP)", graphOutputStructName, functionName, graphInputStructName, k_GraphProperties);
- }
- else
- builder.AppendLine("{0} {1}({2} IN)", graphOutputStructName, functionName, graphInputStructName);
-
- using (builder.BlockScope())
- {
- builder.AppendLine("{0} description = ({0})0;", graphOutputStructName);
- Profiler.BeginSample("GenerateNodeDescriptions");
- for (int i = 0; i < nodes.Count; i++)
- {
- GenerateDescriptionForNode(nodes[i], keywordPermutationsPerNode[i], functionRegistry, builder,
- shaderProperties, shaderKeywords,
- graph, mode);
- }
- Profiler.EndSample();
-
- functionRegistry.builder.currentNode = null;
- builder.currentNode = null;
-
- if (slots.Count != 0)
- {
- foreach (var slot in slots)
- {
- var isSlotConnected = graph.GetEdges(slot.slotReference).Any();
- var slotName = NodeUtils.ConvertToValidHLSLIdentifier(slot.shaderOutputName);
- var slotValue = isSlotConnected ?
- ((AbstractMaterialNode)slot.owner).GetSlotValue(slot.id, mode, slot.owner.concretePrecision) : slot.GetDefaultValue(mode, slot.owner.concretePrecision);
- builder.AppendLine("description.{0} = {1};", slotName, slotValue);
- }
- }
-
- builder.AppendLine("return description;");
- }
- }
-
- internal static string GetSpliceCommand(string command, string token)
- {
- return !string.IsNullOrEmpty(command) ? command : $"// {token}: <None>";
- }
-
- internal static string GetDefaultTemplatePath(string templateName)
- {
- var basePath = "Packages/com.unity.shadergraph/Editor/Generation/Templates/";
- string templatePath = Path.Combine(basePath, templateName);
-
- if (File.Exists(templatePath))
- return templatePath;
-
- throw new FileNotFoundException(string.Format(@"Cannot find a template with name ""{0}"".", templateName));
- }
-
- internal static string[] defaultDefaultSharedTemplateDirectories = new string[]
- {
- "Packages/com.unity.shadergraph/Editor/Generation/Templates"
- };
-
- internal static string[] GetDefaultSharedTemplateDirectories()
- {
- return defaultDefaultSharedTemplateDirectories;
- }
-
- // Returns null if no 'CustomEditor "___"' line should be added, otherwise the name of the ShaderGUI class.
- // 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.
- public static string FinalCustomEditorString(ICanChangeShaderGUI canChangeShaderGUI)
- {
- string finalOverrideName = canChangeShaderGUI.ShaderGUIOverride;
- if (string.IsNullOrEmpty(finalOverrideName))
- return null;
-
- // Do not add to the final shader if the base ShaderGUI is wanted, as errors will occur.
- if (finalOverrideName.Equals("BaseShaderGUI") || finalOverrideName.Equals("UnityEditor.BaseShaderGUI"))
- return null;
-
- return finalOverrideName;
- }
- }
- }
|