Esempio n. 1
0
        static void ProcessSubGraph(SubGraphAsset asset, GraphData graph, ShaderGraphImporter.AssetImportErrorLog importLog)
        {
            var graphIncludes = new IncludeCollection();
            var registry      = new FunctionRegistry(new ShaderStringBuilder(), graphIncludes, true);

            asset.functions.Clear();
            asset.isValid = true;

            graph.OnEnable();
            graph.messageManager.ClearAll();
            graph.ValidateGraph();

            var assetPath = AssetDatabase.GUIDToAssetPath(asset.assetGuid);

            asset.hlslName        = NodeUtils.GetHLSLSafeName(Path.GetFileNameWithoutExtension(assetPath));
            asset.inputStructName = $"Bindings_{asset.hlslName}_{asset.assetGuid}_$precision";
            asset.functionName    = $"SG_{asset.hlslName}_{asset.assetGuid}_$precision";
            asset.path            = graph.path;

            var outputNode = graph.outputNode;

            var outputSlots = PooledList <MaterialSlot> .Get();

            outputNode.GetInputSlots(outputSlots);

            List <AbstractMaterialNode> nodes = new List <AbstractMaterialNode>();

            NodeUtils.DepthFirstCollectNodesFromNode(nodes, outputNode);

            // flag the used nodes so we can filter out errors from unused nodes
            foreach (var node in nodes)
            {
                node.SetUsedByGenerator();
            }

            // Start with a clean slate for the input/output capabilities and dependencies
            asset.inputCapabilities.Clear();
            asset.outputCapabilities.Clear();
            asset.slotDependencies.Clear();

            ShaderStageCapability effectiveShaderStage = ShaderStageCapability.All;

            foreach (var slot in outputSlots)
            {
                var stage = NodeUtils.GetEffectiveShaderStageCapability(slot, true);
                if (effectiveShaderStage == ShaderStageCapability.All && stage != ShaderStageCapability.All)
                {
                    effectiveShaderStage = stage;
                }

                asset.outputCapabilities.Add(new SlotCapability {
                    slotName = slot.RawDisplayName(), capabilities = stage
                });

                // Find all unique property nodes used by this slot and record a dependency for this input/output pair
                var inputPropertyNames = new HashSet <string>();
                var nodeSet            = new HashSet <AbstractMaterialNode>();
                NodeUtils.CollectNodeSet(nodeSet, slot);
                foreach (var node in nodeSet)
                {
                    if (node is PropertyNode propNode && !inputPropertyNames.Contains(propNode.property.displayName))
                    {
                        inputPropertyNames.Add(propNode.property.displayName);
                        var slotDependency = new SlotDependencyPair();
                        slotDependency.inputSlotName  = propNode.property.displayName;
                        slotDependency.outputSlotName = slot.RawDisplayName();
                        asset.slotDependencies.Add(slotDependency);
                    }
                }
            }
            CollectInputCapabilities(asset, graph);

            asset.vtFeedbackVariables = VirtualTexturingFeedbackUtils.GetFeedbackVariables(outputNode as SubGraphOutputNode);
            asset.requirements        = ShaderGraphRequirements.FromNodes(nodes, effectiveShaderStage, false);

            // output precision is whatever the output node has as a graph precision, falling back to the graph default
            asset.outputGraphPrecision = outputNode.graphPrecision.GraphFallback(graph.graphDefaultPrecision);

            // this saves the graph precision, which indicates whether this subgraph is switchable or not
            asset.subGraphGraphPrecision = graph.graphDefaultPrecision;

            asset.previewMode = graph.previewMode;

            asset.includes = graphIncludes;

            GatherDescendentsFromGraph(new GUID(asset.assetGuid), out var containsCircularDependency, out var descendents);
            asset.descendents.AddRange(descendents.Select(g => g.ToString()));
            asset.descendents.Sort();   // ensure deterministic order

            var childrenSet = new HashSet <string>();
            var anyErrors   = false;

            foreach (var node in nodes)
            {
                if (node is SubGraphNode subGraphNode)
                {
                    var subGraphGuid = subGraphNode.subGraphGuid;
                    childrenSet.Add(subGraphGuid);
                }

                if (node.hasError)
                {
                    anyErrors = true;
                }
                asset.children = childrenSet.ToList();
                asset.children.Sort(); // ensure deterministic order
            }

            if (!anyErrors && containsCircularDependency)
            {
                importLog.LogError($"Error in Graph at {assetPath}: Sub Graph contains a circular dependency.", asset);
                anyErrors = true;
            }

            if (anyErrors)
            {
                asset.isValid = false;
                registry.ProvideFunction(asset.functionName, sb => { });
                return;
            }

            foreach (var node in nodes)
            {
                if (node is IGeneratesFunction generatesFunction)
                {
                    registry.builder.currentNode = node;
                    generatesFunction.GenerateNodeFunction(registry, GenerationMode.ForReals);
                }
            }

            // Need to order the properties so that they are in the same order on a subgraph node in a shadergraph
            // as they are in the blackboard for the subgraph itself.  The (blackboard) categories keep that ordering,
            // so traverse those and add those items to the ordered properties list.  Needs to be used to set up the
            // function _and_ to write out the final asset data so that the function call parameter order matches as well.
            var orderedProperties = new List <AbstractShaderProperty>();
            var propertiesList    = graph.properties.ToList();

            foreach (var category in graph.categories)
            {
                foreach (var child in category.Children)
                {
                    var prop = propertiesList.Find(p => p.guid == child.guid);
                    // Not all properties in the category are actually on the graph.
                    // In particular, it seems as if keywords are not properties on sub-graphs.
                    if (prop != null)
                    {
                        orderedProperties.Add(prop);
                    }
                }
            }

            // If we are importing an older file that has not had categories generated for it yet, include those now.
            orderedProperties.AddRange(graph.properties.Except(orderedProperties));

            // provide top level subgraph function
            // NOTE: actual concrete precision here shouldn't matter, it's irrelevant when building the subgraph asset
            registry.ProvideFunction(asset.functionName, asset.subGraphGraphPrecision, ConcretePrecision.Single, sb =>
            {
                GenerationUtils.GenerateSurfaceInputStruct(sb, asset.requirements, asset.inputStructName);
                sb.AppendNewLine();

                // Generate the arguments... first INPUTS
                var arguments = new List <string>();
                foreach (var prop in orderedProperties)
                {
                    // apply fallback to the graph default precision (but don't convert to concrete)
                    // this means "graph switchable" properties will use the precision token
                    GraphPrecision propGraphPrecision = prop.precision.ToGraphPrecision(graph.graphDefaultPrecision);
                    string precisionString            = propGraphPrecision.ToGenericString();
                    arguments.Add(prop.GetPropertyAsArgumentString(precisionString));
                    if (prop.isConnectionTestable)
                    {
                        arguments.Add($"bool {prop.GetConnectionStateHLSLVariableName()}");
                    }
                }

                {
                    var dropdowns = graph.dropdowns;
                    foreach (var dropdown in dropdowns)
                    {
                        arguments.Add($"int {dropdown.referenceName}");
                    }
                }

                // now pass surface inputs
                arguments.Add(string.Format("{0} IN", asset.inputStructName));

                // Now generate output arguments
                foreach (MaterialSlot output in outputSlots)
                {
                    arguments.Add($"out {output.concreteValueType.ToShaderString(asset.outputGraphPrecision.ToGenericString())} {output.shaderOutputName}_{output.id}");
                }

                // Vt Feedback output arguments (always full float4)
                foreach (var output in asset.vtFeedbackVariables)
                {
                    arguments.Add($"out {ConcreteSlotValueType.Vector4.ToShaderString(ConcretePrecision.Single)} {output}_out");
                }

                // Create the function prototype from the arguments
                sb.AppendLine("void {0}({1})"
                              , asset.functionName
                              , arguments.Aggregate((current, next) => $"{current}, {next}"));

                // now generate the function
                using (sb.BlockScope())
                {
                    // Just grab the body from the active nodes
                    foreach (var node in nodes)
                    {
                        if (node is IGeneratesBodyCode generatesBodyCode)
                        {
                            sb.currentNode = node;
                            generatesBodyCode.GenerateNodeCode(sb, GenerationMode.ForReals);

                            if (node.graphPrecision == GraphPrecision.Graph)
                            {
                                // code generated by nodes that use graph precision stays in generic form with embedded tokens
                                // those tokens are replaced when this subgraph function is pulled into a graph that defines the precision
                            }
                            else
                            {
                                sb.ReplaceInCurrentMapping(PrecisionUtil.Token, node.concretePrecision.ToShaderString());
                            }
                        }
                    }

                    foreach (var slot in outputSlots)
                    {
                        sb.AppendLine($"{slot.shaderOutputName}_{slot.id} = {outputNode.GetSlotValue(slot.id, GenerationMode.ForReals)};");
                    }

                    foreach (var slot in asset.vtFeedbackVariables)
                    {
                        sb.AppendLine($"{slot}_out = {slot};");
                    }
                }
            });

            // save all of the node-declared functions to the subgraph asset
            foreach (var name in registry.names)
            {
                var source = registry.sources[name];
                var func   = new FunctionPair(name, source.code, source.graphPrecisionFlags);
                asset.functions.Add(func);
            }

            var collector = new PropertyCollector();

            foreach (var node in nodes)
            {
                int previousPropertyCount = Math.Max(0, collector.propertyCount - 1);

                node.CollectShaderProperties(collector, GenerationMode.ForReals);

                // This is a stop-gap to prevent the autogenerated values from JsonObject and ShaderInput from
                // resulting in non-deterministic import data. While we should move to local ids in the future,
                // this will prevent cascading shader recompilations.
                for (int i = previousPropertyCount; i < collector.propertyCount; ++i)
                {
                    var prop        = collector.GetProperty(i);
                    var namespaceId = node.objectId;
                    var nameId      = prop.referenceName;

                    prop.OverrideObjectId(namespaceId, nameId + "_ObjectId_" + i);
                    prop.OverrideGuid(namespaceId, nameId + "_Guid_" + i);
                }
            }

            asset.WriteData(orderedProperties, graph.keywords, graph.dropdowns, collector.properties, outputSlots, graph.unsupportedTargets);
            outputSlots.Dispose();
        }
