Working on Chapter 2, draft of Chapter 1 is completed

This commit is contained in:
2026-07-17 15:09:17 +01:00
parent 6cf1f7d8f3
commit 01ce568c47
1292 changed files with 294021 additions and 101198 deletions

View File

@@ -1,97 +0,0 @@
using System;
using System.Linq;
using System.Collections.Generic;
namespace UnityEditor.ShaderGraph
{
[GenerationAPI]
internal class TargetSetupContext
{
public List<SubShaderDescriptor> subShaders { get; private set; }
public KernelCollection kernels { get; private set; }
public AssetCollection assetCollection { get; private set; }
// these are data that are now stored in the subshaders.
// but for backwards compatibility with the existing Targets,
// we store the values provided directly by the Target,
// and apply them to all of the subShaders provided by the Target (that don't have their own setting)
// the Targets are free to switch to specifying these values per SubShaderDescriptor instead,
// if they want to specify different values for each subshader.
private List<ShaderCustomEditor> customEditorForRenderPipelines;
private string defaultShaderGUI;
// assetCollection is used to gather asset dependencies
public TargetSetupContext(AssetCollection assetCollection = null)
{
subShaders = new List<SubShaderDescriptor>();
kernels = new KernelCollection();
this.assetCollection = assetCollection;
}
public void SetupFinalize()
{
// copy custom editors to each subshader, if they don't have their own specification
if (subShaders == null)
return;
for (int i = 0; i < subShaders.Count; i++)
{
var subShader = subShaders[i];
if ((subShader.shaderCustomEditors == null) && (customEditorForRenderPipelines != null))
subShader.shaderCustomEditors = new List<ShaderCustomEditor>(customEditorForRenderPipelines);
if (subShader.shaderCustomEditor == null)
subShader.shaderCustomEditor = defaultShaderGUI;
subShaders[i] = subShader; // yay C# structs
}
}
public void AddSubShader(SubShaderDescriptor subShader)
{
subShaders.Add(subShader);
}
public void AddKernel(KernelDescriptor kernel)
{
kernels.Add(kernel);
}
public void AddAssetDependency(GUID guid, AssetCollection.Flags flags)
{
assetCollection?.AddAssetDependency(guid, flags);
}
public void SetDefaultShaderGUI(string defaultShaderGUI)
{
this.defaultShaderGUI = defaultShaderGUI;
}
public void AddCustomEditorForRenderPipeline(string shaderGUI, Type renderPipelineAssetType)
=> AddCustomEditorForRenderPipeline(shaderGUI, renderPipelineAssetType.FullName);
public void AddCustomEditorForRenderPipeline(string shaderGUI, string renderPipelineAssetTypeFullName)
{
if (customEditorForRenderPipelines == null)
customEditorForRenderPipelines = new List<ShaderCustomEditor>();
customEditorForRenderPipelines.Add(
new ShaderCustomEditor()
{
shaderGUI = shaderGUI,
renderPipelineAssetType = renderPipelineAssetTypeFullName
});
}
public bool HasCustomEditorForRenderPipeline<RPT>()
=> HasCustomEditorForRenderPipeline(typeof(RPT).FullName);
public bool HasCustomEditorForRenderPipeline(Type renderPipelineAssetType)
=> HasCustomEditorForRenderPipeline(renderPipelineAssetType.FullName);
public bool HasCustomEditorForRenderPipeline(string renderPipelineAssetTypeFullName)
=> customEditorForRenderPipelines?.Any(c => c.renderPipelineAssetType == renderPipelineAssetTypeFullName) ?? false;
}
}

View File

@@ -1,510 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using UnityEditor.ShaderGraph.Internal;
using UnityEngine.Profiling;
namespace UnityEditor.ShaderGraph
{
static class ShaderSpliceUtil
{
private static char[] channelNames =
{ 'x', 'y', 'z', 'w' };
private static char[] whitespace =
{ ' ', '\t', '\r', '\n', '\f'};
public static string GetChannelSwizzle(int firstChannel, int channelCount)
{
System.Text.StringBuilder result = new System.Text.StringBuilder();
int lastChannel = System.Math.Min(firstChannel + channelCount - 1, 4);
for (int index = firstChannel; index <= lastChannel; index++)
{
result.Append(channelNames[index]);
}
return result.ToString();
}
// returns the offset of the first non-whitespace character, in the range [start, end] inclusive ... will return end if none found
private static int SkipWhitespace(string str, int start, int end)
{
int index = start;
while (index < end)
{
char c = str[index];
bool containsWhiteSpace = false;
foreach (var whiteSpaceChar in whitespace)
{
if (c == whiteSpaceChar)
{
containsWhiteSpace = true;
break;
}
}
if (!containsWhiteSpace)
{
break;
}
index++;
}
return index;
}
public class TemplatePreprocessor
{
// inputs
ActiveFields activeFields;
Dictionary<string, string> namedFragments;
string[] templatePaths;
bool isDebug;
// intermediates
HashSet<string> includedFiles;
Dictionary<string, string[]> includeCache; // this cache is reused across passes
// outputs
ShaderStringBuilder result;
AssetCollection assetCollection;
public TemplatePreprocessor(ActiveFields activeFields, Dictionary<string, string> namedFragments, bool isDebug, string[] templatePaths, AssetCollection assetCollection, bool humanReadable, Dictionary<string, string[]> includeCache, ShaderStringBuilder outShaderCodeResult = null)
{
this.activeFields = activeFields;
this.namedFragments = namedFragments;
this.isDebug = isDebug;
this.templatePaths = templatePaths;
this.assetCollection = assetCollection;
this.result = outShaderCodeResult ?? new ShaderStringBuilder(humanReadable: humanReadable);
includedFiles = new HashSet<string>();
this.includeCache = includeCache;
}
public ShaderStringBuilder GetShaderCode()
{
return result;
}
public void ProcessTemplateFile(string filePath)
{
if (!includedFiles.Contains(filePath) && (includeCache.ContainsKey(filePath) || File.Exists(filePath)))
{
includedFiles.Add(filePath);
if (assetCollection != null)
{
GUID guid = AssetDatabase.GUIDFromAssetPath(filePath);
if (!guid.Empty())
assetCollection.AddAssetDependency(guid, AssetCollection.Flags.SourceDependency);
}
string[] templateLines;
if (!includeCache.TryGetValue(filePath, out templateLines))
{
templateLines = File.ReadAllLines(filePath);
includeCache.TryAdd(filePath, templateLines);
} foreach (string line in templateLines)
{
ProcessTemplateLine(line, 0, line.Length);
}
}
}
private struct Token
{
public string s;
public int start;
public int end;
public Token(string s, int start, int end)
{
this.s = s;
this.start = start;
this.end = end;
}
public static Token Invalid()
{
return new Token(null, 0, 0);
}
public bool IsValid()
{
return (s != null);
}
public bool Is(string other)
{
int len = end - start;
return (other.Length == len) && (0 == string.CompareOrdinal(s, start, other, 0, len));
}
public string GetString()
{
int len = end - start;
if (len > 0)
{
return s.Substring(start, end - start);
}
return null;
}
}
public void ProcessTemplateLine(string line, int start, int end)
{
bool appendEndln = true;
int cur = start;
while (cur < end)
{
// find an escape code '$'
int dollar = line.IndexOf('$', cur, end - cur);
if (dollar < 0)
{
// no escape code found in the remaining code -- just append the rest verbatim
AppendSubstring(line, cur, true, end, false);
break;
}
else
{
// found $ escape sequence
Token command = ParseIdentifier(line, dollar + 1, end);
if (!command.IsValid())
{
Error("ERROR: $ must be followed by a command string (if, splice, or include)", line, dollar + 1);
break;
}
else
{
if (command.Is("include"))
{
ProcessIncludeCommand(command, end);
appendEndln = false;
break; // include command always ignores the rest of the line, error or not
}
else if (command.Is("splice"))
{
if (!ProcessSpliceCommand(command, end, ref cur))
{
// error, skip the rest of the line
break;
}
}
else
{
// let's see if it is a predicate
Token predicate = ParseUntil(line, dollar + 1, end, ':');
if (!predicate.IsValid())
{
Error("ERROR: unrecognized command: " + command.GetString(), line, command.start);
break;
}
else
{
if (!ProcessPredicate(predicate, end, ref cur, ref appendEndln))
{
break; // skip the rest of the line
}
}
}
}
}
}
if (appendEndln)
{
result.AppendNewLine();
}
}
private void ProcessIncludeCommand(Token includeCommand, int lineEnd)
{
if (Expect(includeCommand.s, includeCommand.end, '('))
{
Token param = ParseString(includeCommand.s, includeCommand.end + 1, lineEnd);
if (!param.IsValid())
{
Error("ERROR: $include expected a string file path parameter", includeCommand.s, includeCommand.end + 1);
}
else
{
bool found = false;
string includeLocation = null;
// Use reverse order in the array, higher number element have higher priority in case $include exist in several directories
for (int i = templatePaths.Length - 1; i >= 0; i--)
{
string templatePath = templatePaths[i];
includeLocation = Path.Combine(templatePath, param.GetString());
bool cacheHit = includeCache.ContainsKey(includeLocation);
if (cacheHit || File.Exists(includeLocation)) {
found = true;
break;
}
}
if (!found)
{
string errorStr = "ERROR: $include cannot find file : " + param.GetString() + ". Looked into:\n";
foreach (string templatePath in templatePaths)
{
errorStr += "// " + templatePath + "\n";
}
Error(errorStr, includeCommand.s, param.start);
}
else
{
int oldLength = result.length;
// Wrap in debug mode
if (isDebug)
{
result.AppendLine("//-------------------------------------------------------------------------------------");
result.AppendLine("// TEMPLATE INCLUDE : " + param.GetString());
result.AppendLine("//-------------------------------------------------------------------------------------");
result.AppendNewLine();
}
// Recursively process templates
ProcessTemplateFile(includeLocation);
// Wrap in debug mode
if (isDebug)
{
result.AppendNewLine();
result.AppendLine("//-------------------------------------------------------------------------------------");
result.AppendLine("// END TEMPLATE INCLUDE : " + param.GetString());
result.AppendLine("//-------------------------------------------------------------------------------------");
}
result.ToCodeBlock(oldLength, result.length - oldLength, true);
}
}
}
}
private bool ProcessSpliceCommand(Token spliceCommand, int lineEnd, ref int cur)
{
if (!Expect(spliceCommand.s, spliceCommand.end, '('))
{
return false;
}
else
{
Token param = ParseUntil(spliceCommand.s, spliceCommand.end + 1, lineEnd, ')');
if (!param.IsValid())
{
Error("ERROR: splice command is missing a ')'", spliceCommand.s, spliceCommand.start);
return false;
}
else
{
// append everything before the beginning of the escape sequence
AppendSubstring(spliceCommand.s, cur, true, spliceCommand.start - 1, false);
// find the named fragment
string name = param.GetString(); // unfortunately this allocates a new string
string fragment;
if ((namedFragments != null) && namedFragments.TryGetValue(name, out fragment))
{
// splice the fragment
result.Append(fragment);
}
else
{
// no named fragment found
result.Append("/* WARNING: $splice Could not find named fragment '{0}' */", name);
}
// advance to just after the ')' and continue parsing
cur = param.end + 1;
}
}
return true;
}
private bool ContainsCommand(string source, int begin, int end)
{
for (int i = begin; i < end && i < source.Length; ++i)
{
if (source[i] == '$')
return true;
}
return false;
}
private bool ProcessPredicate(Token predicate, int endLine, ref int cur, ref bool appendEndln)
{
// eval if(param)
var fieldName = predicate.GetString();
var nonwhitespace = SkipWhitespace(predicate.s, predicate.end + 1, endLine);
if (!fieldName.StartsWith("features", StringComparison.Ordinal) && activeFields.permutationCount > 0)
{
var passedPermutations = activeFields.allPermutations.instances.Where(i => i.Contains(fieldName)).ToList();
if (passedPermutations.Count > 0)
{
var ifdefs = KeywordUtil.GetKeywordPermutationSetConditional(
passedPermutations.Select(i => i.permutationIndex).ToList()
);
result.AppendLine(ifdefs);
//Append the rest of the line
var content = predicate.s;
if (ContainsCommand(content, nonwhitespace, endLine))
{
content = content.Substring(nonwhitespace, endLine - nonwhitespace);
ProcessTemplateLine(content, 0, content.Length);
}
else
{
AppendSubstring(predicate.s, nonwhitespace, true, endLine, false);
}
result.AppendNewLine();
result.AppendLine("#endif");
return false;
}
else
{
appendEndln = false; //if line isn't active, remove whitespace
}
return false;
}
else
{
// eval if(param)
bool contains = activeFields.baseInstance.Contains(fieldName);
if (contains)
{
// predicate is active
// append everything before the beginning of the escape sequence
AppendSubstring(predicate.s, cur, true, predicate.start - 1, false);
// continue parsing the rest of the line, starting with the first nonwhitespace character
cur = nonwhitespace;
return true;
}
else
{
// predicate is not active
if (isDebug)
{
// append everything before the beginning of the escape sequence
AppendSubstring(predicate.s, cur, true, predicate.start - 1, false);
// append the rest of the line, commented out
result.Append("// ");
AppendSubstring(predicate.s, nonwhitespace, true, endLine, false);
}
else
{
// don't append anything
appendEndln = false;
}
return false;
}
}
}
private static bool IsLetter(char c)
{
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
}
private static bool IsLetterOrDigit(char c)
{
return IsLetter(c) || Char.IsDigit(c);
}
private Token ParseIdentifier(string code, int start, int end)
{
if (start < end)
{
char c = code[start];
if (IsLetter(c) || (c == '_'))
{
int cur = start + 1;
while (cur < end)
{
c = code[cur];
if (!(IsLetterOrDigit(c) || (c == '_')))
break;
cur++;
}
return new Token(code, start, cur);
}
}
return Token.Invalid();
}
private Token ParseString(string line, int start, int end)
{
if (Expect(line, start, '"'))
{
return ParseUntil(line, start + 1, end, '"');
}
return Token.Invalid();
}
private Token ParseUntil(string line, int start, int end, char endChar)
{
int cur = start;
while (cur < end)
{
if (line[cur] == endChar)
{
return new Token(line, start, cur);
}
cur++;
}
return Token.Invalid();
}
private bool Expect(string line, int location, char expected)
{
if ((location < line.Length) && (line[location] == expected))
{
return true;
}
Error("Expected '" + expected + "'", line, location);
return false;
}
private void Error(string error, string line, int location)
{
// append the line for context
result.Append("\n");
result.Append("// ");
AppendSubstring(line, 0, true, line.Length, false);
result.Append("\n");
// append the location marker, and error description
result.Append("// ");
result.AppendSpaces(location);
result.Append("^ ");
result.Append(error);
result.Append("\n");
}
// an easier to use version of substring Append() -- explicit inclusion on each end, and checks for positive length
private void AppendSubstring(string str, int start, bool includeStart, int end, bool includeEnd)
{
if (!includeStart)
{
start++;
}
if (!includeEnd)
{
end--;
}
int count = end - start + 1;
if (count > 0)
{
result.Append(str, start, count);
}
}
}
}
}

