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

570 行
26 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.Graphing;
using UnityEditor.ShaderGraph.Internal;
using Data.Util;
namespace UnityEditor.ShaderGraph
{
static class SubShaderGenerator
{
public static void GeneratePropertiesBlock(ShaderStringBuilder sb, PropertyCollector propertyCollector, KeywordCollector keywordCollector, GenerationMode mode)
{
sb.AppendLine("Properties");
using (sb.BlockScope())
{
foreach (var prop in propertyCollector.properties.Where(x => x.generatePropertyBlock))
{
sb.AppendLine(prop.GetPropertyBlockString());
}
// Keywords use hardcoded state in preview
// Do not add them to the Property Block
if(mode == GenerationMode.Preview)
return;
foreach (var key in keywordCollector.keywords.Where(x => x.generatePropertyBlock))
{
sb.AppendLine(key.GetPropertyBlockString());
}
}
}
public static void GenerateApplicationVertexInputs(ShaderGraphRequirements graphRequirements, ShaderStringBuilder vertexInputs)
{
vertexInputs.AppendLine("struct GraphVertexInput");
using (vertexInputs.BlockSemicolonScope())
{
vertexInputs.AppendLine("float4 vertex : POSITION;");
if(graphRequirements.requiresNormal != NeededCoordinateSpace.None || graphRequirements.requiresBitangent != NeededCoordinateSpace.None)
vertexInputs.AppendLine("float3 normal : NORMAL;");
if(graphRequirements.requiresTangent != NeededCoordinateSpace.None || graphRequirements.requiresBitangent != NeededCoordinateSpace.None)
vertexInputs.AppendLine("float4 tangent : TANGENT;");
if (graphRequirements.requiresVertexColor)
{
vertexInputs.AppendLine("float4 color : COLOR;");
}
foreach (var channel in graphRequirements.requiresMeshUVs.Distinct())
vertexInputs.AppendLine("float4 texcoord{0} : TEXCOORD{0};", (int)channel);
vertexInputs.AppendLine("UNITY_VERTEX_INPUT_INSTANCE_ID");
}
}
public static GenerationResults GetShader(this GraphData graph, AbstractMaterialNode node, GenerationMode mode, string name)
{
// ----------------------------------------------------- //
// SETUP //
// ----------------------------------------------------- //
// -------------------------------------
// String builders
var finalShader = new ShaderStringBuilder();
var results = new GenerationResults();
var shaderProperties = new PropertyCollector();
var shaderKeywords = new KeywordCollector();
var shaderPropertyUniforms = new ShaderStringBuilder();
var shaderKeywordDeclarations = new ShaderStringBuilder();
var shaderKeywordPermutations = new ShaderStringBuilder(1);
var functionBuilder = new ShaderStringBuilder();
var functionRegistry = new FunctionRegistry(functionBuilder);
var vertexDescriptionFunction = new ShaderStringBuilder(0);
var surfaceDescriptionInputStruct = new ShaderStringBuilder(0);
var surfaceDescriptionStruct = new ShaderStringBuilder(0);
var surfaceDescriptionFunction = new ShaderStringBuilder(0);
var vertexInputs = new ShaderStringBuilder(0);
graph.CollectShaderKeywords(shaderKeywords, mode);
if(graph.GetKeywordPermutationCount() > ShaderGraphPreferences.variantLimit)
{
graph.AddValidationError(node.tempId, ShaderKeyword.kVariantLimitWarning, Rendering.ShaderCompilerMessageSeverity.Error);
results.configuredTextures = shaderProperties.GetConfiguredTexutres();
results.shader = string.Empty;
return results;
}
// -------------------------------------
// Get Slot and Node lists
var activeNodeList = ListPool<AbstractMaterialNode>.Get();
NodeUtils.DepthFirstCollectNodesFromNode(activeNodeList, node);
var slots = new List<MaterialSlot>();
if (node is IMasterNode || node is SubGraphOutputNode)
slots.AddRange(node.GetInputSlots<MaterialSlot>());
else
{
var outputSlots = node.GetOutputSlots<MaterialSlot>().ToList();
if (outputSlots.Count > 0)
slots.Add(outputSlots[0]);
}
// -------------------------------------
// Get Requirements
var requirements = ShaderGraphRequirements.FromNodes(activeNodeList, ShaderStageCapability.Fragment);
// ----------------------------------------------------- //
// KEYWORDS //
// ----------------------------------------------------- //
// -------------------------------------
// Get keyword permutations
graph.CollectShaderKeywords(shaderKeywords, mode);
// Track permutation indicies for all nodes and requirements
List<int>[] keywordPermutationsPerNode = new List<int>[activeNodeList.Count];
// -------------------------------------
// Evaluate all permutations
for(int i = 0; i < shaderKeywords.permutations.Count; i++)
{
// Get active nodes for this permutation
var localNodes = ListPool<AbstractMaterialNode>.Get();
NodeUtils.DepthFirstCollectNodesFromNode(localNodes, node, keywordPermutation: shaderKeywords.permutations[i]);
// Track each pixel node in this permutation
foreach(AbstractMaterialNode pixelNode in localNodes)
{
int nodeIndex = activeNodeList.IndexOf(pixelNode);
if(keywordPermutationsPerNode[nodeIndex] == null)
keywordPermutationsPerNode[nodeIndex] = new List<int>();
keywordPermutationsPerNode[nodeIndex].Add(i);
}
// Get active requirements for this permutation
var localSurfaceRequirements = ShaderGraphRequirements.FromNodes(localNodes, ShaderStageCapability.Fragment, false);
var localPixelRequirements = ShaderGraphRequirements.FromNodes(localNodes, ShaderStageCapability.Fragment);
}
// ----------------------------------------------------- //
// START VERTEX DESCRIPTION //
// ----------------------------------------------------- //
// -------------------------------------
// Generate Vertex Description function
vertexDescriptionFunction.AppendLine("GraphVertexInput PopulateVertexData(GraphVertexInput v)");
using (vertexDescriptionFunction.BlockScope())
{
vertexDescriptionFunction.AppendLine("return v;");
}
// ----------------------------------------------------- //
// START SURFACE DESCRIPTION //
// ----------------------------------------------------- //
// -------------------------------------
// Generate Input structure for Surface Description function
// Surface Description Input requirements are needed to exclude intermediate translation spaces
GenerateSurfaceInputStruct(surfaceDescriptionInputStruct, requirements, "SurfaceDescriptionInputs");
results.previewMode = PreviewMode.Preview2D;
foreach (var pNode in activeNodeList)
{
if (pNode.previewMode == PreviewMode.Preview3D)
{
results.previewMode = PreviewMode.Preview3D;
break;
}
}
// -------------------------------------
// Generate Output structure for Surface Description function
GenerateSurfaceDescriptionStruct(surfaceDescriptionStruct, slots, useIdsInNames: !(node is IMasterNode));
// -------------------------------------
// Generate Surface Description function
GenerateSurfaceDescriptionFunction(
activeNodeList,
keywordPermutationsPerNode,
node,
graph,
surfaceDescriptionFunction,
functionRegistry,
shaderProperties,
shaderKeywords,
mode,
outputIdProperty: results.outputIdProperty);
// ----------------------------------------------------- //
// GENERATE VERTEX > PIXEL PIPELINE //
// ----------------------------------------------------- //
// -------------------------------------
// Keyword declarations
shaderKeywords.GetKeywordsDeclaration(shaderKeywordDeclarations, mode);
// -------------------------------------
// Property uniforms
shaderProperties.GetPropertiesDeclaration(shaderPropertyUniforms, mode, graph.concretePrecision);
// -------------------------------------
// Generate Input structure for Vertex shader
GenerateApplicationVertexInputs(requirements, vertexInputs);
// ----------------------------------------------------- //
// FINALIZE //
// ----------------------------------------------------- //
// -------------------------------------
// Build final shader
finalShader.AppendLine(@"Shader ""{0}""", name);
using (finalShader.BlockScope())
{
SubShaderGenerator.GeneratePropertiesBlock(finalShader, shaderProperties, shaderKeywords, mode);
finalShader.AppendNewLine();
finalShader.AppendLine(@"HLSLINCLUDE");
finalShader.AppendLine(@"#include ""Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl""");
finalShader.AppendLine(@"#include ""Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl""");
finalShader.AppendLine(@"#include ""Packages/com.unity.render-pipelines.core/ShaderLibrary/NormalSurfaceGradient.hlsl""");
finalShader.AppendLine(@"#include ""Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl""");
finalShader.AppendLine(@"#include ""Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl""");
finalShader.AppendLine(@"#include ""Packages/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlsl""");
finalShader.AppendLine(@"#include ""Packages/com.unity.shadergraph/ShaderGraphLibrary/ShaderVariables.hlsl""");
finalShader.AppendLine(@"#include ""Packages/com.unity.shadergraph/ShaderGraphLibrary/ShaderVariablesFunctions.hlsl""");
finalShader.AppendLine(@"#include ""Packages/com.unity.shadergraph/ShaderGraphLibrary/Functions.hlsl""");
finalShader.AppendLines(shaderKeywordDeclarations.ToString());
finalShader.AppendLine(@"#define SHADERGRAPH_PREVIEW 1");
finalShader.AppendNewLine();
finalShader.AppendLines(shaderKeywordPermutations.ToString());
finalShader.AppendLines(shaderPropertyUniforms.ToString());
finalShader.AppendNewLine();
finalShader.AppendLines(surfaceDescriptionInputStruct.ToString());
finalShader.AppendNewLine();
finalShader.Concat(functionBuilder);
finalShader.AppendNewLine();
finalShader.AppendLines(surfaceDescriptionStruct.ToString());
finalShader.AppendNewLine();
finalShader.AppendLines(surfaceDescriptionFunction.ToString());
finalShader.AppendNewLine();
finalShader.AppendLines(vertexInputs.ToString());
finalShader.AppendNewLine();
finalShader.AppendLines(vertexDescriptionFunction.ToString());
finalShader.AppendNewLine();
finalShader.AppendLine(@"ENDHLSL");
finalShader.AppendLines(ShaderGenerator.GetPreviewSubShader(node, requirements));
ListPool<AbstractMaterialNode>.Release(activeNodeList);
}
// -------------------------------------
// Finalize
results.configuredTextures = shaderProperties.GetConfiguredTexutres();
ShaderSourceMap sourceMap;
results.shader = finalShader.ToString(out sourceMap);
results.sourceMap = sourceMap;
return results;
}
public static void GenerateSurfaceInputStruct(ShaderStringBuilder sb, ShaderGraphRequirements requirements, string structName)
{
sb.AppendLine($"struct {structName}");
using (sb.BlockSemicolonScope())
{
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresNormal, InterpolatorType.Normal, sb);
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresTangent, InterpolatorType.Tangent, sb);
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresBitangent, InterpolatorType.BiTangent, sb);
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresViewDir, InterpolatorType.ViewDirection, sb);
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresPosition, InterpolatorType.Position, sb);
if (requirements.requiresVertexColor)
sb.AppendLine("float4 {0};", ShaderGeneratorNames.VertexColor);
if (requirements.requiresScreenPosition)
sb.AppendLine("float4 {0};", ShaderGeneratorNames.ScreenPosition);
if (requirements.requiresFaceSign)
sb.AppendLine("float {0};", ShaderGeneratorNames.FaceSign);
foreach (var channel in requirements.requiresMeshUVs.Distinct())
sb.AppendLine("half4 {0};", channel.GetUVName());
if (requirements.requiresTime)
{
sb.AppendLine("float3 {0};", ShaderGeneratorNames.TimeParameters);
}
}
}
public static void GenerateSurfaceInputTransferCode(ShaderStringBuilder sb, ShaderGraphRequirements requirements, string structName, string variableName)
{
sb.AppendLine($"{structName} {variableName};");
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresNormal, InterpolatorType.Normal, sb, $"{variableName}.{{0}} = IN.{{0}};");
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresTangent, InterpolatorType.Tangent, sb, $"{variableName}.{{0}} = IN.{{0}};");
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresBitangent, InterpolatorType.BiTangent, sb, $"{variableName}.{{0}} = IN.{{0}};");
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresViewDir, InterpolatorType.ViewDirection, sb, $"{variableName}.{{0}} = IN.{{0}};");
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresPosition, InterpolatorType.Position, sb, $"{variableName}.{{0}} = IN.{{0}};");
if (requirements.requiresVertexColor)
sb.AppendLine($"{variableName}.{ShaderGeneratorNames.VertexColor} = IN.{ShaderGeneratorNames.VertexColor};");
if (requirements.requiresScreenPosition)
sb.AppendLine($"{variableName}.{ShaderGeneratorNames.ScreenPosition} = IN.{ShaderGeneratorNames.ScreenPosition};");
if (requirements.requiresFaceSign)
sb.AppendLine($"{variableName}.{ShaderGeneratorNames.FaceSign} = IN.{ShaderGeneratorNames.FaceSign};");
foreach (var channel in requirements.requiresMeshUVs.Distinct())
sb.AppendLine($"{variableName}.{channel.GetUVName()} = IN.{channel.GetUVName()};");
if (requirements.requiresTime)
{
sb.AppendLine($"{variableName}.{ShaderGeneratorNames.TimeParameters} = IN.{ShaderGeneratorNames.TimeParameters};");
}
}
public static void GenerateSurfaceDescriptionStruct(ShaderStringBuilder surfaceDescriptionStruct, List<MaterialSlot> slots, string structName = "SurfaceDescription", IActiveFieldsSet activeFields = null, bool useIdsInNames = false)
{
surfaceDescriptionStruct.AppendLine("struct {0}", structName);
using (surfaceDescriptionStruct.BlockSemicolonScope())
{
foreach (var slot in slots)
{
string hlslName = NodeUtils.GetHLSLSafeName(slot.shaderOutputName);
if (useIdsInNames)
{
hlslName = $"{hlslName}_{slot.id}";
}
surfaceDescriptionStruct.AppendLine("{0} {1};", slot.concreteValueType.ToShaderString(slot.owner.concretePrecision), hlslName);
if (activeFields != null)
{
activeFields.AddAll(structName + "." + hlslName);
}
}
}
}
public static void GenerateSurfaceDescriptionFunction(
List<AbstractMaterialNode> nodes,
List<int>[] keywordPermutationsPerNode,
AbstractMaterialNode rootNode,
GraphData graph,
ShaderStringBuilder surfaceDescriptionFunction,
FunctionRegistry functionRegistry,
PropertyCollector shaderProperties,
KeywordCollector shaderKeywords,
GenerationMode mode,
string functionName = "PopulateSurfaceData",
string surfaceDescriptionName = "SurfaceDescription",
Vector1ShaderProperty outputIdProperty = null,
IEnumerable<MaterialSlot> slots = null,
string graphInputStructName = "SurfaceDescriptionInputs")
{
if (graph == null)
return;
graph.CollectShaderProperties(shaderProperties, mode);
surfaceDescriptionFunction.AppendLine(String.Format("{0} {1}(SurfaceDescriptionInputs IN)", surfaceDescriptionName, functionName), false);
using (surfaceDescriptionFunction.BlockScope())
{
surfaceDescriptionFunction.AppendLine("{0} surface = ({0})0;", surfaceDescriptionName);
for(int i = 0; i < nodes.Count; i++)
{
GenerateDescriptionForNode(nodes[i], keywordPermutationsPerNode[i], functionRegistry, surfaceDescriptionFunction,
shaderProperties, shaderKeywords,
graph, mode);
}
functionRegistry.builder.currentNode = null;
surfaceDescriptionFunction.currentNode = null;
GenerateSurfaceDescriptionRemap(graph, rootNode, slots,
surfaceDescriptionFunction, mode);
surfaceDescriptionFunction.AppendLine("return surface;");
}
}
static void GenerateDescriptionForNode(
AbstractMaterialNode activeNode,
List<int> keywordPermutations,
FunctionRegistry functionRegistry,
ShaderStringBuilder descriptionFunction,
PropertyCollector shaderProperties,
KeywordCollector shaderKeywords,
GraphData graph,
GenerationMode mode)
{
if (activeNode is IGeneratesFunction functionNode)
{
functionRegistry.builder.currentNode = activeNode;
functionNode.GenerateNodeFunction(functionRegistry, mode);
functionRegistry.builder.ReplaceInCurrentMapping(PrecisionUtil.Token, activeNode.concretePrecision.ToShaderString());
}
if (activeNode is IGeneratesBodyCode bodyNode)
{
if(keywordPermutations != null)
descriptionFunction.AppendLine(KeywordUtil.GetKeywordPermutationSetConditional(keywordPermutations));
descriptionFunction.currentNode = activeNode;
bodyNode.GenerateNodeCode(descriptionFunction, mode);
descriptionFunction.ReplaceInCurrentMapping(PrecisionUtil.Token, activeNode.concretePrecision.ToShaderString());
if(keywordPermutations != null)
descriptionFunction.AppendLine("#endif");
}
activeNode.CollectShaderProperties(shaderProperties, mode);
if (activeNode is SubGraphNode subGraphNode)
{
subGraphNode.CollectShaderKeywords(shaderKeywords, mode);
}
}
static void GenerateSurfaceDescriptionRemap(
GraphData graph,
AbstractMaterialNode rootNode,
IEnumerable<MaterialSlot> slots,
ShaderStringBuilder surfaceDescriptionFunction,
GenerationMode mode)
{
if (rootNode is IMasterNode || rootNode is SubGraphOutputNode)
{
var usedSlots = slots ?? rootNode.GetInputSlots<MaterialSlot>();
foreach (var input in usedSlots)
{
if (input != null)
{
var foundEdges = graph.GetEdges(input.slotReference).ToArray();
var hlslName = NodeUtils.GetHLSLSafeName(input.shaderOutputName);
if (rootNode is SubGraphOutputNode)
{
hlslName = $"{hlslName}_{input.id}";
}
if (foundEdges.Any())
{
surfaceDescriptionFunction.AppendLine("surface.{0} = {1};",
hlslName,
rootNode.GetSlotValue(input.id, mode, rootNode.concretePrecision));
}
else
{
surfaceDescriptionFunction.AppendLine("surface.{0} = {1};",
hlslName, input.GetDefaultValue(mode, rootNode.concretePrecision));
}
}
}
}
else if (rootNode.hasPreview)
{
var slot = rootNode.GetOutputSlots<MaterialSlot>().FirstOrDefault();
if (slot != null)
{
var hlslSafeName = $"{NodeUtils.GetHLSLSafeName(slot.shaderOutputName)}_{slot.id}";
surfaceDescriptionFunction.AppendLine("surface.{0} = {1};",
hlslSafeName, rootNode.GetSlotValue(slot.id, mode, rootNode.concretePrecision));
}
}
}
const string k_VertexDescriptionStructName = "VertexDescription";
public static void GenerateVertexDescriptionStruct(ShaderStringBuilder builder, List<MaterialSlot> slots, string structName = k_VertexDescriptionStructName, IActiveFieldsSet activeFields = null)
{
builder.AppendLine("struct {0}", structName);
using (builder.BlockSemicolonScope())
{
foreach (var slot in slots)
{
string hlslName = NodeUtils.GetHLSLSafeName(slot.shaderOutputName);
builder.AppendLine("{0} {1};", slot.concreteValueType.ToShaderString(slot.owner.concretePrecision), hlslName);
if (activeFields != null)
{
activeFields.AddAll(structName + "." + hlslName);
}
}
}
}
public static void GenerateVertexDescriptionFunction(
GraphData graph,
ShaderStringBuilder builder,
FunctionRegistry functionRegistry,
PropertyCollector shaderProperties,
KeywordCollector shaderKeywords,
GenerationMode mode,
AbstractMaterialNode rootNode,
List<AbstractMaterialNode> nodes,
List<int>[] keywordPermutationsPerNode,
List<MaterialSlot> slots,
string graphInputStructName = "VertexDescriptionInputs",
string functionName = "PopulateVertexData",
string graphOutputStructName = k_VertexDescriptionStructName)
{
if (graph == null)
return;
graph.CollectShaderProperties(shaderProperties, mode);
builder.AppendLine("{0} {1}({2} IN)", graphOutputStructName, functionName, graphInputStructName);
using (builder.BlockScope())
{
builder.AppendLine("{0} description = ({0})0;", graphOutputStructName);
for(int i = 0; i < nodes.Count; i++)
{
GenerateDescriptionForNode(nodes[i], keywordPermutationsPerNode[i], functionRegistry, builder,
shaderProperties, shaderKeywords,
graph, mode);
}
functionRegistry.builder.currentNode = null;
builder.currentNode = null;
if(slots.Count != 0)
{
foreach (var slot in slots)
{
var isSlotConnected = slot.owner.owner.GetEdges(slot.slotReference).Any();
var slotName = NodeUtils.GetHLSLSafeName(slot.shaderOutputName);
var slotValue = isSlotConnected ?
((AbstractMaterialNode)slot.owner).GetSlotValue(slot.id, mode, slot.owner.concretePrecision) : slot.GetDefaultValue(mode, slot.owner.concretePrecision);
builder.AppendLine("description.{0} = {1};", slotName, slotValue);
}
}
builder.AppendLine("return description;");
}
}
public static GenerationResults GetPreviewShader(this GraphData graph, AbstractMaterialNode node)
{
return graph.GetShader(node, GenerationMode.Preview, String.Format("hidden/preview/{0}", node.GetVariableNameForNode()));
}
}
}