Esempio n. 2
0
 public bool RequiresMeshUV(UVChannel channel, ShaderStageCapability stageCapability)
 {
     return(true);
 }
Esempio n. 3
0
 public NeededCoordinateSpace RequiresNormal(ShaderStageCapability stageCapability)
 {
     return(CoordinateSpace.World.ToNeededCoordinateSpace());
 }
Esempio n. 4
0
 protected MaterialSlot(int slotId, string displayName, string shaderOutputName, SlotType slotType, int priority, ShaderStageCapability stageCapability = ShaderStageCapability.All, bool hidden = false)
 {
     m_Id                 = slotId;
     m_DisplayName        = displayName;
     m_SlotType           = slotType;
     m_Priority           = priority;
     m_Hidden             = hidden;
     m_ShaderOutputName   = shaderOutputName;
     this.stageCapability = stageCapability;
 }
Esempio n. 5
0
 protected SpaceMaterialSlot(int slotId, string displayName, string shaderOutputName, CoordinateSpace space,
                             ShaderStageCapability stageCapability = ShaderStageCapability.All, bool hidden = false)
     : base(slotId, displayName, shaderOutputName, SlotType.Input, Vector3.zero, stageCapability, hidden: hidden)
 {
     this.space = space;
 }
 public NeededCoordinateSpace RequiresPosition(ShaderStageCapability stageCapability = ShaderStageCapability.Vertex)
 {
     return(NeededCoordinateSpace.World);
 }
