private void BuildFFPSubRenderState( int subRenderStateOrder, string subRenderStateType, ShaderGenerator.SGPass sgPass, TargetRenderState renderState ) { if ( subRenderStateOrder == -1 ) { throw new Exception( "Actual sub render type needs to be declared" ); } SubRenderState subRenderState; subRenderState = sgPass.GetCustomFFPSubState( subRenderStateOrder ); if ( subRenderState == null ) { subRenderState = ShaderGenerator.Instance.CreateSubRenderState( subRenderStateType ); } if ( subRenderState.PreAddToRenderState( renderState, sgPass.SrcPass, sgPass.DstPass ) ) { renderState.AddSubRenderStateInstance( subRenderState ); } else { ShaderGenerator.Instance.DestroySubRenderState( subRenderState ); } }
/// <summary> /// build render state from the given pass that emulates the fixed function pipeline behavior /// </summary> /// <param name="sgPass"> The shader generator pass representation. Contains both source and destination pass </param> /// <param name="renderState"> The target render state that will hold the given pass FFP representation </param> public void BuildRenderState( ShaderGenerator.SGPass sgPass, TargetRenderState renderState ) { renderState.Reset(); //Build transformation sub state BuildFFPSubRenderState( -1, FFPTransform.FFPType, sgPass, renderState ); //Build color sub state BuildFFPSubRenderState( -1, FFPTransform.FFPType, sgPass, renderState ); //Build lighting sub state. BuildFFPSubRenderState( -1, FFPTransform.FFPType, sgPass, renderState ); //Build texturing sub state BuildFFPSubRenderState( -1, FFPTransform.FFPType, sgPass, renderState ); //Build fog sub state BuildFFPSubRenderState( -1, FFPTransform.FFPType, sgPass, renderState ); //resolve color stage flags ResolveColorStageFlags( sgPass, renderState ); }
public static int Main(string[] args) { string referenceItemsResponsePath = null; string compileItemsResponsePath = null; string outputPath = null; string genListFilePath = null; bool listAllFiles = false; string processorPath = null; string processorArgs = null; bool debug = false; for (int i = 0; i < args.Length; i++) { args[i] = args[i].Replace("\\\\", "\\"); } ArgumentSyntax.Parse(args, syntax => { syntax.DefineOption("ref", ref referenceItemsResponsePath, true, "The semicolon-separated list of references to compile against."); syntax.DefineOption("src", ref compileItemsResponsePath, true, "The semicolon-separated list of source files to compile."); syntax.DefineOption("out", ref outputPath, true, "The output path for the generated shaders."); syntax.DefineOption("genlist", ref genListFilePath, true, "The output file to store the list of generated files."); syntax.DefineOption("listall", ref listAllFiles, false, "Forces all generated files to be listed in the list file. By default, only bytecode files will be listed and not the original shader code."); syntax.DefineOption("processor", ref processorPath, false, "The path of an assembly containing IShaderSetProcessor types to be used to post-process GeneratedShaderSet objects."); syntax.DefineOption("processorargs", ref processorArgs, false, "Custom information passed to IShaderSetProcessor."); syntax.DefineOption("debug", ref debug, false, "Compiles the shader with debug information when supported."); }); referenceItemsResponsePath = NormalizePath(referenceItemsResponsePath); compileItemsResponsePath = NormalizePath(compileItemsResponsePath); outputPath = NormalizePath(outputPath); genListFilePath = NormalizePath(genListFilePath); processorPath = NormalizePath(processorPath); if (!File.Exists(referenceItemsResponsePath)) { Console.Error.WriteLine("Reference items response file does not exist: " + referenceItemsResponsePath); return(-1); } if (!File.Exists(compileItemsResponsePath)) { Console.Error.WriteLine("Compile items response file does not exist: " + compileItemsResponsePath); return(-1); } if (!Directory.Exists(outputPath)) { try { Directory.CreateDirectory(outputPath); } catch { Console.Error.WriteLine($"Unable to create the output directory \"{outputPath}\"."); return(-1); } } string[] referenceItems = File.ReadAllLines(referenceItemsResponsePath); string[] compileItems = File.ReadAllLines(compileItemsResponsePath); List <MetadataReference> references = new List <MetadataReference>(); foreach (string referencePath in referenceItems) { if (!File.Exists(referencePath)) { Console.Error.WriteLine("Error: reference does not exist: " + referencePath); return(1); } using (FileStream fs = File.OpenRead(referencePath)) { references.Add(MetadataReference.CreateFromStream(fs, filePath: referencePath)); } } List <SyntaxTree> syntaxTrees = new List <SyntaxTree>(); foreach (string sourcePath in compileItems) { string fullSourcePath = Path.Combine(Environment.CurrentDirectory, sourcePath); if (!File.Exists(fullSourcePath)) { Console.Error.WriteLine("Error: source file does not exist: " + fullSourcePath); return(1); } using (FileStream fs = File.OpenRead(fullSourcePath)) { SourceText text = SourceText.From(fs); syntaxTrees.Add(CSharpSyntaxTree.ParseText(text, path: fullSourcePath)); } } Compilation compilation = CSharpCompilation.Create( "ShaderGen.App.GenerateShaders", syntaxTrees, references, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); HlslBackend hlsl = new HlslBackend(compilation); Glsl330Backend glsl330 = new Glsl330Backend(compilation); GlslEs300Backend glsles300 = new GlslEs300Backend(compilation); Glsl450Backend glsl450 = new Glsl450Backend(compilation); MetalBackend metal = new MetalBackend(compilation); LanguageBackend[] languages = new LanguageBackend[] { hlsl, glsl330, glsles300, glsl450, metal, }; List <IShaderSetProcessor> processors = new List <IShaderSetProcessor>(); if (processorPath != null) { try { Assembly assm = Assembly.LoadFrom(processorPath); IEnumerable <Type> processorTypes = assm.GetTypes().Where( t => t.GetInterface(nameof(ShaderGen) + "." + nameof(IShaderSetProcessor)) != null); foreach (Type type in processorTypes) { IShaderSetProcessor processor = (IShaderSetProcessor)Activator.CreateInstance(type); processor.UserArgs = processorArgs; processors.Add(processor); } } catch (ReflectionTypeLoadException rtle) { string msg = string.Join(Environment.NewLine, rtle.LoaderExceptions.Select(e => e.ToString())); Console.WriteLine("FAIL: " + msg); throw new Exception(msg); } } ShaderGenerator sg = new ShaderGenerator(compilation, languages, processors.ToArray()); ShaderGenerationResult shaderGenResult; try { shaderGenResult = sg.GenerateShaders(); } catch (Exception e) when(!Debugger.IsAttached) { StringBuilder sb = new StringBuilder(); sb.AppendLine("An error was encountered while generating shader code:"); sb.AppendLine(e.ToString()); Console.Error.WriteLine(sb.ToString()); return(-1); } Encoding outputEncoding = new UTF8Encoding(false); List <string> generatedFilePaths = new List <string>(); foreach (LanguageBackend lang in languages) { string extension = BackendExtension(lang); IReadOnlyList <GeneratedShaderSet> sets = shaderGenResult.GetOutput(lang); foreach (GeneratedShaderSet set in sets) { string name = set.Name; if (set.VertexShaderCode != null) { string vsOutName = name + "-vertex." + extension; string vsOutPath = Path.Combine(outputPath, vsOutName); File.WriteAllText(vsOutPath, set.VertexShaderCode, outputEncoding); bool succeeded = CompileCode( lang, vsOutPath, set.VertexFunction.Name, ShaderFunctionType.VertexEntryPoint, out string[] genPaths, debug); if (succeeded) { generatedFilePaths.AddRange(genPaths); } if (!succeeded || listAllFiles) { generatedFilePaths.Add(vsOutPath); } } if (set.FragmentShaderCode != null) { string fsOutName = name + "-fragment." + extension; string fsOutPath = Path.Combine(outputPath, fsOutName); File.WriteAllText(fsOutPath, set.FragmentShaderCode, outputEncoding); bool succeeded = CompileCode( lang, fsOutPath, set.FragmentFunction.Name, ShaderFunctionType.FragmentEntryPoint, out string[] genPaths, debug); if (succeeded) { generatedFilePaths.AddRange(genPaths); } if (!succeeded || listAllFiles) { generatedFilePaths.Add(fsOutPath); } } if (set.ComputeShaderCode != null) { string csOutName = name + "-compute." + extension; string csOutPath = Path.Combine(outputPath, csOutName); File.WriteAllText(csOutPath, set.ComputeShaderCode, outputEncoding); bool succeeded = CompileCode( lang, csOutPath, set.ComputeFunction.Name, ShaderFunctionType.ComputeEntryPoint, out string[] genPaths, debug); if (succeeded) { generatedFilePaths.AddRange(genPaths); } if (!succeeded || listAllFiles) { generatedFilePaths.Add(csOutPath); } } } } File.WriteAllLines(genListFilePath, generatedFilePaths); return(0); }
private static bool GenerateShaderPassLit(AbstractMaterialNode masterNode, Pass pass, GenerationMode mode, SurfaceMaterialOptions materialOptions, ShaderGenerator result, List <string> sourceAssetDependencyPaths) { // apply master node options to active fields HashSet <string> activeFields = GetActiveFieldsFromMasterNode(masterNode, pass); // use standard shader pass generation bool vertexActive = masterNode.IsSlotConnected(PBRMasterNode.PositionSlotId); return(HDSubShaderUtilities.GenerateShaderPass(masterNode, pass, mode, materialOptions, activeFields, result, sourceAssetDependencyPaths, vertexActive)); }
private static bool GenerateShaderPassHair(HairMasterNode masterNode, Pass pass, GenerationMode mode, ShaderGenerator result, List <string> sourceAssetDependencyPaths) { if (mode == GenerationMode.ForReals || pass.UseInPreview) { SurfaceMaterialOptions materialOptions = HDSubShaderUtilities.BuildMaterialOptions(masterNode.surfaceType, masterNode.alphaMode, masterNode.doubleSidedMode != DoubleSidedMode.Disabled, false); pass.OnGeneratePass(masterNode); // apply master node options to active fields HashSet <string> activeFields = GetActiveFieldsFromMasterNode(masterNode, pass); // use standard shader pass generation bool vertexActive = masterNode.IsSlotConnected(HairMasterNode.PositionSlotId); return(HDSubShaderUtilities.GenerateShaderPass(masterNode, pass, mode, materialOptions, activeFields, result, sourceAssetDependencyPaths, vertexActive)); } else { return(false); } }
private static bool GenerateShaderPass(CustomRenderTextureNode masterNode, GenerationMode mode, ShaderGenerator result, List <string> sourceAssetDependencyPaths) { string templateLocation = Path.Combine( HDUtils.GetHDRenderPipelinePath(), "Editor", "CustomRenderTextureShaderGraph", "CustomRenderTexturePass.template"); if (!File.Exists(templateLocation)) { Debug.LogError("Template not found: " + templateLocation); return(false); } var activeFields = new HashSet <string>() { "uv0" }; var pixelNodes = ListPool <AbstractMaterialNode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(pixelNodes, masterNode, NodeUtils.IncludeSelf.Include, CustomRenderTextureNode.AllSlots); var pixelRequirements = ShaderGraphRequirements.FromNodes(pixelNodes, ShaderStageCapability.Fragment, false); var graphNodeFunctions = new ShaderStringBuilder(); graphNodeFunctions.IncreaseIndent(); var functionRegistry = new FunctionRegistry(graphNodeFunctions); var pixelSlots = HDSubShaderUtilities.FindMaterialSlotsOnNode(CustomRenderTextureNode.AllSlots, masterNode); // build the graph outputs structure to hold the results of each active slots (and fill out activeFields to indicate they are active) string pixelGraphInputStructName = "SurfaceDescriptionInputs"; string pixelGraphOutputStructName = "SurfaceDescriptionOutputs"; string pixelGraphEvalFunctionName = "SurfaceDescriptionFunction"; var sharedProperties = new PropertyCollector(); var pixelGraphEvalFunction = new ShaderStringBuilder(); // Build the graph evaluation code, to evaluate the specified slots GraphUtil.GenerateSurfaceDescriptionFunction( pixelNodes, masterNode, masterNode.owner as GraphData, pixelGraphEvalFunction, functionRegistry, sharedProperties, pixelRequirements, mode, pixelGraphEvalFunctionName, pixelGraphOutputStructName, null, pixelSlots, pixelGraphInputStructName); // build graph inputs structures ShaderGenerator pixelGraphInputs = new ShaderGenerator(); ShaderSpliceUtil.BuildType(typeof(HDRPShaderStructs.SurfaceDescriptionInputs), activeFields, pixelGraphInputs); // build graph code var graph = new ShaderGenerator(); { graph.AddShaderChunk("// Shared Graph Properties (uniform inputs)"); graph.AddShaderChunk(sharedProperties.GetPropertiesDeclaration(1, mode)); graph.AddShaderChunk("// Shared Graph Node Functions"); graph.AddShaderChunk(graphNodeFunctions.ToString()); graph.AddShaderChunk("// Pixel Graph Evaluation"); graph.Indent(); graph.AddShaderChunk(pixelGraphEvalFunction.ToString()); graph.Deindent(); } var namedFragments = new Dictionary <string, string>() { { "Graph", graph.GetShaderString(2, false) }, }; string sharedTemplatePath = Path.Combine(HDUtils.GetHDRenderPipelinePath(), "Editor", "ShaderGraph"); string buildTypeAssemblyNameFormat = "UnityEditor.Experimental.Rendering.HDPipeline.HDRPShaderStructs+{0}, " + typeof(HDSubShaderUtilities).Assembly.FullName.ToString(); var templatePreprocessor = new ShaderSpliceUtil.TemplatePreprocessor(activeFields, namedFragments, false, sharedTemplatePath, sourceAssetDependencyPaths, buildTypeAssemblyNameFormat); templatePreprocessor.ProcessTemplateFile(templateLocation); result.AddShaderChunk(templatePreprocessor.GetShaderCode().ToString(), false); return(true); }
public static StageValue Process(ShaderGenerator g, Scope scope) { return(new ScopeProcessor(g, scope).Process()); }
public string GetSubshader(IMasterNode iMasterNode, GenerationMode mode, List <string> sourceAssetDependencyPaths = null) { if (sourceAssetDependencyPaths != null) { // HDLitSubShader.cs sourceAssetDependencyPaths.Add(AssetDatabase.GUIDToAssetPath("bac1a9627cfec924fa2ea9c65af8eeca")); // HDSubShaderUtilities.cs sourceAssetDependencyPaths.Add(AssetDatabase.GUIDToAssetPath("713ced4e6eef4a44799a4dd59041484b")); } var masterNode = iMasterNode as HDLitMasterNode; var subShader = new ShaderGenerator(); subShader.AddShaderChunk("SubShader", true); subShader.AddShaderChunk("{", true); subShader.Indent(); { SurfaceMaterialTags materialTags = HDSubShaderUtilities.BuildMaterialTags(masterNode.surfaceType, masterNode.alphaTest.isOn, masterNode.drawBeforeRefraction.isOn, masterNode.sortPriority); // Add tags at the SubShader level { var tagsVisitor = new ShaderStringBuilder(); materialTags.GetTags(tagsVisitor); subShader.AddShaderChunk(tagsVisitor.ToString(), false); } // generate the necessary shader passes bool opaque = (masterNode.surfaceType == SurfaceType.Opaque); bool transparent = !opaque; bool distortionActive = transparent && masterNode.distortion.isOn; bool transparentBackfaceActive = transparent && masterNode.backThenFrontRendering.isOn; bool transparentDepthPrepassActive = transparent && masterNode.alphaTest.isOn && masterNode.alphaTestDepthPrepass.isOn; bool transparentDepthPostpassActive = transparent && masterNode.alphaTest.isOn && masterNode.alphaTestDepthPostpass.isOn; GenerateShaderPassLit(masterNode, m_PassGBuffer, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassLit(masterNode, m_PassMETA, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassLit(masterNode, m_PassShadowCaster, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassLit(masterNode, m_SceneSelectionPass, mode, subShader, sourceAssetDependencyPaths); if (opaque) { GenerateShaderPassLit(masterNode, m_PassDepthOnly, mode, subShader, sourceAssetDependencyPaths); } GenerateShaderPassLit(masterNode, m_PassMotionVectors, mode, subShader, sourceAssetDependencyPaths); if (distortionActive) { GenerateShaderPassLit(masterNode, m_PassDistortion, mode, subShader, sourceAssetDependencyPaths); } if (transparentBackfaceActive) { GenerateShaderPassLit(masterNode, m_PassTransparentBackface, mode, subShader, sourceAssetDependencyPaths); } GenerateShaderPassLit(masterNode, m_PassForward, mode, subShader, sourceAssetDependencyPaths); if (transparentDepthPrepassActive) { GenerateShaderPassLit(masterNode, m_PassTransparentDepthPrepass, mode, subShader, sourceAssetDependencyPaths); } if (transparentDepthPostpassActive) { GenerateShaderPassLit(masterNode, m_PassTransparentDepthPostpass, mode, subShader, sourceAssetDependencyPaths); } } subShader.Deindent(); subShader.AddShaderChunk("}", true); subShader.AddShaderChunk(@"CustomEditor ""UnityEditor.ShaderGraph.HDLitGUI"""); return(subShader.GetShaderString(0)); }
public string GetSubshader(IMasterNode iMasterNode, GenerationMode mode, List <string> sourceAssetDependencyPaths = null) { if (sourceAssetDependencyPaths != null) { // HDUnlitSubShader.cs sourceAssetDependencyPaths.Add(AssetDatabase.GUIDToAssetPath("1c44ec077faa54145a89357de68e5d26")); // HDSubShaderUtilities.cs sourceAssetDependencyPaths.Add(AssetDatabase.GUIDToAssetPath("713ced4e6eef4a44799a4dd59041484b")); } var masterNode = iMasterNode as HDUnlitMasterNode; var subShader = new ShaderGenerator(); subShader.AddShaderChunk("SubShader", true); subShader.AddShaderChunk("{", true); subShader.Indent(); { // Add tags at the SubShader level int queue = HDRenderQueue.ChangeType(masterNode.renderingPass, masterNode.sortPriority, masterNode.alphaTest.isOn); HDSubShaderUtilities.AddTags(subShader, HDRenderPipeline.k_ShaderTagName, HDRenderTypeTags.HDUnlitShader, queue); // For preview only we generate the passes that are enabled bool opaque = (masterNode.surfaceType == SurfaceType.Opaque); bool transparent = !opaque; bool distortionActive = transparent && masterNode.distortion.isOn; GenerateShaderPassUnlit(masterNode, m_PassShadowCaster, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassUnlit(masterNode, m_PassMETA, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassUnlit(masterNode, m_SceneSelectionPass, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassUnlit(masterNode, m_PassDepthForwardOnly, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassUnlit(masterNode, m_PassMotionVectors, mode, subShader, sourceAssetDependencyPaths); if (distortionActive) { GenerateShaderPassUnlit(masterNode, m_PassDistortion, mode, subShader, sourceAssetDependencyPaths); } GenerateShaderPassUnlit(masterNode, m_PassForwardOnly, mode, subShader, sourceAssetDependencyPaths); } subShader.Deindent(); subShader.AddShaderChunk("}", false); if (mode == GenerationMode.ForReals) { subShader.AddShaderChunk("SubShader", false); subShader.AddShaderChunk("{", false); subShader.Indent(); HDSubShaderUtilities.AddTags(subShader, HDRenderPipeline.k_ShaderTagName); { GenerateShaderPassUnlit(masterNode, m_PassRaytracingIndirect, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassUnlit(masterNode, m_PassRaytracingVisibility, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassUnlit(masterNode, m_PassRaytracingForward, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassUnlit(masterNode, m_PassRaytracingGBuffer, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassUnlit(masterNode, m_PassPathTracing, mode, subShader, sourceAssetDependencyPaths); } subShader.Deindent(); subShader.AddShaderChunk("}", false); } subShader.AddShaderChunk(@"CustomEditor ""UnityEditor.Rendering.HighDefinition.HDUnlitGUI"""); return(subShader.GetShaderString(0)); }
public static async Task RunAsync(GraphicsDevice device) { bool generateWithDelegate = false; // Create graphics buffer int width = 10; int height = 10; float[] array = new float[width * height]; for (int i = 0; i < array.Length; i++) { array[i] = i; } float[] outputArray = new float[width * height]; using GraphicsBuffer <float> sourceBuffer = GraphicsBuffer.Create <float>(device, array, ResourceFlags.None); using GraphicsBuffer <float> destinationBuffer = GraphicsBuffer.Create <float>(device, array.Length * 2, ResourceFlags.AllowUnorderedAccess); GraphicsBuffer <float> slicedDestinationBuffer = destinationBuffer.Slice(20, 60); slicedDestinationBuffer = slicedDestinationBuffer.Slice(10, 50); DescriptorSet descriptorSet = new DescriptorSet(device, 2); descriptorSet.AddUnorderedAccessViews(slicedDestinationBuffer); descriptorSet.AddShaderResourceViews(sourceBuffer); // Generate computer shader ShaderGenerator shaderGenerator = generateWithDelegate ? CreateShaderGeneratorWithDelegate(sourceBuffer, destinationBuffer) : CreateShaderGeneratorWithClass(); ShaderGeneratorResult result = shaderGenerator.GenerateShader(); // Compile shader byte[] shaderBytecode = ShaderCompiler.Compile(ShaderStage.ComputeShader, result.ShaderSource, result.EntryPoints["compute"]); DescriptorRange[] descriptorRanges = new DescriptorRange[] { new DescriptorRange(DescriptorRangeType.UnorderedAccessView, 1, 0), new DescriptorRange(DescriptorRangeType.ShaderResourceView, 1, 0) }; RootParameter rootParameter = new RootParameter(new RootDescriptorTable(descriptorRanges), ShaderVisibility.All); RootSignatureDescription rootSignatureDescription = new RootSignatureDescription(RootSignatureFlags.None, new[] { rootParameter }); RootSignature rootSignature = new RootSignature(device, rootSignatureDescription); PipelineState pipelineState = new PipelineState(device, rootSignature, shaderBytecode); // Execute computer shader using (CommandList commandList = new CommandList(device, CommandListType.Compute)) { commandList.SetPipelineState(pipelineState); commandList.SetComputeRootDescriptorTable(0, descriptorSet); commandList.Dispatch(1, 1, 1); await commandList.FlushAsync(); } // Print matrix Console.WriteLine("Before:"); PrintMatrix(array, width, height); destinationBuffer.GetData(outputArray.AsSpan()); Console.WriteLine(); Console.WriteLine("After:"); PrintMatrix(outputArray, width, height); }
public string GetSubshader(IMasterNode iMasterNode, GenerationMode mode) { var masterNode = iMasterNode as PBRMasterNode; var subShader = new ShaderGenerator(); subShader.AddShaderChunk("SubShader", true); subShader.AddShaderChunk("{", true); subShader.Indent(); { SurfaceMaterialOptions materialOptions = HDSubShaderUtilities.BuildMaterialOptions(masterNode.surfaceType, masterNode.alphaMode, masterNode.twoSided.isOn); // Add tags at the SubShader level { var tagsVisitor = new ShaderStringBuilder(); materialOptions.GetTags(tagsVisitor); subShader.AddShaderChunk(tagsVisitor.ToString(), false); } // generate the necessary shader passes bool opaque = (masterNode.surfaceType == SurfaceType.Opaque); bool transparent = (masterNode.surfaceType != SurfaceType.Opaque); bool distortionActive = false; bool transparentDepthPrepassActive = transparent && false; bool transparentBackfaceActive = transparent && false; bool transparentDepthPostpassActive = transparent && false; if (opaque) { GenerateShaderPass(masterNode, m_PassGBuffer, mode, materialOptions, subShader); GenerateShaderPass(masterNode, m_PassGBufferWithPrepass, mode, materialOptions, subShader); } GenerateShaderPass(masterNode, m_PassMETA, mode, materialOptions, subShader); GenerateShaderPass(masterNode, m_PassShadowCaster, mode, materialOptions, subShader); if (opaque) { GenerateShaderPass(masterNode, m_PassDepthOnly, mode, materialOptions, subShader); GenerateShaderPass(masterNode, m_PassMotionVectors, mode, materialOptions, subShader); } if (distortionActive) { GenerateShaderPass(masterNode, m_PassDistortion, mode, materialOptions, subShader); } if (transparentDepthPrepassActive) { GenerateShaderPass(masterNode, m_PassTransparentDepthPrepass, mode, materialOptions, subShader); } if (transparentBackfaceActive) { GenerateShaderPass(masterNode, m_PassTransparentBackface, mode, materialOptions, subShader); } GenerateShaderPass(masterNode, m_PassForward, mode, materialOptions, subShader); if (transparentDepthPostpassActive) { GenerateShaderPass(masterNode, m_PassTransparentDepthPostpass, mode, materialOptions, subShader); } } subShader.Deindent(); subShader.AddShaderChunk("}", true); return(subShader.GetShaderString(0)); }
private static bool GenerateShaderPass(PBRMasterNode masterNode, Pass pass, GenerationMode mode, SurfaceMaterialOptions materialOptions, ShaderGenerator result) { var templateLocation = Path.Combine(Path.Combine(Path.Combine(HDEditorUtils.GetHDRenderPipelinePath(), "Editor"), "ShaderGraph"), pass.TemplateName); if (!File.Exists(templateLocation)) { // TODO: produce error here return(false); } // grab all of the active nodes var activeNodeList = ListPool <INode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(activeNodeList, masterNode, NodeUtils.IncludeSelf.Include, pass.PixelShaderSlots); // graph requirements describe what the graph itself requires var graphRequirements = ShaderGraphRequirements.FromNodes(activeNodeList, ShaderStageCapability.Fragment); ShaderStringBuilder graphNodeFunctions = new ShaderStringBuilder(); graphNodeFunctions.IncreaseIndent(); var functionRegistry = new FunctionRegistry(graphNodeFunctions); // Build the list of active slots based on what the pass requires // TODO: this can be a shared function -- From here through GraphUtil.GenerateSurfaceDescription(..) var activeSlots = new List <MaterialSlot>(); foreach (var id in pass.PixelShaderSlots) { MaterialSlot slot = masterNode.FindSlot <MaterialSlot>(id); if (slot != null) { activeSlots.Add(slot); } } // build the graph outputs structure to hold the results of each active slots (and fill out activeFields to indicate they are active) string graphInputStructName = "SurfaceDescriptionInputs"; string graphOutputStructName = "SurfaceDescription"; string graphEvalFunctionName = "SurfaceDescriptionFunction"; ShaderStringBuilder graphEvalFunction = new ShaderStringBuilder(); ShaderStringBuilder graphOutputs = new ShaderStringBuilder(); PropertyCollector graphProperties = new PropertyCollector(); // build the graph outputs structure, and populate activeFields with the fields of that structure HashSet <string> activeFields = new HashSet <string>(); GraphUtil.GenerateSurfaceDescriptionStruct(graphOutputs, activeSlots, true); //GraphUtil.GenerateSurfaceDescriptionStruct(graphOutputs, activeSlots, true, graphOutputStructName, activeFields); // Build the graph evaluation code, to evaluate the specified slots GraphUtil.GenerateSurfaceDescriptionFunction( activeNodeList, masterNode, masterNode.owner as AbstractMaterialGraph, graphEvalFunction, functionRegistry, graphProperties, graphRequirements, // TODO : REMOVE UNUSED mode, graphEvalFunctionName, graphOutputStructName, null, activeSlots, graphInputStructName); var blendCode = new ShaderStringBuilder(); var cullCode = new ShaderStringBuilder(); var zTestCode = new ShaderStringBuilder(); var zWriteCode = new ShaderStringBuilder(); var stencilCode = new ShaderStringBuilder(); var colorMaskCode = new ShaderStringBuilder(); HDSubShaderUtilities.BuildRenderStatesFromPassAndMaterialOptions(pass, materialOptions, blendCode, cullCode, zTestCode, zWriteCode, stencilCode, colorMaskCode); if (masterNode.twoSided.isOn) { activeFields.Add("DoubleSided"); if (pass.ShaderPassName != "SHADERPASS_VELOCITY") // HACK to get around lack of a good interpolator dependency system { // we need to be able to build interpolators using multiple input structs // also: should only require isFrontFace if Normals are required... activeFields.Add("DoubleSided.Mirror"); // TODO: change this depending on what kind of normal flip you want.. activeFields.Add("FragInputs.isFrontFace"); // will need this for determining normal flip mode } } if (pass.PixelShaderSlots != null) { foreach (var slotId in pass.PixelShaderSlots) { var slot = masterNode.FindSlot <MaterialSlot>(slotId); if (slot != null) { var rawSlotName = slot.RawDisplayName().ToString(); var descriptionVar = string.Format("{0}.{1}", graphOutputStructName, rawSlotName); activeFields.Add(descriptionVar); } } } var packedInterpolatorCode = new ShaderGenerator(); var graphInputs = new ShaderGenerator(); HDRPShaderStructs.Generate( packedInterpolatorCode, graphInputs, graphRequirements, pass.RequiredFields, CoordinateSpace.World, activeFields); // debug output all active fields var interpolatorDefines = new ShaderGenerator(); { interpolatorDefines.AddShaderChunk("// ACTIVE FIELDS:"); foreach (string f in activeFields) { interpolatorDefines.AddShaderChunk("// " + f); } } ShaderGenerator defines = new ShaderGenerator(); { defines.AddShaderChunk(string.Format("#define SHADERPASS {0}", pass.ShaderPassName), true); if (pass.ExtraDefines != null) { foreach (var define in pass.ExtraDefines) { defines.AddShaderChunk(define); } } defines.AddGenerator(interpolatorDefines); } var shaderPassIncludes = new ShaderGenerator(); if (pass.Includes != null) { foreach (var include in pass.Includes) { shaderPassIncludes.AddShaderChunk(include); } } // build graph code var graph = new ShaderGenerator(); graph.AddShaderChunk("// Graph Inputs"); graph.Indent(); graph.AddGenerator(graphInputs); graph.Deindent(); graph.AddShaderChunk("// Graph Outputs"); graph.Indent(); graph.AddShaderChunk(graphOutputs.ToString()); //graph.AddGenerator(graphOutputs); graph.Deindent(); graph.AddShaderChunk("// Graph Properties (uniform inputs)"); graph.AddShaderChunk(graphProperties.GetPropertiesDeclaration(1)); graph.AddShaderChunk("// Graph Node Functions"); graph.AddShaderChunk(graphNodeFunctions.ToString()); graph.AddShaderChunk("// Graph Evaluation"); graph.Indent(); graph.AddShaderChunk(graphEvalFunction.ToString()); //graph.AddGenerator(graphEvalFunction); graph.Deindent(); // build the hash table of all named fragments TODO: could make this Dictionary<string, ShaderGenerator / string> ? Dictionary <string, string> namedFragments = new Dictionary <string, string>(); namedFragments.Add("${Defines}", defines.GetShaderString(2, false)); namedFragments.Add("${Graph}", graph.GetShaderString(2, false)); namedFragments.Add("${LightMode}", pass.LightMode); namedFragments.Add("${PassName}", pass.Name); namedFragments.Add("${Includes}", shaderPassIncludes.GetShaderString(2, false)); namedFragments.Add("${InterpolatorPacking}", packedInterpolatorCode.GetShaderString(2, false)); namedFragments.Add("${Blending}", blendCode.ToString()); namedFragments.Add("${Culling}", cullCode.ToString()); namedFragments.Add("${ZTest}", zTestCode.ToString()); namedFragments.Add("${ZWrite}", zWriteCode.ToString()); namedFragments.Add("${Stencil}", stencilCode.ToString()); namedFragments.Add("${ColorMask}", colorMaskCode.ToString()); namedFragments.Add("${LOD}", materialOptions.lod.ToString()); namedFragments.Add("${VariantDefines}", GetVariantDefines(masterNode)); // process the template to generate the shader code for this pass TODO: could make this a shared function string[] templateLines = File.ReadAllLines(templateLocation); System.Text.StringBuilder builder = new System.Text.StringBuilder(); foreach (string line in templateLines) { ShaderSpliceUtil.PreprocessShaderCode(line, activeFields, namedFragments, builder); builder.AppendLine(); } result.AddShaderChunk(builder.ToString(), false); return(true); }
private static string GetVariantDefines(PBRMasterNode masterNode) { ShaderGenerator defines = new ShaderGenerator(); // TODO: // _MATERIAL_FEATURE_SUBSURFACE_SCATTERING // _MATERIAL_FEATURE_TRANSMISSION // _MATERIAL_FEATURE_ANISOTROPY // _MATERIAL_FEATURE_CLEAR_COAT // _MATERIAL_FEATURE_IRIDESCENCE switch (masterNode.model) { case PBRMasterNode.Model.Metallic: break; case PBRMasterNode.Model.Specular: defines.AddShaderChunk("#define _MATERIAL_FEATURE_SPECULAR_COLOR 1", true); break; default: // TODO: error! break; } // #pragma shader_feature _ALPHATEST_ON float constantAlpha = 0.0f; if (masterNode.IsSlotConnected(PBRMasterNode.AlphaThresholdSlotId) || (float.TryParse(masterNode.GetSlotValue(PBRMasterNode.AlphaThresholdSlotId, GenerationMode.ForReals), out constantAlpha) && (constantAlpha > 0.0f))) { defines.AddShaderChunk("#define _ALPHATEST_ON 1", true); } // if (kTesselationMode != TessellationMode.None) // { // defines.AddShaderChunk("#define _TESSELLATION_PHONG 1", true); // } // #pragma shader_feature _ _VERTEX_DISPLACEMENT _PIXEL_DISPLACEMENT // switch (kDisplacementMode) // { // case DisplacementMode.None: // break; // case DisplacementMode.Vertex: // defines.AddShaderChunk("#define _VERTEX_DISPLACEMENT 1", true); // break; // case DisplacementMode.Pixel: // defines.AddShaderChunk("#define _PIXEL_DISPLACEMENT 1", true); // Depth offset is only enabled if per pixel displacement is // if (kDepthOffsetEnable) // { // // #pragma shader_feature _DEPTHOFFSET_ON // defines.AddShaderChunk("#define _DEPTHOFFSET_ON 1", true); // } // break; // case DisplacementMode.Tessellation: // if (kTessellationEnabled) // { // defines.AddShaderChunk("#define _TESSELLATION_DISPLACEMENT 1", true); // } // break; // } // #pragma shader_feature _VERTEX_DISPLACEMENT_LOCK_OBJECT_SCALE // #pragma shader_feature _DISPLACEMENT_LOCK_TILING_SCALE // #pragma shader_feature _PIXEL_DISPLACEMENT_LOCK_OBJECT_SCALE // #pragma shader_feature _VERTEX_WIND // #pragma shader_feature _ _REFRACTION_PLANE _REFRACTION_SPHERE // // #pragma shader_feature _ _MAPPING_PLANAR _MAPPING_TRIPLANAR // MOVE to a node // #pragma shader_feature _NORMALMAP_TANGENT_SPACE // #pragma shader_feature _ _REQUIRE_UV2 _REQUIRE_UV3 // // #pragma shader_feature _NORMALMAP if (masterNode.IsSlotConnected(PBRMasterNode.NormalSlotId)) { defines.AddShaderChunk("#define _NORMALMAP 1", true); } // #pragma shader_feature _MASKMAP // #pragma shader_feature _BENTNORMALMAP // #pragma shader_feature _EMISSIVE_COLOR_MAP // #pragma shader_feature _ENABLESPECULAROCCLUSION // #pragma shader_feature _HEIGHTMAP // #pragma shader_feature _TANGENTMAP // #pragma shader_feature _ANISOTROPYMAP // #pragma shader_feature _DETAIL_MAP // MOVE to a node // #pragma shader_feature _SUBSURFACE_RADIUS_MAP // #pragma shader_feature _THICKNESSMAP // #pragma shader_feature _SPECULARCOLORMAP // #pragma shader_feature _TRANSMITTANCECOLORMAP // Keywords for transparent // #pragma shader_feature _SURFACE_TYPE_TRANSPARENT if (masterNode.surfaceType != SurfaceType.Opaque) { // transparent-only defines defines.AddShaderChunk("#define _SURFACE_TYPE_TRANSPARENT 1", true); // #pragma shader_feature _ _BLENDMODE_ALPHA _BLENDMODE_ADD _BLENDMODE_PRE_MULTIPLY if (masterNode.alphaMode == AlphaMode.Alpha) { defines.AddShaderChunk("#define _BLENDMODE_ALPHA 1", true); } else if (masterNode.alphaMode == AlphaMode.Additive) { defines.AddShaderChunk("#define _BLENDMODE_ADD 1", true); } // else if (masterNode.alphaMode == PBRMasterNode.AlphaMode.PremultiplyAlpha) // TODO // { // defines.AddShaderChunk("#define _BLENDMODE_PRE_MULTIPLY 1", true); // } // #pragma shader_feature _BLENDMODE_PRESERVE_SPECULAR_LIGHTING // if (kEnableBlendModePreserveSpecularLighting) // { // defines.AddShaderChunk("#define _BLENDMODE_PRESERVE_SPECULAR_LIGHTING 1", true); // } // #pragma shader_feature _ENABLE_FOG_ON_TRANSPARENT // if (kEnableFogOnTransparent) // { // defines.AddShaderChunk("#define _ENABLE_FOG_ON_TRANSPARENT 1", true); // } } else { // opaque-only defines } // MaterialId are used as shader feature to allow compiler to optimize properly // Note _MATID_STANDARD is not define as there is always the default case "_". We assign default as _MATID_STANDARD, so we never test _MATID_STANDARD // #pragma shader_feature _ _MATID_SSS _MATID_ANISO _MATID_SPECULAR _MATID_CLEARCOAT // enable dithering LOD crossfade // #pragma multi_compile _ LOD_FADE_CROSSFADE // TODO: We should have this keyword only if VelocityInGBuffer is enable, how to do that ? //#pragma multi_compile VELOCITYOUTPUT_OFF VELOCITYOUTPUT_ON return(defines.GetShaderString(2)); }
internal static global::System.Runtime.InteropServices.HandleRef getCPtr(ShaderGenerator obj) { return((obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr); }
public string GetSubshader(IMasterNode iMasterNode, GenerationMode mode, List <string> sourceAssetDependencyPaths = null) { if (sourceAssetDependencyPaths != null) { // HDPBRSubShader.cs sourceAssetDependencyPaths.Add(AssetDatabase.GUIDToAssetPath("c4e8610eb7ce19747bb637c68acc55cd")); // HDSubShaderUtilities.cs sourceAssetDependencyPaths.Add(AssetDatabase.GUIDToAssetPath("713ced4e6eef4a44799a4dd59041484b")); } var masterNode = iMasterNode as PBRMasterNode; var subShader = new ShaderGenerator(); subShader.AddShaderChunk("SubShader", true); subShader.AddShaderChunk("{", true); subShader.Indent(); { SurfaceMaterialOptions materialOptions = HDSubShaderUtilities.BuildMaterialOptions(masterNode.surfaceType, masterNode.alphaMode, masterNode.twoSided.isOn); // Add tags at the SubShader level { var tagsVisitor = new ShaderStringBuilder(); materialOptions.GetTags(tagsVisitor); subShader.AddShaderChunk(tagsVisitor.ToString(), false); } // generate the necessary shader passes bool opaque = (masterNode.surfaceType == SurfaceType.Opaque); bool transparent = (masterNode.surfaceType != SurfaceType.Opaque); bool distortionActive = false; bool transparentDepthPrepassActive = transparent && false; bool transparentBackfaceActive = transparent && false; bool transparentDepthPostpassActive = transparent && false; if (opaque) { GenerateShaderPassLit(masterNode, m_PassGBuffer, mode, materialOptions, subShader, sourceAssetDependencyPaths); GenerateShaderPassLit(masterNode, m_PassGBufferWithPrepass, mode, materialOptions, subShader, sourceAssetDependencyPaths); } GenerateShaderPassLit(masterNode, m_PassMETA, mode, materialOptions, subShader, sourceAssetDependencyPaths); GenerateShaderPassLit(masterNode, m_PassShadowCaster, mode, materialOptions, subShader, sourceAssetDependencyPaths); if (opaque) { GenerateShaderPassLit(masterNode, m_PassDepthOnly, mode, materialOptions, subShader, sourceAssetDependencyPaths); GenerateShaderPassLit(masterNode, m_PassMotionVectors, mode, materialOptions, subShader, sourceAssetDependencyPaths); } if (distortionActive) { GenerateShaderPassLit(masterNode, m_PassDistortion, mode, materialOptions, subShader, sourceAssetDependencyPaths); } if (transparentDepthPrepassActive) { GenerateShaderPassLit(masterNode, m_PassTransparentDepthPrepass, mode, materialOptions, subShader, sourceAssetDependencyPaths); } if (transparentBackfaceActive) { GenerateShaderPassLit(masterNode, m_PassTransparentBackface, mode, materialOptions, subShader, sourceAssetDependencyPaths); } GenerateShaderPassLit(masterNode, m_PassForward, mode, materialOptions, subShader, sourceAssetDependencyPaths); if (transparentDepthPostpassActive) { GenerateShaderPassLit(masterNode, m_PassTransparentDepthPostpass, mode, materialOptions, subShader, sourceAssetDependencyPaths); } } subShader.Deindent(); subShader.AddShaderChunk("}", true); return(subShader.GetShaderString(0)); }
private static bool GenerateShaderPassLit(AbstractMaterialNode masterNode, Pass pass, GenerationMode mode, SurfaceMaterialOptions materialOptions, ShaderGenerator result, List <string> sourceAssetDependencyPaths) { var templateLocation = Path.Combine(Path.Combine(Path.Combine(HDEditorUtils.GetHDRenderPipelinePath(), "Editor"), "ShaderGraph"), pass.TemplateName); if (!File.Exists(templateLocation)) { // TODO: produce error here return(false); } if (sourceAssetDependencyPaths != null) { sourceAssetDependencyPaths.Add(templateLocation); } // grab all of the active nodes (for pixel and vertex graphs) var vertexNodes = ListPool <INode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(vertexNodes, masterNode, NodeUtils.IncludeSelf.Include, pass.VertexShaderSlots); var pixelNodes = ListPool <INode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(pixelNodes, masterNode, NodeUtils.IncludeSelf.Include, pass.PixelShaderSlots); // graph requirements describe what the graph itself requires var pixelRequirements = ShaderGraphRequirements.FromNodes(pixelNodes, ShaderStageCapability.Fragment, false); // TODO: is ShaderStageCapability.Fragment correct? var vertexRequirements = ShaderGraphRequirements.FromNodes(vertexNodes, ShaderStageCapability.Vertex, false); // Function Registry tracks functions to remove duplicates, it wraps a string builder that stores the combined function string ShaderStringBuilder graphNodeFunctions = new ShaderStringBuilder(); graphNodeFunctions.IncreaseIndent(); var functionRegistry = new FunctionRegistry(graphNodeFunctions); // TODO: this can be a shared function for all HDRP master nodes -- From here through GraphUtil.GenerateSurfaceDescription(..) // Build the list of active slots based on what the pass requires var pixelSlots = HDSubShaderUtilities.FindMaterialSlotsOnNode(pass.PixelShaderSlots, masterNode); var vertexSlots = HDSubShaderUtilities.FindMaterialSlotsOnNode(pass.VertexShaderSlots, masterNode); // properties used by either pixel and vertex shader PropertyCollector sharedProperties = new PropertyCollector(); // build the graph outputs structure to hold the results of each active slots (and fill out activeFields to indicate they are active) string pixelGraphInputStructName = "SurfaceDescriptionInputs"; string pixelGraphOutputStructName = "SurfaceDescription"; string pixelGraphEvalFunctionName = "SurfaceDescriptionFunction"; ShaderStringBuilder pixelGraphEvalFunction = new ShaderStringBuilder(); ShaderStringBuilder pixelGraphOutputs = new ShaderStringBuilder(); // dependency tracker -- set of active fields HashSet <string> activeFields = GetActiveFieldsFromMasterNode(masterNode, pass); // build initial requirements HDRPShaderStructs.AddActiveFieldsFromPixelGraphRequirements(activeFields, pixelRequirements); // build the graph outputs structure, and populate activeFields with the fields of that structure GraphUtil.GenerateSurfaceDescriptionStruct(pixelGraphOutputs, pixelSlots, true, pixelGraphOutputStructName, activeFields); // Build the graph evaluation code, to evaluate the specified slots GraphUtil.GenerateSurfaceDescriptionFunction( pixelNodes, masterNode, masterNode.owner as AbstractMaterialGraph, pixelGraphEvalFunction, functionRegistry, sharedProperties, pixelRequirements, // TODO : REMOVE UNUSED mode, pixelGraphEvalFunctionName, pixelGraphOutputStructName, null, pixelSlots, pixelGraphInputStructName); string vertexGraphInputStructName = "VertexDescriptionInputs"; string vertexGraphOutputStructName = "VertexDescription"; string vertexGraphEvalFunctionName = "VertexDescriptionFunction"; ShaderStringBuilder vertexGraphEvalFunction = new ShaderStringBuilder(); ShaderStringBuilder vertexGraphOutputs = new ShaderStringBuilder(); // check for vertex animation -- enables HAVE_VERTEX_MODIFICATION bool vertexActive = false; if (masterNode.IsSlotConnected(PBRMasterNode.PositionSlotId)) { vertexActive = true; activeFields.Add("features.modifyMesh"); HDRPShaderStructs.AddActiveFieldsFromVertexGraphRequirements(activeFields, vertexRequirements); // ------------------------------------- // Generate Output structure for Vertex Description function GraphUtil.GenerateVertexDescriptionStruct(vertexGraphOutputs, vertexSlots, vertexGraphOutputStructName, activeFields); // ------------------------------------- // Generate Vertex Description function GraphUtil.GenerateVertexDescriptionFunction( masterNode.owner as AbstractMaterialGraph, vertexGraphEvalFunction, functionRegistry, sharedProperties, mode, vertexNodes, vertexSlots, vertexGraphInputStructName, vertexGraphEvalFunctionName, vertexGraphOutputStructName); } var blendCode = new ShaderStringBuilder(); var cullCode = new ShaderStringBuilder(); var zTestCode = new ShaderStringBuilder(); var zWriteCode = new ShaderStringBuilder(); var stencilCode = new ShaderStringBuilder(); var colorMaskCode = new ShaderStringBuilder(); HDSubShaderUtilities.BuildRenderStatesFromPassAndMaterialOptions(pass, materialOptions, blendCode, cullCode, zTestCode, zWriteCode, stencilCode, colorMaskCode); HDRPShaderStructs.AddRequiredFields(pass.RequiredFields, activeFields); // apply dependencies to the active fields, and build interpolators (TODO: split this function) var packedInterpolatorCode = new ShaderGenerator(); HDRPShaderStructs.Generate( packedInterpolatorCode, activeFields); // debug output all active fields var interpolatorDefines = new ShaderGenerator(); { interpolatorDefines.AddShaderChunk("// ACTIVE FIELDS:"); foreach (string f in activeFields) { interpolatorDefines.AddShaderChunk("// " + f); } } // build graph inputs structures ShaderGenerator pixelGraphInputs = new ShaderGenerator(); ShaderSpliceUtil.BuildType(typeof(HDRPShaderStructs.SurfaceDescriptionInputs), activeFields, pixelGraphInputs); ShaderGenerator vertexGraphInputs = new ShaderGenerator(); ShaderSpliceUtil.BuildType(typeof(HDRPShaderStructs.VertexDescriptionInputs), activeFields, vertexGraphInputs); ShaderGenerator defines = new ShaderGenerator(); { defines.AddShaderChunk(string.Format("#define SHADERPASS {0}", pass.ShaderPassName), true); if (pass.ExtraDefines != null) { foreach (var define in pass.ExtraDefines) { defines.AddShaderChunk(define); } } defines.AddGenerator(interpolatorDefines); } var shaderPassIncludes = new ShaderGenerator(); if (pass.Includes != null) { foreach (var include in pass.Includes) { shaderPassIncludes.AddShaderChunk(include); } } // build graph code var graph = new ShaderGenerator(); { graph.AddShaderChunk("// Shared Graph Properties (uniform inputs)"); graph.AddShaderChunk(sharedProperties.GetPropertiesDeclaration(1)); if (vertexActive) { graph.AddShaderChunk("// Vertex Graph Inputs"); graph.Indent(); graph.AddGenerator(vertexGraphInputs); graph.Deindent(); graph.AddShaderChunk("// Vertex Graph Outputs"); graph.Indent(); graph.AddShaderChunk(vertexGraphOutputs.ToString()); graph.Deindent(); } graph.AddShaderChunk("// Pixel Graph Inputs"); graph.Indent(); graph.AddGenerator(pixelGraphInputs); graph.Deindent(); graph.AddShaderChunk("// Pixel Graph Outputs"); graph.Indent(); graph.AddShaderChunk(pixelGraphOutputs.ToString()); graph.Deindent(); graph.AddShaderChunk("// Shared Graph Node Functions"); graph.AddShaderChunk(graphNodeFunctions.ToString()); if (vertexActive) { graph.AddShaderChunk("// Vertex Graph Evaluation"); graph.Indent(); graph.AddShaderChunk(vertexGraphEvalFunction.ToString()); graph.Deindent(); } graph.AddShaderChunk("// Pixel Graph Evaluation"); graph.Indent(); graph.AddShaderChunk(pixelGraphEvalFunction.ToString()); graph.Deindent(); } // build the hash table of all named fragments TODO: could make this Dictionary<string, ShaderGenerator / string> ? Dictionary <string, string> namedFragments = new Dictionary <string, string>(); namedFragments.Add("${Defines}", defines.GetShaderString(2, false)); namedFragments.Add("${Graph}", graph.GetShaderString(2, false)); namedFragments.Add("${LightMode}", pass.LightMode); namedFragments.Add("${PassName}", pass.Name); namedFragments.Add("${Includes}", shaderPassIncludes.GetShaderString(2, false)); namedFragments.Add("${InterpolatorPacking}", packedInterpolatorCode.GetShaderString(2, false)); namedFragments.Add("${Blending}", blendCode.ToString()); namedFragments.Add("${Culling}", cullCode.ToString()); namedFragments.Add("${ZTest}", zTestCode.ToString()); namedFragments.Add("${ZWrite}", zWriteCode.ToString()); namedFragments.Add("${Stencil}", stencilCode.ToString()); namedFragments.Add("${ColorMask}", colorMaskCode.ToString()); namedFragments.Add("${LOD}", materialOptions.lod.ToString()); // process the template to generate the shader code for this pass TODO: could make this a shared function string[] templateLines = File.ReadAllLines(templateLocation); System.Text.StringBuilder builder = new System.Text.StringBuilder(); foreach (string line in templateLines) { ShaderSpliceUtil.PreprocessShaderCode(line, activeFields, namedFragments, builder); builder.AppendLine(); } result.AddShaderChunk(builder.ToString(), false); return(true); }
public string GetSubshader(IMasterNode iMasterNode, GenerationMode mode, List <string> sourceAssetDependencyPaths = null) { if (sourceAssetDependencyPaths != null) { // HDUnlitSubShader.cs sourceAssetDependencyPaths.Add(AssetDatabase.GUIDToAssetPath("1c44ec077faa54145a89357de68e5d26")); // HDSubShaderUtilities.cs sourceAssetDependencyPaths.Add(AssetDatabase.GUIDToAssetPath("713ced4e6eef4a44799a4dd59041484b")); } var masterNode = iMasterNode as HDUnlitMasterNode; var subShader = new ShaderGenerator(); subShader.AddShaderChunk("SubShader", true); subShader.AddShaderChunk("{", true); subShader.Indent(); { //Handle data migration here as we need to have a renderingPass already set with accurate data at this point. if (masterNode.renderingPass == HDRenderQueue.RenderQueueType.Unknown) { switch (masterNode.surfaceType) { case SurfaceType.Opaque: masterNode.renderingPass = HDRenderQueue.RenderQueueType.Opaque; break; case SurfaceType.Transparent: #pragma warning disable CS0618 // Type or member is obsolete if (masterNode.m_DrawBeforeRefraction) { masterNode.m_DrawBeforeRefraction = false; #pragma warning restore CS0618 // Type or member is obsolete masterNode.renderingPass = HDRenderQueue.RenderQueueType.PreRefraction; } else { masterNode.renderingPass = HDRenderQueue.RenderQueueType.Transparent; } break; default: throw new System.ArgumentException("Unknown SurfaceType"); } } HDMaterialTags materialTags = HDSubShaderUtilities.BuildMaterialTags(masterNode.renderingPass, masterNode.sortPriority, masterNode.alphaTest.isOn, HDMaterialTags.RenderType.HDUnlitShader); // Add tags at the SubShader level { var tagsVisitor = new ShaderStringBuilder(); materialTags.GetTags(tagsVisitor, HDRenderPipeline.k_ShaderTagName); subShader.AddShaderChunk(tagsVisitor.ToString(), false); } // generate the necessary shader passes bool opaque = (masterNode.surfaceType == SurfaceType.Opaque); bool transparent = !opaque; bool distortionActive = transparent && masterNode.distortion.isOn; GenerateShaderPassLit(masterNode, m_PassMETA, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassLit(masterNode, m_PassShadowCaster, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassLit(masterNode, m_SceneSelectionPass, mode, subShader, sourceAssetDependencyPaths); if (opaque) { GenerateShaderPassLit(masterNode, m_PassDepthForwardOnly, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassLit(masterNode, m_PassMotionVectors, mode, subShader, sourceAssetDependencyPaths); } if (distortionActive) { GenerateShaderPassLit(masterNode, m_PassDistortion, mode, subShader, sourceAssetDependencyPaths); } GenerateShaderPassLit(masterNode, m_PassForwardOnly, mode, subShader, sourceAssetDependencyPaths); } subShader.Deindent(); subShader.AddShaderChunk("}", true); subShader.AddShaderChunk(@"CustomEditor ""UnityEditor.Experimental.Rendering.HDPipeline.HDUnlitGUI"""); return(subShader.GetShaderString(0)); }
bool GenerateShaderPass(PBRMasterNode masterNode, ShaderPass pass, GenerationMode mode, ShaderGenerator result, List <string> sourceAssetDependencyPaths) { UniversalShaderGraphUtilities.SetRenderState(masterNode.surfaceType, masterNode.alphaMode, masterNode.twoSided.isOn, ref pass); // apply master node options to active fields var activeFields = GetActiveFieldsFromMasterNode(masterNode, pass); return(ShaderGraph.GenerationUtils.GenerateShaderPass(masterNode, pass, mode, activeFields, result, sourceAssetDependencyPaths, UniversalShaderGraphResources.s_Dependencies, UniversalShaderGraphResources.s_ResourceClassName, UniversalShaderGraphResources.s_AssemblyName)); }
public string GetSubshader(IMasterNode masterNode, GenerationMode mode, List <string> sourceAssetDependencyPaths = null) { if (sourceAssetDependencyPaths != null) { // LightWeightPBRSubShader.cs sourceAssetDependencyPaths.Add(AssetDatabase.GUIDToAssetPath("ca91dbeb78daa054c9bbe15fef76361c")); } var templatePath = GetTemplatePath("lightweightPBRForwardPass.template"); var extraPassesTemplatePath = GetTemplatePath("lightweightPBRExtraPasses.template"); var lightweight2DPath = GetTemplatePath("lightweight2DPBRPass.template"); if (!File.Exists(templatePath) || !File.Exists(extraPassesTemplatePath)) { return(string.Empty); } if (sourceAssetDependencyPaths != null) { sourceAssetDependencyPaths.Add(templatePath); sourceAssetDependencyPaths.Add(extraPassesTemplatePath); sourceAssetDependencyPaths.Add(lightweight2DPath); var relativePath = "Packages/com.unity.render-pipelines.lightweight/"; var fullPath = Path.GetFullPath(relativePath); var shaderFiles = Directory.GetFiles(Path.Combine(fullPath, "ShaderLibrary")).Select(x => Path.Combine(relativePath, x.Substring(fullPath.Length))); sourceAssetDependencyPaths.AddRange(shaderFiles); } string forwardTemplate = File.ReadAllText(templatePath); string extraTemplate = File.ReadAllText(extraPassesTemplatePath); string lightweight2DTemplate = File.ReadAllText(lightweight2DPath); var pbrMasterNode = masterNode as PBRMasterNode; var pass = pbrMasterNode.model == PBRMasterNode.Model.Metallic ? m_ForwardPassMetallic : m_ForwardPassSpecular; var subShader = new ShaderStringBuilder(); subShader.AppendLine("SubShader"); using (subShader.BlockScope()) { var materialTags = ShaderGenerator.BuildMaterialTags(pbrMasterNode.surfaceType); var tagsBuilder = new ShaderStringBuilder(0); materialTags.GetTags(tagsBuilder, LightweightRenderPipeline.k_ShaderTagName); subShader.AppendLines(tagsBuilder.ToString()); var materialOptions = ShaderGenerator.GetMaterialOptions(pbrMasterNode.surfaceType, pbrMasterNode.alphaMode, pbrMasterNode.twoSided.isOn); subShader.AppendLines(GetShaderPassFromTemplate( forwardTemplate, pbrMasterNode, pass, mode, materialOptions)); subShader.AppendLines(GetShaderPassFromTemplate( extraTemplate, pbrMasterNode, m_DepthShadowPass, mode, materialOptions)); string txt = GetShaderPassFromTemplate( lightweight2DTemplate, pbrMasterNode, pass, mode, materialOptions); subShader.AppendLines(txt); } subShader.Append("CustomEditor \"UnityEditor.ShaderGraph.PBRMasterGUI\""); return(subShader.ToString()); }
public static bool GenerateShaderPass(AbstractMaterialNode masterNode, Pass pass, GenerationMode mode, SurfaceMaterialOptions materialOptions, HashSet <string> activeFields, ShaderGenerator result, List <string> sourceAssetDependencyPaths, bool vertexActive) { string templatePath = Path.Combine(HDUtils.GetHDRenderPipelinePath(), "Editor/Material"); string templateLocation = Path.Combine(Path.Combine(Path.Combine(templatePath, pass.MaterialName), "ShaderGraph"), pass.TemplateName); if (!File.Exists(templateLocation)) { // TODO: produce error here Debug.LogError("Template not found: " + templateLocation); return(false); } bool debugOutput = false; // grab all of the active nodes (for pixel and vertex graphs) var vertexNodes = ListPool <INode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(vertexNodes, masterNode, NodeUtils.IncludeSelf.Include, pass.VertexShaderSlots); var pixelNodes = ListPool <INode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(pixelNodes, masterNode, NodeUtils.IncludeSelf.Include, pass.PixelShaderSlots); // graph requirements describe what the graph itself requires var pixelRequirements = ShaderGraphRequirements.FromNodes(pixelNodes, ShaderStageCapability.Fragment, false); // TODO: is ShaderStageCapability.Fragment correct? var vertexRequirements = ShaderGraphRequirements.FromNodes(vertexNodes, ShaderStageCapability.Vertex, false); var graphRequirements = pixelRequirements.Union(vertexRequirements); // Function Registry tracks functions to remove duplicates, it wraps a string builder that stores the combined function string ShaderStringBuilder graphNodeFunctions = new ShaderStringBuilder(); graphNodeFunctions.IncreaseIndent(); var functionRegistry = new FunctionRegistry(graphNodeFunctions); // TODO: this can be a shared function for all HDRP master nodes -- From here through GraphUtil.GenerateSurfaceDescription(..) // Build the list of active slots based on what the pass requires var pixelSlots = HDSubShaderUtilities.FindMaterialSlotsOnNode(pass.PixelShaderSlots, masterNode); var vertexSlots = HDSubShaderUtilities.FindMaterialSlotsOnNode(pass.VertexShaderSlots, masterNode); // properties used by either pixel and vertex shader PropertyCollector sharedProperties = new PropertyCollector(); // build the graph outputs structure to hold the results of each active slots (and fill out activeFields to indicate they are active) string pixelGraphInputStructName = "SurfaceDescriptionInputs"; string pixelGraphOutputStructName = "SurfaceDescription"; string pixelGraphEvalFunctionName = "SurfaceDescriptionFunction"; ShaderStringBuilder pixelGraphEvalFunction = new ShaderStringBuilder(); ShaderStringBuilder pixelGraphOutputs = new ShaderStringBuilder(); // build initial requirements HDRPShaderStructs.AddActiveFieldsFromPixelGraphRequirements(activeFields, pixelRequirements); // build the graph outputs structure, and populate activeFields with the fields of that structure GraphUtil.GenerateSurfaceDescriptionStruct(pixelGraphOutputs, pixelSlots, true, pixelGraphOutputStructName, activeFields); // Build the graph evaluation code, to evaluate the specified slots GraphUtil.GenerateSurfaceDescriptionFunction( pixelNodes, masterNode, masterNode.owner as AbstractMaterialGraph, pixelGraphEvalFunction, functionRegistry, sharedProperties, pixelRequirements, // TODO : REMOVE UNUSED mode, pixelGraphEvalFunctionName, pixelGraphOutputStructName, null, pixelSlots, pixelGraphInputStructName); string vertexGraphInputStructName = "VertexDescriptionInputs"; string vertexGraphOutputStructName = "VertexDescription"; string vertexGraphEvalFunctionName = "VertexDescriptionFunction"; ShaderStringBuilder vertexGraphEvalFunction = new ShaderStringBuilder(); ShaderStringBuilder vertexGraphOutputs = new ShaderStringBuilder(); // check for vertex animation -- enables HAVE_VERTEX_MODIFICATION if (vertexActive) { vertexActive = true; activeFields.Add("features.modifyMesh"); HDRPShaderStructs.AddActiveFieldsFromVertexGraphRequirements(activeFields, vertexRequirements); // ------------------------------------- // Generate Output structure for Vertex Description function GraphUtil.GenerateVertexDescriptionStruct(vertexGraphOutputs, vertexSlots, vertexGraphOutputStructName, activeFields); // ------------------------------------- // Generate Vertex Description function GraphUtil.GenerateVertexDescriptionFunction( masterNode.owner as AbstractMaterialGraph, vertexGraphEvalFunction, functionRegistry, sharedProperties, mode, vertexNodes, vertexSlots, vertexGraphInputStructName, vertexGraphEvalFunctionName, vertexGraphOutputStructName); } var blendCode = new ShaderStringBuilder(); var cullCode = new ShaderStringBuilder(); var zTestCode = new ShaderStringBuilder(); var zWriteCode = new ShaderStringBuilder(); var zClipCode = new ShaderStringBuilder(); var stencilCode = new ShaderStringBuilder(); var colorMaskCode = new ShaderStringBuilder(); HDSubShaderUtilities.BuildRenderStatesFromPassAndMaterialOptions(pass, materialOptions, blendCode, cullCode, zTestCode, zWriteCode, zClipCode, stencilCode, colorMaskCode); HDRPShaderStructs.AddRequiredFields(pass.RequiredFields, activeFields); // propagate active field requirements using dependencies ShaderSpliceUtil.ApplyDependencies( activeFields, new List <Dependency[]>() { HDRPShaderStructs.FragInputs.dependencies, HDRPShaderStructs.VaryingsMeshToPS.standardDependencies, HDRPShaderStructs.SurfaceDescriptionInputs.dependencies, HDRPShaderStructs.VertexDescriptionInputs.dependencies }); // debug output all active fields var interpolatorDefines = new ShaderGenerator(); if (debugOutput) { interpolatorDefines.AddShaderChunk("// ACTIVE FIELDS:"); foreach (string f in activeFields) { interpolatorDefines.AddShaderChunk("// " + f); } } // build graph inputs structures ShaderGenerator pixelGraphInputs = new ShaderGenerator(); ShaderSpliceUtil.BuildType(typeof(HDRPShaderStructs.SurfaceDescriptionInputs), activeFields, pixelGraphInputs); ShaderGenerator vertexGraphInputs = new ShaderGenerator(); ShaderSpliceUtil.BuildType(typeof(HDRPShaderStructs.VertexDescriptionInputs), activeFields, vertexGraphInputs); ShaderGenerator defines = new ShaderGenerator(); { defines.AddShaderChunk(string.Format("#define SHADERPASS {0}", pass.ShaderPassName), true); if (pass.ExtraDefines != null) { foreach (var define in pass.ExtraDefines) { defines.AddShaderChunk(define); } } if (graphRequirements.requiresDepthTexture) { defines.AddShaderChunk("#define REQUIRE_DEPTH_TEXTURE"); } defines.AddGenerator(interpolatorDefines); } var shaderPassIncludes = new ShaderGenerator(); if (pass.Includes != null) { foreach (var include in pass.Includes) { shaderPassIncludes.AddShaderChunk(include); } } // build graph code var graph = new ShaderGenerator(); { graph.AddShaderChunk("// Shared Graph Properties (uniform inputs)"); graph.AddShaderChunk(sharedProperties.GetPropertiesDeclaration(1)); if (vertexActive) { graph.AddShaderChunk("// Vertex Graph Inputs"); graph.Indent(); graph.AddGenerator(vertexGraphInputs); graph.Deindent(); graph.AddShaderChunk("// Vertex Graph Outputs"); graph.Indent(); graph.AddShaderChunk(vertexGraphOutputs.ToString()); graph.Deindent(); } graph.AddShaderChunk("// Pixel Graph Inputs"); graph.Indent(); graph.AddGenerator(pixelGraphInputs); graph.Deindent(); graph.AddShaderChunk("// Pixel Graph Outputs"); graph.Indent(); graph.AddShaderChunk(pixelGraphOutputs.ToString()); graph.Deindent(); graph.AddShaderChunk("// Shared Graph Node Functions"); graph.AddShaderChunk(graphNodeFunctions.ToString()); if (vertexActive) { graph.AddShaderChunk("// Vertex Graph Evaluation"); graph.Indent(); graph.AddShaderChunk(vertexGraphEvalFunction.ToString()); graph.Deindent(); } graph.AddShaderChunk("// Pixel Graph Evaluation"); graph.Indent(); graph.AddShaderChunk(pixelGraphEvalFunction.ToString()); graph.Deindent(); } // build the hash table of all named fragments TODO: could make this Dictionary<string, ShaderGenerator / string> ? Dictionary <string, string> namedFragments = new Dictionary <string, string>(); namedFragments.Add("Defines", defines.GetShaderString(2, false)); namedFragments.Add("Graph", graph.GetShaderString(2, false)); namedFragments.Add("LightMode", pass.LightMode); namedFragments.Add("PassName", pass.Name); namedFragments.Add("Includes", shaderPassIncludes.GetShaderString(2, false)); namedFragments.Add("Blending", blendCode.ToString()); namedFragments.Add("Culling", cullCode.ToString()); namedFragments.Add("ZTest", zTestCode.ToString()); namedFragments.Add("ZWrite", zWriteCode.ToString()); namedFragments.Add("ZClip", zClipCode.ToString()); namedFragments.Add("Stencil", stencilCode.ToString()); namedFragments.Add("ColorMask", colorMaskCode.ToString()); namedFragments.Add("LOD", materialOptions.lod.ToString()); // this is the format string for building the 'C# qualified assembly type names' for $buildType() commands string buildTypeAssemblyNameFormat = "UnityEditor.Experimental.Rendering.HDPipeline.HDRPShaderStructs+{0}, " + typeof(HDSubShaderUtilities).Assembly.FullName.ToString(); string sharedTemplatePath = Path.Combine(Path.Combine(HDUtils.GetHDRenderPipelinePath(), "Editor"), "ShaderGraph"); // process the template to generate the shader code for this pass ShaderSpliceUtil.TemplatePreprocessor templatePreprocessor = new ShaderSpliceUtil.TemplatePreprocessor(activeFields, namedFragments, debugOutput, sharedTemplatePath, sourceAssetDependencyPaths, buildTypeAssemblyNameFormat); templatePreprocessor.ProcessTemplateFile(templateLocation); result.AddShaderChunk(templatePreprocessor.GetShaderCode().ToString(), false); return(true); }
private static bool GenerateShaderPassLit(HDLitMasterNode masterNode, Pass pass, GenerationMode mode, ShaderGenerator result, List <string> sourceAssetDependencyPaths) { if (mode == GenerationMode.ForReals || pass.UseInPreview) { pass.OnGeneratePass(masterNode); // apply master node options to active fields HashSet <string> activeFields = GetActiveFieldsFromMasterNode(masterNode, pass); pass.ExtraInstancingOptions = GetInstancingOptionsFromMasterNode(masterNode); // use standard shader pass generation bool vertexActive = masterNode.IsSlotConnected(HDLitMasterNode.PositionSlotId); return(HDSubShaderUtilities.GenerateShaderPass(masterNode, pass, mode, activeFields, result, sourceAssetDependencyPaths, vertexActive)); } else { return(false); } }
static string GetExtraPassesFromTemplate(string template, PBRMasterNode masterNode, Pass pass, GenerationMode mode, SurfaceMaterialOptions materialOptions) { // ----------------------------------------------------- // // SETUP // // ----------------------------------------------------- // // ------------------------------------- // String builders var dummyBuilder = new ShaderStringBuilder(0); var shaderProperties = new PropertyCollector(); var functionBuilder = new ShaderStringBuilder(1); var functionRegistry = new FunctionRegistry(functionBuilder); var defines = new ShaderStringBuilder(2); var graph = new ShaderStringBuilder(0); var vertexDescriptionInputStruct = new ShaderStringBuilder(1); var vertexDescriptionStruct = new ShaderStringBuilder(1); var vertexDescriptionFunction = new ShaderStringBuilder(1); var vertexInputStruct = new ShaderStringBuilder(1); var vertexShader = new ShaderStringBuilder(2); var vertexDescriptionInputs = new ShaderStringBuilder(2); // ------------------------------------- // Get Slot and Node lists per stage var vertexSlots = pass.VertexShaderSlots.Select(masterNode.FindSlot <MaterialSlot>).ToList(); var vertexNodes = ListPool <INode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(vertexNodes, masterNode, NodeUtils.IncludeSelf.Include, pass.VertexShaderSlots); // ------------------------------------- // Get requirements var vertexRequirements = ShaderGraphRequirements.FromNodes(vertexNodes, ShaderStageCapability.Vertex, false); var modelRequiements = ShaderGraphRequirements.none; modelRequiements.requiresNormal |= m_VertexCoordinateSpace; modelRequiements.requiresPosition |= m_VertexCoordinateSpace; modelRequiements.requiresMeshUVs.Add(UVChannel.UV1); // ----------------------------------------------------- // // START SHADER GENERATION // // ----------------------------------------------------- // // ------------------------------------- // Calculate material options var cullingBuilder = new ShaderStringBuilder(1); materialOptions.GetCull(cullingBuilder); // ------------------------------------- // Generate defines if (masterNode.IsSlotConnected(PBRMasterNode.AlphaThresholdSlotId)) { defines.AppendLine("#define _AlphaClip 1"); } // ----------------------------------------------------- // // START VERTEX DESCRIPTION // // ----------------------------------------------------- // // ------------------------------------- // Generate Input structure for Vertex Description function // TODO - Vertex Description Input requirements are needed to exclude intermediate translation spaces vertexDescriptionInputStruct.AppendLine("struct VertexDescriptionInputs"); using (vertexDescriptionInputStruct.BlockSemicolonScope()) { ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresNormal, InterpolatorType.Normal, vertexDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresTangent, InterpolatorType.Tangent, vertexDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresBitangent, InterpolatorType.BiTangent, vertexDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresViewDir, InterpolatorType.ViewDirection, vertexDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresPosition, InterpolatorType.Position, vertexDescriptionInputStruct); if (vertexRequirements.requiresVertexColor) { vertexDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.VertexColor); } if (vertexRequirements.requiresScreenPosition) { vertexDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.ScreenPosition); } foreach (var channel in vertexRequirements.requiresMeshUVs.Distinct()) { vertexDescriptionInputStruct.AppendLine("half4 {0};", channel.GetUVName()); } } // ------------------------------------- // Generate Output structure for Vertex Description function GraphUtil.GenerateVertexDescriptionStruct(vertexDescriptionStruct, vertexSlots); // ------------------------------------- // Generate Vertex Description function GraphUtil.GenerateVertexDescriptionFunction( masterNode.owner as AbstractMaterialGraph, vertexDescriptionFunction, functionRegistry, shaderProperties, mode, vertexNodes, vertexSlots); // ----------------------------------------------------- // // GENERATE VERTEX > PIXEL PIPELINE // // ----------------------------------------------------- // // ------------------------------------- // Generate Input structure for Vertex shader GraphUtil.GenerateApplicationVertexInputs(vertexRequirements.Union(modelRequiements), vertexInputStruct); // ------------------------------------- // Generate standard transformations // This method ensures all required transform data is available in vertex and pixel stages ShaderGenerator.GenerateStandardTransforms( 3, 10, dummyBuilder, vertexShader, vertexDescriptionInputs, dummyBuilder, dummyBuilder, dummyBuilder, ShaderGraphRequirements.none, ShaderGraphRequirements.none, modelRequiements, vertexRequirements, CoordinateSpace.World); // ----------------------------------------------------- // // FINALIZE // // ----------------------------------------------------- // // ------------------------------------- // Combine Graph sections graph.AppendLine(shaderProperties.GetPropertiesDeclaration(1)); graph.AppendLine(vertexDescriptionInputStruct.ToString()); graph.AppendLine(functionBuilder.ToString()); graph.AppendLine(vertexDescriptionStruct.ToString()); graph.AppendLine(vertexDescriptionFunction.ToString()); graph.AppendLine(vertexInputStruct.ToString()); // ------------------------------------- // Generate final subshader var resultPass = template.Replace("${Culling}", cullingBuilder.ToString()); resultPass = resultPass.Replace("${Defines}", defines.ToString()); resultPass = resultPass.Replace("${Graph}", graph.ToString()); resultPass = resultPass.Replace("${VertexShader}", vertexShader.ToString()); resultPass = resultPass.Replace("${VertexShaderDescriptionInputs}", vertexDescriptionInputs.ToString()); return(resultPass); }
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 = "Packages/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); }
static string GetShaderPassFromTemplate(string template, ImageEffectMasterNode masterNode, Pass pass, GenerationMode mode, SurfaceMaterialOptions materialOptions) { // ----------------------------------------------------- // // SETUP // // ----------------------------------------------------- // // ------------------------------------- // String builders var shaderProperties = new PropertyCollector(); var functionBuilder = new ShaderStringBuilder(1); var functionRegistry = new FunctionRegistry(functionBuilder); var defines = new ShaderStringBuilder(1); var graph = new ShaderStringBuilder(0); var vertexDescriptionInputStruct = new ShaderStringBuilder(1); var vertexDescriptionStruct = new ShaderStringBuilder(1); var vertexDescriptionFunction = new ShaderStringBuilder(1); var surfaceDescriptionInputStruct = new ShaderStringBuilder(1); var surfaceDescriptionStruct = new ShaderStringBuilder(1); var surfaceDescriptionFunction = new ShaderStringBuilder(1); var vertexInputStruct = new ShaderStringBuilder(1); var vertexOutputStruct = new ShaderStringBuilder(2); var vertexShader = new ShaderStringBuilder(2); var vertexShaderDescriptionInputs = new ShaderStringBuilder(2); var vertexShaderOutputs = new ShaderStringBuilder(2); var pixelShader = new ShaderStringBuilder(2); var pixelShaderSurfaceInputs = new ShaderStringBuilder(2); var pixelShaderSurfaceRemap = new ShaderStringBuilder(2); // ------------------------------------- // Get Slot and Node lists per stage var vertexSlots = pass.VertexShaderSlots.Select(masterNode.FindSlot <MaterialSlot>).ToList(); var vertexNodes = ListPool <INode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(vertexNodes, masterNode, NodeUtils.IncludeSelf.Include, pass.VertexShaderSlots); var pixelSlots = pass.PixelShaderSlots.Select(masterNode.FindSlot <MaterialSlot>).ToList(); var pixelNodes = ListPool <INode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(pixelNodes, masterNode, NodeUtils.IncludeSelf.Include, pass.PixelShaderSlots); // ------------------------------------- // Get Requirements var vertexRequirements = ShaderGraphRequirements.FromNodes(vertexNodes, ShaderStageCapability.Vertex, false); var pixelRequirements = ShaderGraphRequirements.FromNodes(pixelNodes, ShaderStageCapability.Fragment); var graphRequirements = pixelRequirements.Union(vertexRequirements); var surfaceRequirements = ShaderGraphRequirements.FromNodes(pixelNodes, ShaderStageCapability.Fragment, false); var modelRequiements = ShaderGraphRequirements.none; modelRequiements.requiresNormal |= k_PixelCoordinateSpace; modelRequiements.requiresTangent |= k_PixelCoordinateSpace; modelRequiements.requiresBitangent |= k_PixelCoordinateSpace; modelRequiements.requiresPosition |= k_PixelCoordinateSpace; modelRequiements.requiresViewDir |= k_PixelCoordinateSpace; modelRequiements.requiresMeshUVs.Add(UVChannel.UV1); // ----------------------------------------------------- // // START SHADER GENERATION // // ----------------------------------------------------- // // ------------------------------------- // Calculate material options var blendingBuilder = new ShaderStringBuilder(1); var cullingBuilder = new ShaderStringBuilder(1); var zTestBuilder = new ShaderStringBuilder(1); var zWriteBuilder = new ShaderStringBuilder(1); // Cull Off ZWrite Off ZTest Always materialOptions.cullMode = SurfaceMaterialOptions.CullMode.Off; materialOptions.zWrite = SurfaceMaterialOptions.ZWrite.Off; materialOptions.zTest = SurfaceMaterialOptions.ZTest.Always; materialOptions.GetBlend(blendingBuilder); materialOptions.GetCull(cullingBuilder); materialOptions.GetDepthTest(zTestBuilder); materialOptions.GetDepthWrite(zWriteBuilder); // ------------------------------------- // Generate defines //TODO // if (masterNode.IsSlotConnected(UnlitMasterNode.AlphaThresholdSlotId)) // defines.AppendLine("#define _AlphaClip 1"); if (masterNode.surfaceType == SurfaceType.Transparent && masterNode.alphaMode == AlphaMode.Premultiply) { defines.AppendLine("#define _ALPHAPREMULTIPLY_ON 1"); } if (graphRequirements.requiresDepthTexture) { defines.AppendLine("#define REQUIRE_DEPTH_TEXTURE"); } if (graphRequirements.requiresCameraOpaqueTexture) { defines.AppendLine("#define REQUIRE_OPAQUE_TEXTURE"); } // ----------------------------------------------------- // // START VERTEX DESCRIPTION // // ----------------------------------------------------- // // ------------------------------------- // Generate Input structure for Vertex Description function // TODO - Vertex Description Input requirements are needed to exclude intermediate translation spaces vertexDescriptionInputStruct.AppendLine("struct VertexDescriptionInputs"); using (vertexDescriptionInputStruct.BlockSemicolonScope()) { ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresNormal, InterpolatorType.Normal, vertexDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresTangent, InterpolatorType.Tangent, vertexDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresBitangent, InterpolatorType.BiTangent, vertexDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresViewDir, InterpolatorType.ViewDirection, vertexDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresPosition, InterpolatorType.Position, vertexDescriptionInputStruct); if (vertexRequirements.requiresVertexColor) { vertexDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.VertexColor); } if (vertexRequirements.requiresScreenPosition) { vertexDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.ScreenPosition); } foreach (var channel in vertexRequirements.requiresMeshUVs.Distinct()) { vertexDescriptionInputStruct.AppendLine("half4 {0};", channel.GetUVName()); } } // ------------------------------------- // Generate Output structure for Vertex Description function GraphUtil.GenerateVertexDescriptionStruct(vertexDescriptionStruct, vertexSlots); // ------------------------------------- // Generate Vertex Description function GraphUtil.GenerateVertexDescriptionFunction( masterNode.owner as AbstractMaterialGraph, vertexDescriptionFunction, functionRegistry, shaderProperties, mode, vertexNodes, vertexSlots); // ----------------------------------------------------- // // 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(surfaceRequirements.requiresNormal, InterpolatorType.Normal, surfaceDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresTangent, InterpolatorType.Tangent, surfaceDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresBitangent, InterpolatorType.BiTangent, surfaceDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresViewDir, InterpolatorType.ViewDirection, surfaceDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresPosition, InterpolatorType.Position, surfaceDescriptionInputStruct); if (surfaceRequirements.requiresVertexColor) { surfaceDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.VertexColor); } if (surfaceRequirements.requiresScreenPosition) { surfaceDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.ScreenPosition); } if (surfaceRequirements.requiresFaceSign) { surfaceDescriptionInputStruct.AppendLine("float {0};", ShaderGeneratorNames.FaceSign); } foreach (var channel in surfaceRequirements.requiresMeshUVs.Distinct()) { surfaceDescriptionInputStruct.AppendLine("half4 {0};", channel.GetUVName()); } } // ------------------------------------- // Generate Output structure for Surface Description function GraphUtil.GenerateSurfaceDescriptionStruct(surfaceDescriptionStruct, pixelSlots, true); // ------------------------------------- // Generate Surface Description function GraphUtil.GenerateSurfaceDescriptionFunction( pixelNodes, masterNode, masterNode.owner as AbstractMaterialGraph, surfaceDescriptionFunction, functionRegistry, shaderProperties, pixelRequirements, mode, "PopulateSurfaceData", "SurfaceDescription", null, pixelSlots); // ----------------------------------------------------- // // GENERATE VERTEX > PIXEL PIPELINE // // ----------------------------------------------------- // // ------------------------------------- // Generate Input structure for Vertex shader GraphUtil.GenerateApplicationVertexInputs(vertexRequirements.Union(pixelRequirements.Union(modelRequiements)), vertexInputStruct); // ------------------------------------- // Generate standard transformations // This method ensures all required transform data is available in vertex and pixel stages ShaderGenerator.GenerateStandardTransforms( 3, 10, vertexOutputStruct, vertexShader, vertexShaderDescriptionInputs, vertexShaderOutputs, pixelShader, pixelShaderSurfaceInputs, pixelRequirements, surfaceRequirements, modelRequiements, vertexRequirements, CoordinateSpace.World); // ------------------------------------- // Generate pixel shader surface remap foreach (var slot in pixelSlots) { pixelShaderSurfaceRemap.AppendLine("{0} = surf.{0};", slot.shaderOutputName); } // ------------------------------------- // Extra pixel shader work var faceSign = new ShaderStringBuilder(); if (pixelRequirements.requiresFaceSign) { faceSign.AppendLine(", half FaceSign : VFACE"); } // ----------------------------------------------------- // // FINALIZE // // ----------------------------------------------------- // // ------------------------------------- // Combine Graph sections graph.AppendLine(shaderProperties.GetPropertiesDeclaration(1)); graph.AppendLine(vertexDescriptionInputStruct.ToString()); graph.AppendLine(surfaceDescriptionInputStruct.ToString()); graph.AppendLine(functionBuilder.ToString()); graph.AppendLine(vertexDescriptionStruct.ToString()); graph.AppendLine(vertexDescriptionFunction.ToString()); graph.AppendLine(surfaceDescriptionStruct.ToString()); graph.AppendLine(surfaceDescriptionFunction.ToString()); graph.AppendLine(vertexInputStruct.ToString()); // ------------------------------------- // Generate final subshader var resultPass = template.Replace("${Tags}", string.Empty); resultPass = resultPass.Replace("${Blending}", blendingBuilder.ToString()); resultPass = resultPass.Replace("${Culling}", cullingBuilder.ToString()); resultPass = resultPass.Replace("${ZTest}", zTestBuilder.ToString()); resultPass = resultPass.Replace("${ZWrite}", zWriteBuilder.ToString()); resultPass = resultPass.Replace("${Defines}", defines.ToString()); resultPass = resultPass.Replace("${Graph}", graph.ToString()); resultPass = resultPass.Replace("${VertexOutputStruct}", vertexOutputStruct.ToString()); resultPass = resultPass.Replace("${VertexShader}", vertexShader.ToString()); resultPass = resultPass.Replace("${VertexShaderDescriptionInputs}", vertexShaderDescriptionInputs.ToString()); resultPass = resultPass.Replace("${VertexShaderOutputs}", vertexShaderOutputs.ToString()); resultPass = resultPass.Replace("${FaceSign}", faceSign.ToString()); resultPass = resultPass.Replace("${PixelShader}", pixelShader.ToString()); resultPass = resultPass.Replace("${PixelShaderSurfaceInputs}", pixelShaderSurfaceInputs.ToString()); resultPass = resultPass.Replace("${PixelShaderSurfaceRemap}", pixelShaderSurfaceRemap.ToString()); return(resultPass); }
public string GetSubshader(IMasterNode iMasterNode, GenerationMode mode, List <string> sourceAssetDependencyPaths = null) { if (sourceAssetDependencyPaths != null) { // HDLitSubShader.cs sourceAssetDependencyPaths.Add(AssetDatabase.GUIDToAssetPath("bac1a9627cfec924fa2ea9c65af8eeca")); // HDSubShaderUtilities.cs sourceAssetDependencyPaths.Add(AssetDatabase.GUIDToAssetPath("713ced4e6eef4a44799a4dd59041484b")); } var masterNode = iMasterNode as HDLitMasterNode; var subShader = new ShaderGenerator(); subShader.AddShaderChunk("SubShader", false); subShader.AddShaderChunk("{", false); subShader.Indent(); { //Handle data migration here as we need to have a renderingPass already set with accurate data at this point. if (masterNode.renderingPass == HDRenderQueue.RenderQueueType.Unknown) { switch (masterNode.surfaceType) { case SurfaceType.Opaque: masterNode.renderingPass = HDRenderQueue.RenderQueueType.Opaque; break; case SurfaceType.Transparent: #pragma warning disable CS0618 // Type or member is obsolete if (masterNode.m_DrawBeforeRefraction) { masterNode.m_DrawBeforeRefraction = false; #pragma warning restore CS0618 // Type or member is obsolete masterNode.renderingPass = HDRenderQueue.RenderQueueType.PreRefraction; } else { masterNode.renderingPass = HDRenderQueue.RenderQueueType.Transparent; } break; default: throw new System.ArgumentException("Unknown SurfaceType"); } } HDMaterialTags materialTags = HDSubShaderUtilities.BuildMaterialTags(masterNode.renderingPass, masterNode.sortPriority, masterNode.alphaTest.isOn); // Add tags at the SubShader level { var tagsVisitor = new ShaderStringBuilder(); materialTags.GetTags(tagsVisitor, HDRenderPipeline.k_ShaderTagName); subShader.AddShaderChunk(tagsVisitor.ToString(), false); } // generate the necessary shader passes bool opaque = (masterNode.surfaceType == SurfaceType.Opaque); bool transparent = !opaque; bool distortionActive = transparent && masterNode.distortion.isOn; bool transparentBackfaceActive = transparent && masterNode.backThenFrontRendering.isOn; bool transparentDepthPrepassActive = transparent && masterNode.alphaTest.isOn && masterNode.alphaTestDepthPrepass.isOn; bool transparentDepthPostpassActive = transparent && masterNode.alphaTest.isOn && masterNode.alphaTestDepthPostpass.isOn; GenerateShaderPassLit(masterNode, m_PassMETA, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassLit(masterNode, m_PassShadowCaster, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassLit(masterNode, m_SceneSelectionPass, mode, subShader, sourceAssetDependencyPaths); if (opaque) { GenerateShaderPassLit(masterNode, m_PassDepthOnly, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassLit(masterNode, m_PassGBuffer, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassLit(masterNode, m_PassMotionVectors, mode, subShader, sourceAssetDependencyPaths); } if (distortionActive) { GenerateShaderPassLit(masterNode, m_PassDistortion, mode, subShader, sourceAssetDependencyPaths); } if (transparentBackfaceActive) { GenerateShaderPassLit(masterNode, m_PassTransparentBackface, mode, subShader, sourceAssetDependencyPaths); } // Assign define here based on opaque or transparent to save some variant m_PassForward.ExtraDefines = opaque ? HDSubShaderUtilities.s_ExtraDefinesForwardOpaque : HDSubShaderUtilities.s_ExtraDefinesForwardTransparent; GenerateShaderPassLit(masterNode, m_PassForward, mode, subShader, sourceAssetDependencyPaths); if (transparentDepthPrepassActive) { GenerateShaderPassLit(masterNode, m_PassTransparentDepthPrepass, mode, subShader, sourceAssetDependencyPaths); } if (transparentDepthPostpassActive) { GenerateShaderPassLit(masterNode, m_PassTransparentDepthPostpass, mode, subShader, sourceAssetDependencyPaths); } } subShader.Deindent(); subShader.AddShaderChunk("}", false); #if ENABLE_RAYTRACING if (mode == GenerationMode.ForReals) { subShader.AddShaderChunk("SubShader", false); subShader.AddShaderChunk("{", false); subShader.Indent(); { GenerateShaderPassLit(masterNode, m_PassRaytracingReflection, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassLit(masterNode, m_PassRaytracingVisibility, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassLit(masterNode, m_PassRaytracingForward, mode, subShader, sourceAssetDependencyPaths); } subShader.Deindent(); subShader.AddShaderChunk("}", false); } #endif subShader.AddShaderChunk(@"CustomEditor ""UnityEditor.Experimental.Rendering.HDPipeline.HDLitGUI"""); return(subShader.GetShaderString(0)); }
public string GetSubshader(IMasterNode iMasterNode, GenerationMode mode, List <string> sourceAssetDependencyPaths = null) { if (sourceAssetDependencyPaths != null) { // HairSubShader.cs sourceAssetDependencyPaths.Add(AssetDatabase.GUIDToAssetPath("c3f20efb64673e0488a2c8e986a453fa")); // HDSubShaderUtilities.cs sourceAssetDependencyPaths.Add(AssetDatabase.GUIDToAssetPath("713ced4e6eef4a44799a4dd59041484b")); } var masterNode = iMasterNode as HairMasterNode; var subShader = new ShaderGenerator(); subShader.AddShaderChunk("SubShader", true); subShader.AddShaderChunk("{", true); subShader.Indent(); { HDMaterialTags materialTags = HDSubShaderUtilities.BuildMaterialTags(masterNode.surfaceType, masterNode.sortPriority, masterNode.alphaTest.isOn); // Add tags at the SubShader level { var tagsVisitor = new ShaderStringBuilder(); materialTags.GetTags(tagsVisitor, HDRenderPipeline.k_ShaderTagName); subShader.AddShaderChunk(tagsVisitor.ToString(), false); } // generate the necessary shader passes bool opaque = (masterNode.surfaceType == SurfaceType.Opaque); bool transparent = !opaque; bool transparentBackfaceActive = transparent && masterNode.backThenFrontRendering.isOn; bool transparentDepthPrepassActive = transparent && masterNode.alphaTest.isOn && masterNode.alphaTestDepthPrepass.isOn; bool transparentDepthPostpassActive = transparent && masterNode.alphaTest.isOn && masterNode.alphaTestDepthPostpass.isOn; GenerateShaderPassHair(masterNode, m_PassMETA, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassHair(masterNode, m_PassShadowCaster, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassHair(masterNode, m_SceneSelectionPass, mode, subShader, sourceAssetDependencyPaths); if (opaque) { GenerateShaderPassHair(masterNode, m_PassDepthForwardOnly, mode, subShader, sourceAssetDependencyPaths); GenerateShaderPassHair(masterNode, m_PassMotionVectors, mode, subShader, sourceAssetDependencyPaths); } if (transparentBackfaceActive) { GenerateShaderPassHair(masterNode, m_PassTransparentBackface, mode, subShader, sourceAssetDependencyPaths); } if (transparentDepthPrepassActive) { GenerateShaderPassHair(masterNode, m_PassTransparentDepthPrepass, mode, subShader, sourceAssetDependencyPaths); } // Assign define here based on opaque or transparent to save some variant m_PassForwardOnly.ExtraDefines = opaque ? HDSubShaderUtilities.s_ExtraDefinesForwardOpaque : HDSubShaderUtilities.s_ExtraDefinesForwardTransparent; GenerateShaderPassHair(masterNode, m_PassForwardOnly, mode, subShader, sourceAssetDependencyPaths); if (transparentDepthPostpassActive) { GenerateShaderPassHair(masterNode, m_PassTransparentDepthPostpass, mode, subShader, sourceAssetDependencyPaths); } } subShader.Deindent(); subShader.AddShaderChunk("}", true); subShader.AddShaderChunk(@"CustomEditor ""UnityEditor.Experimental.Rendering.HDPipeline.HairGUI"""); return(subShader.GetShaderString(0)); }
static string GetShaderPassFromTemplate(bool isColorPass, string template, SpriteLitMasterNode masterNode, Pass pass, GenerationMode mode, SurfaceMaterialOptions materialOptions) { // ----------------------------------------------------- // // SETUP // // ----------------------------------------------------- // // ------------------------------------- // String builders var shaderProperties = new PropertyCollector(); var shaderPropertyUniforms = new ShaderStringBuilder(1); var functionBuilder = new ShaderStringBuilder(1); var functionRegistry = new FunctionRegistry(functionBuilder); var defines = new ShaderStringBuilder(1); var graph = new ShaderStringBuilder(0); var vertexDescriptionInputStruct = new ShaderStringBuilder(1); var vertexDescriptionStruct = new ShaderStringBuilder(1); var vertexDescriptionFunction = new ShaderStringBuilder(1); var surfaceDescriptionInputStruct = new ShaderStringBuilder(1); var surfaceDescriptionStruct = new ShaderStringBuilder(1); var surfaceDescriptionFunction = new ShaderStringBuilder(1); var vertexInputStruct = new ShaderStringBuilder(1); var vertexOutputStruct = new ShaderStringBuilder(2); var vertexShader = new ShaderStringBuilder(2); var vertexShaderDescriptionInputs = new ShaderStringBuilder(2); var vertexShaderOutputs = new ShaderStringBuilder(2); var pixelShader = new ShaderStringBuilder(2); var pixelShaderSurfaceInputs = new ShaderStringBuilder(2); // ------------------------------------- // Get Slot and Node lists per stage var vertexSlots = pass.VertexShaderSlots.Select(masterNode.FindSlot <MaterialSlot>).ToList(); var vertexNodes = ListPool <AbstractMaterialNode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(vertexNodes, masterNode, NodeUtils.IncludeSelf.Include, pass.VertexShaderSlots); var pixelSlots = pass.PixelShaderSlots.Select(masterNode.FindSlot <MaterialSlot>).ToList(); var pixelNodes = ListPool <AbstractMaterialNode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(pixelNodes, masterNode, NodeUtils.IncludeSelf.Include, pass.PixelShaderSlots); // ------------------------------------- // Get Requirements var vertexRequirements = ShaderGraphRequirements.FromNodes(vertexNodes, ShaderStageCapability.Vertex, false); var pixelRequirements = ShaderGraphRequirements.FromNodes(pixelNodes, ShaderStageCapability.Fragment); var surfaceRequirements = ShaderGraphRequirements.FromNodes(pixelNodes, ShaderStageCapability.Fragment, false); var modelRequiements = ShaderGraphRequirements.none; modelRequiements.requiresVertexColor = true; if (isColorPass) { modelRequiements.requiresMeshUVs = new List <UVChannel>() { UVChannel.UV0 }; } // ----------------------------------------------------- // // START SHADER GENERATION // // ----------------------------------------------------- // // ------------------------------------- // Calculate material options var blendingBuilder = new ShaderStringBuilder(1); var cullingBuilder = new ShaderStringBuilder(1); var zTestBuilder = new ShaderStringBuilder(1); var zWriteBuilder = new ShaderStringBuilder(1); materialOptions.GetBlend(blendingBuilder); materialOptions.GetCull(cullingBuilder); materialOptions.GetDepthTest(zTestBuilder); materialOptions.GetDepthWrite(zWriteBuilder); // ----------------------------------------------------- // // START VERTEX DESCRIPTION // // ----------------------------------------------------- // // ------------------------------------- // Generate Input structure for Vertex Description function // TODO - Vertex Description Input requirements are needed to exclude intermediate translation spaces vertexDescriptionInputStruct.AppendLine("struct VertexDescriptionInputs"); using (vertexDescriptionInputStruct.BlockSemicolonScope()) { ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresNormal, InterpolatorType.Normal, vertexDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresTangent, InterpolatorType.Tangent, vertexDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresBitangent, InterpolatorType.BiTangent, vertexDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresViewDir, InterpolatorType.ViewDirection, vertexDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresPosition, InterpolatorType.Position, vertexDescriptionInputStruct); if (vertexRequirements.requiresVertexColor) { vertexDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.VertexColor); } if (vertexRequirements.requiresScreenPosition) { vertexDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.ScreenPosition); } foreach (var channel in vertexRequirements.requiresMeshUVs.Distinct()) { vertexDescriptionInputStruct.AppendLine("half4 {0};", channel.GetUVName()); } } // ------------------------------------- // Generate Output structure for Vertex Description function GraphUtil.GenerateVertexDescriptionStruct(vertexDescriptionStruct, vertexSlots); // ------------------------------------- // Generate Vertex Description function GraphUtil.GenerateVertexDescriptionFunction( masterNode.owner as GraphData, vertexDescriptionFunction, functionRegistry, shaderProperties, mode, vertexNodes, vertexSlots); // ----------------------------------------------------- // // 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(surfaceRequirements.requiresNormal, InterpolatorType.Normal, surfaceDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresTangent, InterpolatorType.Tangent, surfaceDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresBitangent, InterpolatorType.BiTangent, surfaceDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresViewDir, InterpolatorType.ViewDirection, surfaceDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresPosition, InterpolatorType.Position, surfaceDescriptionInputStruct); if (surfaceRequirements.requiresVertexColor) { surfaceDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.VertexColor); } if (surfaceRequirements.requiresScreenPosition) { surfaceDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.ScreenPosition); } if (surfaceRequirements.requiresFaceSign) { surfaceDescriptionInputStruct.AppendLine("float {0};", ShaderGeneratorNames.FaceSign); } foreach (var channel in surfaceRequirements.requiresMeshUVs.Distinct()) { surfaceDescriptionInputStruct.AppendLine("half4 {0};", channel.GetUVName()); } } // ------------------------------------- // Generate Output structure for Surface Description function GraphUtil.GenerateSurfaceDescriptionStruct(surfaceDescriptionStruct, pixelSlots); // ------------------------------------- // Generate Surface Description function GraphUtil.GenerateSurfaceDescriptionFunction( pixelNodes, masterNode, masterNode.owner as GraphData, surfaceDescriptionFunction, functionRegistry, shaderProperties, pixelRequirements, mode, "PopulateSurfaceData", "SurfaceDescription", null, pixelSlots); // ----------------------------------------------------- // // GENERATE VERTEX > PIXEL PIPELINE // // ----------------------------------------------------- // // ------------------------------------- // Property uniforms shaderProperties.GetPropertiesDeclaration(shaderPropertyUniforms, mode, masterNode.owner.concretePrecision); // ------------------------------------- // Generate Input structure for Vertex shader GraphUtil.GenerateApplicationVertexInputs(vertexRequirements.Union(pixelRequirements.Union(modelRequiements)), vertexInputStruct); // ------------------------------------- // Generate standard transformations // This method ensures all required transform data is available in vertex and pixel stages ShaderGenerator.GenerateStandardTransforms( 3, 10, vertexOutputStruct, vertexShader, vertexShaderDescriptionInputs, vertexShaderOutputs, pixelShader, pixelShaderSurfaceInputs, pixelRequirements, surfaceRequirements, modelRequiements, vertexRequirements, CoordinateSpace.World); // ----------------------------------------------------- // // FINALIZE // // ----------------------------------------------------- // // ------------------------------------- // Combine Graph sections graph.AppendLines(shaderPropertyUniforms.ToString()); graph.AppendLine(vertexDescriptionInputStruct.ToString()); graph.AppendLine(surfaceDescriptionInputStruct.ToString()); graph.AppendLine(functionBuilder.ToString()); graph.AppendLine(vertexDescriptionStruct.ToString()); graph.AppendLine(vertexDescriptionFunction.ToString()); graph.AppendLine(surfaceDescriptionStruct.ToString()); graph.AppendLine(surfaceDescriptionFunction.ToString()); graph.AppendLine(vertexInputStruct.ToString()); // ------------------------------------- // Generate final subshader var resultPass = template.Replace("${Tags}", string.Empty); resultPass = resultPass.Replace("${Blending}", blendingBuilder.ToString()); resultPass = resultPass.Replace("${Culling}", cullingBuilder.ToString()); resultPass = resultPass.Replace("${ZTest}", zTestBuilder.ToString()); resultPass = resultPass.Replace("${ZWrite}", zWriteBuilder.ToString()); resultPass = resultPass.Replace("${Defines}", defines.ToString()); resultPass = resultPass.Replace("${Graph}", graph.ToString()); resultPass = resultPass.Replace("${VertexOutputStruct}", vertexOutputStruct.ToString()); resultPass = resultPass.Replace("${VertexShader}", vertexShader.ToString()); resultPass = resultPass.Replace("${VertexShaderDescriptionInputs}", vertexShaderDescriptionInputs.ToString()); resultPass = resultPass.Replace("${VertexShaderOutputs}", vertexShaderOutputs.ToString()); resultPass = resultPass.Replace("${PixelShader}", pixelShader.ToString()); resultPass = resultPass.Replace("${PixelShaderSurfaceInputs}", pixelShaderSurfaceInputs.ToString()); return(resultPass); }
private static bool GenerateShaderPass(SGEUnlitMasterNode masterNode, ShaderPass pass, GenerationMode mode, ShaderGenerator result, List <string> sourceAssetDependencyPaths) { var options = masterNode.GetMaterialOptions(); SGEShaderGraphUtilities.SetRenderState(options, ref pass); // apply master node options to active fields var activeFields = GetActiveFieldsFromMasterNode(masterNode, pass); // use standard shader pass generation return(GenerationUtils.GenerateShaderPass(masterNode, pass, mode, activeFields, result, sourceAssetDependencyPaths, SGEShaderGraphResources.s_Dependencies, SGEShaderGraphResources.s_ResourceClassName, SGEShaderGraphResources.s_AssemblyName)); }
private static bool GenerateShaderPass(SpriteLitMasterNode masterNode, ShaderPass pass, GenerationMode mode, ShaderGenerator result, List <string> sourceAssetDependencyPaths) { UniversalShaderGraphUtilities.SetRenderState(SurfaceType.Transparent, AlphaMode.Alpha, true, ref pass); // apply master node options to active fields var activeFields = GetActiveFieldsFromMasterNode(masterNode, pass); // use standard shader pass generation return(ShaderGraph.GenerationUtils.GenerateShaderPass(masterNode, pass, mode, activeFields, result, sourceAssetDependencyPaths, UniversalShaderGraphResources.s_Dependencies, UniversalShaderGraphResources.s_ResourceClassName, UniversalShaderGraphResources.s_AssemblyName)); }
private void ResolveColorStageFlags( ShaderGenerator.SGPass sgPass, TargetRenderState renderState ) { var subRenderStateList = renderState.TemplateSubRenderStateList; FFPColor colorSubState = null; //find the color sub state foreach ( var curSubRenderState in subRenderStateList ) { if ( curSubRenderState.Type == FFPColor.FFPType ) { colorSubState = curSubRenderState as FFPColor; } } foreach ( var curSubRenderState in subRenderStateList ) { //Add vertex shader specular lighting output in case of specular enabled. if ( curSubRenderState.Type == FFPLighting.FFPType ) { colorSubState.AddResolveStageMask( (int)FFPColor.StageFlags.VsOutputdiffuse ); Pass srcPass = sgPass.SrcPass; if ( srcPass.Shininess > 0 && srcPass.Specular != ColorEx.Black ) { colorSubState.AddResolveStageMask( (int)FFPColor.StageFlags.VsOutputSpecular ); } break; } } }
public void AllSetsAllLanguagesEndToEnd() { Compilation compilation = TestUtil.GetTestProjectCompilation(); LanguageBackend[] backends = new LanguageBackend[] { new HlslBackend(compilation), new Glsl330Backend(compilation), new Glsl450Backend(compilation), new MetalBackend(compilation), }; ShaderGenerator sg = new ShaderGenerator(compilation, backends); ShaderGenerationResult result = sg.GenerateShaders(); foreach (LanguageBackend backend in backends) { IReadOnlyList <GeneratedShaderSet> sets = result.GetOutput(backend); foreach (GeneratedShaderSet set in sets) { if (set.VertexShaderCode != null) { if (backend is HlslBackend) { FxcTool.AssertCompilesCode(set.VertexShaderCode, "vs_5_0", set.VertexFunction.Name); } else if (backend is MetalBackend) { MetalTool.AssertCompilesCode(set.VertexShaderCode); } else { bool is450 = backend is Glsl450Backend; GlsLangValidatorTool.AssertCompilesCode(set.VertexShaderCode, "vert", is450); } } if (set.FragmentFunction != null) { if (backend is HlslBackend) { FxcTool.AssertCompilesCode(set.FragmentShaderCode, "ps_5_0", set.FragmentFunction.Name); } else if (backend is MetalBackend) { MetalTool.AssertCompilesCode(set.FragmentShaderCode); } else { bool is450 = backend is Glsl450Backend; GlsLangValidatorTool.AssertCompilesCode(set.FragmentShaderCode, "frag", is450); } } if (set.ComputeFunction != null) { if (backend is HlslBackend) { FxcTool.AssertCompilesCode(set.ComputeShaderCode, "cs_5_0", set.ComputeFunction.Name); } else if (backend is MetalBackend) { MetalTool.AssertCompilesCode(set.ComputeShaderCode); } else { bool is450 = backend is Glsl450Backend; GlsLangValidatorTool.AssertCompilesCode(set.ComputeShaderCode, "comp", is450); } } } } }
private static bool GenerateShaderPassUnlit(HDUnlitMasterNode masterNode, Pass pass, GenerationMode mode, ShaderGenerator result, List <string> sourceAssetDependencyPaths) { if (mode == GenerationMode.ForReals || pass.UseInPreview) { pass.OnGeneratePass(masterNode); // apply master node options to active fields var activeFields = GetActiveFieldsFromMasterNode(masterNode, pass); // use standard shader pass generation bool vertexActive = false; if (masterNode.IsSlotConnected(HDUnlitMasterNode.PositionSlotId) || masterNode.IsSlotConnected(HDUnlitMasterNode.VertexNormalSlotId) || masterNode.IsSlotConnected(HDUnlitMasterNode.VertexTangentSlotId)) { vertexActive = true; } return(HDSubShaderUtilities.GenerateShaderPass(masterNode, pass, mode, activeFields, result, sourceAssetDependencyPaths, vertexActive)); } else { return(false); } }
/// <summary> /// Compilation function (must be overrided for a specific graphic library implementation). /// </summary> /// <param name="shader">Shader to compile.</param> /// <returns>Shader instance with compiled binary.</returns> protected override ShaderInstance CompileShader(ShaderInstance shader) { var outShader = new VKShaderInstance(base.CompileShader(shader)); // - Gets all shader referenced assemblies var assemblies = AppDomain.CurrentDomain.GetAssemblies(); var mathAsm = typeof(System.Numerics.Vector4).Assembly.GetReferencedAssemblies(); assemblies = assemblies.Concat(mathAsm.Select(x => Assembly.Load(x.FullName))).ToArray(); var assemblyMeta = assemblies.Select(x => MetadataReference.CreateFromFile(x.Location)); // - Compile the shader code obtaining an IL version CSharpCompilation compilation = CSharpCompilation.Create ( "pEngine", syntaxTrees: new[] { CSharpSyntaxTree.ParseText(outShader.CSourceCode) }, references: assemblyMeta, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) ); // - Get the assembly class path string fullName = outShader.Type.FullName; // - We want to compile targetting GLSL450 compatible for Vulkan var backend = new Glsl450Backend(compilation); // - Prepare a GLSL compiler providing the C# IL binary var generator = new ShaderGenerator ( compilation, backend, outShader.HasVertexShader ? $"{fullName}.{shader.VertexFunctionName}" : null, outShader.HasFragmentShader ? $"{fullName}.{shader.FragmentFunctionName}" : null, outShader.HasComputeShader ? $"{fullName}.{shader.ComputeFunctionName}" : null ); // - Compile to the GLSL code var shaders = generator.GenerateShaders().GetOutput(backend); // - Stores all shader sources outShader.VertexSource = outShader.HasVertexShader ? shaders.Where(x => x.VertexShaderCode != null).First().VertexShaderCode : ""; outShader.FragmentSource = outShader.HasFragmentShader ? shaders.Where(x => x.FragmentShaderCode != null).First().FragmentShaderCode : ""; outShader.ComputeSource = outShader.HasComputeShader ? shaders.Where(x => x.ComputeShaderCode != null).First().ComputeShaderCode : ""; // - This class will compile the GLSL code to the SPIR-V binary ShaderCompiler compiler = new ShaderCompiler(); if (outShader.HasVertexShader) { var res = compiler.CompileToSpirV(outShader.VertexSource, ShaderCompiler.ShaderKind.VertexShader, "main"); if (res.ErrorCount > 0) { throw new InvalidProgramException(res.Errors); } outShader.VertexBinary = res.Binary; } if (outShader.HasFragmentShader) { var res = compiler.CompileToSpirV(outShader.FragmentSource, ShaderCompiler.ShaderKind.FragmentShader, "main"); if (res.ErrorCount > 0) { throw new InvalidProgramException(res.Errors); } outShader.FragmentBinary = res.Binary; } if (outShader.HasComputeShader) { var res = compiler.CompileToSpirV(outShader.ComputeSource, ShaderCompiler.ShaderKind.ComputeShader, "main"); if (res.ErrorCount > 0) { throw new InvalidProgramException(res.Errors); } outShader.ComputeBinary = res.Binary; } return(outShader); }