public string GetSubshader(IMasterNode inMasterNode, GenerationMode mode) { var templatePath = GetTemplatePath("HDUnlitPassForward.template"); if (!File.Exists(templatePath)) return string.Empty; string passTemplate = File.ReadAllText(templatePath); var masterNode = inMasterNode as UnlitMasterNode; var subShader = new ShaderStringBuilder(); subShader.AppendLine("SubShader"); using(subShader.BlockScope()) { subShader.AppendLine("Tags{ \"RenderPipeline\" = \"HDRenderPipeline\"}"); subShader.AppendLine("Tags{ \"RenderType\" = \"Opaque\" }"); subShader.AppendLines( GetShaderPassFromTemplate( passTemplate, masterNode, m_UnlitPassForwardDepthOnly, mode)); subShader.AppendLines( GetShaderPassFromTemplate( passTemplate, masterNode, m_UnlitPassForwardOnly, mode)); } return subShader.ToString(); }
public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode) { string amplitude = GetSlotValue(kAmplitudeSlotId, generationMode); string steps = GetSlotValue(kStepsSlotId, generationMode); string uvs = GetSlotValue(kUVsSlotId, generationMode); string lod = GetSlotValue(kLodSlotId, generationMode); string lodThreshold = GetSlotValue(kLodThresholdSlotId, generationMode); string heightmap = GetSlotValue(kHeightmapSlotId, generationMode); string sampler = GetSlotValue(kHeightmapSamplerSlotId, generationMode); string tmpPOMParam = GetVariableNameForNode() + "_POM"; string tmpViewDir = GetVariableNameForNode() + "_ViewDir"; string tmpNdotV = GetVariableNameForNode() + "_NdotV"; string tmpMaxHeight = GetVariableNameForNode() + "_MaxHeight"; string tmpViewDirUV = GetVariableNameForNode() + "_ViewDirUV"; string tmpOutHeight = GetVariableNameForNode() + "_OutHeight"; sb.AppendLines($@" $precision3 {tmpViewDir} = IN.{CoordinateSpace.Tangent.ToVariableName(InterpolatorType.ViewDirection)} * GetDisplacementObjectScale().xzy; $precision {tmpNdotV} = {tmpViewDir}.z; $precision {tmpMaxHeight} = {amplitude} * 0.01; // cm in the interface so we multiply by 0.01 in the shader to convert in meter // Transform the view vector into the UV space. $precision3 {tmpViewDirUV} = normalize($precision3({tmpViewDir}.xy * {tmpMaxHeight}, {tmpViewDir}.z)); // TODO: skip normalize PerPixelHeightDisplacementParam {tmpPOMParam}; {tmpPOMParam}.uv = {uvs};"); sb.AppendLines($@" $precision {tmpOutHeight}; $precision2 {GetVariableNameForSlot(kParallaxUVsOutputSlotId)} = {uvs} + ParallaxOcclusionMapping{GetVariableNameForNode()}({lod}, {lodThreshold}, {steps}, {tmpViewDirUV}, {tmpPOMParam}, {tmpOutHeight}, TEXTURE2D_ARGS({heightmap}.tex, {sampler}.samplerstate)); $precision {GetVariableNameForSlot(kPixelDepthOffsetOutputSlotId)} = ({tmpMaxHeight} - {tmpOutHeight} * {tmpMaxHeight}) / max({tmpNdotV}, 0.0001); "); }
public static string GetPreviewSubShader(AbstractMaterialNode node, ShaderGraphRequirements shaderGraphRequirements) { 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()); if (node != null) { var outputSlot = node.GetOutputSlots <MaterialSlot>().FirstOrDefault(); if (outputSlot != null) { var result = string.Format("surf.{0}", node.GetVariableNameForSlot(outputSlot.id)); pixelShaderSurfaceRemap.AppendLine("return {0};", AdaptNodeOutputForPreview(node, outputSlot.id, result)); } else { pixelShaderSurfaceRemap.AppendLine("return 0;"); } } else { pixelShaderSurfaceRemap.AppendLine("return surf.PreviewOutput;"); } var res = subShaderTemplate.Replace("${Interpolators}", vertexOutputStruct.ToString()); res = res.Replace("${VertexShader}", vertexShader.ToString()); res = res.Replace("${LocalPixelShader}", pixelShader.ToString()); res = res.Replace("${SurfaceInputs}", pixelShaderSurfaceInputs.ToString()); res = res.Replace("${SurfaceOutputRemap}", pixelShaderSurfaceRemap.ToString()); return(res); }
public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode) { string amplitude = GetSlotValue(kAmplitudeSlotId, generationMode); string steps = GetSlotValue(kStepsSlotId, generationMode); string uvs = GetSlotValue(kUVsSlotId, generationMode); string tiling = GetSlotValue(kTilingSlotId, generationMode); string offset = GetSlotValue(kOffsetSlotId, generationMode); string primitiveSize = GetSlotValue(kPrimitiveSizeSlotId, generationMode); string lod = GetSlotValue(kLodSlotId, generationMode); string lodThreshold = GetSlotValue(kLodThresholdSlotId, generationMode); string heightmap = GetSlotValue(kHeightmapSlotId, generationMode); string sampler = GetSlotValue(kHeightmapSamplerSlotId, generationMode); string tmpPOMParam = GetVariableNameForNode() + "_POM"; string tmpViewDir = GetVariableNameForNode() + "_ViewDir"; string tmpNdotV = GetVariableNameForNode() + "_NdotV"; string tmpMaxHeight = GetVariableNameForNode() + "_MaxHeight"; string tmpViewDirUV = GetVariableNameForNode() + "_ViewDirUV"; string tmpOutHeight = GetVariableNameForNode() + "_OutHeight"; string tmpUVs = GetVariableNameForNode() + "_UVs"; string tmpUVSpaceScale = GetVariableNameForNode() + "_UVSpaceScale"; sb.AppendLines($@" $precision3 {tmpViewDir} = IN.{CoordinateSpace.Tangent.ToVariableName(InterpolatorType.ViewDirection)} * GetDisplacementObjectScale_$precision().xzy; $precision {tmpNdotV} = {tmpViewDir}.z; $precision {tmpMaxHeight} = {amplitude} * 0.01; // cm in the interface so we multiply by 0.01 in the shader to convert in meter {tmpMaxHeight} *= 2.0 / ( abs({tiling}.x) + abs({tiling}.y) ); // reduce height based on the tiling values $precision2 {tmpUVSpaceScale} = {tmpMaxHeight} * {tiling} / {primitiveSize}; // Transform the view vector into the UV space. $precision3 {tmpViewDirUV} = normalize($precision3({tmpViewDir}.xy * {tmpUVSpaceScale}, {tmpViewDir}.z)); // TODO: skip normalize PerPixelHeightDisplacementParam {tmpPOMParam}; $precision2 {tmpUVs} = {uvs} * {tiling} + {offset}; {tmpPOMParam}.uv = {heightmap}.GetTransformedUV({tmpUVs});"); // to avoid crashes when steps gets too big, and // to avoid divide by zero, we clamp it to the range [1, 256] // This should compile out when steps is a static value. steps = "max(min(" + steps + ", 256), 1)"; sb.AppendLines($@" $precision {tmpOutHeight}; $precision2 {GetVariableNameForSlot(kParallaxUVsOutputSlotId)} = {heightmap}.GetTransformedUV({tmpUVs}) + ParallaxOcclusionMapping{GetFunctionName()}({lod}, {lodThreshold}, {steps}, {tmpViewDirUV}, {tmpPOMParam}, {tmpOutHeight}, TEXTURE2D_ARGS({heightmap}.tex, {sampler}.samplerstate)); $precision {GetVariableNameForSlot(kPixelDepthOffsetOutputSlotId)} = ({tmpMaxHeight} - {tmpOutHeight} * {tmpMaxHeight}) / max({tmpNdotV}, 0.0001); "); }
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(); }
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(); }
private void ProcessIncludeCommand(Token includeCommand, int lineEnd) { if (Expect(includeCommand.s, includeCommand.end, '(')) { Token param = ParseString(includeCommand.s, includeCommand.end + 1, lineEnd); if (!param.IsValid()) { Error("ERROR: $include expected a string file path parameter", includeCommand.s, includeCommand.end + 1); } else { var includeLocation = Path.Combine(templatePath, param.GetString()); if (!File.Exists(includeLocation)) { Error("ERROR: $include cannot find file : " + includeLocation, includeCommand.s, param.start); } else { int endIndex = result.length; using (var temp = new ShaderStringBuilder()) { // Wrap in debug mode if (isDebug) { result.AppendLine("//-------------------------------------------------------------------------------------"); result.AppendLine("// TEMPLATE INCLUDE : " + param.GetString()); result.AppendLine("//-------------------------------------------------------------------------------------"); result.AppendNewLine(); } // Recursively process templates ProcessTemplateFile(includeLocation); // Wrap in debug mode if (isDebug) { result.AppendNewLine(); result.AppendLine("//-------------------------------------------------------------------------------------"); result.AppendLine("// END TEMPLATE INCLUDE : " + param.GetString()); result.AppendLine("//-------------------------------------------------------------------------------------"); } result.AppendNewLine(); // Required to enforce indentation rules // Append lines from this include into temporary StringBuilder // Reduce result length to remove this include temp.AppendLines(result.ToString(endIndex, result.length - endIndex)); result.length = endIndex; result.AppendLines(temp.ToCodeBlock()); } } } } }
public static void GenerateVertexDescriptionFunction( AbstractMaterialGraph graph, ShaderStringBuilder builder, FunctionRegistry functionRegistry, PropertyCollector shaderProperties, GenerationMode mode, List <AbstractMaterialNode> nodes, List <MaterialSlot> slots, string graphInputStructName = "VertexDescriptionInputs") { if (graph == null) { return; } GraphContext graphContext = new GraphContext(graphInputStructName); graph.CollectShaderProperties(shaderProperties, mode); builder.AppendLine("{0} PopulateVertexData(VertexDescriptionInputs IN)", k_VertexDescriptionStructName); using (builder.BlockScope()) { ShaderGenerator sg = new ShaderGenerator(); builder.AppendLine("{0} description = ({0})0;", k_VertexDescriptionStructName); foreach (var node in nodes) { var generatesFunction = node as IGeneratesFunction; if (generatesFunction != null) { functionRegistry.builder.currentNode = node; generatesFunction.GenerateNodeFunction(functionRegistry, graphContext, mode); } var generatesBodyCode = node as IGeneratesBodyCode; if (generatesBodyCode != null) { generatesBodyCode.GenerateNodeCode(sg, mode); } node.CollectShaderProperties(shaderProperties, mode); } builder.AppendLines(sg.GetShaderString(0)); foreach (var slot in slots) { var isSlotConnected = slot.owner.owner.GetEdges(slot.slotReference).Any(); var slotName = NodeUtils.GetHLSLSafeName(slot.shaderOutputName); var slotValue = isSlotConnected ? ((AbstractMaterialNode)slot.owner).GetSlotValue(slot.id, mode) : slot.GetDefaultValue(mode); builder.AppendLine("description.{0} = {1};", slotName, slotValue); } builder.AppendLine("return description;"); } }
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 void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode) { var heightmap = GetSlotValue(kHeightmapSlotId, generationMode); var samplerSlot = FindInputSlot <MaterialSlot>(kHeightmapSamplerSlotId); var edgesSampler = owner.GetEdges(samplerSlot.slotReference); var amplitude = GetSlotValue(kAmplitudeSlotId, generationMode); var uvs = GetSlotValue(kUVsSlotId, generationMode); sb.AppendLines(String.Format(@"$precision2 {5} = {4} + ParallaxMapping({0}.tex, {1}.samplerstate, IN.{2}, {3} * 0.01, {4});", heightmap, edgesSampler.Any() ? GetSlotValue(kHeightmapSamplerSlotId, generationMode) : heightmap, CoordinateSpace.Tangent.ToVariableName(InterpolatorType.ViewDirection), amplitude, // cm in the interface so we multiply by 0.01 in the shader to convert in meter uvs, GetSlotValue(kParallaxUVsOutputSlotId, generationMode) )); }
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()); }
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 bool GenerateShaderPass(AbstractMaterialNode masterNode, ShaderPass pass, GenerationMode mode, ActiveFields activeFields, ShaderGenerator result, List <string> sourceAssetDependencyPaths, List <Dependency[]> dependencies, string resourceClassName, string assemblyName) { // -------------------------------------------------- // 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(); masterNode.owner.CollectShaderKeywords(keywordCollector, mode); // Get upstream nodes from ShaderPass port mask List <AbstractMaterialNode> vertexNodes; List <AbstractMaterialNode> pixelNodes; GetUpstreamNodesForShaderPass(masterNode, 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; GetActiveFieldsAndPermutationsForNodes(masterNode, pass, keywordCollector, vertexNodes, pixelNodes, vertexNodePermutations, pixelNodePermutations, activeFields, out graphRequirements); // GET CUSTOM ACTIVE FIELDS HERE! // Get active fields from ShaderPass AddRequiredFields(pass.requiredAttributes, activeFields.baseInstance); AddRequiredFields(pass.requiredVaryings, activeFields.baseInstance); // Get Port references from ShaderPass var pixelSlots = FindMaterialSlotsOnNode(pass.pixelPorts, masterNode); var vertexSlots = FindMaterialSlotsOnNode(pass.vertexPorts, masterNode); // 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) { ShaderSpliceUtil.ApplyDependencies(instance, dependencies); } // -------------------------------------------------- // 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>"); } // Render state BuildRenderStatesFromPass(pass, ref spliceCommands); // -------------------------------------------------- // Pass Code // Pragmas using (var passPragmaBuilder = new ShaderStringBuilder()) { if (pass.pragmas != null) { foreach (string pragma in pass.pragmas) { passPragmaBuilder.AppendLine($"#pragma {pragma}"); } } if (passPragmaBuilder.length == 0) { passPragmaBuilder.AppendLine("// PassPragmas: <None>"); } spliceCommands.Add("PassPragmas", passPragmaBuilder.ToCodeBlack()); } // Includes using (var passIncludeBuilder = new ShaderStringBuilder()) { if (pass.includes != null) { foreach (string include in pass.includes) { passIncludeBuilder.AppendLine($"#include \"{include}\""); } } if (passIncludeBuilder.length == 0) { passIncludeBuilder.AppendLine("// PassIncludes: <None>"); } spliceCommands.Add("PassIncludes", passIncludeBuilder.ToCodeBlack()); } // Keywords using (var passKeywordBuilder = new ShaderStringBuilder()) { if (pass.keywords != null) { foreach (KeywordDescriptor keyword in pass.keywords) { passKeywordBuilder.AppendLine(keyword.ToDeclarationString()); } } if (passKeywordBuilder.length == 0) { passKeywordBuilder.AppendLine("// PassKeywords: <None>"); } spliceCommands.Add("PassKeywords", passKeywordBuilder.ToCodeBlack()); } // -------------------------------------------------- // Graph Vertex var vertexBuilder = new ShaderStringBuilder(); // If vertex modification enabled if (activeFields.baseInstance.Contains("features.graphVertex")) { // Setup string vertexGraphInputName = "VertexDescriptionInputs"; string vertexGraphOutputName = "VertexDescription"; string vertexGraphFunctionName = "VertexDescriptionFunction"; var vertexGraphInputGenerator = new ShaderGenerator(); var vertexGraphFunctionBuilder = new ShaderStringBuilder(); var vertexGraphOutputBuilder = new ShaderStringBuilder(); // Build vertex graph inputs ShaderSpliceUtil.BuildType(GetTypeForStruct("VertexDescriptionInputs", resourceClassName, assemblyName), activeFields, vertexGraphInputGenerator, isDebug); // Build vertex graph outputs // Add struct fields to active fields SubShaderGenerator.GenerateVertexDescriptionStruct(vertexGraphOutputBuilder, vertexSlots, vertexGraphOutputName, activeFields.baseInstance); // Build vertex graph functions from ShaderPass vertex port mask SubShaderGenerator.GenerateVertexDescriptionFunction( masterNode.owner as GraphData, vertexGraphFunctionBuilder, functionRegistry, propertyCollector, keywordCollector, mode, masterNode, vertexNodes, vertexNodePermutations, vertexSlots, vertexGraphInputName, vertexGraphFunctionName, vertexGraphOutputName); // Generate final shader strings vertexBuilder.AppendLines(vertexGraphInputGenerator.GetShaderString(0, false)); vertexBuilder.AppendNewLine(); vertexBuilder.AppendLines(vertexGraphOutputBuilder.ToString()); vertexBuilder.AppendNewLine(); vertexBuilder.AppendLines(vertexGraphFunctionBuilder.ToString()); } // Add to splice commands if (vertexBuilder.length == 0) { vertexBuilder.AppendLine("// GraphVertex: <None>"); } spliceCommands.Add("GraphVertex", vertexBuilder.ToCodeBlack()); // -------------------------------------------------- // Graph Pixel // Setup string pixelGraphInputName = "SurfaceDescriptionInputs"; string pixelGraphOutputName = "SurfaceDescription"; string pixelGraphFunctionName = "SurfaceDescriptionFunction"; var pixelGraphInputGenerator = new ShaderGenerator(); var pixelGraphOutputBuilder = new ShaderStringBuilder(); var pixelGraphFunctionBuilder = new ShaderStringBuilder(); // Build pixel graph inputs ShaderSpliceUtil.BuildType(GetTypeForStruct("SurfaceDescriptionInputs", resourceClassName, assemblyName), activeFields, pixelGraphInputGenerator, isDebug); // Build pixel graph outputs // Add struct fields to active fields SubShaderGenerator.GenerateSurfaceDescriptionStruct(pixelGraphOutputBuilder, pixelSlots, pixelGraphOutputName, activeFields.baseInstance); // Build pixel graph functions from ShaderPass pixel port mask SubShaderGenerator.GenerateSurfaceDescriptionFunction( pixelNodes, pixelNodePermutations, masterNode, masterNode.owner as GraphData, pixelGraphFunctionBuilder, functionRegistry, propertyCollector, keywordCollector, mode, pixelGraphFunctionName, pixelGraphOutputName, null, pixelSlots, pixelGraphInputName); using (var pixelBuilder = new ShaderStringBuilder()) { // Generate final shader strings pixelBuilder.AppendLines(pixelGraphInputGenerator.GetShaderString(0, false)); pixelBuilder.AppendNewLine(); pixelBuilder.AppendLines(pixelGraphOutputBuilder.ToString()); pixelBuilder.AppendNewLine(); pixelBuilder.AppendLines(pixelGraphFunctionBuilder.ToString()); // Add to splice commands if (pixelBuilder.length == 0) { pixelBuilder.AppendLine("// GraphPixel: <None>"); } spliceCommands.Add("GraphPixel", pixelBuilder.ToCodeBlack()); } // -------------------------------------------------- // Graph Functions if (functionBuilder.length == 0) { functionBuilder.AppendLine("// GraphFunctions: <None>"); } spliceCommands.Add("GraphFunctions", functionBuilder.ToCodeBlack()); // -------------------------------------------------- // Graph Keywords using (var keywordBuilder = new ShaderStringBuilder()) { keywordCollector.GetKeywordsDeclaration(keywordBuilder, mode); if (keywordBuilder.length == 0) { keywordBuilder.AppendLine("// GraphKeywords: <None>"); } spliceCommands.Add("GraphKeywords", keywordBuilder.ToCodeBlack()); } // -------------------------------------------------- // Graph Properties using (var propertyBuilder = new ShaderStringBuilder()) { propertyCollector.GetPropertiesDeclaration(propertyBuilder, mode, masterNode.owner.concretePrecision); if (propertyBuilder.length == 0) { propertyBuilder.AppendLine("// GraphProperties: <None>"); } spliceCommands.Add("GraphProperties", propertyBuilder.ToCodeBlack()); } // -------------------------------------------------- // Graph Defines using (var graphDefines = new ShaderStringBuilder()) { graphDefines.AppendLine("#define {0}", pass.referenceName); if (graphRequirements.permutationCount > 0) { List <int> activePermutationIndices; // Depth Texture activePermutationIndices = graphRequirements.allPermutations.instances .Where(p => p.requirements.requiresDepthTexture) .Select(p => p.permutationIndex) .ToList(); if (activePermutationIndices.Count > 0) { graphDefines.AppendLine(KeywordUtil.GetKeywordPermutationSetConditional(activePermutationIndices)); graphDefines.AppendLine("#define REQUIRE_DEPTH_TEXTURE"); graphDefines.AppendLine("#endif"); } // Opaque Texture activePermutationIndices = graphRequirements.allPermutations.instances .Where(p => p.requirements.requiresCameraOpaqueTexture) .Select(p => p.permutationIndex) .ToList(); if (activePermutationIndices.Count > 0) { graphDefines.AppendLine(KeywordUtil.GetKeywordPermutationSetConditional(activePermutationIndices)); graphDefines.AppendLine("#define REQUIRE_OPAQUE_TEXTURE"); graphDefines.AppendLine("#endif"); } } else { // Depth Texture if (graphRequirements.baseInstance.requirements.requiresDepthTexture) { graphDefines.AppendLine("#define REQUIRE_DEPTH_TEXTURE"); } // Opaque Texture if (graphRequirements.baseInstance.requirements.requiresCameraOpaqueTexture) { graphDefines.AppendLine("#define REQUIRE_OPAQUE_TEXTURE"); } } // Add to splice commands spliceCommands.Add("GraphDefines", graphDefines.ToCodeBlack()); } // -------------------------------------------------- // Main // Main include is expected to contain vert/frag definitions for the pass // This must be defined after all graph code using (var mainBuilder = new ShaderStringBuilder()) { mainBuilder.AppendLine($"#include \"{pass.varyingsInclude}\""); mainBuilder.AppendLine($"#include \"{pass.passInclude}\""); // Add to splice commands spliceCommands.Add("MainInclude", mainBuilder.ToCodeBlack()); } // -------------------------------------------------- // Debug // Debug output all active fields using (var debugBuilder = new ShaderStringBuilder()) { if (isDebug) { // Active fields debugBuilder.AppendLine("// ACTIVE FIELDS:"); foreach (string field in activeFields.baseInstance.fields) { debugBuilder.AppendLine("// " + field); } } if (debugBuilder.length == 0) { debugBuilder.AppendLine("// <None>"); } // Add to splice commands spliceCommands.Add("Debug", debugBuilder.ToCodeBlack()); } // -------------------------------------------------- // Finalize // Get Template string templateLocation = GetTemplatePath("PassMesh.template"); if (!File.Exists(templateLocation)) { return(false); } // Get Template preprocessor string templatePath = "Assets/com.unity.render-pipelines.universal/Editor/ShaderGraph/Templates"; var templatePreprocessor = new ShaderSpliceUtil.TemplatePreprocessor(activeFields, spliceCommands, isDebug, templatePath, sourceAssetDependencyPaths, assemblyName, resourceClassName); // Process Template templatePreprocessor.ProcessTemplateFile(templateLocation); result.AddShaderChunk(templatePreprocessor.GetShaderCode().ToString(), false); return(true); }
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;"); } }
private void ProcessIncludeCommand(Token includeCommand, int lineEnd) { if (Expect(includeCommand.s, includeCommand.end, '(')) { Token param = ParseString(includeCommand.s, includeCommand.end + 1, lineEnd); if (!param.IsValid()) { Error("ERROR: $include expected a string file path parameter", includeCommand.s, includeCommand.end + 1); } else { bool found = false; string includeLocation = null; // Use reverse order in the array, higher number element have higher priority in case $include exist in several directories for (int i = templatePaths.Length - 1; i >= 0; i--) { string templatePath = templatePaths[i]; includeLocation = Path.Combine(templatePath, param.GetString()); if (File.Exists(includeLocation)) { found = true; break; } } if (!found) { string errorStr = "ERROR: $include cannot find file : " + param.GetString() + ". Looked into:\n"; foreach (string templatePath in templatePaths) { errorStr += "// " + templatePath + "\n"; } Error(errorStr, includeCommand.s, param.start); } else { int endIndex = result.length; using (var temp = new ShaderStringBuilder()) { // Wrap in debug mode if (isDebug) { result.AppendLine("//-------------------------------------------------------------------------------------"); result.AppendLine("// TEMPLATE INCLUDE : " + param.GetString()); result.AppendLine("//-------------------------------------------------------------------------------------"); result.AppendNewLine(); } // Recursively process templates ProcessTemplateFile(includeLocation); // Wrap in debug mode if (isDebug) { result.AppendNewLine(); result.AppendLine("//-------------------------------------------------------------------------------------"); result.AppendLine("// END TEMPLATE INCLUDE : " + param.GetString()); result.AppendLine("//-------------------------------------------------------------------------------------"); } result.AppendNewLine(); // Required to enforce indentation rules // Append lines from this include into temporary StringBuilder // Reduce result length to remove this include temp.AppendLines(result.ToString(endIndex, result.length - endIndex)); result.length = endIndex; result.AppendLines(temp.ToCodeBlock()); } } } } }