Esempio n. 7
0
 public bool RequiresScreenPosition(ShaderStageCapability stageCapability)
 {
     return(true);
 }
        // TODO: Fix this - VFX Graph can now use ShaderGraph as a code generation path. However, currently, the new
        // generation path still slightly depends on this container (The implementation of it was tightly coupled in VFXShaderGraphParticleOutput,
        // and we keep it now as there is no migration path for users yet). This will need to be decoupled so that we can eventually
        // remove this container.
        static ShaderGraphVfxAsset GenerateVfxShaderGraphAsset(GraphData graph)
        {
            var target = graph.activeTargets.FirstOrDefault(x => x.SupportsVFX());

            if (target == null)
            {
                return(null);
            }

            var nl     = Environment.NewLine;
            var indent = new string(' ', 4);
            var asset  = ScriptableObject.CreateInstance <ShaderGraphVfxAsset>();
            var result = asset.compilationResult = new GraphCompilationResult();
            var mode   = GenerationMode.ForReals;

            if (target is VFXTarget vfxTarget)
            {
                asset.lit                      = vfxTarget.lit;
                asset.alphaClipping            = vfxTarget.alphaTest;
                asset.generatesWithShaderGraph = false;
            }
            else
            {
                asset.lit                      = true;
                asset.alphaClipping            = false;
                asset.generatesWithShaderGraph = true;
            }

            var assetGuid = graph.assetGuid;
            var assetPath = AssetDatabase.GUIDToAssetPath(assetGuid);
            var hlslName  = NodeUtils.GetHLSLSafeName(Path.GetFileNameWithoutExtension(assetPath));

            var ports = new List <MaterialSlot>();
            var nodes = new List <AbstractMaterialNode>();

            foreach (var vertexBlock in graph.vertexContext.blocks)
            {
                vertexBlock.value.GetInputSlots(ports);
                NodeUtils.DepthFirstCollectNodesFromNode(nodes, vertexBlock);
            }

            foreach (var fragmentBlock in graph.fragmentContext.blocks)
            {
                fragmentBlock.value.GetInputSlots(ports);
                NodeUtils.DepthFirstCollectNodesFromNode(nodes, fragmentBlock);
            }

            //Remove inactive blocks from legacy generation
            if (!asset.generatesWithShaderGraph)
            {
                var tmpCtx = new TargetActiveBlockContext(new List <BlockFieldDescriptor>(), null);

                // NOTE: For whatever reason, this call fails for custom interpolator ports (ie, active ones are not detected as active).
                // For the sake of compatibility with custom interpolator with shadergraph generation, skip the removal of inactive blocks.
                target.GetActiveBlocks(ref tmpCtx);

                ports.RemoveAll(materialSlot =>
                {
                    return(!tmpCtx.activeBlocks.Any(o => materialSlot.RawDisplayName() == o.displayName));
                });
            }

            var bodySb        = new ShaderStringBuilder(1);
            var graphIncludes = new IncludeCollection();
            var registry      = new FunctionRegistry(new ShaderStringBuilder(), graphIncludes, true);

            foreach (var properties in graph.properties)
            {
                properties.SetupConcretePrecision(graph.graphDefaultConcretePrecision);
            }

            foreach (var node in nodes)
            {
                if (node is IGeneratesBodyCode bodyGenerator)
                {
                    bodySb.currentNode = node;
                    bodyGenerator.GenerateNodeCode(bodySb, mode);
                    bodySb.ReplaceInCurrentMapping(PrecisionUtil.Token, node.concretePrecision.ToShaderString());
                }

                if (node is IGeneratesFunction generatesFunction)
                {
                    registry.builder.currentNode = node;
                    generatesFunction.GenerateNodeFunction(registry, mode);
                }
            }
            bodySb.currentNode = null;

            var portNodeSets = new HashSet <AbstractMaterialNode> [ports.Count];

            for (var portIndex = 0; portIndex < ports.Count; portIndex++)
            {
                var port    = ports[portIndex];
                var nodeSet = new HashSet <AbstractMaterialNode>();
                NodeUtils.CollectNodeSet(nodeSet, port);
                portNodeSets[portIndex] = nodeSet;
            }

            var portPropertySets = new HashSet <string> [ports.Count];

            for (var portIndex = 0; portIndex < ports.Count; portIndex++)
            {
                portPropertySets[portIndex] = new HashSet <string>();
            }

            foreach (var node in nodes)
            {
                if (!(node is PropertyNode propertyNode))
                {
                    continue;
                }

                for (var portIndex = 0; portIndex < ports.Count; portIndex++)
                {
                    var portNodeSet = portNodeSets[portIndex];
                    if (portNodeSet.Contains(node))
                    {
                        portPropertySets[portIndex].Add(propertyNode.property.objectId);
                    }
                }
            }

            var shaderProperties = new PropertyCollector();

            foreach (var node in nodes)
            {
                node.CollectShaderProperties(shaderProperties, GenerationMode.ForReals);
            }

            asset.SetTextureInfos(shaderProperties.GetConfiguredTextures());

            var codeSnippets      = new List <string>();
            var portCodeIndices   = new List <int> [ports.Count];
            var sharedCodeIndices = new List <int>();

            for (var i = 0; i < portCodeIndices.Length; i++)
            {
                portCodeIndices[i] = new List <int>();
            }

            sharedCodeIndices.Add(codeSnippets.Count);
            codeSnippets.Add($"#include \"Packages/com.unity.shadergraph/ShaderGraphLibrary/Functions.hlsl\"{nl}");

            foreach (var include in graphIncludes)
            {
                sharedCodeIndices.Add(codeSnippets.Count);
                codeSnippets.Add(include.value + nl);
            }

            for (var registryIndex = 0; registryIndex < registry.names.Count; registryIndex++)
            {
                var name      = registry.names[registryIndex];
                var source    = registry.sources[name];
                var precision = source.nodes.First().concretePrecision;

                var hasPrecisionMismatch = false;
                var nodeNames            = new HashSet <string>();
                foreach (var node in source.nodes)
                {
                    nodeNames.Add(node.name);
                    if (node.concretePrecision != precision)
                    {
                        hasPrecisionMismatch = true;
                        break;
                    }
                }

                if (hasPrecisionMismatch)
                {
                    var message = new StringBuilder($"Precision mismatch for function {name}:");
                    foreach (var node in source.nodes)
                    {
                        message.AppendLine($"{node.name} ({node.objectId}): {node.concretePrecision}");
                    }
                    throw new InvalidOperationException(message.ToString());
                }

                var code = source.code.Replace(PrecisionUtil.Token, precision.ToShaderString());
                code = $"// Node: {string.Join(", ", nodeNames)}{nl}{code}";
                var codeIndex = codeSnippets.Count;
                codeSnippets.Add(code + nl);
                for (var portIndex = 0; portIndex < ports.Count; portIndex++)
                {
                    var portNodeSet = portNodeSets[portIndex];
                    foreach (var node in source.nodes)
                    {
                        if (portNodeSet.Contains(node))
                        {
                            portCodeIndices[portIndex].Add(codeIndex);
                            break;
                        }
                    }
                }
            }

            foreach (var property in graph.properties)
            {
                if (property.isExposed)
                {
                    continue;
                }

                for (var portIndex = 0; portIndex < ports.Count; portIndex++)
                {
                    var portPropertySet = portPropertySets[portIndex];
                    if (portPropertySet.Contains(property.objectId))
                    {
                        portCodeIndices[portIndex].Add(codeSnippets.Count);
                    }
                }

                ShaderStringBuilder builder = new ShaderStringBuilder();
                property.ForeachHLSLProperty(h => h.AppendTo(builder));

                codeSnippets.Add($"// Property: {property.displayName}{nl}{builder.ToCodeBlock()}{nl}{nl}");
            }

            foreach (var prop in shaderProperties.properties)
            {
                if (!graph.properties.Contains(prop) && (prop is SamplerStateShaderProperty))
                {
                    sharedCodeIndices.Add(codeSnippets.Count);
                    ShaderStringBuilder builder = new ShaderStringBuilder();
                    prop.ForeachHLSLProperty(h => h.AppendTo(builder));

                    codeSnippets.Add($"// Property: {prop.displayName}{nl}{builder.ToCodeBlock()}{nl}{nl}");
                }
            }

            var inputStructName        = $"SG_Input_{assetGuid}";
            var outputStructName       = $"SG_Output_{assetGuid}";
            var evaluationFunctionName = $"SG_Evaluate_{assetGuid}";

            #region Input Struct

            sharedCodeIndices.Add(codeSnippets.Count);
            codeSnippets.Add($"struct {inputStructName}{nl}{{{nl}");

            #region Requirements

            var portRequirements = new ShaderGraphRequirements[ports.Count];
            for (var portIndex = 0; portIndex < ports.Count; portIndex++)
            {
                var requirementsNodes = portNodeSets[portIndex].ToList();
                requirementsNodes.Add(ports[portIndex].owner);
                portRequirements[portIndex] = ShaderGraphRequirements.FromNodes(requirementsNodes, ports[portIndex].stageCapability);
            }

            var portIndices = new List <int>();
            portIndices.Capacity = ports.Count;

            void AddRequirementsSnippet(Func <ShaderGraphRequirements, bool> predicate, string snippet)
            {
                portIndices.Clear();
                for (var portIndex = 0; portIndex < ports.Count; portIndex++)
                {
                    if (predicate(portRequirements[portIndex]))
                    {
                        portIndices.Add(portIndex);
                    }
                }

                if (portIndices.Count > 0)
                {
                    foreach (var portIndex in portIndices)
                    {
                        portCodeIndices[portIndex].Add(codeSnippets.Count);
                    }

                    codeSnippets.Add($"{indent}{snippet};{nl}");
                }
            }

            void AddCoordinateSpaceSnippets(InterpolatorType interpolatorType, Func <ShaderGraphRequirements, NeededCoordinateSpace> selector)
            {
                foreach (var space in EnumInfo <CoordinateSpace> .values)
                {
                    var neededSpace = space.ToNeededCoordinateSpace();
                    AddRequirementsSnippet(r => (selector(r) & neededSpace) > 0, $"float3 {space.ToVariableName(interpolatorType)}");
                }
            }

            // TODO: Rework requirements system to make this better
            AddCoordinateSpaceSnippets(InterpolatorType.Normal, r => r.requiresNormal);
            AddCoordinateSpaceSnippets(InterpolatorType.Tangent, r => r.requiresTangent);
            AddCoordinateSpaceSnippets(InterpolatorType.BiTangent, r => r.requiresBitangent);
            AddCoordinateSpaceSnippets(InterpolatorType.ViewDirection, r => r.requiresViewDir);
            AddCoordinateSpaceSnippets(InterpolatorType.Position, r => r.requiresPosition);

            AddRequirementsSnippet(r => r.requiresVertexColor, $"float4 {ShaderGeneratorNames.VertexColor}");
            AddRequirementsSnippet(r => r.requiresScreenPosition, $"float4 {ShaderGeneratorNames.ScreenPosition}");
            AddRequirementsSnippet(r => r.requiresFaceSign, $"float4 {ShaderGeneratorNames.FaceSign}");

            foreach (var uvChannel in EnumInfo <UVChannel> .values)
            {
                AddRequirementsSnippet(r => r.requiresMeshUVs.Contains(uvChannel), $"half4 {uvChannel.GetUVName()}");
            }

            AddRequirementsSnippet(r => r.requiresTime, $"float3 {ShaderGeneratorNames.TimeParameters}");

            #endregion

            sharedCodeIndices.Add(codeSnippets.Count);
            codeSnippets.Add($"}};{nl}{nl}");

            #endregion

            // VFX Code heavily relies on the slotId from the original MasterNodes
            // Since we keep these around for upgrades anyway, for now it is simpler to use them
            // Therefore we remap the output blocks back to the original Ids here
            var originialPortIds = new int[ports.Count];
            for (int i = 0; i < originialPortIds.Length; i++)
            {
                if (!VFXTarget.s_BlockMap.TryGetValue((ports[i].owner as BlockNode).descriptor, out var originalId))
                {
                    continue;
                }

                // In Master Nodes we had a different BaseColor/Color slot id between Unlit/Lit
                // In the stack we use BaseColor for both cases. Catch this here.
                if (asset.lit && originalId == ShaderGraphVfxAsset.ColorSlotId)
                {
                    originalId = ShaderGraphVfxAsset.BaseColorSlotId;
                }

                originialPortIds[i] = originalId;
            }

            #region Output Struct

            sharedCodeIndices.Add(codeSnippets.Count);
            codeSnippets.Add($"struct {outputStructName}{nl}{{");

            for (var portIndex = 0; portIndex < ports.Count; portIndex++)
            {
                var port = ports[portIndex];
                portCodeIndices[portIndex].Add(codeSnippets.Count);
                codeSnippets.Add($"{nl}{indent}{port.concreteValueType.ToShaderString(graph.graphDefaultConcretePrecision)} {port.shaderOutputName}_{originialPortIds[portIndex]};");
            }

            sharedCodeIndices.Add(codeSnippets.Count);
            codeSnippets.Add($"{nl}}};{nl}{nl}");

            #endregion

            #region Graph Function

            sharedCodeIndices.Add(codeSnippets.Count);
            codeSnippets.Add($"{outputStructName} {evaluationFunctionName}({nl}{indent}{inputStructName} IN");

            var inputProperties     = new List <AbstractShaderProperty>();
            var portPropertyIndices = new List <int> [ports.Count];
            var propertiesStages    = new List <ShaderStageCapability>();
            for (var portIndex = 0; portIndex < ports.Count; portIndex++)
            {
                portPropertyIndices[portIndex] = new List <int>();
            }

            foreach (var property in graph.properties)
            {
                if (!property.isExposed)
                {
                    continue;
                }

                var propertyIndex = inputProperties.Count;
                var codeIndex     = codeSnippets.Count;

                ShaderStageCapability stageCapability = 0;
                for (var portIndex = 0; portIndex < ports.Count; portIndex++)
                {
                    var portPropertySet = portPropertySets[portIndex];
                    if (portPropertySet.Contains(property.objectId))
                    {
                        portCodeIndices[portIndex].Add(codeIndex);
                        portPropertyIndices[portIndex].Add(propertyIndex);
                        stageCapability |= ports[portIndex].stageCapability;
                    }
                }

                propertiesStages.Add(stageCapability);
                inputProperties.Add(property);
                codeSnippets.Add($",{nl}{indent}/* Property: {property.displayName} */ {property.GetPropertyAsArgumentStringForVFX(property.concretePrecision.ToShaderString())}");
            }

            sharedCodeIndices.Add(codeSnippets.Count);
            codeSnippets.Add($"){nl}{{");

            #region Node Code

            for (var mappingIndex = 0; mappingIndex < bodySb.mappings.Count; mappingIndex++)
            {
                var mapping = bodySb.mappings[mappingIndex];
                var code    = bodySb.ToString(mapping.startIndex, mapping.count);
                if (string.IsNullOrWhiteSpace(code))
                {
                    continue;
                }

                code = $"{nl}{indent}// Node: {mapping.node.name}{nl}{code}";
                var codeIndex = codeSnippets.Count;
                codeSnippets.Add(code);
                for (var portIndex = 0; portIndex < ports.Count; portIndex++)
                {
                    var portNodeSet = portNodeSets[portIndex];
                    if (portNodeSet.Contains(mapping.node))
                    {
                        portCodeIndices[portIndex].Add(codeIndex);
                    }
                }
            }

            #endregion

            #region Output Mapping

            sharedCodeIndices.Add(codeSnippets.Count);
            codeSnippets.Add($"{nl}{indent}// VFXMasterNode{nl}{indent}{outputStructName} OUT;{nl}");

            // Output mapping
            for (var portIndex = 0; portIndex < ports.Count; portIndex++)
            {
                var port = ports[portIndex];
                portCodeIndices[portIndex].Add(codeSnippets.Count);
                codeSnippets.Add($"{indent}OUT.{port.shaderOutputName}_{originialPortIds[portIndex]} = {port.owner.GetSlotValue(port.id, GenerationMode.ForReals, graph.graphDefaultConcretePrecision)};{nl}");
            }

            #endregion

            // Function end
            sharedCodeIndices.Add(codeSnippets.Count);
            codeSnippets.Add($"{indent}return OUT;{nl}}}{nl}");

            #endregion

            result.codeSnippets      = codeSnippets.ToArray();
            result.sharedCodeIndices = sharedCodeIndices.ToArray();
            result.outputCodeIndices = new IntArray[ports.Count];
            for (var i = 0; i < ports.Count; i++)
            {
                result.outputCodeIndices[i] = portCodeIndices[i].ToArray();
            }

            var outputMetadatas = new OutputMetadata[ports.Count];
            for (int portIndex = 0; portIndex < outputMetadatas.Length; portIndex++)
            {
                outputMetadatas[portIndex] = new OutputMetadata(portIndex, ports[portIndex].shaderOutputName, originialPortIds[portIndex]);
            }

            asset.SetOutputs(outputMetadatas);

            asset.evaluationFunctionName = evaluationFunctionName;
            asset.inputStructName        = inputStructName;
            asset.outputStructName       = outputStructName;
            asset.portRequirements       = portRequirements;
            asset.m_PropertiesStages     = propertiesStages.ToArray();
            asset.concretePrecision      = graph.graphDefaultConcretePrecision;
            asset.SetProperties(inputProperties);
            asset.outputPropertyIndices = new IntArray[ports.Count];
            for (var portIndex = 0; portIndex < ports.Count; portIndex++)
            {
                asset.outputPropertyIndices[portIndex] = portPropertyIndices[portIndex].ToArray();
            }

            return(asset);
        }
 public bool RequiresVertexColor(ShaderStageCapability stageCapability)
 {
     return(true);
 }
 public DiffusionProfileInputMaterialSlot(int slotId, string displayName, string shaderOutputName,
                                          ShaderStageCapability stageCapability = ShaderStageCapability.All, bool hidden = false)
     : base(slotId, displayName, shaderOutputName, SlotType.Input, 0.0f, stageCapability, hidden: hidden)
 {
 }
 public bool RequiresFaceSign(ShaderStageCapability stageCapability = ShaderStageCapability.Fragment)
 {
     return(true);
 }
