Boat Attack使用了Universal RP的许多新图形功能,可以用于探索 Universal RP 的使用方式和技巧。
您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

434 行
20 KiB

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEditor.Graphing;
using UnityEditor.ShaderGraph;
namespace UnityEditor.Rendering.Universal
{
delegate void OnGeneratePassDelegate(IMasterNode masterNode, ref Pass pass, ref ShaderGraphRequirements requirements);
struct Pass
{
public string Name;
public string TemplatePath;
public List<int> VertexShaderSlots;
public List<int> PixelShaderSlots;
public ShaderGraphRequirements Requirements;
public List<string> ExtraDefines;
public void OnGeneratePass(IMasterNode masterNode, ShaderGraphRequirements requirements)
{
if (OnGeneratePassImpl != null)
{
OnGeneratePassImpl(masterNode, ref this, ref requirements);
}
}
public OnGeneratePassDelegate OnGeneratePassImpl;
}
static class UniversalSubShaderUtilities
{
public static readonly NeededCoordinateSpace k_PixelCoordinateSpace = NeededCoordinateSpace.World;
static string GetTemplatePath(string templateName)
{
var basePath = "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/";
string templatePath = Path.Combine(basePath, templateName);
if (File.Exists(templatePath))
return templatePath;
throw new FileNotFoundException(string.Format(@"Cannot find a template with name ""{0}"".", templateName));
}
public static string GetSubShader<T>(T masterNode, SurfaceMaterialTags tags, SurfaceMaterialOptions options, Pass[] passes,
GenerationMode mode, string customEditorPath = null, List<string> sourceAssetDependencyPaths = null) where T : IMasterNode
{
if (sourceAssetDependencyPaths != null)
{
var relativePath = "Packages/com.unity.render-pipelines.universal/";
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);
}
var subShader = new ShaderStringBuilder();
subShader.AppendLine("SubShader");
using (subShader.BlockScope())
{
var tagsBuilder = new ShaderStringBuilder(0);
tags.GetTags(tagsBuilder, UnityEngine.Rendering.Universal.UniversalRenderPipeline.k_ShaderTagName);
subShader.AppendLines(tagsBuilder.ToString());
foreach(Pass pass in passes)
{
var templatePath = GetTemplatePath(pass.TemplatePath);
if (!File.Exists(templatePath))
continue;
if (sourceAssetDependencyPaths != null)
sourceAssetDependencyPaths.Add(templatePath);
string template = File.ReadAllText(templatePath);
subShader.AppendLines(GetShaderPassFromTemplate(
template,
masterNode,
pass,
mode,
options));
}
}
if(!string.IsNullOrEmpty(customEditorPath))
subShader.Append($"CustomEditor \"{customEditorPath}\"");
return subShader.ToString();
}
static string GetShaderPassFromTemplate(string template, IMasterNode iMasterNode, Pass pass, GenerationMode mode, SurfaceMaterialOptions materialOptions)
{
// ----------------------------------------------------- //
// SETUP //
// ----------------------------------------------------- //
AbstractMaterialNode masterNode = iMasterNode as AbstractMaterialNode;
// -------------------------------------
// String builders
var shaderProperties = new PropertyCollector();
var shaderKeywords = new KeywordCollector();
var shaderPropertyUniforms = new ShaderStringBuilder(1);
var shaderKeywordDeclarations = 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);
var pixelShaderSurfaceRemap = 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 graphRequirements = pixelRequirements.Union(vertexRequirements);
var surfaceRequirements = ShaderGraphRequirements.FromNodes(pixelNodes, ShaderStageCapability.Fragment, false);
var modelRequirements = pass.Requirements;
// ----------------------------------------------------- //
// 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);
// -------------------------------------
// Generate defines
pass.OnGeneratePass(iMasterNode, graphRequirements);
foreach(string define in pass.ExtraDefines)
defines.AppendLine(define);
// ----------------------------------------------------- //
// KEYWORDS //
// ----------------------------------------------------- //
// -------------------------------------
// Get keyword permutations
masterNode.owner.CollectShaderKeywords(shaderKeywords, mode);
// Track permutation indices for all nodes
List<int>[] keywordPermutationsPerVertexNode = new List<int>[vertexNodes.Count];
List<int>[] keywordPermutationsPerPixelNode = new List<int>[pixelNodes.Count];
// -------------------------------------
// Evaluate all permutations
for(int i = 0; i < shaderKeywords.permutations.Count; i++)
{
// Get active nodes for this permutation
var localVertexNodes = ListPool<AbstractMaterialNode>.Get();
var localPixelNodes = ListPool<AbstractMaterialNode>.Get();
NodeUtils.DepthFirstCollectNodesFromNode(localVertexNodes, masterNode, NodeUtils.IncludeSelf.Include, pass.VertexShaderSlots, shaderKeywords.permutations[i]);
NodeUtils.DepthFirstCollectNodesFromNode(localPixelNodes, masterNode, NodeUtils.IncludeSelf.Include, pass.PixelShaderSlots, shaderKeywords.permutations[i]);
// Track each vertex node in this permutation
foreach(AbstractMaterialNode vertexNode in localVertexNodes)
{
int nodeIndex = vertexNodes.IndexOf(vertexNode);
if(keywordPermutationsPerVertexNode[nodeIndex] == null)
keywordPermutationsPerVertexNode[nodeIndex] = new List<int>();
keywordPermutationsPerVertexNode[nodeIndex].Add(i);
}
// Track each pixel node in this permutation
foreach(AbstractMaterialNode pixelNode in localPixelNodes)
{
int nodeIndex = pixelNodes.IndexOf(pixelNode);
if(keywordPermutationsPerPixelNode[nodeIndex] == null)
keywordPermutationsPerPixelNode[nodeIndex] = new List<int>();
keywordPermutationsPerPixelNode[nodeIndex].Add(i);
}
}
// ----------------------------------------------------- //
// 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());
if (vertexRequirements.requiresTime)
{
vertexDescriptionInputStruct.AppendLine("float3 {0};", ShaderGeneratorNames.TimeParameters);
}
}
// -------------------------------------
// Generate Output structure for Vertex Description function
GraphUtil.GenerateVertexDescriptionStruct(vertexDescriptionStruct, vertexSlots);
// -------------------------------------
// Generate Vertex Description function
GraphUtil.GenerateVertexDescriptionFunction(
masterNode.owner as GraphData,
vertexDescriptionFunction,
functionRegistry,
shaderProperties,
shaderKeywords,
mode,
masterNode,
vertexNodes,
keywordPermutationsPerVertexNode,
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());
if (surfaceRequirements.requiresTime)
{
surfaceDescriptionInputStruct.AppendLine("float3 {0};", ShaderGeneratorNames.TimeParameters);
}
}
// -------------------------------------
// Generate Output structure for Surface Description function
GraphUtil.GenerateSurfaceDescriptionStruct(surfaceDescriptionStruct, pixelSlots);
// -------------------------------------
// Generate Surface Description function
GraphUtil.GenerateSurfaceDescriptionFunction(
pixelNodes,
keywordPermutationsPerPixelNode,
masterNode,
masterNode.owner as GraphData,
surfaceDescriptionFunction,
functionRegistry,
shaderProperties,
shaderKeywords,
mode,
"PopulateSurfaceData",
"SurfaceDescription",
null,
pixelSlots);
// ----------------------------------------------------- //
// GENERATE VERTEX > PIXEL PIPELINE //
// ----------------------------------------------------- //
// -------------------------------------
// Keyword declarations
shaderKeywords.GetKeywordsDeclaration(shaderKeywordDeclarations, mode);
// -------------------------------------
// Property uniforms
shaderProperties.GetPropertiesDeclaration(shaderPropertyUniforms, mode, masterNode.owner.concretePrecision);
// -------------------------------------
// Generate Input structure for Vertex shader
GraphUtil.GenerateApplicationVertexInputs(vertexRequirements.Union(pixelRequirements.Union(modelRequirements)), 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,
modelRequirements,
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.AppendLines(shaderKeywordDeclarations.ToString());
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("${FaceSign}", faceSign.ToString());
resultPass = resultPass.Replace("${PixelShader}", pixelShader.ToString());
resultPass = resultPass.Replace("${PixelShaderSurfaceInputs}", pixelShaderSurfaceInputs.ToString());
resultPass = resultPass.Replace("${PixelShaderSurfaceRemap}", pixelShaderSurfaceRemap.ToString());
return resultPass;
}
}
}