using System; using System.Linq; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; using UnityEngine.UIElements; using UnityEditor.ShaderGraph; using UnityEditor.ShaderGraph.Internal; using UnityEditor.UIElements; using UnityEditor.ShaderGraph.Serialization; using UnityEditor.ShaderGraph.Legacy; #if HAS_VFX_GRAPH using UnityEditor.VFX; #endif namespace UnityEditor.Rendering.Universal.ShaderGraph { public enum MaterialType { Lit, Unlit, SpriteLit, SpriteUnlit, } public enum WorkflowMode { Specular, Metallic, } enum SurfaceType { Opaque, Transparent, } enum ZWriteControl { Auto = 0, ForceEnabled = 1, ForceDisabled = 2 } enum ZTestMode // the values here match UnityEngine.Rendering.CompareFunction { Disabled = 0, Never = 1, Less = 2, Equal = 3, LEqual = 4, // default for most rendering Greater = 5, NotEqual = 6, GEqual = 7, Always = 8, } enum AlphaMode { Alpha, Premultiply, Additive, Multiply, } internal enum RenderFace { Front = 2, // = CullMode.Back -- render front face only Back = 1, // = CullMode.Front -- render back face only Both = 0 // = CullMode.Off -- render both faces } sealed class UniversalTarget : Target, IHasMetadata, ILegacyTarget #if HAS_VFX_GRAPH , IMaySupportVFX, IRequireVFXContext #endif { public override int latestVersion => 1; // Constants static readonly GUID kSourceCodeGuid = new GUID("8c72f47fdde33b14a9340e325ce56f4d"); // UniversalTarget.cs public const string kPipelineTag = "UniversalPipeline"; public const string kLitMaterialTypeTag = "\"UniversalMaterialType\" = \"Lit\""; public const string kUnlitMaterialTypeTag = "\"UniversalMaterialType\" = \"Unlit\""; public static readonly string[] kSharedTemplateDirectories = GenerationUtils.GetDefaultSharedTemplateDirectories().Union(new string[] { "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Templates" #if HAS_VFX_GRAPH , "Packages/com.unity.visualeffectgraph/Editor/ShaderGraph/Templates" #endif }).ToArray(); public const string kUberTemplatePath = "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Templates/ShaderPass.template"; // SubTarget List m_SubTargets; List m_SubTargetNames; int activeSubTargetIndex => m_SubTargets.IndexOf(m_ActiveSubTarget); // View PopupField m_SubTargetField; TextField m_CustomGUIField; #if HAS_VFX_GRAPH Toggle m_SupportVFXToggle; #endif [SerializeField] JsonData m_ActiveSubTarget; // when checked, allows the material to control ALL surface settings (uber shader style) [SerializeField] bool m_AllowMaterialOverride = false; [SerializeField] SurfaceType m_SurfaceType = SurfaceType.Opaque; [SerializeField] ZTestMode m_ZTestMode = ZTestMode.LEqual; [SerializeField] ZWriteControl m_ZWriteControl = ZWriteControl.Auto; [SerializeField] AlphaMode m_AlphaMode = AlphaMode.Alpha; [SerializeField] RenderFace m_RenderFace = RenderFace.Front; [SerializeField] bool m_AlphaClip = false; [SerializeField] bool m_CastShadows = true; [SerializeField] bool m_ReceiveShadows = true; [SerializeField] string m_CustomEditorGUI; [SerializeField] bool m_SupportVFX; internal override bool ignoreCustomInterpolators => false; internal override int padCustomInterpolatorLimit => 4; internal override bool prefersSpritePreview => activeSubTarget is UniversalSpriteUnlitSubTarget or UniversalSpriteLitSubTarget or UniversalSpriteCustomLitSubTarget; public UniversalTarget() { displayName = "Universal"; m_SubTargets = TargetUtils.GetSubTargets(this); m_SubTargetNames = m_SubTargets.Select(x => x.displayName).ToList(); TargetUtils.ProcessSubTargetList(ref m_ActiveSubTarget, ref m_SubTargets); } public string renderType { get { if (surfaceType == SurfaceType.Transparent) return $"{RenderType.Transparent}"; else return $"{RenderType.Opaque}"; } } // this sets up the default renderQueue -- but it can be overridden by ResetMaterialKeywords() public string renderQueue { get { if (surfaceType == SurfaceType.Transparent) return $"{UnityEditor.ShaderGraph.RenderQueue.Transparent}"; else if (alphaClip) return $"{UnityEditor.ShaderGraph.RenderQueue.AlphaTest}"; else return $"{UnityEditor.ShaderGraph.RenderQueue.Geometry}"; } } public SubTarget activeSubTarget { get => m_ActiveSubTarget.value; set => m_ActiveSubTarget = value; } public bool allowMaterialOverride { get => m_AllowMaterialOverride; set => m_AllowMaterialOverride = value; } public SurfaceType surfaceType { get => m_SurfaceType; set => m_SurfaceType = value; } public ZWriteControl zWriteControl { get => m_ZWriteControl; set => m_ZWriteControl = value; } public ZTestMode zTestMode { get => m_ZTestMode; set => m_ZTestMode = value; } public AlphaMode alphaMode { get => m_AlphaMode; set => m_AlphaMode = value; } public RenderFace renderFace { get => m_RenderFace; set => m_RenderFace = value; } public bool alphaClip { get => m_AlphaClip; set => m_AlphaClip = value; } public bool castShadows { get => m_CastShadows; set => m_CastShadows = value; } public bool receiveShadows { get => m_ReceiveShadows; set => m_ReceiveShadows = value; } public string customEditorGUI { get => m_CustomEditorGUI; set => m_CustomEditorGUI = value; } // generally used to know if we need to build a depth pass public bool mayWriteDepth { get { if (allowMaterialOverride) { // material may or may not choose to write depth... we should create the depth pass return true; } else { switch (zWriteControl) { case ZWriteControl.Auto: return (surfaceType == SurfaceType.Opaque); case ZWriteControl.ForceDisabled: return false; default: return true; } } } } public override bool IsActive() { bool isUniversalRenderPipeline = GraphicsSettings.currentRenderPipeline is UniversalRenderPipelineAsset; return isUniversalRenderPipeline && activeSubTarget.IsActive(); } public override bool IsNodeAllowedByTarget(Type nodeType) { SRPFilterAttribute srpFilter = NodeClassCache.GetAttributeOnNodeType(nodeType); bool worksWithThisSrp = srpFilter == null || srpFilter.srpTypes.Contains(typeof(UniversalRenderPipeline)); SubTargetFilterAttribute subTargetFilter = NodeClassCache.GetAttributeOnNodeType(nodeType); bool worksWithThisSubTarget = subTargetFilter == null || subTargetFilter.subTargetTypes.Contains(activeSubTarget.GetType()); return worksWithThisSrp && worksWithThisSubTarget && base.IsNodeAllowedByTarget(nodeType); } public override void Setup(ref TargetSetupContext context) { // Setup the Target context.AddAssetDependency(kSourceCodeGuid, AssetCollection.Flags.SourceDependency); // Override EditorGUI (replaces the URP material editor by a custom one) if (!string.IsNullOrEmpty(m_CustomEditorGUI)) context.AddCustomEditorForRenderPipeline(m_CustomEditorGUI, typeof(UniversalRenderPipelineAsset)); // Setup the active SubTarget TargetUtils.ProcessSubTargetList(ref m_ActiveSubTarget, ref m_SubTargets); m_ActiveSubTarget.value.target = this; m_ActiveSubTarget.value.Setup(ref context); } public override void OnAfterMultiDeserialize(string json) { TargetUtils.ProcessSubTargetList(ref m_ActiveSubTarget, ref m_SubTargets); m_ActiveSubTarget.value.target = this; } 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) { // Core blocks context.AddBlock(BlockFields.VertexDescription.Position); context.AddBlock(BlockFields.VertexDescription.Normal); context.AddBlock(BlockFields.VertexDescription.Tangent); context.AddBlock(BlockFields.SurfaceDescription.BaseColor); // SubTarget blocks m_ActiveSubTarget.value.GetActiveBlocks(ref context); } public override void ProcessPreviewMaterial(Material material) { m_ActiveSubTarget.value.ProcessPreviewMaterial(material); } public override object saveContext => m_ActiveSubTarget.value?.saveContext; public override void CollectShaderProperties(PropertyCollector collector, GenerationMode generationMode) { base.CollectShaderProperties(collector, generationMode); activeSubTarget.CollectShaderProperties(collector, generationMode); collector.AddShaderProperty(LightmappingShaderProperties.kLightmapsArray); collector.AddShaderProperty(LightmappingShaderProperties.kLightmapsIndirectionArray); collector.AddShaderProperty(LightmappingShaderProperties.kShadowMasksArray); // SubTarget blocks m_ActiveSubTarget.value.CollectShaderProperties(collector, generationMode); } public override void GetPropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action registerUndo) { // Core properties m_SubTargetField = new PopupField(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(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) => { }); #if HAS_VFX_GRAPH if (VFXViewPreference.generateOutputContextWithShaderGraph) { // VFX Support if (!(m_ActiveSubTarget.value is UniversalSubTarget)) context.AddHelpBox(MessageType.Info, $"The {m_ActiveSubTarget.value.displayName} target does not support VFX Graph."); else { m_SupportVFXToggle = new Toggle("") { value = m_SupportVFX }; context.AddProperty("Support VFX Graph", m_SupportVFXToggle, (evt) => { m_SupportVFX = m_SupportVFXToggle.value; }); } } #endif } // this is a copy of ZTestMode, but hides the "Disabled" option, which is invalid enum ZTestModeForUI { Never = 1, Less = 2, Equal = 3, LEqual = 4, // default for most rendering Greater = 5, NotEqual = 6, GEqual = 7, Always = 8, }; public void AddDefaultMaterialOverrideGUI(ref TargetPropertyGUIContext context, Action onChange, Action registerUndo) { // At some point we may want to convert this to be a per-property control // or Unify the UX with the upcoming "lock" feature of the Material Variant properties context.AddProperty("Allow Material Override", new Toggle() { value = allowMaterialOverride }, (evt) => { if (Equals(allowMaterialOverride, evt.newValue)) return; registerUndo("Change Allow Material Override"); allowMaterialOverride = evt.newValue; onChange(); }); } public void AddDefaultSurfacePropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action registerUndo, bool showReceiveShadows) { context.AddProperty("Surface Type", new EnumField(SurfaceType.Opaque) { value = surfaceType }, (evt) => { if (Equals(surfaceType, evt.newValue)) return; registerUndo("Change Surface"); surfaceType = (SurfaceType)evt.newValue; onChange(); }); context.AddProperty("Blending Mode", new EnumField(AlphaMode.Alpha) { value = alphaMode }, surfaceType == SurfaceType.Transparent, (evt) => { if (Equals(alphaMode, evt.newValue)) return; registerUndo("Change Blend"); alphaMode = (AlphaMode)evt.newValue; onChange(); }); context.AddProperty("Render Face", new EnumField(RenderFace.Front) { value = renderFace }, (evt) => { if (Equals(renderFace, evt.newValue)) return; registerUndo("Change Render Face"); renderFace = (RenderFace)evt.newValue; onChange(); }); context.AddProperty("Depth Write", new EnumField(ZWriteControl.Auto) { value = zWriteControl }, (evt) => { if (Equals(zWriteControl, evt.newValue)) return; registerUndo("Change Depth Write Control"); zWriteControl = (ZWriteControl)evt.newValue; onChange(); }); context.AddProperty("Depth Test", new EnumField(ZTestModeForUI.LEqual) { value = (ZTestModeForUI)zTestMode }, (evt) => { if (Equals(zTestMode, evt.newValue)) return; registerUndo("Change Depth Test"); zTestMode = (ZTestMode)evt.newValue; onChange(); }); context.AddProperty("Alpha Clipping", new Toggle() { value = alphaClip }, (evt) => { if (Equals(alphaClip, evt.newValue)) return; registerUndo("Change Alpha Clip"); alphaClip = evt.newValue; onChange(); }); context.AddProperty("Cast Shadows", new Toggle() { value = castShadows }, (evt) => { if (Equals(castShadows, evt.newValue)) return; registerUndo("Change Cast Shadows"); castShadows = evt.newValue; onChange(); }); if (showReceiveShadows) context.AddProperty("Receive Shadows", new Toggle() { value = receiveShadows }, (evt) => { if (Equals(receiveShadows, evt.newValue)) return; registerUndo("Change Receive Shadows"); receiveShadows = evt.newValue; onChange(); }); } 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 bool TryUpgradeFromMasterNode(IMasterNode1 masterNode, out Dictionary blockMap) { void UpgradeAlphaClip() { var clipThresholdId = 8; var node = masterNode as AbstractMaterialNode; var clipThresholdSlot = node.FindSlot(clipThresholdId); if (clipThresholdSlot == null) return; clipThresholdSlot.owner = node; if (clipThresholdSlot.isConnected || clipThresholdSlot.value > 0.0f) { m_AlphaClip = true; } } // Upgrade Target allowMaterialOverride = false; switch (masterNode) { case PBRMasterNode1 pbrMasterNode: m_SurfaceType = (SurfaceType)pbrMasterNode.m_SurfaceType; m_AlphaMode = (AlphaMode)pbrMasterNode.m_AlphaMode; m_RenderFace = pbrMasterNode.m_TwoSided ? RenderFace.Both : RenderFace.Front; UpgradeAlphaClip(); m_CustomEditorGUI = pbrMasterNode.m_OverrideEnabled ? pbrMasterNode.m_ShaderGUIOverride : ""; break; case UnlitMasterNode1 unlitMasterNode: m_SurfaceType = (SurfaceType)unlitMasterNode.m_SurfaceType; m_AlphaMode = (AlphaMode)unlitMasterNode.m_AlphaMode; m_RenderFace = unlitMasterNode.m_TwoSided ? RenderFace.Both : RenderFace.Front; UpgradeAlphaClip(); m_CustomEditorGUI = unlitMasterNode.m_OverrideEnabled ? unlitMasterNode.m_ShaderGUIOverride : ""; break; case SpriteLitMasterNode1 spriteLitMasterNode: m_CustomEditorGUI = spriteLitMasterNode.m_OverrideEnabled ? spriteLitMasterNode.m_ShaderGUIOverride : ""; break; case SpriteUnlitMasterNode1 spriteUnlitMasterNode: m_CustomEditorGUI = spriteUnlitMasterNode.m_OverrideEnabled ? spriteUnlitMasterNode.m_ShaderGUIOverride : ""; break; } // Upgrade SubTarget foreach (var subTarget in m_SubTargets) { if (!(subTarget is ILegacyTarget legacySubTarget)) continue; if (legacySubTarget.TryUpgradeFromMasterNode(masterNode, out blockMap)) { m_ActiveSubTarget = subTarget; return true; } } blockMap = null; return false; } public override bool WorksWithSRP(RenderPipelineAsset scriptableRenderPipeline) { return scriptableRenderPipeline?.GetType() == typeof(UniversalRenderPipelineAsset); } #if HAS_VFX_GRAPH public void ConfigureContextData(VFXContext context, VFXContextCompiledData data) { if (!(m_ActiveSubTarget.value is IRequireVFXContext vfxSubtarget)) return; vfxSubtarget.ConfigureContextData(context, data); } #endif public bool CanSupportVFX() { if (m_ActiveSubTarget.value == null) return false; if (m_ActiveSubTarget.value is UniversalUnlitSubTarget) return true; if (m_ActiveSubTarget.value is UniversalLitSubTarget) return true; //It excludes: // - UniversalDecalSubTarget // - UniversalSpriteLitSubTarget // - UniversalSpriteUnlitSubTarget // - UniversalSpriteCustomLitSubTarget return false; } public bool SupportsVFX() { #if HAS_VFX_GRAPH if (!CanSupportVFX()) return false; return m_SupportVFX; #else return false; #endif } [Serializable] class UniversalTargetLegacySerialization { [SerializeField] public bool m_TwoSided = false; } public override void OnAfterDeserialize(string json) { base.OnAfterDeserialize(json); if (this.sgVersion < latestVersion) { if (this.sgVersion == 0) { // deserialize the old settings to upgrade var oldSettings = JsonUtility.FromJson(json); this.m_RenderFace = oldSettings.m_TwoSided ? RenderFace.Both : RenderFace.Front; } ChangeVersion(latestVersion); } } #region Metadata string IHasMetadata.identifier { get { // defer to subtarget if (m_ActiveSubTarget.value is IHasMetadata subTargetHasMetaData) return subTargetHasMetaData.identifier; return null; } } ScriptableObject IHasMetadata.GetMetadataObject(GraphDataReadOnly graph) { // defer to subtarget if (m_ActiveSubTarget.value is IHasMetadata subTargetHasMetaData) return subTargetHasMetaData.GetMetadataObject(graph); return null; } #endregion } #region Passes static class CorePasses { internal static void AddAlphaClipControlToPass(ref PassDescriptor pass, UniversalTarget target) { if (target.allowMaterialOverride) pass.keywords.Add(CoreKeywordDescriptors.AlphaTestOn); else if (target.alphaClip) pass.defines.Add(CoreKeywordDescriptors.AlphaTestOn, 1); } internal static void AddTargetSurfaceControlsToPass(ref PassDescriptor pass, UniversalTarget target) { // the surface settings can either be material controlled or target controlled if (target.allowMaterialOverride) { // setup material control of via keyword pass.keywords.Add(CoreKeywordDescriptors.SurfaceTypeTransparent); pass.keywords.Add(CoreKeywordDescriptors.AlphaPremultiplyOn); } else { // setup target control via define if (target.surfaceType == SurfaceType.Transparent) pass.defines.Add(CoreKeywordDescriptors.SurfaceTypeTransparent, 1); if (target.alphaMode == AlphaMode.Premultiply) pass.defines.Add(CoreKeywordDescriptors.AlphaPremultiplyOn, 1); } AddAlphaClipControlToPass(ref pass, target); } // used by lit/unlit subtargets public static PassDescriptor DepthOnly(UniversalTarget target) { var result = new PassDescriptor() { // Definition displayName = "DepthOnly", referenceName = "SHADERPASS_DEPTHONLY", lightMode = "DepthOnly", useInPreview = true, // Template passTemplatePath = UniversalTarget.kUberTemplatePath, sharedTemplateDirectories = UniversalTarget.kSharedTemplateDirectories, // Port Mask validVertexBlocks = CoreBlockMasks.Vertex, validPixelBlocks = CoreBlockMasks.FragmentAlphaOnly, // Fields structs = CoreStructCollections.Default, fieldDependencies = CoreFieldDependencies.Default, // Conditional State renderStates = CoreRenderStates.DepthOnly(target), pragmas = CorePragmas.Instanced, defines = new DefineCollection(), keywords = new KeywordCollection(), includes = CoreIncludes.DepthOnly, // Custom Interpolator Support customInterpolators = CoreCustomInterpDescriptors.Common }; AddAlphaClipControlToPass(ref result, target); return result; } // used by lit/unlit subtargets public static PassDescriptor DepthNormal(UniversalTarget target) { var result = new PassDescriptor() { // Definition displayName = "DepthNormals", referenceName = "SHADERPASS_DEPTHNORMALS", lightMode = "DepthNormals", useInPreview = false, // Template passTemplatePath = UniversalTarget.kUberTemplatePath, sharedTemplateDirectories = UniversalTarget.kSharedTemplateDirectories, // Port Mask validVertexBlocks = CoreBlockMasks.Vertex, validPixelBlocks = CoreBlockMasks.FragmentDepthNormals, // Fields structs = CoreStructCollections.Default, requiredFields = CoreRequiredFields.DepthNormals, fieldDependencies = CoreFieldDependencies.Default, // Conditional State renderStates = CoreRenderStates.DepthNormalsOnly(target), pragmas = CorePragmas.Instanced, defines = new DefineCollection(), keywords = new KeywordCollection(), includes = CoreIncludes.DepthNormalsOnly, // Custom Interpolator Support customInterpolators = CoreCustomInterpDescriptors.Common }; AddAlphaClipControlToPass(ref result, target); return result; } // used by lit/unlit subtargets public static PassDescriptor DepthNormalOnly(UniversalTarget target) { var result = new PassDescriptor() { // Definition displayName = "DepthNormalsOnly", referenceName = "SHADERPASS_DEPTHNORMALSONLY", lightMode = "DepthNormalsOnly", useInPreview = false, // Template passTemplatePath = UniversalTarget.kUberTemplatePath, sharedTemplateDirectories = UniversalTarget.kSharedTemplateDirectories, // Port Mask validVertexBlocks = CoreBlockMasks.Vertex, validPixelBlocks = CoreBlockMasks.FragmentDepthNormals, // Fields structs = CoreStructCollections.Default, requiredFields = CoreRequiredFields.DepthNormals, fieldDependencies = CoreFieldDependencies.Default, // Conditional State renderStates = CoreRenderStates.DepthNormalsOnly(target), pragmas = CorePragmas.Instanced, defines = new DefineCollection(), keywords = new KeywordCollection(), includes = CoreIncludes.DepthNormalsOnly, // Custom Interpolator Support customInterpolators = CoreCustomInterpDescriptors.Common }; AddAlphaClipControlToPass(ref result, target); return result; } // used by lit/unlit targets public static PassDescriptor ShadowCaster(UniversalTarget target) { var result = new PassDescriptor() { // Definition displayName = "ShadowCaster", referenceName = "SHADERPASS_SHADOWCASTER", lightMode = "ShadowCaster", // Template passTemplatePath = UniversalTarget.kUberTemplatePath, sharedTemplateDirectories = UniversalTarget.kSharedTemplateDirectories, // Port Mask validVertexBlocks = CoreBlockMasks.Vertex, validPixelBlocks = CoreBlockMasks.FragmentAlphaOnly, // Fields structs = CoreStructCollections.Default, requiredFields = CoreRequiredFields.ShadowCaster, fieldDependencies = CoreFieldDependencies.Default, // Conditional State renderStates = CoreRenderStates.ShadowCaster(target), pragmas = CorePragmas.Instanced, defines = new DefineCollection(), keywords = new KeywordCollection() { CoreKeywords.ShadowCaster }, includes = CoreIncludes.ShadowCaster, // Custom Interpolator Support customInterpolators = CoreCustomInterpDescriptors.Common }; AddAlphaClipControlToPass(ref result, target); return result; } public static PassDescriptor SceneSelection(UniversalTarget target) { var result = new PassDescriptor() { // Definition displayName = "SceneSelectionPass", referenceName = "SHADERPASS_DEPTHONLY", lightMode = "SceneSelectionPass", useInPreview = false, // Template passTemplatePath = UniversalTarget.kUberTemplatePath, sharedTemplateDirectories = UniversalTarget.kSharedTemplateDirectories, // Port Mask validVertexBlocks = CoreBlockMasks.Vertex, validPixelBlocks = CoreBlockMasks.FragmentAlphaOnly, // Fields structs = CoreStructCollections.Default, fieldDependencies = CoreFieldDependencies.Default, // Conditional State renderStates = CoreRenderStates.SceneSelection(target), pragmas = CorePragmas.Instanced, defines = new DefineCollection { CoreDefines.SceneSelection, { CoreKeywordDescriptors.AlphaClipThreshold, 1 } }, keywords = new KeywordCollection(), includes = CoreIncludes.SceneSelection, // Custom Interpolator Support customInterpolators = CoreCustomInterpDescriptors.Common }; AddAlphaClipControlToPass(ref result, target); return result; } public static PassDescriptor ScenePicking(UniversalTarget target) { var result = new PassDescriptor() { // Definition displayName = "ScenePickingPass", referenceName = "SHADERPASS_DEPTHONLY", lightMode = "Picking", useInPreview = false, // Template passTemplatePath = UniversalTarget.kUberTemplatePath, sharedTemplateDirectories = UniversalTarget.kSharedTemplateDirectories, // Port Mask validVertexBlocks = CoreBlockMasks.Vertex, validPixelBlocks = CoreBlockMasks.FragmentAlphaOnly, // Fields structs = CoreStructCollections.Default, fieldDependencies = CoreFieldDependencies.Default, // Conditional State renderStates = CoreRenderStates.ScenePicking(target), pragmas = CorePragmas.Instanced, defines = new DefineCollection { CoreDefines.ScenePicking, { CoreKeywordDescriptors.AlphaClipThreshold, 1 } }, keywords = new KeywordCollection(), includes = CoreIncludes.ScenePicking, // Custom Interpolator Support customInterpolators = CoreCustomInterpDescriptors.Common }; AddAlphaClipControlToPass(ref result, target); return result; } public static PassDescriptor _2DSceneSelection(UniversalTarget target) { var result = new PassDescriptor() { // Definition displayName = "SceneSelectionPass", referenceName = "SHADERPASS_DEPTHONLY", lightMode = "SceneSelectionPass", useInPreview = false, // Template passTemplatePath = GenerationUtils.GetDefaultTemplatePath("PassMesh.template"), sharedTemplateDirectories = GenerationUtils.GetDefaultSharedTemplateDirectories(), // Port Mask validVertexBlocks = CoreBlockMasks.Vertex, validPixelBlocks = CoreBlockMasks.FragmentAlphaOnly, // Fields structs = CoreStructCollections.Default, fieldDependencies = CoreFieldDependencies.Default, // Conditional State renderStates = CoreRenderStates.SceneSelection(target), pragmas = CorePragmas._2DDefault, defines = new DefineCollection { CoreDefines.SceneSelection, { CoreKeywordDescriptors.AlphaClipThreshold, 0 } }, keywords = new KeywordCollection(), includes = CoreIncludes.ScenePicking, // Custom Interpolator Support customInterpolators = CoreCustomInterpDescriptors.Common }; AddAlphaClipControlToPass(ref result, target); return result; } public static PassDescriptor _2DScenePicking(UniversalTarget target) { var result = new PassDescriptor() { // Definition displayName = "ScenePickingPass", referenceName = "SHADERPASS_DEPTHONLY", lightMode = "Picking", useInPreview = false, // Template passTemplatePath = GenerationUtils.GetDefaultTemplatePath("PassMesh.template"), sharedTemplateDirectories = GenerationUtils.GetDefaultSharedTemplateDirectories(), // Port Mask validVertexBlocks = CoreBlockMasks.Vertex, validPixelBlocks = CoreBlockMasks.FragmentAlphaOnly, // Fields structs = CoreStructCollections.Default, fieldDependencies = CoreFieldDependencies.Default, // Conditional State renderStates = CoreRenderStates.ScenePicking(target), pragmas = CorePragmas._2DDefault, defines = new DefineCollection { CoreDefines.ScenePicking, { CoreKeywordDescriptors.AlphaClipThreshold, 0 } }, keywords = new KeywordCollection(), includes = CoreIncludes.SceneSelection, // Custom Interpolator Support customInterpolators = CoreCustomInterpDescriptors.Common }; AddAlphaClipControlToPass(ref result, target); return result; } } #endregion #region PortMasks class CoreBlockMasks { public static readonly BlockFieldDescriptor[] Vertex = new BlockFieldDescriptor[] { BlockFields.VertexDescription.Position, BlockFields.VertexDescription.Normal, BlockFields.VertexDescription.Tangent, }; public static readonly BlockFieldDescriptor[] FragmentAlphaOnly = new BlockFieldDescriptor[] { BlockFields.SurfaceDescription.Alpha, BlockFields.SurfaceDescription.AlphaClipThreshold, }; public static readonly BlockFieldDescriptor[] FragmentColorAlpha = new BlockFieldDescriptor[] { BlockFields.SurfaceDescription.BaseColor, 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 StructCollections static class CoreStructCollections { public static readonly StructCollection Default = new StructCollection { { Structs.Attributes }, { UniversalStructs.Varyings }, { Structs.SurfaceDescriptionInputs }, { Structs.VertexDescriptionInputs }, }; } #endregion #region RequiredFields static class CoreRequiredFields { public static readonly FieldCollection ShadowCaster = new FieldCollection() { StructFields.Varyings.normalWS, }; 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 }; } #endregion #region FieldDependencies static class CoreFieldDependencies { public static readonly DependencyCollection Default = new DependencyCollection() { { FieldDependencies.Default }, new FieldDependency(UniversalStructFields.Varyings.stereoTargetEyeIndexAsRTArrayIdx, StructFields.Attributes.instanceID), new FieldDependency(UniversalStructFields.Varyings.stereoTargetEyeIndexAsBlendIdx0, StructFields.Attributes.instanceID), }; } #endregion #region RenderStates static class CoreRenderStates { public static class Uniforms { public static readonly string srcBlend = "[" + Property.SrcBlend + "]"; public static readonly string dstBlend = "[" + Property.DstBlend + "]"; public static readonly string cullMode = "[" + Property.CullMode + "]"; public static readonly string zWrite = "[" + Property.ZWrite + "]"; public static readonly string zTest = "[" + Property.ZTest + "]"; } // used by sprite targets, NOT used by lit/unlit anymore public static readonly RenderStateCollection Default = new RenderStateCollection { { RenderState.ZTest(ZTest.LEqual) }, { RenderState.ZWrite(ZWrite.On), new FieldCondition(UniversalFields.SurfaceOpaque, true) }, { RenderState.ZWrite(ZWrite.Off), new FieldCondition(UniversalFields.SurfaceTransparent, true) }, { RenderState.Cull(Cull.Back), new FieldCondition(Fields.DoubleSided, false) }, { RenderState.Cull(Cull.Off), new FieldCondition(Fields.DoubleSided, true) }, { RenderState.Blend(Blend.One, Blend.Zero), new FieldCondition(UniversalFields.SurfaceOpaque, true) }, { RenderState.Blend(Blend.SrcAlpha, Blend.OneMinusSrcAlpha, Blend.One, Blend.OneMinusSrcAlpha), new FieldCondition(Fields.BlendAlpha, true) }, { RenderState.Blend(Blend.One, Blend.OneMinusSrcAlpha, Blend.One, Blend.OneMinusSrcAlpha), new FieldCondition(UniversalFields.BlendPremultiply, true) }, { RenderState.Blend(Blend.SrcAlpha, Blend.One, Blend.One, Blend.One), new FieldCondition(UniversalFields.BlendAdd, true) }, { RenderState.Blend(Blend.DstColor, Blend.Zero), new FieldCondition(UniversalFields.BlendMultiply, true) }, }; // used by lit/unlit subtargets public static readonly RenderStateCollection MaterialControlledRenderState = new RenderStateCollection { { RenderState.ZTest(Uniforms.zTest) }, { RenderState.ZWrite(Uniforms.zWrite) }, { RenderState.Cull(Uniforms.cullMode) }, { RenderState.Blend(Uniforms.srcBlend, Uniforms.dstBlend) }, //, Uniforms.alphaSrcBlend, Uniforms.alphaDstBlend) }, }; public static Cull RenderFaceToCull(RenderFace renderFace) { switch (renderFace) { case RenderFace.Back: return Cull.Front; case RenderFace.Front: return Cull.Back; case RenderFace.Both: return Cull.Off; } return Cull.Back; } // used by lit/unlit subtargets public static RenderStateCollection UberSwitchedRenderState(UniversalTarget target) { if (target.allowMaterialOverride) return MaterialControlledRenderState; else { var result = new RenderStateCollection(); result.Add(RenderState.ZTest(target.zTestMode.ToString())); if (target.zWriteControl == ZWriteControl.Auto) { if (target.surfaceType == SurfaceType.Opaque) result.Add(RenderState.ZWrite(ZWrite.On)); else result.Add(RenderState.ZWrite(ZWrite.Off)); } else if (target.zWriteControl == ZWriteControl.ForceEnabled) result.Add(RenderState.ZWrite(ZWrite.On)); else result.Add(RenderState.ZWrite(ZWrite.Off)); result.Add(RenderState.Cull(RenderFaceToCull(target.renderFace))); if (target.surfaceType == SurfaceType.Opaque) { result.Add(RenderState.Blend(Blend.One, Blend.Zero)); } else switch (target.alphaMode) { case AlphaMode.Alpha: result.Add(RenderState.Blend(Blend.SrcAlpha, Blend.OneMinusSrcAlpha, Blend.One, Blend.OneMinusSrcAlpha)); break; case AlphaMode.Premultiply: result.Add(RenderState.Blend(Blend.One, Blend.OneMinusSrcAlpha, Blend.One, Blend.OneMinusSrcAlpha)); break; case AlphaMode.Additive: result.Add(RenderState.Blend(Blend.SrcAlpha, Blend.One, Blend.One, Blend.One)); break; case AlphaMode.Multiply: result.Add(RenderState.Blend(Blend.DstColor, Blend.Zero)); break; } return result; } } // used by lit target ONLY public static readonly RenderStateCollection Meta = new RenderStateCollection { { RenderState.Cull(Cull.Off) }, }; public static RenderStateDescriptor UberSwitchedCullRenderState(UniversalTarget target) { if (target.allowMaterialOverride) return RenderState.Cull(Uniforms.cullMode); else return RenderState.Cull(RenderFaceToCull(target.renderFace)); } // used by lit/unlit targets public static RenderStateCollection ShadowCaster(UniversalTarget target) { var result = new RenderStateCollection { { RenderState.ZTest(ZTest.LEqual) }, { RenderState.ZWrite(ZWrite.On) }, { UberSwitchedCullRenderState(target) }, { RenderState.ColorMask("ColorMask 0") }, }; return result; } // used by lit/unlit targets public static RenderStateCollection DepthOnly(UniversalTarget target) { var result = new RenderStateCollection { { RenderState.ZTest(ZTest.LEqual) }, { RenderState.ZWrite(ZWrite.On) }, { UberSwitchedCullRenderState(target) }, { RenderState.ColorMask("ColorMask 0") }, }; return result; } // used by lit target ONLY public static RenderStateCollection DepthNormalsOnly(UniversalTarget target) { var result = new RenderStateCollection { { RenderState.ZTest(ZTest.LEqual) }, { RenderState.ZWrite(ZWrite.On) }, { UberSwitchedCullRenderState(target) } }; return result; } // Used by all targets public static RenderStateCollection SceneSelection(UniversalTarget target) { var result = new RenderStateCollection { { RenderState.Cull(Cull.Off) }, }; return result; } public static RenderStateCollection ScenePicking(UniversalTarget target) { var result = new RenderStateCollection { { UberSwitchedCullRenderState(target) } }; return result; } } #endregion #region Pragmas static class CorePragmas { public static readonly PragmaCollection Default = new PragmaCollection { { Pragma.Target(ShaderModel.Target20) }, { Pragma.OnlyRenderers(new[] { Platform.GLES, Platform.GLES3, Platform.GLCore, Platform.D3D11 }) }, { Pragma.Vertex("vert") }, { Pragma.Fragment("frag") }, }; public static readonly PragmaCollection Instanced = new PragmaCollection { { Pragma.Target(ShaderModel.Target20) }, { Pragma.OnlyRenderers(new[] { Platform.GLES, Platform.GLES3, Platform.GLCore, Platform.D3D11 }) }, { Pragma.MultiCompileInstancing }, { Pragma.Vertex("vert") }, { Pragma.Fragment("frag") }, }; public static readonly PragmaCollection Forward = new PragmaCollection { { Pragma.Target(ShaderModel.Target20) }, { Pragma.OnlyRenderers(new[] { Platform.GLES, Platform.GLES3, Platform.GLCore, Platform.D3D11 }) }, { Pragma.MultiCompileInstancing }, { Pragma.MultiCompileFog }, { Pragma.InstancingOptions(InstancingOptions.RenderingLayer) }, { Pragma.Vertex("vert") }, { Pragma.Fragment("frag") }, }; public static readonly PragmaCollection _2DDefault = new PragmaCollection { { Pragma.Target(ShaderModel.Target20) }, { Pragma.ExcludeRenderers(new[] { Platform.D3D9 }) }, { Pragma.Vertex("vert") }, { Pragma.Fragment("frag") }, }; public static readonly PragmaCollection DOTSDefault = new PragmaCollection { { Pragma.Target(ShaderModel.Target45) }, { Pragma.ExcludeRenderers(new[] { Platform.GLES, Platform.GLES3, Platform.GLCore }) }, { Pragma.Vertex("vert") }, { Pragma.Fragment("frag") }, }; public static readonly PragmaCollection DOTSInstanced = new PragmaCollection { { Pragma.Target(ShaderModel.Target45) }, { Pragma.ExcludeRenderers(new[] { Platform.GLES, Platform.GLES3, Platform.GLCore }) }, { Pragma.MultiCompileInstancing }, { Pragma.DOTSInstancing }, { Pragma.Vertex("vert") }, { Pragma.Fragment("frag") }, }; public static readonly PragmaCollection DOTSForward = new PragmaCollection { { Pragma.Target(ShaderModel.Target45) }, { Pragma.ExcludeRenderers(new[] { Platform.GLES, Platform.GLES3, Platform.GLCore }) }, { Pragma.MultiCompileInstancing }, { Pragma.MultiCompileFog }, { Pragma.InstancingOptions(InstancingOptions.RenderingLayer) }, { Pragma.DOTSInstancing }, { Pragma.Vertex("vert") }, { Pragma.Fragment("frag") }, }; public static readonly PragmaCollection DOTSGBuffer = new PragmaCollection { { Pragma.Target(ShaderModel.Target45) }, { Pragma.ExcludeRenderers(new[] { Platform.GLES, Platform.GLES3, Platform.GLCore }) }, { Pragma.MultiCompileInstancing }, { Pragma.MultiCompileFog }, { Pragma.InstancingOptions(InstancingOptions.RenderingLayer) }, { Pragma.DOTSInstancing }, { Pragma.Vertex("vert") }, { Pragma.Fragment("frag") }, }; } #endregion #region Includes static class CoreIncludes { const string kColor = "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"; const string kTexture = "Packages/com.unity.render-pipelines.core/ShaderLibrary/Texture.hlsl"; const string kCore = "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"; const string kLighting = "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"; const string kGraphFunctions = "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"; const string kVaryings = "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/Varyings.hlsl"; const string kShaderPass = "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/ShaderPass.hlsl"; const string kDepthOnlyPass = "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/DepthOnlyPass.hlsl"; const string kDepthNormalsOnlyPass = "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/DepthNormalsOnlyPass.hlsl"; const string kShadowCasterPass = "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/ShadowCasterPass.hlsl"; const string kTextureStack = "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureStack.hlsl"; const string kDBuffer = "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DBuffer.hlsl"; const string kSelectionPickingPass = "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/SelectionPickingPass.hlsl"; public static readonly IncludeCollection CorePregraph = new IncludeCollection { { kColor, IncludeLocation.Pregraph }, { kTexture, IncludeLocation.Pregraph }, { kCore, IncludeLocation.Pregraph }, { kLighting, IncludeLocation.Pregraph }, { kTextureStack, IncludeLocation.Pregraph }, // TODO: put this on a conditional }; public static readonly IncludeCollection ShaderGraphPregraph = new IncludeCollection { { kGraphFunctions, IncludeLocation.Pregraph }, }; public static readonly IncludeCollection CorePostgraph = new IncludeCollection { { kShaderPass, IncludeLocation.Pregraph }, { kVaryings, IncludeLocation.Postgraph }, }; public static readonly IncludeCollection DepthOnly = new IncludeCollection { // Pre-graph { CorePregraph }, { ShaderGraphPregraph }, // Post-graph { CorePostgraph }, { kDepthOnlyPass, IncludeLocation.Postgraph }, }; public static readonly IncludeCollection DepthNormalsOnly = new IncludeCollection { // Pre-graph { CorePregraph }, { ShaderGraphPregraph }, // Post-graph { CorePostgraph }, { kDepthNormalsOnlyPass, IncludeLocation.Postgraph }, }; public static readonly IncludeCollection ShadowCaster = new IncludeCollection { // Pre-graph { CorePregraph }, { ShaderGraphPregraph }, // Post-graph { CorePostgraph }, { kShadowCasterPass, IncludeLocation.Postgraph }, }; public static readonly IncludeCollection DBufferPregraph = new IncludeCollection { { kDBuffer, IncludeLocation.Pregraph }, }; public static readonly IncludeCollection SceneSelection = new IncludeCollection { // Pre-graph { CorePregraph }, { ShaderGraphPregraph }, // Post-graph { CorePostgraph }, { kSelectionPickingPass, IncludeLocation.Postgraph }, }; public static readonly IncludeCollection ScenePicking = new IncludeCollection { // Pre-graph { CorePregraph }, { ShaderGraphPregraph }, // Post-graph { CorePostgraph }, { kSelectionPickingPass, IncludeLocation.Postgraph }, }; } #endregion #region Defines static class CoreDefines { public static readonly DefineCollection UseLegacySpriteBlocks = new DefineCollection { { CoreKeywordDescriptors.UseLegacySpriteBlocks, 1, new FieldCondition(CoreFields.UseLegacySpriteBlocks, true) }, }; public static readonly DefineCollection UseFragmentFog = new DefineCollection() { {CoreKeywordDescriptors.UseFragmentFog, 1}, }; public static readonly DefineCollection SceneSelection = new DefineCollection { { CoreKeywordDescriptors.SceneSelectionPass, 1 }, }; public static readonly DefineCollection ScenePicking = new DefineCollection { { CoreKeywordDescriptors.ScenePickingPass, 1 }, }; } #endregion #region KeywordDescriptors static class CoreKeywordDescriptors { public static readonly KeywordDescriptor StaticLightmap = new KeywordDescriptor() { displayName = "Static Lightmap", referenceName = "LIGHTMAP_ON", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, }; public static readonly KeywordDescriptor DynamicLightmap = new KeywordDescriptor() { displayName = "Dynamic Lightmap", referenceName = "DYNAMICLIGHTMAP_ON", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, }; public static readonly KeywordDescriptor DirectionalLightmapCombined = new KeywordDescriptor() { displayName = "Directional Lightmap Combined", referenceName = "DIRLIGHTMAP_COMBINED", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, }; public static readonly KeywordDescriptor SampleGI = new KeywordDescriptor() { displayName = "Sample GI", referenceName = "_SAMPLE_GI", type = KeywordType.Boolean, definition = KeywordDefinition.ShaderFeature, scope = KeywordScope.Global, }; public static readonly KeywordDescriptor AlphaTestOn = new KeywordDescriptor() { displayName = ShaderKeywordStrings._ALPHATEST_ON, referenceName = ShaderKeywordStrings._ALPHATEST_ON, type = KeywordType.Boolean, definition = KeywordDefinition.ShaderFeature, scope = KeywordScope.Local, stages = KeywordShaderStage.Fragment, }; public static readonly KeywordDescriptor SurfaceTypeTransparent = new KeywordDescriptor() { displayName = ShaderKeywordStrings._SURFACE_TYPE_TRANSPARENT, referenceName = ShaderKeywordStrings._SURFACE_TYPE_TRANSPARENT, type = KeywordType.Boolean, definition = KeywordDefinition.ShaderFeature, scope = KeywordScope.Global, // needs to match HDRP stages = KeywordShaderStage.Fragment, }; public static readonly KeywordDescriptor AlphaPremultiplyOn = new KeywordDescriptor() { displayName = ShaderKeywordStrings._ALPHAPREMULTIPLY_ON, referenceName = ShaderKeywordStrings._ALPHAPREMULTIPLY_ON, type = KeywordType.Boolean, definition = KeywordDefinition.ShaderFeature, scope = KeywordScope.Local, stages = KeywordShaderStage.Fragment, }; public static readonly KeywordDescriptor MainLightShadows = new KeywordDescriptor() { displayName = "Main Light Shadows", referenceName = "", type = KeywordType.Enum, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, entries = new KeywordEntry[] { new KeywordEntry() { displayName = "Off", referenceName = "" }, new KeywordEntry() { displayName = "No Cascade", referenceName = "MAIN_LIGHT_SHADOWS" }, new KeywordEntry() { displayName = "Cascade", referenceName = "MAIN_LIGHT_SHADOWS_CASCADE" }, new KeywordEntry() { displayName = "Screen", referenceName = "MAIN_LIGHT_SHADOWS_SCREEN" }, } }; public static readonly KeywordDescriptor CastingPunctualLightShadow = new KeywordDescriptor() { displayName = "Casting Punctual Light Shadow", referenceName = "_CASTING_PUNCTUAL_LIGHT_SHADOW", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, stages = KeywordShaderStage.Vertex, }; public static readonly KeywordDescriptor AdditionalLights = new KeywordDescriptor() { displayName = "Additional Lights", referenceName = "", type = KeywordType.Enum, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, entries = new KeywordEntry[] { new KeywordEntry() { displayName = "Off", referenceName = "" }, new KeywordEntry() { displayName = "Vertex", referenceName = "ADDITIONAL_LIGHTS_VERTEX" }, new KeywordEntry() { displayName = "Fragment", referenceName = "ADDITIONAL_LIGHTS" }, } }; public static readonly KeywordDescriptor AdditionalLightShadows = new KeywordDescriptor() { displayName = "Additional Light Shadows", referenceName = "_ADDITIONAL_LIGHT_SHADOWS", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, stages = KeywordShaderStage.Fragment, }; public static readonly KeywordDescriptor ReflectionProbeBlending = new KeywordDescriptor() { displayName = "Reflection Probe Blending", referenceName = "_REFLECTION_PROBE_BLENDING", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, stages = KeywordShaderStage.Fragment, }; public static readonly KeywordDescriptor ReflectionProbeBoxProjection = new KeywordDescriptor() { displayName = "Reflection Probe Box Projection", referenceName = "_REFLECTION_PROBE_BOX_PROJECTION", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, stages = KeywordShaderStage.Fragment, }; public static readonly KeywordDescriptor ShadowsSoft = new KeywordDescriptor() { displayName = "Shadows Soft", referenceName = "_SHADOWS_SOFT", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, stages = KeywordShaderStage.Fragment, }; public static readonly KeywordDescriptor MixedLightingSubtractive = new KeywordDescriptor() { displayName = "Mixed Lighting Subtractive", referenceName = "_MIXED_LIGHTING_SUBTRACTIVE", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, }; public static readonly KeywordDescriptor LightmapShadowMixing = new KeywordDescriptor() { displayName = "Lightmap Shadow Mixing", referenceName = "LIGHTMAP_SHADOW_MIXING", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, }; public static readonly KeywordDescriptor ShadowsShadowmask = new KeywordDescriptor() { displayName = "Shadows Shadowmask", referenceName = "SHADOWS_SHADOWMASK", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, }; public static readonly KeywordDescriptor LightLayers = new KeywordDescriptor() { displayName = "Light Layers", referenceName = "_LIGHT_LAYERS", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, stages = KeywordShaderStage.Fragment, }; public static readonly KeywordDescriptor RenderPassEnabled = new KeywordDescriptor() { displayName = "Render Pass Enabled", referenceName = "_RENDER_PASS_ENABLED", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, stages = KeywordShaderStage.Fragment, }; public static readonly KeywordDescriptor ShapeLightType0 = new KeywordDescriptor() { displayName = "Shape Light Type 0", referenceName = "USE_SHAPE_LIGHT_TYPE_0", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, }; public static readonly KeywordDescriptor ShapeLightType1 = new KeywordDescriptor() { displayName = "Shape Light Type 1", referenceName = "USE_SHAPE_LIGHT_TYPE_1", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, }; public static readonly KeywordDescriptor ShapeLightType2 = new KeywordDescriptor() { displayName = "Shape Light Type 2", referenceName = "USE_SHAPE_LIGHT_TYPE_2", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, }; public static readonly KeywordDescriptor ShapeLightType3 = new KeywordDescriptor() { displayName = "Shape Light Type 3", referenceName = "USE_SHAPE_LIGHT_TYPE_3", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, }; public static readonly KeywordDescriptor UseLegacySpriteBlocks = new KeywordDescriptor() { displayName = "UseLegacySpriteBlocks", referenceName = "USELEGACYSPRITEBLOCKS", type = KeywordType.Boolean, }; public static readonly KeywordDescriptor UseFragmentFog = new KeywordDescriptor() { displayName = "UseFragmentFog", referenceName = "_FOG_FRAGMENT", type = KeywordType.Boolean, }; public static readonly KeywordDescriptor GBufferNormalsOct = new KeywordDescriptor() { displayName = "GBuffer normal octahedron encoding", referenceName = "_GBUFFER_NORMALS_OCT", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, stages = KeywordShaderStage.Fragment, }; public static readonly KeywordDescriptor DBuffer = new KeywordDescriptor() { displayName = "Decals", referenceName = "", type = KeywordType.Enum, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, entries = new KeywordEntry[] { new KeywordEntry() { displayName = "Off", referenceName = "" }, new KeywordEntry() { displayName = "DBuffer Mrt1", referenceName = "DBUFFER_MRT1" }, new KeywordEntry() { displayName = "DBuffer Mrt2", referenceName = "DBUFFER_MRT2" }, new KeywordEntry() { displayName = "DBuffer Mrt3", referenceName = "DBUFFER_MRT3" }, }, stages = KeywordShaderStage.Fragment, }; public static readonly KeywordDescriptor DebugDisplay = new KeywordDescriptor() { displayName = "Debug Display", referenceName = "DEBUG_DISPLAY", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, stages = KeywordShaderStage.Fragment, }; public static readonly KeywordDescriptor SceneSelectionPass = new KeywordDescriptor() { displayName = "Scene Selection Pass", referenceName = "SCENESELECTIONPASS", type = KeywordType.Boolean, }; public static readonly KeywordDescriptor ScenePickingPass = new KeywordDescriptor() { displayName = "Scene Picking Pass", referenceName = "SCENEPICKINGPASS", type = KeywordType.Boolean, }; public static readonly KeywordDescriptor AlphaClipThreshold = new KeywordDescriptor() { displayName = "AlphaClipThreshold", referenceName = "ALPHA_CLIP_THRESHOLD", type = KeywordType.Boolean, definition = KeywordDefinition.Predefined, }; public static readonly KeywordDescriptor LightCookies = new KeywordDescriptor() { displayName = "Light Cookies", referenceName = "_LIGHT_COOKIES", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, stages = KeywordShaderStage.Fragment, }; public static readonly KeywordDescriptor ClusteredRendering = new KeywordDescriptor() { displayName = "Clustered Rendering", referenceName = "_CLUSTERED_RENDERING", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, }; public static readonly KeywordDescriptor EditorVisualization = new KeywordDescriptor() { displayName = "Editor Visualization", referenceName = "EDITOR_VISUALIZATION", type = KeywordType.Boolean, definition = KeywordDefinition.ShaderFeature, scope = KeywordScope.Global, }; } #endregion #region Keywords static class CoreKeywords { public static readonly KeywordCollection ShadowCaster = new KeywordCollection { { CoreKeywordDescriptors.CastingPunctualLightShadow }, }; } #endregion #region FieldDescriptors static class CoreFields { public static readonly FieldDescriptor UseLegacySpriteBlocks = new FieldDescriptor("Universal", "UseLegacySpriteBlocks", "UNIVERSAL_USELEGACYSPRITEBLOCKS"); } #endregion #region CustomInterpolators static class CoreCustomInterpDescriptors { public static readonly CustomInterpSubGen.Collection Common = new CustomInterpSubGen.Collection { // Custom interpolators are not explicitly defined in the SurfaceDescriptionInputs template. // This entry point will let us generate a block of pass-through assignments for each field. CustomInterpSubGen.Descriptor.MakeBlock(CustomInterpSubGen.Splice.k_spliceCopyToSDI, "output", "input"), // sgci_PassThroughFunc is called from BuildVaryings in Varyings.hlsl to copy custom interpolators from vertex descriptions. // this entry point allows for the function to be defined before it is used. CustomInterpSubGen.Descriptor.MakeFunc(CustomInterpSubGen.Splice.k_splicePreSurface, "CustomInterpolatorPassThroughFunc", "Varyings", "VertexDescription", "CUSTOMINTERPOLATOR_VARYPASSTHROUGH_FUNC", "FEATURES_GRAPH_VERTEX") }; } #endregion }