Esempio n. 12
0
        public static bool RequiresScreenPosition(this MaterialSlot slot, ShaderStageCapability stageCapability = ShaderStageCapability.All)
        {
            var mayRequireScreenPosition = slot as IMayRequireScreenPosition;

            return(mayRequireScreenPosition != null && mayRequireScreenPosition.RequiresScreenPosition(stageCapability));
        }
        internal static ShaderGraphRequirements FromNodes <T>(List <T> nodes, ShaderStageCapability stageCapability = ShaderStageCapability.All, bool includeIntermediateSpaces = true)
            where T : AbstractMaterialNode
        {
            NeededCoordinateSpace requiresNormal    = nodes.OfType <IMayRequireNormal>().Aggregate(NeededCoordinateSpace.None, (mask, node) => mask | node.RequiresNormal(stageCapability));
            NeededCoordinateSpace requiresBitangent = nodes.OfType <IMayRequireBitangent>().Aggregate(NeededCoordinateSpace.None, (mask, node) => mask | node.RequiresBitangent(stageCapability));
            NeededCoordinateSpace requiresTangent   = nodes.OfType <IMayRequireTangent>().Aggregate(NeededCoordinateSpace.None, (mask, node) => mask | node.RequiresTangent(stageCapability));
            NeededCoordinateSpace requiresViewDir   = nodes.OfType <IMayRequireViewDirection>().Aggregate(NeededCoordinateSpace.None, (mask, node) => mask | node.RequiresViewDirection(stageCapability));
            NeededCoordinateSpace requiresPosition  = nodes.OfType <IMayRequirePosition>().Aggregate(NeededCoordinateSpace.None, (mask, node) => mask | node.RequiresPosition(stageCapability));
            bool requiresScreenPosition             = nodes.OfType <IMayRequireScreenPosition>().Any(x => x.RequiresScreenPosition());
            bool requiresVertexColor         = nodes.OfType <IMayRequireVertexColor>().Any(x => x.RequiresVertexColor());
            bool requiresFaceSign            = nodes.OfType <IMayRequireFaceSign>().Any(x => x.RequiresFaceSign());
            bool requiresDepthTexture        = nodes.OfType <IMayRequireDepthTexture>().Any(x => x.RequiresDepthTexture());
            bool requiresCameraOpaqueTexture = nodes.OfType <IMayRequireCameraOpaqueTexture>().Any(x => x.RequiresCameraOpaqueTexture());
            bool requiresTime           = nodes.Any(x => x.RequiresTime());
            bool requiresVertexSkinning = nodes.OfType <IMayRequireVertexSkinning>().Any(x => x.RequiresVertexSkinning(stageCapability));

            var meshUV = new List <UVChannel>();

            for (int uvIndex = 0; uvIndex < ShaderGeneratorNames.UVCount; ++uvIndex)
            {
                var channel = (UVChannel)uvIndex;
                if (nodes.OfType <IMayRequireMeshUV>().Any(x => x.RequiresMeshUV(channel)))
                {
                    meshUV.Add(channel);
                }
            }

            // if anything needs tangentspace we have make
            // sure to have our othonormal basis!
            if (includeIntermediateSpaces)
            {
                var compoundSpaces = requiresBitangent | requiresNormal | requiresPosition
                                     | requiresTangent | requiresViewDir | requiresPosition
                                     | requiresNormal;

                var needsTangentSpace = (compoundSpaces & NeededCoordinateSpace.Tangent) > 0;
                if (needsTangentSpace)
                {
                    requiresBitangent |= NeededCoordinateSpace.World;
                    requiresNormal    |= NeededCoordinateSpace.World;
                    requiresTangent   |= NeededCoordinateSpace.World;
                }
            }

            var reqs = new ShaderGraphRequirements()
            {
                m_RequiresNormal              = requiresNormal,
                m_RequiresBitangent           = requiresBitangent,
                m_RequiresTangent             = requiresTangent,
                m_RequiresViewDir             = requiresViewDir,
                m_RequiresPosition            = requiresPosition,
                m_RequiresScreenPosition      = requiresScreenPosition,
                m_RequiresVertexColor         = requiresVertexColor,
                m_RequiresFaceSign            = requiresFaceSign,
                m_RequiresMeshUVs             = meshUV,
                m_RequiresDepthTexture        = requiresDepthTexture,
                m_RequiresCameraOpaqueTexture = requiresCameraOpaqueTexture,
                m_RequiresTime           = requiresTime,
                m_RequiresVertexSkinning = requiresVertexSkinning
            };

            return(reqs);
        }
