private static void InsertAntecedent(List <AbstractMaterialNode> nodes, AbstractMaterialNode node) { var upstream = node.GetInputSlots <MaterialSlot>().Where(slot => slot.isConnected).Select(slot => node.GetInputNodeFromSlot(slot.id)); int safeIdx = nodes.FindLastIndex(n => upstream.Contains(n)) + 1; nodes.Insert(safeIdx, node); }
static void Visit(List <AbstractMaterialNode> outputList, Dictionary <Guid, AbstractMaterialNode> unmarkedNodes, AbstractMaterialNode node) { if (!unmarkedNodes.ContainsKey(node.guid)) { return; } foreach (var slot in node.GetInputSlots <ISlot>()) { foreach (var edge in node.owner.GetEdges(slot.slotReference)) { var inputNode = node.owner.GetNodeFromGuid(edge.outputSlot.nodeGuid); Visit(outputList, unmarkedNodes, inputNode); } } unmarkedNodes.Remove(node.guid); outputList.Add(node); }
static void GenerateSurfaceDescriptionRemap( GraphData graph, AbstractMaterialNode rootNode, IEnumerable <MaterialSlot> slots, ShaderStringBuilder surfaceDescriptionFunction, GenerationMode mode) { if (rootNode is IMasterNode || rootNode is SubGraphOutputNode) { var usedSlots = slots ?? rootNode.GetInputSlots <MaterialSlot>(); foreach (var input in usedSlots) { if (input != null) { var foundEdges = graph.GetEdges(input.slotReference).ToArray(); var hlslName = NodeUtils.GetHLSLSafeName(input.shaderOutputName); if (rootNode is SubGraphOutputNode) { hlslName = $"{hlslName}_{input.id}"; } if (foundEdges.Any()) { surfaceDescriptionFunction.AppendLine("surface.{0} = {1};", hlslName, rootNode.GetSlotValue(input.id, mode, rootNode.concretePrecision)); } else { surfaceDescriptionFunction.AppendLine("surface.{0} = {1};", hlslName, input.GetDefaultValue(mode, rootNode.concretePrecision)); } } } } else if (rootNode.hasPreview) { var slot = rootNode.GetOutputSlots <MaterialSlot>().FirstOrDefault(); if (slot != null) { var hlslSafeName = $"{NodeUtils.GetHLSLSafeName(slot.shaderOutputName)}_{slot.id}"; surfaceDescriptionFunction.AppendLine("surface.{0} = {1};", hlslSafeName, rootNode.GetSlotValue(slot.id, mode, rootNode.concretePrecision)); } } }
// // Find all nodes of the given type downstream from the given node // Returns a unique list. So even if a node can be reached through different paths it will be present only once. // public static List <NodeType> FindDownStreamNodesOfType <NodeType>(AbstractMaterialNode node) where NodeType : AbstractMaterialNode { // Should never be called without a node Debug.Assert(node != null); HashSet <AbstractMaterialNode> visitedNodes = new HashSet <AbstractMaterialNode>(); List <NodeType> vtNodes = new List <NodeType>(); Queue <AbstractMaterialNode> nodeStack = new Queue <AbstractMaterialNode>(); nodeStack.Enqueue(node); visitedNodes.Add(node); while (nodeStack.Count > 0) { AbstractMaterialNode visit = nodeStack.Dequeue(); // Flood fill through all the nodes foreach (var slot in visit.GetInputSlots <MaterialSlot>()) { foreach (var edge in visit.owner.GetEdges(slot.slotReference)) { var inputNode = edge.outputSlot.node; if (!visitedNodes.Contains(inputNode)) { nodeStack.Enqueue(inputNode); visitedNodes.Add(inputNode); } } } // Extract vt node if (visit is NodeType) { NodeType vtNode = visit as NodeType; vtNodes.Add(vtNode); } } return(vtNodes); }
void GenerateShaderPass(int targetIndex, PassDescriptor pass, ActiveFields activeFields) { // Early exit if pass is not used in preview if (m_Mode == GenerationMode.Preview && !pass.useInPreview) { return; } // -------------------------------------------------- // Debug // Get scripting symbols BuildTargetGroup buildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup; string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup); bool isDebug = defines.Contains(kDebugSymbol); // -------------------------------------------------- // Setup // Initiailize Collectors var propertyCollector = new PropertyCollector(); var keywordCollector = new KeywordCollector(); m_OutputNode.owner.CollectShaderKeywords(keywordCollector, m_Mode); // Get upstream nodes from ShaderPass port mask List <AbstractMaterialNode> vertexNodes; List <AbstractMaterialNode> pixelNodes; GenerationUtils.GetUpstreamNodesForShaderPass(m_OutputNode, pass, out vertexNodes, out pixelNodes); // Track permutation indices for all nodes List <int>[] vertexNodePermutations = new List <int> [vertexNodes.Count]; List <int>[] pixelNodePermutations = new List <int> [pixelNodes.Count]; // Get active fields from upstream Node requirements ShaderGraphRequirementsPerKeyword graphRequirements; GenerationUtils.GetActiveFieldsAndPermutationsForNodes(m_OutputNode, pass, keywordCollector, vertexNodes, pixelNodes, vertexNodePermutations, pixelNodePermutations, activeFields, out graphRequirements); // GET CUSTOM ACTIVE FIELDS HERE! // Get active fields from ShaderPass GenerationUtils.AddRequiredFields(pass.requiredFields, activeFields.baseInstance); // Get Port references from ShaderPass List <MaterialSlot> pixelSlots; List <MaterialSlot> vertexSlots; if (m_OutputNode is IMasterNode) { pixelSlots = GenerationUtils.FindMaterialSlotsOnNode(pass.pixelPorts, m_OutputNode); vertexSlots = GenerationUtils.FindMaterialSlotsOnNode(pass.vertexPorts, m_OutputNode); } else if (m_OutputNode is SubGraphOutputNode) { pixelSlots = new List <MaterialSlot>() { m_OutputNode.GetInputSlots <MaterialSlot>().FirstOrDefault(), }; vertexSlots = new List <MaterialSlot>(); } else { pixelSlots = new List <MaterialSlot>() { new Vector4MaterialSlot(0, "Out", "Out", SlotType.Output, Vector4.zero) { owner = m_OutputNode }, }; vertexSlots = new List <MaterialSlot>(); } // Function Registry var functionBuilder = new ShaderStringBuilder(); var functionRegistry = new FunctionRegistry(functionBuilder); // Hash table of named $splice(name) commands // Key: splice token // Value: string to splice Dictionary <string, string> spliceCommands = new Dictionary <string, string>(); // -------------------------------------------------- // Dependencies // Propagate active field requirements using dependencies // Must be executed before types are built foreach (var instance in activeFields.all.instances) { GenerationUtils.ApplyFieldDependencies(instance, pass.fieldDependencies); } // -------------------------------------------------- // Pass Setup // Name if (!string.IsNullOrEmpty(pass.displayName)) { spliceCommands.Add("PassName", $"Name \"{pass.displayName}\""); } else { spliceCommands.Add("PassName", "// Name: <None>"); } // Tags if (!string.IsNullOrEmpty(pass.lightMode)) { spliceCommands.Add("LightMode", $"\"LightMode\" = \"{pass.lightMode}\""); } else { spliceCommands.Add("LightMode", "// LightMode: <None>"); } // -------------------------------------------------- // Pass Code // Render State using (var renderStateBuilder = new ShaderStringBuilder()) { // Render states need to be separated by RenderState.Type // The first passing ConditionalRenderState of each type is inserted foreach (RenderStateType type in Enum.GetValues(typeof(RenderStateType))) { var renderStates = pass.renderStates?.Where(x => x.descriptor.type == type); if (renderStates != null) { foreach (RenderStateCollection.Item renderState in renderStates) { if (renderState.TestActive(activeFields)) { renderStateBuilder.AppendLine(renderState.value); break; } } } } string command = GenerationUtils.GetSpliceCommand(renderStateBuilder.ToCodeBlock(), "RenderState"); spliceCommands.Add("RenderState", command); } // Pragmas using (var passPragmaBuilder = new ShaderStringBuilder()) { if (pass.pragmas != null) { foreach (PragmaCollection.Item pragma in pass.pragmas) { if (pragma.TestActive(activeFields)) { passPragmaBuilder.AppendLine(pragma.value); } } } string command = GenerationUtils.GetSpliceCommand(passPragmaBuilder.ToCodeBlock(), "PassPragmas"); spliceCommands.Add("PassPragmas", command); } // Includes using (var preGraphIncludeBuilder = new ShaderStringBuilder()) { if (pass.includes != null) { foreach (IncludeCollection.Item include in pass.includes.Where(x => x.descriptor.location == IncludeLocation.Pregraph)) { if (include.TestActive(activeFields)) { preGraphIncludeBuilder.AppendLine(include.value); } } } string command = GenerationUtils.GetSpliceCommand(preGraphIncludeBuilder.ToCodeBlock(), "PreGraphIncludes"); spliceCommands.Add("PreGraphIncludes", command); } using (var postGraphIncludeBuilder = new ShaderStringBuilder()) { if (pass.includes != null) { foreach (IncludeCollection.Item include in pass.includes.Where(x => x.descriptor.location == IncludeLocation.Postgraph)) { if (include.TestActive(activeFields)) { postGraphIncludeBuilder.AppendLine(include.value); } } } string command = GenerationUtils.GetSpliceCommand(postGraphIncludeBuilder.ToCodeBlock(), "PostGraphIncludes"); spliceCommands.Add("PostGraphIncludes", command); } // Keywords using (var passKeywordBuilder = new ShaderStringBuilder()) { if (pass.keywords != null) { foreach (KeywordCollection.Item keyword in pass.keywords) { if (keyword.TestActive(activeFields)) { passKeywordBuilder.AppendLine(keyword.value); } } } string command = GenerationUtils.GetSpliceCommand(passKeywordBuilder.ToCodeBlock(), "PassKeywords"); spliceCommands.Add("PassKeywords", command); } // ----------------------------- // Generated structs and Packing code var interpolatorBuilder = new ShaderStringBuilder(); var passStructs = new List <StructDescriptor>(); if (pass.structs != null) { passStructs.AddRange(pass.structs.Select(x => x.descriptor)); foreach (StructCollection.Item shaderStruct in pass.structs) { if (shaderStruct.descriptor.packFields == false) { continue; //skip structs that do not need interpolator packs } List <int> packedCounts = new List <int>(); var packStruct = new StructDescriptor(); //generate packed functions if (activeFields.permutationCount > 0) { var generatedPackedTypes = new Dictionary <string, (ShaderStringBuilder, List <int>)>(); foreach (var instance in activeFields.allPermutations.instances) { var instanceGenerator = new ShaderStringBuilder(); GenerationUtils.GenerateInterpolatorFunctions(shaderStruct.descriptor, instance, out instanceGenerator); var key = instanceGenerator.ToCodeBlock(); if (generatedPackedTypes.TryGetValue(key, out var value)) { value.Item2.Add(instance.permutationIndex); } else { generatedPackedTypes.Add(key, (instanceGenerator, new List <int> { instance.permutationIndex }));
internal static void GenerateSurfaceDescription( List <INode> activeNodeList, AbstractMaterialNode masterNode, AbstractMaterialGraph graph, ShaderGenerator surfaceDescriptionFunction, FunctionRegistry functionRegistry, PropertyCollector shaderProperties, ShaderGraphRequirements requirements, GenerationMode mode, string functionName = "PopulateSurfaceData", string surfaceDescriptionName = "SurfaceDescription", Vector1ShaderProperty outputIdProperty = null, IEnumerable <MaterialSlot> slots = null) { if (graph == null) { return; } surfaceDescriptionFunction.AddShaderChunk(String.Format("{0} {1}(SurfaceInputs IN) {{", surfaceDescriptionName, functionName), false); surfaceDescriptionFunction.Indent(); surfaceDescriptionFunction.AddShaderChunk(String.Format("{0} surface = ({0})0;", surfaceDescriptionName), false); graph.CollectShaderProperties(shaderProperties, mode); foreach (var activeNode in activeNodeList.OfType <AbstractMaterialNode>()) { if (activeNode is IGeneratesFunction) { functionRegistry.builder.currentNode = activeNode; (activeNode as IGeneratesFunction).GenerateNodeFunction(functionRegistry, mode); } if (activeNode is IGeneratesBodyCode) { (activeNode as IGeneratesBodyCode).GenerateNodeCode(surfaceDescriptionFunction, mode); } if (masterNode == null && activeNode.hasPreview) { var outputSlot = activeNode.GetOutputSlots <MaterialSlot>().FirstOrDefault(); if (outputSlot != null) { surfaceDescriptionFunction.AddShaderChunk(String.Format("if ({0} == {1}) {{ surface.PreviewOutput = {2}; return surface; }}", outputIdProperty.referenceName, activeNode.tempId.index, ShaderGenerator.AdaptNodeOutputForPreview(activeNode, outputSlot.id, activeNode.GetVariableNameForSlot(outputSlot.id))), false); } } activeNode.CollectShaderProperties(shaderProperties, mode); } functionRegistry.builder.currentNode = null; if (masterNode != null) { if (masterNode is IMasterNode) { var usedSlots = slots ?? masterNode.GetInputSlots <MaterialSlot>(); foreach (var input in usedSlots) { var foundEdges = graph.GetEdges(input.slotReference).ToArray(); if (foundEdges.Any()) { surfaceDescriptionFunction.AddShaderChunk(string.Format("surface.{0} = {1};", NodeUtils.GetHLSLSafeName(input.shaderOutputName), masterNode.GetSlotValue(input.id, mode)), true); } else { surfaceDescriptionFunction.AddShaderChunk(string.Format("surface.{0} = {1};", NodeUtils.GetHLSLSafeName(input.shaderOutputName), input.GetDefaultValue(mode)), true); } } } else if (masterNode.hasPreview) { foreach (var slot in masterNode.GetOutputSlots <MaterialSlot>()) { surfaceDescriptionFunction.AddShaderChunk(string.Format("surface.{0} = {1};", NodeUtils.GetHLSLSafeName(slot.shaderOutputName), masterNode.GetSlotValue(slot.id, mode)), true); } } } surfaceDescriptionFunction.AddShaderChunk("return surface;", false); surfaceDescriptionFunction.Deindent(); surfaceDescriptionFunction.AddShaderChunk("}", false); }
public static GenerationResults GetShader(this GraphData graph, AbstractMaterialNode node, GenerationMode mode, string name) { // ----------------------------------------------------- // // SETUP // // ----------------------------------------------------- // // ------------------------------------- // String builders var finalShader = new ShaderStringBuilder(); var results = new GenerationResults(); var shaderProperties = new PropertyCollector(); var shaderKeywords = new KeywordCollector(); var shaderPropertyUniforms = new ShaderStringBuilder(); var shaderKeywordDeclarations = new ShaderStringBuilder(); var shaderKeywordPermutations = new ShaderStringBuilder(1); var functionBuilder = new ShaderStringBuilder(); var functionRegistry = new FunctionRegistry(functionBuilder); var vertexDescriptionFunction = new ShaderStringBuilder(0); var surfaceDescriptionInputStruct = new ShaderStringBuilder(0); var surfaceDescriptionStruct = new ShaderStringBuilder(0); var surfaceDescriptionFunction = new ShaderStringBuilder(0); var vertexInputs = new ShaderStringBuilder(0); graph.CollectShaderKeywords(shaderKeywords, mode); if (graph.GetKeywordPermutationCount() > ShaderGraphPreferences.variantLimit) { graph.AddValidationError(node.tempId, ShaderKeyword.kVariantLimitWarning, Rendering.ShaderCompilerMessageSeverity.Error); results.configuredTextures = shaderProperties.GetConfiguredTexutres(); results.shader = string.Empty; return(results); } // ------------------------------------- // Get Slot and Node lists var activeNodeList = ListPool <AbstractMaterialNode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(activeNodeList, node); var slots = new List <MaterialSlot>(); if (node is IMasterNode || node is SubGraphOutputNode) { slots.AddRange(node.GetInputSlots <MaterialSlot>()); } else { var outputSlots = node.GetOutputSlots <MaterialSlot>().ToList(); if (outputSlots.Count > 0) { slots.Add(outputSlots[0]); } } // ------------------------------------- // Get Requirements var requirements = ShaderGraphRequirements.FromNodes(activeNodeList, ShaderStageCapability.Fragment); // ----------------------------------------------------- // // KEYWORDS // // ----------------------------------------------------- // // ------------------------------------- // Get keyword permutations graph.CollectShaderKeywords(shaderKeywords, mode); // Track permutation indicies for all nodes and requirements List <int>[] keywordPermutationsPerNode = new List <int> [activeNodeList.Count]; // ------------------------------------- // Evaluate all permutations for (int i = 0; i < shaderKeywords.permutations.Count; i++) { // Get active nodes for this permutation var localNodes = ListPool <AbstractMaterialNode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(localNodes, node, keywordPermutation: shaderKeywords.permutations[i]); // Track each pixel node in this permutation foreach (AbstractMaterialNode pixelNode in localNodes) { int nodeIndex = activeNodeList.IndexOf(pixelNode); if (keywordPermutationsPerNode[nodeIndex] == null) { keywordPermutationsPerNode[nodeIndex] = new List <int>(); } keywordPermutationsPerNode[nodeIndex].Add(i); } // Get active requirements for this permutation var localSurfaceRequirements = ShaderGraphRequirements.FromNodes(localNodes, ShaderStageCapability.Fragment, false); var localPixelRequirements = ShaderGraphRequirements.FromNodes(localNodes, ShaderStageCapability.Fragment); } // ----------------------------------------------------- // // START VERTEX DESCRIPTION // // ----------------------------------------------------- // // ------------------------------------- // Generate Vertex Description function vertexDescriptionFunction.AppendLine("GraphVertexInput PopulateVertexData(GraphVertexInput v)"); using (vertexDescriptionFunction.BlockScope()) { vertexDescriptionFunction.AppendLine("return v;"); } // ----------------------------------------------------- // // START SURFACE DESCRIPTION // // ----------------------------------------------------- // // ------------------------------------- // Generate Input structure for Surface Description function // Surface Description Input requirements are needed to exclude intermediate translation spaces GenerateSurfaceInputStruct(surfaceDescriptionInputStruct, requirements, "SurfaceDescriptionInputs"); results.previewMode = PreviewMode.Preview2D; foreach (var pNode in activeNodeList) { if (pNode.previewMode == PreviewMode.Preview3D) { results.previewMode = PreviewMode.Preview3D; break; } } // ------------------------------------- // Generate Output structure for Surface Description function GenerateSurfaceDescriptionStruct(surfaceDescriptionStruct, slots, useIdsInNames: !(node is IMasterNode)); // ------------------------------------- // Generate Surface Description function GenerateSurfaceDescriptionFunction( activeNodeList, keywordPermutationsPerNode, node, graph, surfaceDescriptionFunction, functionRegistry, shaderProperties, shaderKeywords, mode, outputIdProperty: results.outputIdProperty); // ----------------------------------------------------- // // GENERATE VERTEX > PIXEL PIPELINE // // ----------------------------------------------------- // // ------------------------------------- // Keyword declarations shaderKeywords.GetKeywordsDeclaration(shaderKeywordDeclarations, mode); // ------------------------------------- // Property uniforms shaderProperties.GetPropertiesDeclaration(shaderPropertyUniforms, mode, graph.concretePrecision); // ------------------------------------- // Generate Input structure for Vertex shader GenerateApplicationVertexInputs(requirements, vertexInputs); // ----------------------------------------------------- // // FINALIZE // // ----------------------------------------------------- // // ------------------------------------- // Build final shader finalShader.AppendLine(@"Shader ""{0}""", name); using (finalShader.BlockScope()) { SubShaderGenerator.GeneratePropertiesBlock(finalShader, shaderProperties, shaderKeywords, mode); finalShader.AppendNewLine(); finalShader.AppendLine(@"HLSLINCLUDE"); finalShader.AppendLine(@"#include ""Assets/Scripts/URP/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"""); finalShader.AppendLine(@"#include ""Assets/Scripts/URP/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl"""); finalShader.AppendLine(@"#include ""Assets/Scripts/URP/com.unity.render-pipelines.core/ShaderLibrary/NormalSurfaceGradient.hlsl"""); finalShader.AppendLine(@"#include ""Assets/Scripts/URP/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"""); finalShader.AppendLine(@"#include ""Assets/Scripts/URP/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl"""); finalShader.AppendLine(@"#include ""Assets/Scripts/URP/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlsl"""); finalShader.AppendLine(@"#include ""Assets/Scripts/URP/com.unity.shadergraph/ShaderGraphLibrary/ShaderVariables.hlsl"""); finalShader.AppendLine(@"#include ""Assets/Scripts/URP/com.unity.shadergraph/ShaderGraphLibrary/ShaderVariablesFunctions.hlsl"""); finalShader.AppendLine(@"#include ""Assets/Scripts/URP/com.unity.shadergraph/ShaderGraphLibrary/Functions.hlsl"""); finalShader.AppendLines(shaderKeywordDeclarations.ToString()); finalShader.AppendLine(@"#define SHADERGRAPH_PREVIEW 1"); finalShader.AppendNewLine(); finalShader.AppendLines(shaderKeywordPermutations.ToString()); finalShader.AppendLines(shaderPropertyUniforms.ToString()); finalShader.AppendNewLine(); finalShader.AppendLines(surfaceDescriptionInputStruct.ToString()); finalShader.AppendNewLine(); finalShader.Concat(functionBuilder); finalShader.AppendNewLine(); finalShader.AppendLines(surfaceDescriptionStruct.ToString()); finalShader.AppendNewLine(); finalShader.AppendLines(surfaceDescriptionFunction.ToString()); finalShader.AppendNewLine(); finalShader.AppendLines(vertexInputs.ToString()); finalShader.AppendNewLine(); finalShader.AppendLines(vertexDescriptionFunction.ToString()); finalShader.AppendNewLine(); finalShader.AppendLine(@"ENDHLSL"); finalShader.AppendLines(ShaderGenerator.GetPreviewSubShader(node, requirements)); ListPool <AbstractMaterialNode> .Release(activeNodeList); } // ------------------------------------- // Finalize results.configuredTextures = shaderProperties.GetConfiguredTexutres(); ShaderSourceMap sourceMap; results.shader = finalShader.ToString(out sourceMap); results.sourceMap = sourceMap; return(results); }
public static string GetPreviewSubShader(AbstractMaterialNode node, ShaderGraphRequirements shaderGraphRequirements) { // Should never be called without a node Debug.Assert(node != null); var vertexOutputStruct = new ShaderStringBuilder(2); var vertexShader = new ShaderStringBuilder(2); var vertexShaderDescriptionInputs = new ShaderStringBuilder(2); var vertexShaderOutputs = new ShaderStringBuilder(1); var pixelShader = new ShaderStringBuilder(2); var pixelShaderSurfaceInputs = new ShaderStringBuilder(2); var pixelShaderSurfaceRemap = new ShaderStringBuilder(2); ShaderGenerator.GenerateStandardTransforms( 0, 16, vertexOutputStruct, vertexShader, vertexShaderDescriptionInputs, vertexShaderOutputs, pixelShader, pixelShaderSurfaceInputs, shaderGraphRequirements, shaderGraphRequirements, ShaderGraphRequirements.none, ShaderGraphRequirements.none, CoordinateSpace.World); vertexShader.AppendLines(vertexShaderDescriptionInputs.ToString()); vertexShader.AppendLines(vertexShaderOutputs.ToString()); var outputSlot = node.GetOutputSlots <MaterialSlot>().FirstOrDefault(); // Sub Graph Output uses first input slot if (node is SubGraphOutputNode) { outputSlot = node.GetInputSlots <MaterialSlot>().FirstOrDefault(); } if (outputSlot != null) { var result = $"surf.{NodeUtils.GetHLSLSafeName(outputSlot.shaderOutputName)}_{outputSlot.id}"; pixelShaderSurfaceRemap.AppendLine("return all(isfinite({0})) ? {1} : {2};", result, AdaptNodeOutputForPreview(node, outputSlot.id, result), nanOutput); } else { // No valid slots to display, so just show black. // It's up to each node to error or warn as appropriate. pixelShaderSurfaceRemap.AppendLine("return 0;"); } // ------------------------------------- // Extra pixel shader work var faceSign = new ShaderStringBuilder(); if (shaderGraphRequirements.requiresFaceSign) { faceSign.AppendLine(", half FaceSign : VFACE"); } var res = subShaderTemplate.Replace("${Interpolators}", vertexOutputStruct.ToString()); res = res.Replace("${VertexShader}", vertexShader.ToString()); res = res.Replace("${FaceSign}", faceSign.ToString()); res = res.Replace("${LocalPixelShader}", pixelShader.ToString()); res = res.Replace("${SurfaceInputs}", pixelShaderSurfaceInputs.ToString()); res = res.Replace("${SurfaceOutputRemap}", pixelShaderSurfaceRemap.ToString()); return(res); }
public static void GenerateSurfaceDescriptionFunction( List <INode> activeNodeList, AbstractMaterialNode masterNode, AbstractMaterialGraph graph, ShaderStringBuilder surfaceDescriptionFunction, FunctionRegistry functionRegistry, PropertyCollector shaderProperties, ShaderGraphRequirements requirements, GenerationMode mode, string functionName = "PopulateSurfaceData", string surfaceDescriptionName = "SurfaceDescription", Vector1ShaderProperty outputIdProperty = null, IEnumerable <MaterialSlot> slots = null, string graphInputStructName = "SurfaceDescriptionInputs") { if (graph == null) { return; } GraphContext graphContext = new GraphContext(graphInputStructName); graph.CollectShaderProperties(shaderProperties, mode); surfaceDescriptionFunction.AppendLine(String.Format("{0} {1}(SurfaceDescriptionInputs IN)", surfaceDescriptionName, functionName), false); using (surfaceDescriptionFunction.BlockScope()) { ShaderGenerator sg = new ShaderGenerator(); surfaceDescriptionFunction.AppendLine("{0} surface = ({0})0;", surfaceDescriptionName); foreach (var activeNode in activeNodeList.OfType <AbstractMaterialNode>()) { if (activeNode is IGeneratesFunction) { functionRegistry.builder.currentNode = activeNode; (activeNode as IGeneratesFunction).GenerateNodeFunction(functionRegistry, graphContext, mode); } if (activeNode is IGeneratesBodyCode) { (activeNode as IGeneratesBodyCode).GenerateNodeCode(sg, mode); } if (masterNode == null && activeNode.hasPreview) { var outputSlot = activeNode.GetOutputSlots <MaterialSlot>().FirstOrDefault(); if (outputSlot != null) { sg.AddShaderChunk(String.Format("if ({0} == {1}) {{ surface.PreviewOutput = {2}; return surface; }}", outputIdProperty.referenceName, activeNode.tempId.index, ShaderGenerator.AdaptNodeOutputForPreview(activeNode, outputSlot.id, activeNode.GetVariableNameForSlot(outputSlot.id))), false); } } // In case of the subgraph output node, the preview is generated // from the first input to the node. if (activeNode is SubGraphOutputNode) { var inputSlot = activeNode.GetInputSlots <MaterialSlot>().FirstOrDefault(); if (inputSlot != null) { var foundEdges = graph.GetEdges(inputSlot.slotReference).ToArray(); string slotValue = foundEdges.Any() ? activeNode.GetSlotValue(inputSlot.id, mode) : inputSlot.GetDefaultValue(mode); sg.AddShaderChunk(String.Format("if ({0} == {1}) {{ surface.PreviewOutput = {2}; return surface; }}", outputIdProperty.referenceName, activeNode.tempId.index, slotValue), false); } } activeNode.CollectShaderProperties(shaderProperties, mode); } surfaceDescriptionFunction.AppendLines(sg.GetShaderString(0)); functionRegistry.builder.currentNode = null; if (masterNode != null) { if (masterNode is IMasterNode) { var usedSlots = slots ?? masterNode.GetInputSlots <MaterialSlot>(); foreach (var input in usedSlots) { var foundEdges = graph.GetEdges(input.slotReference).ToArray(); if (foundEdges.Any()) { surfaceDescriptionFunction.AppendLine("surface.{0} = {1};", NodeUtils.GetHLSLSafeName(input.shaderOutputName), masterNode.GetSlotValue(input.id, mode)); } else { surfaceDescriptionFunction.AppendLine("surface.{0} = {1};", NodeUtils.GetHLSLSafeName(input.shaderOutputName), input.GetDefaultValue(mode)); } } } else if (masterNode.hasPreview) { foreach (var slot in masterNode.GetOutputSlots <MaterialSlot>()) { surfaceDescriptionFunction.AppendLine("surface.{0} = {1};", NodeUtils.GetHLSLSafeName(slot.shaderOutputName), masterNode.GetSlotValue(slot.id, mode)); } } } surfaceDescriptionFunction.AppendLine("return surface;"); } }