View File

@@ -1,89 +0,0 @@
using System;
using UnityEditor.ShaderGraph;
using UnityEngine.UIElements;
using UnityEditor.Rendering.Canvas.ShaderGraph;
namespace UnityEditor.Rendering.BuiltIn.ShaderGraph
{
class BuiltInCanvasSubTarget : CanvasSubTarget<BuiltInTarget>, IRequiresData<CanvasData>, IHasMetadata
{
static readonly GUID kSourceCodeGuid = new GUID("5a0372ef872c4103b70866297bd45e38"); // BuiltInCanvasSubTarget.cs
static readonly string kCanvasPass = "Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/Editor/ShaderGraph/Includes/BuiltInCanvasPass.hlsl";
public BuiltInCanvasSubTarget()
{
displayName = "Canvas";
}
public override object saveContext => null;
protected override string pipelineTag { get; }
public override bool IsActive() => true;
public override void Setup(ref TargetSetupContext context)
{
context.AddAssetDependency(kSourceCodeGuid, AssetCollection.Flags.SourceDependency);
context.AddSubShader(GenerateDefaultSubshader( false ));
}
public override void GetActiveBlocks(ref TargetActiveBlockContext context)
{
base.GetActiveBlocks(ref context);
context.AddBlock(BlockFields.SurfaceDescription.Alpha, target.alphaClip);
context.AddBlock(BlockFields.SurfaceDescription.AlphaClipThreshold, target.alphaClip);
}
public override void GetFields(ref TargetFieldContext context)
{
if(target.alphaClip)
context.AddField(UnityEditor.ShaderGraph.Fields.AlphaTest);
base.GetFields(ref context);
}
protected override IncludeCollection pregraphIncludes => new IncludeCollection
{
{ CoreIncludes.CorePregraph },
{ kInstancing, IncludeLocation.Pregraph },
{ CoreIncludes.ShaderGraphPregraph },
};
protected override IncludeCollection postgraphIncludes => new IncludeCollection
{
{kCanvasPass, IncludeLocation.Postgraph},
};
protected override DefineCollection GetAdditionalDefines()
{
var result = new DefineCollection() { CoreDefines.BuiltInTargetAPI };
if (target.alphaClip)
result.Add(CoreKeywordDescriptors.AlphaTestOn, 1);
result.Add(base.GetAdditionalDefines());
return result;
}
protected override KeywordCollection GetAdditionalKeywords() => new KeywordCollection {};
public override void GetPropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action<string> registerUndo)
{
var builtInTarget = (target as BuiltInTarget);
context.AddProperty("Alpha Clipping", new Toggle() { value = builtInTarget.alphaClip }, (evt) =>
{
if (Equals(builtInTarget.alphaClip, evt.newValue))
return;
registerUndo("Change Alpha Clip");
builtInTarget.alphaClip = evt.newValue;
onChange();
});
// copied from subtarget, because built-in overrides this function completely.
context.AddProperty("Disable Color Tint", new Toggle() { value = canvasData.disableTint }, (evt) =>
{
if (Equals(canvasData.disableTint, evt.newValue))
return;
registerUndo("Disable Tint");
canvasData.disableTint = evt.newValue;
onChange();
});
}
}
}

View File