Esempio n. 14
0
 public NeededTransform[] RequiresTransform(ShaderStageCapability stageCapability = ShaderStageCapability.All) => new[] { NeededTransform.ObjectToWorld };
Esempio n. 15
0
        private static MaterialSlot CreateBoundSlot(Binding attributeBinding, int slotId, string displayName, string shaderOutputName, ShaderStageCapability shaderStageCapability, bool hidden)
        {
            switch (attributeBinding)
            {
            case Binding.ObjectSpaceNormal:
                return(new NormalMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Object, shaderStageCapability));

            case Binding.ObjectSpaceTangent:
                return(new TangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Object, shaderStageCapability));

            case Binding.ObjectSpaceBitangent:
                return(new BitangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Object, shaderStageCapability));

            case Binding.ObjectSpacePosition:
                return(new PositionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Object, shaderStageCapability));

            case Binding.ViewSpaceNormal:
                return(new NormalMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.View, shaderStageCapability));

            case Binding.ViewSpaceTangent:
                return(new TangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.View, shaderStageCapability));

            case Binding.ViewSpaceBitangent:
                return(new BitangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.View, shaderStageCapability));

            case Binding.ViewSpacePosition:
                return(new PositionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.View, shaderStageCapability));

            case Binding.WorldSpaceNormal:
                return(new NormalMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.World, shaderStageCapability));

            case Binding.WorldSpaceTangent:
                return(new TangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.World, shaderStageCapability));

            case Binding.WorldSpaceBitangent:
                return(new BitangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.World, shaderStageCapability));

            case Binding.WorldSpacePosition:
                return(new PositionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.World, shaderStageCapability));

            case Binding.TangentSpaceNormal:
                return(new NormalMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Tangent, shaderStageCapability));

            case Binding.TangentSpaceTangent:
                return(new TangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Tangent, shaderStageCapability));

            case Binding.TangentSpaceBitangent:
                return(new BitangentMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Tangent, shaderStageCapability));

            case Binding.TangentSpacePosition:
                return(new PositionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Tangent, shaderStageCapability));

            case Binding.MeshUV0:
                return(new UVMaterialSlot(slotId, displayName, shaderOutputName, UVChannel.UV0, shaderStageCapability));

            case Binding.MeshUV1:
                return(new UVMaterialSlot(slotId, displayName, shaderOutputName, UVChannel.UV1, shaderStageCapability));

            case Binding.MeshUV2:
                return(new UVMaterialSlot(slotId, displayName, shaderOutputName, UVChannel.UV2, shaderStageCapability));

            case Binding.MeshUV3:
                return(new UVMaterialSlot(slotId, displayName, shaderOutputName, UVChannel.UV3, shaderStageCapability));

            case Binding.ScreenPosition:
                return(new ScreenPositionMaterialSlot(slotId, displayName, shaderOutputName, ScreenSpaceType.Default, shaderStageCapability));

            case Binding.ObjectSpaceViewDirection:
                return(new ViewDirectionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Object, shaderStageCapability));

            case Binding.ViewSpaceViewDirection:
                return(new ViewDirectionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.View, shaderStageCapability));

            case Binding.WorldSpaceViewDirection:
                return(new ViewDirectionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.World, shaderStageCapability));

            case Binding.TangentSpaceViewDirection:
                return(new ViewDirectionMaterialSlot(slotId, displayName, shaderOutputName, CoordinateSpace.Tangent, shaderStageCapability));

            case Binding.VertexColor:
                return(new VertexColorMaterialSlot(slotId, displayName, shaderOutputName, shaderStageCapability));

            default:
                throw new ArgumentOutOfRangeException("attributeBinding", attributeBinding, null);
            }
        }
