You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
500 lines
18 KiB
500 lines
18 KiB
using UnityEditor.ShaderGraph;
|
|
using UnityEngine;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine.UIElements;
|
|
using UnityEditor.Rendering.BuiltIn.ShaderGraph;
|
|
using UnityEditor.ShaderGraph.Drawing.Slots;
|
|
|
|
namespace UnityEditor.Rendering.UITK.ShaderGraph
|
|
{
|
|
[GenerateBlocks("UI")]
|
|
struct UITKBlocks
|
|
{
|
|
public static BlockFieldDescriptor coverage = new(BlockFields.SurfaceDescription.name, "Coverage", "Coverage",
|
|
"SURFACEDESCRIPTION_COVERAGE", new FloatControl(1), ShaderStage.Fragment, true);
|
|
}
|
|
|
|
internal abstract class UISubTarget<T> : SubTarget<T>, IUISubTarget, INodeValidationExtension, IRequiresData<UIData> where T : Target
|
|
{
|
|
const string kAssetGuid = "a5150c3db0b6942f6a0b1f7a9ce97d5c"; // UISubTarget.cs
|
|
|
|
#region Includes
|
|
static readonly string[] kSharedTemplateDirectories = GetUITKTemplateDirectories();
|
|
|
|
private static string[] GetUITKTemplateDirectories()
|
|
{
|
|
var shared = GenerationUtils.GetDefaultSharedTemplateDirectories();
|
|
|
|
var uitkTemplateDirectories = new string[shared.Length + 1];
|
|
uitkTemplateDirectories[shared.Length] = "Packages/com.unity.shadergraph/Editor/Generation/Targets/UITK/Templates";
|
|
for(int i = 0; i < shared.Length; ++i)
|
|
{
|
|
uitkTemplateDirectories[i] = shared[i];
|
|
}
|
|
return uitkTemplateDirectories;
|
|
}
|
|
|
|
//HLSL Includes
|
|
protected static readonly string kTemplatePath = "Packages/com.unity.shadergraph/Editor/Generation/Targets/UITK/Templates/PassUI.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 kPacking = "Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.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 static readonly string kUIShim = "Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/ShaderLibrary/Shim/UIShim.hlsl";
|
|
#endregion
|
|
|
|
UIData m_UIData;
|
|
|
|
UIData IRequiresData<UIData>.data
|
|
{
|
|
get => m_UIData;
|
|
set => m_UIData = value;
|
|
}
|
|
|
|
public UIData uiData
|
|
{
|
|
get => m_UIData;
|
|
set => m_UIData = value;
|
|
}
|
|
protected bool TargetsVFX() => false;
|
|
protected virtual IncludeCollection pregraphIncludes => new IncludeCollection();
|
|
protected virtual IncludeCollection postgraphIncludes => new IncludeCollection();
|
|
protected abstract string pipelineTag { get; }
|
|
|
|
public virtual string identifier => GetType().Name;
|
|
|
|
public override bool IsActive() => true;
|
|
public override void Setup(ref TargetSetupContext context)
|
|
{
|
|
context.AddAssetDependency(new GUID(kAssetGuid), AssetCollection.Flags.SourceDependency);
|
|
context.AddSubShader(GenerateDefaultSubshader());
|
|
}
|
|
|
|
public override void GetActiveBlocks(ref TargetActiveBlockContext context)
|
|
{
|
|
context.AddBlock(BlockFields.SurfaceDescription.BaseColor);
|
|
context.AddBlock(BlockFields.SurfaceDescription.Alpha);
|
|
}
|
|
|
|
public override void CollectShaderProperties(PropertyCollector collector, GenerationMode generationMode)
|
|
{
|
|
base.CollectShaderProperties(collector, generationMode);
|
|
|
|
CollectRenderStateShaderProperties(collector, generationMode);
|
|
}
|
|
|
|
public void CollectRenderStateShaderProperties(PropertyCollector collector, GenerationMode generationMode)
|
|
{
|
|
base.CollectShaderProperties(collector, generationMode);
|
|
}
|
|
|
|
public override void GetFields(ref TargetFieldContext context)
|
|
{
|
|
context.AddField(UnityEditor.ShaderGraph.Fields.GraphPixel);
|
|
}
|
|
|
|
public virtual SubShaderDescriptor GenerateDefaultSubshader(bool isSRP = true )
|
|
{
|
|
var result = new SubShaderDescriptor()
|
|
{
|
|
pipelineTag = pipelineTag,
|
|
renderQueue = "Transparent",
|
|
IgnoreProjector = "True",
|
|
renderType = "Transparent",
|
|
PreviewType = "Plane",
|
|
shaderFallback = "",
|
|
CanUseSpriteAtlas = "True",
|
|
generatesPreview = true,
|
|
passes = new PassCollection(),
|
|
|
|
};
|
|
result.passes.Add(GenerateUIPassDescriptor(isSRP));
|
|
return result;
|
|
}
|
|
|
|
public IncludeCollection AdditionalIncludesOnly()
|
|
{
|
|
return new IncludeCollection
|
|
{
|
|
{ pregraphIncludes },
|
|
{ postgraphIncludes },
|
|
};
|
|
}
|
|
|
|
public IncludeCollection SRPCoreIncludes()
|
|
{
|
|
return new IncludeCollection
|
|
{
|
|
// Pre-graph
|
|
SRPPreGraphIncludes(),
|
|
// Post-graph
|
|
SRPPostGraphIncludes(),
|
|
};
|
|
}
|
|
public virtual IncludeCollection SRPPreGraphIncludes()
|
|
{
|
|
return new IncludeCollection
|
|
{
|
|
{kCommon, IncludeLocation.Pregraph},
|
|
{kColor, IncludeLocation.Pregraph},
|
|
{kTexture, IncludeLocation.Pregraph},
|
|
{kTextureStack, IncludeLocation.Pregraph},
|
|
{ pregraphIncludes },
|
|
{kSpaceTransforms, IncludeLocation.Pregraph},
|
|
{kFunctions, IncludeLocation.Pregraph},
|
|
};
|
|
}
|
|
|
|
public virtual IncludeCollection SRPPostGraphIncludes()
|
|
{
|
|
return new IncludeCollection
|
|
{
|
|
{ postgraphIncludes },
|
|
};
|
|
}
|
|
|
|
protected virtual DefineCollection GetPassDefines()
|
|
=> new DefineCollection();
|
|
|
|
protected virtual KeywordCollection GetPassKeywords()
|
|
=> new KeywordCollection();
|
|
|
|
public virtual PassDescriptor GenerateUIPassDescriptor(bool isSRP)
|
|
{
|
|
|
|
var DefaultUITKPass = new PassDescriptor()
|
|
{
|
|
// Definition
|
|
displayName = "Default",
|
|
referenceName = "SHADERPASS_CUSTOM_UI",
|
|
|
|
useInPreview = true,
|
|
|
|
// Templates
|
|
passTemplatePath = kTemplatePath,
|
|
sharedTemplateDirectories = kSharedTemplateDirectories,
|
|
|
|
// Port Mask
|
|
validVertexBlocks = UITKBlockMasks.Vertex,
|
|
validPixelBlocks = UITKBlockMasks.Fragment,
|
|
|
|
// Collections
|
|
|
|
// Fields
|
|
structs = UITKStructCollections.Default,
|
|
requiredFields = UITKRequiredFields.Default,
|
|
fieldDependencies = FieldDependencies.Default,
|
|
|
|
//Conditional State
|
|
renderStates = UITKRenderStates.GenerateRenderStateDeclaration(),
|
|
pragmas = UITKPragmas.Default,
|
|
keywords = UITKKeywords.Default,
|
|
includes = AdditionalIncludesOnly(),
|
|
|
|
//definitions
|
|
defines = GetPassDefines(),
|
|
};
|
|
return DefaultUITKPass;
|
|
}
|
|
|
|
// We don't need the save context / update materials for nows
|
|
public override object saveContext => null;
|
|
|
|
public UISubTarget()
|
|
{
|
|
displayName = "UI";
|
|
}
|
|
|
|
System.Collections.Generic.HashSet<Type> m_UnsupportedNodes;
|
|
|
|
public string GetValidatorKey()
|
|
{
|
|
return "UISubTarget";
|
|
}
|
|
|
|
public INodeValidationExtension.Status GetValidationStatus(AbstractMaterialNode node, out string msg)
|
|
{
|
|
// Make sure node is in our graph first
|
|
if (node.owner == null)
|
|
{
|
|
msg = null;
|
|
return INodeValidationExtension.Status.None;
|
|
}
|
|
|
|
foreach (var item in node.owner.activeTargets)
|
|
{
|
|
if (item.prefersUITKPreview)
|
|
{
|
|
if (ValidateUV(node, out msg))
|
|
{
|
|
return INodeValidationExtension.Status.Warning;
|
|
}
|
|
|
|
UVNode uvNode = node as UVNode;
|
|
if (uvNode != null)
|
|
{
|
|
if (uvNode.uvChannel != UnityEditor.ShaderGraph.Internal.UVChannel.UV0)
|
|
{
|
|
msg = "UI Material does not support UV1-7. Consider using 'UV0'.";
|
|
return INodeValidationExtension.Status.Warning;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
msg = null;
|
|
return INodeValidationExtension.Status.None;
|
|
}
|
|
|
|
private bool ValidateUV(AbstractMaterialNode node, out string warningMessage)
|
|
{
|
|
List<UVMaterialSlot> uvSlots = new();
|
|
node.GetInputSlots<UVMaterialSlot>(uvSlots);
|
|
|
|
foreach (var uvSlot in uvSlots)
|
|
{
|
|
if (uvSlot.channel != UnityEditor.ShaderGraph.Internal.UVChannel.UV0)
|
|
{
|
|
warningMessage = "UI Material does not support UV1-7. Consider using 'UV0'.";
|
|
return true;
|
|
}
|
|
}
|
|
|
|
warningMessage = null;
|
|
return false;
|
|
}
|
|
|
|
public override bool ValidateNodeCompatibility(AbstractMaterialNode node, out string warningMessage, out Rendering.ShaderCompilerMessageSeverity severity)
|
|
{
|
|
List<UVMaterialSlot> uvSlots = new();
|
|
node.GetInputSlots<UVMaterialSlot>(uvSlots);
|
|
severity = ShaderCompilerMessageSeverity.Warning;
|
|
|
|
if (ValidateUV(node, out warningMessage))
|
|
return true;
|
|
|
|
foreach (var uvSlot in uvSlots)
|
|
{
|
|
if (uvSlot.channel != UnityEditor.ShaderGraph.Internal.UVChannel.UV0)
|
|
{
|
|
warningMessage = "UI Material does not support UV1-7. Consider using 'UV0'.";
|
|
return true;
|
|
}
|
|
}
|
|
|
|
SubGraphNode subGraphNode = node as SubGraphNode;
|
|
if (subGraphNode != null)
|
|
{
|
|
SubGraphAsset subGraphAsset = subGraphNode.asset;
|
|
if (subGraphAsset == null)
|
|
{
|
|
warningMessage = null;
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
foreach (var item in subGraphAsset.requirements.requiresMeshUVs)
|
|
{
|
|
if (item != UnityEditor.ShaderGraph.Internal.UVChannel.UV0)
|
|
{
|
|
warningMessage = "UI Material does not support UV1-7. Consider using 'UV0' in the subgraph.";
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
warningMessage = null;
|
|
return false;
|
|
}
|
|
|
|
public override bool IsNodeAllowedBySubTarget(Type nodeType)
|
|
{
|
|
if (m_UnsupportedNodes == null)
|
|
{
|
|
m_UnsupportedNodes = new HashSet<Type>();
|
|
m_UnsupportedNodes.Add(typeof(BakedGINode));
|
|
m_UnsupportedNodes.Add(typeof(ParallaxMappingNode));
|
|
m_UnsupportedNodes.Add(typeof(ParallaxOcclusionMappingNode));
|
|
m_UnsupportedNodes.Add(typeof(TriplanarNode));
|
|
m_UnsupportedNodes.Add(typeof(IsFrontFaceNode));
|
|
|
|
// Node deviring from GeometryNode
|
|
m_UnsupportedNodes.Add(typeof(BitangentVectorNode));
|
|
m_UnsupportedNodes.Add(typeof(NormalVectorNode));
|
|
m_UnsupportedNodes.Add(typeof(PositionNode));
|
|
m_UnsupportedNodes.Add(typeof(TangentVectorNode));
|
|
m_UnsupportedNodes.Add(typeof(ViewDirectionNode));
|
|
|
|
// Vertex attribute related node which cannot be correctly handled in UITK.
|
|
m_UnsupportedNodes.Add(typeof(VertexIDNode));
|
|
m_UnsupportedNodes.Add(typeof(ComputeDeformNode));
|
|
m_UnsupportedNodes.Add(typeof(LinearBlendSkinningNode));
|
|
}
|
|
|
|
var interfaces = nodeType.GetInterfaces();
|
|
int numInterfaces = interfaces.Length;
|
|
|
|
// Subgraph nodes inherits all the interfaces including vertex ones.
|
|
if (m_UnsupportedNodes.Contains(nodeType))
|
|
return false;
|
|
|
|
if (nodeType == typeof(SubGraphNode))
|
|
return true;
|
|
|
|
for (int i = 0; i < numInterfaces; i++)
|
|
{
|
|
if (interfaces[i] == typeof(IMayRequireVertexSkinning)) return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
#region PortMasks
|
|
class UITKBlockMasks
|
|
{
|
|
// Port Mask
|
|
public static BlockFieldDescriptor[] Vertex = null;
|
|
|
|
public static BlockFieldDescriptor[] Fragment =
|
|
{
|
|
BlockFields.SurfaceDescription.BaseColor,
|
|
BlockFields.SurfaceDescription.Alpha,
|
|
};
|
|
}
|
|
#endregion
|
|
|
|
#region StructCollections
|
|
static class UITKStructCollections
|
|
{
|
|
public static StructCollection Default = new StructCollection()
|
|
{
|
|
UIStructs.Attributes,
|
|
UIStructs.UITKSurfaceDescriptionInputs,
|
|
UIStructs.Varyings,
|
|
UIStructs.UITKVertexDescriptionInputs,
|
|
};
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RequiredFields
|
|
static class UITKRequiredFields
|
|
{
|
|
public static FieldCollection Default = new FieldCollection()
|
|
{
|
|
StructFields.Attributes.positionOS,
|
|
StructFields.Attributes.color,
|
|
StructFields.Attributes.uv0,
|
|
StructFields.Attributes.uv1,
|
|
StructFields.Attributes.uv2,
|
|
StructFields.Attributes.uv3,
|
|
StructFields.Attributes.uv4,
|
|
StructFields.Attributes.uv5,
|
|
StructFields.Attributes.uv6,
|
|
StructFields.Attributes.uv7,
|
|
|
|
StructFields.Varyings.positionCS,
|
|
StructFields.Varyings.color,
|
|
StructFields.Varyings.texCoord0,
|
|
StructFields.Varyings.texCoord1,
|
|
StructFields.Varyings.texCoord3,
|
|
StructFields.Varyings.texCoord4,
|
|
};
|
|
}
|
|
#endregion
|
|
|
|
#region Keywords
|
|
|
|
static class UITKKeywords
|
|
{
|
|
public static KeywordDescriptor ForceGamma = new()
|
|
{
|
|
displayName = "Force Gamma",
|
|
referenceName = "",
|
|
type = KeywordType.Enum,
|
|
definition = KeywordDefinition.MultiCompile,
|
|
scope = KeywordScope.Local,
|
|
entries = new KeywordEntry[]
|
|
{
|
|
new(){ displayName = "Disabled", referenceName = "" },
|
|
new(){ displayName = "Enabled", referenceName = "UIE_FORCE_GAMMA" },
|
|
}
|
|
};
|
|
|
|
public static KeywordDescriptor ForceTextureSlotCount = new()
|
|
{
|
|
displayName = "Force Texture Slot Count",
|
|
referenceName = "",
|
|
type = KeywordType.Enum,
|
|
definition = KeywordDefinition.MultiCompile,
|
|
scope = KeywordScope.Local,
|
|
entries = new KeywordEntry[]
|
|
{
|
|
new(){ displayName = "8 Dynamic Texture Slots", referenceName = "" },
|
|
new(){ displayName = "4 Dynamic Texture Slots", referenceName = "UIE_TEXTURE_SLOT_COUNT_4" },
|
|
new(){ displayName = "2 Dynamic Texture Slots", referenceName = "UIE_TEXTURE_SLOT_COUNT_2" },
|
|
new(){ displayName = "No Dynamic Texture Slot", referenceName = "UIE_TEXTURE_SLOT_COUNT_1" },
|
|
}
|
|
};
|
|
|
|
public static KeywordDescriptor ForceRenderType = new()
|
|
{
|
|
displayName = "Force Render Type",
|
|
referenceName = "",
|
|
type = KeywordType.Enum,
|
|
definition = KeywordDefinition.MultiCompile,
|
|
scope = KeywordScope.Local,
|
|
entries = new KeywordEntry[]
|
|
{
|
|
new(){ displayName = "Any Render Type", referenceName = "" },
|
|
new(){ displayName = "Force Solid", referenceName = "UIE_RENDER_TYPE_SOLID" },
|
|
new(){ displayName = "Force Texture", referenceName = "UIE_RENDER_TYPE_TEXTURE" },
|
|
new(){ displayName = "Force Text", referenceName = "UIE_RENDER_TYPE_TEXT" },
|
|
new(){ displayName = "Force Gradient", referenceName = "UIE_RENDER_TYPE_GRADIENT" },
|
|
}
|
|
};
|
|
|
|
public static KeywordCollection Default = new()
|
|
{
|
|
ForceGamma,
|
|
ForceTextureSlotCount,
|
|
ForceRenderType,
|
|
};
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderStates
|
|
static class UITKRenderStates
|
|
{
|
|
public static RenderStateCollection GenerateRenderStateDeclaration()
|
|
{
|
|
return new RenderStateCollection
|
|
{
|
|
{RenderState.Cull(Cull.Off)},
|
|
{RenderState.ZWrite(ZWrite.Off)},
|
|
{RenderState.Blend(Blend.SrcAlpha, Blend.OneMinusSrcAlpha)},
|
|
};
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Pragmas
|
|
static class UITKPragmas
|
|
{
|
|
public static PragmaCollection Default = new PragmaCollection
|
|
{
|
|
{Pragma.Target(ShaderModel.Target35)},
|
|
{Pragma.Vertex("uie_custom_vert")},
|
|
{Pragma.Fragment("uie_custom_frag")},
|
|
};
|
|
}
|
|
#endregion
|
|
}
|