@@ -1,660 +0,0 @@
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor.ShaderGraph;
using UnityEngine.Rendering;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
using UnityEditor.ShaderGraph.Legacy;
using static UnityEditor.Rendering.BuiltIn.ShaderUtils;
namespace UnityEditor.Rendering.BuiltIn.ShaderGraph
{
sealed class BuiltInLitSubTarget : BuiltInSubTarget
{
static readonly GUID kSourceCodeGuid = new GUID("8c2d5b55aa47443878a55a05f4294270"); // BuiltInLitSubTarget.cs
[SerializeField]
WorkflowMode m_WorkflowMode = WorkflowMode.Metallic;
[SerializeField]
NormalDropOffSpace m_NormalDropOffSpace = NormalDropOffSpace.Tangent;
public BuiltInLitSubTarget()
{
displayName = "Lit";
}
protected override ShaderID shaderID => ShaderID.SG_Lit;
public WorkflowMode workflowMode
{
get => m_WorkflowMode;
set => m_WorkflowMode = value;
}
public NormalDropOffSpace normalDropOffSpace
{
get => m_NormalDropOffSpace;
set => m_NormalDropOffSpace = value;
}
public override bool IsActive() => true;
public override void Setup(ref TargetSetupContext context)
{
context.AddAssetDependency(kSourceCodeGuid, AssetCollection.Flags.SourceDependency);
if (!context.HasCustomEditorForRenderPipeline("") && String.IsNullOrEmpty(target.customEditorGUI))
context.AddCustomEditorForRenderPipeline(typeof(BuiltInLitGUI).FullName, "");
// Process SubShaders
context.AddSubShader(SubShaders.Lit(target, target.renderType, target.renderQueue));
}
public override void ProcessPreviewMaterial(Material material)
{
if (target.allowMaterialOverride)
{
// copy our target's default settings into the material
// (technically not necessary since we are always recreating the material from the shader each time,
// which will pull over the defaults from the shader definition)
// but if that ever changes, this will ensure the defaults are set
material.SetFloat(Property.SpecularWorkflowMode(), (float)workflowMode);
material.SetFloat(Property.Surface(), (float)target.surfaceType);
material.SetFloat(Property.Blend(), (float)target.alphaMode);
material.SetFloat(Property.AlphaClip(), target.alphaClip ? 1.0f : 0.0f);
material.SetFloat(Property.Cull(), (int)target.renderFace);
material.SetFloat(Property.ZWriteControl(), (float)target.zWriteControl);
material.SetFloat(Property.ZTest(), (float)target.zTestMode);
}
// We always need these properties regardless of whether the material is allowed to override
// Queue control & offset enable correct automatic render queue behavior
// Control == 0 is automatic, 1 is user-specified render queue
material.SetFloat(Property.QueueOffset(), 0.0f);
material.SetFloat(Property.QueueControl(), (float)BuiltInBaseShaderGUI.QueueControl.Auto);
// call the full unlit material setup function
BuiltInLitGUI.UpdateMaterial(material);
}
public override void GetFields(ref TargetFieldContext context)
{
var descs = context.blocks.Select(x => x.descriptor);
// Lit
context.AddField(BuiltInFields.NormalDropOffOS, normalDropOffSpace == NormalDropOffSpace.Object);
context.AddField(BuiltInFields.NormalDropOffTS, normalDropOffSpace == NormalDropOffSpace.Tangent);
context.AddField(BuiltInFields.NormalDropOffWS, normalDropOffSpace == NormalDropOffSpace.World);
context.AddField(BuiltInFields.SpecularSetup, workflowMode == WorkflowMode.Specular);
context.AddField(BuiltInFields.Normal, descs.Contains(BlockFields.SurfaceDescription.NormalOS) ||
descs.Contains(BlockFields.SurfaceDescription.NormalTS) ||
descs.Contains(BlockFields.SurfaceDescription.NormalWS));
}
public override void GetActiveBlocks(ref TargetActiveBlockContext context)
{
context.AddBlock(BlockFields.SurfaceDescription.Smoothness);
context.AddBlock(BlockFields.SurfaceDescription.NormalOS, normalDropOffSpace == NormalDropOffSpace.Object);
context.AddBlock(BlockFields.SurfaceDescription.NormalTS, normalDropOffSpace == NormalDropOffSpace.Tangent);
context.AddBlock(BlockFields.SurfaceDescription.NormalWS, normalDropOffSpace == NormalDropOffSpace.World);
context.AddBlock(BlockFields.SurfaceDescription.Emission);
context.AddBlock(BlockFields.SurfaceDescription.Occlusion);
// when the surface options are material controlled, we must show all of these blocks
// when target controlled, we can cull the unnecessary blocks
// NOTE: Specular workflow is not supported so we need to not have this check now,
// otherwise allowMaterialOverride will show a block that does nothing.
//context.AddBlock(BlockFields.SurfaceDescription.Specular, (workflowMode == WorkflowMode.Specular) || target.allowMaterialOverride);
context.AddBlock(BlockFields.SurfaceDescription.Metallic, (workflowMode == WorkflowMode.Metallic) || target.allowMaterialOverride);
context.AddBlock(BlockFields.SurfaceDescription.Alpha, (target.surfaceType == SurfaceType.Transparent || target.alphaClip) || target.allowMaterialOverride);
context.AddBlock(BlockFields.SurfaceDescription.AlphaClipThreshold, (target.alphaClip) || target.allowMaterialOverride);
}
public override void CollectShaderProperties(PropertyCollector collector, GenerationMode generationMode)
{
if (target.allowMaterialOverride)
{
base.CollectShaderProperties(collector, generationMode);
// setup properties using the defaults
collector.AddFloatProperty(Property.Surface(), (float)target.surfaceType);
collector.AddFloatProperty(Property.Blend(), (float)target.alphaMode);
collector.AddFloatProperty(Property.AlphaClip(), target.alphaClip ? 1.0f : 0.0f);
collector.AddFloatProperty(Property.SrcBlend(), 1.0f); // always set by material inspector (TODO : get src/dst blend and set here?)
collector.AddFloatProperty(Property.DstBlend(), 0.0f); // always set by material inspector
collector.AddFloatProperty(Property.ZWrite(), (target.surfaceType == SurfaceType.Opaque) ? 1.0f : 0.0f);
collector.AddFloatProperty(Property.ZWriteControl(), (float)target.zWriteControl);
collector.AddFloatProperty(Property.ZTest(), (float)target.zTestMode); // ztest mode is designed to directly pass as ztest
collector.AddFloatProperty(Property.Cull(), (float)target.renderFace); // render face enum is designed to directly pass as a cull mode
}
// We always need these properties regardless of whether the material is allowed to override other shader properties.
// Queue control & offset enable correct automatic render queue behavior. Control == 0 is automatic, 1 is user-specified.
// We initialize queue control to -1 to indicate to UpdateMaterial that it needs to initialize it properly on the material.
collector.AddFloatProperty(Property.QueueOffset(), 0.0f);
collector.AddFloatProperty(Property.QueueControl(), -1.0f);
}
public override void GetPropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action<String> registerUndo)
{
// Temporarily remove the workflow mode until specular is supported
//context.AddProperty("Workflow", new EnumField(WorkflowMode.Metallic) { value = workflowMode }, (evt) =>
//{
// if (Equals(workflowMode, evt.newValue))
// return;
// registerUndo("Change Workflow");
// workflowMode = (WorkflowMode)evt.newValue;
// onChange();
//});
// show the target default surface properties
var builtInTarget = (target as BuiltInTarget);
builtInTarget?.AddDefaultMaterialOverrideGUI(ref context, onChange, registerUndo);
builtInTarget?.GetDefaultSurfacePropertiesGUI(ref context, onChange, registerUndo);
context.AddProperty("Fragment Normal Space", new EnumField(NormalDropOffSpace.Tangent) { value = normalDropOffSpace }, (evt) =>
{
if (Equals(normalDropOffSpace, evt.newValue))
return;
registerUndo("Change Fragment Normal Space");
normalDropOffSpace = (NormalDropOffSpace)evt.newValue;
onChange();
});
}
#region SubShader
static class SubShaders
{
// Overloads to do inline PassDescriptor modifications
// NOTE: param order should match PassDescriptor field order for consistency
#region PassVariant
private static PassDescriptor PassVariant(in PassDescriptor source, PragmaCollection pragmas)
{
var result = source;
result.pragmas = pragmas;
return result;
}
private static PassDescriptor PassVariant(in PassDescriptor source, BlockFieldDescriptor[] vertexBlocks, BlockFieldDescriptor[] pixelBlocks, PragmaCollection pragmas, DefineCollection defines)
{
var result = source;
result.validVertexBlocks = vertexBlocks;
result.validPixelBlocks = pixelBlocks;
result.pragmas = pragmas;
result.defines = defines;
return result;
}
#endregion
// SM 2.0
public static SubShaderDescriptor Lit(BuiltInTarget target, string renderType, string renderQueue)
{
var result = new SubShaderDescriptor()
{
//pipelineTag = BuiltInTarget.kPipelineTag,
customTags = BuiltInTarget.kLitMaterialTypeTag,
renderType = renderType,
renderQueue = renderQueue,
generatesPreview = true,
passes = new PassCollection(),
};
result.passes.Add(LitPasses.Forward(target));
result.passes.Add(LitPasses.ForwardAdd(target));
result.passes.Add(LitPasses.Deferred(target));
result.passes.Add(CorePasses.ShadowCaster(target));
if (target.mayWriteDepth)
result.passes.Add(CorePasses.DepthOnly(target));
result.passes.Add(LitPasses.Meta(target));
result.passes.Add(CorePasses.SceneSelection(target));
result.passes.Add(CorePasses.ScenePicking(target));
return result;
}
}
#endregion
#region Passes
static class LitPasses
{
public static PassDescriptor Forward(BuiltInTarget target)
{
var result = new PassDescriptor()
{
// Definition
displayName = "BuiltIn Forward",
referenceName = "SHADERPASS_FORWARD",
lightMode = "ForwardBase",
useInPreview = true,
// Template
passTemplatePath = BuiltInTarget.kTemplatePath,
sharedTemplateDirectories = BuiltInTarget.kSharedTemplateDirectories,
// Port Mask
validVertexBlocks = CoreBlockMasks.Vertex,
validPixelBlocks = LitBlockMasks.FragmentLit,
// Fields
structs = CoreStructCollections.Default,
requiredFields = LitRequiredFields.Forward,
fieldDependencies = CoreFieldDependencies.Default,
// Conditional State
renderStates = CoreRenderStates.Default(target),
pragmas = CorePragmas.Forward, // NOTE: SM 2.0 only GL
defines = new DefineCollection() { CoreDefines.BuiltInTargetAPI },
keywords = new KeywordCollection { LitKeywords.Forward },
includes = LitIncludes.Forward,
// Custom Interpolator Support
customInterpolators = CoreCustomInterpDescriptors.Common
};
AddForwardSurfaceControlsToPass(ref result, target);
return result;
}
public static PassDescriptor ForwardAdd(BuiltInTarget target)
{
var result = new PassDescriptor()
{
// Definition
displayName = "BuiltIn ForwardAdd",
referenceName = "SHADERPASS_FORWARD_ADD",
lightMode = "ForwardAdd",
useInPreview = true,
// Template
passTemplatePath = BuiltInTarget.kTemplatePath,
sharedTemplateDirectories = BuiltInTarget.kSharedTemplateDirectories,
// Port Mask
validVertexBlocks = CoreBlockMasks.Vertex,
validPixelBlocks = LitBlockMasks.FragmentLit,
// Fields
structs = CoreStructCollections.Default,
requiredFields = LitRequiredFields.Forward,
fieldDependencies = CoreFieldDependencies.Default,
// Conditional State
renderStates = CoreRenderStates.ForwardAdd(target),
pragmas = CorePragmas.ForwardAdd, // NOTE: SM 2.0 only GL
defines = new DefineCollection() { CoreDefines.BuiltInTargetAPI },
keywords = new KeywordCollection { LitKeywords.ForwardAdd },
includes = LitIncludes.ForwardAdd,
// Custom Interpolator Support
customInterpolators = CoreCustomInterpDescriptors.Common
};
AddForwardAddControlsToPass(ref result, target);
return result;
}
public static PassDescriptor ForwardOnly(BuiltInTarget target)
{
var result = new PassDescriptor()
{
// Definition
displayName = "BuiltIn Forward Only",
referenceName = "SHADERPASS_FORWARDONLY",
lightMode = "BuiltInForwardOnly",
useInPreview = true,
// Template
passTemplatePath = BuiltInTarget.kTemplatePath,
sharedTemplateDirectories = BuiltInTarget.kSharedTemplateDirectories,
// Port Mask
validVertexBlocks = CoreBlockMasks.Vertex,
validPixelBlocks = LitBlockMasks.FragmentLit,
// Fields
structs = CoreStructCollections.Default,
requiredFields = LitRequiredFields.Forward,
fieldDependencies = CoreFieldDependencies.Default,
// Conditional State
renderStates = CoreRenderStates.Default(target),
pragmas = CorePragmas.Forward, // NOTE: SM 2.0 only GL
defines = new DefineCollection() { CoreDefines.BuiltInTargetAPI },
keywords = new KeywordCollection { LitKeywords.Forward },
includes = LitIncludes.Forward,
// Custom Interpolator Support
customInterpolators = CoreCustomInterpDescriptors.Common
};
AddForwardOnlyControlsToPass(ref result, target);
return result;
}
public static PassDescriptor Deferred(BuiltInTarget target)
{
var result = new PassDescriptor()
{
// Definition
displayName = "BuiltIn Deferred",
referenceName = "SHADERPASS_DEFERRED",
lightMode = "Deferred",
useInPreview = true,
// Template
passTemplatePath = BuiltInTarget.kTemplatePath,
sharedTemplateDirectories = BuiltInTarget.kSharedTemplateDirectories,
// Port Mask
validVertexBlocks = CoreBlockMasks.Vertex,
validPixelBlocks = LitBlockMasks.FragmentLit,
// Fields
structs = CoreStructCollections.Default,
requiredFields = LitRequiredFields.Forward,
fieldDependencies = CoreFieldDependencies.Default,
// Conditional State
renderStates = CoreRenderStates.Default(target),
pragmas = CorePragmas.Deferred, // NOTE: SM 2.0 only GL
defines = new DefineCollection() { CoreDefines.BuiltInTargetAPI },
keywords = new KeywordCollection { LitKeywords.Deferred },
includes = LitIncludes.Deferred,
// Custom Interpolator Support
customInterpolators = CoreCustomInterpDescriptors.Common
};
AddDeferredControlsToPass(ref result, target);
return result;
}
public static PassDescriptor Meta(BuiltInTarget target)
{
var result = new PassDescriptor()
{
// Definition
displayName = "Meta",
referenceName = "SHADERPASS_META",
lightMode = "Meta",
// Template
passTemplatePath = BuiltInTarget.kTemplatePath,
sharedTemplateDirectories = BuiltInTarget.kSharedTemplateDirectories,
// Port Mask
validVertexBlocks = CoreBlockMasks.Vertex,
validPixelBlocks = LitBlockMasks.FragmentMeta,
// Fields
structs = CoreStructCollections.Default,
requiredFields = LitRequiredFields.Meta,
fieldDependencies = CoreFieldDependencies.Default,
// Conditional State
renderStates = CoreRenderStates.Meta,
pragmas = CorePragmas.Default,
defines = new DefineCollection() { CoreDefines.BuiltInTargetAPI },
keywords = new KeywordCollection { LitKeywords.Meta },
includes = LitIncludes.Meta,
// Custom Interpolator Support
customInterpolators = CoreCustomInterpDescriptors.Common
};
AddMetaControlsToPass(ref result, target);
return result;
}
internal static void AddForwardSurfaceControlsToPass(ref PassDescriptor pass, BuiltInTarget target)
{
CorePasses.AddTargetSurfaceControlsToPass(ref pass, target);
}
internal static void AddForwardAddControlsToPass(ref PassDescriptor pass, BuiltInTarget target)
{
CorePasses.AddSurfaceTypeControlToPass(ref pass, target);
CorePasses.AddAlphaClipControlToPass(ref pass, target);
}
internal static void AddForwardOnlyControlsToPass(ref PassDescriptor pass, BuiltInTarget target)
{
CorePasses.AddTargetSurfaceControlsToPass(ref pass, target);
}
internal static void AddDeferredControlsToPass(ref PassDescriptor pass, BuiltInTarget target)
{
CorePasses.AddTargetSurfaceControlsToPass(ref pass, target);
}
internal static void AddMetaControlsToPass(ref PassDescriptor pass, BuiltInTarget target)
{
CorePasses.AddSurfaceTypeControlToPass(ref pass, target);
CorePasses.AddAlphaClipControlToPass(ref pass, target);
}
}
#endregion
#region PortMasks
static class LitBlockMasks
{
public static readonly BlockFieldDescriptor[] FragmentLit = new BlockFieldDescriptor[]
{
BlockFields.SurfaceDescription.BaseColor,
BlockFields.SurfaceDescription.NormalOS,
BlockFields.SurfaceDescription.NormalTS,
BlockFields.SurfaceDescription.NormalWS,
BlockFields.SurfaceDescription.Emission,
BlockFields.SurfaceDescription.Metallic,
BlockFields.SurfaceDescription.Specular,
BlockFields.SurfaceDescription.Smoothness,
BlockFields.SurfaceDescription.Occlusion,
BlockFields.SurfaceDescription.Alpha,
BlockFields.SurfaceDescription.AlphaClipThreshold,
};
public static readonly BlockFieldDescriptor[] FragmentMeta = new BlockFieldDescriptor[]
{
BlockFields.SurfaceDescription.BaseColor,
BlockFields.SurfaceDescription.Emission,
BlockFields.SurfaceDescription.Alpha,
BlockFields.SurfaceDescription.AlphaClipThreshold,
};
public static readonly BlockFieldDescriptor[] FragmentDepthNormals = new BlockFieldDescriptor[]
{
BlockFields.SurfaceDescription.NormalOS,
BlockFields.SurfaceDescription.NormalTS,
BlockFields.SurfaceDescription.NormalWS,
BlockFields.SurfaceDescription.Alpha,
BlockFields.SurfaceDescription.AlphaClipThreshold,
};
}
#endregion
#region RequiredFields
static class LitRequiredFields
{
public static readonly FieldCollection Forward = new FieldCollection()
{
StructFields.Attributes.uv1, // needed for meta vertex position
StructFields.Varyings.positionWS,
StructFields.Varyings.normalWS,
StructFields.Varyings.tangentWS, // needed for vertex lighting
BuiltInStructFields.Varyings.lightmapUV,
BuiltInStructFields.Varyings.sh,
BuiltInStructFields.Varyings.fogFactorAndVertexLight, // fog and vertex lighting, vert input is dependency
BuiltInStructFields.Varyings.shadowCoord, // shadow coord, vert input is dependency
};
public static readonly FieldCollection GBuffer = new FieldCollection()
{
StructFields.Attributes.uv1, // needed for meta vertex position
StructFields.Varyings.positionWS,
StructFields.Varyings.normalWS,
StructFields.Varyings.tangentWS, // needed for vertex lighting
BuiltInStructFields.Varyings.lightmapUV,
BuiltInStructFields.Varyings.sh,
BuiltInStructFields.Varyings.fogFactorAndVertexLight, // fog and vertex lighting, vert input is dependency
BuiltInStructFields.Varyings.shadowCoord, // shadow coord, vert input is dependency
};
public static readonly FieldCollection DepthNormals = new FieldCollection()
{
StructFields.Attributes.uv1, // needed for meta vertex position
StructFields.Varyings.normalWS,
StructFields.Varyings.tangentWS, // needed for vertex lighting
};
public static readonly FieldCollection Meta = new FieldCollection()
{
StructFields.Attributes.uv1, // needed for meta vertex position
StructFields.Attributes.uv2, //needed for meta vertex position
};
}
#endregion
#region Defines
#endregion
#region Keywords
static class LitKeywords
{
public static readonly KeywordDescriptor GBufferNormalsOct = new KeywordDescriptor()
{
displayName = "GBuffer normal octaedron encoding",
referenceName = "_GBUFFER_NORMALS_OCT",
type = KeywordType.Boolean,
definition = KeywordDefinition.MultiCompile,
scope = KeywordScope.Global,
};
public static readonly KeywordDescriptor ScreenSpaceAmbientOcclusion = new KeywordDescriptor()
{
displayName = "Screen Space Ambient Occlusion",
referenceName = "_SCREEN_SPACE_OCCLUSION",
type = KeywordType.Boolean,
definition = KeywordDefinition.MultiCompile,
scope = KeywordScope.Global,
};
public static readonly KeywordCollection Forward = new KeywordCollection
{
{ ScreenSpaceAmbientOcclusion },
{ CoreKeywordDescriptors.Lightmap },
{ CoreKeywordDescriptors.DirectionalLightmapCombined },
{ CoreKeywordDescriptors.MainLightShadows },
{ CoreKeywordDescriptors.AdditionalLights },
{ CoreKeywordDescriptors.AdditionalLightShadows },
{ CoreKeywordDescriptors.ShadowsSoft },
{ CoreKeywordDescriptors.LightmapShadowMixing },
{ CoreKeywordDescriptors.ShadowsShadowmask },
};
public static readonly KeywordCollection ForwardAdd = new KeywordCollection
{
{ ScreenSpaceAmbientOcclusion },
{ CoreKeywordDescriptors.Lightmap },
{ CoreKeywordDescriptors.DirectionalLightmapCombined },
{ CoreKeywordDescriptors.MainLightShadows },
{ CoreKeywordDescriptors.AdditionalLights },
{ CoreKeywordDescriptors.AdditionalLightShadows },
{ CoreKeywordDescriptors.ShadowsSoft },
{ CoreKeywordDescriptors.LightmapShadowMixing },
{ CoreKeywordDescriptors.ShadowsShadowmask },
};
public static readonly KeywordCollection Deferred = new KeywordCollection
{
{ CoreKeywordDescriptors.MainLightShadows },
{ CoreKeywordDescriptors.ShadowsSoft },
{ CoreKeywordDescriptors.LightmapShadowMixing },
{ CoreKeywordDescriptors.MixedLightingSubtractive },
{ GBufferNormalsOct },
};
public static readonly KeywordCollection Meta = new KeywordCollection
{
{ CoreKeywordDescriptors.SmoothnessChannel },
};
}
#endregion
#region Includes
static class LitIncludes
{
const string kShadows = "Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/ShaderLibrary/Shadows.hlsl";
const string kMetaInput = "Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/ShaderLibrary/MetaInput.hlsl";
const string kForwardPass = "Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/Editor/ShaderGraph/Includes/PBRForwardPass.hlsl";
const string kForwardAddPass = "Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/Editor/ShaderGraph/Includes/PBRForwardAddPass.hlsl";
const string kDeferredPass = "Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/Editor/ShaderGraph/Includes/PBRDeferredPass.hlsl";
const string kGBuffer = "Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/ShaderLibrary/UnityGBuffer.hlsl";
const string kPBRGBufferPass = "Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/Editor/ShaderGraph/Includes/PBRGBufferPass.hlsl";
const string kLightingMetaPass = "Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/Editor/ShaderGraph/Includes/LightingMetaPass.hlsl";
public static readonly IncludeCollection Forward = new IncludeCollection
{
// Pre-graph
{ CoreIncludes.CorePregraph },
{ CoreIncludes.ShaderGraphPregraph },
// Post-graph
{ CoreIncludes.CorePostgraph },
{ kForwardPass, IncludeLocation.Postgraph },
};
public static readonly IncludeCollection ForwardAdd = new IncludeCollection
{
// Pre-graph
{ CoreIncludes.CorePregraph },
{ CoreIncludes.ShaderGraphPregraph },
// Post-graph
{ CoreIncludes.CorePostgraph },
{ kForwardAddPass, IncludeLocation.Postgraph },
};
public static readonly IncludeCollection Deferred = new IncludeCollection
{
// Pre-graph
{ CoreIncludes.CorePregraph },
{ CoreIncludes.ShaderGraphPregraph },
// Post-graph
{ CoreIncludes.CorePostgraph },
{ kDeferredPass, IncludeLocation.Postgraph },
};
public static readonly IncludeCollection GBuffer = new IncludeCollection
{
// Pre-graph
{ CoreIncludes.CorePregraph },
{ kShadows, IncludeLocation.Pregraph },
{ CoreIncludes.ShaderGraphPregraph },
// Post-graph
{ CoreIncludes.CorePostgraph },
{ kGBuffer, IncludeLocation.Postgraph },
{ kPBRGBufferPass, IncludeLocation.Postgraph },
};
public static readonly IncludeCollection Meta = new IncludeCollection
{
// Pre-graph
{ CoreIncludes.CorePregraph },
{ CoreIncludes.ShaderGraphPregraph },
// Post-graph
{ CoreIncludes.CorePostgraph },
{ kLightingMetaPass, IncludeLocation.Postgraph },
};
}
#endregion
}
}