Esempio n. 16
0
 public NeededCoordinateSpace RequiresBitangent(ShaderStageCapability stageCapability)
 {
     return(NeededCoordinateSpace.World);
 }
Esempio n. 17
0
 public NeededCoordinateSpace RequiresBitangent(ShaderStageCapability stageCapability)
 {
     return(space.ToNeededCoordinateSpace());
 }
Esempio n. 18
0
 public bool RequiresPixelPosition(ShaderStageCapability stageCapability = ShaderStageCapability.All) =>
 FindSlot <MaterialSlot>(kUvInputSlotId)?.RequiresPixelPosition(stageCapability) ?? false;
Esempio n. 19
0
 public bool RequiresScreenPosition(ShaderStageCapability stageCapability = ShaderStageCapability.All)
 {
     // Feedback dithering requires screen position (and only works in Pixel Shader currently)
     return(stageCapability.HasFlag(ShaderStageCapability.Fragment) && !noFeedback);
 }
Esempio n. 20
0
 public TestSlot(int slotId, string displayName, SlotType slotType, int priority, ShaderStageCapability stageCapability = ShaderStageCapability.All, bool hidden = false)
     : base(slotId, displayName, displayName, slotType, priority, stageCapability, hidden)
 {
 }
Esempio n. 21
0
        public static MaterialSlot CreateMaterialSlot(SlotValueType type, int slotId, string displayName, string shaderOutputName, SlotType slotType, Vector4 defaultValue, ShaderStageCapability shaderStageCapability = ShaderStageCapability.All, bool hidden = false)
        {
            switch (type)
            {
            case SlotValueType.SamplerState:
                return(new SamplerStateMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden));

            case SlotValueType.DynamicMatrix:
                return(new DynamicMatrixMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden));

            case SlotValueType.Matrix4:
                return(new Matrix4MaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden));

            case SlotValueType.Matrix3:
                return(new Matrix3MaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden));

            case SlotValueType.Matrix2:
                return(new Matrix2MaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden));

            case SlotValueType.Texture2D:
                return(slotType == SlotType.Input
                        ? new Texture2DInputMaterialSlot(slotId, displayName, shaderOutputName, shaderStageCapability, hidden)
                        : new Texture2DMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden));

            case SlotValueType.Texture2DArray:
                return(slotType == SlotType.Input
                        ? new Texture2DArrayInputMaterialSlot(slotId, displayName, shaderOutputName, shaderStageCapability, hidden)
                        : new Texture2DArrayMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden));

            case SlotValueType.Texture3D:
                return(slotType == SlotType.Input
                        ? new Texture3DInputMaterialSlot(slotId, displayName, shaderOutputName, shaderStageCapability, hidden)
                        : new Texture3DMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden));

            case SlotValueType.Cubemap:
                return(slotType == SlotType.Input
                        ? new CubemapInputMaterialSlot(slotId, displayName, shaderOutputName, shaderStageCapability, hidden)
                        : new CubemapMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden));

            case SlotValueType.Gradient:
                return(slotType == SlotType.Input
                        ? new GradientInputMaterialSlot(slotId, displayName, shaderOutputName, shaderStageCapability, hidden)
                        : new GradientMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden));

            case SlotValueType.DynamicVector:
                return(new DynamicVectorMaterialSlot(slotId, displayName, shaderOutputName, slotType, defaultValue, shaderStageCapability, hidden));

            case SlotValueType.Vector4:
                return(new Vector4MaterialSlot(slotId, displayName, shaderOutputName, slotType, defaultValue, shaderStageCapability, hidden: hidden));

            case SlotValueType.Vector3:
                return(new Vector3MaterialSlot(slotId, displayName, shaderOutputName, slotType, defaultValue, shaderStageCapability, hidden: hidden));

            case SlotValueType.Vector2:
                return(new Vector2MaterialSlot(slotId, displayName, shaderOutputName, slotType, defaultValue, shaderStageCapability, hidden: hidden));

            case SlotValueType.Vector1:
                return(new Vector1MaterialSlot(slotId, displayName, shaderOutputName, slotType, defaultValue.x, shaderStageCapability, hidden: hidden));

            case SlotValueType.Dynamic:
                return(new DynamicValueMaterialSlot(slotId, displayName, shaderOutputName, slotType, new Matrix4x4(defaultValue, Vector4.zero, Vector4.zero, Vector4.zero), shaderStageCapability, hidden));

            case SlotValueType.Boolean:
                return(new BooleanMaterialSlot(slotId, displayName, shaderOutputName, slotType, false, shaderStageCapability, hidden));
            }

            throw new ArgumentOutOfRangeException("type", type, null);
        }
