Working on Chapter 2, draft of Chapter 1 is completed
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 },
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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 },
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user