View File

@@ -1,247 +0,0 @@
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UIElements;
using UnityEditor;
using UnityEditor.ShaderGraph;
using UnityEditor.UIElements;
using UnityEditor.ShaderGraph.Serialization;
using SubTargetListPool = UnityEngine.Rendering.ListPool<UnityEditor.ShaderGraph.SubTarget>;
using System.Reflection;
namespace UnityEditor.Rendering.CustomRenderTexture.ShaderGraph
{
[GenerateBlocks]
internal struct FullScreenBlocks
{
// TODO: use base color and alpha blocks
public static BlockFieldDescriptor colorBlock = new BlockFieldDescriptor(String.Empty, "Color", "Color",
new ColorRGBAControl(UnityEngine.Color.white), ShaderStage.Fragment);
}
sealed class CustomRenderTextureTarget : Target
{
// Constants
const string kAssetGuid = "a0bae34258e39cd4899b63278c24c086"; // FullscreenPassTarget.cs
// SubTarget
List<SubTarget> m_SubTargets;
List<string> m_SubTargetNames;
int activeSubTargetIndex => m_SubTargets.IndexOf(m_ActiveSubTarget);
// View
PopupField<string> m_SubTargetField;
TextField m_CustomGUIField;
[SerializeField]
JsonData<SubTarget> m_ActiveSubTarget;
[SerializeField]
string m_CustomEditorGUI;
public CustomRenderTextureTarget()
{
displayName = "Custom Render Texture";
isHidden = false;
m_SubTargets = GetSubTargets(this);
m_SubTargetNames = m_SubTargets.Select(x => x.displayName).ToList();
ProcessSubTargetList(ref m_ActiveSubTarget, ref m_SubTargets);
}
public static void ProcessSubTargetList(ref JsonData<SubTarget> activeSubTarget, ref List<SubTarget> subTargets)
{
if (subTargets == null || subTargets.Count == 0)
return;
// assign the initial sub-target, if none is assigned yet
if (activeSubTarget.value == null)
activeSubTarget = subTargets[0];
// Update SubTarget list with active SubTarget
var activeSubTargetType = activeSubTarget.value.GetType();
var activeSubTargetCurrent = subTargets.FirstOrDefault(x => x.GetType() == activeSubTargetType);
var index = subTargets.IndexOf(activeSubTargetCurrent);
subTargets[index] = activeSubTarget;
}
public static List<SubTarget> GetSubTargets<T>(T target) where T : Target
{
// Get Variants
var subTargets = SubTargetListPool.Get();
var typeCollection = TypeCache.GetTypesDerivedFrom<SubTarget>();
foreach (var type in typeCollection)
{
if (type.IsAbstract || !type.IsClass)
continue;
var subTarget = (SubTarget)Activator.CreateInstance(type);
if (!subTarget.isHidden && subTarget.targetType.Equals(typeof(T)))
{
subTarget.target = target;
subTargets.Add(subTarget);
}
}
return subTargets;
}
public override SubTarget activeSubTarget
{
get => m_ActiveSubTarget;
set => m_ActiveSubTarget = value;
}
public string customEditorGUI
{
get => m_CustomEditorGUI;
set => m_CustomEditorGUI = value;
}
public override bool IsActive() => activeSubTarget.IsActive();
public override void Setup(ref TargetSetupContext context)
{
// Setup the Target
context.AddAssetDependency(new GUID(kAssetGuid), AssetCollection.Flags.SourceDependency);
// Setup the active SubTarget
ProcessSubTargetList(ref m_ActiveSubTarget, ref m_SubTargets);
m_ActiveSubTarget.value.target = this;
m_ActiveSubTarget.value.Setup(ref context);
// Override EditorGUI
if (!string.IsNullOrEmpty(m_CustomEditorGUI))
{
context.SetDefaultShaderGUI(m_CustomEditorGUI);
}
}
public override void GetFields(ref TargetFieldContext context)
{
var descs = context.blocks.Select(x => x.descriptor);
// Core fields
context.AddField(Fields.GraphVertex, descs.Contains(BlockFields.VertexDescription.Position) ||
descs.Contains(BlockFields.VertexDescription.Normal) ||
descs.Contains(BlockFields.VertexDescription.Tangent));
context.AddField(Fields.GraphPixel);
// SubTarget fields
m_ActiveSubTarget.value.GetFields(ref context);
}
public override void GetActiveBlocks(ref TargetActiveBlockContext context)
{
// SubTarget blocks
m_ActiveSubTarget.value.GetActiveBlocks(ref context);
}
public override void GetPropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action<String> registerUndo)
{
// Core properties
m_SubTargetField = new PopupField<string>(m_SubTargetNames, activeSubTargetIndex);
context.AddProperty("Material", m_SubTargetField, (evt) =>
{
if (Equals(activeSubTargetIndex, m_SubTargetField.index))
return;
registerUndo("Change Material");
m_ActiveSubTarget = m_SubTargets[m_SubTargetField.index];
onChange();
});
// SubTarget properties
m_ActiveSubTarget.value.GetPropertiesGUI(ref context, onChange, registerUndo);
// Custom Editor GUI
// Requires FocusOutEvent
m_CustomGUIField = new TextField("") { value = customEditorGUI };
m_CustomGUIField.RegisterCallback<FocusOutEvent>(s =>
{
if (Equals(customEditorGUI, m_CustomGUIField.value))
return;
registerUndo("Change Custom Editor GUI");
customEditorGUI = m_CustomGUIField.value;
onChange();
});
context.AddProperty("Custom Editor GUI", m_CustomGUIField, (evt) => { });
}
public bool TrySetActiveSubTarget(Type subTargetType)
{
if (!subTargetType.IsSubclassOf(typeof(SubTarget)))
return false;
foreach (var subTarget in m_SubTargets)
{
if (subTarget.GetType().Equals(subTargetType))
{
m_ActiveSubTarget = subTarget;
return true;
}
}
return false;
}
public override bool WorksWithSRP(RenderPipelineAsset scriptableRenderPipeline) => true;
public override bool IsNodeAllowedByTarget(System.Type nodeType)
{
SRPFilterAttribute srpFilter = NodeClassCache.GetAttributeOnNodeType<SRPFilterAttribute>(nodeType);
bool allowed = true;
if (srpFilter != null)
allowed = false;
return allowed && nodeType != typeof(MainLightDirectionNode);
}
}
static class FullscreePasses
{
public static PassDescriptor CustomRenderTexture = new PassDescriptor
{
// Definition
referenceName = "SHADERPASS_CUSTOM_RENDER_TEXTURE",
useInPreview = true,
// Template
passTemplatePath = AssetDatabase.GUIDToAssetPath("afa536a0de48246de92194c9e987b0b8"), // CustomTextureSubShader.template
// Port Mask
validVertexBlocks = new BlockFieldDescriptor[]
{
BlockFields.VertexDescription.Position,
BlockFields.VertexDescription.Normal,
BlockFields.VertexDescription.Tangent,
},
validPixelBlocks = new BlockFieldDescriptor[]
{
BlockFields.SurfaceDescription.BaseColor,
BlockFields.SurfaceDescription.Alpha,
},
// Fields
structs = new StructCollection
{
{ Structs.Attributes },
{ Structs.SurfaceDescriptionInputs },
{ Structs.VertexDescriptionInputs },
},
requiredFields = new FieldCollection()
{
StructFields.Attributes.color,
StructFields.Attributes.uv0,
StructFields.Varyings.color,
StructFields.Varyings.texCoord0,
},
fieldDependencies = new DependencyCollection()
{
{ FieldDependencies.Default },
},
};
}
}