Esempio n. 22
0
 public bool RequiresVertexSkinning(ShaderStageCapability stageCapability = ShaderStageCapability.All)
 {
     return(true);
 }
Esempio n. 23
0
 public UVMaterialSlot(int slotId, string displayName, string shaderOutputName, UVChannel channel,
                       ShaderStageCapability stageCapability = ShaderStageCapability.All, bool hidden = false)
     : base(slotId, displayName, shaderOutputName, SlotType.Input, Vector2.zero, stageCapability, hidden: hidden)
 {
     this.channel = channel;
 }
 public bool RequiresCameraOpaqueTexture(ShaderStageCapability stageCapability)
 {
     return(true);
 }
Esempio n. 25
0
 public PositionMaterialSlot(int slotId, string displayName, string shaderOutputName, CoordinateSpace space,
                             ShaderStageCapability stageCapability = ShaderStageCapability.All, bool hidden = false)
     : base(slotId, displayName, shaderOutputName, space, stageCapability, hidden)
 {
 }
Esempio n. 26
0
 public SlotAttribute(int mSlotId, Binding mImplicitBinding, bool mHidden, ShaderStageCapability mStageCapability = ShaderStageCapability.All)
 {
     slotId          = mSlotId;
     binding         = mImplicitBinding;
     hidden          = mHidden;
     defaultValue    = null;
     stageCapability = mStageCapability;
 }
Esempio n. 27
0
 public NeededCoordinateSpace RequiresPosition(ShaderStageCapability stageCapability)
 {
     return(CoordinateSpace.AbsoluteWorld.ToNeededCoordinateSpace() | CoordinateSpace.World.ToNeededCoordinateSpace());
 }
Esempio n. 28
0
 public SlotAttribute(int mSlotId, Binding mImplicitBinding, float defaultX, float defaultY, float defaultZ, float defaultW, ShaderStageCapability mStageCapability = ShaderStageCapability.All)
 {
     slotId          = mSlotId;
     binding         = mImplicitBinding;
     defaultValue    = new Vector4(defaultX, defaultY, defaultZ, defaultW);
     stageCapability = mStageCapability;
 }
Esempio n. 29
0
 public NeededCoordinateSpace RequiresViewDirection(ShaderStageCapability stageCapability = ShaderStageCapability.All)
 {
     return(NeededCoordinateSpace.Tangent);
 }
Esempio n. 30
0
 public bool RequiresVertexColor(ShaderStageCapability stageCapability)
 {
     return(!isConnected);
 }