void BuildShader() { var activeNodeList = Graphing.ListPool <AbstractMaterialNode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(activeNodeList, m_OutputNode); var shaderProperties = new PropertyCollector(); var shaderKeywords = new KeywordCollector(); m_GraphData.CollectShaderProperties(shaderProperties, m_Mode); m_GraphData.CollectShaderKeywords(shaderKeywords, m_Mode); if (m_GraphData.GetKeywordPermutationCount() > ShaderGraphPreferences.variantLimit) { m_GraphData.AddValidationError(m_OutputNode.guid, ShaderKeyword.kVariantLimitWarning, Rendering.ShaderCompilerMessageSeverity.Error); m_ConfiguredTextures = shaderProperties.GetConfiguredTexutres(); m_Builder.AppendLines(ShaderGraphImporter.k_ErrorShader); } GetTargetImplementations(); foreach (var activeNode in activeNodeList.OfType <AbstractMaterialNode>()) { activeNode.CollectShaderProperties(shaderProperties, m_Mode); } m_Builder.AppendLine(@"Shader ""{0}""", m_Name); using (m_Builder.BlockScope()) { GenerationUtils.GeneratePropertiesBlock(m_Builder, shaderProperties, shaderKeywords, m_Mode); for (int i = 0; i < m_TargetImplementations.Length; i++) { TargetSetupContext context = new TargetSetupContext(); context.SetMasterNode(m_OutputNode as IMasterNode); // Instead of setup target, we can also just do get context m_TargetImplementations[i].SetupTarget(ref context); GetAssetDependencyPaths(context); GenerateSubShader(i, context.descriptor); } // Either grab the pipeline default for the active node or the user override if (m_OutputNode is ICanChangeShaderGUI canChangeShaderGui) { string customEditor = GenerationUtils.FinalCustomEditorString(canChangeShaderGui); if (customEditor != null) { m_Builder.AppendLine("CustomEditor \"" + customEditor + "\""); } } m_Builder.AppendLine(@"FallBack ""Hidden/Shader Graph/FallbackError"""); } m_ConfiguredTextures = shaderProperties.GetConfiguredTexutres(); }
public string GetShader(GenerationMode mode, string outputName, out List <PropertyCollector.TextureInfo> configuredTextures, List <string> sourceAssetDependencyPaths = null) { var activeNodeList = ListPool <AbstractMaterialNode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(activeNodeList, this); var shaderProperties = new PropertyCollector(); var shaderKeywords = new KeywordCollector(); if (owner != null) { owner.CollectShaderProperties(shaderProperties, mode); owner.CollectShaderKeywords(shaderKeywords, mode); } if (owner.GetKeywordPermutationCount() > ShaderGraphPreferences.variantLimit) { owner.AddValidationError(tempId, ShaderKeyword.kVariantLimitWarning, Rendering.ShaderCompilerMessageSeverity.Error); configuredTextures = shaderProperties.GetConfiguredTexutres(); return(ShaderGraphImporter.k_ErrorShader); } foreach (var activeNode in activeNodeList.OfType <AbstractMaterialNode>()) { activeNode.CollectShaderProperties(shaderProperties, mode); } var finalShader = new ShaderStringBuilder(); finalShader.AppendLine(@"Shader ""{0}""", outputName); using (finalShader.BlockScope()) { GraphUtil.GeneratePropertiesBlock(finalShader, shaderProperties, shaderKeywords, mode); foreach (var subShader in m_SubShaders) { if (mode != GenerationMode.Preview || subShader.IsPipelineCompatible(GraphicsSettings.renderPipelineAsset)) { finalShader.AppendLines(subShader.GetSubshader(this, mode, sourceAssetDependencyPaths)); } } finalShader.AppendLine(@"FallBack ""Hidden/InternalErrorShader"""); } configuredTextures = shaderProperties.GetConfiguredTexutres(); return(finalShader.ToString()); }
public string GetShader(GenerationMode mode, string outputName, out List<PropertyCollector.TextureInfo> configuredTextures, List<string> sourceAssetDependencyPaths = null) { var activeNodeList = ListPool<AbstractMaterialNode>.Get(); NodeUtils.DepthFirstCollectNodesFromNode(activeNodeList, this); var shaderProperties = new PropertyCollector(); var abstractMaterialGraph = owner as GraphData; if (abstractMaterialGraph != null) abstractMaterialGraph.CollectShaderProperties(shaderProperties, mode); foreach (var activeNode in activeNodeList.OfType<AbstractMaterialNode>()) activeNode.CollectShaderProperties(shaderProperties, mode); var finalShader = new ShaderStringBuilder(); finalShader.AppendLine(@"Shader ""{0}""", outputName); using (finalShader.BlockScope()) { finalShader.AppendLine("Properties"); using (finalShader.BlockScope()) { finalShader.AppendLine(shaderProperties.GetPropertiesBlock(0)); } foreach (var subShader in m_SubShaders) { if (mode != GenerationMode.Preview || subShader.IsPipelineCompatible(GraphicsSettings.renderPipelineAsset)) finalShader.AppendLines(subShader.GetSubshader(this, mode, sourceAssetDependencyPaths)); } finalShader.AppendLine(@"FallBack ""Hidden/InternalErrorShader"""); } configuredTextures = shaderProperties.GetConfiguredTexutres(); return finalShader.ToString(); }
public override string GetShader(GenerationMode mode, string outputName, out List <PropertyCollector.TextureInfo> configuredTextures) { var activeNodeList = ListPool <INode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(activeNodeList, this); var shaderProperties = new PropertyCollector(); var abstractMaterialGraph = owner as AbstractMaterialGraph; if (abstractMaterialGraph != null) { abstractMaterialGraph.CollectShaderProperties(shaderProperties, mode); } foreach (var activeNode in activeNodeList.OfType <AbstractMaterialNode>()) { activeNode.CollectShaderProperties(shaderProperties, mode); } var finalShader = new ShaderGenerator(); finalShader.AddShaderChunk(string.Format(@"Shader ""{0}""", outputName), false); finalShader.AddShaderChunk("{", false); finalShader.Indent(); finalShader.AddShaderChunk("Properties", false); finalShader.AddShaderChunk("{", false); finalShader.Indent(); finalShader.AddShaderChunk(shaderProperties.GetPropertiesBlock(2), false); finalShader.Deindent(); finalShader.AddShaderChunk("}", false); var lwSub = new LightWeightUnlitSubShader(); finalShader.AddShaderChunk(lwSub.GetSubshader(this, mode), true); //Disable HD for now as there is no mapping // for many inputs like worldSpaceNormal and similar /*var hdSub = new HDUnlitSubShader(); * finalShader.AddShaderChunk(hdSub.GetSubshader(this, mode), true);*/ finalShader.Deindent(); finalShader.AddShaderChunk("}", false); configuredTextures = shaderProperties.GetConfiguredTexutres(); return(finalShader.GetShaderString(0)); }
public override string GetShader(GenerationMode mode, string outputName, out List <PropertyCollector.TextureInfo> configuredTextures) { var activeNodeList = ListPool <INode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(activeNodeList, this); var shaderProperties = new PropertyCollector(); var abstractMaterialGraph = owner as AbstractMaterialGraph; if (abstractMaterialGraph != null) { abstractMaterialGraph.CollectShaderProperties(shaderProperties, mode); } foreach (var activeNode in activeNodeList.OfType <AbstractMaterialNode>()) { activeNode.CollectShaderProperties(shaderProperties, mode); } var finalShader = new ShaderGenerator(); finalShader.AddShaderChunk(string.Format(@"Shader ""{0}""", outputName), false); finalShader.AddShaderChunk("{", false); finalShader.Indent(); finalShader.AddShaderChunk("Properties", false); finalShader.AddShaderChunk("{", false); finalShader.Indent(); finalShader.AddShaderChunk(shaderProperties.GetPropertiesBlock(2), false); finalShader.Deindent(); finalShader.AddShaderChunk("}", false); var lwSub = new LightWeightPBRSubShader(); foreach (var subshader in lwSub.GetSubshader(this, mode)) { finalShader.AddShaderChunk(subshader, true); } finalShader.Deindent(); finalShader.AddShaderChunk("}", false); configuredTextures = shaderProperties.GetConfiguredTexutres(); return(finalShader.GetShaderString(0)); }
public string GetShader(GenerationMode mode, string outputName, out List <PropertyCollector.TextureInfo> configuredTextures) { var activeNodeList = ListPool <INode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(activeNodeList, this); var shaderProperties = new PropertyCollector(); var abstractMaterialGraph = owner as AbstractMaterialGraph; if (abstractMaterialGraph != null) { abstractMaterialGraph.CollectShaderProperties(shaderProperties, mode); } foreach (var activeNode in activeNodeList.OfType <AbstractMaterialNode>()) { activeNode.CollectShaderProperties(shaderProperties, mode); } var finalShader = new ShaderStringBuilder(); finalShader.AppendLine(@"Shader ""{0}""", outputName); using (finalShader.BlockScope()) { finalShader.AppendLine("Properties"); using (finalShader.BlockScope()) { finalShader.AppendLine(shaderProperties.GetPropertiesBlock(0)); } foreach (var subShader in m_SubShaders) { finalShader.AppendLines(subShader.GetSubshader(this, mode)); } finalShader.AppendLine(@"FallBack ""Hidden/InternalErrorShader"""); } configuredTextures = shaderProperties.GetConfiguredTexutres(); return(finalShader.ToString()); }
// TODO: Fix this static ShaderGraphVfxAsset GenerateVfxShaderGraphAsset(GraphData graph) { var target = graph.activeTargets.FirstOrDefault(x => x is VFXTarget) as VFXTarget; 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; asset.lit = target.lit; asset.alphaClipping = target.alphaTest; 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 generation { var tmpCtx = new TargetActiveBlockContext(new List <BlockFieldDescriptor>(), null); target.GetActiveBlocks(ref tmpCtx); ports.RemoveAll(materialSlot => { return(!tmpCtx.activeBlocks.Any(o => materialSlot.RawDisplayName() == o.displayName)); }); } var bodySb = new ShaderStringBuilder(1); var registry = new FunctionRegistry(new ShaderStringBuilder(), true); foreach (var properties in graph.properties) { properties.ValidateConcretePrecision(graph.concretePrecision); } 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.GetConfiguredTexutres()); 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}"); 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.isExposable && property.generatePropertyBlock) { 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}"); } 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.concretePrecision)} {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]; for (var portIndex = 0; portIndex < ports.Count; portIndex++) { portPropertyIndices[portIndex] = new List <int>(); } foreach (var property in graph.properties) { if (!property.isExposable || !property.generatePropertyBlock) { continue; } var propertyIndex = inputProperties.Count; var codeIndex = codeSnippets.Count; 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); } } inputProperties.Add(property); codeSnippets.Add($",{nl}{indent}/* Property: {property.displayName} */ {property.GetPropertyAsArgumentString()}"); } 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.concretePrecision)};{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.concretePrecision = graph.concretePrecision; 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); }
static ShaderGraphVfxAsset GenerateVfxShaderGraphAsset(VfxMasterNode masterNode) { var nl = Environment.NewLine; var indent = new string(' ', 4); var asset = ScriptableObject.CreateInstance <ShaderGraphVfxAsset>(); var result = asset.compilationResult = new GraphCompilationResult(); var mode = GenerationMode.ForReals; var graph = masterNode.owner; asset.lit = masterNode.lit.isOn; var assetGuid = masterNode.owner.assetGuid; var assetPath = AssetDatabase.GUIDToAssetPath(assetGuid); var hlslName = NodeUtils.GetHLSLSafeName(Path.GetFileNameWithoutExtension(assetPath)); var ports = new List <MaterialSlot>(); masterNode.GetInputSlots(ports); var nodes = new List <AbstractMaterialNode>(); NodeUtils.DepthFirstCollectNodesFromNode(nodes, masterNode); var bodySb = new ShaderStringBuilder(1); var registry = new FunctionRegistry(new ShaderStringBuilder(), true); foreach (var properties in graph.properties) { properties.ValidateConcretePrecision(graph.concretePrecision); } 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 <Guid> [ports.Count]; for (var portIndex = 0; portIndex < ports.Count; portIndex++) { portPropertySets[portIndex] = new HashSet <Guid>(); } 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.propertyGuid); } } } var shaderProperties = new PropertyCollector(); foreach (var node in nodes) { node.CollectShaderProperties(shaderProperties, GenerationMode.ForReals); } asset.SetTextureInfos(shaderProperties.GetConfiguredTexutres()); 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}"); 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.guid}): {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.isExposable && property.generatePropertyBlock) { continue; } for (var portIndex = 0; portIndex < ports.Count; portIndex++) { var portPropertySet = portPropertySets[portIndex]; if (portPropertySet.Contains(property.guid)) { portCodeIndices[portIndex].Add(codeSnippets.Count); } } codeSnippets.Add($"// Property: {property.displayName}{nl}{property.GetPropertyDeclarationString()}{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++) { portRequirements[portIndex] = ShaderGraphRequirements.FromNodes(portNodeSets[portIndex].ToList(), 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 #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.concretePrecision)} {port.shaderOutputName}_{port.id};"); } 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]; for (var portIndex = 0; portIndex < ports.Count; portIndex++) { portPropertyIndices[portIndex] = new List <int>(); } foreach (var property in graph.properties) { if (!property.isExposable || !property.generatePropertyBlock) { continue; } var propertyIndex = inputProperties.Count; var codeIndex = codeSnippets.Count; for (var portIndex = 0; portIndex < ports.Count; portIndex++) { var portPropertySet = portPropertySets[portIndex]; if (portPropertySet.Contains(property.guid)) { portCodeIndices[portIndex].Add(codeIndex); portPropertyIndices[portIndex].Add(propertyIndex); } } inputProperties.Add(property); codeSnippets.Add($",{nl}{indent}/* Property: {property.displayName} */ {property.GetPropertyAsArgumentString()}"); } 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}// {masterNode.name}{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}_{port.id} = {masterNode.GetSlotValue(port.id, GenerationMode.ForReals, graph.concretePrecision)};{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(); } asset.SetOutputs(ports.Select((t, i) => new OutputMetadata(i, t.shaderOutputName, t.id)).ToArray()); asset.evaluationFunctionName = evaluationFunctionName; asset.inputStructName = inputStructName; asset.outputStructName = outputStructName; asset.portRequirements = portRequirements; asset.concretePrecision = graph.concretePrecision; 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 static GenerationResults GetShader(this AbstractMaterialGraph graph, AbstractMaterialNode node, GenerationMode mode, string name) { var results = new GenerationResults(); bool isUber = node == null; var vertexInputs = new ShaderGenerator(); var vertexShader = new ShaderGenerator(); var surfaceDescriptionFunction = new ShaderGenerator(); var surfaceDescriptionStruct = new ShaderGenerator(); var functionBuilder = new ShaderStringBuilder(); var functionRegistry = new FunctionRegistry(functionBuilder); var surfaceInputs = new ShaderGenerator(); surfaceInputs.AddShaderChunk("struct SurfaceInputs{", false); surfaceInputs.Indent(); var activeNodeList = ListPool <INode> .Get(); if (isUber) { var unmarkedNodes = graph.GetNodes <INode>().Where(x => !(x is IMasterNode)).ToDictionary(x => x.guid); while (unmarkedNodes.Any()) { var unmarkedNode = unmarkedNodes.FirstOrDefault(); Visit(activeNodeList, unmarkedNodes, unmarkedNode.Value); } } else { NodeUtils.DepthFirstCollectNodesFromNode(activeNodeList, node); } var requirements = ShaderGraphRequirements.FromNodes(activeNodeList); GenerateApplicationVertexInputs(requirements, vertexInputs); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresNormal, InterpolatorType.Normal, surfaceInputs); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresTangent, InterpolatorType.Tangent, surfaceInputs); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresBitangent, InterpolatorType.BiTangent, surfaceInputs); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresViewDir, InterpolatorType.ViewDirection, surfaceInputs); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresPosition, InterpolatorType.Position, surfaceInputs); if (requirements.requiresVertexColor) { surfaceInputs.AddShaderChunk(String.Format("float4 {0};", ShaderGeneratorNames.VertexColor), false); } if (requirements.requiresScreenPosition) { surfaceInputs.AddShaderChunk(String.Format("float4 {0};", ShaderGeneratorNames.ScreenPosition), false); } results.previewMode = PreviewMode.Preview3D; if (!isUber) { foreach (var pNode in activeNodeList.OfType <AbstractMaterialNode>()) { if (pNode.previewMode == PreviewMode.Preview3D) { results.previewMode = PreviewMode.Preview3D; break; } } } foreach (var channel in requirements.requiresMeshUVs.Distinct()) { surfaceInputs.AddShaderChunk(String.Format("half4 {0};", channel.GetUVName()), false); } surfaceInputs.Deindent(); surfaceInputs.AddShaderChunk("};", false); vertexShader.AddShaderChunk("GraphVertexInput PopulateVertexData(GraphVertexInput v){", false); vertexShader.Indent(); vertexShader.AddShaderChunk("return v;", false); vertexShader.Deindent(); vertexShader.AddShaderChunk("}", false); var slots = new List <MaterialSlot>(); foreach (var activeNode in isUber ? activeNodeList.Where(n => ((AbstractMaterialNode)n).hasPreview) : ((INode)node).ToEnumerable()) { if (activeNode is IMasterNode) { slots.AddRange(activeNode.GetInputSlots <MaterialSlot>()); } else { slots.AddRange(activeNode.GetOutputSlots <MaterialSlot>()); } } GenerateSurfaceDescriptionStruct(surfaceDescriptionStruct, slots, !isUber); var shaderProperties = new PropertyCollector(); results.outputIdProperty = new Vector1ShaderProperty { displayName = "OutputId", generatePropertyBlock = false, value = -1 }; if (isUber) { shaderProperties.AddShaderProperty(results.outputIdProperty); } GenerateSurfaceDescription( activeNodeList, node, graph, surfaceDescriptionFunction, functionRegistry, shaderProperties, requirements, mode, outputIdProperty: results.outputIdProperty); var finalBuilder = new ShaderStringBuilder(); finalBuilder.AppendLine(@"Shader ""{0}""", name); using (finalBuilder.BlockScope()) { finalBuilder.AppendLine("Properties"); using (finalBuilder.BlockScope()) { finalBuilder.AppendLines(shaderProperties.GetPropertiesBlock(0)); } finalBuilder.AppendLine(@"HLSLINCLUDE"); finalBuilder.AppendLine("#define USE_LEGACY_UNITY_MATRIX_VARIABLES"); finalBuilder.AppendLine(@"#include ""CoreRP/ShaderLibrary/Common.hlsl"""); finalBuilder.AppendLine(@"#include ""CoreRP/ShaderLibrary/Packing.hlsl"""); finalBuilder.AppendLine(@"#include ""CoreRP/ShaderLibrary/Color.hlsl"""); finalBuilder.AppendLine(@"#include ""CoreRP/ShaderLibrary/UnityInstancing.hlsl"""); finalBuilder.AppendLine(@"#include ""CoreRP/ShaderLibrary/EntityLighting.hlsl"""); finalBuilder.AppendLine(@"#include ""ShaderGraphLibrary/ShaderVariables.hlsl"""); finalBuilder.AppendLine(@"#include ""ShaderGraphLibrary/ShaderVariablesFunctions.hlsl"""); finalBuilder.AppendLine(@"#include ""ShaderGraphLibrary/Functions.hlsl"""); finalBuilder.AppendLines(shaderProperties.GetPropertiesDeclaration(0)); finalBuilder.AppendLines(surfaceInputs.GetShaderString(0)); finalBuilder.Concat(functionBuilder); finalBuilder.AppendLines(vertexInputs.GetShaderString(0)); finalBuilder.AppendLines(surfaceDescriptionStruct.GetShaderString(0)); finalBuilder.AppendLines(vertexShader.GetShaderString(0)); finalBuilder.AppendLines(surfaceDescriptionFunction.GetShaderString(0)); finalBuilder.AppendLine(@"ENDHLSL"); finalBuilder.AppendLines(ShaderGenerator.GetPreviewSubShader(node, requirements)); ListPool <INode> .Release(activeNodeList); } results.configuredTextures = shaderProperties.GetConfiguredTexutres(); ShaderSourceMap sourceMap; results.shader = finalBuilder.ToString(out sourceMap); results.sourceMap = sourceMap; return(results); }
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); }