View File

@@ -1,57 +0,0 @@
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.ShaderGraph;
using UnityEditor.ShaderGraph.Legacy;
using UnityEngine;
namespace UnityEditor.Rendering.CustomRenderTexture.ShaderGraph
{
sealed class CustomTextureSubTarget : SubTarget<CustomRenderTextureTarget>
{
const string kAssetGuid = "5b2d4724a38a5485ba5e7dc2f7d86f1a"; // CustomTextureSubTarget.cs
internal static FieldDescriptor colorField = new FieldDescriptor(String.Empty, "Color", string.Empty);
public CustomTextureSubTarget()
{
isHidden = false;
displayName = "Custom Render Texture";
}
public override bool IsActive() => true;
public override void Setup(ref TargetSetupContext context)
{
context.AddAssetDependency(new GUID(kAssetGuid), AssetCollection.Flags.SourceDependency);
context.AddSubShader(SubShaders.CustomRenderTexture);
}
public override void GetFields(ref TargetFieldContext context)
{
context.AddField(colorField, true);
}
public override void GetActiveBlocks(ref TargetActiveBlockContext context)
{
context.AddBlock(BlockFields.SurfaceDescription.BaseColor);
context.AddBlock(BlockFields.SurfaceDescription.Alpha);
}
public override void GetPropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action<String> registerUndo)
{
}
static class SubShaders
{
public static SubShaderDescriptor CustomRenderTexture = new SubShaderDescriptor()
{
generatesPreview = true,
passes = new PassCollection
{
{ FullscreePasses.CustomRenderTexture },
},
};
}
}
}

View File

