using System.Reflection; using UnityEngine; using UnityEditor.Graphing; using UnityEditor.ShaderGraph.Drawing.Controls; using UnityEditor.Rendering; using UnityEngine.Rendering.Universal; using System.Collections.Generic; namespace UnityEditor.ShaderGraph { /// /// ShaderGraph node for fetching scene depth using input attachments. /// This node reads depth directly from tile memory at the current fragment position. /// [SRPFilter(typeof(UniversalRenderPipeline))] [Title("Input", "Scene", "Fetch Scene Depth")] sealed class FetchSceneDepthNode : CodeFunctionNode, IMayRequireDepthTexture { const string kOutputSlotName = "Out"; public const int OutputSlotId = 0; [SerializeField] private DepthSamplingMode m_DepthSamplingMode = DepthSamplingMode.Linear01; [EnumControl("Sampling Mode")] public DepthSamplingMode depthSamplingMode { get { return m_DepthSamplingMode; } set { if (m_DepthSamplingMode == value) return; m_DepthSamplingMode = value; Dirty(ModificationScope.Graph); } } private static ShaderKeyword DepthAsInputAttachment; private static ShaderKeyword DepthAsInputAttachmentMSAA; public FetchSceneDepthNode() { name = "Fetch Scene Depth"; synonyms = new string[] { "input attachment", "framebuffer fetch", "tile memory" }; DepthAsInputAttachment = new ShaderKeyword() { displayName = "Depth As Input Attachment", keywordType = KeywordType.Enum, keywordDefinition = KeywordDefinition.MultiCompile, keywordScope = KeywordScope.Global, keywordStages = KeywordShaderStage.Fragment, entries = new List { new KeywordEntry() { displayName = "Off", referenceName = "" }, new KeywordEntry() { displayName = "Depth As Input Attachment", referenceName = "DEPTH_AS_INPUT_ATTACHMENT" }, new KeywordEntry() { displayName = "Depth As Input Attachment MSAA", referenceName = "DEPTH_AS_INPUT_ATTACHMENT_MSAA" }, }, }; UpdateNodeAfterDeserialization(); } public override bool hasPreview { get { return false; } } public override void CollectShaderKeywords(KeywordCollector keywords, GenerationMode generationMode) { base.CollectShaderKeywords(keywords, generationMode); // Add keywords requires by this node keywords.AddShaderKeyword(DepthAsInputAttachment); } protected override MethodInfo GetFunctionToConvert() { switch (m_DepthSamplingMode) { case DepthSamplingMode.Raw: return GetType().GetMethod("Unity_FetchSceneDepth_Raw", BindingFlags.Static | BindingFlags.NonPublic); case DepthSamplingMode.Eye: return GetType().GetMethod("Unity_FetchSceneDepth_Eye", BindingFlags.Static | BindingFlags.NonPublic); case DepthSamplingMode.Linear01: default: return GetType().GetMethod("Unity_FetchSceneDepth_Linear01", BindingFlags.Static | BindingFlags.NonPublic); } } static string Unity_FetchSceneDepth_Linear01( [Slot(0, Binding.ClipPosition, true, ShaderStageCapability.Fragment)] Vector4 clipPos, [Slot(1, Binding.None, ShaderStageCapability.Fragment)] out Vector1 Out) { return @" { #if defined(_DEPTH_AS_INPUT_ATTACHMENT) || defined(_DEPTH_AS_INPUT_ATTACHMENT_MSAA) // Fetch depth from tile memory using input attachment float rawDepth = shadergraph_LWFetchSceneDepth(clipPos.xy); Out = Linear01Depth(rawDepth, _ZBufferParams); #else // There is explicitly no fallback here. Out = 0; #endif } "; } static string Unity_FetchSceneDepth_Raw( [Slot(0, Binding.ClipPosition, true, ShaderStageCapability.Fragment)] Vector4 clipPos, [Slot(1, Binding.None, ShaderStageCapability.Fragment)] out Vector1 Out) { return @" { #if defined(_DEPTH_AS_INPUT_ATTACHMENT) || defined(_DEPTH_AS_INPUT_ATTACHMENT_MSAA) // Fetch raw depth from tile memory using input attachment Out = shadergraph_LWFetchSceneDepth(clipPos.xy); #else // There is explicitly no fallback here. Out = 0; #endif } "; } static string Unity_FetchSceneDepth_Eye( [Slot(0, Binding.ClipPosition, true, ShaderStageCapability.Fragment)] Vector4 clipPos, [Slot(1, Binding.None, ShaderStageCapability.Fragment)] out Vector1 Out) { return @" { #if defined(_DEPTH_AS_INPUT_ATTACHMENT) || defined(_DEPTH_AS_INPUT_ATTACHMENT_MSAA) // Fetch depth from tile memory using input attachment float rawDepth = shadergraph_LWFetchSceneDepth(clipPos.xy); { Out = LinearEyeDepth(rawDepth, _ZBufferParams); } #else { // There is explicitly no fallback here. Out = 0; } #endif } "; } public bool RequiresDepthTexture(ShaderStageCapability stageCapability) { return true; } public override void ValidateNode() { base.ValidateNode(); owner.AddValidationError(objectId, "Fetch Scene Depth uses input attachments to read depth directly from tile memory. " + "For texture-based depth sampling, use 'Sample Scene Depth' node instead.", Rendering.ShaderCompilerMessageSeverity.Warning); } } }