public void GetKeywordsDeclaration(ShaderStringBuilder builder, GenerationMode mode) { if (keywords.Count == 0) { return; } // Declare keywords foreach (var keyword in keywords) { // Hardcode active keywords in preview to reduce compiled variants if (mode == GenerationMode.Preview) { string declaration = keyword.GetKeywordPreviewDeclarationString(); if (!string.IsNullOrEmpty(declaration)) { builder.AppendLine(declaration); } } else { string declaration = keyword.GetKeywordDeclarationString(); if (!string.IsNullOrEmpty(declaration)) { builder.AppendLine(declaration); } } } // Declare another keyword per permutation for simpler if/defs in the graph code builder.AppendNewLine(); KeywordUtil.GetKeywordPermutationDeclarations(builder, permutations); builder.AppendNewLine(); }
public string GetDotsInstancingPropertiesDeclaration(GenerationMode mode) { // Hybrid V1 needs to declare a special macro to that is injected into // builtin instancing variables. // Hybrid V2 does not need it. #if !ENABLE_HYBRID_RENDERER_V2 var builder = new ShaderStringBuilder(); var batchAll = (mode == GenerationMode.Preview); // build a list of all HLSL properties var hybridHLSLProps = new List <HLSLProperty>(); properties.ForEach(p => p.ForeachHLSLProperty(h => { if (h.declaration == HLSLDeclaration.HybridPerInstance) { hybridHLSLProps.Add(h); } })); if (hybridHLSLProps.Any()) { builder.AppendLine("#if defined(UNITY_HYBRID_V1_INSTANCING_ENABLED)"); builder.AppendLine("#define HYBRID_V1_CUSTOM_ADDITIONAL_MATERIAL_VARS \\"); int count = 0; foreach (var prop in hybridHLSLProps) { // Combine multiple UNITY_DEFINE_INSTANCED_PROP lines with \ so the generated // macro expands into multiple definitions if there are more than one. if (count > 0) { builder.Append("\\"); builder.AppendNewLine(); } builder.Append("UNITY_DEFINE_INSTANCED_PROP("); builder.Append(prop.GetValueTypeString()); builder.Append(", "); builder.Append(prop.name); builder.Append("_Array)"); count++; } builder.AppendNewLine(); foreach (var prop in hybridHLSLProps) { string varName = $"{prop.name}_Array"; builder.AppendLine("#define {0} UNITY_ACCESS_INSTANCED_PROP(unity_Builtins0, {1})", prop.name, varName); } } builder.AppendLine("#endif"); return(builder.ToString()); #else return(""); #endif }
internal override void AppendNonBatchablePropertyDeclarations(ShaderStringBuilder builder, string delimiter = ";") { int numLayers = value.layers.Count; if (numLayers > 0) { if (!value.procedural) { // declare regular texture properties (for fallback case) for (int i = 0; i < value.layers.Count; i++) { string layerRefName = value.layers[i].layerRefName; builder.AppendLine( $"TEXTURE2D({layerRefName}); SAMPLER(sampler{layerRefName}); {concretePrecision.ToShaderString()}4 {layerRefName}_TexelSize;"); } } // declare texture stack builder.AppendIndentation(); builder.Append("DECLARE_STACK"); builder.Append((numLayers <= 1) ? "" : numLayers.ToString()); builder.Append("("); builder.Append(referenceName); builder.Append(","); for (int i = 0; i < value.layers.Count; i++) { if (i != 0) { builder.Append(","); } builder.Append(value.layers[i].layerRefName); } builder.Append(")"); builder.Append(delimiter); builder.AppendNewLine(); // declare the actual virtual texture property "variable" as a macro define to the BuildVTProperties function builder.AppendIndentation(); builder.Append("#define "); builder.Append(referenceName); builder.Append(" AddTextureType(BuildVTProperties_"); builder.Append(referenceName); builder.Append("()"); for (int i = 0; i < value.layers.Count; i++) { builder.Append(","); builder.Append("TEXTURETYPE_"); builder.Append(value.layers[i].layerTextureType.ToString().ToUpper()); } builder.Append(")"); builder.AppendNewLine(); } }
public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode) { var inputValue = GetSlotValue(InputSlotId, generationMode); var outputValue = GetSlotValue(OutputSlotId, generationMode); sb.AppendLine("{0} {1};", FindOutputSlot <MaterialSlot>(OutputSlotId).concreteValueType.ToShaderString(), GetVariableNameForSlot(OutputSlotId)); if (!generationMode.IsPreview()) { sb.AppendIndentation(); sb.Append("{0} _{1}_Flip = {0} ({2}", FindInputSlot <MaterialSlot>(InputSlotId).concreteValueType.ToShaderString(), GetVariableNameForNode(), Convert.ToInt32(m_RedChannel)); if (channelCount > 1) { sb.Append(", {0}", Convert.ToInt32(m_GreenChannel)); } if (channelCount > 2) { sb.Append(", {0}", Convert.ToInt32(m_BlueChannel)); } if (channelCount > 3) { sb.Append(", {0}", Convert.ToInt32(m_AlphaChannel)); } sb.Append(");"); sb.AppendNewLine(); } sb.AppendLine("{0}({1}, _{2}_Flip, {3});", GetFunctionName(), inputValue, GetVariableNameForNode(), outputValue); }
public void GetPropertiesDeclaration(ShaderStringBuilder builder, GenerationMode mode, ConcretePrecision inheritedPrecision) { foreach (var prop in properties) { prop.SetConcretePrecision(inheritedPrecision); } var batchAll = mode == GenerationMode.Preview; builder.AppendLine("CBUFFER_START(UnityPerMaterial)"); foreach (var prop in properties.Where(n => batchAll || (n.generatePropertyBlock && n.isBatchable))) { builder.AppendLine(prop.GetPropertyDeclarationString()); } builder.AppendLine("CBUFFER_END"); builder.AppendNewLine(); if (batchAll) { return; } foreach (var prop in properties.Where(n => !n.isBatchable || !n.generatePropertyBlock)) { builder.AppendLine(prop.GetPropertyDeclarationString()); } }
void AppendVtSample(ShaderStringBuilder sb, string propertiesName, string vtInputVariable, string infoVariable, int layerIndex, string outputVariableName) { sb.AppendIndentation(); sb.Append(outputVariableName); sb.Append(" = "); sb.Append("SampleVTLayerWithTextureType("); sb.Append(propertiesName); sb.Append(", "); sb.Append(vtInputVariable); sb.Append(", "); sb.Append(infoVariable); sb.Append(", "); sb.Append(layerIndex.ToString()); sb.Append(");"); sb.AppendNewLine(); }
public void GetPropertiesDeclaration(ShaderStringBuilder builder, GenerationMode mode, ConcretePrecision inheritedPrecision) { foreach (var prop in properties) { prop.ValidateConcretePrecision(inheritedPrecision); } var batchAll = mode == GenerationMode.Preview; builder.AppendLine("CBUFFER_START(UnityPerMaterial)"); int instancedCount = 0; foreach (var prop in properties.Where(n => batchAll || (n.generatePropertyBlock && n.isBatchable))) { if (!prop.gpuInstanced) { builder.AppendLine(prop.GetPropertyDeclarationString()); } else { instancedCount++; } } if (instancedCount > 0) { builder.AppendLine("#ifndef UNITY_DOTS_INSTANCING_ENABLED"); foreach (var prop in properties.Where(n => batchAll || (n.generatePropertyBlock && n.isBatchable))) { if (prop.gpuInstanced) { builder.AppendLine(prop.GetPropertyDeclarationString()); } } builder.AppendLine("#endif"); } builder.AppendLine("CBUFFER_END"); builder.AppendNewLine(); if (batchAll) { return; } foreach (var prop in properties.Where(n => !n.isBatchable || !n.generatePropertyBlock)) { builder.AppendLine(prop.GetPropertyDeclarationString()); } }
public void GetPropertiesDeclaration(ShaderStringBuilder builder) { builder.AppendLine("CBUFFER_START(UnityPerMaterial)"); foreach (var prop in m_Properties.Where(n => n.isBatchable && n.generatePropertyBlock)) { builder.AppendLine(prop.GetPropertyDeclarationString()); } builder.AppendLine("CBUFFER_END"); builder.AppendNewLine(); foreach (var prop in m_Properties.Where(n => !n.isBatchable || !n.generatePropertyBlock)) { builder.AppendLine(prop.GetPropertyDeclarationString()); } }
private void GenStruct(string structName, ShaderStringBuilder builder, string makeDefine = "") { builder.AppendLine($"struct {structName}"); builder.AppendLine("{"); using (builder.IndentScope()) { foreach (var bn in customBlockNodes) { builder.AppendLine($"float{(int)bn.customWidth} {bn.customName};"); } } builder.AppendLine("};"); if (makeDefine != null && makeDefine != "") { builder.AppendLine($"#define {makeDefine}"); } builder.AppendNewLine(); }
public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode) { bool success = false; if (IsSlotConnected(VirtualTextureInputId)) { var vtProperty = GetSlotProperty(VirtualTextureInputId) as VirtualTextureShaderProperty; if (vtProperty != null) { var layerOutputVariables = new List <string>(); int layerCount = vtProperty.value.layers.Count; for (int i = 0; i < layerCount; i++) { if (IsSlotConnected(OutputSlotIds[i])) { // declare output variables up front string layerOutputVariable = GetVariableNameForSlot(OutputSlotIds[i]); sb.AppendLine("$precision4 " + layerOutputVariable + ";"); layerOutputVariables.Add(layerOutputVariable); } } if (layerOutputVariables.Count > 0) { // assign feedback variable sb.AppendIndentation(); if (!noFeedback) { sb.Append("float4 "); sb.Append(GetFeedbackVariableName()); sb.Append(" = "); } sb.Append(GetFunctionName(out var unused)); sb.Append("("); sb.Append(GetSlotValue(UVInputId, generationMode)); switch (lodCalculation) { case LodCalculation.VtLevel_Lod: case LodCalculation.VtLevel_Bias: sb.Append(", "); sb.Append((lodCalculation == LodCalculation.VtLevel_Lod) ? GetSlotValue(LODInputId, generationMode) : GetSlotValue(BiasInputId, generationMode)); break; case LodCalculation.VtLevel_Derivatives: sb.Append(", "); sb.Append(GetSlotValue(DxInputId, generationMode)); sb.Append(", "); sb.Append(GetSlotValue(DyInputId, generationMode)); break; } sb.Append(", "); sb.Append(vtProperty.referenceName); foreach (string layerOutputVariable in layerOutputVariables) { sb.Append(", "); sb.Append(layerOutputVariable); } sb.Append(");"); sb.AppendNewLine(); success = true; } } } if (!success) { // set all outputs to zero for (int i = 0; i < kMaxLayers; i++) { if (IsSlotConnected(OutputSlotIds[i])) { // declare output variables up front string layerOutputVariable = GetVariableNameForSlot(OutputSlotIds[i]); sb.AppendLine("$precision4 " + layerOutputVariable + " = 0;"); } } // TODO: should really just disable feedback in this case (need different feedback interface to do this) sb.AppendLine("$precision4 " + GetFeedbackVariableName() + " = 1;"); } }
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 void ProcessTemplateLine(string line, int start, int end) { bool appendEndln = true; int cur = start; while (cur < end) { // find an escape code '$' int dollar = line.IndexOf('$', cur, end - cur); if (dollar < 0) { // no escape code found in the remaining code -- just append the rest verbatim AppendSubstring(line, cur, true, end, false); break; } else { // found $ escape sequence Token command = ParseIdentifier(line, dollar + 1, end); if (!command.IsValid()) { Error("ERROR: $ must be followed by a command string (if, splice, or include)", line, dollar + 1); break; } else { if (command.Is("include")) { ProcessIncludeCommand(command, end); appendEndln = false; break; // include command always ignores the rest of the line, error or not } else if (command.Is("splice")) { if (!ProcessSpliceCommand(command, end, ref cur)) { // error, skip the rest of the line break; } } else { // let's see if it is a predicate Token predicate = ParseUntil(line, dollar + 1, end, ':'); if (!predicate.IsValid()) { Error("ERROR: unrecognized command: " + command.GetString(), line, command.start); break; } else { if (!ProcessPredicate(predicate, end, ref cur, ref appendEndln)) { break; // skip the rest of the line } } } } } } if (appendEndln) { result.AppendNewLine(); } }
public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode) { if (asset == null || hasError) { var outputSlots = new List <MaterialSlot>(); GetOutputSlots(outputSlots); var outputPrecision = asset != null ? asset.outputPrecision : ConcretePrecision.Single; foreach (var slot in outputSlots) { sb.AppendLine($"{slot.concreteValueType.ToShaderString(outputPrecision)} {GetVariableNameForSlot(slot.id)} = {slot.GetDefaultValue(GenerationMode.ForReals)};"); } return; } var inputVariableName = $"_{GetVariableNameForNode()}"; GenerationUtils.GenerateSurfaceInputTransferCode(sb, asset.requirements, asset.inputStructName, inputVariableName); foreach (var outSlot in asset.outputs) { sb.AppendLine("{0} {1};", outSlot.concreteValueType.ToShaderString(asset.outputPrecision), GetVariableNameForSlot(outSlot.id)); } var arguments = new List <string>(); foreach (var prop in asset.inputs) { prop.ValidateConcretePrecision(asset.graphPrecision); var inSlotId = m_PropertyIds[m_PropertyGuids.IndexOf(prop.guid.ToString())]; arguments.Add(GetSlotValue(inSlotId, generationMode, prop.concretePrecision)); } // pass surface inputs through arguments.Add(inputVariableName); foreach (var outSlot in asset.outputs) { arguments.Add(GetVariableNameForSlot(outSlot.id)); } foreach (var feedbackSlot in asset.vtFeedbackVariables) { string feedbackVar = GetVariableNameForNode() + "_" + feedbackSlot; sb.AppendLine("{0} {1};", ConcreteSlotValueType.Vector4.ToShaderString(ConcretePrecision.Single), feedbackVar); arguments.Add(feedbackVar); } sb.AppendIndentation(); sb.Append(asset.functionName); sb.Append("("); bool firstArg = true; foreach (var arg in arguments) { if (!firstArg) { sb.Append(", "); } firstArg = false; sb.Append(arg); } sb.Append(");"); sb.AppendNewLine(); }
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 GenerationResults GetShader(this AbstractMaterialGraph graph, AbstractMaterialNode node, GenerationMode mode, string name) { // ----------------------------------------------------- // // SETUP // // ----------------------------------------------------- // // ------------------------------------- // String builders var finalShader = new ShaderStringBuilder(); var results = new GenerationResults(); bool isUber = node == null; var shaderProperties = new PropertyCollector(); 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); // ------------------------------------- // Get Slot and Node lists 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 slots = new List <MaterialSlot>(); foreach (var activeNode in isUber ? activeNodeList.Where(n => ((AbstractMaterialNode)n).hasPreview) : ((INode)node).ToEnumerable()) { if (activeNode is IMasterNode || activeNode is SubGraphOutputNode) { slots.AddRange(activeNode.GetInputSlots <MaterialSlot>()); } else { slots.AddRange(activeNode.GetOutputSlots <MaterialSlot>()); } } // ------------------------------------- // Get Requirements var requirements = ShaderGraphRequirements.FromNodes(activeNodeList, ShaderStageCapability.Fragment); // ------------------------------------- // Add preview shader output property results.outputIdProperty = new Vector1ShaderProperty { displayName = "OutputId", generatePropertyBlock = false, value = -1 }; if (isUber) { shaderProperties.AddShaderProperty(results.outputIdProperty); } // ----------------------------------------------------- // // 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 surfaceDescriptionInputStruct.AppendLine("struct SurfaceDescriptionInputs"); using (surfaceDescriptionInputStruct.BlockSemicolonScope()) { ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresNormal, InterpolatorType.Normal, surfaceDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresTangent, InterpolatorType.Tangent, surfaceDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresBitangent, InterpolatorType.BiTangent, surfaceDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresViewDir, InterpolatorType.ViewDirection, surfaceDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresPosition, InterpolatorType.Position, surfaceDescriptionInputStruct); if (requirements.requiresVertexColor) { surfaceDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.VertexColor); } if (requirements.requiresScreenPosition) { surfaceDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.ScreenPosition); } 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()) { surfaceDescriptionInputStruct.AppendLine("half4 {0};", channel.GetUVName()); } } // ------------------------------------- // Generate Output structure for Surface Description function GenerateSurfaceDescriptionStruct(surfaceDescriptionStruct, slots, !isUber); // ------------------------------------- // Generate Surface Description function GenerateSurfaceDescriptionFunction( activeNodeList, node, graph, surfaceDescriptionFunction, functionRegistry, shaderProperties, requirements, mode, outputIdProperty: results.outputIdProperty); // ----------------------------------------------------- // // GENERATE VERTEX > PIXEL PIPELINE // // ----------------------------------------------------- // // ------------------------------------- // Generate Input structure for Vertex shader GenerateApplicationVertexInputs(requirements, vertexInputs); // ----------------------------------------------------- // // FINALIZE // // ----------------------------------------------------- // // ------------------------------------- // Build final shader finalShader.AppendLine(@"Shader ""{0}""", name); using (finalShader.BlockScope()) { finalShader.AppendLine("Properties"); using (finalShader.BlockScope()) { finalShader.AppendLines(shaderProperties.GetPropertiesBlock(0)); } finalShader.AppendNewLine(); finalShader.AppendLine(@"HLSLINCLUDE"); finalShader.AppendLine("#define USE_LEGACY_UNITY_MATRIX_VARIABLES"); finalShader.AppendLine(@"#include ""CoreRP/ShaderLibrary/Common.hlsl"""); finalShader.AppendLine(@"#include ""CoreRP/ShaderLibrary/Packing.hlsl"""); finalShader.AppendLine(@"#include ""CoreRP/ShaderLibrary/Color.hlsl"""); finalShader.AppendLine(@"#include ""CoreRP/ShaderLibrary/UnityInstancing.hlsl"""); finalShader.AppendLine(@"#include ""CoreRP/ShaderLibrary/EntityLighting.hlsl"""); finalShader.AppendLine(@"#include ""ShaderGraphLibrary/ShaderVariables.hlsl"""); finalShader.AppendLine(@"#include ""ShaderGraphLibrary/ShaderVariablesFunctions.hlsl"""); finalShader.AppendLine(@"#include ""ShaderGraphLibrary/Functions.hlsl"""); finalShader.AppendNewLine(); finalShader.AppendLines(shaderProperties.GetPropertiesDeclaration(0)); 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 <INode> .Release(activeNodeList); } // ------------------------------------- // Finalize results.configuredTextures = shaderProperties.GetConfiguredTexutres(); ShaderSourceMap sourceMap; results.shader = finalShader.ToString(out sourceMap); results.sourceMap = sourceMap; return(results); }
public void GetPropertiesDeclaration(ShaderStringBuilder builder, GenerationMode mode, ConcretePrecision inheritedPrecision) { foreach (var prop in properties) { prop.ValidateConcretePrecision(inheritedPrecision); } // build a list of all HLSL properties var hlslProps = BuildHLSLPropertyList(); if (mode == GenerationMode.Preview) { builder.AppendLine("CBUFFER_START(UnityPerMaterial)"); // all non-gpu instanced properties (even non-batchable ones!) // this is because for preview we convert all properties to UnityPerMaterial properties // as we will be submitting the default preview values via the Material.. :) foreach (var h in hlslProps) { if ((h.declaration == HLSLDeclaration.UnityPerMaterial) || (h.declaration == HLSLDeclaration.Global)) { h.AppendTo(builder); } } // gpu-instanced properties var gpuInstancedProps = hlslProps.Where(h => h.declaration == HLSLDeclaration.HybridPerInstance); if (gpuInstancedProps.Any()) { builder.AppendLine("#ifdef UNITY_HYBRID_V1_INSTANCING_ENABLED"); foreach (var h in gpuInstancedProps) { h.AppendTo(builder, name => name + "_dummy"); } builder.AppendLine("#else // V2"); foreach (var h in gpuInstancedProps) { h.AppendTo(builder); } builder.AppendLine("#endif"); } builder.AppendLine("CBUFFER_END"); return; } // Hybrid V1 generates a special version of UnityPerMaterial, which has dummy constants for // instanced properties, and regular constants for other properties. // Hybrid V2 generates a perfectly normal UnityPerMaterial, but needs to append // a UNITY_DOTS_INSTANCING_START/END block after it that contains the instanced properties. #if !ENABLE_HYBRID_RENDERER_V2 builder.AppendLine("CBUFFER_START(UnityPerMaterial)"); // non-GPU-instanced batchable properties go first in the UnityPerMaterial cbuffer foreach (var h in hlslProps) { if (h.declaration == HLSLDeclaration.UnityPerMaterial) { h.AppendTo(builder); } } // followed by GPU-instanced batchable properties var gpuInstancedProperties = hlslProps.Where(h => h.declaration == HLSLDeclaration.HybridPerInstance); if (gpuInstancedProperties.Any()) { builder.AppendLine("#ifdef UNITY_HYBRID_V1_INSTANCING_ENABLED"); foreach (var hlslProp in gpuInstancedProperties) { hlslProp.AppendTo(builder, name => name + "_dummy"); } builder.AppendLine("#else"); foreach (var hlslProp in gpuInstancedProperties) { hlslProp.AppendTo(builder); } builder.AppendLine("#endif"); } builder.AppendLine("CBUFFER_END"); #else // TODO: need to test this path with HYBRID_RENDERER_V2 ... builder.AppendLine("CBUFFER_START(UnityPerMaterial)"); int instancedCount = 0; foreach (var h in hlslProps) { if (h.declaration == HLSLDeclaration.UnityPerMaterial) { h.AppendTo(builder); } else if (h.declaration == HLSLDeclaration.HybridPerInstance) { instancedCount++; } } if (instancedCount > 0) { builder.AppendLine("// Hybrid instanced properties"); foreach (var h in hlslProps.Where(h => h.declaration == HLSLDeclaration.HybridPerInstance)) { h.AppendTo(builder); } } builder.AppendLine("CBUFFER_END"); if (instancedCount > 0) { builder.AppendLine("#if defined(UNITY_DOTS_INSTANCING_ENABLED)"); builder.AppendLine("// DOTS instancing definitions"); builder.AppendLine("UNITY_DOTS_INSTANCING_START(MaterialPropertyMetadata)"); foreach (var h in hlslProps.Where(h => h.declaration == HLSLDeclaration.HybridPerInstance)) { var n = h.name; string type = h.GetValueTypeString(); builder.AppendLine($" UNITY_DOTS_INSTANCED_PROP({type}, {n})"); } builder.AppendLine("UNITY_DOTS_INSTANCING_END(MaterialPropertyMetadata)"); builder.AppendLine("// DOTS instancing usage macros"); foreach (var h in hlslProps.Where(h => h.declaration == HLSLDeclaration.HybridPerInstance)) { var n = h.name; string type = h.GetValueTypeString(); builder.AppendLine($"#define {n} UNITY_ACCESS_DOTS_INSTANCED_PROP_FROM_MACRO({type}, Metadata_{n})"); } builder.AppendLine("#endif"); } #endif builder.AppendNewLine(); builder.AppendLine("// Object and Global properties"); foreach (var h in hlslProps) { if (h.declaration == HLSLDeclaration.Global) { h.AppendTo(builder); } } }
public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode) { var outputGraphPrecision = asset?.outputGraphPrecision ?? GraphPrecision.Single; var outputPrecision = outputGraphPrecision.ToConcrete(concretePrecision); if (asset == null || hasError) { var outputSlots = new List <MaterialSlot>(); GetOutputSlots(outputSlots); foreach (var slot in outputSlots) { sb.AppendLine($"{slot.concreteValueType.ToShaderString(outputPrecision)} {GetVariableNameForSlot(slot.id)} = {slot.GetDefaultValue(GenerationMode.ForReals)};"); } return; } var inputVariableName = $"_{GetVariableNameForNode()}"; GenerationUtils.GenerateSurfaceInputTransferCode(sb, asset.requirements, asset.inputStructName, inputVariableName); // declare output variables foreach (var outSlot in asset.outputs) { sb.AppendLine("{0} {1};", outSlot.concreteValueType.ToShaderString(outputPrecision), GetVariableNameForSlot(outSlot.id)); } var arguments = new List <string>(); foreach (AbstractShaderProperty prop in asset.inputs) { // setup the property concrete precision (fallback to node concrete precision when it's switchable) prop.SetupConcretePrecision(this.concretePrecision); var inSlotId = m_PropertyIds[m_PropertyGuids.IndexOf(prop.guid.ToString())]; arguments.Add(GetSlotValue(inSlotId, generationMode, prop.concretePrecision)); if (prop.isConnectionTestable) { arguments.Add(IsSlotConnected(inSlotId) ? "true" : "false"); } } var dropdowns = asset.dropdowns; foreach (var dropdown in dropdowns) { var name = GetDropdownEntryName(dropdown.referenceName); if (dropdown.ContainsEntry(name)) { arguments.Add(dropdown.IndexOfName(name).ToString()); } else { arguments.Add(dropdown.value.ToString()); } } // pass surface inputs through arguments.Add(inputVariableName); foreach (var outSlot in asset.outputs) { arguments.Add(GetVariableNameForSlot(outSlot.id)); } foreach (var feedbackSlot in asset.vtFeedbackVariables) { string feedbackVar = GetVariableNameForNode() + "_" + feedbackSlot; sb.AppendLine("{0} {1};", ConcreteSlotValueType.Vector4.ToShaderString(ConcretePrecision.Single), feedbackVar); arguments.Add(feedbackVar); } sb.AppendIndentation(); sb.Append(asset.functionName); sb.Append("("); bool firstArg = true; foreach (var arg in arguments) { if (!firstArg) { sb.Append(", "); } firstArg = false; sb.Append(arg); } sb.Append(");"); sb.AppendNewLine(); }
public static void GetKeywordPermutationDeclarations(ShaderStringBuilder sb, List <List <KeyValuePair <ShaderKeyword, int> > > permutations) { if (permutations.Count == 0) { return; } for (int p = 0; p < permutations.Count; p++) { // ShaderStringBuilder.Append doesnt apply indentation sb.AppendIndentation(); // Append correct if bool isLast = false; if (p == 0) { sb.Append("#if "); } else if (p == permutations.Count - 1) { sb.Append("#else"); isLast = true; } else { sb.Append("#elif "); } // Last permutation is always #else if (!isLast) { // Track whether && is required bool appendAnd = false; // Iterate all keywords that are part of the permutation for (int i = 0; i < permutations[p].Count; i++) { // When previous keyword was inserted subsequent requires && string and = appendAnd ? " && " : string.Empty; switch (permutations[p][i].Key.keywordType) { case KeywordType.Enum: { sb.Append($"{and}defined({permutations[p][i].Key.referenceName}_{permutations[p][i].Key.entries[permutations[p][i].Value].referenceName})"); appendAnd = true; break; } case KeywordType.Boolean: { // HLSL does not support a !value predicate if (permutations[p][i].Value != 0) { continue; } sb.Append($"{and}defined({permutations[p][i].Key.referenceName})"); appendAnd = true; break; } default: throw new ArgumentOutOfRangeException(); } } } sb.AppendNewLine(); // Define the matching permutation keyword sb.IncreaseIndent(); sb.AppendLine($"#define KEYWORD_PERMUTATION_{p}"); sb.DecreaseIndent(); } // End statement sb.AppendLine("#endif"); }
public void GetPropertiesDeclaration(ShaderStringBuilder builder, GenerationMode mode, ConcretePrecision defaultPrecision) { foreach (var prop in properties) { // set up switched properties to use the inherited precision prop.SetupConcretePrecision(defaultPrecision); } // build a list of all HLSL properties var hlslProps = BuildHLSLPropertyList(); if (mode == GenerationMode.Preview) { builder.AppendLine("CBUFFER_START(UnityPerMaterial)"); // all non-gpu instanced properties (even non-batchable ones!) // this is because for preview we convert all properties to UnityPerMaterial properties // as we will be submitting the default preview values via the Material.. :) foreach (var h in hlslProps) { if ((h.declaration == HLSLDeclaration.UnityPerMaterial) || (h.declaration == HLSLDeclaration.Global)) { h.AppendTo(builder); } } // DOTS instanced properties var dotsInstancedProperties = hlslProps.Where(h => h.declaration == HLSLDeclaration.HybridPerInstance); if (dotsInstancedProperties.Any()) { foreach (var h in dotsInstancedProperties) { h.AppendTo(builder); } } builder.AppendLine("CBUFFER_END"); builder.AppendLine("#define UNITY_ACCESS_HYBRID_INSTANCED_PROP(var, type) var"); return; } builder.AppendLine("CBUFFER_START(UnityPerMaterial)"); int instancedCount = 0; foreach (var h in hlslProps) { if (h.declaration == HLSLDeclaration.UnityPerMaterial) { h.AppendTo(builder); } else if (h.declaration == HLSLDeclaration.HybridPerInstance) { instancedCount++; } } if (instancedCount > 0) { builder.AppendLine("// Hybrid instanced properties"); foreach (var h in hlslProps.Where(h => h.declaration == HLSLDeclaration.HybridPerInstance)) { h.AppendTo(builder); } } builder.AppendLine("CBUFFER_END"); if (instancedCount > 0) { builder.AppendLine("#if defined(UNITY_DOTS_INSTANCING_ENABLED)"); builder.AppendLine("// DOTS instancing definitions"); builder.AppendLine("UNITY_DOTS_INSTANCING_START(MaterialPropertyMetadata)"); foreach (var h in hlslProps.Where(h => h.declaration == HLSLDeclaration.HybridPerInstance)) { var n = h.name; string type = h.GetValueTypeString(); builder.AppendLine($" UNITY_DOTS_INSTANCED_PROP({type}, {n})"); } builder.AppendLine("UNITY_DOTS_INSTANCING_END(MaterialPropertyMetadata)"); builder.AppendLine("// DOTS instancing usage macros"); builder.AppendLine("#define UNITY_ACCESS_HYBRID_INSTANCED_PROP(var, type) UNITY_ACCESS_DOTS_INSTANCED_PROP_WITH_DEFAULT(type, var)"); builder.AppendLine("#else"); builder.AppendLine("#define UNITY_ACCESS_HYBRID_INSTANCED_PROP(var, type) var"); builder.AppendLine("#endif"); } builder.AppendNewLine(); builder.AppendLine("// Object and Global properties"); foreach (var h in hlslProps) { if (h.declaration == HLSLDeclaration.Global) { h.AppendTo(builder); } } }