@@ -1,904 +0,0 @@
using UnityEditor.ShaderGraph;
using UnityEngine;
using System;
using UnityEditor.ShaderGraph.Internal;
using System.Linq;
using BlendMode = UnityEngine.Rendering.BlendMode;
using BlendOp = UnityEditor.ShaderGraph.BlendOp;
using UnityEngine.UIElements;
using UnityEditor.UIElements;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering.Fullscreen.ShaderGraph
{
[GenerateBlocks("Fullscreen")]
internal struct FullscreenBlocks
{
public static BlockFieldDescriptor color = new BlockFieldDescriptor(BlockFields.SurfaceDescription.name, "FullscreenColor", "Color",
"SURFACEDESCRIPTION_COLOR", new ColorControl(UnityEngine.Color.grey, true), ShaderStage.Fragment);
public static BlockFieldDescriptor eyeDepth = new BlockFieldDescriptor(BlockFields.SurfaceDescription.name, "FullscreenEyeDepth", "Eye Depth",
"SURFACEDESCRIPTION_EYE_DEPTH", new FloatControl(0), ShaderStage.Fragment);
public static BlockFieldDescriptor linear01Depth = new BlockFieldDescriptor(BlockFields.SurfaceDescription.name, "FullscreenLinear01Depth", "Linear01 Depth",
"SURFACEDESCRIPTION_LINEAR01_DEPTH", new FloatControl(0), ShaderStage.Fragment);
public static BlockFieldDescriptor rawDepth = new BlockFieldDescriptor(BlockFields.SurfaceDescription.name, "FullscreenRawDepth", "Raw Depth",
"SURFACEDESCRIPTION_RAW_DEPTH", new FloatControl(0), ShaderStage.Fragment);
}
[GenerationAPI]
internal struct FullscreenFields
{
public static FieldDescriptor depth = new FieldDescriptor("OUTPUT", "depth", "OUTPUT_DEPTH");
}
internal enum FullscreenMode
{
FullScreen,
CustomRenderTexture,
}
internal enum FullscreenCompatibility
{
Blit,
DrawProcedural,
}
internal enum FullscreenBlendMode
{
Disabled,
Alpha,
Premultiply,
Additive,
Multiply,
Custom,
}
internal enum FullscreenDepthWriteMode
{
LinearEye,
Linear01,
Raw,
}
internal static class FullscreenUniforms
{
public static readonly string blendModeProperty = "_Fullscreen_BlendMode";
public static readonly string srcColorBlendProperty = "_Fullscreen_SrcColorBlend";
public static readonly string dstColorBlendProperty = "_Fullscreen_DstColorBlend";
public static readonly string srcAlphaBlendProperty = "_Fullscreen_SrcAlphaBlend";
public static readonly string dstAlphaBlendProperty = "_Fullscreen_DstAlphaBlend";
public static readonly string colorBlendOperationProperty = "_Fullscreen_ColorBlendOperation";
public static readonly string alphaBlendOperationProperty = "_Fullscreen_AlphaBlendOperation";
public static readonly string depthWriteProperty = "_Fullscreen_DepthWrite";
public static readonly string depthTestProperty = "_Fullscreen_DepthTest";
public static readonly string stencilEnableProperty = "_Fullscreen_Stencil";
public static readonly string stencilReferenceProperty = "_Fullscreen_StencilReference";
public static readonly string stencilReadMaskProperty = "_Fullscreen_StencilReadMask";
public static readonly string stencilWriteMaskProperty = "_Fullscreen_StencilWriteMask";
public static readonly string stencilComparisonProperty = "_Fullscreen_StencilComparison";
public static readonly string stencilPassProperty = "_Fullscreen_StencilPass";
public static readonly string stencilFailProperty = "_Fullscreen_StencilFail";
public static readonly string stencilDepthFailProperty = "_Fullscreen_StencilDepthFail";
public static readonly string srcColorBlend = "[" + srcColorBlendProperty + "]";
public static readonly string dstColorBlend = "[" + dstColorBlendProperty + "]";
public static readonly string srcAlphaBlend = "[" + srcAlphaBlendProperty + "]";
public static readonly string dstAlphaBlend = "[" + dstAlphaBlendProperty + "]";
public static readonly string colorBlendOperation = "[" + colorBlendOperationProperty + "]";
public static readonly string alphaBlendOperation = "[" + alphaBlendOperationProperty + "]";
public static readonly string depthWrite = "[" + depthWriteProperty + "]";
public static readonly string depthTest = "[" + depthTestProperty + "]";
public static readonly string stencilReference = "[" + stencilReferenceProperty + "]";
public static readonly string stencilReadMask = "[" + stencilReadMaskProperty + "]";
public static readonly string stencilWriteMask = "[" + stencilWriteMaskProperty + "]";
public static readonly string stencilComparison = "[" + stencilComparisonProperty + "]";
public static readonly string stencilPass = "[" + stencilPassProperty + "]";
public static readonly string stencilFail = "[" + stencilFailProperty + "]";
public static readonly string stencilDepthFail = "[" + stencilDepthFailProperty + "]";
}
internal abstract class FullscreenSubTarget<T> : SubTarget<T>, IRequiresData<FullscreenData>, IHasMetadata where T : Target
{
static readonly GUID kSourceCodeGuid = new GUID("1cfc804c75474e144be5d4158b9522ed"); // FullscreenSubTarget.cs // TODO
static readonly string[] kSharedTemplateDirectories = GenerationUtils.GetDefaultSharedTemplateDirectories().Union(new string[] { "Packages/com.unity.shadergraph/Editor/Generation/Targets/Fullscreen/Templates" }).ToArray();
// HLSL includes
protected static readonly string kFullscreenCommon = "Packages/com.unity.shadergraph/Editor/Generation/Targets/Fullscreen/Includes/FullscreenCommon.hlsl";
protected static readonly string kTemplatePath = "Packages/com.unity.shadergraph/Editor/Generation/Targets/Fullscreen/Templates/ShaderPass.template";
protected static readonly string kCommon = "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl";
protected static readonly string kColor = "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl";
protected static readonly string kTexture = "Packages/com.unity.render-pipelines.core/ShaderLibrary/Texture.hlsl";
protected static readonly string kInstancing = "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl";
protected static readonly string kFullscreenShaderPass = "Packages/com.unity.shadergraph/Editor/Generation/Targets/Fullscreen/Includes/FullscreenShaderPass.cs.hlsl";
protected static readonly string kSpaceTransforms = "Packages/com.unity.render-pipelines.core/ShaderLibrary/SpaceTransforms.hlsl";
protected static readonly string kFunctions = "Packages/com.unity.shadergraph/ShaderGraphLibrary/Functions.hlsl";
protected static readonly string kTextureStack = "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureStack.hlsl";
protected virtual string fullscreenDrawProceduralInclude => "Packages/com.unity.shadergraph/Editor/Generation/Targets/Fullscreen/Includes/FullscreenDrawProcedural.hlsl";
protected virtual string fullscreenBlitInclude => "Packages/com.unity.shadergraph/Editor/Generation/Targets/Fullscreen/Includes/FullscreenBlit.hlsl";
FullscreenData m_FullscreenData;
FullscreenData IRequiresData<FullscreenData>.data
{
get => m_FullscreenData;
set => m_FullscreenData = value;
}
public FullscreenData fullscreenData
{
get => m_FullscreenData;
set => m_FullscreenData = value;
}
public override void Setup(ref TargetSetupContext context)
{
context.AddAssetDependency(kSourceCodeGuid, AssetCollection.Flags.SourceDependency);
context.SetDefaultShaderGUI(GetDefaultShaderGUI().FullName);
context.AddSubShader(GenerateSubShader());
}
protected virtual IncludeCollection pregraphIncludes => new IncludeCollection();
protected abstract string pipelineTag { get; }
protected virtual Type GetDefaultShaderGUI() => typeof(FullscreenShaderGUI);
public virtual string identifier => GetType().Name;
public virtual ScriptableObject GetMetadataObject(GraphDataReadOnly graph)
{
var bultInMetadata = ScriptableObject.CreateInstance<FullscreenMetaData>();
bultInMetadata.fullscreenMode = fullscreenData.fullscreenMode;
return bultInMetadata;
}
public RenderStateCollection GetRenderState()
{
var result = new RenderStateCollection();
if (fullscreenData.allowMaterialOverride)
{
if (fullscreenData.depthTestMode != CompareFunction.Disabled)
result.Add(RenderState.ZTest(FullscreenUniforms.depthTest));
else
result.Add(RenderState.ZTest("Off"));
result.Add(RenderState.ZWrite(FullscreenUniforms.depthWrite));
if (fullscreenData.blendMode != FullscreenBlendMode.Disabled)
{
result.Add(RenderState.Blend(FullscreenUniforms.srcColorBlend, FullscreenUniforms.dstColorBlend, FullscreenUniforms.srcAlphaBlend, FullscreenUniforms.dstAlphaBlend));
result.Add(RenderState.BlendOp(FullscreenUniforms.colorBlendOperation, FullscreenUniforms.alphaBlendOperation));
}
else
{
result.Add(RenderState.Blend("Blend Off"));
}
if (fullscreenData.enableStencil)
{
result.Add(RenderState.Stencil(new StencilDescriptor { Ref = FullscreenUniforms.stencilReference, ReadMask = FullscreenUniforms.stencilReadMask, WriteMask = FullscreenUniforms.stencilWriteMask, Comp = FullscreenUniforms.stencilComparison, ZFail = FullscreenUniforms.stencilDepthFail, Fail = FullscreenUniforms.stencilFail, Pass = FullscreenUniforms.stencilPass }));
}
}
else
{
if (fullscreenData.depthTestMode == CompareFunction.Disabled)
result.Add(RenderState.ZTest("Off"));
else
result.Add(RenderState.ZTest(CompareFunctionToZTest(fullscreenData.depthTestMode).ToString()));
result.Add(RenderState.ZWrite(fullscreenData.depthWrite ? ZWrite.On.ToString() : ZWrite.Off.ToString()));
// Blend mode
if (fullscreenData.blendMode == FullscreenBlendMode.Alpha)
result.Add(RenderState.Blend(Blend.SrcAlpha, Blend.OneMinusSrcAlpha, Blend.One, Blend.OneMinusSrcAlpha));
else if (fullscreenData.blendMode == FullscreenBlendMode.Premultiply)
result.Add(RenderState.Blend(Blend.One, Blend.OneMinusSrcAlpha, Blend.One, Blend.OneMinusSrcAlpha));
else if (fullscreenData.blendMode == FullscreenBlendMode.Additive)
result.Add(RenderState.Blend(Blend.SrcAlpha, Blend.One, Blend.One, Blend.One));
else if (fullscreenData.blendMode == FullscreenBlendMode.Multiply)
result.Add(RenderState.Blend(Blend.DstColor, Blend.Zero));
else if (fullscreenData.blendMode == FullscreenBlendMode.Disabled)
result.Add(RenderState.Blend("Blend Off"));
else
{
result.Add(RenderState.Blend(BlendModeToBlend(fullscreenData.srcColorBlendMode), BlendModeToBlend(fullscreenData.dstColorBlendMode), BlendModeToBlend(fullscreenData.srcAlphaBlendMode), BlendModeToBlend(fullscreenData.dstAlphaBlendMode)));
result.Add(RenderState.BlendOp(fullscreenData.colorBlendOperation, fullscreenData.alphaBlendOperation));
}
if (fullscreenData.enableStencil)
{
result.Add(RenderState.Stencil(new StencilDescriptor
{
Ref = fullscreenData.stencilReference.ToString(),
ReadMask = fullscreenData.stencilReadMask.ToString(),
WriteMask = fullscreenData.stencilWriteMask.ToString(),
Comp = CompareFunctionToStencilString(fullscreenData.stencilCompareFunction),
ZFail = StencilOpToStencilString(fullscreenData.stencilDepthTestFailOperation),
Fail = StencilOpToStencilString(fullscreenData.stencilFailOperation),
Pass = StencilOpToStencilString(fullscreenData.stencilPassOperation),
}));
}
}
result.Add(RenderState.Cull(UnityEditor.ShaderGraph.Cull.Off));
return result;
}
public static Blend BlendModeToBlend(BlendMode mode)
{
switch (mode)
{
case BlendMode.Zero: return Blend.Zero;
case BlendMode.One: return Blend.One;
case BlendMode.DstColor: return Blend.DstColor;
case BlendMode.SrcColor: return Blend.SrcColor;
case BlendMode.OneMinusDstColor: return Blend.OneMinusDstColor;
case BlendMode.SrcAlpha: return Blend.SrcAlpha;
case BlendMode.OneMinusSrcColor: return Blend.OneMinusSrcColor;
case BlendMode.DstAlpha: return Blend.DstAlpha;
case BlendMode.OneMinusDstAlpha: return Blend.OneMinusDstAlpha;
case BlendMode.SrcAlphaSaturate: return Blend.SrcAlpha;
case BlendMode.OneMinusSrcAlpha: return Blend.OneMinusSrcAlpha;
default: return Blend.Zero;
}
;
}
public static ZTest CompareFunctionToZTest(CompareFunction mode)
{
switch (mode)
{
case CompareFunction.Equal: return ZTest.Equal;
case CompareFunction.NotEqual: return ZTest.NotEqual;
case CompareFunction.Greater: return ZTest.Greater;
case CompareFunction.Less: return ZTest.Less;
case CompareFunction.GreaterEqual: return ZTest.GEqual;
case CompareFunction.LessEqual: return ZTest.LEqual;
case CompareFunction.Always: return ZTest.Always;
case CompareFunction.Disabled: return ZTest.Always;
default: return ZTest.Always;
}
;
}
public static string CompareFunctionToStencilString(CompareFunction compare)
{
switch (compare)
{
case CompareFunction.Never: return "Never";
case CompareFunction.Equal: return "Equal";
case CompareFunction.NotEqual: return "NotEqual";
case CompareFunction.Greater: return "Greater";
case CompareFunction.Less: return "Less";
case CompareFunction.GreaterEqual: return "GEqual";
case CompareFunction.LessEqual: return "LEqual";
case CompareFunction.Always: return "Always";
default: return "Always";
}
;
}
public static string StencilOpToStencilString(StencilOp op)
{
switch (op)
{
case StencilOp.Keep: return "Keep";
case StencilOp.Zero: return "Zero";
case StencilOp.Replace: return "Replace";
case StencilOp.IncrementSaturate: return "IncrSat";
case StencilOp.DecrementSaturate: return "DecrSat";
case StencilOp.Invert: return "Invert";
case StencilOp.IncrementWrap: return "IncrWrap";
case StencilOp.DecrementWrap: return "DecrWrap";
default: return "Keep";
}
;
}
public virtual SubShaderDescriptor GenerateSubShader()
{
var result = new SubShaderDescriptor()
{
generatesPreview = true,
passes = new PassCollection(),
pipelineTag = pipelineTag,
};
result.passes.Add(GenerateFullscreenPass(FullscreenCompatibility.DrawProcedural));
result.passes.Add(GenerateFullscreenPass(FullscreenCompatibility.Blit));
return result;
}
public virtual IncludeCollection GetPreGraphIncludes()
{
return new IncludeCollection
{
{ kCommon, IncludeLocation.Pregraph },
{ kColor, IncludeLocation.Pregraph },
{ kTexture, IncludeLocation.Pregraph },
{ kTextureStack, IncludeLocation.Pregraph },
{ kFullscreenShaderPass, IncludeLocation.Pregraph }, // For VR
{ pregraphIncludes },
{ kSpaceTransforms, IncludeLocation.Pregraph },
{ kFunctions, IncludeLocation.Pregraph },
};
}
public virtual IncludeCollection GetPostGraphIncludes()
{
return new IncludeCollection { { kFullscreenCommon, IncludeLocation.Postgraph } };
}
static readonly KeywordDescriptor depthWriteKeyword = new KeywordDescriptor
{
displayName = "Depth Write",
referenceName = "DEPTH_WRITE",
type = KeywordType.Boolean,
definition = KeywordDefinition.ShaderFeature,
stages = KeywordShaderStage.Fragment,
};
static readonly KeywordDescriptor depthWriteModeKeyword = new KeywordDescriptor
{
displayName = "Depth Write Mode",
referenceName = "DEPTH_WRITE_MODE",
type = KeywordType.Enum,
definition = KeywordDefinition.Predefined,
entries = new KeywordEntry[]
{
new KeywordEntry("Eye Depth", "EYE"),
new KeywordEntry("Eye Linear 01", "LINEAR01"),
new KeywordEntry("Eye Raw", "RAW"),
},
stages = KeywordShaderStage.Fragment,
};
public static StructDescriptor Varyings = new StructDescriptor()
{
name = "Varyings",
packFields = true,
populateWithCustomInterpolators = false,
fields = new FieldDescriptor[]
{
StructFields.Varyings.positionCS,
StructFields.Varyings.texCoord0,
StructFields.Varyings.texCoord1,
StructFields.Varyings.instanceID,
StructFields.Varyings.stereoTargetEyeIndexAsBlendIdx0,
StructFields.Varyings.stereoTargetEyeIndexAsRTArrayIdx,
}
};
protected virtual DefineCollection GetPassDefines(FullscreenCompatibility compatibility)
=> new DefineCollection();
protected virtual KeywordCollection GetPassKeywords(FullscreenCompatibility compatibility)
=> new KeywordCollection();
static StructDescriptor GetFullscreenAttributes(FullscreenCompatibility compatibility)
{
var desc = new StructDescriptor()
{
name = "Attributes",
packFields = false,
};
if (compatibility == FullscreenCompatibility.Blit)
{
desc.fields = new FieldDescriptor[]
{
StructFields.Attributes.instanceID,
StructFields.Attributes.vertexID,
StructFields.Attributes.positionOS,
};
}
else
{
desc.fields = new FieldDescriptor[]
{
StructFields.Attributes.instanceID,
StructFields.Attributes.vertexID,
};
}
return desc;
}
public virtual PassDescriptor GenerateFullscreenPass(FullscreenCompatibility compatibility)
{
var fullscreenPass = new PassDescriptor
{
// Definition
displayName = compatibility.ToString(),
referenceName = "SHADERPASS_" + compatibility.ToString().ToUpper(),
useInPreview = true,
// Template
passTemplatePath = kTemplatePath,
sharedTemplateDirectories = kSharedTemplateDirectories,
// Port Mask
validVertexBlocks = null,
validPixelBlocks = new BlockFieldDescriptor[]
{
BlockFields.SurfaceDescription.BaseColor,
BlockFields.SurfaceDescription.Alpha,
FullscreenBlocks.eyeDepth,
FullscreenBlocks.linear01Depth,
FullscreenBlocks.rawDepth,
},
// Fields
structs = new StructCollection
{
{ GetFullscreenAttributes(compatibility) },
{ Structs.SurfaceDescriptionInputs },
{ Varyings },
{ Structs.VertexDescriptionInputs },
},
fieldDependencies = FieldDependencies.Default,
requiredFields = new FieldCollection
{
StructFields.Varyings.texCoord0, // Always need texCoord0 to calculate the other properties in fullscreen node code
StructFields.Varyings.texCoord1, // We store the view direction computed in the vertex in the texCoord1
StructFields.Attributes.vertexID, // Need the vertex Id for the DrawProcedural case
},
// Conditional State
renderStates = GetRenderState(),
pragmas = new PragmaCollection
{
{ Pragma.Target(ShaderModel.Target30) },
{ Pragma.Vertex("vert") },
{ Pragma.Fragment("frag") },
},
defines = new DefineCollection
{
{depthWriteKeyword, 1, new FieldCondition(FullscreenFields.depth, true)},
{depthWriteModeKeyword, (int)fullscreenData.depthWriteMode, new FieldCondition(FullscreenFields.depth, true)},
GetPassDefines(compatibility),
},
keywords = GetPassKeywords(compatibility),
includes = new IncludeCollection
{
// Pre-graph
GetPreGraphIncludes(),
// Post-graph
GetPostGraphIncludes(),
},
};
switch (compatibility)
{
default:
case FullscreenCompatibility.Blit:
fullscreenPass.includes.Add(fullscreenBlitInclude, IncludeLocation.Postgraph);
break;
case FullscreenCompatibility.DrawProcedural:
fullscreenPass.includes.Add(fullscreenDrawProceduralInclude, IncludeLocation.Postgraph);
break;
}
return fullscreenPass;
}
// We don't need the save context / update materials for now
public override object saveContext => null;
public FullscreenSubTarget()
{
displayName = "Fullscreen";
}
public override bool IsNodeAllowedBySubTarget(Type nodeType)
{
var interfaces = nodeType.GetInterfaces();
bool allowed = true;
// Subgraph nodes inherits all the interfaces including vertex ones.
if (nodeType == typeof(SubGraphNode))
return true;
// There is no input in the vertex block for now
if (interfaces.Contains(typeof(IMayRequireVertexID))
|| interfaces.Contains(typeof(IMayRequireVertexSkinning))
|| interfaces.Contains(typeof(IMayRequireInstanceID)))
allowed = false;
return allowed;
}
public override bool IsActive() => true;
public override void GetFields(ref TargetFieldContext context)
{
context.AddField(UnityEditor.ShaderGraph.Fields.GraphPixel);
context.AddField(FullscreenFields.depth, fullscreenData.depthWrite || fullscreenData.depthTestMode != CompareFunction.Disabled);
}
public override void GetActiveBlocks(ref TargetActiveBlockContext context)
{
context.AddBlock(BlockFields.SurfaceDescription.BaseColor);
context.AddBlock(BlockFields.SurfaceDescription.Alpha);
var depthBlock = FullscreenBlocks.eyeDepth;
if (fullscreenData.depthWriteMode == FullscreenDepthWriteMode.Linear01)
depthBlock = FullscreenBlocks.linear01Depth;
if (fullscreenData.depthWriteMode == FullscreenDepthWriteMode.Raw)
depthBlock = FullscreenBlocks.rawDepth;
context.AddBlock(depthBlock, fullscreenData.depthWrite || fullscreenData.depthTestMode != CompareFunction.Disabled);
}
public override void CollectShaderProperties(PropertyCollector collector, GenerationMode generationMode)
{
if (fullscreenData.allowMaterialOverride)
{
base.CollectShaderProperties(collector, generationMode);
CollectRenderStateShaderProperties(collector, generationMode);
}
collector.AddFloatProperty("_FlipY", 0, HLSLDeclaration.Global, false);
}
public void CollectRenderStateShaderProperties(PropertyCollector collector, GenerationMode generationMode)
{
if (generationMode != GenerationMode.Preview && fullscreenData.allowMaterialOverride)
{
// When blend mode is disabled, we can't override
if (fullscreenData.blendMode != FullscreenBlendMode.Disabled)
{
BlendMode srcColorBlend = fullscreenData.srcColorBlendMode;
BlendMode srcAlphaBlend = fullscreenData.srcAlphaBlendMode;
BlendMode dstColorBlend = fullscreenData.dstColorBlendMode;
BlendMode dstAlphaBlend = fullscreenData.dstAlphaBlendMode;
BlendOp colorBlendOp = fullscreenData.colorBlendOperation;
BlendOp alphaBlendOp = fullscreenData.alphaBlendOperation;
// Patch the default blend values depending on the Blend Mode:
if (fullscreenData.blendMode != FullscreenBlendMode.Custom)
{
colorBlendOp = BlendOp.Add;
alphaBlendOp = BlendOp.Add;
}
if (fullscreenData.blendMode == FullscreenBlendMode.Alpha)
{
srcColorBlend = BlendMode.SrcAlpha;
dstColorBlend = BlendMode.OneMinusSrcAlpha;
srcAlphaBlend = BlendMode.One;
dstAlphaBlend = BlendMode.OneMinusSrcAlpha;
}
else if (fullscreenData.blendMode == FullscreenBlendMode.Premultiply)
{
srcColorBlend = BlendMode.One;
dstColorBlend = BlendMode.OneMinusSrcAlpha;
srcAlphaBlend = BlendMode.One;
dstAlphaBlend = BlendMode.OneMinusSrcAlpha;
}
else if (fullscreenData.blendMode == FullscreenBlendMode.Additive)
{
srcColorBlend = BlendMode.SrcAlpha;
dstColorBlend = BlendMode.One;
srcAlphaBlend = BlendMode.One;
dstAlphaBlend = BlendMode.One;
}
else if (fullscreenData.blendMode == FullscreenBlendMode.Multiply)
{
srcColorBlend = BlendMode.DstColor;
dstColorBlend = BlendMode.Zero;
srcAlphaBlend = BlendMode.One;
dstAlphaBlend = BlendMode.OneMinusSrcAlpha;
}
collector.AddEnumProperty(FullscreenUniforms.blendModeProperty, fullscreenData.blendMode);
collector.AddEnumProperty(FullscreenUniforms.srcColorBlendProperty, srcColorBlend);
collector.AddEnumProperty(FullscreenUniforms.dstColorBlendProperty, dstColorBlend);
collector.AddEnumProperty(FullscreenUniforms.srcAlphaBlendProperty, srcAlphaBlend);
collector.AddEnumProperty(FullscreenUniforms.dstAlphaBlendProperty, dstAlphaBlend);
collector.AddEnumProperty(FullscreenUniforms.colorBlendOperationProperty, colorBlendOp);
collector.AddEnumProperty(FullscreenUniforms.alphaBlendOperationProperty, alphaBlendOp);
}
collector.AddBoolProperty(FullscreenUniforms.depthWriteProperty, fullscreenData.depthWrite);
if (fullscreenData.depthTestMode != CompareFunction.Disabled)
collector.AddEnumProperty(FullscreenUniforms.depthTestProperty, fullscreenData.depthTestMode);
// When stencil is disabled, we can't override
if (fullscreenData.enableStencil)
{
collector.AddBoolProperty(FullscreenUniforms.stencilEnableProperty, fullscreenData.enableStencil);
collector.AddIntProperty(FullscreenUniforms.stencilReferenceProperty, fullscreenData.stencilReference);
collector.AddIntProperty(FullscreenUniforms.stencilReadMaskProperty, fullscreenData.stencilReadMask);
collector.AddIntProperty(FullscreenUniforms.stencilWriteMaskProperty, fullscreenData.stencilWriteMask);
collector.AddEnumProperty(FullscreenUniforms.stencilComparisonProperty, fullscreenData.stencilCompareFunction);
collector.AddEnumProperty(FullscreenUniforms.stencilPassProperty, fullscreenData.stencilPassOperation);
collector.AddEnumProperty(FullscreenUniforms.stencilFailProperty, fullscreenData.stencilFailOperation);
collector.AddEnumProperty(FullscreenUniforms.stencilDepthFailProperty, fullscreenData.stencilDepthTestFailOperation);
}
}
}
public override void GetPropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action<String> registerUndo)
{
context.AddProperty("Allow Material Override", new Toggle() { value = fullscreenData.allowMaterialOverride }, (evt) =>
{
if (Equals(fullscreenData.allowMaterialOverride, evt.newValue))
return;
registerUndo("Change Allow Material Override");
fullscreenData.allowMaterialOverride = evt.newValue;
onChange();
});
GetRenderStatePropertiesGUI(ref context, onChange, registerUndo);
}
protected virtual void GetRenderStatePropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action<String> registerUndo)
{
GetBlendingPropertiesGUI(ref context, onChange, registerUndo);
context.AddProperty("Depth Test", new EnumField(fullscreenData.depthTestMode) { value = fullscreenData.depthTestMode }, (evt) =>
{
if (Equals(fullscreenData.depthTestMode, evt.newValue))
return;
registerUndo("Change Depth Test");
fullscreenData.depthTestMode = (CompareFunction)evt.newValue;
onChange();
});
context.AddProperty("Depth Write", new Toggle { value = fullscreenData.depthWrite }, (evt) =>
{
if (Equals(fullscreenData.depthWrite, evt.newValue))
return;
registerUndo("Change Depth Write");
fullscreenData.depthWrite = evt.newValue;
onChange();
});
if (fullscreenData.depthWrite || fullscreenData.depthTestMode != CompareFunction.Disabled)
{
context.AddProperty("Depth Write Mode", new EnumField(fullscreenData.depthWriteMode) { value = fullscreenData.depthWriteMode }, (evt) =>
{
if (Equals(fullscreenData.depthWriteMode, evt.newValue))
return;
registerUndo("Change Depth Write Mode");
fullscreenData.depthWriteMode = (FullscreenDepthWriteMode)evt.newValue;
onChange();
});
}
GetStencilPropertiesGUI(ref context, onChange, registerUndo);
}
protected virtual void GetBlendingPropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action<String> registerUndo)
{
context.AddProperty("Blend Mode", new EnumField(fullscreenData.blendMode) { value = fullscreenData.blendMode }, (evt) =>
{
if (Equals(fullscreenData.blendMode, evt.newValue))
return;
registerUndo("Change Blend Mode");
fullscreenData.blendMode = (FullscreenBlendMode)evt.newValue;
onChange();
});
if (fullscreenData.blendMode == FullscreenBlendMode.Custom)
{
context.globalIndentLevel++;
context.AddLabel("Color Blend Mode", 0);
context.AddProperty("Src Color", new EnumField(fullscreenData.srcColorBlendMode) { value = fullscreenData.srcColorBlendMode }, (evt) =>
{
if (Equals(fullscreenData.srcColorBlendMode, evt.newValue))
return;
registerUndo("Change Blend Mode");
fullscreenData.srcColorBlendMode = (BlendMode)evt.newValue;
onChange();
});
context.AddProperty("Dst Color", new EnumField(fullscreenData.dstColorBlendMode) { value = fullscreenData.dstColorBlendMode }, (evt) =>
{
if (Equals(fullscreenData.dstColorBlendMode, evt.newValue))
return;
registerUndo("Change Blend Mode");
fullscreenData.dstColorBlendMode = (BlendMode)evt.newValue;
onChange();
});
context.AddProperty("Color Operation", new EnumField(fullscreenData.colorBlendOperation) { value = fullscreenData.colorBlendOperation }, (evt) =>
{
if (Equals(fullscreenData.colorBlendOperation, evt.newValue))
return;
registerUndo("Change Blend Mode");
fullscreenData.colorBlendOperation = (BlendOp)evt.newValue;
onChange();
});
context.AddLabel("Alpha Blend Mode", 0);
context.AddProperty("Src", new EnumField(fullscreenData.srcAlphaBlendMode) { value = fullscreenData.srcAlphaBlendMode }, (evt) =>
{
if (Equals(fullscreenData.srcAlphaBlendMode, evt.newValue))
return;
registerUndo("Change Blend Mode");
fullscreenData.srcAlphaBlendMode = (BlendMode)evt.newValue;
onChange();
});
context.AddProperty("Dst", new EnumField(fullscreenData.dstAlphaBlendMode) { value = fullscreenData.dstAlphaBlendMode }, (evt) =>
{
if (Equals(fullscreenData.dstAlphaBlendMode, evt.newValue))
return;
registerUndo("Change Blend Mode");
fullscreenData.dstAlphaBlendMode = (BlendMode)evt.newValue;
onChange();
});
context.AddProperty("Blend Operation Alpha", new EnumField(fullscreenData.alphaBlendOperation) { value = fullscreenData.alphaBlendOperation }, (evt) =>
{
if (Equals(fullscreenData.alphaBlendOperation, evt.newValue))
return;
registerUndo("Change Blend Mode");
fullscreenData.alphaBlendOperation = (BlendOp)evt.newValue;
onChange();
});
context.globalIndentLevel--;
}
}
protected virtual void GetStencilPropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action<String> registerUndo)
{
context.AddProperty("Enable Stencil", new Toggle { value = fullscreenData.enableStencil }, (evt) =>
{
if (Equals(fullscreenData.enableStencil, evt.newValue))
return;
registerUndo("Change Enable Stencil");
fullscreenData.enableStencil = evt.newValue;
onChange();
});
if (fullscreenData.enableStencil)
{
context.globalIndentLevel++;
context.AddProperty("Reference", new IntegerField { value = fullscreenData.stencilReference, isDelayed = true }, (evt) =>
{
if (Equals(fullscreenData.stencilReference, evt.newValue))
return;
registerUndo("Change Stencil Reference");
fullscreenData.stencilReference = evt.newValue;
onChange();
});
context.AddProperty("Read Mask", new IntegerField { value = fullscreenData.stencilReadMask, isDelayed = true }, (evt) =>
{
if (Equals(fullscreenData.stencilReadMask, evt.newValue))
return;
registerUndo("Change Stencil Read Mask");
fullscreenData.stencilReadMask = evt.newValue;
onChange();
});
context.AddProperty("Write Mask", new IntegerField { value = fullscreenData.stencilWriteMask, isDelayed = true }, (evt) =>
{
if (Equals(fullscreenData.stencilWriteMask, evt.newValue))
return;
registerUndo("Change Stencil Write Mask");
fullscreenData.stencilWriteMask = evt.newValue;
onChange();
});
context.AddProperty("Comparison", new EnumField(fullscreenData.stencilCompareFunction) { value = fullscreenData.stencilCompareFunction }, (evt) =>
{
if (Equals(fullscreenData.stencilCompareFunction, evt.newValue))
return;
registerUndo("Change Stencil Comparison");
fullscreenData.stencilCompareFunction = (CompareFunction)evt.newValue;
onChange();
});
context.AddProperty("Pass", new EnumField(fullscreenData.stencilPassOperation) { value = fullscreenData.stencilPassOperation }, (evt) =>
{
if (Equals(fullscreenData.stencilPassOperation, evt.newValue))
return;
registerUndo("Change Stencil Pass Operation");
fullscreenData.stencilPassOperation = (StencilOp)evt.newValue;
onChange();
});
context.AddProperty("Fail", new EnumField(fullscreenData.stencilFailOperation) { value = fullscreenData.stencilFailOperation }, (evt) =>
{
if (Equals(fullscreenData.stencilFailOperation, evt.newValue))
return;
registerUndo("Change Stencil Fail Operation");
fullscreenData.stencilFailOperation = (StencilOp)evt.newValue;
onChange();
});
context.AddProperty("Depth Fail", new EnumField(fullscreenData.stencilDepthTestFailOperation) { value = fullscreenData.stencilDepthTestFailOperation }, (evt) =>
{
if (Equals(fullscreenData.stencilDepthTestFailOperation, evt.newValue))
return;
registerUndo("Change Stencil Depth Fail Operation");
fullscreenData.stencilDepthTestFailOperation = (StencilOp)evt.newValue;
onChange();
});
context.globalIndentLevel--;
}
}
}
internal static class FullscreenPropertyCollectorExtension
{
public static void AddEnumProperty<T>(this PropertyCollector collector, string prop, T value, HLSLDeclaration hlslDeclaration = HLSLDeclaration.DoNotDeclare) where T : Enum
{
collector.AddShaderProperty(new Vector1ShaderProperty
{
floatType = FloatType.Enum,
enumType = EnumType.CSharpEnum,
cSharpEnumType = typeof(T),
hidden = true,
overrideHLSLDeclaration = true,
hlslDeclarationOverride = hlslDeclaration,
value = Convert.ToInt32(value),
overrideReferenceName = prop,
});
}
public static void AddIntProperty(this PropertyCollector collector, string prop, int value, HLSLDeclaration hlslDeclaration = HLSLDeclaration.DoNotDeclare)
{
collector.AddShaderProperty(new Vector1ShaderProperty
{
floatType = FloatType.Integer,
hidden = true,
overrideHLSLDeclaration = true,
hlslDeclarationOverride = hlslDeclaration,
value = value,
overrideReferenceName = prop,
});
}
public static void AddBoolProperty(this PropertyCollector collector, string prop, bool value, HLSLDeclaration hlslDeclaration = HLSLDeclaration.DoNotDeclare)
{
collector.AddShaderProperty(new BooleanShaderProperty
{
hidden = true,
overrideHLSLDeclaration = true,
hlslDeclarationOverride = hlslDeclaration,
value = value,
overrideReferenceName = prop,
});
}
public static void AddFloatProperty(this PropertyCollector collector, string referenceName, float defaultValue, HLSLDeclaration declarationType = HLSLDeclaration.DoNotDeclare, bool generatePropertyBlock = true)
{
collector.AddShaderProperty(new Vector1ShaderProperty
{
floatType = FloatType.Default,
hidden = true,
overrideHLSLDeclaration = true,
hlslDeclarationOverride = declarationType,
value = defaultValue,
generatePropertyBlock = generatePropertyBlock,
overrideReferenceName = referenceName,
});
}
}
}