diff --git a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugState.cs b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugState.cs index 2e72da47421..c9dafbe881b 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugState.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugState.cs @@ -182,6 +182,35 @@ public sealed class DebugStateInt : DebugState { } [Serializable, DebugState(typeof(DebugUI.ObjectPopupField), typeof(DebugUI.CameraSelector), typeof(DebugUI.ObjectField))] public sealed class DebugStateObject : DebugState { + [SerializeField] string m_UserData; + + /// + public override void SetValue(object value, DebugUI.IValueField field) + { + // DebugStateObject is used to serialize the selected camera reference in DebugUI.CameraSelector. For SceneView Camera this doesn't work because + // the camera is never saved and always recreated. So we use a special string to identify this case and restore the reference later. + if (field is DebugUI.CameraSelector && SceneView.lastActiveSceneView != null && (Camera)value == SceneView.lastActiveSceneView.camera) + { + m_UserData = "SceneViewCamera"; + } + else + { + m_UserData = null; + } + base.SetValue(value, field); + } + + /// + public override object GetValue() + { + if (value == null && m_UserData != null && m_UserData == "SceneViewCamera" && SceneView.lastActiveSceneView != null && SceneView.lastActiveSceneView.camera != null) + { + value = SceneView.lastActiveSceneView.camera; + } + + return base.GetValue(); + } + /// /// Returns the hash code of the Debug Item. /// diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.LightTransport.cs b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.LightTransport.cs index 207d96af906..8a67dd9219e 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.LightTransport.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.LightTransport.cs @@ -94,7 +94,7 @@ class DefaultLightTransport : LightingBaker public override void Initialize(bool bakeProbeOcclusion, NativeArray probePositions) { - if (!InputExtraction.ExtractFromScene(out input)) + if (!InputExtraction.ExtractFromScene(out input, true)) { Debug.LogError("InputExtraction.ExtractFromScene failed."); return; diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.VirtualOffset.cs b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.VirtualOffset.cs index 29588cad039..aa6ac50f95b 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.VirtualOffset.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.VirtualOffset.cs @@ -109,7 +109,7 @@ public override void Initialize(ProbeVolumeBakingSet bakingSet, NativeArray !s.isDirty) || EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo()) { foreach (var scene in scenesToUnload) - EditorSceneManager.CloseScene(scene, false); + EditorSceneManager.CloseScene(scene, string.IsNullOrEmpty(scene.path)); // Remove the scene from the hierarchy iff it has never been saved. } break; } diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/VirtualOffset/TraceVirtualOffset.urtshader b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/VirtualOffset/TraceVirtualOffset.urtshader index f528bf94f5f..90e95a176ff 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/VirtualOffset/TraceVirtualOffset.urtshader +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/VirtualOffset/TraceVirtualOffset.urtshader @@ -87,21 +87,22 @@ void RayGenExecute(UnifiedRT::DispatchInfo dispatchInfo) if (!hit.IsValid() || hit.isFrontFace) { validHits++; - continue; } - - float distanceDiff = hit.hitDistance - minDist; - if (distanceDiff < DISTANCE_THRESHOLD) + else if (hit.IsValid()) { - UnifiedRT::HitGeomAttributes attributes = UnifiedRT::FetchHitGeomAttributes(hit, UnifiedRT::kGeomAttribFaceNormal); - float dotSurface = dot(ray.direction, attributes.faceNormal); - - // If new distance is smaller by at least kDistanceThreshold, or if ray is at least DOT_THRESHOLD more colinear with normal - if (distanceDiff < -DISTANCE_THRESHOLD || dotSurface - maxDotSurface > DOT_THRESHOLD) + float distanceDiff = hit.hitDistance - minDist; + if (distanceDiff < DISTANCE_THRESHOLD) { - outDirection = ray.direction; - maxDotSurface = dotSurface; - minDist = hit.hitDistance; + UnifiedRT::HitGeomAttributes attributes = UnifiedRT::FetchHitGeomAttributes(hit, UnifiedRT::kGeomAttribFaceNormal); + float dotSurface = dot(ray.direction, attributes.faceNormal); + + // If new distance is smaller by at least kDistanceThreshold, or if ray is at least DOT_THRESHOLD more colinear with normal + if (distanceDiff < -DISTANCE_THRESHOLD || dotSurface - maxDotSurface > DOT_THRESHOLD) + { + outDirection = ray.direction; + maxDotSurface = dotSurface; + minDist = hit.hitDistance; + } } } } diff --git a/Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphTestsCore.cs b/Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphTestsCore.cs index 9602d17ebc2..a511caadf8b 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphTestsCore.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphTestsCore.cs @@ -187,7 +187,7 @@ public void CleanupRenderGraph() m_RenderGraphTestPipeline.invalidContextForTesting = false; // Cleaning all Render Graph resources and data structures // Nothing remains, Render Graph in next test will start from scratch - m_RenderGraph.ForceCleanup(); + m_RenderGraph.CleanupResourcesAndGraph(); } } } diff --git a/Packages/com.unity.render-pipelines.core/Editor/Upscaling.meta b/Packages/com.unity.render-pipelines.core/Editor/Upscaling.meta new file mode 100644 index 00000000000..ba73323abaa --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/Upscaling.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dfe03cc61c27c974ab28f8691b3f8c0f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.render-pipelines.core/Editor/Upscaling/DLSSOptionsEditor.cs b/Packages/com.unity.render-pipelines.core/Editor/Upscaling/DLSSOptionsEditor.cs new file mode 100644 index 00000000000..aac3f477f0b --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/Upscaling/DLSSOptionsEditor.cs @@ -0,0 +1,167 @@ +#if UNITY_EDITOR +#if ENABLE_UPSCALER_FRAMEWORK && ENABLE_NVIDIA && ENABLE_NVIDIA_MODULE +using UnityEditor; +using UnityEngine; +using UnityEngine.NVIDIA; + +[CustomEditor(typeof(DLSSOptions))] +public class DLSSOptionsEditor : Editor +{ + // Declare variables to hold each property + private SerializedProperty m_QualityMode; + private SerializedProperty m_FixedResolution; + private SerializedProperty m_PresetQuality; + private SerializedProperty m_PresetBalanced; + private SerializedProperty m_PresetPerformance; + private SerializedProperty m_PresetUltraPerformance; + private SerializedProperty m_PresetDLAA; + private void OnEnable() + { + // Find each property by its exact field name in DLSSOptions.cs + m_QualityMode = serializedObject.FindProperty("DLSSQualityMode"); + m_FixedResolution = serializedObject.FindProperty("FixedResolutionMode"); + m_PresetQuality = serializedObject.FindProperty("DLSSRenderPresetQuality"); + m_PresetBalanced = serializedObject.FindProperty("DLSSRenderPresetBalanced"); + m_PresetPerformance = serializedObject.FindProperty("DLSSRenderPresetPerformance"); + m_PresetUltraPerformance = serializedObject.FindProperty("DLSSRenderPresetUltraPerformance"); + m_PresetDLAA = serializedObject.FindProperty("DLSSRenderPresetDLAA"); + } + + #region STYLES + private static readonly string[] DLSSPerfQualityLabels = + { // should follow enum value ordering in DLSSQuality enum + DLSSQuality.MaximumPerformance.ToString(), + DLSSQuality.Balanced.ToString(), + DLSSQuality.MaximumQuality.ToString(), + DLSSQuality.UltraPerformance.ToString(), + DLSSQuality.DLAA.ToString() + }; + private static string[][] DLSSPresetOptionsForEachPerfQuality = PopulateDLSSQualityPresetLabels(); + private static string[][] PopulateDLSSQualityPresetLabels() + { + int CountBits(uint bitMask) // System.Numerics.BitOperations not available + { + int count = 0; + while (bitMask > 0) + { + count += (bitMask & 1) > 0 ? 1 : 0; + bitMask >>= 1; + } + return count; + } + + System.Array perfQualities = System.Enum.GetValues(typeof(DLSSQuality)); + string[][] labels = new string[perfQualities.Length][]; + foreach (DLSSQuality quality in perfQualities) + { + uint presetBitmask = GraphicsDevice.GetAvailableDLSSPresetsForQuality(quality); + int numPresets = CountBits(presetBitmask) + 1; // +1 for default option which is available to all quality enums + labels[(int)quality] = new string[numPresets]; + + int iWrite = 0; + System.Array presets = System.Enum.GetValues(typeof(DLSSPreset)); + foreach (DLSSPreset preset in presets) + { + if (preset == DLSSPreset.Preset_Default) + { + labels[(int)quality][iWrite++] = "Default Preset"; + continue; + } + + if ((presetBitmask & (uint)preset) != 0) + { + string presetName = preset.ToString().Replace('_', ' '); + labels[(int)quality][iWrite++] = presetName + " - " + GraphicsDevice.GetDLSSPresetExplanation(preset); + } + } + } + return labels; + } + + private static readonly GUIContent renderPresetsLabel = new GUIContent("Render Presets", "Selects an internal DLSS tuning profile. Presets adjust reconstruction behavior, trading off between sharpness, stability, and performance. Different presets may work better depending on scene content and motion."); + #endregion + + + // DLSSOptions contain DLSS presets for each quality mode. + // The presets available for each quality mode may be different from one another and change over time between DLSS releases. + // E.g. DLAAPreset = { F, J, K } + // BalancedPreset = { J, K } + // Instead of letting Unity default-render the GUI, we write our own inspector logic to enforce the preset value requirements. + void DrawPresetDropdown(ref SerializedProperty presetProp, DLSSQuality perfQuality) + { + // each DLSSQuality has a different set of DLSSPresets, represented by a bitmask. + uint presetBitmask = GraphicsDevice.GetAvailableDLSSPresetsForQuality(perfQuality); + bool propHasInvalidPresetValue = presetProp.uintValue != 0 && (presetBitmask & presetProp.uintValue) == 0; + if (propHasInvalidPresetValue) + { + Debug.LogWarningFormat("DLSS Preset {0} not found for quality setting {1}, resetting to default value.", + ((DLSSPreset)presetProp.uintValue).ToString(), + perfQuality.ToString() + ); + presetProp.uintValue = 0; + } + + // We don't want to deal with List & using bitmasks, + // so we need some bit ops to convert between GUI index <--> Preset value + int FindPresetGUIIndex(uint presetBitmask, uint presetValue) + { + int i = 0; + while (presetValue > 0) + { + i += (presetBitmask & 1) > 0 ? 1 : 0; + presetBitmask >>= 1; + presetValue >>= 1; + } + return i; // includes 0=default, goes like 1=preset_A, 2=preset_B ... + } + uint GUIIndexToPresetValue(uint presetBitmask, uint index) + { + // e.g. bitset: 100101 --> 3 bits set, supports 4 presets (0=default, +3 other presets). + // ^ i = 1 -> Preset A = 1 + // ^ i = 2 -> Preset C = 4 + // ^ i = 3 -> Preset F = 32 + uint val = 0; + while (index > 0 && presetBitmask > 0) + { + if ((presetBitmask & 1) != 0) + --index; + presetBitmask >>= 1; + val = val == 0 ? 1 : (val << 1); + } + if (index != 0) + { + Debug.LogWarningFormat("DLSSPreset (index={0}) not found in the supported preset list (mask={1}), setting to default value.", index, presetBitmask); + return 0; + } + // Debug.LogFormat("Setting preset {0} : {1}", ((DLSSPreset)val).ToString(), val); + return val; + } + + int presetIndex = FindPresetGUIIndex(presetBitmask, presetProp.uintValue); + int iNew = EditorGUILayout.Popup(DLSSPerfQualityLabels[(int)perfQuality], presetIndex, DLSSPresetOptionsForEachPerfQuality[(int)perfQuality]); + if (iNew != presetIndex) + presetProp.uintValue = GUIIndexToPresetValue(presetBitmask, (uint)iNew); + } + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.PropertyField(m_QualityMode); + EditorGUILayout.PropertyField(m_FixedResolution); + + EditorGUILayout.LabelField(renderPresetsLabel, EditorStyles.boldLabel); + ++EditorGUI.indentLevel; + + DrawPresetDropdown(ref m_PresetQuality, DLSSQuality.MaximumQuality); + DrawPresetDropdown(ref m_PresetBalanced, DLSSQuality.Balanced); + DrawPresetDropdown(ref m_PresetPerformance, DLSSQuality.MaximumPerformance); + DrawPresetDropdown(ref m_PresetUltraPerformance, DLSSQuality.UltraPerformance); + DrawPresetDropdown(ref m_PresetDLAA, DLSSQuality.DLAA); + + --EditorGUI.indentLevel; + + serializedObject.ApplyModifiedProperties(); + } +} +#endif +#endif diff --git a/Packages/com.unity.render-pipelines.core/Editor/Upscaling/DLSSOptionsEditor.cs.meta b/Packages/com.unity.render-pipelines.core/Editor/Upscaling/DLSSOptionsEditor.cs.meta new file mode 100644 index 00000000000..a6c2860babc --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/Upscaling/DLSSOptionsEditor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3d45844b7594ca649b150d24562f5429 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Editor/Upscaling/UpscalerOptionsEditor.cs b/Packages/com.unity.render-pipelines.core/Editor/Upscaling/UpscalerOptionsEditor.cs new file mode 100644 index 00000000000..df858ac9e4c --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/Upscaling/UpscalerOptionsEditor.cs @@ -0,0 +1,20 @@ +#if ENABLE_UPSCALER_FRAMEWORK +#if UNITY_EDITOR +using UnityEditor; + +/// +/// This custom editor ensures that when drawing any UpscalerOptions object, +/// the default "Script" field is not shown. Applies to all derived options. +/// +[CustomEditor(typeof(UnityEngine.Rendering.UpscalerOptions), true)] +public class UpscalerOptionsEditor : Editor +{ + public override void OnInspectorGUI() + { + // DrawDefaultInspector renders all serialized fields except for the "Script" field + // and any fields marked with [HideInInspector]. + DrawDefaultInspector(); + } +} +#endif +#endif diff --git a/Packages/com.unity.render-pipelines.core/Editor/Upscaling/UpscalerOptionsEditor.cs.meta b/Packages/com.unity.render-pipelines.core/Editor/Upscaling/UpscalerOptionsEditor.cs.meta new file mode 100644 index 00000000000..9ae0ab7a6b1 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/Upscaling/UpscalerOptionsEditor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b9e58b38929a83b4aa0fd7b0d0144014 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Editor/Upscaling/UpscalerOptionsEditorCache.cs b/Packages/com.unity.render-pipelines.core/Editor/Upscaling/UpscalerOptionsEditorCache.cs new file mode 100644 index 00000000000..85bef5d585c --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/Upscaling/UpscalerOptionsEditorCache.cs @@ -0,0 +1,52 @@ +#if ENABLE_UPSCALER_FRAMEWORK +#if UNITY_EDITOR +using System.Collections.Generic; +using UnityEditor; + +namespace UnityEngine.Rendering +{ +#nullable enable + /// + /// Manages the lifecycle of cached editors for UpscalerOptions ScriptableObjects. + /// + public class UpscalerOptionsEditorCache + { + private readonly Dictionary m_EditorCache = new Dictionary(); + + /// + /// Gets a cached editor for the given @options. If the editor is not + /// found in the cache, a new editor is created and then cached. + /// + public Editor? GetOrCreateEditor(ScriptableObject options) + { + if (options == null) + return null; + + if (!m_EditorCache.TryGetValue(options, out var editor) || editor == null) + { + editor = Editor.CreateEditor(options); + m_EditorCache[options] = editor; + } + + return editor; + } + + /// + /// Destroys all cached editor instances. + /// Call this from the parent editor's OnDisable method. + /// + public void Cleanup() + { + foreach (var editor in m_EditorCache.Values) + { + if (editor != null) + Object.DestroyImmediate(editor); + } + m_EditorCache.Clear(); + } + } + +#nullable disable +} +#endif +#endif // ENABLE_UPSCALER_FRAMEWORK diff --git a/Packages/com.unity.render-pipelines.core/Editor/Upscaling/UpscalerOptionsEditorCache.cs.meta b/Packages/com.unity.render-pipelines.core/Editor/Upscaling/UpscalerOptionsEditorCache.cs.meta new file mode 100644 index 00000000000..14580aa456a --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/Upscaling/UpscalerOptionsEditorCache.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b35dd4b6f122695459036b125fcb7b48 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeComponentListEditor.cs b/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeComponentListEditor.cs index bc12819098b..debabea11a7 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeComponentListEditor.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeComponentListEditor.cs @@ -202,7 +202,8 @@ void RefreshEditors() // Recreate editors for existing settings, if any var components = asset.components; for (int i = 0; i < components.Count; i++) - CreateEditor(components[i], m_ComponentsProperty.GetArrayElementAtIndex(i)); + if (components[i] != null) //can happens if a component type is removed and opening old serialized data + CreateEditor(components[i], m_ComponentsProperty.GetArrayElementAtIndex(i)); m_CurrentHashCode = asset.GetComponentListHashCode(); diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettingsVolumes.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettingsVolumes.cs index b3721d1c4dc..a176848d3dc 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettingsVolumes.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettingsVolumes.cs @@ -59,23 +59,10 @@ public Type selectedComponentType /// Current camera to debug. public Camera selectedCamera { - get - { -#if UNITY_EDITOR - // By default pick the one scene camera - if (m_SelectedCamera == null && SceneView.lastActiveSceneView != null) - { - var sceneCamera = SceneView.lastActiveSceneView.camera; - if (sceneCamera != null) - m_SelectedCamera = sceneCamera; - } -#endif - - return m_SelectedCamera; - } + get => m_SelectedCamera; set { - if (value != null && value != m_SelectedCamera) + if (value != m_SelectedCamera) { m_SelectedCamera = value; OnSelectionChanged(); @@ -333,7 +320,7 @@ public static DebugUI.EnumField CreateComponentSelector(SettingsPanel panel, Act }; } - public static DebugUI.ObjectPopupField CreateCameraSelector(SettingsPanel panel, Action, Object> refresh) + public static DebugUI.CameraSelector CreateCameraSelector(SettingsPanel panel, Action, Object> refresh) { return new DebugUI.CameraSelector() { @@ -708,7 +695,14 @@ public override void Dispose() public SettingsPanel(DebugDisplaySettingsVolume data) : base(data) { - AddWidget(WidgetFactory.CreateCameraSelector(this, (_, __) => Refresh())); + var cameraSelector = WidgetFactory.CreateCameraSelector(this, (_, __) => Refresh()); + + // Select first camera if none is selected + var availableCameras = cameraSelector.getObjects() as List; + if (data.selectedCamera == null && availableCameras is { Count: > 0 }) + data.selectedCamera = availableCameras[0]; + + AddWidget(cameraSelector); AddWidget(WidgetFactory.CreateComponentSelector(this, (_, __) => Refresh())); Func hiddenCallback = () => data.selectedCamera == null || data.selectedComponent <= 0; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/CompilerContextData.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/CompilerContextData.cs index d408644c86c..0a008a7005b 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/CompilerContextData.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/CompilerContextData.cs @@ -180,8 +180,8 @@ public bool TryAddToFragmentList(TextureAccess access, int listFirstIndex, int n } } - // Validate that we're correctly building up the fragment lists we can only append to the last list - // not int the middle of lists + // Validate that we're correctly building up the fragment lists, we can only append to the last list + // not in the middle of the other lists Debug.Assert(listFirstIndex + numItems == fragmentData.Length); fragmentData.Add(new PassFragmentData( diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/NativePassCompiler.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/NativePassCompiler.cs index e9d827c25be..9cb98202609 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/NativePassCompiler.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/NativePassCompiler.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; -using UnityEngine.Rendering; namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler { @@ -23,7 +22,8 @@ internal struct RenderGraphInputInfo internal CompilerContextData contextData = null; internal CompilerContextData defaultContextData; internal CommandBuffer previousCommandBuffer; - Stack toVisitPassIds; + Stack m_HasSideEffectPassIdCullingStack; + List> m_UnusedVersionedResourceIdCullingStacks; RenderGraphCompilationCache m_CompilationCache; @@ -40,7 +40,11 @@ public NativePassCompiler(RenderGraphCompilationCache cache) { m_CompilationCache = cache; defaultContextData = new CompilerContextData(); - toVisitPassIds = new Stack(k_EstimatedPassCount); + m_HasSideEffectPassIdCullingStack = new Stack(k_EstimatedPassCount); + + m_UnusedVersionedResourceIdCullingStacks = new List>(); + for (int type = 0; type < (int)RenderGraphResourceType.Count; ++type) + m_UnusedVersionedResourceIdCullingStacks.Add(new Stack()); m_TempMRTArrays = new RenderTargetIdentifier[RenderGraph.kMaxMRTCount][]; for (int i = 0; i < RenderGraph.kMaxMRTCount; ++i) @@ -132,7 +136,7 @@ public void Compile(RenderGraphResourceRegistry resources) BuildGraph(); - CullUnusedRenderPasses(); + CullUnusedRenderGraphPasses(); TryMergeNativePasses(); @@ -152,7 +156,11 @@ public void Clear(bool clearContextData) { if (clearContextData) contextData.Clear(); - toVisitPassIds.Clear(); + + m_HasSideEffectPassIdCullingStack.Clear(); + + for (int type = 0; type < (int)RenderGraphResourceType.Count; ++type) + m_UnusedVersionedResourceIdCullingStacks[type].Clear(); } void SetPassStatesForNativePass(int nativePassId) @@ -247,16 +255,18 @@ bool TrySetupRasterFragmentList(ref PassData ctxPass, ref RenderGraphPass inputP } } - // shading rate - if (inputPass.hasShadingRateImage && - inputPass.shadingRateAccess.textureHandle.handle.IsValid()) + // shading rate image - this is a specific type of attachment (more of an image resource that can't be sampled, only used by the rasterizer) + if (inputPass.hasShadingRateImage && inputPass.shadingRateAccess.textureHandle.handle.IsValid()) { - ctxPass.shadingRateImageIndex = ctx.fragmentData.Length; - ctx.TryAddToFragmentList(inputPass.shadingRateAccess, ctxPass.shadingRateImageIndex, 0, out errorMessage); + if (ctx.TryAddToFragmentList(inputPass.shadingRateAccess, ctxPass.firstFragment, ctxPass.numFragments, out errorMessage)) + { + ctxPass.shadingRateImageIndex = ctx.fragmentData.Length - 1; + } if (errorMessage != null) { - errorMessage = $"when trying to add VRS attachment of type {inputPass.shadingRateAccess.textureHandle.handle.type} at index {inputPass.shadingRateAccess.textureHandle.handle.index} - {errorMessage}"; + errorMessage = + $"when trying to add VRS attachment of type {inputPass.shadingRateAccess.textureHandle.handle.type} at index {inputPass.shadingRateAccess.textureHandle.handle.index} - {errorMessage}"; return false; } } @@ -269,9 +279,7 @@ bool TrySetupRasterFragmentList(ref PassData ctxPass, ref RenderGraphPass inputP // Skip unused fragment input slots if (!inputPass.fragmentInputAccess[ci].textureHandle.IsValid()) continue; - var resource = inputPass.fragmentInputAccess[ci].textureHandle; - if (ctx.TryAddToFragmentList(inputPass.fragmentInputAccess[ci], ctxPass.firstFragmentInput, - ctxPass.numFragmentInputs, out errorMessage)) + if (ctx.TryAddToFragmentList(inputPass.fragmentInputAccess[ci], ctxPass.firstFragmentInput, ctxPass.numFragmentInputs, out errorMessage)) { ctxPass.TryAddFragmentInput(inputPass.fragmentInputAccess[ci].textureHandle.handle, ctx, out errorMessage); } @@ -294,8 +302,7 @@ bool TrySetupRasterFragmentList(ref PassData ctxPass, ref RenderGraphPass inputP // Skip unused random write slots if (!uav.h.IsValid()) continue; - if (ctx.TryAddToRandomAccessResourceList(uav.h, ci, uav.preserveCounterValue, - ctxPass.firstRandomAccessResource, ctxPass.numRandomAccessResources, out errorMessage)) + if (ctx.TryAddToRandomAccessResourceList(uav.h, ci, uav.preserveCounterValue, ctxPass.firstRandomAccessResource, ctxPass.numRandomAccessResources, out errorMessage)) { ctxPass.AddRandomAccessResource(); } @@ -350,7 +357,7 @@ void BuildGraph() if (ctxPass.hasSideEffects) { - toVisitPassIds.Push(passId); + m_HasSideEffectPassIdCullingStack.Push(passId); } // Set up the list of fragment attachments for this pass @@ -382,7 +389,7 @@ void BuildGraph() if (!ctxPass.hasSideEffects) { ctxPass.hasSideEffects = true; - toVisitPassIds.Push(passId); + m_HasSideEffectPassIdCullingStack.Push(passId); } } @@ -434,28 +441,26 @@ void BuildGraph() } } - void CullUnusedRenderPasses() + void CullUnusedRenderGraphPasses() { - var ctx = contextData; - - // Source = input of the graph and starting point that takes no inputs itself : e.g. z-prepass - // Sink = output of the graph and end point e.g. rendered frame - // Usually sinks will have to be pinned or write to an external resource or the whole graph would get culled :-) - using (new ProfilingScope(ProfilingSampler.Get(NativeCompilerProfileId.NRPRGComp_CullNodes))) { - // No need to go further if we don't enable culling if (graph.disablePassCulling) return; + // Must come first + // TODO make another subfunction CullRenderGraphPassesWithNoSideEffect() for this first step of the culling stage + var ctx = contextData; + // Cull all passes first ctx.CullAllPasses(true); // Flood fill downstream algorithm using BFS, - // starting from the pinned nodes to all their dependencies - while (toVisitPassIds.Count != 0) + // starting from the passes with side effects (writting to imported texture, not allowed to be culled, globals modification...) + // to all their dependencies + while (m_HasSideEffectPassIdCullingStack.Count != 0) { - int passId = toVisitPassIds.Pop(); + int passId = m_HasSideEffectPassIdCullingStack.Pop(); ref var passData = ref ctx.passData.ElementAt(passId); @@ -465,8 +470,12 @@ void CullUnusedRenderPasses() // Flow upstream from this node foreach (ref readonly var input in passData.Inputs(ctx)) { - int inputPassIndex = ctx.resources[input.resource].writePassId; - toVisitPassIds.Push(inputPassIndex); + ref var inputVersionedDataRes = ref ctx.resources[input.resource]; + + if (inputVersionedDataRes.written) + { + m_HasSideEffectPassIdCullingStack.Push(inputVersionedDataRes.writePassId); + } } // We need this node, don't cull it @@ -483,23 +492,90 @@ void CullUnusedRenderPasses() // Remove the connections from the list so they won't be visited again if (pass.culled) { - // If the culled pass was supposed to generate the latest version of a given resource, - // we need to decrement the latestVersionNumber of this resource - // because its last version will never be created due to its producer being culled - foreach (ref readonly var output in pass.Outputs(ctx)) - { - var outputResource = output.resource; - bool isOutputLastVersion = (outputResource.version == ctx.UnversionedResourceData(outputResource).latestVersionNumber); + pass.DisconnectFromResources(ctx); + } + } - if (isOutputLastVersion) - ctx.UnversionedResourceData(outputResource).latestVersionNumber--; - } + // Second step of the algorithm, must come after + // TODO: The resources culling step is currently disabled due to an issue: https://jira.unity3d.com/projects/SRP/issues/SRP-897 + // Renabled the resource culling step after addressing the depth attachment problem above. + // Renabled the relevent tests + // CullRenderGraphPassesWritingOnlyUnusedResources(); + } + } + + void CullRenderGraphPassesWritingOnlyUnusedResources() + { + var ctx = contextData; + + var numPasses = ctx.passData.Length; + for (int passIndex = 0; passIndex < numPasses; passIndex++) + { + ref var passData = ref ctx.passData.ElementAt(passIndex); + + // Use the generic tag to monitor the number of written resources that are used + passData.tag = passData.numOutputs; + + // Find all resources that are written by a pass but not read at all and add them to the stacks + foreach (ref readonly var output in passData.Outputs(ctx)) + { + ref readonly var outputResource = ref output.resource; + ref var outputVersionedDataRes = ref ctx.resources[outputResource]; - // Notifying the versioned resources that this pass is no longer reading them - foreach (ref readonly var input in pass.Inputs(ctx)) + if (outputVersionedDataRes.numReaders == 0) + m_UnusedVersionedResourceIdCullingStacks[outputResource.iType].Push(outputResource); + } + } + + // Go through each stack of unused resources and try to cull their producer + for (int type = 0; type < (int)RenderGraphResourceType.Count; ++type) + { + var unusedVersionedResourceIdCullingStack = m_UnusedVersionedResourceIdCullingStacks[type]; + + // Goal is to find the producers of the unused resources and culled them if they only write to unused resources + while (unusedVersionedResourceIdCullingStack.Count != 0) + { + var unusedResource = unusedVersionedResourceIdCullingStack.Pop(); + + ref var unusedUnversionedDataRes = ref ctx.resources.unversionedData[type].ElementAt(unusedResource.index); + if (unusedUnversionedDataRes.isImported) continue; // Not always unused as someone can read it outside the graph + + ref var unusedVersionedDataRes = ref ctx.resources[unusedResource]; + ref var producerData = ref ctx.passData.ElementAt(unusedVersionedDataRes.writePassId); + if (producerData.culled) continue; // Producer has been culled already + + // Decrement the number of written resources that are used for this pass + producerData.tag--; + + Debug.Assert(producerData.tag >= 0); + + // Producer is not necessary anymore, as it only writes to unused resources and has no side effects + if (producerData.tag == 0 && !producerData.hasSideEffects) + { + producerData.culled = true; + producerData.DisconnectFromResources(ctx, unusedVersionedResourceIdCullingStack, type); + } + else // Producer is (still) necessary, but we might need to remove the read of the previous version coming implicitly with the write of the current version + { + // We always add written resource to the stack so versionedIndex > 0 + var prevVersionedRes = new ResourceHandle(unusedResource, unusedResource.version - 1); + + // If no explicit read is requested by the user (AccessFlag.Write only), we need to remove the implicit read + // so that we cut cleanly the connection between previous version of the resource and current producer + bool isImplicitRead = graph.m_RenderPasses[producerData.passId].implicitReadsList.Contains(prevVersionedRes); + + if (isImplicitRead) { - var inputResource = input.resource; - ctx.resources[inputResource].RemoveReadingPass(ctx, inputResource, pass.passId); + ref var prevVersionedDataRes = ref ctx.resources[prevVersionedRes]; + + // Notify the previous version of this resource that it is not read anymore by this pass + prevVersionedDataRes.RemoveReadingPass(ctx, prevVersionedRes, producerData.passId); + + // We also need to add the previous version of the resource to the stack IF no other pass than current producer needed it + if (prevVersionedDataRes.written && prevVersionedDataRes.numReaders == 0) + { + unusedVersionedResourceIdCullingStack.Push(prevVersionedRes); + } } } } @@ -625,18 +701,15 @@ void FindResourceUsageRanges() ref var pointTo = ref ctx.UnversionedResourceData(inputResource); pointTo.lastUsePassID = -1; - // If we use version 0 and nobody else is using it yet, + // If nobody else is using it yet, // mark this pass as the first using the resource. // It can happen that two passes use v0, e.g.: // pass1.UseTex(v0,Read) -> this will clear the pass but keep it at v0 // pass2.UseTex(v0,Read) -> "reads" v0 - if (inputResource.version == 0) + if (pointTo.firstUsePassID < 0) { - if (pointTo.firstUsePassID < 0) - { - pointTo.firstUsePassID = pass.passId; - pass.AddFirstUse(inputResource, ctx); - } + pointTo.firstUsePassID = pass.passId; + pass.AddFirstUse(inputResource, ctx); } // This pass uses the last version of a resource increase the ref count of this resource @@ -654,18 +727,16 @@ void FindResourceUsageRanges() { var outputResource = output.resource; ref var pointTo = ref ctx.UnversionedResourceData(outputResource); - if (outputResource.version == 1) + + // If nobody else is using it yet (no explicit read), + // Mark this pass as the first using the resource. + // It can happen that two passes use v0, e.g.: + // pass1.UseTex(v0, Write) -> implicit read of v0, writes v1 - culled because none explicitly reads v1 + // pass3.UseTex(v1, Write) -> implicit read of v1, writes v2 - not culled because of unrelated reason + if (pointTo.firstUsePassID < 0) { - // If we use version 0 and nobody else is using it yet, - // Mark this pass as the first using the resource. - // It can happen that two passes use v0, e.g.: - // pass1.UseTex(v0,Read) -> this will clear the pass but keep it at v0 - // pass3.UseTex(v0,Read/Write) -> wites v0, brings it to v1 from here on - if (pointTo.firstUsePassID < 0) - { - pointTo.firstUsePassID = pass.passId; - pass.AddFirstUse(outputResource, ctx); - } + pointTo.firstUsePassID = pass.passId; + pass.AddFirstUse(outputResource, ctx); } // This pass outputs the last version of a resource track that diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/PassesData.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/PassesData.cs index 7859f019546..2b68c16b3f9 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/PassesData.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/PassesData.cs @@ -5,6 +5,7 @@ using UnityEngine.Rendering; using System.Collections.Generic; using Unity.Collections; +using UnityEngine.Experimental.Rendering; namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler { @@ -262,14 +263,17 @@ public readonly ReadOnlySpan Outputs(CompilerContextData ctx) public readonly ReadOnlySpan Inputs(CompilerContextData ctx) => ctx.inputData.MakeReadOnlySpan(firstInput, numInputs); + // RenderAttachments - MRT colors and depth [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly ReadOnlySpan Fragments(CompilerContextData ctx) => ctx.fragmentData.MakeReadOnlySpan(firstFragment, numFragments); + // ShadingRateImageAttachment [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly PassFragmentData ShadingRateImage(CompilerContextData ctx) => ctx.fragmentData[shadingRateImageIndex]; + // RenderInputAttachments [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly ReadOnlySpan FragmentInputs(CompilerContextData ctx) => ctx.fragmentData.MakeReadOnlySpan(firstFragmentInput, numFragmentInputs); @@ -442,6 +446,35 @@ internal readonly bool IsUsedAsFragment(ResourceHandle h, CompilerContextData ct return false; } + + internal void DisconnectFromResources(CompilerContextData ctx, Stack unusedVersionedResourceIdCullingStack = null, int type = 0) + { + // If the culled pass was supposed to generate the latest version of a given resource, + // we need to decrement the latestVersionNumber of this resource + // because its last version will never be created due to its producer being culled + foreach (ref readonly var output in Outputs(ctx)) + { + ref readonly var outputResource = ref output.resource; + bool isOutputLastVersion = (outputResource.version == ctx.UnversionedResourceData(outputResource).latestVersionNumber); + + if (isOutputLastVersion) + ctx.UnversionedResourceData(outputResource).latestVersionNumber--; + } + + // Notifying the versioned resources that this pass is no longer reading them + foreach (ref readonly var input in Inputs(ctx)) + { + ref readonly var inputResource = ref input.resource; + ref var inputVersionedDataResource = ref ctx.resources[inputResource]; + inputVersionedDataResource.RemoveReadingPass(ctx, inputResource, passId); + + // If a resource of the same type is not used anymore, adding it to the stack + if (unusedVersionedResourceIdCullingStack != null && inputResource.iType == type && inputVersionedDataResource.written && inputVersionedDataResource.numReaders == 0) + { + unusedVersionedResourceIdCullingStack.Push(inputResource); + } + } + } } // Data per attachment of a native renderpass @@ -881,11 +914,15 @@ public static PassBreakAudit CanMerge(CompilerContextData contextData, int activ foreach (ref readonly var input in passToMerge.Inputs(contextData)) { var inputResource = input.resource; - var writingPassId = contextData.resources[inputResource].writePassId; - // Is the writing pass enclosed in the current native renderpass - if (writingPassId >= nativePass.firstGraphPass && writingPassId < nativePass.lastGraphPass + 1) + + ref readonly var inputDataVersioned = ref contextData.VersionedResourceData(inputResource); + + bool isWrittenInCurrNativePass = inputDataVersioned.written && (inputDataVersioned.writePassId >= nativePass.firstGraphPass && inputDataVersioned.writePassId < nativePass.lastGraphPass + 1); + + if (isWrittenInCurrNativePass) { - // If it's not used as a fragment, it's used as some sort of texture read of load so we need so sync it out + // If it's not used as a fragment, it's used as some sort of texture read or load so we need to break the current native render pass + // as we can't sample and write to it in the same native render pass if (!passToMerge.IsUsedAsFragment(inputResource, contextData)) { return new PassBreakAudit(PassBreakReason.NextPassReadsTexture, passIdToMerge); @@ -893,7 +930,6 @@ public static PassBreakAudit CanMerge(CompilerContextData contextData, int activ } } - // Gather which attachments to add to the current renderpass var attachmentsToTryAdding = new FixedAttachmentArray(); @@ -929,7 +965,7 @@ public static PassBreakAudit CanMerge(CompilerContextData contextData, int activ } } - // Check if this fragment is already sampled in the native renderpass not as a fragment but as an input + // Check if this fragment is already sampled in the native renderpass as a standard texture for (int i = nativePass.firstGraphPass; i <= nativePass.lastGraphPass; ++i) { ref var earlierPassData = ref contextData.passData.ElementAt(i); @@ -948,7 +984,6 @@ public static PassBreakAudit CanMerge(CompilerContextData contextData, int activ } } - foreach (ref readonly var fragmentInput in passToMerge.FragmentInputs(contextData)) { bool alreadyAttached = false; @@ -979,6 +1014,12 @@ public static PassBreakAudit CanMerge(CompilerContextData contextData, int activ } } + // Determines if the pixel storage limit is reached after adding the new 'pass to merge' attachments to the current native render pass. + if (TotalAttachmentsSizeExceedPixelStorageLimit(contextData, ref nativePass, ref attachmentsToTryAdding)) + { + return new PassBreakAudit(PassBreakReason.AttachmentLimitReached, passIdToMerge); + } + // We check first if we are at risk of having too many subpasses, // only then we do the costlier subpass merging check, short circuiting it whenever possible bool canAddAnExtraSubpass = (nativePass.numGraphPasses < NativePassCompiler.k_MaxSubpass); @@ -991,6 +1032,34 @@ public static PassBreakAudit CanMerge(CompilerContextData contextData, int activ return new PassBreakAudit(PassBreakReason.Merged, passIdToMerge); } + static bool TotalAttachmentsSizeExceedPixelStorageLimit(CompilerContextData contextData, ref NativePassData nativePass, ref FixedAttachmentArray attachmentsToTryAdding) + { + // TODO: We are currently only checking for iOS GPU Family 1 to 3 since the storage size is much more restricted (16 bytes for Family 1 and 32 for Family 2 & 3). + // This is temporary. Later on, we should check all iOS GPU Families but also Android (Vulkan) to avoid the same potential restrictions. + if (Application.platform == RuntimePlatform.IPhonePlayer && SystemInfo.maxTiledPixelStorageSize <= 32) + { + int totalSize = 0; + + // Iterate over current attachments + for (int i = 0; i < nativePass.fragments.size; ++i) + { + ref readonly var unvResource = ref contextData.UnversionedResourceData(nativePass.fragments[i].resource); + totalSize += SystemInfo.GetTiledRenderTargetStorageSize(unvResource.graphicsFormat, unvResource.msaaSamples); + } + + // Iterate over new attachments to add + for (int i = 0; i < attachmentsToTryAdding.size; ++i) + { + ref readonly var unvResource = ref contextData.UnversionedResourceData(attachmentsToTryAdding[i].resource); + totalSize += SystemInfo.GetTiledRenderTargetStorageSize(unvResource.graphicsFormat, unvResource.msaaSamples); + } + + return totalSize > SystemInfo.maxTiledPixelStorageSize; + } + + return false; + } + // This function follows the structure of TryMergeNativeSubPass but only tests if the new native subpass can be // merged with the last one, allowing for early returns. It does not modify the state // ref for nativePass is used for performance reasons. The method should not modify nativePass. @@ -1283,7 +1352,8 @@ void AddDepthAttachmentFirstDuringMerge(CompilerContextData contextData, in Pass } } - // We also need to update the shading rate image index (VRS) + // We also need to update the shading rate image SRI index (used for VRS) + // This is unlikely to happen because the SRI is always added last, after color and input attachments if (hasShadingRateImage && shadingRateImageIndex == 0) { shadingRateImageIndex = prevDepthIdx; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/ResourcesData.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/ResourcesData.cs index 83ecf3d8025..e117c199ef9 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/ResourcesData.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/ResourcesData.cs @@ -2,6 +2,7 @@ using System.Runtime.CompilerServices; using Unity.Collections; using UnityEngine.Rendering; +using UnityEngine.Experimental.Rendering; namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler { @@ -29,6 +30,7 @@ internal struct ResourceUnversionedData public readonly int height; public readonly int volumeDepth; public readonly int msaaSamples; + public readonly GraphicsFormat graphicsFormat; public int latestVersionNumber; // mostly readonly, can be decremented only if all passes using the last version are culled @@ -62,6 +64,7 @@ public ResourceUnversionedData(TextureResource rll, ref RenderTargetInfo info, r discard = desc.discardBuffer; bindMS = info.bindMS; textureUVOrigin = rll.textureUVOrigin; + graphicsFormat = desc.format; } public ResourceUnversionedData(IRenderGraphResource rll, ref BufferDesc _, bool isResourceShared) @@ -87,6 +90,7 @@ public ResourceUnversionedData(IRenderGraphResource rll, ref BufferDesc _, bool discard = false; bindMS = false; textureUVOrigin = TextureUVOriginSelection.Unknown; + graphicsFormat = GraphicsFormat.None; } public ResourceUnversionedData(IRenderGraphResource rll, ref RayTracingAccelerationStructureDesc _, bool isResourceShared) @@ -112,6 +116,7 @@ public ResourceUnversionedData(IRenderGraphResource rll, ref RayTracingAccelerat discard = false; bindMS = false; textureUVOrigin = TextureUVOriginSelection.Unknown; + graphicsFormat = GraphicsFormat.None; } public void InitializeNullResource() @@ -152,7 +157,7 @@ public void SetWritingPass(CompilerContextData ctx, ResourceHandle h, int passId public void RegisterReadingPass(CompilerContextData ctx, ResourceHandle h, int passId, int index) { #if DEVELOPMENT_BUILD || UNITY_EDITOR - if (numReaders >= ctx.resources.MaxReaders) + if (numReaders >= ctx.resources.MaxReaders[h.iType]) { string passName = ctx.GetPassName(passId); string resourceName = ctx.GetResourceName(h); @@ -200,8 +205,8 @@ internal class ResourcesData public NativeList[] versionedData; // Flattened fixed size array storing up to MaxVersions versions per resource id. public NativeList[] readerData; // Flattened fixed size array storing up to MaxReaders per resource id per version. - public int MaxVersions; - public int MaxReaders; + public int[] MaxVersions; + public int[] MaxReaders; public DynamicArray[] resourceNames; @@ -211,6 +216,8 @@ public ResourcesData() versionedData = new NativeList[(int)RenderGraphResourceType.Count]; readerData = new NativeList[(int)RenderGraphResourceType.Count]; resourceNames = new DynamicArray[(int)RenderGraphResourceType.Count]; + MaxVersions = new int[(int)RenderGraphResourceType.Count]; + MaxReaders = new int[(int)RenderGraphResourceType.Count]; for (int t = 0; t < (int)RenderGraphResourceType.Count; t++) resourceNames[t] = new DynamicArray(0); // T in NativeList cannot contain managed types, so the names are stored separately @@ -247,14 +254,14 @@ void AllocateAndResizeNativeListIfNeeded(ref NativeList nativeList, int si public void Initialize(RenderGraphResourceRegistry resources) { - uint maxReaders = 0; - uint maxWriters = 0; - for (int t = 0; t < (int)RenderGraphResourceType.Count; t++) { RenderGraphResourceType resourceType = (RenderGraphResourceType) t; var numResources = resources.GetResourceCount(resourceType); + uint maxReaders = 0; + uint maxWriters = 0; + // We don't clear the list as we reinitialize it right after AllocateAndResizeNativeListIfNeeded(ref unversionedData[t], numResources, NativeArrayOptions.UninitializedMemory); @@ -315,12 +322,12 @@ public void Initialize(RenderGraphResourceRegistry resources) } // The first resource is a null resource, so we need to add 1 to the count. - MaxReaders = (int)maxReaders + 1; - MaxVersions = (int)maxWriters + 1; + MaxReaders[t] = (int)maxReaders + 1; + MaxVersions[t] = (int)maxWriters + 1; // Clear the other caching structures, they will be filled later - AllocateAndResizeNativeListIfNeeded(ref versionedData[t], MaxVersions * numResources, NativeArrayOptions.ClearMemory); - AllocateAndResizeNativeListIfNeeded(ref readerData[t], MaxVersions * MaxReaders * numResources, NativeArrayOptions.ClearMemory); + AllocateAndResizeNativeListIfNeeded(ref versionedData[t], MaxVersions[t] * numResources, NativeArrayOptions.ClearMemory); + AllocateAndResizeNativeListIfNeeded(ref readerData[t], MaxVersions[t] * MaxReaders[t] * numResources, NativeArrayOptions.ClearMemory); } } @@ -329,10 +336,10 @@ public void Initialize(RenderGraphResourceRegistry resources) public int Index(ResourceHandle h) { #if UNITY_EDITOR // Hot path - if (h.version < 0 || h.version >= MaxVersions) + if (h.version < 0 || h.version >= MaxVersions[h.iType]) throw new Exception("Invalid version: " + h.version); #endif - return h.index * MaxVersions + h.version; + return h.index * MaxVersions[h.iType] + h.version; } // Flatten array index @@ -340,12 +347,12 @@ public int Index(ResourceHandle h) public int IndexReader(ResourceHandle h, int readerID) { #if UNITY_EDITOR // Hot path - if (h.version < 0 || h.version >= MaxVersions) + if (h.version < 0 || h.version >= MaxVersions[h.iType]) throw new Exception("Invalid version"); - if (readerID < 0 || readerID >= MaxReaders) + if (readerID < 0 || readerID >= MaxReaders[h.iType]) throw new Exception("Invalid reader"); #endif - return (h.index * MaxVersions + h.version) * MaxReaders + readerID; + return (h.index * MaxVersions[h.iType] + h.version) * MaxReaders[h.iType] + readerID; } // Lookup data for a given handle diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs index 9b5ba940419..201b0ea333d 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs @@ -664,23 +664,11 @@ public RenderGraph(string name = "RenderGraph") #endif } - /// - /// Cleanup the Render Graph. - /// - /// - /// This API cannot be called when Render Graph is active, please call it outside of RecordRenderGraph(). - /// - void CleanupResourcesAndGraph() - { - CheckNotUsedWhenActive(); - - ForceCleanup(); - } - // Internal, only for testing // Useful when we need to clean when calling // internal functions in tests even if Render Graph is active - internal void ForceCleanup() + // This API shouldn't be called when the render graph is active! + internal void CleanupResourcesAndGraph() { // Usually done at the end of Execute step // Also doing it here in case RG stopped before it @@ -700,6 +688,11 @@ internal void ForceCleanup() /// public void Cleanup() { + CheckNotUsedWhenActive(); + + // Dispose of the compiled graphs left over in the cache + m_CompilationCache?.Cleanup(); + CleanupResourcesAndGraph(); UnregisterGraph(); } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilders.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilders.cs index de45306a944..f34f8a29503 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilders.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilders.cs @@ -493,6 +493,13 @@ public TextureHandle SetRandomAccessAttachment(TextureHandle input, int index, A return input; } + public void SetShadingRateImageAttachment(in TextureHandle tex) + { + CheckNotUseFragment(tex); + var versionedTextureHandle = new TextureHandle(UseResource(tex.handle, AccessFlags.Read)); + m_RenderPass.SetShadingRateImageRaw(versionedTextureHandle); + } + public BufferHandle UseBufferRandomAccess(BufferHandle input, int index, AccessFlags flags = AccessFlags.Read) { var h = UseBuffer(input, flags); @@ -588,17 +595,6 @@ void CheckFrameBufferFetchEmulationIsSupported(in TextureHandle tex) } } - public void SetShadingRateImageAttachment(in TextureHandle sriTextureHandle) - { - CheckNotUseFragment(sriTextureHandle); - - // shading rate image access flag is always read, only 1 mip and 1 slice - var newSriTextureHandle = new TextureHandle(); - newSriTextureHandle.handle = UseResource(sriTextureHandle.handle, AccessFlags.Read); - - m_RenderPass.SetShadingRateImage(newSriTextureHandle, AccessFlags.Read, 0, 0); - } - public void SetShadingRateFragmentSize(ShadingRateFragmentSize shadingRateFragmentSize) { m_RenderPass.SetShadingRateFragmentSize(shadingRateFragmentSize); diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphCompilationCache.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphCompilationCache.cs index 6bd8f3766f0..82588ff8259 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphCompilationCache.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphCompilationCache.cs @@ -114,4 +114,42 @@ public void Clear() } m_NativeHashEntries.Clear(); } + + public void Cleanup() + { + // We clear the contents of the pools but not the pool themselves, because they are only + // filled at the beginning of the renderer pipeline and never after. This means when we call + // Cleanup() after an error, if we were clearing the pools, the render graph could not gracefully start + // back up because the cache would have a size of 0 (so no room to cache anything). + + // Cleanup compiled graphs currently in the cache + for (int i = 0; i < m_HashEntries.size; ++i) + { + var compiledGraph = m_HashEntries[i].compiledGraph; + compiledGraph.Clear(); + } + m_HashEntries.Clear(); + + // Cleanup compiled graphs that might be left in the pool + var compiledGraphs = m_CompiledGraphPool.ToArray(); + for (int i = 0; i < compiledGraphs.Length; ++i) + { + compiledGraphs[i].Clear(); + } + + // Dispose of CompilerContextData currently in the cache + for (int i = 0; i < m_NativeHashEntries.size; ++i) + { + var compiledGraph = m_NativeHashEntries[i].compiledGraph; + compiledGraph.Dispose(); + } + m_NativeHashEntries.Clear(); + + // Dispose of CompilerContextData that might be left in the pool + var nativeCompiledGraphs = m_NativeCompiledGraphPool.ToArray(); + for (int i = 0; i < nativeCompiledGraphs.Length; ++i) + { + nativeCompiledGraphs[i].Dispose(); + } + } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphPass.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphPass.cs index 8643987c676..e92dea42a27 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphPass.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphPass.cs @@ -553,6 +553,16 @@ public void ComputeHash(ref HashFNV1A32 generator, RenderGraphResourceRegistry r generator.Append(GetRenderFuncHash()); } + public void SetShadingRateImageRaw(in TextureHandle shadingRateImage) + { + if (ShadingRateInfo.supportsPerImageTile) + { + hasShadingRateImage = true; + // shading rate image access flag is always read, only 1 mip and 1 slice + shadingRateAccess = new TextureAccess(shadingRateImage, AccessFlags.Read, 0, 0); + } + } + public void SetShadingRateImage(in TextureHandle shadingRateImage, AccessFlags accessFlags, int mipLevel, int depthSlice) { if (ShadingRateInfo.supportsPerImageTile) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/UnifiedRayTracing/Common/AccelStructAdapter.cs b/Packages/com.unity.render-pipelines.core/Runtime/UnifiedRayTracing/Common/AccelStructAdapter.cs index 4b9bb1e8e8e..a14bccf7ed8 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/UnifiedRayTracing/Common/AccelStructAdapter.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/UnifiedRayTracing/Common/AccelStructAdapter.cs @@ -132,7 +132,7 @@ void AddTrees(TerrainDesc terrainDesc, ref List instanceHandles) { TerrainData terrainData = terrainDesc.terrain.terrainData; float4x4 terrainLocalToWorld = terrainDesc.localToWorldMatrix; - float3 positionScale = new float3((float)terrainData.heightmapResolution, 1.0f, (float)terrainData.heightmapResolution) * (float3)(terrainData.heightmapScale); + float3 positionScale = new float3((float)terrainData.heightmapResolution, 1.0f, (float)terrainData.heightmapResolution) * terrainData.heightmapScale; float3 positionOffset = new float3(terrainLocalToWorld[3].x, terrainLocalToWorld[3].y, terrainLocalToWorld[3].z); foreach (var treeInstance in terrainData.treeInstances) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Upscaling/DLSSOptions.cs b/Packages/com.unity.render-pipelines.core/Runtime/Upscaling/DLSSOptions.cs index 41258437521..e67f84b8853 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Upscaling/DLSSOptions.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Upscaling/DLSSOptions.cs @@ -17,25 +17,22 @@ [Serializable] public class DLSSOptions : UpscalerOptions { - [EnumOption(typeof(DLSSQuality), "DLSS Quality Mode")] - public int DLSSQualityMode = (int)DLSSQuality.MaximumQuality; + [Tooltip("Selects a performance quality setting for NVIDIA Deep Learning Super Sampling (DLSS).")] + public DLSSQuality DLSSQualityMode = DLSSQuality.MaximumQuality; - [BoolOption("Force Quality Mode")] + [Tooltip("Forces a fixed resolution scale derived from the selected quality mode, ignoring dynamic resolution.")] public bool FixedResolutionMode = false; - // TODO: fix available preset values, currently all values are displayed. - // every preset have their own list of available presets, that may differ from each other. - // need a way to represent the available subset of enum values for each preset to enforce the value requirements. - [EnumOption(typeof(DLSSPreset), "DLSS Preset for Quality")] - public int DLSSRenderPresetQuality; - [EnumOption(typeof(DLSSPreset), "DLSS Preset for Balanced")] - public int DLSSRenderPresetBalanced; - [EnumOption(typeof(DLSSPreset), "DLSS Preset for Performance")] - public int DLSSRenderPresetPerformance; - [EnumOption(typeof(DLSSPreset), "DLSS Preset for Ultra Performance")] - public int DLSSRenderPresetUltraPerformance; - [EnumOption(typeof(DLSSPreset), "DLSS Preset for DLAA")] - public int DLSSRenderPresetDLAA; + [Tooltip("DLSS will use the specified render preset for the Quality mode.")] + public DLSSPreset DLSSRenderPresetQuality; + [Tooltip("DLSS will use the specified render preset for the Balanced mode.")] + public DLSSPreset DLSSRenderPresetBalanced; + [Tooltip("DLSS will use the specified render preset for the Performance mode.")] + public DLSSPreset DLSSRenderPresetPerformance; + [Tooltip("DLSS will use the specified render preset for the Ultra Performance mode.")] + public DLSSPreset DLSSRenderPresetUltraPerformance; + [Tooltip("DLSS will use the specified render preset for the DLAA mode.")] + public DLSSPreset DLSSRenderPresetDLAA; } #endif // ENABLE_UPSCALER_FRAMEWORK && ENABLE_NVIDIA && ENABLE_NVIDIA_MODULE diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Upscaling/FSR2Options.cs b/Packages/com.unity.render-pipelines.core/Runtime/Upscaling/FSR2Options.cs index e3f4bb4d95b..24fd49124a5 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Upscaling/FSR2Options.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Upscaling/FSR2Options.cs @@ -17,16 +17,17 @@ [Serializable] public class FSR2Options : UpscalerOptions { - [EnumOption(typeof(FSR2Quality), "FSR2 Quality Mode")] - public int FSR2QualityMode = (int)FSR2Quality.Quality; + [Tooltip("Selects a performance quality setting for AMD FidelityFX 2.0 Super Resolution (FSR2).")] + public FSR2Quality FSR2QualityMode = FSR2Quality.Quality; - [BoolOption("Fixed Resolution")] + [Tooltip("Forces a fixed resolution scale derived from the selected quality mode, ignoring dynamic resolution.")] public bool FixedResolutionMode = false; - [BoolOption("Enable Sharpening")] + [Tooltip("Enable an additional sharpening pass on FidelityFX 2.0 Super Resolution (FSR2).")] public bool EnableSharpening = false; - [FloatOption(0.0f, 1.0f, "Sharpness")] + [Tooltip("The sharpness value between 0 and 1, where 0 is no additional sharpness and 1 is maximum additional sharpness.")] + [Range(0.0f, 1.0f)] public float Sharpness = 0.92f; }; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Upscaling/IUpscalerOptions.cs b/Packages/com.unity.render-pipelines.core/Runtime/Upscaling/IUpscalerOptions.cs index 1553d21d07e..37b4f310241 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Upscaling/IUpscalerOptions.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Upscaling/IUpscalerOptions.cs @@ -9,380 +9,6 @@ namespace UnityEngine.Rendering { #nullable enable - #region Attributes - - /// - /// Base class for all custom option attributes. - /// UpscalerOptions attributes facilitate GUI rendering for a given option by sepcifying its type, range of values and display label. - /// - public abstract class BaseOptionAttribute : PropertyAttribute // Using PropertyAttribute for Unity Editor integration - { - public string? DisplayName { get; protected set; } - - protected BaseOptionAttribute(string? displayName = null) - { - DisplayName = displayName; - } - } - - - /// - /// Marks an int field as representing an enum value. - /// - [AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)] - public class EnumOptionAttribute : BaseOptionAttribute - { - public Type EnumType { get; private set; } - - public EnumOptionAttribute(Type enumType, string? displayName = null) : base(displayName) - { - if (enumType == null || !enumType.IsEnum) - { - throw new ArgumentException("EnumType must be a valid Enum type.", nameof(enumType)); - } - EnumType = enumType; - } - } - - /// - /// Marks a float field as an option. - /// - [AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)] - public class FloatOptionAttribute : BaseOptionAttribute - { - public float Min { get; private set; } - public float Max { get; private set; } - public bool HasRange { get; private set; } // Indicates if min/max were explicitly set - public FloatOptionAttribute(string? displayName = null) : base(displayName) - { - HasRange = false; - Min = 0f; // Default, will be ignored if HasRange is false - Max = 0f; - } - public FloatOptionAttribute(float min, float max, string? displayName = null) : base(displayName) - { - HasRange = true; - Min = min; - Max = max; - } - } - - /// - /// Marks an int field as an option. - /// - [AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)] - public class IntOptionAttribute : BaseOptionAttribute - { - public int Min { get; private set; } - public int Max { get; private set; } - public bool HasRange { get; private set; } // Indicates if min/max were explicitly set - - // Constructor for int without range - public IntOptionAttribute(string? displayName = null) : base(displayName) - { - HasRange = false; - Min = 0; // Default - Max = 0; - } - - // Constructor for int with range - public IntOptionAttribute(int min, int max, string? displayName = null) : base(displayName) - { - HasRange = true; - Min = min; - Max = max; - } - } - - /// - /// Marks a boolean field as an option. - /// - [AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)] - public class BoolOptionAttribute : BaseOptionAttribute - { - public BoolOptionAttribute(string? displayName = null) : base(displayName) { } - } - #endregion - - #region OptionsBase - /// - /// Represents a single configurable option that can be read from and written to. - /// - public interface IOption - { - string Id { get; } // A unique identifier for the option (e.g., field name) - string DisplayName { get; } // A user-friendly name for the option - Type ValueType { get; } // The actual C# type of the option's value (e.g., typeof(float), typeof(DLSSQuality)) - - abstract object? GetValue(object targetInstance); - abstract void SetValue(object targetInstance, object? newValue); - } - - /// - /// Represents an option whose value is an enum. - /// - public interface IEnumOption : IOption - { - Type EnumType { get; } // The specific enum Type (e.g., typeof(DLSSQuality)) - Array GetEnumValues(); // Returns an array of the actual enum values - string[] GetEnumNames(); // Returns an array of the enum names (for display) - } - - /// - /// Represents a numeric option that has a defined minimum and maximum value. - /// - public interface IRangeOption : IOption - { - float MinValue { get; } // Using float for generics, int ranges will cast - float MaxValue { get; } // Using float for generics, int ranges will cast - bool HasRange { get; } // True if a min/max was explicitly set - } - - - /// - /// Abstract base class for option implementations, handles common properties. - /// - internal abstract class OptionBase : IOption - { - protected readonly FieldInfo _fieldInfo; - - public string Id { get; private set; } - public string DisplayName { get; private set; } - public abstract Type ValueType { get; } - - protected OptionBase(FieldInfo fieldInfo, string displayName) - { - _fieldInfo = fieldInfo ?? throw new ArgumentNullException(nameof(fieldInfo)); - Id = fieldInfo.Name; - DisplayName = displayName; - } - - public virtual object? GetValue(object targetInstance) - { - if (targetInstance == null || !_fieldInfo.DeclaringType!.IsAssignableFrom(targetInstance.GetType())) - { - throw new ArgumentException($"Target instance is not compatible with option's field type. Expected {_fieldInfo.DeclaringType.Name}, got {targetInstance?.GetType().Name}.", nameof(targetInstance)); - } - return _fieldInfo.GetValue(targetInstance); - } - - public virtual void SetValue(object targetInstance, object? newValue) - { - if (targetInstance == null || !_fieldInfo.DeclaringType!.IsAssignableFrom(targetInstance.GetType())) - { - throw new ArgumentException($"Target instance is not compatible with option's field type. Expected {_fieldInfo.DeclaringType.Name}, got {targetInstance?.GetType().Name}.", nameof(targetInstance)); - } - _fieldInfo.SetValue(targetInstance, newValue); - } - } - #endregion - - - #region TypedOptions - /// - /// Represents an integer option backed by an enum. - /// - internal class EnumIntOption : OptionBase, IEnumOption - { - public Type EnumType { get; private set; } - - public override Type ValueType => EnumType; - - public EnumIntOption(FieldInfo fieldInfo, string displayName, Type enumType) - : base(fieldInfo, displayName) - { - if (!enumType.IsEnum) - { - throw new ArgumentException($"Provided type '{enumType.Name}' is not an enum.", nameof(enumType)); - } - if (fieldInfo.FieldType != typeof(int)) - { - throw new ArgumentException($"EnumIntOption can only wrap int fields. Field '{fieldInfo.Name}' is of type '{fieldInfo.FieldType.Name}'.", nameof(fieldInfo)); - } - EnumType = enumType; - } - - public override object? GetValue(object targetInstance) - { - int intValue = (int)(base.GetValue(targetInstance) ?? 0); // Handle potential null for value types - return Enum.ToObject(EnumType, intValue); - } - - public override void SetValue(object targetInstance, object? newValue) - { - if (newValue != null && newValue.GetType() != EnumType) - { - throw new ArgumentException($"Cannot set EnumIntOption '{DisplayName}': value type mismatch. Expected '{EnumType.Name}', got '{newValue?.GetType().Name}'.", nameof(newValue)); - } - base.SetValue(targetInstance, Convert.ToInt32(newValue)); - } - - public Array GetEnumValues() => Enum.GetValues(EnumType); - public string[] GetEnumNames() => Enum.GetNames(EnumType); - } - - /// - /// Represents a boolean option. - /// - internal class BoolOption : OptionBase - { - public override Type ValueType => typeof(bool); - - public BoolOption(FieldInfo fieldInfo, string displayName) - : base(fieldInfo, displayName) - { - if (fieldInfo.FieldType != typeof(bool)) - { - throw new ArgumentException($"BoolOption can only wrap bool fields. Field '{fieldInfo.Name}' is of type '{fieldInfo.FieldType.Name}'.", nameof(fieldInfo)); - } - } - } - - /// - /// Represents a float option, with an optional min/max range. - /// - internal class FloatOption : OptionBase, IRangeOption - { - public override Type ValueType => typeof(float); - public float MinValue { get; private set; } - public float MaxValue { get; private set; } - public bool HasRange { get; private set; } - - public FloatOption(FieldInfo fieldInfo, string displayName, float min, float max, bool hasRange) - : base(fieldInfo, displayName) - { - if (fieldInfo.FieldType != typeof(float)) - { - throw new ArgumentException($"FloatOption can only wrap float fields. Field '{fieldInfo.Name}' is of type '{fieldInfo.FieldType.Name}'.", nameof(fieldInfo)); - } - MinValue = min; - MaxValue = max; - HasRange = hasRange; - } - } - - /// - /// Represents an int option, with an optional min/max range. - /// - internal class IntOption : OptionBase, IRangeOption - { - public override Type ValueType => typeof(int); - public float MinValue { get; private set; } // Storing as float, will cast to int when used - public float MaxValue { get; private set; } // Storing as float, will cast to int when used - public bool HasRange { get; private set; } - - public IntOption(FieldInfo fieldInfo, string displayName, int min, int max, bool hasRange) - : base(fieldInfo, displayName) - { - if (fieldInfo.FieldType != typeof(int)) - { - throw new ArgumentException($"IntOption can only wrap int fields. Field '{fieldInfo.Name}' is of type '{fieldInfo.FieldType.Name}'.", nameof(fieldInfo)); - } - MinValue = min; - MaxValue = max; - HasRange = hasRange; - } - } - - #endregion - - #region OptionsRegistry - /// - /// Provides methods to generically inspect UpscalerOptions instances - /// and retrieve their configurable options. - /// - public static class UpscalerOptionsRegistry - { - // Cached reflection results - private static readonly Dictionary> s_CachedOptions = new(); - -#if UNITY_EDITOR - /// - /// Discovers and returns all configurable options for a given UpscalerOptions instance. - /// This method uses reflection and caches results for performance. - /// - /// The UpscalerOptions instance to inspect. - /// A list of IOption objects representing the configurable options. - [Preserve] // Prevent IL2CPP stripping if attributes/reflection are only used by this. - public static IReadOnlyList GetConfigurableOptions(UpscalerOptions optionsInstance) - { - if (optionsInstance == null) - { - Debug.LogWarning("GetConfigurableOptions called with a null options instance."); - return new List(); - } - - Type optionsType = optionsInstance.GetType(); - - // Use cached metadata if available - if (s_CachedOptions.TryGetValue(optionsType, out var optionsList)) - { - return optionsList; - } - - // Otherwise, perform reflection and build the metadata - List discoveredOptions = new List(); - - // Get all instance fields, both public and non-public (for [SerializeField] private fields) - FieldInfo[] fields = optionsType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - - foreach (FieldInfo field in fields) - { - // Check for our custom option attributes - BaseOptionAttribute? attr = field.GetCustomAttribute(true); - - if (attr == null) continue; // Not an option we care about - - // Determine the display name, prioritizing the one from the attribute - string displayName = attr.DisplayName ?? ObjectNames.NicifyVariableName(field.Name); - - // Create the appropriate IOption wrapper based on the attribute type - if (attr is EnumOptionAttribute enumAttr) - { - discoveredOptions.Add(new EnumIntOption(field, displayName, enumAttr.EnumType)); - } - else if (attr is FloatOptionAttribute floatAttr) - { - discoveredOptions.Add(new FloatOption(field, displayName, floatAttr.Min, floatAttr.Max, floatAttr.HasRange)); - } - else if (attr is IntOptionAttribute intAttr) - { - discoveredOptions.Add(new IntOption(field, displayName, intAttr.Min, intAttr.Max, intAttr.HasRange)); - } - else if (attr is BoolOptionAttribute) - { - discoveredOptions.Add(new BoolOption(field, displayName)); - } - else - { - Debug.LogWarning($"Unhandled BaseOptionAttribute type for field '{field.Name}' in '{optionsType.Name}': {attr.GetType().Name}."); - } - } - - // Cache and return - s_CachedOptions[optionsType] = discoveredOptions; - return discoveredOptions; - } - - /// - /// Finds a specific option by its ID (field name). - /// - /// The UpscalerOptions instance. - /// The ID (field name) of the option to find. - /// The IOption object if found, otherwise null. - public static IOption? GetOptionById(UpscalerOptions optionsInstance, string optionId) - { - foreach(IOption opt in GetConfigurableOptions(optionsInstance)) - { - if (opt.Id == optionId) - return opt; - } - return null; - } -#endif - }; - #endregion - [Serializable] public class UpscalerOptions : ScriptableObject @@ -399,75 +25,13 @@ public UpsamplerScheduleType InjectionPoint set => m_InjectionPoint = value; } - [SerializeField] private string m_UpscalerName = ""; - [SerializeField] private UpsamplerScheduleType m_InjectionPoint = UpsamplerScheduleType.BeforePost; + [SerializeField, HideInInspector] + private string m_UpscalerName = ""; + [SerializeField, HideInInspector] // hide in inspector for URP, HDRP manually renders it + private UpsamplerScheduleType m_InjectionPoint = UpsamplerScheduleType.BeforePost; #if UNITY_EDITOR - public bool DrawOptionsEditorGUI() - { - bool optionUpdated = false; - IReadOnlyList options = UpscalerOptionsRegistry.GetConfigurableOptions(this); - foreach (IOption opt in options) - { - object? currentValue = opt.GetValue(this); - object? newValue = null; // store the value returned by the GUI control - - // ranged int/float options - if (opt is IRangeOption rangeOption && rangeOption.HasRange) - { - if (opt.ValueType == typeof(float)) - { - float currentFloatValue = (float)currentValue!; - newValue = EditorGUILayout.Slider(opt.DisplayName, currentFloatValue, rangeOption.MinValue, rangeOption.MaxValue); - } - else if (opt.ValueType == typeof(int)) - { - int currentIntValue = (int)currentValue!; - newValue = EditorGUILayout.IntSlider(opt.DisplayName, currentIntValue, (int)rangeOption.MinValue, (int)rangeOption.MaxValue); - } - else - { - // Fallback for unexpected IRangeOption types (shouldn't happen if attributes are correct) - EditorGUILayout.LabelField(opt.DisplayName, $"Range Type (Unhandled): {opt.ValueType.Name}, Value: {currentValue?.ToString() ?? "N/A"}"); - } - } - // regular options - else - { - if (opt is IEnumOption enumOption) - { - Enum currentEnumValue = (Enum)currentValue!; - newValue = EditorGUILayout.EnumPopup(enumOption.DisplayName, currentEnumValue); - } - else if (opt.ValueType == typeof(float)) - { - float currentFloatValue = (float)currentValue!; - newValue = EditorGUILayout.FloatField(opt.DisplayName, currentFloatValue); - } - else if (opt.ValueType == typeof(int)) - { - int currentIntValue = (int)currentValue!; - newValue = EditorGUILayout.IntField(opt.DisplayName, currentIntValue); - } - else if (opt.ValueType == typeof(bool)) - { - bool currentBoolValue = (bool)currentValue!; - newValue = EditorGUILayout.Toggle(opt.DisplayName, currentBoolValue); - } - } - - bool valueChanged = newValue != null && !newValue.Equals(currentValue); - if (valueChanged) - { - opt.SetValue(this, newValue); - optionUpdated = true; - } - } - - return optionUpdated; - } - // The core method to ensure options exist and are linked. // It operates on a SerializedProperty representing the list. public static bool ValidateSerializedUpscalerOptionReferencesWithinRPAsset(ScriptableObject parentRPAsset, SerializedProperty optionsListProp) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blitter.cs b/Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blitter.cs index a4f968a48dd..5962100a8b0 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blitter.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blitter.cs @@ -514,8 +514,9 @@ public static void BlitTexture(RasterCommandBuffer cmd, RTHandle source, Vector4 /// public static void BlitTexture(CommandBuffer cmd, RTHandle source, Vector4 scaleBias, float mipLevel, bool bilinear) { + var dimension = (source.rt != null) ? source.rt.dimension : TextureXR.dimension; s_PropertyBlock.SetFloat(BlitShaderIDs._BlitMipLevel, mipLevel); - BlitTexture(cmd, source, scaleBias, GetBlitMaterial(source.rt.dimension), s_BlitShaderPassIndicesMap[bilinear ? 1 : 0]); + BlitTexture(cmd, source, scaleBias, GetBlitMaterial(dimension), s_BlitShaderPassIndicesMap[bilinear ? 1 : 0]); } /// diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/NativePassCompilerRenderGraphTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/NativePassCompilerRenderGraphTests.cs index 6fb2d3b6ab9..b8ff96726b9 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Editor/NativePassCompilerRenderGraphTests.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/NativePassCompilerRenderGraphTests.cs @@ -48,7 +48,7 @@ TestRenderTargets ImportAndCreateRenderTargets(RenderGraph g) var extraDepthBufferHandle = RTHandles.Alloc(depthBuffer, "Extra Depth Buffer"); var extraDepthBufferBottomLeftHandle = RTHandles.Alloc(depthBuffer, "Extra Depth Buffer Bottom Left"); var extraTextureTopLeftHandle = RTHandles.Alloc(backBuffer, "ExtraTextureTopLeft"); - var extraTextureBottomLeftHandle = RTHandles.Alloc(backBuffer,"ExtraTextureBottomLeft"); + var extraTextureBottomLeftHandle = RTHandles.Alloc(backBuffer, "ExtraTextureBottomLeft"); ImportResourceParams importParams = new ImportResourceParams(); importParams.textureUVOrigin = TextureUVOrigin.TopLeft; @@ -967,7 +967,7 @@ public void ImportParametersWork() // Render to final buffer using (var builder = g.AddRasterRenderPass("TestPass2", out var passData)) { - builder.SetRenderAttachment(renderTargets.extraTextures[0], 0, AccessFlags.Write); + builder.SetRenderAttachment(renderTargets.extraTextures[0], 0, AccessFlags.ReadWrite); builder.SetRenderAttachment(importedTexture, 1, AccessFlags.Write); builder.SetRenderAttachment(renderTargets.backBuffer, 2, AccessFlags.Write); builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); @@ -1081,11 +1081,11 @@ public void MaxReadersAndMaxVersionsAreCorrectForBuffers() // The resource with the biggest MaxReaders is buffer2: // 1 implicit read (TestPass0) + 1 explicit read (TestPass1) + 1 for the offset. - Assert.AreEqual(result.contextData.resources.MaxReaders, 3); + Assert.AreEqual(result.contextData.resources.MaxReaders[(int)RenderGraphResourceType.Buffer], 3); // The resource with the biggest MaxVersion is buffer2: // 1 explicit write (TestPass0) + 1 explicit readwrite (TestPass1) + 1 for the offset - Assert.AreEqual(result.contextData.resources.MaxVersions, 3); + Assert.AreEqual(result.contextData.resources.MaxVersions[(int)RenderGraphResourceType.Buffer], 3); } [Test] @@ -1122,11 +1122,11 @@ public void MaxReadersAndMaxVersionsAreCorrectForTextures() // Resources with the biggest MaxReaders are extraTextures[0] and depthBuffer (both being equal): // 1 implicit read (TestPass0) + 2 explicit read (TestPass1 & TestPass2) + 1 for the offset - Assert.AreEqual(result.contextData.resources.MaxReaders, 4); + Assert.AreEqual(result.contextData.resources.MaxReaders[(int)RenderGraphResourceType.Texture], 4); // The resource with the biggest MaxVersion is extraTextures[0]: // 1 explicit write (TestPass0) + 1 explicit read-write (TestPass1) + 1 for the offset - Assert.AreEqual(result.contextData.resources.MaxVersions, 3); + Assert.AreEqual(result.contextData.resources.MaxVersions[(int)RenderGraphResourceType.Texture], 3); } [Test] @@ -1164,11 +1164,88 @@ public void MaxReadersAndMaxVersionsAreCorrectForBuffersMultiplePasses() // The resource with the biggest MaxReaders is buffer2: // 5 implicit read (TestPass0-2-4-6-8) + 5 explicit read (TestPass1-3-5-7-9) + 1 for the offset. - Assert.AreEqual(result.contextData.resources.MaxReaders, 11); + Assert.AreEqual(result.contextData.resources.MaxReaders[(int)RenderGraphResourceType.Buffer], 11); // The resource with the biggest MaxVersion is buffer2: // 5 explicit write (TestPass0-2-4-6-8) + 5 explicit readwrite (TestPass1-3-5-7-9) + 1 for the offset - Assert.AreEqual(result.contextData.resources.MaxVersions, 11); + Assert.AreEqual(result.contextData.resources.MaxVersions[(int)RenderGraphResourceType.Buffer], 11); + } + + [Test] + public void ResourcesData_MaxReadersAndVersionsPerResourceType() + { + var g = AllocateRenderGraph(); + var renderTargets = ImportAndCreateRenderTargets(g); + + var desc = new BufferDesc(1024, 16); + var buffer = g.CreateBuffer(desc); + + int indexName = 0; + + // TEXTURE PASSES: Create 2 versions with different reader counts + // Texture Pass 0: Create version 1 of extraTextures[0] (ReadWrite = 1 write + 1 implicit read) + using (var builder = g.AddRasterRenderPass("TestPassTexture" + indexName++, out var passData)) + { + builder.AllowPassCulling(false); + builder.SetRenderAttachment(renderTargets.extraTextures[0], 0, AccessFlags.ReadWrite); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + } + // Texture Pass 1: Create version 2 of extraTextures[0] (ReadWrite = 1 write + 1 explicit read of version 1) + using (var builder = g.AddRasterRenderPass("TestPassTexture" + indexName++, out var passData)) + { + builder.AllowPassCulling(false); + builder.SetRenderAttachment(renderTargets.extraTextures[0], 0, AccessFlags.ReadWrite); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + } + + // BUFFER PASSES: Create many versions to test higher reader/version counts + indexName = 0; + for (int i = 0; i < 5; ++i) + { + // Buffer Pass (Write): Creates version N (1 write + 1 implicit read from previous version) + using (var builder = g.AddRasterRenderPass("TestPassBuffer" + indexName++, out var passData)) + { + builder.AllowPassCulling(false); + builder.UseBufferRandomAccess(buffer, 0, AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + } + // Buffer Pass (ReadWrite): Creates version N+1 (1 write + 1 explicit read from version N) + using (var builder = g.AddRasterRenderPass("TestPassBuffer" + indexName++, out var passData)) + { + builder.AllowPassCulling(false); + builder.UseBufferRandomAccess(buffer, 0, AccessFlags.ReadWrite); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + } + } + + var result = g.CompileNativeRenderGraph(g.ComputeGraphHash()); + var passes = result.contextData.GetNativePasses(); + + // VERIFY: MaxReaders and MaxVersions are calculated PER RESOURCE TYPE + // TEXTURE TYPE: + // 2 readwrite operations = 2 versions + 1 offset = 3 versions/readers. + Assert.AreEqual(result.contextData.resources.MaxReaders[(int)RenderGraphResourceType.Texture], 3); + Assert.AreEqual(result.contextData.resources.MaxVersions[(int)RenderGraphResourceType.Texture], 3); + + // BUFFER TYPE: + // 5 write operations + 5 readwrite operations = 10 versions + 1 offset = 11 versions/readers. + Assert.AreEqual(result.contextData.resources.MaxReaders[(int)RenderGraphResourceType.Buffer], 11); + Assert.AreEqual(result.contextData.resources.MaxVersions[(int)RenderGraphResourceType.Buffer], 11); + + // VERIFY: Index calculations work correctly with per-type maximums + // Get the texture handle from the first native pass attachment + var textureHandle = passes[0].attachments[0].handle; + Assert.AreEqual(renderTargets.extraTextures[0].handle.index, passes[0].attachments[0].handle.index); + + // Test Index() calculation uses correct MaxVersions for texture type + int indexExpected = textureHandle.index * result.contextData.resources.MaxVersions[(int)RenderGraphResourceType.Texture] + textureHandle.version; + Assert.AreEqual(result.contextData.resources.Index(textureHandle), indexExpected); + Assert.IsTrue(indexExpected < result.contextData.resources.versionedData[(int)RenderGraphResourceType.Texture].Capacity); + + // Test IndexReader() calculation uses correct MaxReaders for texture type + int indexReaderExpected = indexExpected * result.contextData.resources.MaxReaders[(int)RenderGraphResourceType.Texture] + 0; + Assert.AreEqual(result.contextData.resources.IndexReader(textureHandle, 0), indexReaderExpected); + Assert.IsTrue(indexExpected < result.contextData.resources.readerData[(int)RenderGraphResourceType.Texture].Capacity); } [Test] @@ -1629,58 +1706,309 @@ public void UpdateSubpassAttachmentIndices_WhenDepthAttachmentIsAdded() Assert.IsTrue(subPassDesc3.inputs[0] == 3); } -/* //VRS bug. It seems that there is a bug with VRS forcing pass breaking between passes using the same shading rate image where it shouldn't: UUM-102113. [Test] - public void UpdateShadingRateImageIndex_WhenDepthAttachmentIsAdded() + public void MergePasses_WhenSameShadingRateImage() { var g = AllocateRenderGraph(); - var buffers = ImportAndCreateBuffers(g); + var renderTargets = ImportAndCreateRenderTargets(g); - using (var builder = g.AddRasterRenderPass("NoDepth_Subpass0", out var passData)) + using (var builder = g.AddRasterRenderPass("Pass0", out var passData)) { - builder.SetShadingRateImageAttachment(buffers.extraTextures[0]); - builder.SetRenderAttachment(buffers.extraTextures[1], 0); + builder.SetRenderAttachment(renderTargets.extraTextures[1], 0); + builder.SetShadingRateImageAttachment(renderTargets.extraTextures[0]); builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); builder.AllowPassCulling(false); } - // Render Pass - // attachments: [extraTextures[0], extraTextures[1]] - // shading rate image : [0] - // subpass 0: color outputs : [1] - - using (var builder = g.AddRasterRenderPass("Depth_Subpass1", out var passData)) + // Same attachments, we should merge in the same subpass as Pass0's one + using (var builder = g.AddRasterRenderPass("Pass1", out var passData)) { - builder.SetShadingRateImageAttachment(buffers.extraTextures[0]); - builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write); - builder.SetRenderAttachment(buffers.extraTextures[2], 0); + builder.SetRenderAttachment(renderTargets.extraTextures[1], 0); + builder.SetShadingRateImageAttachment(renderTargets.extraTextures[0]); builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); builder.AllowPassCulling(false); } - // Render Pass - // attachments: [depthBuffer, extraTextures[1], extraTextures[0], extraTextures[2]] - // shading rate image : [0 -> 2] - // subpass 0: color outputs : [1] - // subpass 1: color outputs : [3] + // Same shading rate image but different render attachments, we should stay in the same native render pass but in a different subpass + using (var builder = g.AddRasterRenderPass("Pass2", out var passData)) + { + builder.SetRenderAttachment(renderTargets.extraTextures[2], 0); + builder.SetShadingRateImageAttachment(renderTargets.extraTextures[0]); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(false); + } var result = g.CompileNativeRenderGraph(g.ComputeGraphHash()); var passes = result.contextData.GetNativePasses(); // All graph passes are merged in the same render pass - Assert.IsTrue(passes != null && passes.Count == 1 && passes[0].numGraphPasses == 2 && passes[0].numNativeSubPasses == 2); + Assert.IsTrue(passes != null && passes.Count == 1 && passes[0].numGraphPasses == 3 && passes[0].numNativeSubPasses == 2); - // Depth is the first attachment - Assert.IsTrue(passes[0].attachments[0].handle.index == buffers.depthBuffer.handle.index); - Assert.IsTrue(passes[0].attachments[1].handle.index == buffers.extraTextures[1].handle.index); - Assert.IsTrue(passes[0].attachments[2].handle.index == buffers.extraTextures[0].handle.index); - Assert.IsTrue(passes[0].attachments[3].handle.index == buffers.extraTextures[2].handle.index); + // If no SRI support, we just discard the API call + if (ShadingRateInfo.supportsPerImageTile) + { + var shadingRateImageAttachmentIndex = passes[0].shadingRateImageIndex; + Assert.IsTrue(shadingRateImageAttachmentIndex == 1); // always after color and depth attachments + Assert.IsTrue(passes[0].attachments[shadingRateImageAttachmentIndex].handle.index == renderTargets.extraTextures[0].handle.index); + } + } + + [Test] + public void BreakPasses_WhenNoOrDifferentShadingRateImage() + { + var g = AllocateRenderGraph(); + var renderTargets = ImportAndCreateRenderTargets(g); + + using (var builder = g.AddRasterRenderPass("Pass0", out var passData)) + { + builder.SetRenderAttachment(renderTargets.extraTextures[1], 0); + builder.SetShadingRateImageAttachment(renderTargets.extraTextures[0]); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(false); + } + + // Different SRI, we should break into a new native render pass + using (var builder = g.AddRasterRenderPass("Pass1", out var passData)) + { + builder.SetRenderAttachment(renderTargets.extraTextures[1], 0); + builder.SetShadingRateImageAttachment(renderTargets.extraTextures[2]); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(false); + } + + // No SRI, we should break into a new native render pass + using (var builder = g.AddRasterRenderPass("Pass2", out var passData)) + { + builder.SetRenderAttachment(renderTargets.extraTextures[1], 0); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(false); + } + + var result = g.CompileNativeRenderGraph(g.ComputeGraphHash()); + var passes = result.contextData.GetNativePasses(); + + if (ShadingRateInfo.supportsPerImageTile) + { + // All graph passes are in different native render passes + Assert.IsTrue(passes != null && passes.Count == 3); + } + else + { + // If no SRI support, we just discard the API call, all graph passes are merged together + Assert.IsTrue(passes != null && passes.Count == 1); + } + } + +/* // DepthAttachment bug: https://jira.unity3d.com/projects/SRP/issues/SRP-897 + [Test] + public void UnusedResourceCulling_CullProducer_WhenVersionsAreNotExplicitlyRead() + { + var g = AllocateRenderGraph(); + var renderTargets = ImportAndCreateRenderTargets(g); + + // Bumping version of extraTexture within RG to 1 as we write to it in first pass + using (var builder = g.AddRasterRenderPass("TestPass0", out var passData)) + { + builder.SetRenderAttachment(renderTargets.extraTextures[0], 0); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(true); + } + + // Bumping version of extraTexture within RG to 2 as we write to it in second pass + using (var builder = g.AddRasterRenderPass("TestPass1", out var passData)) + { + builder.SetRenderAttachment(renderTargets.extraTextures[0], 0); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(true); + } + + // Bumping version of extraTexture within RG to 3 as we write to it in third pass + using (var builder = g.AddRasterRenderPass("TestPass2", out var passData)) + { + builder.SetRenderAttachment(renderTargets.extraTextures[0], 0); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(true); + } + + // Bumping version of extraTexture within RG to 4 as we write to it in fourth pass + using (var builder = g.AddRasterRenderPass("TestPass3", out var passData)) + { + builder.SetRenderAttachment(renderTargets.extraTextures[0], 0); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(false); // Not culled! + } + + // Bumping version of extraTexture within RG to 5 as we write to it in fifth pass + using (var builder = g.AddRasterRenderPass("TestPass4", out var passData)) + { + builder.SetRenderAttachment(renderTargets.extraTextures[0], 0); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(true); + } + + var result = g.CompileNativeRenderGraph(g.ComputeGraphHash()); + var passes = result.contextData.GetNativePasses(); + + // All passes are only writing different versions of a non-imported texture that is never explicitly read by anyone + // Only fourth pass is preserved as requested but other passes are culled + Assert.IsTrue(passes != null && passes.Count == 1 && passes[0].numGraphPasses == 1); + // TestPass3 is the first pass needing extraBuffers[0] so this is the pass allocating it + Assert.IsTrue(result.contextData.passData.ElementAt(3).FirstUsedResources(result.contextData).Length == 1); + // extraBuffer version has decreased to 4 as it is written by the fourth pass + Assert.AreEqual(result.contextData.UnversionedResourceData(passes[0].attachments[0].handle).latestVersionNumber, 4); + } + + [Test] + public void UnusedResourceCulling_CullProducer_WhenNoneOfItsWrittenResourcesAreExplicitlyRead() + { + var g = AllocateRenderGraph(); + var buffers = ImportAndCreateBuffers(g); + + // This pass implicitly reads version 0 of extraBuffers[0] and writes its version 1 that will be implicitly read in the next pass - dependency + // It also explicitly reads version 0 of extraBuffers[1] and writes its version 1 but none reads it - no side effect + // It also implicitly reads version 0 of depthBuffer that is imported in RG but don't write it - no side effect + using (var builder = g.AddRasterRenderPass("TestPass0", out var passData)) + { + builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.ReadWrite); + builder.SetRenderAttachment(buffers.extraBuffers[1], 1, AccessFlags.Write); + builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Read); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + } + + // This pass implicitly reads version 1 of extraBuffers[1] and writes its version 2 that none reads - no side effect + // It also implicitly reads version 0 of extraBuffers[2] and writes its version 1 that will be explicitly read in the next pass - dependency + using (var builder = g.AddRasterRenderPass("TestPass1", out var passData)) + { + builder.SetRenderAttachment(buffers.extraBuffers[1], 1, AccessFlags.Write); + builder.SetRenderAttachment(buffers.extraBuffers[2], 2, AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + } + + // This pass explicitly reads version 1 of extraBuffers[2] + // We explicitly request this pass not to be culled, so it will be preserved + using (var builder = g.AddRasterRenderPass("TestPass2", out var passData)) + { + builder.SetRenderAttachment(buffers.extraBuffers[2], 2, AccessFlags.Read); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(false); + } - // Check Shading Rate Image index is correctly updated - Assert.IsTrue(passes[0].shadingRateImageIndex == buffers.extraTextures[0].handle.index); + var result = g.CompileNativeRenderGraph(g.ComputeGraphHash()); + var passes = result.contextData.GetNativePasses(); + + // - TestPass2 can NOT be culled + // - TestPass1 can NOT be culled as it is an explicit dependency of TestPass2 through extraBuffers[2] + // - TestPass0 can be culled as it is an implicit dependency of TestPass1 through extraBuffers[1] but none reads extraBuffers[1] so we can break this dependency + Assert.IsTrue(passes != null && passes.Count == 1 && passes[0].numGraphPasses == 2); + // extraBuffer[1] latest version remains at 2 but none writes version 1, it is okay since none reads it + Assert.AreEqual(result.contextData.UnversionedResourceData(passes[0].attachments[0].handle).latestVersionNumber, 2); + // extraBuffer[2] latest version remains at 1 + Assert.AreEqual(result.contextData.UnversionedResourceData(passes[0].attachments[1].handle).latestVersionNumber, 1); } */ + [Test] + public void UnusedResourceCulling_DoNotCullProducer_WhenOneOfItsWrittenResourcesIsExplicitlyRead() + { + var g = AllocateRenderGraph(); + var renderTargets = ImportAndCreateRenderTargets(g); + + // This pass implicitly reads version 0 of extraBuffers[0] and writes its version 1 that will be explicitly read in the next pass - dependency + // It also explicitly reads version 0 of extraBuffers[1] and writes its version 1 but none reads it - no side effect + // It also implicitly reads version 0 of depthBuffer that is imported in RG but don't write it - no side effect + using (var builder = g.AddRasterRenderPass("TestPass0", out var passData)) + { + builder.SetRenderAttachment(renderTargets.extraTextures[0], 0, AccessFlags.ReadWrite); + builder.SetRenderAttachment(renderTargets.extraTextures[1], 1, AccessFlags.Write); + builder.SetRenderAttachmentDepth(renderTargets.depthBuffer, AccessFlags.Read); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + } + + // This pass explicitly reads version 1 of extraBuffers[1] and writes its version 2 that none reads - no side effect + // It also implicitly reads version 0 of extraBuffers[2] and writes its version 1 that will be explicitly read in the next pass - dependency + using (var builder = g.AddRasterRenderPass("TestPass1", out var passData)) + { + builder.SetRenderAttachment(renderTargets.extraTextures[1], 1, AccessFlags.ReadWrite); + builder.SetRenderAttachment(renderTargets.extraTextures[2], 2, AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + } + + // This pass explicitly reads version 1 of extraBuffers[2] + // We explicitly request this pass not to be culled, so it will be preserved + using (var builder = g.AddRasterRenderPass("TestPass2", out var passData)) + { + builder.SetRenderAttachment(renderTargets.extraTextures[2], 2, AccessFlags.Read); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(false); + } + + var result = g.CompileNativeRenderGraph(g.ComputeGraphHash()); + var passes = result.contextData.GetNativePasses(); + + // All passes are preserved, + // - TestPass2 can't be culled + // - TestPass1 is an explicit dependency of TestPass2 through extraBuffers[2] + // - TestPass0 is an explicit dependency of TestPass1 through extraBuffers[1] + Assert.IsTrue(passes != null && passes.Count == 1 && passes[0].numGraphPasses == 3); + // depth last version is 0 + Assert.AreEqual(result.contextData.UnversionedResourceData(passes[0].attachments[0].handle).latestVersionNumber, 0); + // extraBuffer[0] latest version remains at 1 + Assert.AreEqual(result.contextData.UnversionedResourceData(passes[0].attachments[1].handle).latestVersionNumber, 1); + // extraBuffer[1] latest version remains at 2 + Assert.AreEqual(result.contextData.UnversionedResourceData(passes[0].attachments[2].handle).latestVersionNumber, 2); + // extraBuffer[2] latest version remains at 1 + Assert.AreEqual(result.contextData.UnversionedResourceData(passes[0].attachments[3].handle).latestVersionNumber, 1); + } + + [Test] + public void UnusedResourceCulling_CullProducer_WhenNextVersionOfProducedResourceIsWrittenAll() + { + var g = AllocateRenderGraph(); + var renderTargets = ImportAndCreateRenderTargets(g); + + // This pass implicitly reads version 0 of extraBuffers[0] and writes its version 1 that will be explicitly read in the next pass - dependency + using (var builder = g.AddRasterRenderPass("TestPass0", out var passData)) + { + builder.SetRenderAttachment(renderTargets.extraTextures[0], 0, AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + } + + // This pass explicitly reads version 1 of extraBuffers[0] - no side effect + using (var builder = g.AddRasterRenderPass("TestPass1", out var passData)) + { + builder.SetRenderAttachment(renderTargets.extraTextures[0], 0, AccessFlags.Read); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + } + + // This pass implicitly reads version 1 of extraBuffers[0] and writes its version 2 that will not be read in the next pass - no side effect + using (var builder = g.AddRasterRenderPass("TestPass2", out var passData)) + { + builder.SetRenderAttachment(renderTargets.extraTextures[0], 0, AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + } + + // This pass writes all version 3 of extraBuffers[2] + // We explicitly request this pass not to be culled, so it will be preserved + using (var builder = g.AddRasterRenderPass("TestPass3", out var passData)) + { + builder.SetRenderAttachment(renderTargets.extraTextures[0], 0, AccessFlags.WriteAll); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(false); + } + + var result = g.CompileNativeRenderGraph(g.ComputeGraphHash()); + var passes = result.contextData.GetNativePasses(); + + // Only last pass is preserved + // - TestPass3 can't be culled + // - TestPass2 can be culled as it is has no side effect and writes extraBuffers[0] at version 2 that none reads as TestPass3 rewrites all of extraBuffers[0] + // - TestPass1 can be culled as it is has no side effect and only reads extraBuffers[0] + // - TestPass0 can be culled as it is an implicit dependency of TestPass1 through extraBuffers[0] but TestPass1 will be culled + Assert.IsTrue(passes != null && passes.Count == 1 && passes[0].numGraphPasses == 1); + // extraBuffer[0] latest version remains at 2 + Assert.AreEqual(result.contextData.UnversionedResourceData(passes[0].attachments[0].handle).latestVersionNumber, 3); + } + // Test using a texture as both a texture and render attachment, one will require topleft and one bottom left so this should throw. [Test] public void TextureUVOrigin_CheckInvalidMixedUVOriginUseTextureCompiler() @@ -1777,4 +2105,4 @@ public void TextureUVOrigin_CheckInvalidMixedUVOriginDirect_InputCheck() } } } -} +} \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo1.png b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo1.png index c280c693446..24afa0d13be 100644 Binary files a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo1.png and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo1.png differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo2.png b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo2.png index ada6d4592be..e349f2a65ce 100644 Binary files a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo2.png and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo2.png differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo3.png b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo3.png index 579e8bc92ad..35b2971e64e 100644 Binary files a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo3.png and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo3.png differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo4.png b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo4.png index 5282b9facf4..ace602cfc02 100644 Binary files a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo4.png and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo4.png differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo5.png b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo5.png index b08422451f0..87c3686fa95 100644 Binary files a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo5.png and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo5.png differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo6.png b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo6.png index bd163280333..64cc9d01b5e 100644 Binary files a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo6.png and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ReflectionProbeGizmo6.png differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/render-graph-viewer-hdrp.png b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/render-graph-viewer-hdrp.png new file mode 100644 index 00000000000..e2ae2c42f0e Binary files /dev/null and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/render-graph-viewer-hdrp.png differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/render-graph-viewer-icon-acceleration-structure.png b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/render-graph-viewer-icon-acceleration-structure.png new file mode 100644 index 00000000000..80bba685a27 Binary files /dev/null and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/render-graph-viewer-icon-acceleration-structure.png differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/render-graph-viewer-icon-buffer.png b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/render-graph-viewer-icon-buffer.png new file mode 100644 index 00000000000..f8a9efe7eb8 Binary files /dev/null and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/render-graph-viewer-icon-buffer.png differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/render-graph-viewer-icon-texture.png b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/render-graph-viewer-icon-texture.png new file mode 100644 index 00000000000..e85b2bfa981 Binary files /dev/null and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/render-graph-viewer-icon-texture.png differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Planar-Reflection-Probe.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Planar-Reflection-Probe.md index f53a0367676..13a8319aa90 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Planar-Reflection-Probe.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Planar-Reflection-Probe.md @@ -85,7 +85,7 @@ You can use Scene view gizmos to visually customize specific properties. | ![Blend Normal Distance boundary gizmo](Images/ReflectionProbeGizmo3.png) | **Blend Normal Distance boundary** | Provides Scene view handles that allow you to resize the boundary where pixels with a normal pointing away from the **Capture Position** don’t receive any influence from this Probe. | | ![Mirror Position gizmo](Images/ReflectionProbeGizmo4.png) | **Mirror Position** | Changes the behavior of the Move Tool so that it alters the **Mirror** **Position** property, rather than the **Position** of the **Transform**. | | ![Mirror Rotation gizmo](Images/ReflectionProbeGizmo5.png) | **Mirror Rotation** | Changes the behavior of the Rotate Tool so that it alters the **Mirror Rotation** property, rather than the **Rotation** of the **Transform**. | -| ![Chrome gizmo](Images/ReflectionProbeGizmo6.png) | **Chrome Gizmo**. | Displays a chrome quad to preview the probe's texture in the scene. | +| ![Chrome gizmo](Images/ReflectionProbeGizmo6.png) | **Chrome Gizmo** | Displays a chrome quad to preview the probe's texture in the scene. | ## Best practices diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Reflection-Probe.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Reflection-Probe.md index 65198ce07fe..4699980ce17 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Reflection-Probe.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Reflection-Probe.md @@ -86,7 +86,7 @@ You can use Scene view gizmos to visually customize specific properties. | **Gizmo** | **Property** | **Description** | | ------------------------------------------------------------ | ----------------------------------- | ------------------------------------------------------------ | -| ![Influence Volume boundary](Images/ReflectionProbeGizmo1.png) | **Influence Volume boundary**. | Provides Scene view handles that allow you to resize the boundaries of the [Influence Volume](#InfluenceVolume), which defines the area this Reflection Probe affects reflective Materials. Edits the **Box Size** or **Radius** value, depending on the **Shape** you select. | -| ![Blend Distance boundary](Images/ReflectionProbeGizmo2.png) | **Blend Distance boundary**. | Provides Scene view handles that allows you to alter the inward distance from the **Box Size** or **Radius** at which this Reflection Probe blends with other Reflection Probes. Its behavior depends on the [workflow mode](#Workflows) you are using. It scales all sides equally in **Normal** mode, scales just the side with the handle you control in **Advanced** mode. | -| ![Blend Normal Distance boundary](Images/ReflectionProbeGizmo3.png) | **Blend Normal Distance boundary**. | Provides Scene view handles that allow you to resize the boundary where pixels with a normal pointing away from the **Capture Position** don’t receive any influence from this Probe. | -| ![Capture Position](Images/ReflectionProbeGizmo4.png) | **Capture Position**. | Changes the behavior of the Move Tool so that it alters the **Capture Position** property, rather than the **Position** of the **Transform**. | +| ![Influence Volume boundary](Images/ReflectionProbeGizmo1.png) | **Influence Volume boundary** | Provides Scene view handles that allow you to resize the boundaries of the [Influence Volume](#InfluenceVolume), which defines the area this Reflection Probe affects reflective Materials. Edits the **Box Size** or **Radius** value, depending on the **Shape** you select. | +| ![Blend Distance boundary](Images/ReflectionProbeGizmo2.png) | **Blend Distance boundary** | Provides Scene view handles that allows you to alter the inward distance from the **Box Size** or **Radius** at which this Reflection Probe blends with other Reflection Probes. Its behavior depends on the [workflow mode](#Workflows) you are using. It scales all sides equally in **Normal** mode, scales just the side with the handle you control in **Advanced** mode. | +| ![Blend Normal Distance boundary](Images/ReflectionProbeGizmo3.png) | **Blend Normal Distance boundary** | Provides Scene view handles that allow you to resize the boundary where pixels with a normal pointing away from the **Capture Position** don’t receive any influence from this Probe. | +| ![Capture Position](Images/ReflectionProbeGizmo4.png) | **Capture Position** | Changes the behavior of the Move Tool so that it alters the **Capture Position** property, rather than the **Position** of the **Transform**. | diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/TableOfContents.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/TableOfContents.md index 437d65cd327..0d54da51e27 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/TableOfContents.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/TableOfContents.md @@ -243,7 +243,11 @@ * [Use the Rendering Debugger](use-the-rendering-debugger.md) * [Add controls to the Rendering Debugger](add-controls-to-the-rendering-debugger.md) * [Rendering and post-processing](rendering-and-post-processing.md) - * [Execution order reference](rendering-execution-order.md) + * [Render passes](render-passes-landing.md) + * [Render graph system](render-graph-introduction.md) + * [Analyze the render graph](render-graph-view.md) + * [Render Graph Viewer reference](render-graph-viewer-reference.md) + * [Execution order reference](rendering-execution-order.md) * [Understand post-processing](Post-Processing-Main.md) * [Anti-aliasing](Anti-Aliasing.md) * [Dynamic resolution](Dynamic-Resolution.md) @@ -309,7 +313,6 @@ * [Understand custom pass variables](AOVs.md) * [Manage a custom pass without a GameObject](Global-Custom-Pass-API.md) * [Injection points](Custom-Pass-Injection-Points.md) - * [Customize the High Definition Render Pipeline (HDRP)](render-graph.md) * [Test and debug rendering and post-processing](rendering-troubleshoot.md) * [Troubleshoot a custom pass](Custom-Pass-Troubleshooting.md) * [Troubleshoot a custom post-processing effect](rendering-troubleshoot-custom-post-processes.md) diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/canvas-master-stack-reference.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/canvas-master-stack-reference.md index efa077e5724..ce06104815a 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/canvas-master-stack-reference.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/canvas-master-stack-reference.md @@ -62,4 +62,4 @@ The following table describes the Surface options: [!include[](snippets/shader-properties/surface-options/material-type.md)] [!include[](snippets/shader-properties/surface-options/alpha-clipping.md)] - +[!include[](snippets/shader-properties/surface-options/disable-color-tint.md)] diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/render-graph-introduction.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/render-graph-introduction.md new file mode 100644 index 00000000000..81ccfdbf1a3 --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/render-graph-introduction.md @@ -0,0 +1,25 @@ +# Render graph system in HDRP + +The render graph system is a set of APIs from the [Core Scriptable Render Pipeline (SRP) package](https://docs.unity3d.com/Packages/com.unity.render-pipelines.core@latest). The High Definition Render Pipeline (HDRP) uses these APIs to create the render passes in the render pipeline. + +The render graph system automatically optimizes the graph to minimize the number of render passes, and the memory and bandwidth the render passes use. + +**Note:** Unlike in the Universal Render Pipeline (URP), you can't use the render graph system to write custom render passes in HDRP. Use [Custom Passes](Custom-Pass.md) instead. + +## How the render graph system optimizes rendering + +The render graph system does the following to optimize rendering: + +- Avoids allocating resources the frame doesn’t use. +- Removes render passes if the final frame doesn’t use their output. +- Optimizes GPU memory, for example by reusing allocated memory if a texture has the same properties as an earlier texture. +- Automatically synchronizes the compute and graphics GPU command queues, if compute shaders are used. + +On mobile platforms that use tile-based deferred rendering (TBDR), the render graph system can also merge multiple render passes into a single native render pass. A native render pass keeps textures in tile memory, rather than copying textures from the GPU to the CPU. As a result, HDRP uses less memory bandwidth and rendering time. + +To check how the render graph system optimizes rendering, refer to [Analyze the render graph](render-graph-view.md) + +## Additional resources + +- [Optimizing draw calls](reduce-draw-calls-landing-hdrp.md) +- [Reduce rendering work on the CPU](reduce-rendering-work-on-cpu.md) diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/render-graph-view.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/render-graph-view.md new file mode 100644 index 00000000000..360b4bf59bf --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/render-graph-view.md @@ -0,0 +1,63 @@ +--- +uid: hdrp-render-graph-view +--- +# Analyze the render graph in HDRP + +To analyze the render graph in HDRP, use the **Render Graph Viewer** window. + +The render graph is the optimized sequence of render passes the High Definition Render Pipeline (HDRP) steps through each frame. The Render Graph Viewer displays both built-in render passes and any [custom passes](Custom-Pass.md) you create. + +For more information about the **Render Graph Viewer** window, refer to [Render Graph Viewer window reference](render-graph-viewer-reference.md). + +## Open the Render Graph Viewer window + +Go to **Window** > **Analysis** > **Render Graph Viewer**. + +The **Render Graph Viewer** window displays the render graph for the active camera by default. To select another camera, use the dropdown in the toolbar. + + +## View the render graph for a build + +To connect the Render Graph Viewer window to a build, enable **Development Build** in the **Build Profiles** window when you build the project. If you build for WebGL or Universal Windows Platform (UWP), enable both **Development Build** and **Autoconnect Profiler**. + +After you build your project, follow these steps: + +1. Run your built project. +2. In the **Render Graph Viewer** window, select the **Target Selection** dropdown. The dropdown is set to **Editor** by default. +3. In the **Local** section, select your build. + +Your build appears in the **Local** section only if the build is running. + +## Example: Check how HDRP uses a resource + +You can use the resource access blocks next to a resource name to check how the render passes use the resource. + +![Render Graph Viewer example](Images/render-graph-viewer-hdrp.png) + +In this example, the **Ambient Occlusion** texture goes through the following stages: + +1. During the first 19 render passes between **Set Global Sky Texture** and **Temporal Denoise GTAO**, the texture doesn't exist. The resource assess blocks are dotted lines. + +2. The **Upsample GTAO** render pass creates the texture, and has write-only access to it. The resource access block is red. + +3. The next four render passes don't have access to the texture. The resource access blocks are gray. + +4. The **Deferred Lighting** render pass has read-only access to the texture. The resource access block is green. + +6. The **Forward (+ Emissive) Opaque** render pass has read-only access to the texture. The resource access block is green. + +7. Unity destroys the texture, because it's no longer needed. The resource access blocks are blank. + +## Check how HDRP optimized a render pass + +To check the details of a render pass, for example to find out why it's not a native render pass or a merged pass, do either of the following: + +- Select the render pass name to display the details in the Pass List. +- Below the render pass name, hover your cursor over the gray, blue, or flashing blue resource access overview block. + +For more information about displaying details of a render pass, refer to [Render Graph Viewer window reference](render-graph-viewer-reference.md). + +## Additional resources + +- [Optimizing draw calls](reduce-draw-calls-landing-hdrp.md) +- [Reduce rendering work on the CPU](reduce-rendering-work-on-cpu.md) diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/render-graph-viewer-reference.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/render-graph-viewer-reference.md new file mode 100644 index 00000000000..09ca879fee0 --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/render-graph-viewer-reference.md @@ -0,0 +1,153 @@ +--- +uid: hdrp-render-graph-viewer-reference +--- + +# Render Graph Viewer window reference for HDRP + +The **Render Graph Viewer** window displays the [render graph](render-graph-introduction.md) for the current scene in the High Definition Render Pipeline (HDRP). + +For more information about the **Render Graph Viewer** window, refer to [Analyze a render graph](render-graph-view.md). + +## Toolbar + +|**Control**|**Description**| +|-|-| +|**Refresh**|Selects whether to update the window automatically. The options are:
  • **Auto Update**: Updates the window automatically.
  • **Pause**: Doesn't update the window automatically.
| +|**Target Selection**|Selects which project the window connects to. For more information, refer to [View the render graph for a built project](render-graph-view.md#built-project). The options are:
  • **Editor**: Connects to the project in the Unity Editor.
  • **Local**: Connects to a built project on the same device.
  • **Remote**: Connects to a built project on a different device.
  • **Direct Connection**: Connects to an application through an IP address.
| +|**Camera**|Selects the camera to display the rendering loop for.| +|**Pass Filter**|Selects which render passes to display. For more information, refer to [Pass Filter dropdown](#pass-filter-property).| +|**Resource Filter**|Selects which resources to display. For more information, refer to [Resource Filter dropdown](#resource-filter-property).| +|**View Options**|Selects whether to display how the render pass stores and loads the resource in the main window.| + + +### Pass Filter dropdown + +|**Control**|**Description**| +|-|-| +|**Culled Passes**|Displays render passes that HDRP hasn't included in the render graph because they have no effect on the final image.| +|**Raster Passes**|Displays only raster render passes created using `renderGraph.AddRasterRenderPass`.| +|**Unsafe Passes**|Displays only render passes that use the `AddUnsafePass` API to use `CommandBuffer` interface APIs such as `SetRenderTarget`.| +|**Compute Passes**|Displays only compute render passes created using `renderGraph.AddComputePass`.| + + +### Resource Filter dropdown + +|**Control**|**Description**| +|-|-| +|**Imported Resources**|Displays only resources imported into the render graph using `ImportTexure`.| +|**Textures**|Displays only textures.| +|**Buffers**|Displays only buffers.| +|**Acceleration Structures**|Displays only acceleration structures used in compute render passes.| + +## Main window + +The main window is a timeline graph that displays the render passes in the render graph. It displays the following: + +- On the left, the list of resources the render passes use, in the order HDRP creates them. +- At the top, the list of render passes, in the order HDRP executes them. + +At the point where a render pass and a texture meet on the graph, a resource access block displays how the render pass uses the resource. The access block uses the following icons and colors: + +|**Access block icon or color**|**Description**| +|-|-| +|Dotted lines|The resource hasn't been created yet.| +|Green|The render pass has read-only access to the resource. The render pass can read the resource.| +|Red|The render pass has write-only access to the resource. The render pass can write to the resource.| +|Green and red|The render pass has read-write access to the resource. The render pass can read from or write to the resource.| +|Gray|The render pass can't access the resource.| +|Globe icon|The render pass sets the texture as a global resource. If the globe icon has a gray background, the resource was imported into the render graph as a `TextureHandle` object, and the pass uses the `SetGlobalTextureAfterPass` API.| +|**F**|The render pass can read the resource from on-chip GPU memory.| +|Blank|The resource has been deallocated in memory, so it no longer exists.| + +If you enable **View Options** > **Load Store Actions**, the access block displays triangles that represent how the render pass loads the resource (top-left) and stores the resource (bottom-right). The triangles use the following colors: + +|**Triangle color**|**Load or store action**| +|-|-| +|Blue|Clear| +|Green|Load| +|Red|Store| +|Gray|Don't Care| + +Select an access block to display the resource in the Resource List and the render pass in the Pass Inspector List. + +### Render passes + +|**Control**|**Description**| +|-|-| +|Render pass name|The name of the render pass. This name is set in the `AddRasterRenderPass` or `AddComputePass` method.| +|Merge bar|If HDRP merged this pass with other passes, the Render Graph Viewer displays a blue bar below the merged passes.| +|Resource access overview bar|When you select a render pass name, the resource access overview bar displays information about the pass you selected and related passes. Hover your cursor over an overview block for more information. Select an overview block to open the C# file for the render pass.

Overview blocks use the following colors:
  • White: The selected pass.
  • Gray: The pass isn't related to the selected pass.
  • Blue: The pass reads from or writes to a resource the selected pass uses.
  • Flashing blue: The pass reads from or writes to a resource the selected pass uses, and can be merged with the current pass.
| + +### Resources + +|**Property**|**Description**| +|-|-| +|Resource type|The type of the resource. Refer to the following screenshot.| +|Resource name|The resource name.| +|Imported resource|Displays a left-facing arrow if the resource is imported.| + +### Render graph viewer icons + +|**Icon**|**Description**| +|-|-| +|![Texture icon](Images/render-graph-viewer-icon-texture.png)|A texture.| +|![Acceleration structure icon](Images/render-graph-viewer-icon-acceleration-structure.png)|An acceleration structure.| +|![Buffer icon](Images/render-graph-viewer-icon-buffer.png)|A buffer.| + +## Resource List + +Select a resource in the Resource List to expand or collapse information about the resource. + +You can also use the Search bar to find a resource by name. + +|**Property**|**Description**| +|-|-| +|Resource name|The resource name.| +|Imported resource|Displays a left-facing arrow if the resource is imported.| +|**Size**|The resource size in pixels.| +|**Format**|The texture format. For more information about texture formats, refer to [GraphicsFormat](https://docs.unity3d.com/Documentation/ScriptReference/Experimental.Rendering.GraphicsFormat.html).| +|**Clear**|Displays **True** if HDRP clears the texture.| +|**BindMS**|Whether the texture is bound as a multisampled texture. For more information about multisampled textures, refer to [RenderTextureDescriptor.BindMS](https://docs.unity3d.com/ScriptReference/RenderTextureDescriptor-bindMS.html).| +|**Samples**|How many times Multisample Anti-aliasing (MSAA) samples the texture. Refer to [Anti-aliasing](anti-aliasing.md).| +|**Memoryless**|Displays **True** if the resource is stored in tile memory on mobile platforms that use tile-based deferred rendering (TBDR). For more information about TBDR, refer to [Render graph system introduction](render-graph-introduction.md).| + +## Pass List + +Select a render pass in the main window to display information about the render pass in the Pass List. + +You can also use the Search bar to find a render pass by name. + +|**Property**|**Description**| +|-|-| +|Pass name|The render pass name. If HDRP merged multiple passes, this property displays the names of all the merged passes.| +|**Native Render Pass Info**|Displays information about whether HDRP created a native render pass for this render pass by merging multiple render passes. For more information about native render passes, refer to [Introduction to the render graph system](render-graph-introduction.md).| +|**Pass break reasoning**|Displays the reasons why HDRP could not merge this render pass with the next render pass. | + +### Render Graph Pass Info + +The **Render Graph Pass Info** section displays information about the render pass, and each of the resources it uses. + +If HDRP merged multiple passes into this pass, the section displays information for each merged pass. + +|**Property**|**Description**| +|-|-| +|**Name**|The render pass name.| +|**Attachment dimensions**|The size of a resource the render pass uses, in pixels. Displays **0x0x0** if the render pass doesn't use a resource.| +|**Has depth attachment**|Whether the resource has a depth texture.| +|**MSAA samples**|How many times Multisample Anti-aliasing (MSAA) samples the texture. Refer to [Anti-aliasing](anti-aliasing.md). | +|**Async compute**|Whether the render pass accesses the resource using a compute shader.| + +### Attachments Load/Store Actions + +The **Attachments Load/Store Actions** section displays the resources the render pass uses. The section displays **No attachments** if the render pass doesn't use any resources. + +|**Property**|**Description**| +|-|-| +|**Name**|The resource name.| +|**Load Action**|The load action for the resource. Refer to [`RenderBufferLoadAction`](https://docs.unity3d.com/ScriptReference/Rendering.RenderBufferLoadAction.html).| +|**Store Action**|The store action for the resource, and how HDRP uses the resource later in another render pass or outside the graph. Refer to [`RenderBufferStoreAction`](https://docs.unity3d.com/ScriptReference/Rendering.RenderBufferStoreAction.html).| + +## Additional resources + +- [Frame Debugger](https://docs.unity3d.com/Manual/frame-debugger-window.html) +- [Optimization](Optimization.md) diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/render-graph.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/render-graph.md deleted file mode 100644 index 1b63f398632..00000000000 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/render-graph.md +++ /dev/null @@ -1,4 +0,0 @@ -# Customize the High Definition Render Pipeline (HDRP) - -The High Definition Render Pipeline (HDRP) uses the [render graph system](https://docs.unity3d.com/Packages/com.unity.render-pipelines.core@latest/index.html?subfolder=/manual/render-graph-system.html) in its implementation. This means that if you want to extend HDRP and implement your own render pipeline features, you need to learn how the render graph system works and how to write rendering code using it. For information on the render graph system and how to use it to write render pipeline features, see the [render graph system](https://docs.unity3d.com/Packages/com.unity.render-pipelines.core@latest/index.html?subfolder=/manual/render-graph-system.html) documentation. - diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/render-passes-landing.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/render-passes-landing.md new file mode 100644 index 00000000000..93997068be7 --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/render-passes-landing.md @@ -0,0 +1,19 @@ +--- +uid: hdrp-render-passes +--- +# Render passes in HDRP + +Explore the sequence of render passes in the High Definition Render Pipeline (HDRP) and how to analyze them. + +|**Topic**|**Description**| +|-|-| +|[Render graph system in HDRP](render-graph-introduction.md)|What the render graph system is, and how it optimizes rendering.| +|[Analyze the render graph](render-graph-view.md)|Analyze the sequence of render passes in HDRP using the Render Graph Viewer.| +|[Render Graph Viewer window reference](render-graph-viewer-reference.md)|Reference for the **Render Graph Viewer** window.| +|[Execution order reference](rendering-execution-order.md)|Learn the order in which HDRP executes render passes.| + +## Additional resources + +- [Frame Debugger](https://docs.unity3d.com/Manual/frame-debugger-window.html) +- [Use the Rendering Debugger](use-the-rendering-debugger.md) + diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/rendering-and-post-processing.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/rendering-and-post-processing.md index b2e7215b017..1583248ce6b 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/rendering-and-post-processing.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/rendering-and-post-processing.md @@ -4,7 +4,7 @@ Control how the High Definition Render Pipeline (HDRP) renders a scene and apply |Page|Description| |-|-| -|[Execution order reference](rendering-execution-order.md)|Learn the order in which HDRP executes render passes.| +|[Render passes](render-passes-landing.md)|Learn about and analyze the sequence of render passes in HDRP.| |[Understand post-processing](Post-Processing-Main.md)|Learn how HDRP performs post-processing.| |[Anti-aliasing](Anti-Aliasing.md)|Use an antialiasing method to reduce the appearance of jagged edges.| |[Dynamic resolution](Dynamic-Resolution.md)|Change the screen resolution automatically to maintain a stable frame rate.| @@ -16,6 +16,5 @@ Control how the High Definition Render Pipeline (HDRP) renders a scene and apply |[Motion effects](motion-effects.md)|Apply effects to simulate the appearance of objects moving at speed.| |[Runtime effects](runtime-effects.md)|Use HDRP's API to control properties in a script at runtime.| |[Custom rendering effects](Custom-rendering.md)|Create an effect in a script and control when and how HDRP renders it.| -|[Customize the High Definition Render Pipeline (HDRP)](render-graph.md)|Uses the [render graph system](https://docs.unity3d.com/Packages/com.unity.render-pipelines.core@latest/index.html?subfolder=/manual/render-graph-system.html) to add render pipeline features to HDRP.| |[Troubleshoot rendering and post-processing issues]()|Fix common issues with custom effects.| diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/snippets/shader-properties/surface-options/disable-color-tint.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/snippets/shader-properties/surface-options/disable-color-tint.md new file mode 100644 index 00000000000..a49f8f41d2c --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/snippets/shader-properties/surface-options/disable-color-tint.md @@ -0,0 +1,6 @@ + +Disable Color Tint +N/A +N/A +Prevents Shader Graph tinting the texture with the color of the UI element. If you enable this setting, use a [Vertex Color Node](https://docs.unity3d.com/Packages/com.unity.shadergraph@latest/index.html?preview=1&subfolder=/manual/Vertex-Color-Node.html) to access the color of the UI element. + diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/ShaderGraph/Templates/Kernels/VertexSetup.template b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/ShaderGraph/Templates/Kernels/VertexSetup.template index 0491ebe992b..832b3a0aa24 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/ShaderGraph/Templates/Kernels/VertexSetup.template +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/ShaderGraph/Templates/Kernels/VertexSetup.template @@ -276,7 +276,7 @@ void VertexSetup (uint3 dispatchThreadID : SV_DispatchThreadID) { const uint i = dispatchThreadID.x; - if (i >= (uint)_VertexCount) + if ((_VertexOffset +i) >= (uint)_VertexCount) return; // Construct the input vertex. diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineEditor.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineEditor.cs index 6a02db0d08c..c2778b5f70a 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineEditor.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineEditor.cs @@ -18,9 +18,24 @@ sealed class HDRenderPipelineEditor : Editor internal ReorderableList reusableReorderableList; +#if ENABLE_UPSCALER_FRAMEWORK + internal UpscalerOptionsEditorCache upscalerOptionsEditorCache => m_UpscalerOptionsEditorCache; + UpscalerOptionsEditorCache m_UpscalerOptionsEditorCache; +#endif + void OnEnable() { m_SerializedHDRenderPipeline = new SerializedHDRenderPipelineAsset(serializedObject); +#if ENABLE_UPSCALER_FRAMEWORK + m_UpscalerOptionsEditorCache = new UpscalerOptionsEditorCache(); +#endif + } + + void OnDisable() + { +#if ENABLE_UPSCALER_FRAMEWORK + m_UpscalerOptionsEditorCache?.Cleanup(); +#endif } public override void OnInspectorGUI() diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs index a6bace5bf55..75cc2e4d7b6 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs @@ -893,9 +893,10 @@ uint GUIIndexToPresetValue(uint presetBitmask, uint index) ++EditorGUI.indentLevel; bool optionsChanged = false; + HDRenderPipelineEditor hdrpEditor = owner as HDRenderPipelineEditor; // O(N^2) IUpscaler name comparison but typical use case is <6 entries w/ each entry around 20B of char data - for(int i=0; i< serialized.renderPipelineSettings.dynamicResolutionSettings.advancedUpscalerNames.arraySize; ++i) + for (int i = 0; i < serialized.renderPipelineSettings.dynamicResolutionSettings.advancedUpscalerNames.arraySize; ++i) { string advancedUpscalerName = serialized.renderPipelineSettings.dynamicResolutionSettings.advancedUpscalerNames.GetArrayElementAtIndex(i).stringValue; @@ -910,31 +911,40 @@ uint GUIIndexToPresetValue(uint presetBitmask, uint index) EditorGUILayout.LabelField(upscalerOptions.UpscalerName, EditorStyles.boldLabel); ++EditorGUI.indentLevel; - // injection point selection (common to all IUpscalers) - int injectionPointBefore = (int)upscalerOptions.InjectionPoint; - int injectionPointSelection = EditorGUILayout.IntPopup(Styles.IUpscalerInjectionPoint, (int)upscalerOptions.InjectionPoint, Styles.UpscalerInjectionPointNames, Styles.UpscalerInjectionPointValues); - bool injectionPointChanged = injectionPointBefore != injectionPointSelection; - if (injectionPointChanged) - upscalerOptions.InjectionPoint = (DynamicResolutionHandler.UpsamplerScheduleType)injectionPointSelection; - - // draw rest of the options - bool optionsChangedOnThisUpscaler = upscalerOptions.DrawOptionsEditorGUI(); + Debug.Assert(hdrpEditor != null); + Editor editor = hdrpEditor.upscalerOptionsEditorCache.GetOrCreateEditor(upscalerOptions); + if (editor != null) + { + //------------------------------------------------------------------------------------------------------------------------ + // Edge Case: Manually draw the "InjectionPoint" property. + // It is hidden by default to serve URP requirements. + // When URP supports injection points, this snippet can be safely removed + SerializedProperty injectionPointProp = editor.serializedObject.FindProperty("m_InjectionPoint"); + if (injectionPointProp != null) + { + EditorGUILayout.PropertyField(injectionPointProp); + editor.serializedObject.ApplyModifiedProperties(); + } + //------------------------------------------------------------------------------------------------------------------------ - optionsChanged = optionsChanged || injectionPointChanged || optionsChangedOnThisUpscaler; + editor.OnInspectorGUI(); + } --EditorGUI.indentLevel; - } - } + + } // foreach upscaler option + } // foreach advanced upscaler name --EditorGUI.indentLevel; - if(optionsChanged) + if (optionsChanged) { EditorUtility.SetDirty(HDRenderPipeline.currentAsset); } } #endif #endregion + EditorGUILayout.PropertyField(serialized.renderPipelineSettings.dynamicResolutionSettings.dynamicResType, Styles.dynResType); bool isHwDrs = (serialized.renderPipelineSettings.dynamicResolutionSettings.dynamicResType.intValue == (int)DynamicResolutionType.Hardware); bool gfxDeviceSupportsHwDrs = HDUtils.IsHardwareDynamicResolutionSupportedByDevice(SystemInfo.graphicsDeviceType); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsCamera.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsCamera.cs index 46509f724a9..d84ccbe9e4c 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsCamera.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsCamera.cs @@ -10,29 +10,8 @@ class DebugDisplaySettingsCamera : IDebugDisplaySettingsData [Serializable] public class FrameSettingsDebugData { - private Camera m_SelectedCamera; - public Camera selectedCamera - { - get - { -#if UNITY_EDITOR - if (m_SelectedCamera == null && UnityEditor.SceneView.lastActiveSceneView != null) - { - var sceneCamera = UnityEditor.SceneView.lastActiveSceneView.camera; - if (sceneCamera != null) - m_SelectedCamera = sceneCamera; - } -#endif - return m_SelectedCamera; - } - set - { - if (value != null && value != m_SelectedCamera) - { - m_SelectedCamera = value; - } - } - } + public Camera selectedCamera { get; set; } + public Dictionary registeredCameras = new (); } @@ -98,8 +77,8 @@ public static DebugUI.CameraSelector CreateCameraSelector(SettingsPanel panel, getter = () => panel.data.frameSettingsData.selectedCamera, setter = value => { - if (value is Camera cam && value != panel.data.frameSettingsData.selectedCamera) - panel.data.frameSettingsData.selectedCamera = cam; + if (value != panel.data.frameSettingsData.selectedCamera) + panel.data.frameSettingsData.selectedCamera = value as Camera; }, onValueChanged = refresh }; @@ -134,6 +113,12 @@ public SettingsPanel(DebugDisplaySettingsCamera data) : base(data) { m_CameraSelector = WidgetFactory.CreateCameraSelector(this, (_, __) => Refresh()); + + // Select first camera if none is selected + var availableCameras = m_CameraSelector.getObjects() as List; + if (data.frameSettingsData.selectedCamera == null && availableCameras is { Count: > 0 }) + data.frameSettingsData.selectedCamera = availableCameras[0]; + AddWidget(m_CameraSelector); if (GetOrCreateFrameSettingsWidgets(out var frameSettingsWidgets)) diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightEvaluation.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightEvaluation.hlsl index 1b8a20ce70c..b4c5c59a837 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightEvaluation.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightEvaluation.hlsl @@ -408,18 +408,27 @@ float4 EvaluateCookie_Punctual(LightLoopContext lightLoopContext, LightData ligh float z = positionLS.z; float r = light.range; + cookie.a = 1.0; // Box lights have no range attenuation, so we must clip manually. - bool isInBounds = Max3(abs(positionCS.x), abs(positionCS.y), abs(z - 0.5 * r) - 0.5 * r + 1) <= light.boxLightSafeExtent; - if (lightType != GPULIGHTTYPE_PROJECTOR_PYRAMID && lightType != GPULIGHTTYPE_PROJECTOR_BOX) + if ( Max3(abs(positionCS.x), abs(positionCS.y), abs(z - 0.5 * r) - 0.5 * r + 1) > light.boxLightSafeExtent ) { - isInBounds = isInBounds && (dot(positionCS, positionCS) <= light.iesCut * light.iesCut); + cookie.a = 0.0; + } + else + { + if (lightType != GPULIGHTTYPE_PROJECTOR_PYRAMID && lightType != GPULIGHTTYPE_PROJECTOR_BOX) + { + float iesCut = light.iesCut; + if (dot(positionCS, positionCS) > (iesCut * iesCut)) + { + cookie.a = 0; + } + } } - float2 positionNDC = positionCS * 0.5 + 0.5; // Manually clamp to border (black). cookie.rgb = SampleCookie2D(positionNDC, light.cookieScaleOffset, lod); - cookie.a = isInBounds ? 1.0 : 0.0; } #else diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/TemporalAntialiasing.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/TemporalAntialiasing.hlsl index 70de30c7f4a..84ea023e00a 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/TemporalAntialiasing.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/TemporalAntialiasing.hlsl @@ -491,11 +491,8 @@ void VarianceNeighbourhood(inout NeighbourhoodSamples samples, float historyLuma // and high temporal contrast, we let the history to be closer to be unclipped. To achieve, the min/max bounds // are extended artificially more. #if ANTI_FLICKER - stDevMultiplier = 1.5; - - float aggressiveStdDevLuma = GetLuma(stdDev)* 0.5; + float aggressiveStdDevLuma = GetLuma(stdDev) * 0.5; aggressiveClampedHistoryLuma = clamp(historyLuma, GetLuma(moment1) - aggressiveStdDevLuma, GetLuma(moment1) + aggressiveStdDevLuma); - float temporalContrast = saturate(abs(colorLuma - aggressiveClampedHistoryLuma) / Max3(0.15, colorLuma, aggressiveClampedHistoryLuma)); #if ANTI_FLICKER_MV_DEPENDENT const float maxFactorScale = 2.25f; // when stationary const float minFactorScale = 0.8f; // when moving more than slightly @@ -508,6 +505,7 @@ void VarianceNeighbourhood(inout NeighbourhoodSamples samples, float historyLuma #if TEMPORAL_CONTRAST // TODO: Because we use a very aggressivley clipped history to compute the temporal contrast (hopefully cutting a chunk of ghosting) // can we be more aggressive here, being a bit more confident that the issue is from flickering? To investigate. + float temporalContrast = saturate(abs(colorLuma - aggressiveClampedHistoryLuma) / Max3(0.15, colorLuma, aggressiveClampedHistoryLuma)); stDevMultiplier += lerp(0.0, localizedAntiFlicker, smoothstep(0.05, antiFlickerParams.y, temporalContrast)); #else stDevMultiplier += localizedAntiFlicker; diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineGlobalSettings.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineGlobalSettings.cs index 7568959746d..e7738fe3679 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineGlobalSettings.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineGlobalSettings.cs @@ -112,9 +112,10 @@ public override void Initialize(RenderPipelineGlobalSettings source = null) if (TryGet(typeof(LookDevVolumeProfileSettings), out var lookDevSettings) && lookDevSettings is LookDevVolumeProfileSettings lookDevVolumeProfileSettings && + lookDevVolumeProfileSettings.volumeProfile == null && assets != null) { - lookDevVolumeProfileSettings.volumeProfile ??= VolumeUtils.CopyVolumeProfileFromResourcesToAssets(assets.lookDevVolumeProfile); + lookDevVolumeProfileSettings.volumeProfile = VolumeUtils.CopyVolumeProfileFromResourcesToAssets(assets.lookDevVolumeProfile); } } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/LineRendering/Kernels/StageRasterBin.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/LineRendering/Kernels/StageRasterBin.compute index 9820af44684..0825ed4f0c2 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/LineRendering/Kernels/StageRasterBin.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/LineRendering/Kernels/StageRasterBin.compute @@ -52,7 +52,8 @@ void RecordIntersection(Wave wave, bool intersects, uint2 coord, SegmentRecord s { const float depthVS = lerp(segment.depthVS0, segment.depthVS1, t); - const uint clusterDepth = floor(log10(depthVS) * gs_ClusteringCoefficients.x - gs_ClusteringCoefficients.y); + int clusterDepth = floor(log10(depthVS) * gs_ClusteringCoefficients.x - gs_ClusteringCoefficients.y); + clusterDepth = clamp(clusterDepth,0,(_ClusterDepth-1)); const uint clusterIndex = (coord.y * (uint)_DimBin.x + coord.x) + ((uint)_DimBin.x * (uint)_DimBin.y * clusterDepth); const uint waveOffset = wave.PrefixCountBits(intersects); @@ -73,20 +74,20 @@ void RecordIntersection(Wave wave, bool intersects, uint2 coord, SegmentRecord s // Normalize the cluster depth for more precision in the 10-bit encoded version const float segmentSortKey = NormalizeClusterDepth(depthVS, clusterDepth); - if (!intersects) - return; - - uint clusterOffset; - _ClusterCountersBuffer.InterlockedAdd(clusterIndex << 2, intersects, clusterOffset); - - // Write back the record. - ClusterRecord record; + if (intersects) { - record.segmentIndex = PackFloatToUInt(segmentSortKey, 24, 8) | segmentIndex; - record.clusterIndex = clusterIndex; - record.clusterOffset = clusterOffset; + uint clusterOffset; + _ClusterCountersBuffer.InterlockedAdd(clusterIndex << 2, 1, clusterOffset); + + // Write back the record. + ClusterRecord record; + { + record.segmentIndex = PackFloatToUInt(segmentSortKey, 24, 8) | segmentIndex; + record.clusterIndex = clusterIndex; + record.clusterOffset = clusterOffset; + } + _ClusterRecordBuffer[globalOffset+waveOffset] = record; } - _ClusterRecordBuffer[globalOffset + waveOffset] = record; } [numthreads(NUM_LANE_RASTER_BIN, 1, 1)] diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/LineRendering/Kernels/StageRasterFine.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/LineRendering/Kernels/StageRasterFine.compute index 6ef4c11e1eb..ba37c651d89 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/LineRendering/Kernels/StageRasterFine.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/LineRendering/Kernels/StageRasterFine.compute @@ -40,7 +40,11 @@ ByteAddressBuffer _BinCountersBuffer; ByteAddressBuffer _WorkQueueBuffer; ByteAddressBuffer _ClusterCountersBuffer; +#if defined (SHADER_API_SWITCH) || defined (SHADER_API_SWITCH2) +Texture2D _ShadingSamplesTexture; +#else Texture2D _ShadingSamplesTexture; +#endif // Outputs RW_TEXTURE2D_X(float4, _OutputTargetColor); @@ -501,7 +505,10 @@ void Main(Group group) break; // Note: Not all of these segments are guaranteed to exist in memory if greater than cluster segment count. - gs_SegmentBatch[groupIndex] = GetSegment(segmentBatchOffset + groupIndex); + if ( (segmentBatchOffset + groupIndex ) > 0 & 0xFFFF, - segmentIndicesCompressed >> 16 & 0xFFFF - ); -#endif - - // Load Vertices - const float4 positionCS0 = asfloat(_Vertex0RecordBuffer.Load4(segmentIndices.x << 4)); - const float4 positionCS1 = asfloat(_Vertex0RecordBuffer.Load4(segmentIndices.y << 4)); - - // Cull segments with degenerate vertices (could be produced by vertex shader). - if (AnyIsNaN(positionCS0) || AnyIsNaN(positionCS1)) - { - culled = true; - } - // Fast rejection for segments behind the near clipping plane. - if (positionCS0.w <= 0 || positionCS1.w <= 0) - { - culled = true; - } + Wave wave = group.GetWave(); + SegmentRecord record; - // Perspective divide. Homogenous -> NDC. - float3 positionNDC0 = positionCS0.xyz * rcp(positionCS0.w); - float3 positionNDC1 = positionCS1.xyz * rcp(positionCS1.w); + record.positionSS0 = float2(0,0); + record.positionSS1 = float2(0,0); + record.depthVS0 = 0; + record.depthVS1 = 0; + record.vertexIndex0 = 0; + record.vertexIndex1 = 0; - // Cohen-Sutherland algorithm to perform line segment clipping in NDC space. - if(!ClipSegmentCohenSutherland(positionNDC0.x, positionNDC0.y, positionNDC1.x, positionNDC1.y)) + if (!culled) { - culled = true; - } - - // NDC -> Screen Space. - const float2 positionSS0 = _ScreenSize.xy * (0.5 + 0.5 * positionNDC0.xy); - const float2 positionSS1 = _ScreenSize.xy * (0.5 + 0.5 * positionNDC1.xy); + + // Load Indices +#if INDEX_FORMAT_UINT_32 + const uint2 segmentIndices = _VertexOffset + _IndexBuffer. Load2(segmentIndex << 3); +#else + const uint segmentIndicesCompressed = _IndexBuffer.Load(segmentIndex << 2); - // Depth test against each segment vertex. - if(positionNDC1.z < LoadCameraDepth(float2(positionSS1.x, _ScreenSize.y - positionSS1.y)) && positionNDC0.z < LoadCameraDepth(float2(positionSS0.x, _ScreenSize.y - positionSS0.y))) - { - culled = true; - } + const uint2 segmentIndices = _VertexOffset + uint2 + ( + segmentIndicesCompressed >> 0 & 0xFFFF, + segmentIndicesCompressed >> 16 & 0xFFFF + ); +#endif - SegmentRecord record; - { - record.positionSS0 = positionSS0.xy; - record.positionSS1 = positionSS1.xy; - record.depthVS0 = LinearEyeDepth(positionNDC0.z, _ZBufferParams); - record.depthVS1 = LinearEyeDepth(positionNDC1.z, _ZBufferParams); - record.vertexIndex0 = segmentIndices.x; - record.vertexIndex1 = segmentIndices.y; + // Load Vertices + const float4 positionCS0 = asfloat(_Vertex0RecordBuffer.Load4(segmentIndices.x << 4)); + const float4 positionCS1 = asfloat(_Vertex0RecordBuffer.Load4(segmentIndices.y << 4)); + + // Cull segments with degenerate vertices (could be produced by vertex shader). + if (AnyIsNaN(positionCS0) || AnyIsNaN(positionCS1)) + { + culled = true; + } + + // Fast rejection for segments behind the near clipping plane. + if (positionCS0.w <= 0 || positionCS1.w <= 0) + { + culled = true; + } + + // Perspective divide. Homogenous -> NDC. + float3 positionNDC0 = positionCS0.xyz * rcp(positionCS0.w); + float3 positionNDC1 = positionCS1.xyz * rcp(positionCS1.w); + + // Cohen-Sutherland algorithm to perform line segment clipping in NDC space. + if(!ClipSegmentCohenSutherland(positionNDC0.x, positionNDC0.y, positionNDC1.x, positionNDC1.y)) + { + culled = true; + } + + // NDC -> Screen Space. + const float2 positionSS0 = _ScreenSize.xy * (0.5 + 0.5 * positionNDC0.xy); + const float2 positionSS1 = _ScreenSize.xy * (0.5 + 0.5 * positionNDC1.xy); + + // Depth test against each segment vertex. + if(positionNDC1.z < LoadCameraDepth(float2(positionSS1.x, _ScreenSize.y - positionSS1.y)) && positionNDC0.z < LoadCameraDepth(float2(positionSS0.x, _ScreenSize.y - positionSS0.y))) + { + culled = true; + } + + if (!culled) + { + record.positionSS0 = positionSS0.xy; + record.positionSS1 = positionSS1.xy; + record.depthVS0 = LinearEyeDepth(positionNDC0.z, _ZBufferParams); + record.depthVS1 = LinearEyeDepth(positionNDC1.z, _ZBufferParams); + record.vertexIndex0 = segmentIndices.x; + record.vertexIndex1 = segmentIndices.y; + } } - Wave wave = group.GetWave(); - // Compute the minimum and maximum view space depths (needed for clustering). UpdateDepthRange(wave, record, !culled); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/LineRendering/Kernels/StageWorkQueue.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/LineRendering/Kernels/StageWorkQueue.compute index c87b5c025c5..025a4534aa6 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/LineRendering/Kernels/StageWorkQueue.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/LineRendering/Kernels/StageWorkQueue.compute @@ -48,17 +48,18 @@ void WorkQueueBuild(uint3 dispatchThreadID : SV_DispatchThreadID, uint groupInde const uint i = dispatchThreadID.x; - if (i >= g_RecordCount) - return; - - // Load the record for this index. - const ClusterRecord record = _ClusterRecordBuffer[i]; - - // Compute the new index into the work queue. - uint workQueueIndex = _BinOffsetsBuffer.Load(record.clusterIndex << 2) + record.clusterOffset; - - // Write the bin segment into the work queue at this index. - _WorkQueueBuffer.Store(workQueueIndex << 2, record.segmentIndex); + if (i < (g_RecordCount)) + { + // Load the record for this index. + const ClusterRecord record = _ClusterRecordBuffer[i]; + uint index = (record.clusterIndex<<2); + + // Compute the new index into the work queue. + uint workQueueIndex = _BinOffsetsBuffer.Load(index) + record.clusterOffset; + + // Write the bin segment into the work queue at this index. + _WorkQueueBuffer.Store(workQueueIndex << 2, record.segmentIndex); + } } #define THREADING_BLOCK_SIZE 1024 diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/LineRendering/ShaderPass/LineRenderingOffscreenShading.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/LineRendering/ShaderPass/LineRenderingOffscreenShading.hlsl index 35d5c8d8fbe..08da432ef5b 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/LineRendering/ShaderPass/LineRenderingOffscreenShading.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/LineRendering/ShaderPass/LineRenderingOffscreenShading.hlsl @@ -62,38 +62,40 @@ void OffscreenShadingFillFragInputs(uint2 positionViewport, inout FragInputs out if (sampleIndex == INVALID_SHADING_SAMPLE) discard; - - const uint vertexID = _VertexOffset + sampleIndex; - - const float4 positionCS = asfloat(_Vertex0RecordBuffer.Load4(vertexID << 4)); - const float4 encodedFrame = asfloat(_Vertex2RecordBuffer.Load4(vertexID << 4)); - - const float3 N = UnpackNormalOctQuadEncode(encodedFrame.xy); - const float3 T = UnpackNormalOctQuadEncode(encodedFrame.zw); - - float4 texcoord; -#ifdef FRAG_INPUTS_USE_TEXCOORD0 - uint unnormalizedPackedID = _Vertex3RecordBuffer.Load2(8 * vertexID); - - texcoord = float4 - ( - ((unnormalizedPackedID >> 0) & 0xFF) / 255.0, - ((unnormalizedPackedID >> 8) & 0xFF) / 255.0, - ((unnormalizedPackedID >> 16) & 0xFF) / 255.0, - ((unnormalizedPackedID >> 24) & 0xFF) / 255.0 - ); -#endif - - // Configure the fragment. + else { - output.tangentToWorld = BuildTangentToWorld(float4(T, 1), N); - output.positionRWS = ComputeWorldSpacePosition(positionCS, UNITY_MATRIX_UNJITTERED_I_VP); - output.positionSS = ClipSpaceToRasterSpacePosition(positionCS); - output.positionPixel = output.positionSS.xy; - output.isFrontFace = true; -#ifdef FRAG_INPUTS_USE_TEXCOORD0 - output.texCoord0 = texcoord; -#endif + const uint vertexID = _VertexOffset + sampleIndex; + + const float4 positionCS = asfloat(_Vertex0RecordBuffer.Load4(vertexID << 4)); + const float4 encodedFrame = asfloat(_Vertex2RecordBuffer.Load4(vertexID << 4)); + + const float3 N = UnpackNormalOctQuadEncode(encodedFrame.xy); + const float3 T = UnpackNormalOctQuadEncode(encodedFrame.zw); + + float4 texcoord; + #ifdef FRAG_INPUTS_USE_TEXCOORD0 + uint unnormalizedPackedID = _Vertex3RecordBuffer.Load2(8 * vertexID); + + texcoord = float4 + ( + ((unnormalizedPackedID >> 0) & 0xFF) / 255.0, + ((unnormalizedPackedID >> 8) & 0xFF) / 255.0, + ((unnormalizedPackedID >> 16) & 0xFF) / 255.0, + ((unnormalizedPackedID >> 24) & 0xFF) / 255.0 + ); + #endif + + // Configure the fragment. + { + output.tangentToWorld = BuildTangentToWorld(float4(T, 1), N); + output.positionRWS = ComputeWorldSpacePosition(positionCS, UNITY_MATRIX_UNJITTERED_I_VP); + output.positionSS = ClipSpaceToRasterSpacePosition(positionCS); + output.positionPixel = output.positionSS.xy; + output.isFrontFace = true; + #ifdef FRAG_INPUTS_USE_TEXCOORD0 + output.texCoord0 = texcoord; + #endif + } } #endif } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/PathTracing.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/PathTracing.cs index 77f8bb24ec9..a22091d0856 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/PathTracing.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/PathTracing.cs @@ -711,6 +711,12 @@ void RenderSkyBackground(RenderGraph renderGraph, HDCamera hdCamera, TextureHand // Override the exposure texture, as we need a neutral value for this render SetGlobalTexture(renderGraph, HDShaderIDs._ExposureTexture, m_EmptyExposureTexture); + // Parts of sky rendering may access shadowmap-related uniforms. + // In the full path tracing path, these uniforms won't actually be used, + // but they still need to be populated with neutral values, + // or we get errors about unpopulated uniforms. + HDShadowManager.BindDefaultShadowGlobalResources(renderGraph); + m_SkyManager.RenderSky(renderGraph, hdCamera, skyBuffer, CreateDepthBuffer(renderGraph, true, MSAASamples.None), "Render Sky Background for Path Tracing"); // Restore the regular exposure texture diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRenderPipeline.RaytracingReflection.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRenderPipeline.RaytracingReflection.cs index 75f665ecfae..ffea10d2c3a 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRenderPipeline.RaytracingReflection.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRenderPipeline.RaytracingReflection.cs @@ -448,7 +448,7 @@ DeferredLightingRTParameters PrepareReflectionDeferredLightingRTParameters(HDCam deferredParameters.raytracingCB._RayTracingRayMissUseAmbientProbeAsSky = 0; deferredParameters.raytracingCB._RayTracingLastBounceFallbackHierarchy = deferredParameters.lastBounceFallbackHierarchy; deferredParameters.raytracingCB._RayTracingAmbientProbeDimmer = settings.ambientProbeDimmer.value; - deferredParameters.raytracingCB._RaytracingAPVLayerMask = settings.adaptiveProbeVolumesLayerMask.value; + deferredParameters.raytracingCB._RaytracingAPVLayerMask = settings.adaptiveProbeVolumesLayerMask.value; return deferredParameters; } @@ -585,10 +585,10 @@ RayTracingReflectionsQualityOutput QualityRTR(RenderGraph renderGraph, HDCamera // Output textures passData.lightingTexture = renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true) - { format = GraphicsFormat.R16G16B16A16_SFloat, enableRandomWrite = true, name = "Ray Traced Reflections" }); + { format = GraphicsFormat.R16G16B16A16_SFloat, enableRandomWrite = true, name = "Ray Traced Reflections (Lighting + Weight)" }); builder.UseTexture(passData.lightingTexture, AccessFlags.Write); passData.distanceTexture = renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true) - { format = GraphicsFormat.R16G16B16A16_SFloat, enableRandomWrite = true, name = "Ray Traced Reflections" }); + { format = GraphicsFormat.R16_SFloat, enableRandomWrite = true, name = "Ray Traced Reflections (Ray Distances)" }); builder.UseTexture(passData.distanceTexture, AccessFlags.Write); passData.enableDecals = hdCamera.frameSettings.IsEnabled(FrameSettingsField.Decals); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/ReblurDenoiser.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/ReblurDenoiser.cs index 5b430917e2c..1ac93388c4b 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/ReblurDenoiser.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/ReblurDenoiser.cs @@ -402,7 +402,7 @@ public TextureHandle DenoiseIndirectSpecular(RenderGraph renderGraph, HDCamera h using (new ProfilingScope(ctx.cmd, ProfilingSampler.Get(HDProfileId.ReBlurMipHistoryFix))) { // Mini GBuffer - natCmd.SetComputeTextureParam(data.historyFixCS, data.historyFixKernel, HDShaderIDs._DepthTexture, data.depthBuffer); + natCmd.SetComputeTextureParam(data.historyFixCS, data.historyFixKernel, HDShaderIDs._DepthTexture, data.depthPyramidBuffer); natCmd.SetComputeTextureParam(data.historyFixCS, data.historyFixKernel, HDShaderIDs._NormalBufferTexture, data.normalBuffer); natCmd.SetComputeTextureParam(data.historyFixCS, data.historyFixKernel, _ReBlurMipChain, data.mipTexture); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_Blur.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_Blur.compute index 9bee8a57e7c..2cbf7de3c25 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_Blur.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_Blur.compute @@ -56,18 +56,19 @@ void Blur(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV // Evaluate the position and view vectors float3 viewWS = GetWorldSpaceNormalizeViewDir(center.position); - // Convert both directions to view space - float NdotV = abs(dot(center.normal, viewWS)); - // Get the dominant direction float4 dominantWS = GetSpecularDominantDirection(center.normal, viewWS, center.roughness); // Evaluate the blur radius float distanceToCamera = length(center.position); float blurRadius = ComputeBlurRadius(center.roughness, BLUR_MAX_RADIUS) * _ReBlurDenoiserRadius; - blurRadius *= (1.0 - saturate(accumulationFactor / MAX_ACCUM_FRAME_NUM)); + blurRadius *= lerp(1.0f, 0.1f, accumulationFactor / MAX_ACCUM_FRAME_NUM); blurRadius *= HitDistanceAttenuation(center.roughness, distanceToCamera, centerSignal.w); - blurRadius *= lerp(saturate((distanceToCamera - MIN_BLUR_DISTANCE) / BLUR_OUT_RANGE), 0.0, 1.0); + + // As the camera nears an object it becomes increasingly likely that the disc sample points + // land outside the view frustum, so we shrink radius accordingly to reduce the likelihood + // of this happening. + blurRadius *= saturate((distanceToCamera - MIN_BLUR_DISTANCE) / BLUR_OUT_RANGE); // Evalute the local basis float2x3 TvBv = GetKernelBasis(dominantWS.xyz, center.normal, center.roughness); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_HistoryFix.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_HistoryFix.compute index 8e6ea939be8..52af6afdfd2 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_HistoryFix.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_HistoryFix.compute @@ -36,7 +36,7 @@ void HistoryFix(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadI uint2 currentCoord = dispatchThreadId.xy; // Fetch the full resolution depth - float depthFR = LOAD_TEXTURE2D_X(_DepthTexture, currentCoord).x; + float depthFR = LOAD_TEXTURE2D_X(_DepthTexture, _DepthPyramidMipLevelOffsets[0] + currentCoord).x; // IF this is a background pixel, we have nothing to do here if (depthFR == UNITY_RAW_FAR_CLIP_VALUE) @@ -63,10 +63,8 @@ void HistoryFix(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadI NormalData normalData; DecodeFromNormalBuffer(currentCoord.xy, normalData); - // Grab the signal of the current frame - int mipLevel = (int)(MIP_LEVEL_COUNT * (1.0 - normAcc) * normalData.perceptualRoughness); + const int mipLevel = min(MIP_LEVEL_COUNT - 1, (1.0 - normAcc) * normalData.perceptualRoughness * MIP_LEVEL_COUNT); - // Now we need to loop through the LODs (going from the lowest to the highest until we have enough representative samples) float4 signalSum = 0.0; float weightSum = 0.0; int2 mipOffset = _DepthPyramidMipLevelOffsets[mipLevel]; @@ -75,7 +73,7 @@ void HistoryFix(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadI for (int x = -1; x <= 1; ++x) { // Evaluate the tap coordinate - int2 tapCoord = (currentCoord << mipLevel) + int2(x, y); + int2 tapCoord = (currentCoord >> mipLevel) + int2(x, y); // Read and linearize the depth float tapDepth = Linear01Depth(LOAD_TEXTURE2D_X(_DepthTexture, mipOffset + tapCoord).x, _ZBufferParams); @@ -83,7 +81,7 @@ void HistoryFix(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadI // Is the depth compatible with the full resolution depth float4 lightDistance = LOAD_TEXTURE2D_X_LOD(_ReBlurMipChain, tapCoord, mipLevel); if ((abs(tapDepth - linearDepth) < linearDepth * 0.1) && lightDistance.w >= 0.0) - { + { float weight = Gaussian(length(int2(x, y)), 1.0); signalSum += lightDistance * weight; weightSum += weight; diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_PreBlur.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_PreBlur.compute index 22f6dfe6a91..c3186157f81 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_PreBlur.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_PreBlur.compute @@ -185,7 +185,7 @@ void PreBlur(uint3 dispatchThreadId : SV_DispatchThreadID, } else { - // If we are + // If we are #if defined(HALF_RESOLUTION) float4 fallbackLighting = 0.0; float weightSum = 0.0; @@ -227,7 +227,7 @@ void PreBlur(uint3 dispatchThreadId : SV_DispatchThreadID, #else fallbackLighting += float4(LOAD_TEXTURE2D_X(_LightingInputTexture, halfResCoord).xyz, LOAD_TEXTURE2D_X(_DistanceInputTexture, halfResCoord).x) * weight; #endif - weightSum += weight; + weightSum += weight; } } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_TemporalAccumulation.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_TemporalAccumulation.compute index 4150db65190..9412d0bde5b 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_TemporalAccumulation.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_TemporalAccumulation.compute @@ -83,7 +83,7 @@ void TemporalAccumulation(uint3 currentCoord : SV_DispatchThreadID, // Compute N dot V float NdotV = abs(dot(normalData.normalWS, viewWS)); - + // Surface motion history (the disocclusion code guarantees that the reprojected surface motion is inside the viewport and is an equivalent point) float2 historyUVUnscaled; float2 historySurfaceMotionCoord; @@ -146,7 +146,7 @@ void TemporalAccumulation(uint3 currentCoord : SV_DispatchThreadID, float4 virtualLightingDistance; virtualLightingDistance.xyz = lerp(virtualHistory.xyz, lightingDistance.xyz, 1/(1 + Avirt)); virtualLightingDistance.w = lerp(virtualHistory.w, lightingDistance.w, 1/(1 + Ahitdist)); - + // Mix surface and virtual motion-based combined specular // signals into the final result. float4 currentResult = lerp(surfaceLightingDistance, virtualLightingDistance, amount); @@ -157,7 +157,6 @@ void TemporalAccumulation(uint3 currentCoord : SV_DispatchThreadID, float Acurr = 1.0 / a - 1.0; } - // Normalize the result _LightingDistanceTextureRW[COORD_TEXTURE2D_X(currentCoord.xy)] = surfaceLightingDistance; _AccumulationTextureRW[COORD_TEXTURE2D_X(currentCoord.xy)] = accumulationFactor; } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_TemporalStabilization.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_TemporalStabilization.compute index a1701a975b0..23d645840c1 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_TemporalStabilization.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_TemporalStabilization.compute @@ -168,7 +168,7 @@ void TemporalStabilization(uint3 dispatchThreadId : SV_DispatchThreadID, int gro // Compute the neighborhood index int nIndex = (x + 1) + (y + 1) * 3; nIndex = nIndex > 4 ? nIndex - 1 : nIndex; - + // If this is a background pixel or one that doesn't have SSR or is Unlit we can't use it if (gs_cacheDepth[tapLDSIndex] == UNITY_RAW_FAR_CLIP_VALUE || !gs_cacheValidity[tapLDSIndex] @@ -188,6 +188,17 @@ void TemporalStabilization(uint3 dispatchThreadId : SV_DispatchThreadID, int gro // Clip the history prevSignal = GetClippedHistory(nbSamples.central, prevSignal, nbSamples.minNeighbour, nbSamples.maxNeighbour); + // Variance neighbourhood clipping works great when the associated "color box" is relatively small. + // However, this is not necessarily the case for perfect mirrors: Neighbouring pixels in screen space + // may differ by an arbitrary amount, even with many ray tracing samples. This means that the color box + // can be huge and thus neighbourhood clipping will do nothing, not even if the overall input signal + // changes (UUM-103701). Therefore, mirrors cannot rely _only_ on neighbourhood clipping. + // We fix this by using a bit of the input signal proportional to how smooth the pixel is. + // This is only an imperfect heuristic and can theoretically increase temporal noise in extreme cases, + // but it is preferable to no updates at all. + const float maxRoughness = 0.06f; // Empirically chosen. + prevSignal = lerp(nbSamples.central, prevSignal, smoothstep(0.0f, maxRoughness, normalData.perceptualRoughness)); + // Move back to the output space prevSignal.xyz = ConvertToOutputSpace(prevSignal.xyz); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_Utilities.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_Utilities.hlsl index c0b76253edf..8da9e859e91 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_Utilities.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_Utilities.hlsl @@ -7,7 +7,7 @@ // Accumulation loop is done on 32 frames #define MAX_ACCUM_FRAME_NUM 32.0 -#define MIP_LEVEL_COUNT 4.0 +#define MIP_LEVEL_COUNT 4 #define MAX_FRAME_NUM_WITH_HISTORY_FIX 4.0 float2 RotateVector(float4 rotator, float2 v) @@ -73,7 +73,7 @@ float GetCombinedWeight(float2 geometryWeightParams, float3 Nv, float3 Xvs, floa #define SPECULAR_DOMINANT_DIRECTION_DEFAULT 2 float GetSpecularDominantFactor(float NoV, float linearRoughness) -{ +{ float a = 0.298475 * log( 39.4115 - 39.0029 * linearRoughness ); float dominantFactor = pow(saturate(1.0 - NoV), 10.8649 ) * ( 1.0 - a ) + a; return saturate(dominantFactor); @@ -105,7 +105,7 @@ float2x3 GetKernelBasis( float3 V, float3 N, float linearRoughness) float3 R = reflect( -V, N ); float3 D = normalize( lerp( N, R, f ) ); float NoD = abs( dot( N, D ) ); - + if( NoD < 0.999 && linearRoughness != 1.0 ) { float3 Dreflected = reflect( -D, N ); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingReflectionFilter.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingReflectionFilter.compute index e58704c7b06..75a25cda725 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingReflectionFilter.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingReflectionFilter.compute @@ -162,7 +162,7 @@ void ReflectionUpscale(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 fullResolution = dispatchThreadId.xy; // Fetch the full resolution depth - float hiResDepth = Linear01Depth(LOAD_TEXTURE2D_X(_DepthTexture, fullResolution).x, _ZBufferParams); + float hiResDepth = Linear01Depth(LOAD_TEXTURE2D_X(_DepthTexture, fullResolution).x, _ZBufferParams); // If the full resolution depth is a background pixel, write the invalid data and we are done if (hiResDepth == 1.0) @@ -196,10 +196,10 @@ void ReflectionUpscale(uint3 dispatchThreadId : SV_DispatchThreadID, // Make sure the pixel has a valid signal weight *= gs_cacheValidity[tapHalfResLDSIndex] ? 1.0 : 0.0; - + // Add the contribution of the sample fallbackLighting += float4(gs_cacheLighting[tapHalfResLDSIndex], 0.0) * weight; - weightSum += weight; + weightSum += weight; } } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Settings/LookDevVolumeProfileSettings.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Settings/LookDevVolumeProfileSettings.cs index 99691e07873..1b2d50f5c28 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Settings/LookDevVolumeProfileSettings.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Settings/LookDevVolumeProfileSettings.cs @@ -1,4 +1,6 @@ using System; +using UnityEditor.Rendering; +using UnityEditor; namespace UnityEngine.Rendering.HighDefinition { @@ -63,22 +65,28 @@ public VolumeProfile volumeProfile get => m_VolumeProfile; set => this.SetValueAndNotify(ref m_VolumeProfile, value); } - - void IRenderPipelineGraphicsSettings.Reset() - { + #if UNITY_EDITOR - if (UnityEditor.Rendering.EditorGraphicsSettings.TryGetRenderPipelineSettingsForPipeline(out var rpgs)) + //Overriding "Reset" in menu that is not called at HDRPDefaultVolumeProfileSettings creation such Reset() + struct ResetImplementation : IRenderPipelineGraphicsSettingsContextMenu2 + { + public void PopulateContextMenu(LookDevVolumeProfileSettings setting, SerializedProperty _, ref GenericMenu menu) + { + void Reset() { - //UUM-100350 - //When opening the new HDRP project from the template the first time, the global settings is created and the population of IRenderPipelineGraphicsSettings - //will call this Reset() method. At this time, the copied item will appear ok but will be seen as null soon after. This lead to errors when opening the - //inspector of the LookDev's VolumeProfile (at the creation of Editors for VolumeComponent). Closing and opening the project would make this issue disappear. - //This asset data base manipulation issue disappear if we delay it. - UnityEditor.EditorApplication.delayCall += () => - volumeProfile = VolumeUtils.CopyVolumeProfileFromResourcesToAssets(rpgs.lookDevVolumeProfile); + if (EditorGraphicsSettings.TryGetRenderPipelineSettingsForPipeline(out var rpgs)) + { + RenderPipelineGraphicsSettingsEditorUtility.Rebind( + new LookDevVolumeProfileSettings() { volumeProfile = VolumeUtils.CopyVolumeProfileFromResourcesToAssets(rpgs.lookDevVolumeProfile, true) }, + typeof(HDRenderPipeline) + ); + } } -#endif + + menu.AddItem(new GUIContent("Reset"), false, Reset); } } +#endif + } } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Sky/SkyManager.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Sky/SkyManager.cs index f529681382a..042d0747abf 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Sky/SkyManager.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Sky/SkyManager.cs @@ -82,6 +82,8 @@ public class BuiltinSkyParameters public static RenderTargetIdentifier nullRT = -1; /// Index of the current cubemap face to render (Unknown for texture2D). public CubemapFace cubemapFace = CubemapFace.Unknown; + /// Fallback for structured buffer of CelestialBodyData. + internal BufferHandle emptyCelestialBodyBuffer; /// /// Copy content of this BuiltinSkyParameters to another instance. @@ -381,6 +383,9 @@ void SetGlobalSkyData(RenderGraph renderGraph, SkyUpdateContext skyContext, Buil passData.builtinParameters.volumetricClouds = skyContext.volumetricClouds; passData.skyRenderer = skyContext.skyRenderer; + passData.builtinParameters.emptyCelestialBodyBuffer = builder.CreateTransientBuffer( + new BufferDesc(1, System.Runtime.InteropServices.Marshal.SizeOf(typeof(CelestialBodyData)))); + builder.SetRenderFunc( (SetGlobalSkyDataPassData data, UnsafeGraphContext ctx) => { diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Sky/SkyRenderer.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Sky/SkyRenderer.cs index dbaf3228f33..71f7c0b9e52 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Sky/SkyRenderer.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Sky/SkyRenderer.cs @@ -88,6 +88,17 @@ protected static float GetSkyIntensity(SkySettings skySettings, DebugDisplaySett /// Sky system builtin parameters. public virtual void SetGlobalSkyData(CommandBuffer cmd, BuiltinSkyParameters builtinParams) { + // bind empty resources for non-PBR sky. + if (ShaderConfig.s_PrecomputedAtmosphericAttenuation == 0) + { + cmd.SetGlobalTexture(HDShaderIDs._AirSingleScatteringTexture, (RenderTargetIdentifier)CoreUtils.blackVolumeTexture); + cmd.SetGlobalTexture(HDShaderIDs._AerosolSingleScatteringTexture, (RenderTargetIdentifier)CoreUtils.blackVolumeTexture); + cmd.SetGlobalTexture(HDShaderIDs._MultipleScatteringTexture, (RenderTargetIdentifier)CoreUtils.blackVolumeTexture); + } + else + cmd.SetGlobalTexture(HDShaderIDs._AtmosphericScatteringLUT, (RenderTargetIdentifier)CoreUtils.blackVolumeTexture); + + cmd.SetGlobalBuffer(HDShaderIDs._CelestialBodyDatas, builtinParams.emptyCelestialBodyBuffer); } internal bool DoUpdate(BuiltinSkyParameters parameters) diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Utilities/GPUPrefixSum/GPUPrefixSum.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/Utilities/GPUPrefixSum/GPUPrefixSum.compute index 042c8e9dae2..cd31ab8c53c 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Utilities/GPUPrefixSum/GPUPrefixSum.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Utilities/GPUPrefixSum/GPUPrefixSum.compute @@ -131,7 +131,11 @@ void MainPrefixSumOnGroupCommon(int3 dispatchThreadID, int groupThreadIndex, boo GroupMemoryBarrierWithGroupSync(); int threadID = dispatchThreadID.x; - uint inputVal = (uint)threadID >= gs_CurrentLevelOffsets.count ? 0u : _InputBuffer.Load(threadID << 2); + uint inputVal = 0; + if ( (uint)threadID < gs_CurrentLevelOffsets.count ) + { + inputVal = _InputBuffer.Load(threadID << 2); + } gs_prefixCache[groupThreadIndex] = inputVal; GroupMemoryBarrierWithGroupSync(); @@ -189,7 +193,9 @@ void MainPrefixSumResolveParentCommon(int3 dispatchThreadID, int groupThreadInde if (groupThreadIndex == 0) { gs_CurrentLevelOffsets = _LevelsOffsetsBuffer[_CurrentLevel]; - gs_ParentSum = groupID.x == 0 ? 0 : _OutputBuffer.Load((gs_CurrentLevelOffsets.offset + groupID.x - 1) << 2); + gs_ParentSum = 0; + if (groupID.x>0) + gs_ParentSum = _OutputBuffer.Load((gs_CurrentLevelOffsets.offset + groupID.x - 1) << 2); } GroupMemoryBarrierWithGroupSync(); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Utilities/VolumeUtils.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Utilities/VolumeUtils.cs index a9d731296f1..978c4e4ad3e 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Utilities/VolumeUtils.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Utilities/VolumeUtils.cs @@ -43,12 +43,23 @@ public static VolumeProfile CopyVolumeProfileFromResourcesToAssets(VolumeProfile c.parameters[i].SetValue(resourceComponent.parameters[i]); } } - } return profile; } + internal static VolumeProfile CopyVolumeProfileFromResourcesToAssets(VolumeProfile profileInResourcesFolder, bool forcedOverrideValue = false) + { + var profile = CopyVolumeProfileFromResourcesToAssets(profileInResourcesFolder); + + if (profile != null) + foreach (var component in profile.components) + for (int i = 0; i < component.parameters.Count; i++) + component.parameters[i].overrideState = forcedOverrideValue; + + return profile; + } + public static bool IsDefaultVolumeProfile(VolumeProfile volumeProfile, VolumeProfile profileInResourcesFolder) { return volumeProfile != null && volumeProfile.Equals(profileInResourcesFolder); diff --git a/Packages/com.unity.render-pipelines.high-definition/Samples~/RendererShaderUserValueSamples/Scenes/LookDev.unity b/Packages/com.unity.render-pipelines.high-definition/Samples~/RendererShaderUserValueSamples/Scenes/LookDev.unity index a56a8cf7b99..450b9d273a9 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Samples~/RendererShaderUserValueSamples/Scenes/LookDev.unity +++ b/Packages/com.unity.render-pipelines.high-definition/Samples~/RendererShaderUserValueSamples/Scenes/LookDev.unity @@ -500,6 +500,18 @@ PrefabInstance: propertyPath: m_Layer value: 2 objectReference: {fileID: 0} + - target: {fileID: 8553631396527524258, guid: eeab7b6e71b7483489dd15b45d828c30, type: 3} + propertyPath: m_LocalScale.x + value: 0.9458514 + objectReference: {fileID: 0} + - target: {fileID: 8553631396527524258, guid: eeab7b6e71b7483489dd15b45d828c30, type: 3} + propertyPath: m_LocalScale.y + value: 0.9458514 + objectReference: {fileID: 0} + - target: {fileID: 8553631396527524258, guid: eeab7b6e71b7483489dd15b45d828c30, type: 3} + propertyPath: m_LocalScale.z + value: 0.9458514 + objectReference: {fileID: 0} - target: {fileID: 8553631396527524258, guid: eeab7b6e71b7483489dd15b45d828c30, type: 3} propertyPath: m_LocalPosition.x value: 0 @@ -881,51 +893,6 @@ Transform: m_Children: [] m_Father: {fileID: 59383918} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1045504573 -GameObject: - m_ObjectHideFlags: 19 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1045504575} - - component: {fileID: 1045504574} - m_Layer: 0 - m_Name: SceneIDMap - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1045504574 -MonoBehaviour: - m_ObjectHideFlags: 19 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1045504573} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 1642155417} - m_Name: - m_EditorClassIdentifier: - m_Entries: [] ---- !u!4 &1045504575 -Transform: - m_ObjectHideFlags: 19 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1045504573} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1191974066 GameObject: m_ObjectHideFlags: 0 @@ -1135,21 +1102,6 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!115 &1642155417 -MonoScript: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: - serializedVersion: 7 - m_DefaultReferences: {} - m_Icon: {fileID: 0} - m_Type: 0 - m_ExecutionOrder: 0 - m_ClassName: SceneObjectIDMapSceneAsset - m_Namespace: UnityEngine.Rendering.HighDefinition - m_AssemblyName: Unity.RenderPipelines.HighDefinition.Runtime --- !u!1 &119734848978804391 GameObject: m_ObjectHideFlags: 0 @@ -1232,7 +1184,7 @@ Light: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1659505970839723442} m_Enabled: 1 - serializedVersion: 12 + serializedVersion: 13 m_Type: 0 m_Color: {r: 1, g: 1, b: 1, a: 1} m_Intensity: 318.31006 @@ -1284,7 +1236,7 @@ Light: m_UseBoundingSphereOverride: 0 m_UseViewFrustumForShadowCasterCull: 0 m_ForceVisible: 0 - m_ShadowRadius: 0.025 + m_ShapeRadius: 0.025 m_ShadowAngle: 0 m_LightUnit: 0 m_LuxAtDistance: 1 @@ -1620,6 +1572,7 @@ MonoBehaviour: m_ShapeWidth: -1 m_ShapeHeight: -1 m_AspectRatio: 1 + m_ShapeRadius: -1 m_SpotIESCutoffPercent: 100 m_LightDimmer: 1 m_VolumetricDimmer: 1 @@ -1628,7 +1581,6 @@ MonoBehaviour: m_AffectDiffuse: 1 m_AffectSpecular: 1 m_NonLightmappedOnly: 0 - m_ShapeRadius: 0.025 m_SoftnessScale: 1 m_UseCustomSpotLightShadowCone: 1 m_CustomSpotLightShadowCone: 100 @@ -1666,7 +1618,6 @@ MonoBehaviour: m_FilterTracedShadow: 1 m_FilterSizeTraced: 16 m_SunLightConeAngle: 0.5 - m_LightShadowRadius: 0.5 m_SemiTransparentShadow: 0 m_ColorShadow: 1 m_DistanceBasedFiltering: 0 @@ -1734,7 +1685,7 @@ MonoBehaviour: m_AreaLightEmissiveMeshShadowCastingMode: 0 m_AreaLightEmissiveMeshMotionVectorGenerationMode: 0 m_AreaLightEmissiveMeshLayer: -1 - m_Version: 14 + m_Version: 15 m_ObsoleteShadowResolutionTier: 1 m_ObsoleteUseShadowQualitySettings: 0 m_ObsoleteCustomShadowResolution: 512 @@ -1810,7 +1761,7 @@ Light: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 927598970997111942} m_Enabled: 1 - serializedVersion: 12 + serializedVersion: 13 m_Type: 0 m_Color: {r: 1, g: 1, b: 1, a: 1} m_Intensity: 92.96667 @@ -1862,7 +1813,7 @@ Light: m_UseBoundingSphereOverride: 0 m_UseViewFrustumForShadowCasterCull: 1 m_ForceVisible: 0 - m_ShadowRadius: 0.025 + m_ShapeRadius: 0.025 m_ShadowAngle: 0 m_LightUnit: 0 m_LuxAtDistance: 1 @@ -1941,6 +1892,7 @@ MonoBehaviour: m_ShapeWidth: -1 m_ShapeHeight: -1 m_AspectRatio: 1 + m_ShapeRadius: -1 m_SpotIESCutoffPercent: 100 m_LightDimmer: 1 m_VolumetricDimmer: 1 @@ -1949,7 +1901,6 @@ MonoBehaviour: m_AffectDiffuse: 1 m_AffectSpecular: 1 m_NonLightmappedOnly: 0 - m_ShapeRadius: 0.025 m_SoftnessScale: 1 m_UseCustomSpotLightShadowCone: 0 m_CustomSpotLightShadowCone: 30 @@ -1987,7 +1938,6 @@ MonoBehaviour: m_FilterTracedShadow: 1 m_FilterSizeTraced: 16 m_SunLightConeAngle: 0.5 - m_LightShadowRadius: 0.5 m_SemiTransparentShadow: 0 m_ColorShadow: 1 m_DistanceBasedFiltering: 0 @@ -2055,7 +2005,7 @@ MonoBehaviour: m_AreaLightEmissiveMeshShadowCastingMode: 0 m_AreaLightEmissiveMeshMotionVectorGenerationMode: 0 m_AreaLightEmissiveMeshLayer: -1 - m_Version: 14 + m_Version: 15 m_ObsoleteShadowResolutionTier: 1 m_ObsoleteUseShadowQualitySettings: 0 m_ObsoleteCustomShadowResolution: 512 @@ -2644,6 +2594,7 @@ MonoBehaviour: m_ShapeWidth: -1 m_ShapeHeight: -1 m_AspectRatio: 1 + m_ShapeRadius: -1 m_SpotIESCutoffPercent: 100 m_LightDimmer: 1 m_VolumetricDimmer: 1 @@ -2652,7 +2603,6 @@ MonoBehaviour: m_AffectDiffuse: 1 m_AffectSpecular: 1 m_NonLightmappedOnly: 0 - m_ShapeRadius: 0.025 m_SoftnessScale: 1 m_UseCustomSpotLightShadowCone: 0 m_CustomSpotLightShadowCone: 30 @@ -2690,7 +2640,6 @@ MonoBehaviour: m_FilterTracedShadow: 1 m_FilterSizeTraced: 16 m_SunLightConeAngle: 0.5 - m_LightShadowRadius: 0.5 m_SemiTransparentShadow: 0 m_ColorShadow: 1 m_DistanceBasedFiltering: 0 @@ -2758,7 +2707,7 @@ MonoBehaviour: m_AreaLightEmissiveMeshShadowCastingMode: 0 m_AreaLightEmissiveMeshMotionVectorGenerationMode: 0 m_AreaLightEmissiveMeshLayer: -1 - m_Version: 14 + m_Version: 15 m_ObsoleteShadowResolutionTier: 1 m_ObsoleteUseShadowQualitySettings: 0 m_ObsoleteCustomShadowResolution: 512 @@ -2787,7 +2736,7 @@ Light: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1935158662385014115} m_Enabled: 1 - serializedVersion: 12 + serializedVersion: 13 m_Type: 0 m_Color: {r: 1, g: 1, b: 1, a: 1} m_Intensity: 160.46211 @@ -2839,7 +2788,7 @@ Light: m_UseBoundingSphereOverride: 0 m_UseViewFrustumForShadowCasterCull: 1 m_ForceVisible: 0 - m_ShadowRadius: 0.025 + m_ShapeRadius: 0.025 m_ShadowAngle: 0 m_LightUnit: 0 m_LuxAtDistance: 1 @@ -3185,6 +3134,7 @@ MonoBehaviour: m_ShapeWidth: -1 m_ShapeHeight: -1 m_AspectRatio: 1 + m_ShapeRadius: -1 m_SpotIESCutoffPercent: 100 m_LightDimmer: 1 m_VolumetricDimmer: 1 @@ -3193,7 +3143,6 @@ MonoBehaviour: m_AffectDiffuse: 1 m_AffectSpecular: 1 m_NonLightmappedOnly: 0 - m_ShapeRadius: 0.025 m_SoftnessScale: 1 m_UseCustomSpotLightShadowCone: 0 m_CustomSpotLightShadowCone: 30 @@ -3231,7 +3180,6 @@ MonoBehaviour: m_FilterTracedShadow: 1 m_FilterSizeTraced: 16 m_SunLightConeAngle: 0.5 - m_LightShadowRadius: 0.5 m_SemiTransparentShadow: 0 m_ColorShadow: 1 m_DistanceBasedFiltering: 0 @@ -3299,7 +3247,7 @@ MonoBehaviour: m_AreaLightEmissiveMeshShadowCastingMode: 0 m_AreaLightEmissiveMeshMotionVectorGenerationMode: 0 m_AreaLightEmissiveMeshLayer: -1 - m_Version: 14 + m_Version: 15 m_ObsoleteShadowResolutionTier: 1 m_ObsoleteUseShadowQualitySettings: 0 m_ObsoleteCustomShadowResolution: 512 @@ -4012,7 +3960,7 @@ Light: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 8598119875628110629} m_Enabled: 1 - serializedVersion: 12 + serializedVersion: 13 m_Type: 0 m_Color: {r: 1, g: 1, b: 1, a: 1} m_Intensity: 352.14642 @@ -4064,7 +4012,7 @@ Light: m_UseBoundingSphereOverride: 0 m_UseViewFrustumForShadowCasterCull: 1 m_ForceVisible: 0 - m_ShadowRadius: 0.025 + m_ShapeRadius: 0.025 m_ShadowAngle: 0 m_LightUnit: 0 m_LuxAtDistance: 1 @@ -4536,7 +4484,6 @@ SceneRoots: - {fileID: 450753641} - {fileID: 7057516004932664435} - {fileID: 59383918} - - {fileID: 1045504575} - {fileID: 1191974067} - {fileID: 1522427161} - {fileID: 1276148452} diff --git a/Packages/com.unity.render-pipelines.high-definition/Samples~/WaterSamples/Scenes/Scene Resources/CaveSampleDescription.json b/Packages/com.unity.render-pipelines.high-definition/Samples~/WaterSamples/Scenes/Scene Resources/CaveSampleDescription.json index d4e7c8c028f..039d127107b 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Samples~/WaterSamples/Scenes/Scene Resources/CaveSampleDescription.json +++ b/Packages/com.unity.render-pipelines.high-definition/Samples~/WaterSamples/Scenes/Scene Resources/CaveSampleDescription.json @@ -19,7 +19,7 @@ You can open the Custom Pass

Custom Local Volumetric Fog

• To simulate light rays bouncing on the water surface, a Local Volumetric Fog with a custom material is used. -• This shader, simply sample the caustics texture passed by the script on the Water Surface using absolute world position node. +• This shader, simply sample the caustics texture passed by the BindTexture script on the Water Surface using absolute world position node. You can open the Local Volumetric Fog Shader Graph for more details. diff --git a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/MotionVectorPass.hlsl b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/MotionVectorPass.hlsl index e1c3a831dd1..980437a6ba8 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/MotionVectorPass.hlsl +++ b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/MotionVectorPass.hlsl @@ -129,25 +129,32 @@ void vert( previousPositionOS -= passInput.alembicMotionVectorOS; #endif +#if defined(APPLICATION_SPACE_WARP_MOTION) + // We do not need jittered position in ASW + mvOutput.positionCSNoJitter = mul(_NonJitteredViewProjMatrix, float4(currentFrameMvData.positionWS, 1.0f)); + packedOutput.positionCS = mvOutput.positionCSNoJitter; + mvOutput.previousPositionCSNoJitter = mul(_PrevViewProjMatrix, mul(UNITY_PREV_MATRIX_M, float4(previousPositionOS, 1.0f))); +#else mvOutput.positionCSNoJitter = mul(_NonJitteredViewProjMatrix, float4(currentFrameMvData.positionWS, 1.0f)); -#if defined(HAVE_VFX_MODIFICATION) - #if defined(VFX_FEATURE_MOTION_VECTORS_VERTS) - #if defined(FEATURES_GRAPH_VERTEX_MOTION_VECTOR_OUTPUT) || defined(_ADD_PRECOMPUTED_VELOCITY) - #error Unexpected fast path rendering VFX motion vector while there are vertex modification afterwards. - #endif - mvOutput.previousPositionCSNoJitter = VFXGetPreviousClipPosition(input, currentFrameMvData.vfxElementAttributes, mvOutput.positionCSNoJitter); - #else - #if VFX_WORLD_SPACE - //previousPositionOS is already in world space - const float3 previousPositionWS = previousPositionOS; + #if defined(HAVE_VFX_MODIFICATION) + #if defined(VFX_FEATURE_MOTION_VECTORS_VERTS) + #if defined(FEATURES_GRAPH_VERTEX_MOTION_VECTOR_OUTPUT) || defined(_ADD_PRECOMPUTED_VELOCITY) + #error Unexpected fast path rendering VFX motion vector while there are vertex modification afterwards. + #endif + mvOutput.previousPositionCSNoJitter = VFXGetPreviousClipPosition(input, currentFrameMvData.vfxElementAttributes, mvOutput.positionCSNoJitter); #else - const float3 previousPositionWS = mul(UNITY_PREV_MATRIX_M, float4(previousPositionOS, 1.0f)).xyz; + #if VFX_WORLD_SPACE + //previousPositionOS is already in world space + const float3 previousPositionWS = previousPositionOS; + #else + const float3 previousPositionWS = mul(UNITY_PREV_MATRIX_M, float4(previousPositionOS, 1.0f)).xyz; + #endif + mvOutput.previousPositionCSNoJitter = mul(_PrevViewProjMatrix, float4(previousPositionWS, 1.0f)); #endif - mvOutput.previousPositionCSNoJitter = mul(_PrevViewProjMatrix, float4(previousPositionWS, 1.0f)); + #else + mvOutput.previousPositionCSNoJitter = mul(_PrevViewProjMatrix, mul(UNITY_PREV_MATRIX_M, float4(previousPositionOS, 1.0f))); #endif -#else - mvOutput.previousPositionCSNoJitter = mul(_PrevViewProjMatrix, mul(UNITY_PREV_MATRIX_M, float4(previousPositionOS, 1.0f))); #endif } @@ -175,6 +182,11 @@ float4 frag( LODFadeCrossFade(input.positionCS); #endif + +#if defined(APPLICATION_SPACE_WARP_MOTION) + return float4(CalcAswNdcMotionVectorFromCsPositions(mvInput.positionCSNoJitter, mvInput.previousPositionCSNoJitter), 1); +#else return float4(CalcNdcMotionVectorFromCsPositions(mvInput.positionCSNoJitter, mvInput.previousPositionCSNoJitter), 0, 0); +#endif } #endif diff --git a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/UITKPass.hlsl b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/UITKPass.hlsl index 46bd4b9038f..e1f5bcf34dc 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/UITKPass.hlsl +++ b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/UITKPass.hlsl @@ -19,11 +19,16 @@ PackedVaryings uie_custom_vert(Attributes input) uieInput.circle = input.uv6; uieInput.textureId = input.uv7.x; - v2f uieOutput = uie_std_vert(uieInput); Varyings varyings = (Varyings)0; varyings.positionCS = uieOutput.pos; + +#ifdef VARYINGS_NEED_POSITION_WS + float3 positionWS = TransformObjectToWorld(input.positionOS); + varyings.positionWS = positionWS; +#endif + varyings.color = uieOutput.color; varyings.texCoord0 = uieOutput.uvClip; varyings.texCoord1 = uieOutput.typeTexSettings; diff --git a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/Varyings.hlsl b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/Varyings.hlsl index 488fab541d0..dcdd2e4fb4b 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/Varyings.hlsl +++ b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/Varyings.hlsl @@ -34,7 +34,7 @@ VertexDescription BuildVertexDescription(Attributes input) #endif #endif -#if (SHADERPASS == SHADERPASS_MOTION_VECTORS) +#if (SHADERPASS == SHADERPASS_MOTION_VECTORS || SHADERPASS == SHADERPASS_XR_MOTION_VECTORS) // We want to gather some internal data from the BuildVaryings call to // avoid rereading and recalculating these values again in the ShaderGraph motion vector pass struct MotionVectorPassOutput @@ -55,7 +55,7 @@ struct MotionVectorPassOutput #if defined(HAVE_VFX_MODIFICATION) bool PrepareVFXModification(inout Attributes input, inout Varyings output, inout AttributesElement element - #if (SHADERPASS == SHADERPASS_MOTION_VECTORS) + #if (SHADERPASS == SHADERPASS_MOTION_VECTORS || SHADERPASS == SHADERPASS_XR_MOTION_VECTORS) , inout MotionVectorPassOutput motionVectorOutput #endif ) @@ -72,7 +72,7 @@ bool PrepareVFXModification(inout Attributes input, inout Varyings output, inout SetupVFXMatrices(element, output); -#if (SHADERPASS == SHADERPASS_MOTION_VECTORS) +#if (SHADERPASS == SHADERPASS_MOTION_VECTORS || SHADERPASS == SHADERPASS_XR_MOTION_VECTORS) motionVectorOutput.vfxParticlePositionOS = input.positionOS; #endif @@ -81,7 +81,7 @@ bool PrepareVFXModification(inout Attributes input, inout Varyings output, inout #endif Varyings BuildVaryings(Attributes input -#if (SHADERPASS == SHADERPASS_MOTION_VECTORS) +#if (SHADERPASS == SHADERPASS_MOTION_VECTORS || SHADERPASS == SHADERPASS_XR_MOTION_VECTORS) , inout MotionVectorPassOutput motionVectorOutput #endif ) @@ -98,7 +98,7 @@ Varyings BuildVaryings(Attributes input AttributesElement element; ZERO_INITIALIZE(AttributesElement, element); - #if (SHADERPASS == SHADERPASS_MOTION_VECTORS) + #if (SHADERPASS == SHADERPASS_MOTION_VECTORS || SHADERPASS == SHADERPASS_XR_MOTION_VECTORS) isCulledOrDead = PrepareVFXModification(input, output, element, motionVectorOutput); #else isCulledOrDead = PrepareVFXModification(input, output, element); @@ -141,7 +141,7 @@ Varyings BuildVaryings(Attributes input // Returns the camera relative position (if enabled) float3 positionWS = vertexInput.positionWS; - #if (SHADERPASS == SHADERPASS_MOTION_VECTORS) + #if (SHADERPASS == SHADERPASS_MOTION_VECTORS || SHADERPASS == SHADERPASS_XR_MOTION_VECTORS) motionVectorOutput.positionOS = input.positionOS; motionVectorOutput.positionWS = positionWS; #if defined(FEATURES_GRAPH_VERTEX_MOTION_VECTOR_OUTPUT) diff --git a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Targets/UniversalTarget.cs b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Targets/UniversalTarget.cs index 66c4a7fb49b..2566168cdd1 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Targets/UniversalTarget.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Targets/UniversalTarget.cs @@ -1195,23 +1195,20 @@ public static PassDescriptor XRMotionVectors(UniversalTarget target) displayName = "XRMotionVectors", referenceName = "SHADERPASS_XR_MOTION_VECTORS", lightMode = "XRMotionVectors", - useInPreview = true, + useInPreview = false, // Template passTemplatePath = UniversalTarget.kUberTemplatePath, sharedTemplateDirectories = UniversalTarget.kSharedTemplateDirectories, // Port Mask - validVertexBlocks = new BlockFieldDescriptor[]{ }, - validPixelBlocks = new BlockFieldDescriptor[] { }, + validVertexBlocks = CoreBlockMasks.MotionVectorVertex, + validPixelBlocks = CoreBlockMasks.FragmentAlphaOnly, // Fields - structs = new StructCollection() { - { Structs.SurfaceDescriptionInputs }, - { Structs.VertexDescriptionInputs }, - }, + structs = CoreStructCollections.Default, requiredFields = new FieldCollection(), - fieldDependencies = new DependencyCollection() { }, + fieldDependencies = CoreFieldDependencies.Default, // Conditional State renderStates = CoreRenderStates.XRMotionVector(target), @@ -1219,10 +1216,16 @@ public static PassDescriptor XRMotionVectors(UniversalTarget target) defines = new DefineCollection(), keywords = new KeywordCollection(), includes = CoreIncludes.XRMotionVectors, + + // Custom Interpolator Support + customInterpolators = CoreCustomInterpDescriptors.Common }; result.defines.Add(CoreKeywordDescriptors.XRMotionVectors, 1); + AddAlphaClipControlToPass(ref result, target); + AddLODCrossFadeControlToPass(ref result, target); + return result; } @@ -1706,8 +1709,10 @@ static class CorePragmas public static readonly PragmaCollection XRMotionVectors = new PragmaCollection { - { Pragma.MultiCompileLodCrossfade }, - { Pragma.ShaderFeatureLocalVertex("_ADD_PRECOMPUTED_VELOCITY") }, + { Pragma.Target(ShaderModel.Target35) }, + { Pragma.MultiCompileInstancing }, + { Pragma.Vertex("vert") }, + { Pragma.Fragment("frag") }, }; public static readonly PragmaCollection Forward = new PragmaCollection @@ -1768,7 +1773,6 @@ static class CoreIncludes const string kFog = "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Fog.hlsl"; const string kRenderingLayers = "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RenderingLayers.hlsl"; const string kProbeVolumes = "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ProbeVolumeVariants.hlsl"; - const string kObjectMotionVectors = "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ObjectMotionVectors.hlsl"; public static readonly IncludeCollection CorePregraph = new IncludeCollection { @@ -1803,11 +1807,6 @@ static class CoreIncludes { kProbeVolumes, IncludeLocation.Pregraph, true }, }; - public static readonly IncludeCollection ObjectMotionVectors = new IncludeCollection - { - { kObjectMotionVectors, IncludeLocation.Pregraph, true }, - }; - public static readonly IncludeCollection ShaderGraphPregraph = new IncludeCollection { { kGraphFunctions, IncludeLocation.Pregraph }, @@ -1860,9 +1859,13 @@ static class CoreIncludes public static readonly IncludeCollection XRMotionVectors = new IncludeCollection { // Pre-graph + { DOTSPregraph }, { CorePregraph }, { ShaderGraphPregraph }, - { ObjectMotionVectors }, + + //Post-graph + { CorePostgraph }, + { kMotionVectorPass, IncludeLocation.Postgraph }, }; public static readonly IncludeCollection ShadowCaster = new IncludeCollection diff --git a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Targets/UniversalTerrainLitSubTarget.cs b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Targets/UniversalTerrainLitSubTarget.cs index 7a2522eb4ca..81cb6c44c5a 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Targets/UniversalTerrainLitSubTarget.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Targets/UniversalTerrainLitSubTarget.cs @@ -63,34 +63,21 @@ public override void Setup(ref TargetSetupContext context) if (!context.HasCustomEditorForRenderPipeline(universalRPType)) context.AddCustomEditorForRenderPipeline(typeof(ShaderGraphTerrainLitGUI).FullName, universalRPType); - context.AddSubShader(PostProcessSubShader(TerrainSubShaders.LitComputeDotsSubShader(target, target.renderType, target.renderQueue, blendModePreserveSpecular))); - context.AddSubShader(PostProcessSubShader(TerrainSubShaders.LitGLESSubShader(target, target.renderType, target.renderQueue, blendModePreserveSpecular))); + // terrain shaders are always opaque, so these values are hardcoded to not inherit from the Universal Target + var renderTypeOpaque = RenderType.Opaque.ToString(); + var renderQueue = target.alphaClip?RenderQueue.AlphaTest.ToString():RenderQueue.Geometry.ToString(); - context.AddSubShader(PostProcessSubShader(TerrainLitAddSubShaders.LitComputeDotsSubShader(target, target.renderType, target.renderQueue, blendModePreserveSpecular))); - context.AddSubShader(PostProcessSubShader(TerrainLitAddSubShaders.LitGLESSubShader(target, target.renderType, target.renderQueue, blendModePreserveSpecular))); + context.AddSubShader(PostProcessSubShader(TerrainSubShaders.LitComputeDotsSubShader(target, renderTypeOpaque, renderQueue, blendModePreserveSpecular))); + context.AddSubShader(PostProcessSubShader(TerrainSubShaders.LitGLESSubShader(target, renderTypeOpaque, renderQueue, blendModePreserveSpecular))); - context.AddSubShader(PostProcessSubShader(TerrainLitBaseMapGenSubShaders.GenerateBaseMap(target, target.renderType, target.renderQueue, blendModePreserveSpecular))); + context.AddSubShader(PostProcessSubShader(TerrainLitAddSubShaders.LitComputeDotsSubShader(target, renderTypeOpaque, renderQueue, blendModePreserveSpecular))); + context.AddSubShader(PostProcessSubShader(TerrainLitAddSubShaders.LitGLESSubShader(target, renderTypeOpaque, renderQueue, blendModePreserveSpecular))); + + context.AddSubShader(PostProcessSubShader(TerrainLitBaseMapGenSubShaders.GenerateBaseMap(target, renderTypeOpaque, renderQueue, blendModePreserveSpecular))); } 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, 1.0f); - material.SetFloat(Property.CastShadows, target.castShadows ? 1.0f : 0.0f); - material.SetFloat(Property.ReceiveShadows, target.receiveShadows ? 1.0f : 0.0f); - material.SetFloat(Property.SurfaceType, 0.0f); - material.SetFloat(Property.BlendMode, (float)target.alphaMode); - material.SetFloat(Property.AlphaClip, target.alphaClip ? 1.0f : 0.0f); - material.SetFloat(Property.CullMode, 2.0f); - 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 @@ -348,19 +335,6 @@ public override void CollectShaderProperties(PropertyCollector collector, Genera public override void GetPropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action registerUndo) { - var universalTarget = (target as UniversalTarget); - universalTarget.AddDefaultMaterialOverrideGUI(ref context, onChange, registerUndo); - - context.AddProperty("Blending Mode", new EnumField(AlphaMode.Alpha) { value = target.alphaMode }, target.surfaceType == SurfaceType.Transparent, (evt) => - { - if (Equals(target.alphaMode, evt.newValue)) - return; - - registerUndo("Change Blend"); - target.alphaMode = (AlphaMode)evt.newValue; - onChange(); - }); - context.AddProperty("Depth Write", new EnumField(ZWriteControl.Auto) { value = target.zWriteControl }, (evt) => { if (Equals(target.zWriteControl, evt.newValue)) @@ -841,14 +815,33 @@ private static InstancingOptions[] InstancingOptionList() } #endregion + private static RenderStateCollection GetTerrainRenderState(UniversalTarget target) + { + var result = new RenderStateCollection + { + RenderState.ZTest(target.zTestMode.ToString()), + RenderState.Cull(Cull.Back), + RenderState.Blend(Blend.One, Blend.Zero) + }; + switch (target.zWriteControl) + { + case ZWriteControl.Auto: + case ZWriteControl.ForceEnabled: + result.Add(RenderState.ZWrite(ZWrite.On)); + break; + default: + result.Add(RenderState.ZWrite(ZWrite.Off)); + break; + } + return result; + } + #region Passes internal static class TerrainLitPasses { - public static void AddReceiveShadowsControlToPass(ref PassDescriptor pass, UniversalTarget target, bool receiveShadows) + private static void AddReceiveShadowsControlToPass(ref PassDescriptor pass, UniversalTarget target, bool receiveShadows) { - if (target.allowMaterialOverride) - pass.keywords.Add(TerrainLitKeywords.ReceiveShadowsOff); - else if (!receiveShadows) + if (!receiveShadows) pass.defines.Add(TerrainLitKeywords.ReceiveShadowsOff, 1); } @@ -876,7 +869,7 @@ public static PassDescriptor Forward(UniversalTarget target, bool blendModePrese fieldDependencies = CoreFieldDependencies.Default, // Conditional State - renderStates = CoreRenderStates.UberSwitchedRenderState(target, blendModePreserveSpecular), + renderStates = GetTerrainRenderState(target), pragmas = pragmas ?? TerrainCorePragmas.Forward, defines = new DefineCollection() { CoreDefines.UseFragmentFog, }, keywords = new KeywordCollection() { TerrainLitKeywords.Forward }, @@ -895,7 +888,7 @@ public static PassDescriptor Forward(UniversalTarget target, bool blendModePrese result.defines.Add(TerrainDefines.SmoothnessTextureAlbedoChannelA, 1); result.defines.Add(TerrainDefines.TerrainAlphaClipEnable, target.alphaClip?1:0); - CorePasses.AddTargetSurfaceControlsToPass(ref result, target, blendModePreserveSpecular); + CorePasses.AddAlphaClipControlToPass(ref result, target); AddReceiveShadowsControlToPass(ref result, target, target.receiveShadows); return result; @@ -925,7 +918,7 @@ public static PassDescriptor GBuffer(UniversalTarget target, bool blendModePrese fieldDependencies = CoreFieldDependencies.Default, // Conditional State - renderStates = CoreRenderStates.UberSwitchedRenderState(target, blendModePreserveSpecular), + renderStates = GetTerrainRenderState(target), pragmas = TerrainCorePragmas.DOTSGBuffer, defines = new DefineCollection() { CoreDefines.UseFragmentFog }, keywords = new KeywordCollection() { TerrainLitKeywords.GBuffer }, @@ -945,7 +938,7 @@ public static PassDescriptor GBuffer(UniversalTarget target, bool blendModePrese result.defines.Add(TerrainDefines.SmoothnessTextureAlbedoChannelA, 1); result.defines.Add(TerrainDefines.TerrainAlphaClipEnable, target.alphaClip?1:0); - CorePasses.AddTargetSurfaceControlsToPass(ref result, target, blendModePreserveSpecular); + CorePasses.AddAlphaClipControlToPass(ref result, target); AddReceiveShadowsControlToPass(ref result, target, target.receiveShadows); return result; @@ -987,8 +980,8 @@ public static PassDescriptor ShadowCaster(UniversalTarget target) result.defines.Add(TerrainDefines.TerrainEnabled, 1); result.defines.Add(TerrainDefines.TerrainAlphaClipEnable, target.alphaClip?1:0); - // CorePasses.AddTargetSurfaceControlsToPass(ref result, target, blendModePreserveSpecular); - CorePasses.AddAlphaClipControlToPass(ref result, target); + if (target.alphaClip) + result.defines.Add(CoreKeywordDescriptors.AlphaTestOn, 1); return result; } @@ -1030,7 +1023,8 @@ public static PassDescriptor DepthOnly(UniversalTarget target) result.defines.Add(TerrainDefines.TerrainEnabled, 1); result.defines.Add(TerrainDefines.TerrainAlphaClipEnable, target.alphaClip?1:0); - CorePasses.AddAlphaClipControlToPass(ref result, target); + if (target.alphaClip) + result.defines.Add(CoreKeywordDescriptors.AlphaTestOn, 1); return result; } @@ -1076,7 +1070,8 @@ public static PassDescriptor DepthNormal(UniversalTarget target) result.keywords.Add(TerrainDefines.TerrainNormalmap); result.keywords.Add(TerrainDefines.TerrainInstancedPerPixelNormal); - CorePasses.AddAlphaClipControlToPass(ref result, target); + if (target.alphaClip) + result.defines.Add(CoreKeywordDescriptors.AlphaTestOn, 1); return result; } @@ -1121,7 +1116,8 @@ public static PassDescriptor Meta(UniversalTarget target) result.defines.Add(TerrainDefines.SmoothnessTextureAlbedoChannelA, 1); result.defines.Add(TerrainDefines.TerrainAlphaClipEnable, target.alphaClip?1:0); - CorePasses.AddAlphaClipControlToPass(ref result, target); + if (target.alphaClip) + result.defines.Add(CoreKeywordDescriptors.AlphaTestOn, 1); return result; } @@ -1163,7 +1159,8 @@ public static PassDescriptor SceneSelection(UniversalTarget target) result.defines.Add(TerrainDefines.TerrainEnabled, 1); result.defines.Add(TerrainDefines.TerrainAlphaClipEnable, target.alphaClip?1:0); - CorePasses.AddAlphaClipControlToPass(ref result, target); + if (target.alphaClip) + result.defines.Add(CoreKeywordDescriptors.AlphaTestOn, 1); return result; } @@ -1205,7 +1202,8 @@ public static PassDescriptor ScenePicking(UniversalTarget target) result.defines.Add(TerrainDefines.TerrainEnabled, 1); result.defines.Add(TerrainDefines.TerrainAlphaClipEnable, target.alphaClip?1:0); - CorePasses.AddAlphaClipControlToPass(ref result, target); + if (target.alphaClip) + result.defines.Add(CoreKeywordDescriptors.AlphaTestOn, 1); return result; } diff --git a/Packages/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineAsset/UniversalRenderPipelineAssetUI.Drawers.cs b/Packages/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineAsset/UniversalRenderPipelineAssetUI.Drawers.cs index a1b09038ae3..c8b3af98fd5 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineAsset/UniversalRenderPipelineAssetUI.Drawers.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineAsset/UniversalRenderPipelineAssetUI.Drawers.cs @@ -191,7 +191,7 @@ static void DrawQuality(SerializedUniversalRenderPipelineAsset serialized, Edito EditorGUILayout.PropertyField(serialized.msaa, Styles.msaaText); serialized.renderScale.floatValue = EditorGUILayout.Slider(Styles.renderScaleText, serialized.renderScale.floatValue, UniversalRenderPipeline.minRenderScale, UniversalRenderPipeline.maxRenderScale); - DrawUpscalingFilterDropdownAndOptions(serialized); + DrawUpscalingFilterDropdownAndOptions(serialized, ownerEditor); if (serialized.renderScale.floatValue < 1.0f || serialized.asset.upscalingFilter == UpscalingFilterSelection.STP || serialized.asset.upscalingFilter == UpscalingFilterSelection.FSR) { @@ -213,7 +213,7 @@ static void DrawQuality(SerializedUniversalRenderPipelineAsset serialized, Edito EditorGUI.EndDisabledGroup(); } - static void DrawUpscalingFilterDropdownAndOptions(SerializedUniversalRenderPipelineAsset serialized) + static void DrawUpscalingFilterDropdownAndOptions(SerializedUniversalRenderPipelineAsset serialized, Editor ownerEditor) { // Get the names of IUpscalers currently present string[] iUpscalerNames = { }; @@ -343,21 +343,20 @@ static void DrawUpscalingFilterDropdownAndOptions(SerializedUniversalRenderPipel if (RenderPipelineManager.currentPipeline is UniversalRenderPipeline && selectedIUpscalerIndex != -1) { UpscalerOptions options = serialized.asset.GetIUpscalerOptions(serialized.iUpscalerName.stringValue); - if (options != null) + + UniversalRenderPipelineAssetEditor urpEditor = ownerEditor as UniversalRenderPipelineAssetEditor; + + Editor upscalerOptionsEditor = urpEditor.upscalerOptionsEditorCache.GetOrCreateEditor(options); + if (upscalerOptionsEditor != null) { ++EditorGUI.indentLevel; - bool optionChanged = options.DrawOptionsEditorGUI(); - if (optionChanged) - { - EditorUtility.SetDirty(serialized.asset); - } + upscalerOptionsEditor.OnInspectorGUI(); --EditorGUI.indentLevel; } } } break; #endif } - } static void DrawHDR(SerializedUniversalRenderPipelineAsset serialized, Editor ownerEditor) diff --git a/Packages/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineAssetEditor.cs b/Packages/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineAssetEditor.cs index 5f2051de358..9bc99d8338d 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineAssetEditor.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineAssetEditor.cs @@ -1,5 +1,6 @@ using UnityEditorInternal; using UnityEngine; +using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; using Styles = UnityEditor.Rendering.Universal.UniversalRenderPipelineAssetUI.Styles; @@ -19,6 +20,11 @@ public class UniversalRenderPipelineAssetEditor : Editor private SerializedUniversalRenderPipelineAsset m_SerializedURPAsset; +#if ENABLE_UPSCALER_FRAMEWORK + internal UpscalerOptionsEditorCache upscalerOptionsEditorCache => m_UpscalerOptionsEditorCache; + UpscalerOptionsEditorCache m_UpscalerOptionsEditorCache; +#endif + /// public override void OnInspectorGUI() { @@ -30,9 +36,21 @@ public override void OnInspectorGUI() void OnEnable() { m_SerializedURPAsset = new SerializedUniversalRenderPipelineAsset(serializedObject); + +#if ENABLE_UPSCALER_FRAMEWORK + m_UpscalerOptionsEditorCache = new UpscalerOptionsEditorCache(); +#endif + CreateRendererReorderableList(); } + private void OnDisable() + { +#if ENABLE_UPSCALER_FRAMEWORK + m_UpscalerOptionsEditorCache?.Cleanup(); +#endif + } + void CreateRendererReorderableList() { m_RendererDataProp = serializedObject.FindProperty("m_RendererDataList"); diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawLight2DPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawLight2DPass.cs index 13f90393c57..20f8e548299 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawLight2DPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawLight2DPass.cs @@ -8,11 +8,11 @@ namespace UnityEngine.Rendering.Universal internal class DrawLight2DPass : ScriptableRenderPass { static readonly string k_LightPass = "Light2D Pass"; - static readonly string k_LightLowLevelPass = "Light2D LowLevelPass"; + static readonly string k_LightSRTPass = "Light2D SRT Pass"; static readonly string k_LightVolumetricPass = "Light2D Volumetric Pass"; private static readonly ProfilingSampler m_ProfilingSampler = new ProfilingSampler(k_LightPass); - private static readonly ProfilingSampler m_ProfilingSamplerLowLevel = new ProfilingSampler(k_LightLowLevelPass); + private static readonly ProfilingSampler m_ProfilingSampleSRT = new ProfilingSampler(k_LightSRTPass); private static readonly ProfilingSampler m_ProfilingSamplerVolume = new ProfilingSampler(k_LightVolumetricPass); internal static readonly int k_InverseHDREmulationScaleID = Shader.PropertyToID("_InverseHDREmulationScale"); internal static readonly string k_NormalMapID = "_NormalMap"; @@ -22,7 +22,7 @@ internal class DrawLight2DPass : ScriptableRenderPass internal static MaterialPropertyBlock s_PropertyBlock = new MaterialPropertyBlock(); - public void Setup(RenderGraph renderGraph, ref Renderer2DData rendererData) + internal void Setup(RenderGraph renderGraph, ref Renderer2DData rendererData) { foreach (var light in rendererData.lightCullResult.visibleLights) { @@ -55,158 +55,78 @@ public override void Execute(ScriptableRenderContext context, ref RenderingData } #endif - private static void Execute(RasterCommandBuffer cmd, PassData passData, ref LayerBatch layerBatch) + private static void Execute(RasterCommandBuffer cmd, PassData passData, ref LayerBatch layerBatch, int lightTextureIndex) { cmd.SetGlobalFloat(k_InverseHDREmulationScaleID, 1.0f / passData.rendererData.hdrEmulationScale); - for (var i = 0; i < layerBatch.activeBlendStylesIndices.Length; ++i) - { - var blendStyleIndex = layerBatch.activeBlendStylesIndices[i]; - var blendOpName = passData.rendererData.lightBlendStyles[blendStyleIndex].name; - cmd.BeginSample(blendOpName); + var blendStyleIndex = layerBatch.activeBlendStylesIndices[lightTextureIndex]; + var blendOpName = passData.rendererData.lightBlendStyles[blendStyleIndex].name; + cmd.BeginSample(blendOpName); - if (!passData.isVolumetric) - RendererLighting.EnableBlendStyle(cmd, i, true); + var indicesIndex = Renderer2D.supportsMRT ? lightTextureIndex : 0; + if (!passData.isVolumetric) + RendererLighting.EnableBlendStyle(cmd, indicesIndex, true); - var lights = passData.layerBatch.lights; + var lights = passData.layerBatch.lights; - for (int j = 0; j < lights.Count; ++j) - { - var light = lights[j]; + for (int j = 0; j < lights.Count; ++j) + { + var light = lights[j]; - // Check if light is valid - if (light == null || - light.lightType == Light2D.LightType.Global || - light.blendStyleIndex != blendStyleIndex) - continue; + // Check if light is valid + if (light == null || + light.lightType == Light2D.LightType.Global || + light.blendStyleIndex != blendStyleIndex) + continue; - // Check if light is volumetric - if (passData.isVolumetric && - (light.volumeIntensity <= 0.0f || - !light.volumetricEnabled || - layerBatch.endLayerValue != light.GetTopMostLitLayer())) - continue; + // Check if light is volumetric + if (passData.isVolumetric && + (light.volumeIntensity <= 0.0f || + !light.volumetricEnabled || + layerBatch.endLayerValue != light.GetTopMostLitLayer())) + continue; - var useShadows = passData.layerBatch.lightStats.useShadows && layerBatch.shadowIndices.Contains(j); - var lightMaterial = passData.rendererData.GetLightMaterial(light, passData.isVolumetric, useShadows); - var lightMesh = light.lightMesh; + var useShadows = passData.layerBatch.lightStats.useShadows && layerBatch.shadowIndices.Contains(j); + var lightMaterial = passData.rendererData.GetLightMaterial(light, passData.isVolumetric, useShadows); + var lightMesh = light.lightMesh; - // For Batching. - var index = light.batchSlotIndex; - var slotIndex = RendererLighting.lightBatch.SlotIndex(index); - bool canBatch = RendererLighting.lightBatch.CanBatch(light, lightMaterial, index, out int lightHash); + // For Batching. + var index = light.batchSlotIndex; + var slotIndex = RendererLighting.lightBatch.SlotIndex(index); + bool canBatch = RendererLighting.lightBatch.CanBatch(light, lightMaterial, index, out int lightHash); - bool breakBatch = !canBatch; - if (breakBatch && LightBatch.isBatchingSupported) - RendererLighting.lightBatch.Flush(cmd); + bool breakBatch = !canBatch; + if (breakBatch && LightBatch.isBatchingSupported) + RendererLighting.lightBatch.Flush(cmd); - if (passData.layerBatch.lightStats.useNormalMap) - s_PropertyBlock.SetTexture(k_NormalMapID, passData.normalMap); + if (passData.layerBatch.lightStats.useNormalMap) + s_PropertyBlock.SetTexture(k_NormalMapID, passData.normalMap); - if (useShadows && TryGetShadowIndex(ref layerBatch, j, out var shadowIndex)) - s_PropertyBlock.SetTexture(k_ShadowMapID, passData.shadowTextures[shadowIndex]); + if (useShadows && TryGetShadowIndex(ref layerBatch, j, out var shadowIndex)) + s_PropertyBlock.SetTexture(k_ShadowMapID, passData.shadowTextures[shadowIndex]); - if (!passData.isVolumetric || (passData.isVolumetric && light.volumetricEnabled)) - RendererLighting.SetCookieShaderProperties(light, s_PropertyBlock); + if (!passData.isVolumetric || (passData.isVolumetric && light.volumetricEnabled)) + RendererLighting.SetCookieShaderProperties(light, s_PropertyBlock); - // Set shader global properties - RendererLighting.SetPerLightShaderGlobals(cmd, light, slotIndex, passData.isVolumetric, useShadows, LightBatch.isBatchingSupported); + // Set shader global properties + RendererLighting.SetPerLightShaderGlobals(cmd, light, slotIndex, passData.isVolumetric, useShadows, LightBatch.isBatchingSupported); - if (light.normalMapQuality != Light2D.NormalMapQuality.Disabled || light.lightType == Light2D.LightType.Point) - RendererLighting.SetPerPointLightShaderGlobals(cmd, light, slotIndex, LightBatch.isBatchingSupported); + if (light.normalMapQuality != Light2D.NormalMapQuality.Disabled || light.lightType == Light2D.LightType.Point) + RendererLighting.SetPerPointLightShaderGlobals(cmd, light, slotIndex, LightBatch.isBatchingSupported); - if (LightBatch.isBatchingSupported) - { - RendererLighting.lightBatch.AddBatch(light, lightMaterial, light.GetMatrix(), lightMesh, 0, lightHash, index); - RendererLighting.lightBatch.Flush(cmd); - } - else - { - cmd.DrawMesh(lightMesh, light.GetMatrix(), lightMaterial, 0, 0, s_PropertyBlock); - } + if (LightBatch.isBatchingSupported) + { + RendererLighting.lightBatch.AddBatch(light, lightMaterial, light.GetMatrix(), lightMesh, 0, lightHash, index); + RendererLighting.lightBatch.Flush(cmd); } - - RendererLighting.EnableBlendStyle(cmd, i, false); - cmd.EndSample(blendOpName); - } - } - - internal static void ExecuteUnsafe(UnsafeCommandBuffer cmd, PassData passData, ref LayerBatch layerBatch, List lights) - { - cmd.SetGlobalFloat(k_InverseHDREmulationScaleID, 1.0f / passData.rendererData.hdrEmulationScale); - - for (var i = 0; i < layerBatch.activeBlendStylesIndices.Length; ++i) - { - var blendStyleIndex = layerBatch.activeBlendStylesIndices[i]; - var blendOpName = passData.rendererData.lightBlendStyles[blendStyleIndex].name; - cmd.BeginSample(blendOpName); - - if (!Renderer2D.supportsMRT && !passData.isVolumetric) - cmd.SetRenderTarget(passData.lightTextures[i]); - - var indicesIndex = Renderer2D.supportsMRT ? i : 0; - if (!passData.isVolumetric) - RendererLighting.EnableBlendStyle(cmd, indicesIndex, true); - - for (int j = 0; j < lights.Count; ++j) + else { - var light = lights[j]; - - // Check if light is valid - if (light == null || - light.lightType == Light2D.LightType.Global || - light.blendStyleIndex != blendStyleIndex) - continue; - - // Check if light is volumetric - if (passData.isVolumetric && - (light.volumeIntensity <= 0.0f || - !light.volumetricEnabled || - layerBatch.endLayerValue != light.GetTopMostLitLayer())) - continue; - - var useShadows = passData.layerBatch.lightStats.useShadows && layerBatch.shadowIndices.Contains(j); - var lightMaterial = passData.rendererData.GetLightMaterial(light, passData.isVolumetric, useShadows); - var lightMesh = light.lightMesh; - - // For Batching. - var index = light.batchSlotIndex; - var slotIndex = RendererLighting.lightBatch.SlotIndex(index); - bool canBatch = RendererLighting.lightBatch.CanBatch(light, lightMaterial, index, out int lightHash); - - //bool breakBatch = !canBatch; - //if (breakBatch && LightBatch.isBatchingSupported) - // RendererLighting.lightBatch.Flush(cmd); - - if (passData.layerBatch.lightStats.useNormalMap) - s_PropertyBlock.SetTexture(k_NormalMapID, passData.normalMap); - - if (useShadows && TryGetShadowIndex(ref layerBatch, j, out var shadowIndex)) - s_PropertyBlock.SetTexture(k_ShadowMapID, passData.shadowTextures[shadowIndex]); - - if (!passData.isVolumetric || (passData.isVolumetric && light.volumetricEnabled)) - RendererLighting.SetCookieShaderProperties(light, s_PropertyBlock); - - // Set shader global properties - RendererLighting.SetPerLightShaderGlobals(cmd, light, slotIndex, passData.isVolumetric, useShadows, LightBatch.isBatchingSupported); - - if (light.normalMapQuality != Light2D.NormalMapQuality.Disabled || light.lightType == Light2D.LightType.Point) - RendererLighting.SetPerPointLightShaderGlobals(cmd, light, slotIndex, LightBatch.isBatchingSupported); - - //if (LightBatch.isBatchingSupported) - //{ - // RendererLighting.lightBatch.AddBatch(light, lightMaterial, light.GetMatrix(), lightMesh, 0, lightHash, index); - // RendererLighting.lightBatch.Flush(cmd); - //} - //else - { - cmd.DrawMesh(lightMesh, light.GetMatrix(), lightMaterial, 0, 0, s_PropertyBlock); - } + cmd.DrawMesh(lightMesh, light.GetMatrix(), lightMaterial, 0, 0, s_PropertyBlock); } - - RendererLighting.EnableBlendStyle(cmd, indicesIndex, false); - cmd.EndSample(blendOpName); } + + RendererLighting.EnableBlendStyle(cmd, indicesIndex, false); + cmd.EndSample(blendOpName); } internal class PassData @@ -218,15 +138,46 @@ internal class PassData internal TextureHandle normalMap; internal TextureHandle[] shadowTextures; - // TODO: Optimize and remove low level pass - // For low level shadow and light pass - internal TextureHandle[] lightTextures; + internal int lightTextureIndex; } - public void Render(RenderGraph graph, ContextContainer frameData, Renderer2DData rendererData, ref LayerBatch layerBatch, int batchIndex, bool isVolumetric = false) + void InitializeRenderPass(IRasterRenderGraphBuilder builder, ContextContainer frameData, PassData passData, Renderer2DData rendererData, ref LayerBatch layerBatch, int batchIndex, bool isVolumetric = false) { Universal2DResourceData universal2DResourceData = frameData.Get(); CommonResourceData commonResourceData = frameData.Get(); + + intermediateTexture[0] = commonResourceData.activeColorTexture; + + if (layerBatch.lightStats.useNormalMap) + builder.UseTexture(universal2DResourceData.normalsTexture[batchIndex]); + + if (layerBatch.lightStats.useShadows) + { + passData.shadowTextures = universal2DResourceData.shadowTextures[batchIndex]; + for (var i = 0; i < passData.shadowTextures.Length; i++) + builder.UseTexture(passData.shadowTextures[i]); + } + + foreach (var light in layerBatch.lights) + { + if (light == null || !light.m_CookieSpriteTextureHandle.IsValid()) + continue; + + if (!isVolumetric || (isVolumetric && light.volumetricEnabled)) + builder.UseTexture(light.m_CookieSpriteTextureHandle); + } + + passData.layerBatch = layerBatch; + passData.rendererData = rendererData; + passData.isVolumetric = isVolumetric; + passData.normalMap = layerBatch.lightStats.useNormalMap ? universal2DResourceData.normalsTexture[batchIndex] : TextureHandle.nullHandle; + + builder.AllowGlobalStateModification(true); + } + + internal void Render(RenderGraph graph, ContextContainer frameData, Renderer2DData rendererData, ref LayerBatch layerBatch, int batchIndex, bool isVolumetric = false) + { + Universal2DResourceData universal2DResourceData = frameData.Get(); UniversalCameraData cameraData = frameData.Get(); DebugHandler debugHandler = ScriptableRenderPass.GetActiveDebugHandler(cameraData); @@ -245,47 +196,26 @@ public void Render(RenderGraph graph, ContextContainer frameData, Renderer2DData !isDebugLightingActive) return; - // Render single RTs by using low level pass for apis that don't support MRTs + // Render single RTs by for apis that don't support MRTs if (!isVolumetric && !Renderer2D.supportsMRT) { - using (var builder = graph.AddUnsafePass(k_LightLowLevelPass, out var passData, m_ProfilingSamplerLowLevel)) + for (var i = 0; i < layerBatch.activeBlendStylesIndices.Length; ++i) { - intermediateTexture[0] = commonResourceData.activeColorTexture; - passData.lightTextures = universal2DResourceData.lightTextures[batchIndex]; - - for (var i = 0; i < passData.lightTextures.Length; i++) - builder.UseTexture(passData.lightTextures[i], AccessFlags.Write); - - if (layerBatch.lightStats.useNormalMap) - builder.UseTexture(universal2DResourceData.normalsTexture[batchIndex]); - - if (layerBatch.lightStats.useShadows) + using (var builder = graph.AddRasterRenderPass(k_LightSRTPass, out var passData, m_ProfilingSampleSRT)) { - passData.shadowTextures = universal2DResourceData.shadowTextures[batchIndex]; - for (var i = 0; i < passData.shadowTextures.Length; i++) - builder.UseTexture(passData.shadowTextures[i]); - } + InitializeRenderPass(builder, frameData, passData, rendererData, ref layerBatch, batchIndex, isVolumetric); - foreach (var light in layerBatch.lights) - { - if (light == null || !light.m_CookieSpriteTextureHandle.IsValid()) - continue; - - if (!isVolumetric || (isVolumetric && light.volumetricEnabled)) - builder.UseTexture(light.m_CookieSpriteTextureHandle); - } + var lightTextures = universal2DResourceData.lightTextures[batchIndex]; - passData.layerBatch = layerBatch; - passData.rendererData = rendererData; - passData.isVolumetric = isVolumetric; - passData.normalMap = layerBatch.lightStats.useNormalMap ? universal2DResourceData.normalsTexture[batchIndex] : TextureHandle.nullHandle; + builder.SetRenderAttachment(lightTextures[i], 0); - builder.AllowGlobalStateModification(true); + passData.lightTextureIndex = i; - builder.SetRenderFunc((PassData data, UnsafeGraphContext context) => - { - ExecuteUnsafe(context.cmd, data, ref data.layerBatch, data.layerBatch.lights); - }); + builder.SetRenderFunc((PassData data, RasterGraphContext context) => + { + Execute(context.cmd, data, ref data.layerBatch, data.lightTextureIndex); + }); + } } } else @@ -293,41 +223,17 @@ public void Render(RenderGraph graph, ContextContainer frameData, Renderer2DData // Default Raster Pass with MRTs using (var builder = graph.AddRasterRenderPass(!isVolumetric ? k_LightPass : k_LightVolumetricPass, out var passData, !isVolumetric ? m_ProfilingSampler : m_ProfilingSamplerVolume)) { - intermediateTexture[0] = commonResourceData.activeColorTexture; + InitializeRenderPass(builder, frameData, passData, rendererData, ref layerBatch, batchIndex, isVolumetric); + var lightTextures = !isVolumetric ? universal2DResourceData.lightTextures[batchIndex] : intermediateTexture; for (var i = 0; i < lightTextures.Length; i++) builder.SetRenderAttachment(lightTextures[i], i); - - if (layerBatch.lightStats.useNormalMap) - builder.UseTexture(universal2DResourceData.normalsTexture[batchIndex]); - - if (layerBatch.lightStats.useShadows) - { - passData.shadowTextures = universal2DResourceData.shadowTextures[batchIndex]; - for (var i = 0; i < passData.shadowTextures.Length; i++) - builder.UseTexture(passData.shadowTextures[i]); - } - - foreach (var light in layerBatch.lights) - { - if (light == null || !light.m_CookieSpriteTextureHandle.IsValid()) - continue; - - if (!isVolumetric || (isVolumetric && light.volumetricEnabled)) - builder.UseTexture(light.m_CookieSpriteTextureHandle); - } - - passData.layerBatch = layerBatch; - passData.rendererData = rendererData; - passData.isVolumetric = isVolumetric; - passData.normalMap = layerBatch.lightStats.useNormalMap ? universal2DResourceData.normalsTexture[batchIndex] : TextureHandle.nullHandle; - - builder.AllowGlobalStateModification(true); - + builder.SetRenderFunc((PassData data, RasterGraphContext context) => { - Execute(context.cmd, data, ref data.layerBatch); + for (var i = 0; i < data.layerBatch.activeBlendStylesIndices.Length; ++i) + Execute(context.cmd, data, ref data.layerBatch, i); }); } } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/FinalBlitPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/FinalBlitPass.cs index 33b6140cb0d..3f4debe42e5 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/FinalBlitPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/FinalBlitPass.cs @@ -218,7 +218,7 @@ public override void Execute(ScriptableRenderContext context, ref RenderingData loadAction = RenderBufferLoadAction.Load; #endif - CoreUtils.SetRenderTarget(renderingData.commandBuffer, cameraTargetHandle, loadAction, RenderBufferStoreAction.Store, ClearFlag.None, Color.clear); + CoreUtils.SetRenderTarget(renderingData.commandBuffer, cameraTargetHandle.nameID, loadAction, RenderBufferStoreAction.Store, ClearFlag.None, Color.clear); ExecutePass(CommandBufferHelpers.GetRasterCommandBuffer(renderingData.commandBuffer), m_PassData, m_Source, cameraTargetHandle, cameraData); cameraData.renderer.ConfigureCameraTarget(cameraTargetHandle, cameraTargetHandle); } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/RenderingUtils.cs b/Packages/com.unity.render-pipelines.universal/Runtime/RenderingUtils.cs index 1f317d895d9..68f722153db 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/RenderingUtils.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/RenderingUtils.cs @@ -861,6 +861,41 @@ public static bool ReAllocateHandleIfNeeded( return false; } + /// + /// Re-allocate fixed-size RTHandle if it is not allocated or doesn't match the descriptor + /// + /// RTHandle to check (can be null) + /// TextureDesc for the RTHandle to match + /// Name of the RTHandle. + /// If an allocation was done. + public static bool ReAllocateHandleIfNeeded( + ref RTHandle handle, + TextureDesc descriptor, + string name) + { + descriptor.name = name; + descriptor.sizeMode = TextureSizeMode.Explicit; + + if (RTHandleNeedsReAlloc(handle, in descriptor, false)) + { + if (handle != null && handle.rt != null) + { + TextureDesc currentRTDesc = RTHandleResourcePool.CreateTextureDesc(handle.rt.descriptor, TextureSizeMode.Explicit, handle.rt.anisoLevel, handle.rt.mipMapBias, handle.rt.filterMode, handle.rt.wrapMode, handle.name); + AddStaleResourceToPoolOrRelease(currentRTDesc, handle); + } + + if (UniversalRenderPipeline.s_RTHandlePool.TryGetResource(descriptor, out handle)) + { + return true; + } + + var allocInfo = CreateRTHandleAllocInfo(descriptor, name); + handle = RTHandles.Alloc(descriptor.width, descriptor.height, allocInfo); + return true; + } + return false; + } + /// /// Re-allocate dynamically resized RTHandle if it is not allocated or doesn't match the descriptor /// @@ -1131,5 +1166,36 @@ internal static RTHandleAllocInfo CreateRTHandleAllocInfo(in RenderTextureDescri return allocInfo; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static RTHandleAllocInfo CreateRTHandleAllocInfo(in TextureDesc descriptor, string name) + { + // NOTE: this calls default(RTHandleAllocInfo) not RTHandleAllocInfo(string = "") + RTHandleAllocInfo allocInfo = new RTHandleAllocInfo(); + allocInfo.slices = descriptor.slices; + allocInfo.format = descriptor.format; + allocInfo.filterMode = descriptor.filterMode; + allocInfo.wrapModeU = descriptor.wrapMode; + allocInfo.wrapModeV = descriptor.wrapMode; + allocInfo.wrapModeW = descriptor.wrapMode; + allocInfo.dimension = descriptor.dimension; + allocInfo.enableRandomWrite = descriptor.enableRandomWrite; + allocInfo.enableShadingRate = descriptor.enableShadingRate; + allocInfo.useMipMap = descriptor.useMipMap; + allocInfo.autoGenerateMips = descriptor.autoGenerateMips; + allocInfo.anisoLevel = descriptor.anisoLevel; + allocInfo.mipMapBias = descriptor.mipMapBias; + allocInfo.isShadowMap = descriptor.isShadowMap; + allocInfo.msaaSamples = (MSAASamples)descriptor.msaaSamples; + allocInfo.bindTextureMS = descriptor.bindTextureMS; + allocInfo.useDynamicScale = descriptor.useDynamicScale; + allocInfo.useDynamicScaleExplicit = descriptor.useDynamicScaleExplicit; + allocInfo.memoryless = descriptor.memoryless; + allocInfo.vrUsage = descriptor.vrUsage; + allocInfo.enableShadingRate = descriptor.enableShadingRate; + allocInfo.name = name; + + return allocInfo; + } } } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs index 7d5d407fce8..1083541af39 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs @@ -709,13 +709,11 @@ bool IsDepthPrimingEnabled(UniversalCameraData cameraData) bool depthPrimingRequested = (m_DepthPrimingRecommended && m_DepthPrimingMode == DepthPrimingMode.Auto) || m_DepthPrimingMode == DepthPrimingMode.Forced; bool isForwardRenderingMode = m_RenderingMode == RenderingMode.Forward || m_RenderingMode == RenderingMode.ForwardPlus; bool isFirstCameraToWriteDepth = cameraData.renderType == CameraRenderType.Base || cameraData.clearDepth; - // Enabled Depth priming when baking Reflection Probes causes artefacts (UUM-12397) - bool isNotReflectionCamera = cameraData.cameraType != CameraType.Reflection; // Depth is not rendered in a depth-only camera setup with depth priming (UUM-38158) bool isNotOffscreenDepthTexture = !IsOffscreenDepthTexture(cameraData); bool isNotMSAA = cameraData.cameraTargetDescriptor.msaaSamples == 1; - return depthPrimingRequested && isForwardRenderingMode && isFirstCameraToWriteDepth && isNotReflectionCamera && isNotOffscreenDepthTexture && isNotWebGL && isNotMSAA; + return depthPrimingRequested && isForwardRenderingMode && isFirstCameraToWriteDepth && isNotOffscreenDepthTexture && isNotWebGL && isNotMSAA; } #endif diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs index f27a5ccdb2f..611e01c251a 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs @@ -1348,7 +1348,7 @@ private void OnAfterRendering(RenderGraph renderGraph, bool applyPostProcessing) (cameraData.IsTemporalAAEnabled() && cameraData.taaSettings.contrastAdaptiveSharpening > 0.0f)); bool hasCaptureActions = cameraData.captureActions != null && cameraData.resolveFinalTarget; - bool hasPassesAfterPostProcessing = activeRenderPassQueue.Find(x => x.renderPassEvent == RenderPassEvent.AfterRenderingPostProcessing) != null; + bool hasPassesAfterPostProcessing = activeRenderPassQueue.Find(x => x.renderPassEvent >= RenderPassEvent.AfterRenderingPostProcessing && x.renderPassEvent < RenderPassEvent.AfterRendering) != null; bool resolvePostProcessingToCameraTarget = !hasCaptureActions && !hasPassesAfterPostProcessing && !applyFinalPostProcessing; bool needsColorEncoding = DebugHandler == null || !DebugHandler.HDRDebugViewIsActive(cameraData.resolveFinalTarget); @@ -1393,7 +1393,7 @@ private void OnAfterRendering(RenderGraph renderGraph, bool applyPostProcessing) importColorParams.clearColor = Color.black; importColorParams.discardOnLastUse = cameraData.resolveFinalTarget; // check if last camera in the stack - if (cameraData.IsSTPEnabled() || (cameraData.IsTemporalAAEnabled() && + if (cameraData.IsSTPEnabled() || (cameraData.IsTemporalAAEnabled() && #if ENABLE_UPSCALER_FRAMEWORK cameraData.upscalingFilter == ImageUpscalingFilter.IUpscaler #else @@ -1622,6 +1622,8 @@ static bool IsDepthPrimingEnabledRenderGraph(UniversalCameraData cameraData, in // We only do one depth prepass per camera. If the texture requires a prepass, and priming is on, then we do priming and a copy afterwards to the cameraDepthTexture. // However, some platforms don't support this copy (like GLES when MSAA is on). When a copy is not supported we turn off priming so the prepass will target the cameraDepthTexture, avoiding the copy. + // Note: From Unity 2021 to Unity 6.3, depth priming was disabled in renders for reflections probes as a brute-force bugfix for artefacts appearing in reflection probes when screen space shadows are enabled. + // Depth priming has now been restored in reflection probe renders. Please consider a more targeted fix if issues with screen space shadows resurface again. (See UUM-99152 and UUM-12397) if (requireDepthTexture && !CanCopyDepth(cameraData)) return false; @@ -1644,12 +1646,10 @@ static bool IsDepthPrimingEnabledRenderGraph(UniversalCameraData cameraData, in } bool isFirstCameraToWriteDepth = cameraData.renderType == CameraRenderType.Base || cameraData.clearDepth; - // Enabled Depth priming when baking Reflection Probes causes artefacts (UUM-12397) - bool isNotReflectionCamera = cameraData.cameraType != CameraType.Reflection; // Depth is not rendered in a depth-only camera setup with depth priming (UUM-38158) bool isNotOffscreenDepthTexture = !IsOffscreenDepthTexture(cameraData); - return depthPrimingRequested && !usesDeferredLighting && isFirstCameraToWriteDepth && isNotReflectionCamera && isNotOffscreenDepthTexture && isNotWebGL && isNotMSAA; + return depthPrimingRequested && !usesDeferredLighting && isFirstCameraToWriteDepth && isNotOffscreenDepthTexture && isNotWebGL && isNotMSAA; } internal void SetRenderingLayersGlobalTextures(RenderGraph renderGraph) diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/RendererShaderUserValueSamples/Scenes/LookDev.unity b/Packages/com.unity.render-pipelines.universal/Samples~/RendererShaderUserValueSamples/Scenes/LookDev.unity index 4cd0de9ea43..a188c480a23 100644 --- a/Packages/com.unity.render-pipelines.universal/Samples~/RendererShaderUserValueSamples/Scenes/LookDev.unity +++ b/Packages/com.unity.render-pipelines.universal/Samples~/RendererShaderUserValueSamples/Scenes/LookDev.unity @@ -184,6 +184,18 @@ PrefabInstance: propertyPath: eyebrowsStyle value: 0 objectReference: {fileID: 0} + - target: {fileID: 8553631396527524258, guid: eeab7b6e71b7483489dd15b45d828c30, type: 3} + propertyPath: m_LocalScale.x + value: 1.0618654 + objectReference: {fileID: 0} + - target: {fileID: 8553631396527524258, guid: eeab7b6e71b7483489dd15b45d828c30, type: 3} + propertyPath: m_LocalScale.y + value: 1.0618654 + objectReference: {fileID: 0} + - target: {fileID: 8553631396527524258, guid: eeab7b6e71b7483489dd15b45d828c30, type: 3} + propertyPath: m_LocalScale.z + value: 1.0618654 + objectReference: {fileID: 0} - target: {fileID: 8553631396527524258, guid: eeab7b6e71b7483489dd15b45d828c30, type: 3} propertyPath: m_LocalPosition.x value: 0 @@ -446,50 +458,6 @@ Transform: m_Children: [] m_Father: {fileID: 59383918} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1045504573 -GameObject: - m_ObjectHideFlags: 19 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1045504575} - - component: {fileID: 1045504574} - m_Layer: 0 - m_Name: SceneIDMap - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1045504574 -MonoBehaviour: - m_ObjectHideFlags: 19 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1045504573} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 1642155417} - m_Name: - m_EditorClassIdentifier: ---- !u!4 &1045504575 -Transform: - m_ObjectHideFlags: 19 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1045504573} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1143907757 GameObject: m_ObjectHideFlags: 0 @@ -681,21 +649,6 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!115 &1642155417 -MonoScript: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: - serializedVersion: 7 - m_DefaultReferences: {} - m_Icon: {fileID: 0} - m_Type: 0 - m_ExecutionOrder: 0 - m_ClassName: SceneObjectIDMapSceneAsset - m_Namespace: UnityEngine.Rendering.HighDefinition - m_AssemblyName: Unity.RenderPipelines.HighDefinition.Runtime --- !u!1 &119734848978804391 GameObject: m_ObjectHideFlags: 0 @@ -778,7 +731,7 @@ Light: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1659505970839723442} m_Enabled: 1 - serializedVersion: 12 + serializedVersion: 13 m_Type: 0 m_Color: {r: 1, g: 1, b: 1, a: 1} m_Intensity: 30 @@ -830,7 +783,7 @@ Light: m_UseBoundingSphereOverride: 0 m_UseViewFrustumForShadowCasterCull: 0 m_ForceVisible: 0 - m_ShadowRadius: 0.025 + m_ShapeRadius: 0.025 m_ShadowAngle: 0 m_LightUnit: 0 m_LuxAtDistance: 1 @@ -1214,7 +1167,7 @@ Light: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 927598970997111942} m_Enabled: 1 - serializedVersion: 12 + serializedVersion: 13 m_Type: 0 m_Color: {r: 1, g: 1, b: 1, a: 1} m_Intensity: 1.98 @@ -1266,7 +1219,7 @@ Light: m_UseBoundingSphereOverride: 0 m_UseViewFrustumForShadowCasterCull: 1 m_ForceVisible: 0 - m_ShadowRadius: 0.025 + m_ShapeRadius: 0.025 m_ShadowAngle: 0 m_LightUnit: 0 m_LuxAtDistance: 1 @@ -1935,7 +1888,7 @@ Light: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1935158662385014115} m_Enabled: 1 - serializedVersion: 12 + serializedVersion: 13 m_Type: 0 m_Color: {r: 1, g: 1, b: 1, a: 1} m_Intensity: 15 @@ -1987,7 +1940,7 @@ Light: m_UseBoundingSphereOverride: 0 m_UseViewFrustumForShadowCasterCull: 1 m_ForceVisible: 0 - m_ShadowRadius: 0.025 + m_ShapeRadius: 0.025 m_ShadowAngle: 0 m_LightUnit: 0 m_LuxAtDistance: 1 @@ -2667,7 +2620,7 @@ Light: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 8598119875628110629} m_Enabled: 1 - serializedVersion: 12 + serializedVersion: 13 m_Type: 0 m_Color: {r: 1, g: 1, b: 1, a: 1} m_Intensity: 7.5 @@ -2719,7 +2672,7 @@ Light: m_UseBoundingSphereOverride: 0 m_UseViewFrustumForShadowCasterCull: 1 m_ForceVisible: 0 - m_ShadowRadius: 0.025 + m_ShapeRadius: 0.025 m_ShadowAngle: 0 m_LightUnit: 0 m_LuxAtDistance: 1 @@ -3220,7 +3173,6 @@ SceneRoots: - {fileID: 450753641} - {fileID: 7057516004932664435} - {fileID: 59383918} - - {fileID: 1045504575} - {fileID: 1191974067} - {fileID: 1522427161} - {fileID: 1276148452} diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Blit w. FrameData/BlitRendererFeature.cs b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Blit w. FrameData/BlitRendererFeature.cs deleted file mode 100644 index bc0e4910244..00000000000 --- a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Blit w. FrameData/BlitRendererFeature.cs +++ /dev/null @@ -1,289 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.Rendering.RenderGraphModule; -using UnityEngine.Rendering; -using UnityEngine.Rendering.Universal; - -// Example of how Blit operatrions can be handled using frameData using multiple ScriptaleRenderPasses. -public class BlitRendererFeature : ScriptableRendererFeature -{ - // The class living in frameData. It will take care of managing the texture resources. - public class BlitData : ContextItem, IDisposable - { - // Textures used for the blit operations. - RTHandle m_TextureFront; - RTHandle m_TextureBack; - // Render graph texture handles. - TextureHandle m_TextureHandleFront; - TextureHandle m_TextureHandleBack; - - // Scale bias is used to control how the blit operation is done. The x and y parameter controls the scale - // and z and w controls the offset. - static Vector4 scaleBias = new Vector4(1f, 1f, 0f, 0f); - - // Bool to manage which texture is the most resent. - bool m_IsFront = true; - - // The texture which contains the color buffer from the most resent blit operation. - public TextureHandle texture; - - // Function used to initialize BlitDatat. Should be called before starting to use the class for each frame. - public void Init(RenderGraph renderGraph, RenderTextureDescriptor targetDescriptor, string textureName = null) - { - // Checks if the texture name is valid and puts in default value if not. - var texName = String.IsNullOrEmpty(textureName) ? "_BlitTextureData" : textureName; - // Reallocate if the RTHandles are being initialized for the first time or if the targetDescriptor has changed since last frame. - RenderingUtils.ReAllocateHandleIfNeeded(ref m_TextureFront, targetDescriptor, FilterMode.Bilinear, TextureWrapMode.Clamp, name: texName + "Front"); - RenderingUtils.ReAllocateHandleIfNeeded(ref m_TextureBack, targetDescriptor, FilterMode.Bilinear, TextureWrapMode.Clamp, name: texName + "Back"); - // Create the texture handles inside render graph by importing the RTHandles in render graph. - m_TextureHandleFront = renderGraph.ImportTexture(m_TextureFront); - m_TextureHandleBack = renderGraph.ImportTexture(m_TextureBack); - // Sets the active texture to the front buffer - texture = m_TextureHandleFront; - } - - // We will need to reset the texture handle after each frame to avoid leaking invalid texture handles - // since the texture handles only lives for one frame. - public override void Reset() - { - // Resets the color buffers to avoid carrying invalid references to the next frame. - // This could be BlitData texture handles from last frame which will now be invalid. - m_TextureHandleFront = TextureHandle.nullHandle; - m_TextureHandleBack = TextureHandle.nullHandle; - texture = TextureHandle.nullHandle; - // Reset the acrive texture to be the front buffer. - m_IsFront = true; - } - - // The data we use to transfer data to the render function. - class PassData - { - // When makeing a blit operation we will need a source, a destination and a material. - // The source and destination is used to know where to copy from and to. - public TextureHandle source; - public TextureHandle destination; - // The material is used to transform the color buffer while copying. - public Material material; - } - - // For this function we don't take a material as argument to show that we should remember to reset values - // we don't use to avoid leaking values from last frame. - public void RecordBlitColor(RenderGraph renderGraph, ContextContainer frameData) - { - // Check if BlitData's texture is valid if it isn't initialize BlitData. - if (!texture.IsValid()) - { - // Setup the descriptor we use for BlitData. We should use the camera target's descriptor as a start. - var cameraData = frameData.Get(); - var descriptor = cameraData.cameraTargetDescriptor; - // We disable MSAA for the blit operations. - descriptor.msaaSamples = 1; - // We disable the depth buffer, since we are only makeing transformations to the color buffer. - descriptor.depthStencilFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.None; - Init(renderGraph, descriptor); - } - - // Starts the recording of the render graph pass given the name of the pass - // and outputting the data used to pass data to the execution of the render function. - using (var builder = renderGraph.AddRasterRenderPass("BlitColorPass", out var passData)) - { - // Fetch UniversalResourceData from frameData to retrive the camera's active color attachment. - var resourceData = frameData.Get(); - - // Remember to reset material since it contains the value from last frame. - // If we don't do this we would get the material last commited to the BlitPassData using RenderGraph - // since we reuse the object allocation. - passData.material = null; - passData.source = resourceData.activeColorTexture; - passData.destination = texture; - - // Sets input attachment to the cameras color buffer. - builder.UseTexture(passData.source); - // Sets output attachment 0 to BlitData's active texture. - builder.SetRenderAttachment(passData.destination, 0); - - // Sets the render function. - builder.SetRenderFunc((PassData passData, RasterGraphContext rgContext) => ExecutePass(passData, rgContext)); - } - } - - // Records a render graph render pass which blits the BlitData's active texture back to the camera's color attachment. - public void RecordBlitBackToColor(RenderGraph renderGraph, ContextContainer frameData) - { - // Check if BlitData's texture is valid if it isn't it hasn't been initialized or an error has occured. - if (!texture.IsValid()) return; - - // Starts the recording of the render graph pass given the name of the pass - // and outputting the data used to pass data to the execution of the render function. - using (var builder = renderGraph.AddRasterRenderPass($"BlitBackToColorPass", out var passData)) - { - // Fetch UniversalResourceData from frameData to retrive the camera's active color attachment. - var resourceData = frameData.Get(); - - // Remember to reset material. Otherwise you would use the last material used in RecordFullScreenPass. - passData.material = null; - passData.source = texture; - passData.destination = resourceData.activeColorTexture; - - // Sets input attachment to BitData's active texture. - builder.UseTexture(passData.source); - // Sets output attachment 0 to the cameras color buffer. - builder.SetRenderAttachment(passData.destination, 0); - - // Sets the render function. - builder.SetRenderFunc((PassData passData, RasterGraphContext rgContext) => ExecutePass(passData, rgContext)); - } - } - - // This function blits the whole screen for a given material. - public void RecordFullScreenPass(RenderGraph renderGraph, string passName, Material material) - { - // Checks if the data is previously initialized and if the material is valid. - if (!texture.IsValid() || material == null) - { - Debug.LogWarning("Invalid input texture handle, will skip fullscreen pass."); - return; - } - - // Starts the recording of the render graph pass given the name of the pass - // and outputting the data used to pass data to the execution of the render function. - using (var builder = renderGraph.AddRasterRenderPass(passName, out var passData)) - { - // Switching the active texture handles to avoid blit. If we want the most recent - // texture we can simply look at the variable texture - m_IsFront = !m_IsFront; - - // Setting data to be used when executing the render function. - passData.material = material; - passData.source = texture; - - // Swap the active texture. - if (m_IsFront) - passData.destination = m_TextureHandleFront; - else - passData.destination = m_TextureHandleBack; - - // Sets input attachment to BlitData's old active texture. - builder.UseTexture(passData.source); - // Sets output attachment 0 to BitData's new active texture. - builder.SetRenderAttachment(passData.destination, 0); - - // Update the texture after switching. - texture = passData.destination; - - // Sets the render function. - builder.SetRenderFunc((PassData passData, RasterGraphContext rgContext) => ExecutePass(passData, rgContext)); - } - } - - // ExecutePass is the render function for each of the blit render graph recordings. - // This is good practice to avoid using variables outside of the lambda it is called from. - // It is static to avoid using member variables which could cause unintended behaviour. - static void ExecutePass(PassData data, RasterGraphContext rgContext) - { - // We can use blit with or without a material both using the static scaleBias to avoid reallocations. - if (data.material == null) - Blitter.BlitTexture(rgContext.cmd, data.source, scaleBias, 0, false); - else - Blitter.BlitTexture(rgContext.cmd, data.source, scaleBias, data.material, 0); - } - - // We need to release the textures once the renderer is released which will dispose every item inside - // frameData (also data types previously created in earlier frames). - public void Dispose() - { - m_TextureFront?.Release(); - m_TextureBack?.Release(); - } - } - - // Initial render pass for the renderer feature which is run to initialize the data in frameData and copying - // the camera's color attachment to a texture inside BlitData so we can do transformations using blit. - class BlitStartRenderPass : ScriptableRenderPass - { - public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) - { - // Creating the data BlitData inside frameData. - var blitTextureData = frameData.Create(); - // Copies the camera's color attachment to a texture inside BlitData. - blitTextureData.RecordBlitColor(renderGraph, frameData); - } - } - - // Render pass which makes a blit for each material given to the renderer feature. - class BlitRenderPass : ScriptableRenderPass - { - List m_Materials; - - // Setup function used to retrive the materials from the renderer feature. - public void Setup(List materials) - { - m_Materials = materials; - } - - public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) - { - // Retrives the BlitData from the current frame. - var blitTextureData = frameData.Get(); - foreach(var material in m_Materials) - { - // Skip current cycle if the material is null since there is no need to blit if no - // transformation happens. - if (material == null) continue; - // Records the material blit pass. - blitTextureData.RecordFullScreenPass(renderGraph, $"Blit {material.name} Pass", material); - } - } - } - - // Final render pass to copying the texture back to the camera's color attachment. - class BlitEndRenderPass : ScriptableRenderPass - { - public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) - { - // Retrives the BlitData from the current frame and blit it back again to the camera's color attachment. - var blitTextureData = frameData.Get(); - blitTextureData.RecordBlitBackToColor(renderGraph, frameData); - } - } - - [SerializeField] - [Tooltip("Materials used for blitting. They will be blit in the same order they have in the list starting from index 0. ")] - List m_Materials; - - BlitStartRenderPass m_StartPass; - BlitRenderPass m_BlitPass; - BlitEndRenderPass m_EndPass; - - // Here you can create passes and do the initialization of them. This is called everytime serialization happens. - public override void Create() - { - m_StartPass = new BlitStartRenderPass(); - m_BlitPass = new BlitRenderPass(); - m_EndPass = new BlitEndRenderPass(); - - // Configures where the render pass should be injected. - m_StartPass.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing; - m_BlitPass.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing; - m_EndPass.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing; - } - - // Here you can inject one or multiple render passes in the renderer. - // This method is called when setting up the renderer once per-camera. - public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) - { - // Early return if there is no texture to blit. - if (m_Materials == null || m_Materials.Count == 0) return; - - // Pass the material to the blit render pass. - m_BlitPass.Setup(m_Materials); - - // Since they have the same RenderPassEvent the order matters when enqueueing them. - renderer.EnqueuePass(m_StartPass); - renderer.EnqueuePass(m_BlitPass); - renderer.EnqueuePass(m_EndPass); - } -} - - diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Blit/CopyRenderFeature.cs b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Blit/CopyRenderFeature.cs index 5254f619243..ea668a6c015 100644 --- a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Blit/CopyRenderFeature.cs +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Blit/CopyRenderFeature.cs @@ -12,9 +12,10 @@ class CopyRenderPass : ScriptableRenderPass { public CopyRenderPass() { - //The pass will read the current color texture. That needs to be an intermediate texture. It's not supported to use the BackBuffer as input texture. - //By setting this property, URP will automatically create an intermediate texture. - //It's good practice to set it here and not from the RenderFeature. This way, the pass is selfcontaining and you can use it to directly enqueue the pass from a monobehaviour without a RenderFeature. + // The pass will read the current color texture. That needs to be an intermediate texture. It's not supported to use the BackBuffer as input texture. + // By setting this property, URP will automatically create an intermediate texture. + // It's good practice to set it here and not from the RenderFeature. This way, the pass is self-containing, + // and you can use it to directly enqueue the pass from a MonoBehaviour without a RenderFeature. requiresIntermediateTexture = true; } @@ -22,8 +23,6 @@ public CopyRenderPass() // Each ScriptableRenderPass can use the RenderGraph handle to add multiple render passes to the render graph public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) { - const string passName = "Copy To or From Temp Texture"; - // UniversalResourceData contains all the texture handles used by the renderer, including the active color and depth textures // The active color and depth textures are the main color and depth buffers that the camera renders into UniversalResourceData resourceData = frameData.Get(); @@ -41,10 +40,10 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer if (RenderGraphUtils.CanAddCopyPassMSAA()) { // This simple pass copies the active color texture to a new texture. - renderGraph.AddCopyPass(resourceData.activeColorTexture, destination, passName: passName); + renderGraph.AddCopyPass(resourceData.activeColorTexture, destination, passName: "Copy Active Color Texture to Temp Texture"); - //Need to copy back otherwise the pass gets culled since the result of the previous copy is not read. This is just for demonstration purposes. - renderGraph.AddCopyPass(destination, resourceData.activeColorTexture, passName: passName); + // Need to copy back - otherwise the pass gets culled since the result of the previous copy is not read. This is just for demonstration purposes. + renderGraph.AddCopyPass(destination, resourceData.activeColorTexture, passName: "Copy Temp Texture to Active Color Texture"); } else { diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Blit w. FrameData.meta b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithFrameData.meta similarity index 100% rename from Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Blit w. FrameData.meta rename to Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithFrameData.meta diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithFrameData/BlitRendererFeature.cs b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithFrameData/BlitRendererFeature.cs new file mode 100644 index 00000000000..3ac48bfbbff --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithFrameData/BlitRendererFeature.cs @@ -0,0 +1,216 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Rendering.RenderGraphModule; +using UnityEngine.Rendering; +using UnityEngine.Rendering.RenderGraphModule.Util; +using UnityEngine.Rendering.Universal; + +// Example of how Blit operations can be handled using frameData and multiple ScriptableRenderPasses. +// BlitStartRenderPass initializes the BlitData in the frameData and copies the camera's color attachment to a texture inside the BlitData. +// BlitRenderPass makes a blit for each material given to the RendererFeature. +// BlitEndRenderPass blits the resulting BlitData texture back to the camera's color attachment. + +public class BlitRendererFeature : ScriptableRendererFeature +{ + // The class living in frameData. It will take care of managing the texture resources. + public class BlitData : ContextItem + { + // Render graph texture handles. + TextureHandle m_TextureHandleFront; + TextureHandle m_TextureHandleBack; + + // Scale bias is used to control how the blit operation is done. The x and y parameter controls the scale + // and z and w controls the offset. + static Vector4 scaleBias = new Vector4(1f, 1f, 0f, 0f); + + // Bool to manage which texture is the most recent. + bool m_IsFront = true; + + // The texture which contains the color buffer from the most recent blit operation. + public TextureHandle texture; + + // Function used to initialize BlitData. Should be called before starting to use the class for each frame. + public void Init(RenderGraph renderGraph, TextureDesc targetDescriptor, string textureName = null) + { + // Checks if the texture name is valid and puts in default value if not. + var baseTexName = String.IsNullOrEmpty(textureName) ? "_BlitTextureData" : textureName; + + targetDescriptor.filterMode = FilterMode.Bilinear; + targetDescriptor.wrapMode = TextureWrapMode.Clamp; + // We disable MSAA for the blit operations. + targetDescriptor.msaaSamples = MSAASamples.None; + // We disable the depth buffer, since we are only making transformations to the color buffer. + targetDescriptor.depthBufferBits = 0; + + targetDescriptor.name = baseTexName + "Front"; + m_TextureHandleFront = renderGraph.CreateTexture(targetDescriptor); + + targetDescriptor.name = baseTexName + "Back"; + m_TextureHandleBack = renderGraph.CreateTexture(targetDescriptor); + + // Sets the active texture to the front buffer. + texture = m_TextureHandleFront; + } + + // We will need to reset the texture handle after each frame to avoid leaking invalid texture handles + // since the texture handles only lives for one frame. + public override void Reset() + { + // Resets the color buffers to avoid carrying invalid references to the next frame. + // This could be BlitData texture handles from last frame which will now be invalid. + m_TextureHandleFront = TextureHandle.nullHandle; + m_TextureHandleBack = TextureHandle.nullHandle; + texture = TextureHandle.nullHandle; + // Reset the active texture to be the front buffer. + m_IsFront = true; + } + + // For this function we don't take a material as argument to show that we should remember to reset values + // we don't use to avoid leaking values from last frame. + public void RecordBlitColor(RenderGraph renderGraph, ContextContainer frameData) + { + // Fetch UniversalResourceData from frameData to retrieve the camera's active color attachment. + var resourceData = frameData.Get(); + + // Check if BlitData's texture is valid if it isn't initialize BlitData. + if (!texture.IsValid()) + { + // Set up the descriptor we use for BlitData. We use the camera color's descriptor as a start. + Init(renderGraph, resourceData.activeColorTexture.GetDescriptor(renderGraph)); + } + + // Copy the activeColorTexture to the current front texture + renderGraph.AddCopyPass(resourceData.activeColorTexture, texture, "BlitCameraColorToTexturePass"); + } + + // Records a render graph render pass which blits the BlitData's current front texture back to the camera's color attachment. + public void RecordBlitBackToColor(RenderGraph renderGraph, ContextContainer frameData) + { + // Check if BlitData's texture is valid if it isn't it hasn't been initialized or an error has occured. + if (!texture.IsValid()) return; + + // Fetch UniversalResourceData from frameData to retrieve the camera's active color attachment. + var resourceData = frameData.Get(); + + // Copy the current front texture back to the activeColorTexture. + renderGraph.AddCopyPass(texture, resourceData.activeColorTexture, "BlitTextureToColorPass"); + } + + // This function blits the whole screen for a given material. + public void RecordFullScreenPass(RenderGraph renderGraph, string passName, Material material) + { + // Checks if the data is previously initialized and if the material is valid. + if (!texture.IsValid() || material == null) + { + Debug.LogWarning("Invalid input texture handle, will skip fullscreen pass."); + return; + } + + // Switching the active texture handles to avoid blit. If we want the most recent + // texture we can simply look at the variable texture. + m_IsFront = !m_IsFront; + + // Swap the active texture. + var destination = m_IsFront ? m_TextureHandleFront : m_TextureHandleBack; + + // Setting data to be used when executing the render function. + var blitMaterialParameters = new RenderGraphUtils.BlitMaterialParameters(texture, destination, material, 0); + + // Blit + renderGraph.AddBlitPass(blitMaterialParameters, passName); + + // Update the texture after switching. + texture = destination; + } + } + + // Initial render pass for the renderer feature which is run to initialize the data in frameData and copying + // the camera's color attachment to a texture inside BlitData so we can do transformations using blit. + class BlitStartRenderPass : ScriptableRenderPass + { + public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) + { + // Creating the data BlitData inside frameData. + var blitTextureData = frameData.Create(); + // Copies the camera's color attachment to a texture inside BlitData. + blitTextureData.RecordBlitColor(renderGraph, frameData); + } + } + + // Render pass which makes a blit for each material given to the renderer feature. + class BlitRenderPass : ScriptableRenderPass + { + List m_Materials; + + // Setup function used to retrieve the materials from the renderer feature. + public void Setup(List materials) + { + m_Materials = materials; + } + + public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) + { + // Retrieves the BlitData from the current frame. + var blitTextureData = frameData.Get(); + foreach(var material in m_Materials) + { + // Skip current cycle if the material is null since there is no need to blit if no + // transformation happens. + if (material == null) continue; + // Records the material blit pass. + blitTextureData.RecordFullScreenPass(renderGraph, $"Blit {material.name} Pass", material); + } + } + } + + // Final render pass for copying the texture back to the camera's color attachment. + class BlitEndRenderPass : ScriptableRenderPass + { + public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) + { + // Retrieves the BlitData from the current frame and blit it back again to the camera's color attachment. + var blitTextureData = frameData.Get(); + blitTextureData.RecordBlitBackToColor(renderGraph, frameData); + } + } + + [SerializeField] + [Tooltip("Materials used for blitting. They will be blit in the same order they have in the list starting from index 0. ")] + List m_Materials; + + BlitStartRenderPass m_StartPass; + BlitRenderPass m_BlitPass; + BlitEndRenderPass m_EndPass; + + // Here you can create and initialize passes. This is called every time serialization happens. + public override void Create() + { + m_StartPass = new BlitStartRenderPass(); + m_BlitPass = new BlitRenderPass(); + m_EndPass = new BlitEndRenderPass(); + + // Configures where the render pass should be injected. + m_StartPass.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing; + m_BlitPass.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing; + m_EndPass.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing; + } + + // Here you can inject one or multiple render passes in the renderer. + // This method is called when setting up the renderer once per-camera. + public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) + { + // Early return if there is no texture to blit. + if (m_Materials == null || m_Materials.Count == 0) return; + + // Pass the material to the blit render pass. + m_BlitPass.Setup(m_Materials); + + // Since they have the same RenderPassEvent the order matters when enqueueing them. + renderer.EnqueuePass(m_StartPass); + renderer.EnqueuePass(m_BlitPass); + renderer.EnqueuePass(m_EndPass); + } +} + + diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Blit w. FrameData/BlitRendererFeature.cs.meta b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithFrameData/BlitRendererFeature.cs.meta similarity index 100% rename from Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Blit w. FrameData/BlitRendererFeature.cs.meta rename to Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithFrameData/BlitRendererFeature.cs.meta diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial.meta b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial.meta index 07129902ec2..89f9da16daf 100644 --- a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial.meta +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 50ac20be57e0e2c4581d99cbfc925a30 +guid: 09bb382fce3ae4ac09a3d2c953cbfb8f folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitAndSwapColorRendererFeature.cs b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitAndSwapColorRendererFeature.cs index 34f1c82b71d..414c4c93e0f 100644 --- a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitAndSwapColorRendererFeature.cs +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitAndSwapColorRendererFeature.cs @@ -4,12 +4,11 @@ using UnityEngine.Rendering.Universal; using UnityEngine.Rendering.RenderGraphModule.Util; -//This example blits the active CameraColor to a new texture. It shows how to do a blit with material, and how to use the ResourceData to avoid another blit back to the active color target. -//This example is for API demonstrative purposes. - +// This example blits the active CameraColor to a new texture. It shows how to do a blit with material, and how to use the ResourceData to avoid another blit back to the active color target. +// This example is for API demonstrative purposes. // This pass blits the whole screen for a given material to a temp texture, and swaps the UniversalResourceData.cameraColor to this temp texture. -// Therefor, the next pass that references the cameraColor will reference this new temp texture as the cameraColor, saving us a blit. +// Therefore, the next pass that references the cameraColor will reference this new temp texture as the cameraColor, saving us a blit. // Using the ResourceData, you can manage swapping of resources yourself and don't need a bespoke API like the SwapColorBuffer API that was specific for the cameraColor. // This allows you to write more decoupled passes without the added costs of avoidable copies/blits. public class BlitAndSwapColorPass : ScriptableRenderPass @@ -24,43 +23,43 @@ public void Setup(Material mat) { m_BlitMaterial = mat; - //The pass will read the current color texture. That needs to be an intermediate texture. It's not supported to use the BackBuffer as input texture. - //By setting this property, URP will automatically create an intermediate texture. This has a performance cost so don't set this if you don't need it. - //It's good practice to set it here and not from the RenderFeature. This way, the pass is selfcontaining and you can use it to directly enqueue the pass from a monobehaviour without a RenderFeature. + // The pass will read the current color texture. That needs to be an intermediate texture. It's not supported to use the BackBuffer as input texture. + // By setting this property, URP will automatically create an intermediate texture. This has a performance cost so don't set this if you don't need it. + // It's good practice to set it here and not from the RenderFeature. This way, the pass is self-containing, + // and you can use it to directly enqueue the pass from a MonoBehaviour without a RenderFeature. requiresIntermediateTexture = true; } public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) { - // UniversalResourceData contains all the texture handles used by the renderer, including the active color and depth textures - // The active color and depth textures are the main color and depth buffers that the camera renders into + // UniversalResourceData contains all the texture handles used by the renderer, including the active color and depth textures. + // The active color and depth textures are the main color and depth buffers that the camera renders into. var resourceData = frameData.Get(); - //This should never happen since we set m_Pass.requiresIntermediateTexture = true; - //Unless you set the render event to AfterRendering, where we only have the BackBuffer. + // This should never happen since we set m_Pass.requiresIntermediateTexture = true; + // Unless you set the render event to AfterRendering, where we only have the BackBuffer. if (resourceData.isActiveTargetBackBuffer) { Debug.LogError($"Skipping render pass. BlitAndSwapColorRendererFeature requires an intermediate ColorTexture, we can't use the BackBuffer as a texture input."); return; } - // The destination texture is created here, - // the texture is created with the same dimensions as the active color texture + // The destination texture is created here, + // the texture is created with the same dimensions as the active color texture. var source = resourceData.activeColorTexture; - + var destinationDesc = renderGraph.GetTextureDesc(source); destinationDesc.name = $"CameraColor-{m_PassName}"; destinationDesc.clearBuffer = false; - TextureHandle destination = renderGraph.CreateTexture(destinationDesc); RenderGraphUtils.BlitMaterialParameters para = new(source, destination, m_BlitMaterial, 0); renderGraph.AddBlitPass(para, passName: m_PassName); - //FrameData allows to get and set internal pipeline buffers. Here we update the CameraColorBuffer to the texture that we just wrote to in this pass. - //Because RenderGraph manages the pipeline resources and dependencies, following up passes will correctly use the right color buffer. - //This optimization has some caveats. You have to be careful when the color buffer is persistent across frames and between different cameras, such as in camera stacking. - //In those cases you need to make sure your texture is an RTHandle and that you properly manage the lifecycle of it. + // FrameData allows to get and set internal pipeline buffers. Here we update the CameraColorBuffer to the texture that we just wrote to in this pass. + // Because RenderGraph manages the pipeline resources and dependencies, following up passes will correctly use the right color buffer. + // This optimization has some caveats. You have to be careful when the color buffer is persistent across frames and between different cameras, such as in camera stacking. + // In those cases you need to make sure your texture is an RTHandle and that you properly manage the lifecycle of it. resourceData.cameraColor = destination; } } @@ -75,7 +74,7 @@ public class BlitAndSwapColorRendererFeature : ScriptableRendererFeature BlitAndSwapColorPass m_Pass; - // Here you can create passes and do the initialization of them. This is called everytime serialization happens. + // Here you can create passes and do the initialization of them. This is called every time serialization happens. public override void Create() { m_Pass = new BlitAndSwapColorPass(); @@ -96,7 +95,7 @@ public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingD } m_Pass.Setup(material); - renderer.EnqueuePass(m_Pass); + renderer.EnqueuePass(m_Pass); } } diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitAndSwapColorRendererFeature.cs.meta b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitAndSwapColorRendererFeature.cs.meta index b29e14ce7c5..916f14de5ad 100644 --- a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitAndSwapColorRendererFeature.cs.meta +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitAndSwapColorRendererFeature.cs.meta @@ -1,2 +1,2 @@ fileFormatVersion: 2 -guid: 77eb6cb355f03b344a41286db9580ec6 \ No newline at end of file +guid: 7b89c4d71193d4b40b9b1532d7cc40ee \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitWithMaterial.mat b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitWithMaterial.mat index b00d17f621c..b9d7a5c984b 100644 --- a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitWithMaterial.mat +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitWithMaterial.mat @@ -21,7 +21,7 @@ Material: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_Name: BlitWithMaterial - m_Shader: {fileID: 4800000, guid: 385f641abc6b039499b848e66d7ca429, type: 3} + m_Shader: {fileID: 4800000, guid: fa0759f0cab2944609a61ef36ec489a2, type: 3} m_Parent: {fileID: 0} m_ModifiedSerializedProperties: 0 m_ValidKeywords: [] diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitWithMaterial.mat.meta b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitWithMaterial.mat.meta index 89e21d96bd1..5d8a3a8a26b 100644 --- a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitWithMaterial.mat.meta +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitWithMaterial.mat.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 8a71df55532db1d43b360c40a9f67532 +guid: 66d4c156766b146b7baa4a870a2fe9a7 NativeFormatImporter: externalObjects: {} mainObjectFileID: 0 diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitWithMaterial.shader.meta b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitWithMaterial.shader.meta index cc5d3d21b52..89295501e38 100644 --- a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitWithMaterial.shader.meta +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitWithMaterial.shader.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 385f641abc6b039499b848e66d7ca429 +guid: fa0759f0cab2944609a61ef36ec489a2 ShaderImporter: externalObjects: {} defaultTextures: [] diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Compute/ComputeRendererFeature.cs b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Compute/ComputeRendererFeature.cs index 0bea87d6db8..97a350ce7fc 100644 --- a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Compute/ComputeRendererFeature.cs +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Compute/ComputeRendererFeature.cs @@ -16,38 +16,29 @@ public class ComputeRendererFeature : ScriptableRendererFeature class ComputePass : ScriptableRenderPass { // Compute shader. - ComputeShader cs; + ComputeShader m_ComputeShader; - // Compute buffers: - GraphicsBuffer inputBuffer; - GraphicsBuffer outputBuffer; + // Compute buffers. + BufferHandle m_InputBufferHandle; + BufferHandle m_OutputBufferHandle; - // Reflection of the data output. I use a preallocated list to avoid memory - // allocations each frame. - int[] outputData = new int[20]; + // Input data for the compute shader. + private List inputData = new List(); - // Constructor is used to initialize the compute buffers. + // Constructor is used to initialize the input data. public ComputePass() { - BufferDesc desc = new BufferDesc(20, sizeof(int)); - inputBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, 20, sizeof(int)); - var list = new List(); for (int i = 0; i < 20; i++) { - list.Add(i); + inputData.Add(i); } - inputBuffer.SetData(list); - outputBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, 20, sizeof(int)); - // We don't need to initialize the output normaly with data but I read the - // buffer from the start when each frame is starting to look at last frames result. - outputBuffer.SetData(list); } // Setup function to transfer the compute shader from the renderer feature to // the render pass. public void Setup(ComputeShader cs) { - this.cs = cs; + m_ComputeShader = cs; } // PassData is used to pass data when recording to the execution of the pass. @@ -55,37 +46,75 @@ class PassData { // Compute shader. public ComputeShader cs; + // Buffer handles for the compute buffers. public BufferHandle input; public BufferHandle output; + public List bufferData; + } + + // ReadbackPassData is used to read data asynchronously from the specified bufferHandle. + class ReadbackPassData + { + public BufferHandle bufferHandle; } // Records a render graph render pass which blits the BlitData's active texture back to the camera's color attachment. public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) { - // Last frame data should be done. Retrive the data if valid. - outputBuffer.GetData(outputData); - Debug.Log($"Output from compute shader: {string.Join(", ", outputData)}"); - - // We need to import buffers when they are created outside of the render graph. - BufferHandle inputHandle = renderGraph.ImportBuffer(inputBuffer); - BufferHandle outputHandle = renderGraph.ImportBuffer(outputBuffer); + // Create buffers + var bufferDesc = new BufferDesc() + { + name = "InputBuffer", + count = 20, + stride = sizeof(int), + target = GraphicsBuffer.Target.Structured + }; + m_InputBufferHandle = renderGraph.CreateBuffer(bufferDesc); + + bufferDesc.name = "OutputBuffer"; + m_OutputBufferHandle = renderGraph.CreateBuffer(bufferDesc); // Starts the recording of the render graph pass given the name of the pass // and outputting the data used to pass data to the execution of the render function. // Notice that we use "AddComputePass" when we are working with compute. using (var builder = renderGraph.AddComputePass("ComputePass", out PassData passData)) { - // Set the pass data so the data can be transfered from the recording to the execution. - passData.cs = cs; - passData.input = inputHandle; - passData.output = outputHandle; - - // UseBuffer is used to setup render graph dependencies together with read and write flags. - builder.UseBuffer(passData.input); + // Set the pass data so the data can be transferred from the recording to the execution. + passData.cs = m_ComputeShader; + passData.input = m_InputBufferHandle; + passData.output = m_OutputBufferHandle; + passData.bufferData = inputData; + + // Log input data in the console to show before and after + Debug.Log($"Input Data: {string.Join(",", inputData)}"); + + // UseBuffer is used to set up render graph dependencies together with read and write flags. + builder.UseBuffer(passData.input, AccessFlags.Read); builder.UseBuffer(passData.output, AccessFlags.Write); - // The execution function is also call SetRenderfunc for compute passes. - builder.SetRenderFunc((PassData data, ComputeGraphContext cgContext) => ExecutePass(data, cgContext)); + + // The execution function is also called SetRenderFunc for compute passes. + builder.SetRenderFunc(static (PassData data, ComputeGraphContext cgContext) => ExecutePass(data, cgContext)); + } + + // Because our BufferHandles are managed by the render graph, we don't have access to the data when the + // RenderGraph is done executing. We need to add a pass to read from the output buffer if we want to + // use the output data from the compute shader. + using (var builder = renderGraph.AddUnsafePass("ReadbackPass", out ReadbackPassData passData)) + { + builder.AllowPassCulling(false); + + // Which buffer to read from + passData.bufferHandle = m_OutputBufferHandle; + builder.UseBuffer(passData.bufferHandle, AccessFlags.Read); + builder.SetRenderFunc(static (ReadbackPassData data, UnsafeGraphContext ctx) => + { + ctx.cmd.RequestAsyncReadback(data.bufferHandle, (AsyncGPUReadbackRequest request) => + { + var result = request.GetData(); + Debug.Log($"Output Data: {string.Join(",", result)}"); + }); + }); } } @@ -95,17 +124,17 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer static void ExecutePass(PassData data, ComputeGraphContext cgContext) { // Attaches the compute buffers. + cgContext.cmd.SetBufferData(data.input, data.bufferData); cgContext.cmd.SetComputeBufferParam(data.cs, data.cs.FindKernel("CSMain"), "inputData", data.input); cgContext.cmd.SetComputeBufferParam(data.cs, data.cs.FindKernel("CSMain"), "outputData", data.output); - // Dispaches the compute shader with a given kernel as entrypoint. - // The amount of thread groups determine how many groups to execute of the kernel. + // Dispatches the compute shader with a given kernel as entrypoint. + // The amount of thread groups determines how many groups to execute of the kernel. cgContext.cmd.DispatchCompute(data.cs, data.cs.FindKernel("CSMain"), 1, 1, 1); } } [SerializeField] ComputeShader computeShader; - ComputePass m_ComputePass; /// @@ -121,7 +150,7 @@ public override void Create() // This method is called when setting up the renderer once per-camera. public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { - // Check if the system support compute shaders, if not make an early exit. + // Check if the system supports compute shaders, if not make an early exit. if (!SystemInfo.supportsComputeShaders) { Debug.LogWarning("Device does not support compute shaders. The pass will be skipped."); diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Culling.meta b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Culling.meta new file mode 100644 index 00000000000..0c6e15bb779 --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Culling.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 598943c9393b540b986b90d0ba594f7c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Culling/CullingRenderPassRendererFeature.cs b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Culling/CullingRenderPassRendererFeature.cs index e80ab5380eb..a3b9007fae1 100644 --- a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Culling/CullingRenderPassRendererFeature.cs +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Culling/CullingRenderPassRendererFeature.cs @@ -8,7 +8,6 @@ public class CullingRenderPassRendererFeature : ScriptableRendererFeature { // Layer mask used to filter objects to put in the renderer list. public LayerMask m_LayerMask; - private CullingRenderPass m_CullingRenderPass; public override void Create() @@ -62,7 +61,7 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer var cameraData = frameData.Get(); - // CullContextData contains the culling APIs. + // CullContextData contains the culling APIs. var cullContextData = frameData.Get(); // Retrieve the culling parameters for the camera used. @@ -71,10 +70,10 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer // Perform culling using the CullContextData API. var cullingResults = cullContextData.Cull(ref cullingParameters); - // Fill up the passData with the data needed by the pass + // Fill up the passData with the data needed by the pass. InitRendererLists(cullingResults, frameData, ref passData, renderGraph); - // Make sure the renderer list is valid + // Make sure the renderer list is valid. if (!passData.rendererListHandle.IsValid()) return; @@ -86,7 +85,7 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer builder.SetRenderAttachmentDepth(resourceData.activeDepthTexture, AccessFlags.Write); // Assign the ExecutePass function to the render pass delegate, which will be called by the render graph when executing the pass. - builder.SetRenderFunc((PassData data, RasterGraphContext context) => ExecutePass(data, context)); + builder.SetRenderFunc(static (PassData data, RasterGraphContext context) => ExecutePass(data, context)); } } @@ -101,7 +100,7 @@ static void ExecutePass(PassData data, RasterGraphContext context) // Sample utility method that showcases how to create a renderer list via the RenderGraph API. private void InitRendererLists(CullingResults cullResults, ContextContainer frameData, ref PassData passData, RenderGraph renderGraph) { - // Access the relevant frame data from the Universal Render Pipeline + // Access the relevant frame data from the Universal Render Pipeline. var universalRenderingData = frameData.Get(); var cameraData = frameData.Get(); var lightData = frameData.Get(); diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Culling/CullingRenderPassRendererFeature.cs.meta b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Culling/CullingRenderPassRendererFeature.cs.meta new file mode 100644 index 00000000000..7d61df871e5 --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/Culling/CullingRenderPassRendererFeature.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 449c507e86381462c8fc85c5342da54a \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/FramebufferFetch/FrameBufferFetchRenderFeature.cs b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/FramebufferFetch/FrameBufferFetchRenderFeature.cs index d7bc6cc902f..f6e025241c9 100644 --- a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/FramebufferFetch/FrameBufferFetchRenderFeature.cs +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/FramebufferFetch/FrameBufferFetchRenderFeature.cs @@ -20,13 +20,14 @@ public FrameBufferFetchPass( Material fbFetchMaterial) { m_FBFetchMaterial = fbFetchMaterial; - //The pass will read the current color texture. That needs to be an intermediate texture. It's not supported to use the BackBuffer as input texture. - //By setting this property, URP will automatically create an intermediate texture. This has a performance cost so don't set this if you don't need it. - //It's good practice to set it here and not from the RenderFeature. This way, the pass is selfcontaining and you can use it to directly enqueue the pass from a monobehaviour without a RenderFeature. + // The pass will read the current color texture. That needs to be an intermediate texture. It's not supported to use the BackBuffer as input texture. + // By setting this property, URP will automatically create an intermediate texture. This has a performance cost so don't set this if you don't need it. + // It's good practice to set it here and not from the RenderFeature. This way, the pass is self-containing, + // and you can use it to directly enqueue the pass from a MonoBehaviour without a RenderFeature. requiresIntermediateTexture = true; } - // This class stores the data needed by the pass, passed as parameter to the delegate function that executes the pass + // This class stores the data needed by the pass, passed as parameter to the delegate function that executes the pass. private class PassData { internal TextureHandle src; @@ -34,7 +35,7 @@ private class PassData internal bool useMSAA; } - // This static method is used to execute the pass and passed as the RenderFunc delegate to the RenderGraph render pass + // This static method is used to execute the pass and passed as the RenderFunc delegate to the RenderGraph render pass. static void ExecuteFBFetchPass(PassData data, RasterGraphContext context) { context.cmd.DrawProcedural(Matrix4x4.identity, data.material, data.useMSAA? 1 : 0, MeshTopology.Triangles, 3, 1, null); @@ -47,30 +48,30 @@ private void FBFetchPass(RenderGraph renderGraph, ContextContainer frameData, Te // This simple pass copies the target of the previous pass to a new texture using a custom material and framebuffer fetch. This sample is for API demonstrative purposes, // so the new texture is not used anywhere else in the frame, you can use the frame debugger to verify its contents. - // add a raster render pass to the render graph, specifying the name and the data type that will be passed to the ExecutePass function + // add a raster render pass to the render graph, specifying the name and the data type that will be passed to the ExecutePass function. using (var builder = renderGraph.AddRasterRenderPass(passName, out var passData)) { - // Fill the pass data + // Fill the pass data. passData.material = m_FBFetchMaterial; passData.useMSAA = useMSAA; - // We declare the src as input attachment. This is required for Frame buffer fetch. + // We declare the src as input attachment. This is required for framebuffer fetch. builder.SetInputAttachment(source, 0, AccessFlags.Read); - // Setup as a render target via UseTextureFragment, which is the equivalent of using the old cmd.SetRenderTarget + // Setup as a render target via UseTextureFragment, which is the equivalent of using the old cmd.SetRenderTarget. builder.SetRenderAttachment(destination, 0); // We disable culling for this pass for the demonstrative purpose of this sample, as normally this pass would be culled, - // since the destination texture is not used anywhere else + // since the destination texture is not used anywhere else. builder.AllowPassCulling(false); - // Assign the ExecutePass function to the render pass delegate, which will be called by the render graph when executing the pass - builder.SetRenderFunc((PassData data, RasterGraphContext context) => ExecuteFBFetchPass(data, context)); + // Assign the ExecutePass function to the render pass delegate, which will be called by the render graph when executing the pass. + builder.SetRenderFunc(static (PassData data, RasterGraphContext context) => ExecuteFBFetchPass(data, context)); } } // This is where the renderGraph handle can be accessed. - // Each ScriptableRenderPass can use the RenderGraph handle to add multiple render passes to the render graph + // Each ScriptableRenderPass can use the RenderGraph handle to add multiple render passes to the render graph. public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) { // This pass showcases how to implement framebuffer fetch: this is an advanced TBDR GPU optimization @@ -80,8 +81,8 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer // As a result, the passes are merged (you can verify in the RenderGraph Visualizer) and the bandwidth usage is reduced, since we can discard the temporary render target. - // UniversalResourceData contains all the texture handles used by the renderer, including the active color and depth textures - // The active color and depth textures are the main color and depth buffers that the camera renders into + // UniversalResourceData contains all the texture handles used by the renderer, including the active color and depth textures. + // The active color and depth textures are the main color and depth buffers that the camera renders into. var resourceData = frameData.Get(); // The destination texture is created here, @@ -98,8 +99,8 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer FBFetchPass(renderGraph, frameData, source, fbFetchDestination, destinationDesc.msaaSamples != MSAASamples.None); - //Copy back the FBF output to the camera color to easily see the result in the game view - //This copy pass also uses FBF under the hood. All the passes should be merged this way and the destination attachment should be memoryless (no load/store of memory). + // Copy back the FBF output to the camera color to easily see the result in the game view. + // This copy pass also uses FBF under the hood. All the passes should be merged this way and the destination attachment should be memoryless (no load/store of memory). renderGraph.AddCopyPass(fbFetchDestination, source, passName: "Copy Back FF Destination (also using FBF)"); } else @@ -110,7 +111,6 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer } FrameBufferFetchPass m_FbFetchPass; - public Material m_FBFetchMaterial; /// diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/GbufferVisualization/GbufferVisualizationRendererFeature.cs b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/GbufferVisualization/GbufferVisualizationRendererFeature.cs index dd32bf72d7b..228951d5290 100644 --- a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/GbufferVisualization/GbufferVisualizationRendererFeature.cs +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/GbufferVisualization/GbufferVisualizationRendererFeature.cs @@ -22,28 +22,28 @@ class GBufferVisualizationRenderPass : ScriptableRenderPass // private static readonly int GBufferRenderingLayersIndex = 5; // Components marked as optional are only present when the pipeline requests it. - // If for example there is no rendering layers texture, _GBuffer5 will contain the ShadowMask texture + // If for example there is no rendering layers texture, _GBuffer5 will contain the ShadowMask texture. private static readonly int[] s_GBufferShaderPropertyIDs = new int[] { - // Contains Albedo Texture + // Contains Albedo texture. Shader.PropertyToID("_GBuffer0"), - // Contains Specular Metallic Texture + // Contains Specular Metallic texture. Shader.PropertyToID("_GBuffer1"), - // Contains Normals and Smoothness, referenced as _CameraNormalsTexture in other shaders + // Contains Normals and Smoothness, referenced as _CameraNormalsTexture in other shaders. Shader.PropertyToID("_GBuffer2"), - // Contains Lighting texture + // Contains Lighting texture. Shader.PropertyToID("_GBuffer3"), - // Contains Depth texture, referenced as _CameraDepthTexture in other shaders (optional) + // Contains Depth texture, referenced as _CameraDepthTexture in other shaders (optional). Shader.PropertyToID("_GBuffer4"), - // Contains Rendering Layers Texture, referenced as _CameraRenderingLayersTexture in other shaders (optional) + // Contains Rendering Layers texture, referenced as _CameraRenderingLayersTexture in other shaders (optional). Shader.PropertyToID("_GBuffer5"), - // Contains ShadowMask texture (optional) + // Contains ShadowMask texture (optional). Shader.PropertyToID("_GBuffer6") }; @@ -59,7 +59,7 @@ public void Setup(Material material) m_Material = material; } - // This method will draw the contents of the gBuffer component requested in the shader + // This method will draw the contents of the gBuffer component requested in the shader. static void ExecutePass(PassData data, RasterGraphContext context) { // Here, we read all the gBuffer components as an example even though the shader only needs one. @@ -70,7 +70,7 @@ static void ExecutePass(PassData data, RasterGraphContext context) data.material.SetTexture(s_GBufferShaderPropertyIDs[i], data.gBuffer[i]); } - // Draw the gBuffer component requested by the shader over the geometry + // Draw the gBuffer component requested by the shader over the geometry. context.cmd.DrawProcedural(Matrix4x4.identity, data.material, 0, MeshTopology.Triangles, 3, 1); } @@ -94,14 +94,14 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer // For this pass, we want to write to the activeColorTexture, which is the gBuffer Lighting component (_GBuffer3) in the deferred path. builder.SetRenderAttachment(resourceData.activeColorTexture, 0, AccessFlags.Write); - // We are reading the gBuffer components in our pass, so we need call UseTexture on them. + // We are reading the gBuffer components in our pass, so we need to call UseTexture on them. // When they are global, they can be all read with builder.UseAllGlobalTexture(true), but // in this pass they are not global. for (int i = 0; i < resourceData.gBuffer.Length; i++) { if (i == GbufferLightingIndex) { - // We already specify we are writing to it above (SetRenderAttachment) + // We already specify we are writing to it above (SetRenderAttachment). continue; } @@ -112,7 +112,7 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer passData.gBuffer = gBuffer; // Assigns the ExecutePass function to the render pass delegate. This will be called by the render graph when executing the pass. - builder.SetRenderFunc((PassData data, RasterGraphContext context) => ExecutePass(data, context)); + builder.SetRenderFunc(static (PassData data, RasterGraphContext context) => ExecutePass(data, context)); } } } @@ -132,7 +132,7 @@ public override void Create() public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { - // The gBuffers are only used in the Deferred rendering path + // The gBuffers are only used in the Deferred rendering path. if (m_Material != null) { m_GBufferRenderPass.Setup(m_Material); diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/GlobalGbuffers/GlobalGbuffersRendererFeature.cs b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/GlobalGbuffers/GlobalGbuffersRendererFeature.cs index 0ac205a0689..16adb100ff9 100644 --- a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/GlobalGbuffers/GlobalGbuffersRendererFeature.cs +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/GlobalGbuffers/GlobalGbuffersRendererFeature.cs @@ -20,29 +20,29 @@ class GlobalGBuffersRenderPass : ScriptableRenderPass private static readonly int GbufferLightingIndex = 3; private static readonly int GBufferRenderingLayersIndex = 5; - // The pipeline already sets the gBuffer depth component to be global in a few places, so uncomment this code as needed + // The pipeline already sets the gBuffer depth component to be global in a few places, so uncomment this code as needed. // private static readonly int GbufferDepthIndex = 4; // Components marked as optional are only present when the pipeline requests it. - // If for example there is no rendering layers texture, _GBuffer5 will contain the ShadowMask texture + // If for example there is no rendering layers texture, _GBuffer5 will contain the ShadowMask texture. private static readonly int[] s_GBufferShaderPropertyIDs = new int[] { - // Contains Albedo Texture + // Contains Albedo texture. Shader.PropertyToID("_GBuffer0"), - // Contains Specular Metallic Texture + // Contains Specular Metallic texture. Shader.PropertyToID("_GBuffer1"), - // Contains Normals and Smoothness, referenced as _CameraNormalsTexture in other shaders + // Contains Normals and Smoothness, referenced as _CameraNormalsTexture in other shaders. Shader.PropertyToID("_GBuffer2"), - // Contains Lighting texture + // Contains Lighting texture. Shader.PropertyToID("_GBuffer3"), - // Contains Depth texture, referenced as _CameraDepthTexture in other shaders (optional) + // Contains Depth texture, referenced as _CameraDepthTexture in other shaders (optional). Shader.PropertyToID("_GBuffer4"), - // Contains Rendering Layers Texture, referenced as _CameraRenderingLayersTexture in other shaders (optional) + // Contains Rendering Layers texture, referenced as _CameraRenderingLayersTexture in other shaders (optional). Shader.PropertyToID("_GBuffer5"), // Contains ShadowMask texture (optional) @@ -55,11 +55,11 @@ private class PassData // This sets the gBuffer components as global after the current pass. After the pass, the gBuffers components made global // will be made accessible using 'builder.UseAllGlobalTextures(true)' instead of 'builder.UseTexture(gBuffer[i]) - // Shaders that use global texture will be able to fetch them without the need to call 'material.SetTexture()' + // Shaders that use global textures will be able to fetch them without the need to call 'material.SetTexture()' // like we do in the ExecutePass function of this pass. private void SetGlobalGBufferTextures(IRasterRenderGraphBuilder builder, TextureHandle[] gBuffer) { - // This loop will make the gBuffers accessible by all shaders using _GBufferX texture shader IDs + // This loop will make the gBuffers accessible by all shaders using _GBufferX texture shader IDs. for (int i = 0; i < gBuffer.Length; i++) { if (i != GbufferLightingIndex && gBuffer[i].IsValid()) @@ -70,12 +70,12 @@ private void SetGlobalGBufferTextures(IRasterRenderGraphBuilder builder, Texture // need to set the ID to point to the corresponding gBuffer component. if (gBuffer[GBufferNormalSmoothnessIndex].IsValid()) { - // After this pass, shaders that use the _CameraNormalsTexture will get the gBuffer's NormalsSmoothnessTexture component + // After this pass, shaders that use the _CameraNormalsTexture will get the gBuffer's NormalsSmoothnessTexture component. builder.SetGlobalTextureAfterPass(gBuffer[GBufferNormalSmoothnessIndex], Shader.PropertyToID("_CameraNormalsTexture")); } - // The pipeline already sets the gBuffer depth component to be global in a few places, so uncomment this code as needed + // The pipeline already sets the gBuffer depth component to be global in a few places, so uncomment this code as needed. // if (GbufferDepthIndex < gBuffer.Length && gBuffer[GbufferDepthIndex].IsValid()) // { // // After this pass, shaders that use the _CameraDepthTexture will get the gBuffer's Depth component (note that it is also set global by the copy depth pass) @@ -85,7 +85,7 @@ private void SetGlobalGBufferTextures(IRasterRenderGraphBuilder builder, Texture if (GBufferRenderingLayersIndex < gBuffer.Length && gBuffer[GBufferRenderingLayersIndex].IsValid()) { - // After this pass, shaders that use the _CameraRenderingLayersTexture will get the gBuffer's RenderingLayersTexture component + // After this pass, shaders that use the _CameraRenderingLayersTexture will get the gBuffer's RenderingLayersTexture component. builder.SetGlobalTextureAfterPass(gBuffer[GBufferRenderingLayersIndex], Shader.PropertyToID("_CameraRenderingLayersTexture")); } @@ -96,20 +96,20 @@ private void SetGlobalGBufferTextures(IRasterRenderGraphBuilder builder, Texture public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) { UniversalRenderingData universalRenderingData = frameData.Get(); - // The gBuffer components are only used in deferred mode + // The gBuffer components are only used in deferred mode. if (universalRenderingData.renderingMode != RenderingMode.Deferred) return; - // Get the gBuffer texture handles are stored in the resourceData + // Get the gBuffer texture handles are stored in the resourceData. UniversalResourceData resourceData = frameData.Get(); TextureHandle[] gBuffer = resourceData.gBuffer; using (var builder = renderGraph.AddRasterRenderPass(m_PassName, out var passData)) { builder.AllowPassCulling(false); - // Set the gBuffers to be global after the pass + // Set the gBuffers to be global after the pass. SetGlobalGBufferTextures(builder, gBuffer); - builder.SetRenderFunc((PassData data, RasterGraphContext context) => { /* nothing to be rendered */ }); + builder.SetRenderFunc(static (PassData data, RasterGraphContext context) => { /* nothing to be rendered */ }); } } } diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/MRT/MrtRendererFeature.cs b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/MRT/MrtRendererFeature.cs index 4fca8a725ca..60179252699 100644 --- a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/MRT/MrtRendererFeature.cs +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/MRT/MrtRendererFeature.cs @@ -36,7 +36,7 @@ public void Setup(string texName, Material material, RenderTexture[] renderTextu m_texName = String.IsNullOrEmpty(texName) ? "_ColorTexture" : texName; - //Create RTHandles from the RenderTextures if they have changed. + // Create RTHandles from the RenderTextures if they have changed. for (int i = 0; i < 3; i++) { if (m_RTs[i] == null || m_RTs[i].rt != renderTextures[i]) @@ -60,7 +60,7 @@ public void Setup(string texName, Material material, RenderTexture[] renderTextu public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) { var handles = new TextureHandle[3]; - // Imports the texture handles them in RenderGraph. + // Imports the texture handles in RenderGraph. for (int i = 0; i < 3; i++) { handles[i] = renderGraph.ImportTexture(m_RTs[i], m_RTInfos[i]); @@ -69,7 +69,7 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer // and outputting the data used to pass data to the execution of the render function. using (var builder = renderGraph.AddRasterRenderPass("MRT Pass", out var passData)) { - // Fetch the universal resource data to exstract the camera's color attachment. + // Fetch the universal resource data to extract the camera's color attachment. var resourceData = frameData.Get(); // Fill in the pass data using by the render function. @@ -90,7 +90,7 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer } // Sets the render function. - builder.SetRenderFunc((PassData data, RasterGraphContext rgContext) => ExecutePass(data, rgContext)); + builder.SetRenderFunc(static (PassData data, RasterGraphContext rgContext) => ExecutePass(data, rgContext)); } } @@ -115,7 +115,7 @@ static void ExecutePass(PassData data, RasterGraphContext rgContext) MrtPass m_MrtPass; - // Here you can create passes and do the initialization of them. This is called everytime serialization happens. + // Here you can create passes and do the initialization of them. This is called every time serialization happens. public override void Create() { m_MrtPass = new MrtPass(); @@ -133,7 +133,7 @@ public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingD // Early exit if there are no materials. if (mrtMaterial == null || renderTextures.Length != 3) { - Debug.LogWarning("Skipping MRTPass because the material is null or render textures doesn't have a size of 3."); + Debug.LogWarning("Skipping MRTPass because the material is null or the renderTextures array doesn't have a size of 3."); return; } diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/OutputTexture/OutputTextureRendererFeature.cs b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/OutputTexture/OutputTextureRendererFeature.cs index 18b7de52ec4..e282d491abf 100644 --- a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/OutputTexture/OutputTextureRendererFeature.cs +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/OutputTexture/OutputTextureRendererFeature.cs @@ -6,11 +6,11 @@ using UnityEngine.Rendering.RenderGraphModule.Util; // MERGING: This pass can be merged with Draw Objects Pass and Draw Skybox pass if you set the m_PassEvent in -// the inspector to After Rendering Opagues and set the texture type to Normal. -// Your can observe this merging in the Render Graph Visualizer. If set to After Rendering Post Processing we -// can now see that the pass isn't merged with any thing. +// the inspector to After Rendering Opaques and set the texture type to Normal. +// You can observe this merging in the Render Graph Visualizer. If set to After Rendering Post Processing we +// can now see that the pass isn't merged with anything. -// This RenderFeature shows how to used RenderGraph to output a specific texture used in URP, how a texture +// This RenderFeature shows how to use the RenderGraph to output a specific texture used in URP, how a texture // can be attached by name to a material and how two render passes can be merged if executed in the correct order. public class OutputTextureRendererFeature : ScriptableRendererFeature { @@ -42,20 +42,20 @@ static TextureHandle GetTextureHandleFromType(UniversalResourceData resourceData } } - // Pass which outputs a texture from rendering to inspect a texture + // Pass which outputs a texture from rendering to inspect a texture. class OutputTexturePass : ScriptableRenderPass { // The texture name you wish to bind the texture handle to for a given material. string m_TextureName; - // The texture type you want to retrive from URP. + // The texture type you want to retrieve from URP. TextureType m_TextureType; // The material used for blitting to the color output. Material m_Material; - // Function set setup the ConfigureInput() and transfer the renderer feature settings to the render pass. + // Function to set up the ConfigureInput() and transfer the renderer feature settings to the render pass. public void Setup(string textureName, TextureType textureType, Material material) { - // Setup code to trigger each corrspoinding texture is ready for use one the pass is run. + // Setup code to trigger each corresponding texture is ready for use when the pass is run. if (textureType == TextureType.OpaqueColor) ConfigureInput(ScriptableRenderPassInput.Color); else if (textureType == TextureType.Depth) @@ -65,11 +65,11 @@ public void Setup(string textureName, TextureType textureType, Material material else if (textureType == TextureType.MotionVector) ConfigureInput(ScriptableRenderPassInput.Motion); - // Setup the texture name, type and material used when blitting. - // In this example we will use a mateial using a custom name for the input texture name when blitting. + // Set up the texture name, type and material used when blitting. + // In this example we will use a material using a custom name for the input texture name when blitting. // This texture name has to match the material texture input you are using. m_TextureName = String.IsNullOrEmpty(textureName) ? "_BlitTexture" : textureName; - // Texture type selects which input we would like to retrive from the camera. + // Texture type selects which input we would like to retrieve from the camera. m_TextureType = textureType; // The material is used to blit the texture to the cameras color attachment. m_Material = material; @@ -78,7 +78,7 @@ public void Setup(string textureName, TextureType textureType, Material material // Records a render graph render pass which blits the BlitData's active texture back to the camera's color attachment. public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) { - // Fetch UniversalResourceData from frameData to retrive the URP's texture handles. + // Fetch UniversalResourceData from frameData to retrieve the URP's texture handles. var resourceData = frameData.Get(); // Sets the texture handle input using the helper function to fetch the correct handle from resourceData. @@ -120,6 +120,12 @@ public override void Create() // This method is called when setting up the renderer once per-camera. public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { + if (m_Material == null) + { + Debug.LogWarning("Skipping OutputTexturePass because the material is null."); + return; + } + // Setup the correct data for the render pass, and transfers the data from the renderer feature to the render pass. m_ScriptablePass.Setup(m_TextureName, m_TextureType, m_Material); renderer.EnqueuePass(m_ScriptablePass); diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/RendererList/RendererListRenderFeature.cs b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/RendererList/RendererListRenderFeature.cs index decc8904fa6..ef6a672868d 100644 --- a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/RendererList/RendererListRenderFeature.cs +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/RendererList/RendererListRenderFeature.cs @@ -2,7 +2,6 @@ using UnityEngine; using UnityEngine.Rendering.RenderGraphModule; using UnityEngine.Rendering; -using UnityEngine.Rendering.RendererUtils; using UnityEngine.Rendering.Universal; // This example clears the current active color texture, then renders the scene geometry associated to the m_LayerMask layer. @@ -12,10 +11,10 @@ public class RendererListRenderFeature : ScriptableRendererFeature { class RendererListPass : ScriptableRenderPass { - // Layer mask used to filter objects to put in the renderer list + // Layer mask used to filter objects to put in the renderer list. private LayerMask m_LayerMask; - // List of shader tags used to build the renderer list + // List of shader tags used to build the renderer list. private List m_ShaderTagIdList = new List(); public RendererListPass(LayerMask layerMask) @@ -23,16 +22,16 @@ public RendererListPass(LayerMask layerMask) m_LayerMask = layerMask; } - // This class stores the data needed by the pass, passed as parameter to the delegate function that executes the pass + // This class stores the data needed by the pass, passed as parameter to the delegate function that executes the pass. private class PassData { public RendererListHandle rendererListHandle; } - // Sample utility method that showcases how to create a renderer list via the RenderGraph API + // Sample utility method that showcases how to create a renderer list via the RenderGraph API. private void InitRendererLists(ContextContainer frameData, ref PassData passData, RenderGraph renderGraph) { - // Access the relevant frame data from the Universal Render Pipeline + // Access the relevant frame data from the Universal Render Pipeline. UniversalRenderingData universalRenderingData = frameData.Get(); UniversalCameraData cameraData = frameData.Get(); UniversalLightData lightData = frameData.Get(); @@ -45,8 +44,8 @@ private void InitRendererLists(ContextContainer frameData, ref PassData passData { new ShaderTagId("UniversalForwardOnly"), new ShaderTagId("UniversalForward"), - new ShaderTagId("SRPDefaultUnlit"), // Legacy shaders (do not have a gbuffer pass) are considered forward-only for backward compatibility - new ShaderTagId("LightweightForward") // Legacy shaders (do not have a gbuffer pass) are considered forward-only for backward compatibility + new ShaderTagId("SRPDefaultUnlit"), // Legacy shaders (do not have a gbuffer pass) are considered forward-only for backward compatibility. + new ShaderTagId("LightweightForward") // Legacy shaders (do not have a gbuffer pass) are considered forward-only for backward compatibility. }; m_ShaderTagIdList.Clear(); @@ -60,7 +59,7 @@ private void InitRendererLists(ContextContainer frameData, ref PassData passData passData.rendererListHandle = renderGraph.CreateRendererList(param); } - // This static method is used to execute the pass and passed as the RenderFunc delegate to the RenderGraph render pass + // This static method is used to execute the pass and passed as the RenderFunc delegate to the RenderGraph render pass. static void ExecutePass(PassData data, RasterGraphContext context) { context.cmd.ClearRenderTarget(RTClearFlags.Color, Color.green, 1,0); @@ -69,46 +68,43 @@ static void ExecutePass(PassData data, RasterGraphContext context) } // This is where the renderGraph handle can be accessed. - // Each ScriptableRenderPass can use the RenderGraph handle to add multiple render passes to the render graph + // Each ScriptableRenderPass can use the RenderGraph handle to add multiple render passes to the render graph. public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) { string passName = "RenderList Render Pass"; // This simple pass clears the current active color texture, then renders the scene geometry associated to the m_LayerMask layer. // Add scene geometry to your own custom layers and experiment switching the layer mask in the render feature UI. - // You can use the frame debugger to inspect the pass output + // You can use the frame debugger to inspect the pass output. // add a raster render pass to the render graph, specifying the name and the data type that will be passed to the ExecutePass function using (var builder = renderGraph.AddRasterRenderPass(passName, out var passData)) { // UniversalResourceData contains all the texture handles used by the renderer, including the active color and depth textures - // The active color and depth textures are the main color and depth buffers that the camera renders into + // The active color and depth textures are the main color and depth buffers that the camera renders into. UniversalResourceData resourceData = frameData.Get(); - // Fill up the passData with the data needed by the pass + // Fill up the passData with the data needed by the pass. InitRendererLists(frameData, ref passData, renderGraph); - // Make sure the renderer list is valid - //if (!passData.rendererListHandle.IsValid()) - // return; + // Optional check to make sure the rendererList is valid. If it isn't, the pass will not execute (instead of the render graph possibly throwing an error). + if (!passData.rendererListHandle.IsValid()) + return; - // We declare the RendererList we just created as an input dependency to this pass, via UseRendererList() + // We declare the RendererList we just created as an input dependency to this pass, via UseRendererList(). builder.UseRendererList(passData.rendererListHandle); // Setup as a render target via UseTextureFragment and UseTextureFragmentDepth, which are the equivalent of using the old cmd.SetRenderTarget(color,depth) builder.SetRenderAttachment(resourceData.activeColorTexture, 0); builder.SetRenderAttachmentDepth(resourceData.activeDepthTexture, AccessFlags.Write); - // Assign the ExecutePass function to the render pass delegate, which will be called by the render graph when executing the pass - builder.SetRenderFunc((PassData data, RasterGraphContext context) => ExecutePass(data, context)); - - builder.SetRenderFunc(ExecutePass); + // Assign the ExecutePass function to the render pass delegate, which will be called by the render graph when executing the pass. + builder.SetRenderFunc(static (PassData data, RasterGraphContext context) => ExecutePass(data, context)); } } } RendererListPass m_ScriptablePass; - public LayerMask m_LayerMask; /// diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/TextureReference w. FrameData.meta b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/TextureReferenceWithFrameData.meta similarity index 100% rename from Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/TextureReference w. FrameData.meta rename to Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/TextureReferenceWithFrameData.meta diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/TextureReference w. FrameData/TextureRefRendererFeature.cs b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/TextureReferenceWithFrameData/TextureRefRendererFeature.cs similarity index 51% rename from Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/TextureReference w. FrameData/TextureRefRendererFeature.cs rename to Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/TextureReferenceWithFrameData/TextureRefRendererFeature.cs index e6a46a05a4f..45fc04cde34 100644 --- a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/TextureReference w. FrameData/TextureRefRendererFeature.cs +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/TextureReferenceWithFrameData/TextureRefRendererFeature.cs @@ -5,10 +5,10 @@ using UnityEngine.Rendering.RenderGraphModule.Util; // In this example we will create a texture reference ContextItem in frameData to hold a reference -// used by furture passes. This is usefull to avoid additional blit operations copying back and forth -// to the cameras color attachment. Instead of copying it back after the blit operation we can instead +// used by future passes. This is useful to avoid additional blit operations copying back and forth +// to the camera's color attachment. Instead of copying it back after the blit operation we can instead // update the reference to the blit destination and use that for future passes. -// The is the prefered way to share resources between passes. Previously, it was common to use global textures for this. +// The frameData is the preferred way to share resources between passes. Previously, it was common to use global textures for this. // However, it's better to avoid using global textures where you can. public class TextureRefRendererFeature : ScriptableRendererFeature { @@ -22,7 +22,7 @@ public class TexRefData : ContextItem // over to next frame. public override void Reset() { - // We should always reset texture handles since they are only vaild for the current frame. + // We should always reset texture handles since they are only valid for the current frame. texture = TextureHandle.nullHandle; } } @@ -30,20 +30,6 @@ public override void Reset() // This pass updates the reference when making a blit operation using a material and the camera's color attachment. class UpdateRefPass : ScriptableRenderPass { - // The data we want to transfer to the render function after recording. - class PassData - { - // For the blit operation we will need the source and destination of the color attachments. - public TextureHandle source; - public TextureHandle destination; - // We will also need a material to transform the color attachment when making a blit operation. - public Material material; - } - - // Scale bias is used to blit from source to distination given a 2d scale in the x and y parameters - // and an offset in the z and w parameters. - static Vector4 scaleBias = new Vector4(1f, 1f, 0f, 0f); - // Material used in the blit operation. Material[] m_DisplayMaterials; @@ -64,61 +50,36 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer Debug.LogWarning($"Skipping render pass for unassigned material."); continue; } + + var texRefExist = frameData.Contains(); + var texRef = frameData.GetOrCreate(); - - // Starts the recording of the render graph pass given the name of the pass - // and outputting the data used to pass data to the execution of the render function. - using (var builder = renderGraph.AddRasterRenderPass($"UpdateRefPass_{mat.name}", out var passData)) + // First time running this pass. Fetch ref from active color buffer. + if (!texRefExist) { - var texRefExist = frameData.Contains(); - var texRef = frameData.GetOrCreate(); - - // First time running this pass. Fetch ref from active color buffer. - if (!texRefExist) - { - var resourceData = frameData.Get(); - // For this first occurence we would like - texRef.texture = resourceData.activeColorTexture; - } - - // Fill in the pass data using by the render function. - - // Use the old reference from TexRefData. - passData.source = texRef.texture; - - var descriptor = passData.source.GetDescriptor(renderGraph); - // We disable MSAA for the blit operations. - descriptor.msaaSamples = MSAASamples.None; - descriptor.name = $"BlitMaterialRefTex_{mat.name}"; - descriptor.clearBuffer = false; - - // Create a new temporary texture to keep the blit result. - passData.destination = renderGraph.CreateTexture(descriptor); - - // Material used in the blit operation. - passData.material = mat; - - // Update the texture reference to the blit destination. - texRef.texture = passData.destination; - - // Sets input attachment. - builder.UseTexture(passData.source); - // Sets color attachment 0. - builder.SetRenderAttachment(passData.destination, 0); - - // Sets the render function. - builder.SetRenderFunc((PassData data, RasterGraphContext rgContext) => ExecutePass(data, rgContext)); + var resourceData = frameData.Get(); + // For this first occurrence we would like: + texRef.texture = resourceData.activeColorTexture; } + + // Create the destination texture for the pass. + var descriptor = texRef.texture.GetDescriptor(renderGraph); + // We disable MSAA for the blit operations. + descriptor.msaaSamples = MSAASamples.None; + descriptor.name = $"BlitMaterialRefTex_{mat.name}"; + descriptor.clearBuffer = false; + + // Create a new temporary texture to keep the blit result. + var destination = renderGraph.CreateTexture(descriptor); + + // Fill in the pass data used by the render function. + var blitPassParams = new RenderGraphUtils.BlitMaterialParameters(texRef.texture, destination, mat, 0); + renderGraph.AddBlitPass(blitPassParams, $"UpdateRefPass_{mat.name}"); + + // Update the texRef. + texRef.texture = destination; } } - - // ExecutePass is the render function for each of the blit render graph recordings. - // This is good practice to avoid using variables outside of the lambda it is called from. - // It is static to avoid using member variables which could cause unintended behaviour. - static void ExecutePass(PassData data, RasterGraphContext rgContext) - { - Blitter.BlitTexture(rgContext.cmd, data.source, scaleBias, data.material, 0); - } } // After updating the reference we will need to use the result copying it back to camera's @@ -128,12 +89,12 @@ class CopyBackRefPass : ScriptableRenderPass // This function blits the reference back to the camera's color attachment. public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) { - // Early exit if TexRefData doesn't exist within frameData since where is nothing to copy back. + // Early exit if TexRefData doesn't exist within frameData since there is nothing to copy back. if (!frameData.Contains()) return; - // Fetch UniversalResourceData to retrive the camera's active color texture. + // Fetch UniversalResourceData to retrieve the camera's active color texture. var resourceData = frameData.Get(); - // Fetch TexRefData to retrive the texture reference. + // Fetch TexRefData to retrieve the texture reference. var texRef = frameData.Get(); renderGraph.AddBlitPass(texRef.texture, resourceData.activeColorTexture, Vector2.one, Vector2.zero, passName: "Blit Back Pass"); @@ -146,7 +107,7 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer UpdateRefPass m_UpdateRefPass; CopyBackRefPass m_CopyBackRefPass; - // Here you can create passes and do the initialization of them. This is called everytime serialization happens. + // Here you can create passes and do the initialization of them. This is called every time serialization happens. public override void Create() { m_UpdateRefPass = new UpdateRefPass(); @@ -161,8 +122,6 @@ public override void Create() // This method is called when setting up the renderer once per-camera. public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { - // Since they have the same RenderPassEvent the order matters when enqueueing them. - // Early exit if there are no materials. if (displayMaterials == null) { @@ -170,6 +129,7 @@ public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingD return; } + // Since they have the same RenderPassEvent the order matters when enqueueing them. m_UpdateRefPass.Setup(displayMaterials); renderer.EnqueuePass(m_UpdateRefPass); renderer.EnqueuePass(m_CopyBackRefPass); diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/TextureReference w. FrameData/TextureRefRendererFeature.cs.meta b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/TextureReferenceWithFrameData/TextureRefRendererFeature.cs.meta similarity index 100% rename from Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/TextureReference w. FrameData/TextureRefRendererFeature.cs.meta rename to Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/TextureReferenceWithFrameData/TextureRefRendererFeature.cs.meta diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/UnsafePass/UnsafePassRenderFeature.cs b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/UnsafePass/UnsafePassRenderFeature.cs index a495acd6c20..8e06b663816 100644 --- a/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/UnsafePass/UnsafePassRenderFeature.cs +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/UnsafePass/UnsafePassRenderFeature.cs @@ -5,15 +5,15 @@ // This example copies the active color texture to a new texture, it then downsamples the source texture twice. This example is for API demonstrative purposes, // so the new textures are not used anywhere else in the frame, you can use the frame debugger to verify their contents. -// The key concept of this example, is the UnsafePass usage: these type of passes are unsafe and allow using command like SetRenderTarget() which are +// The key concept of this example, is the UnsafePass usage: these type of passes are unsafe and allow using commands like SetRenderTarget() which are // not compatible with RasterRenderPasses. Using UnsafePasses means that the RenderGraph won't try to optimize the pass by merging it inside a NativeRenderPass. // In some cases using UnsafePasses makes sense, if for example we know that a set of adjacent passes are not mergeable, so this can optimize the RenderGraph -// compiling times, on top of simplifying the multiple passes setup. +// compile time, on top of simplifying the multiple passes setup. public class UnsafePassRenderFeature : ScriptableRendererFeature { class UnsafePass : ScriptableRenderPass { - // This class stores the data needed by the pass, passed as parameter to the delegate function that executes the pass + // This class stores the data needed by the pass, passed as parameter to the delegate function that executes the pass. private class PassData { internal TextureHandle source; @@ -22,11 +22,11 @@ private class PassData internal TextureHandle destinationQuarter; } - // This static method is used to execute the pass and passed as the RenderFunc delegate to the RenderGraph render pass + // This static method is used to execute the pass and passed as the RenderFunc delegate to the RenderGraph render pass. static void ExecutePass(PassData data, UnsafeGraphContext context) { // Set manually the RenderTarget for each blit. Each SetRenderTarget call would require a separate RasterCommandPass if we wanted - // to setup RenderGraph for merging passes when possible. + // to set up RenderGraph for merging passes when possible. // In this case we know that these 3 subpasses are not compatible for merging, because RenderTargets have different dimensions, // so we simplify our code to use an unsafe pass, also saving RenderGraph processing time. @@ -55,32 +55,32 @@ static void ExecutePass(PassData data, UnsafeGraphContext context) } // This is where the renderGraph handle can be accessed. - // Each ScriptableRenderPass can use the RenderGraph handle to add multiple render passes to the render graph + // Each ScriptableRenderPass can use the RenderGraph handle to add multiple render passes to the render graph. public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) { string passName = "Unsafe Pass"; - // add a raster render pass to the render graph, specifying the name and the data type that will be passed to the ExecutePass function + // Add a raster render pass to the render graph, specifying the name and the data type that will be passed to the ExecutePass function. using (var builder = renderGraph.AddUnsafePass(passName, out var passData)) { - // UniversalResourceData contains all the texture handles used by the renderer, including the active color and depth textures - // The active color and depth textures are the main color and depth buffers that the camera renders into + // UniversalResourceData contains all the texture handles used by the renderer, including the active color and depth textures. + // The active color and depth textures are the main color and depth buffers that the camera renders into. UniversalResourceData resourceData = frameData.Get(); - // Fill up the passData with the data needed by the pass + // Fill up the passData with the data needed by the pass. - // Get the active color texture through the frame data, and set it as the source texture for the blit + // Get the active color texture through the frame data, and set it as the source texture for the blit. passData.source = resourceData.activeColorTexture; // The destination textures are created here, // the texture is created with the same dimensions as the active color texture, but with no depth buffer, being a copy of the color texture - // we also disable MSAA as we don't need multisampled textures for this sample - // the other two textures halve the resolution of the previous one + // we also disable MSAA as we don't need multisampled textures for this sample. + // The other two textures halve the resolution of the previous one. var descriptor = passData.source.GetDescriptor(renderGraph); // We disable MSAA for the blit operations. - descriptor.msaaSamples = MSAASamples.None; + descriptor.msaaSamples = MSAASamples.None; descriptor.clearBuffer = false; @@ -105,17 +105,17 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer // We declare the src texture as an input dependency to this pass, via UseTexture() builder.UseTexture(passData.source); - // UnsafePasses don't setup the outputs using UseTextureFragment/UseTextureFragmentDepth, you should specify your writes with UseTexture instead + // UnsafePasses don't setup the outputs using UseTextureFragment/UseTextureFragmentDepth, you should specify your writes with UseTexture instead. builder.UseTexture(passData.destination, AccessFlags.WriteAll); builder.UseTexture(passData.destinationHalf, AccessFlags.WriteAll); builder.UseTexture(passData.destinationQuarter, AccessFlags.WriteAll); // We disable culling for this pass for the demonstrative purpose of this sample, as normally this pass would be culled, - // since the destination texture is not used anywhere else + // since the destination texture is not used anywhere else. builder.AllowPassCulling(false); - // Assign the ExecutePass function to the render pass delegate, which will be called by the render graph when executing the pass - builder.SetRenderFunc((PassData data, UnsafeGraphContext context) => ExecutePass(data, context)); + // Assign the ExecutePass function to the render pass delegate, which will be called by the render graph when executing the pass. + builder.SetRenderFunc(static (PassData data, UnsafeGraphContext context) => ExecutePass(data, context)); } } } diff --git a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/SSAO.hlsl b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/SSAO.hlsl index efa4bd13a51..e355b6f6256 100644 --- a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/SSAO.hlsl +++ b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/SSAO.hlsl @@ -278,15 +278,13 @@ half3 ReconstructNormal(float2 uv, float linearDepth, float3 vpos, float2 pixelD #if defined(_SOURCE_DEPTH_LOW) return half3(normalize(cross(ddy(vpos), ddx(vpos)))); #else - float2 delta = float2(_SourceSize.zw * 2.0); - - pixelDensity = rcp(pixelDensity); + float2 delta = float2(_SourceSize.zw * 2.0) * rcp(pixelDensity); // Sample the neighbour fragments - float2 lUV = float2(-delta.x, 0.0) * pixelDensity; - float2 rUV = float2(delta.x, 0.0) * pixelDensity; - float2 uUV = float2(0.0, delta.y) * pixelDensity; - float2 dUV = float2(0.0, -delta.y) * pixelDensity; + float2 lUV = float2(-delta.x, 0.0); + float2 rUV = float2(delta.x, 0.0); + float2 uUV = float2(0.0, delta.y); + float2 dUV = float2(0.0, -delta.y); float3 l1 = float3(uv + lUV, 0.0); l1.z = SampleAndGetLinearEyeDepth(l1.xy); // Left1 float3 r1 = float3(uv + rUV, 0.0); r1.z = SampleAndGetLinearEyeDepth(r1.xy); // Right1 @@ -316,17 +314,17 @@ half3 ReconstructNormal(float2 uv, float linearDepth, float3 vpos, float2 pixelD // h == 1.0 && v == 1.0: p1 = right, p2 = up // h == 0.0 && v == 1.0: p1 = up, p2 = left // Calculate the view space positions for the three points... - half3 P1; - half3 P2; + float3 P1; + float3 P2; if (closest_vertical == 0) { - P1 = half3(closest_horizontal == 0 ? l1 : d1); - P2 = half3(closest_horizontal == 0 ? d1 : r1); + P1 = closest_horizontal == 0 ? l1 : d1; + P2 = closest_horizontal == 0 ? d1 : r1; } else { - P1 = half3(closest_horizontal == 0 ? u1 : r1); - P2 = half3(closest_horizontal == 0 ? l1 : u1); + P1 = closest_horizontal == 0 ? u1 : r1; + P2 = closest_horizontal == 0 ? l1 : u1; } // Use the cross product to calculate the normal... diff --git a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/VisualEffectVertex.hlsl b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/VisualEffectVertex.hlsl index c76235e6d07..436fe1daac4 100644 --- a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/VisualEffectVertex.hlsl +++ b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/VisualEffectVertex.hlsl @@ -7,7 +7,7 @@ void VertVFX( Attributes input #endif -#if (SHADERPASS == SHADERPASS_MOTION_VECTORS) +#if (SHADERPASS == SHADERPASS_MOTION_VECTORS || SHADERPASS == SHADERPASS_XR_MOTION_VECTORS) , out PackedMotionVectorPassVaryings packedMvOutput #endif , out PackedVaryings packedOutput @@ -20,7 +20,7 @@ void VertVFX( input.instanceID = instanceID; #endif -#if (SHADERPASS != SHADERPASS_MOTION_VECTORS) +#if (SHADERPASS != SHADERPASS_MOTION_VECTORS || SHADERPASS == SHADERPASS_XR_MOTION_VECTORS) packedOutput = vert(input); #else MotionVectorPassAttributes dummy = (MotionVectorPassAttributes)0; diff --git a/Packages/com.unity.render-pipelines.universal/Tests/Editor/EditorTests.cs b/Packages/com.unity.render-pipelines.universal/Tests/Editor/EditorTests.cs index 868229c7499..40fcc5c3d7e 100644 --- a/Packages/com.unity.render-pipelines.universal/Tests/Editor/EditorTests.cs +++ b/Packages/com.unity.render-pipelines.universal/Tests/Editor/EditorTests.cs @@ -2,13 +2,10 @@ using UnityEditor; using UnityEngine; using UnityEngine.Rendering; -using UnityEngine.Profiling; using UnityEngine.Rendering.Universal; using UnityEditor.Rendering.Universal.Internal; using UnityEngine.Experimental.Rendering; -using UnityEngine.Experimental.Rendering.Universal; -using UnityEngine.TestTools; -using System.Xml.Linq; +using UnityEngine.Rendering.RenderGraphModule; class EditorTests { @@ -184,6 +181,78 @@ public void UseReAllocateIfNeededWithoutTextureLeak() Assert.That(posttestTextures, Is.EquivalentTo(pretestTextures), "A texture leak is detected when using RenderingUtils.ReAllocateIfNeeded."); } + [Test] + public void UseReAllocateIfNeededWithoutTextureLeakTextureDesc() + { + Object[] pretestTextures = Resources.FindObjectsOfTypeAll(typeof(Texture)); + RTHandle myHandle = default(RTHandle); + + // URP is not initlized in test framework, init RTHandlePool here which is required for this test. + if (UniversalRenderPipeline.s_RTHandlePool == null) + { + UniversalRenderPipeline.s_RTHandlePool = new RTHandleResourcePool(); + } + + // Realloc RTHandle 100 times with different resolution. + for (int i = 0; i < 100; i++) + { + var desc = new TextureDesc(1, 1 + i); + desc.format = GraphicsFormat.R8G8B8A8_UNorm; + desc.filterMode = FilterMode.Point; + desc.wrapMode = TextureWrapMode.Clamp; + RenderingUtils.ReAllocateHandleIfNeeded(ref myHandle, desc, "TestTexture"); + } + UniversalRenderPipeline.s_RTHandlePool.Cleanup(); + RTHandles.Release(myHandle); + + Object[] posttestTextures = Resources.FindObjectsOfTypeAll(typeof(Texture)); + + Assert.That(posttestTextures, Is.EquivalentTo(pretestTextures), "A texture leak is detected when using RenderingUtils.ReAllocateIfNeeded."); + } + + [Test] + public void UseReAllocateIfNeededCorrect() + { + Object[] pretestTextures = Resources.FindObjectsOfTypeAll(typeof(Texture)); + RTHandle myHandle = default(RTHandle); + + // URP is not initlized in test framework, init RTHandlePool here which is required for this test. + if (UniversalRenderPipeline.s_RTHandlePool == null) + { + UniversalRenderPipeline.s_RTHandlePool = new RTHandleResourcePool(); + } + + var desc = new TextureDesc(128, 128); + desc.format = GraphicsFormat.R8G8B8A8_UNorm; + desc.filterMode = FilterMode.Point; + desc.wrapMode = TextureWrapMode.Clamp; + + RenderingUtils.ReAllocateHandleIfNeeded(ref myHandle, desc, "TestTexture"); + + Assert.That(IsEqualDesc(in desc, myHandle), "RenderingUtils.ReAllocateIfNeeded alloced RTHandle with different properties than requested."); + + desc.width = desc.height = 64; + desc.format = GraphicsFormat.R32_SFloat; + desc.filterMode = FilterMode.Bilinear; + desc.wrapMode = TextureWrapMode.Repeat; + + RenderingUtils.ReAllocateHandleIfNeeded(ref myHandle, desc, "TestTexture"); + + Assert.That(IsEqualDesc(in desc, myHandle), "RenderingUtils.ReAllocateIfNeeded alloced RTHandle with different properties than requested."); + + UniversalRenderPipeline.s_RTHandlePool.Cleanup(); + RTHandles.Release(myHandle); + } + + bool IsEqualDesc(in TextureDesc desc, RTHandle rt) + { + return rt.rt.width == desc.width + && rt.rt.height == desc.height + && rt.rt.graphicsFormat == desc.format + && rt.rt.wrapMode == desc.wrapMode + && rt.rt.filterMode == desc.filterMode; + } + [TestCase(ShaderPathID.Lit)] [TestCase(ShaderPathID.SimpleLit)] [TestCase(ShaderPathID.Unlit)] diff --git a/Packages/com.unity.shadergraph/Documentation~/Getting-Started.md b/Packages/com.unity.shadergraph/Documentation~/Getting-Started.md index 96b65f6dce8..4ba39a34efe 100644 --- a/Packages/com.unity.shadergraph/Documentation~/Getting-Started.md +++ b/Packages/com.unity.shadergraph/Documentation~/Getting-Started.md @@ -1,21 +1,9 @@ -# Getting started with Shader Graph +# Get started with Shader Graph -Use Shader Graph with either of the Scriptable Render Pipelines (SRPs) available in Unity version 2018.1 and later: +Explore the Shader Graph user interface and general workflows to start creating your own shader graphs. -- The [High Definition Render Pipeline (HDRP)](https://docs.unity3d.com/Packages/com.unity.render-pipelines.high-definition@latest) -- The [Universal Render Pipeline (URP)](https://docs.unity3d.com/Manual/urp/urp-introduction.html) - -As of Unity version 2021.2, you can also use Shader Graph with the [Built-In Render Pipeline](https://docs.unity3d.com/Documentation/Manual/built-in-render-pipeline.html). - -> [!NOTE] -> Shader Graph support for the Built-In Render Pipeline is for compatibility purposes only. Shader Graph doesn't receive updates for Built-In Render Pipeline support, aside from bug fixes for existing features. It's recommended to use Shader Graph with the Scriptable Render Pipelines. - -## Installation - -When you install HDRP or URP into your project, Unity also installs the Shader Graph package automatically. You can manually install Shader Graph for use with the Built-In Render Pipeline on Unity version 2021.2 and later with the Package Manager. For more information on how to install a package, see [Adding and removing packages](https://docs.unity3d.com/Manual/upm-ui-actions.html) in the Unity User Manual. - -For more information about how to set up a Scriptable Render Pipeline, see [Getting started with HDRP](https://docs.unity3d.com/Packages/com.unity.render-pipelines.high-definition@17.0/manual/getting-started-in-hdrp.html) or [Getting started with URP](https://docs.unity3d.com/Manual/urp/InstallingAndConfiguringURP). - -## What's new - -For information about the latest updates and improvements to Shader Graph, refer to [What's new in Unity](https://docs.unity3d.com/Manual/WhatsNew.html). +| Topic | Description | +| :--- | :--- | +| **[Creating a new shader graph asset](Create-Shader-Graph.md)** | Create a shader graph asset and get an overview of the main Shader Graph interface elements available to create and configure a shader graph. | +| **[My first Shader Graph](First-Shader-Graph.md)** | Create and configure a shader graph, and create and manipulate a material that uses that shader graph. | +| **[Create a new shader graph from a template](create-shader-graph-template.md)** | Use the Shader Graph template browser to create a shader graph. | diff --git a/Packages/com.unity.shadergraph/Documentation~/Input-Nodes.md b/Packages/com.unity.shadergraph/Documentation~/Input-Nodes.md index 5983f8dc84c..65296db3cee 100644 --- a/Packages/com.unity.shadergraph/Documentation~/Input-Nodes.md +++ b/Packages/com.unity.shadergraph/Documentation~/Input-Nodes.md @@ -100,3 +100,10 @@ Supply shaders with essential data such as constants, mesh attributes, gradients | [Texture 2D Array Asset](Texture-2D-Array-Asset-Node.md) | Defines a constant Texture 2D Array Asset for use in the shader. | | [Texture 2D Asset](Texture-2D-Asset-Node.md) | Defines a constant Texture 2D Asset for use in the shader. | | [Texture 3D Asset](Texture-3D-Asset-Node.md) | Defines a constant Texture 3D Asset for use in the shader. | + +## UI +| **Topic** | **Description** | +|-------------|------------------| +| [Element Texture UV](element-texture-uv-node.md) | Provides the texture coordinates (UV) typically used to sample the texture assigned to a UI element. | +| [Element Layout UV](element-layout-uv-node.md) | Provides the layout UV coordinates within a UI element's layout rectangle. | +| [Element Texture Size](element-texture-size-node.md) | Provides the size of the texture assigned to a UI element. | \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/Keywords-reference.md b/Packages/com.unity.shadergraph/Documentation~/Keywords-reference.md index 98dc40b4c9c..c7577407f91 100644 --- a/Packages/com.unity.shadergraph/Documentation~/Keywords-reference.md +++ b/Packages/com.unity.shadergraph/Documentation~/Keywords-reference.md @@ -9,7 +9,7 @@ Parameters that all keyword types have in common. | **Name** | **Description** | | :--- | :--- | | **Name** | The display name of the keyword. Unity shows this name in the title bar of nodes that reference the corresponding keyword, and also in the Material Inspector if you expose that keyword. | -| **Reference** | The internal name for the keyword in the shader.

If you overwrite this parameter, be aware of the following:
  • A Keyword **Reference** has to be in full capitals. Unity converts any lowercase letters to uppercase.
  • If **Reference** contains any characters that HLSL does not support, Unity replaces those characters with underscores.
  • You can revert to the default **Reference**: right-click on the **Reference** field label, and select **Reset Reference**.
| +| **Reference** | The internal name for the keyword in the shader. Use this **Reference** name instead of the display **Name** when you reference the keyword in a script.

If you overwrite this parameter, be aware of the following:
  • A Keyword **Reference** has to be in full capitals. Unity converts any lowercase letters to uppercase.
  • If the string contains any characters that HLSL does not support, Unity replaces those characters with underscores.
  • You can revert to the default value: right-click on the **Reference** field label, and select **Reset Reference**.
| | **Definition** | Sets the keyword declaration type, which determines how Unity compiles the shader code. This allows you to [optimize the balance between build time, runtime, and file sizes](Keywords-concepts.md#keyword-impact-optimization).

The options are:
  • **Shader Feature**: Unity only compiles shader variants for keyword combinations used by materials in your build, and removes other shader variants.
  • **Multi Compile**: Unity compiles shader variants for all keyword combinations regardless of whether the build uses these variants.
  • **Predefined**: Specifies that the target/sub-target already defines the keyword and you just want to reuse it. Predefined Keywords can either use a [built-in macro](https://docs.unity3d.com/Manual/shader-branching-built-in-macros.html), which results in static branching at build time, or any of the keywords already defined by the Shader Graph Target (for example, [URP](https://docs.unity3d.com/Manual/urp/urp-shaders/shader-keywords-macros.html)), including [Built-In keyword sets](https://docs.unity3d.com/Manual/SL-MultipleProgramVariants-shortcuts.html), and where the branching depends on that definition.
  • **Dynamic Branch**: Unity keeps branching code in one compiled shader program.
| | **Is Overridable** | Indicates whether the keyword's state can be overridden.
For more information, refer to [Toggle shader keywords in a script](https://docs.unity3d.com/Manual/shader-keywords-scripts.html). | | **Generate Material Property** | Generates a material property declaration to display the keyword as a property in the material inspector.
This adds a `[Toggle(_KEYWORD)]` attribute to the material property. For more information, refer to [`MaterialPropertyDrawer`](https://docs.unity3d.com/ScriptReference/MaterialPropertyDrawer.html). | diff --git a/Packages/com.unity.shadergraph/Documentation~/Node-Library.md b/Packages/com.unity.shadergraph/Documentation~/Node-Library.md index 9d773bda455..762a150fae7 100644 --- a/Packages/com.unity.shadergraph/Documentation~/Node-Library.md +++ b/Packages/com.unity.shadergraph/Documentation~/Node-Library.md @@ -12,6 +12,7 @@ Explore nodes that enable color and channel manipulation, mathematical and proce | [Input](Input-Nodes.md) | Learn about values, mesh attributes, gradients, matrices, deformation data, PBR parameters, scene information, and texture sampling options. | | [Math](Math-Nodes.md) | Learn about mathematical operations. | | [Procedural](Procedural-Nodes.md) | Learn about creating patterns, noise textures, and geometric shapes. | +| [UI](UI-Nodes.md) | Learn about nodes specifically designed for UI elements, including render type handling, element texture sampling, and layout-based UVs. | | [Utility](Utility-Nodes.md) | Learn about basic preview, sub-graph referencing, and essential logic operations. | | [UV](UV-Nodes.md) | Learn about manipulation and mapping effects, enabling advanced texture animations, coordinate transformations, and warping techniques. | diff --git a/Packages/com.unity.shadergraph/Documentation~/Property-Types.md b/Packages/com.unity.shadergraph/Documentation~/Property-Types.md index 94e50de03fb..9b83dfdf03a 100644 --- a/Packages/com.unity.shadergraph/Documentation~/Property-Types.md +++ b/Packages/com.unity.shadergraph/Documentation~/Property-Types.md @@ -13,7 +13,9 @@ All properties have the following common parameters in addition to those specifi | Parameter | Description | | :--- | :--- | | **Name** | The display name of the property. | -| **Reference** | The internal name for the property in the shader.

If you overwrite this parameter, be aware of the following:
  • If **Reference** doesn't begin with an underscore, Unity automatically adds one.
  • If **Reference** contains any characters which are unsupported in HLSL, Unity removes them.
  • You can revert to the default **Reference**: right-click on the **Reference** field label, and select **Reset Reference**.
| +| **Reference** | The internal name for the property in the shader. Use this **Reference** name instead of the display **Name** when you reference the property in a script.

If you overwrite this parameter, be aware of the following:
  • If the string doesn't begin with an underscore, Unity automatically adds one.
  • If the string contains any characters that HLSL does not support, Unity removes them.
  • You can revert to the default value: right-click on the **Reference** field label, and select **Reset Reference**.
| +| **Precision** | Sets the data precision mode of the Property. The options are **Inherit**, **Single**, **Half**, and **Use Graph Precision**.
For more details, refer to [Precision Modes](Precision-Modes.md). | +| **Scope** | Specifies where you expect to edit the property for materials. The options are:
  • **Global**: Makes the property editable at a global level, through a C# script only, for all materials that use it. Selecting this option hides or grays out all parameters that relate to the Inspector UI display.
  • **Per Material**: Makes the property independently editable per material, either through a C# script, or in the Inspector UI if you enable **Show In Inspector**.
  • **Hybrid Per Instance**: Has the same effect as **Per Material**, unless you're using [DOTS instancing](https://docs.unity3d.com/Packages/com.unity.entities.graphics@latest/index.html?subfolder=/manual/dots-instancing-shader.html).
| | **Show In Inspector** | Displays the property in the material inspector.
If you disable this option, it includes an `[HideInInspector]` attribute to the material property (refer to [Properties block reference in ShaderLab](https://docs.unity3d.com/Manual/SL-Properties.html#material-property-attributes) for more details). | | **Read Only** | Adds a [`PerRendererData`](https://docs.unity3d.com/ScriptReference/Rendering.ShaderPropertyFlags.html) attribute to the material property to display the value as read-only in the material inspector. | | **Custom Attributes** | A list of entries that allow you to call custom functions you scripted to create additional [material property drawers](https://docs.unity3d.com/ScriptReference/MaterialPropertyDrawer.html), like static decorators or complex controls.
The **Custom Material Property Drawers** sample, available in the Package Manager among other [Shader Graph samples](ShaderGraph-Samples.md), shows how to display a Vector2 as a min/max slider, for example.

**Note**: When you declare the custom functions in the script, make sure to suffix their names with `Drawer` or `Decorator`.

In the list, use **+** or **-** to add or remove entries. Each entry corresponds to a function call which requires the following parameters:
  • **Name**: A shorthened version of the function name, without its `Drawer` or `Decorator` suffix.
  • **Value**: The input values for the function as the script expects them.
**Note**: A property can only have one drawer at any given time. | @@ -185,3 +187,27 @@ Defines a **Boolean** value. Displays a **ToggleUI** field in the material inspe | Field | Type | Description | |:-------------|:------|:------------| | Default | Boolean | The default value of the [Property](https://docs.unity3d.com/Manual/SL-Properties.html). | + +## Matrix 2x2 + +Defines a Matrix 2. Matrices do not display in the **Inspector** window of the material. + +| Field | Type | +|:--------|:---------| +| Default | Matrix 2 | + +## Matrix 3x3 + +Defines a Matrix 3 value. Can't be displayed in the material inspector. + +| Field | Type | +|:--------|:---------| +| Default | Matrix 3 | + +## Matrix 4x4 + +Defines a Matrix 4 value. Can't be displayed in the material inspector. + +| Field | Type | +|:--------|:---------| +| Default | Matrix 4 | diff --git a/Packages/com.unity.shadergraph/Documentation~/TableOfContents.md b/Packages/com.unity.shadergraph/Documentation~/TableOfContents.md index caf762d022f..59e48029acc 100644 --- a/Packages/com.unity.shadergraph/Documentation~/TableOfContents.md +++ b/Packages/com.unity.shadergraph/Documentation~/TableOfContents.md @@ -1,8 +1,14 @@ * [About Shader Graph](index.md) -* [Getting started with Shader Graph](Getting-Started.md) +* [What's new in Shader Graph](whats-new.md) +* [Install and upgrade](install-and-upgrade.md) + * [Install Shader Graph](install-shader-graph.md) + * [Upgrade to Shader Graph 10.0.x](Upgrade-Guide-10-0-x.md) +* [Get started with Shader Graph](Getting-Started.md) * [Creating a new Shader Graph Asset](Create-Shader-Graph.md) * [My first Shader Graph](First-Shader-Graph.md) * [Create a new shader graph from a template](create-shader-graph-template.md) +* [Shader Graph UI reference](ui-reference.md) + * [Shader Graph template browser](template-browser.md) * [Shader Graph Window](Shader-Graph-Window.md) * [Blackboard](Blackboard.md) * [Main Preview](Main-Preview.md) @@ -10,30 +16,27 @@ * [Create Node Menu](Create-Node-Menu.md) * [Graph Settings Tab](Graph-Settings-Tab.md) * [Master Stack](Master-Stack.md) - * [Sticky Notes](Sticky-Notes.md) - * [Sub Graph](Sub-graph.md) - * [Color Modes](Color-Modes.md) - * [Precision Modes](Precision-Modes.md) - * [Preview Mode Control](Preview-Mode-Control.md) - * [Custom Function Node](Custom-Function-Node.md) - * [Custom Render Textures](Custom-Render-Texture.md) - * [Accessing](Custom-Render-Texture-Accessing.md) - * [Example](Custom-Render-Texture-Example.md) * [Shader Graph Preferences](Shader-Graph-Preferences.md) * [Shader Graph Project Settings](Shader-Graph-Project-Settings.md) * [Shader Graph Keyboard Shortcuts](Keyboard-shortcuts.md) - * [Material Variants](materialvariant-SG.md) -* Upgrade Guides - * [Upgrade to Shader Graph 10.0.x](Upgrade-Guide-10-0-x.md) -* Inside Shader Graph +* [Inside Shader Graph](inside-shader-graph.md) * [Shader Graph Asset](Shader-Graph-Asset.md) * [Graph Target](Graph-Target.md) - * [Sub Graph Asset](Sub-graph-Asset.md) - * [SpeedTree 8 Sub Graph Assets](SpeedTree8-SubGraphAssets.md) * [Node](Node.md) * [Port](Port.md) * [Custom Port Menu](Custom-Port-Menu.md) * [Edge](Edge.md) + * [Sub Graph](Sub-graph.md) + * [Sub Graph Asset](Sub-graph-Asset.md) + * [SpeedTree 8 Sub Graph Assets](SpeedTree8-SubGraphAssets.md) + * [Sticky Notes](Sticky-Notes.md) + * [Color Modes](Color-Modes.md) + * [Precision Modes](Precision-Modes.md) + * [Preview Mode Control](Preview-Mode-Control.md) + * [Custom Render Textures](Custom-Render-Texture.md) + * [Accessing](Custom-Render-Texture-Accessing.md) + * [Example](Custom-Render-Texture-Example.md) + * [Material Variants](materialvariant-SG.md) * [Property Types](Property-Types.md) * [Keywords](Keywords.md) * [Introduction to keywords](Keywords-concepts.md) @@ -162,6 +165,10 @@ * [Texture 2D Asset](Texture-2D-Asset-Node.md) * [Texture 3D Asset](Texture-3D-Asset-Node.md) * [Texture Size](Texture-Size-Node.md) + * UI + * [Element Layout UV](element-layout-uv-node.md) + * [Element Texture Size](element-texture-size-node.md) + * [Element Texture UV](element-texture-uv-node.md) * [Math](Math-Nodes.md) * Advanced * [Absolute](Absolute-Node.md) @@ -252,6 +259,15 @@ * [Rounded Polygon](Rounded-Polygon-Node.md) * [Rounded Rectangle](Rounded-Rectangle-Node.md) * [Checkerboard](Checkerboard-Node.md) + * [UI](ui-nodes.md) + * [Default Bitmap Text](default-bitmap-text-node.md) + * [Default Gradient](default-gradient-node.md) + * [Default SDF Text](default-sdf-text-node.md) + * [Default Solid](default-solid-node.md) + * [Default Texture](default-texture-node.md) + * [Render Type](render-type-node.md) + * [Render Type Branch](render-type-branch-node.md) + * [Sample Element Texture](sample-element-texture-node.md) * [Utility](Utility-Nodes.md) * Logic * [All](All-Node.md) diff --git a/Packages/com.unity.shadergraph/Documentation~/Transform-Node.md b/Packages/com.unity.shadergraph/Documentation~/Transform-Node.md index c3ec4cbdbfa..f83183eb4f2 100644 --- a/Packages/com.unity.shadergraph/Documentation~/Transform-Node.md +++ b/Packages/com.unity.shadergraph/Documentation~/Transform-Node.md @@ -83,7 +83,7 @@ float3 _Transform_Out = GetAbsolutePositionWS(In); **World > Screen** ``` -float4 hclipPosition = TransformWorldToHClipDir(In); +float4 hclipPosition = TransformWorldToHClip(In); float3 screenPos = hclipPosition.xyz / hclipPosition.w; float3 _Transform_Out = float3(screenPos.xy * 0.5 + 0.5, screenPos.z); ``` diff --git a/Packages/com.unity.shadergraph/Documentation~/Upgrade-Guide-10-0-x.md b/Packages/com.unity.shadergraph/Documentation~/Upgrade-Guide-10-0-x.md index 6a8dd75313a..279ad68de72 100644 --- a/Packages/com.unity.shadergraph/Documentation~/Upgrade-Guide-10-0-x.md +++ b/Packages/com.unity.shadergraph/Documentation~/Upgrade-Guide-10-0-x.md @@ -1,5 +1,7 @@ # Upgrade to version 10.0.x of Shader Graph +Upgrade your project to make it compatible with Shader Graph 10.0 or later. + ## Renamed Vector 1 property and Float precision Shader Graph has renamed the **Vector 1** property as **Float** in both the Vector 1 node and the exposed parameter list. The **Float** precision was also renamed as **Single**. Behavior is exactly the same, and only the names have changed. diff --git a/Packages/com.unity.shadergraph/Documentation~/create-shader-graph-template.md b/Packages/com.unity.shadergraph/Documentation~/create-shader-graph-template.md index cbaae299484..5e791693749 100644 --- a/Packages/com.unity.shadergraph/Documentation~/create-shader-graph-template.md +++ b/Packages/com.unity.shadergraph/Documentation~/create-shader-graph-template.md @@ -1,35 +1,20 @@ # Create a new shader graph from a template -To create a shader graph from a template, use the Template Browser window. You can then adapt the shader graph to your needs. +To create a new shader graph from a template, follow these steps: -You can also share custom templates with your team through the Template Browser window, to maintain consistency across shaders in a project. This feature is particularly useful for projects with unique lighting setups or specific shader requirements. +1. In the **Project** window, right-click and select **Create** > **Shader Graph** > **From Template**. -The Template Browser window displays only templates that are compatible with the current project. + The [template browser](template-browser.md) opens. -# Create a new shader graph using a template +1. Select the desired template and click **Create**. -To create a new shader graph using a template: + Unity creates a new shader graph asset in your project. -1. In the **Project** window, right-click and select **Create** > **Shader Graph** > **From Template...**. +1. Name the shader graph asset. - The Template Browser window opens. +You can now edit the graph in the [Shader Graph window](Shader-Graph-Window.md). -1. Select the desired template. +## Additional resources - Unity creates a new shader graph asset. - -1. Name the shader graph asset and edit it. - -## Create a custom shader graph template - -To create a custom shader graph template: - -1. Select a shader graph asset in your project. - -1. In the **Inspector** window, enable **Use As Template**. - -1. Expand the **Template** foldout (triangle). - -1. Set the metadata that describes the template in the Template Browser window. - -1. Click anywhere in the **Project** window to preview and save the template metadata. +* [Shader Graph template browser](template-browser.md) +* [Create a custom shader graph template](template-browser.md#create-a-custom-shader-graph-template) diff --git a/Packages/com.unity.shadergraph/Documentation~/default-bitmap-text-node.md b/Packages/com.unity.shadergraph/Documentation~/default-bitmap-text-node.md new file mode 100644 index 00000000000..53ceaec084b --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/default-bitmap-text-node.md @@ -0,0 +1,24 @@ +--- +uid: default-bitmap-text-node +--- + +# Default Bitmap Text node + +[!include[](include_note_uitk.md)] + +Outputs the text color set for bitmap text rendering and includes a tint input you can use to modify the color of the text. For example, if you connect a **Color** node to the tint input and set it to red, and connect the output to bitmap text render type, the text color of your bitmap text becomes red. + +## Ports + +| Name | Direction | Type | Description | +|:----------- |:--------------------|:------|:------------| +| Tint | Input | Color | The color tint to apply to the text. | +| Bitmap text| Output | Texture| The rendered bitmap of the text. | + +## Additional resources + +- [Default Solid node](xref:default-solid-node) +- [Default Gradient node](xref:default-gradient-node) +- [Default Texture node](xref:default-texture-node) +- [Default SDF Text node](xref:default-sdf-text-node) +- [Render Type Branch node](xref:render-type-branch-node) \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/default-gradient-node.md b/Packages/com.unity.shadergraph/Documentation~/default-gradient-node.md new file mode 100644 index 00000000000..259bff845ee --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/default-gradient-node.md @@ -0,0 +1,26 @@ +--- +uid: default-gradient-node +--- + +# Default Gradient node + +[!include[](include_note_uitk.md)] + +Outputs the gradient specified for your UI elements. For example, if you set the background image of a button to use a vector graphic with a linear gradient from top red to bottom green, the Default Gradient node outputs that gradient for the button. + +You can use the Default Gradient node combined with other nodes to create custom effects for the gradient render type. For example, you can multiply the output of this node with a **Color** node to filter unwanted colors from the gradient. + +## Ports + +| Name | Direction | Type | Description | +|----------|-----------|---------|--------------------------------------| +| Gradient | Output | Gradient| The gradient specified for the UI element. | + + +## Additional resources + +- [Default Solid node](xref:default-solid-node) +- [Default Texture node](xref:default-texture-node) +- [Default SDF Text node](xref:default-sdf-text-node) +- [Default Bitmap Text node](xref:default-bitmap-text-node) +- [Render Type Branch node](xref:render-type-branch-node) \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/default-sdf-text-node.md b/Packages/com.unity.shadergraph/Documentation~/default-sdf-text-node.md new file mode 100644 index 00000000000..efc9550749e --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/default-sdf-text-node.md @@ -0,0 +1,24 @@ +--- +uid: default-sdf-text-node +--- + +# Default SDF Text node + +[!include[](include_note_uitk.md)] + +Outputs the text color for SDF text rendering and includes a tint input you can use to modify the color of the text. For example, if you connect a **Color** node to the tint input and set it to red, and connect the output to SDF text render type, the text color of your SDF text becomes red. + +## Ports + +| Name | Direction | Type | Description | +|----------|-----------|---------|--------------------------------------| +| Tint | Input | Color | The tint color to apply to the text. | +| SDF Text | Output | Texture | The rendered SDF text as a texture. | + +## Additional resources + +- [Default Solid node](xref:default-solid-node) +- [Default Gradient node](xref:default-gradient-node) +- [Default Texture node](xref:default-texture-node) +- [Default Bitmap Text node](xref:default-bitmap-text-node) +- [Render Type Branch node](xref:render-type-branch-node) \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/default-solid-node.md b/Packages/com.unity.shadergraph/Documentation~/default-solid-node.md new file mode 100644 index 00000000000..0144c9d4e8c --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/default-solid-node.md @@ -0,0 +1,25 @@ +--- +uid: default-solid-node +--- + +# Default Solid node + +[!include[](include_note_uitk.md)] + +Outputs the solid color specified for your UI elements, such as the background color of a button. For example, if you set the background color of a button to yellow, the **Default Solid** node outputs yellow for that button. + +You can use this node combined with other nodes to create custom effects for the Solid color render type. For example, you can multiply the output of this node with a **Color** node to filter unwanted colors. + +## Ports + +| Name | Direction | Type | Description | +|----------|-----------|---------|-----------------------------------------------| +| Solid | Output | Color | The solid color specified for the UI element. | + +## Additional resources + +- [Default Gradient node](xref:default-gradient-node) +- [Default Texture node](xref:default-texture-node) +- [Default SDF Text node](xref:default-sdf-text-node) +- [Default Bitmap Text node](xref:default-bitmap-text-node) +- [Render Type Branch node](xref:render-type-branch-node) \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/default-texture-node.md b/Packages/com.unity.shadergraph/Documentation~/default-texture-node.md new file mode 100644 index 00000000000..d4aea64caea --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/default-texture-node.md @@ -0,0 +1,26 @@ +--- +uid: default-texture-node +--- + +# Default Texture node + +[!include[](include_note_uitk.md)] + +Provides the texture assigned to the UI element. + +You can use this node to access the texture assigned to a UI element, such as a Texture 2D background image. The node includes UV and tint inputs that allow you to modify how the texture is applied. For example, you can connect a **Tiling and Offset** node to the UV input to create a repeating effect for the background image, or connect a **Color** node to the tint input to adjust the tint color of the background image. + +## Ports + +| Name | Direction | Type | Description | +|----------|-----------|---------|--------------------------------------| +| UV | Input | Vector2 | The UV coordinates for the texture. | +| Tint | Input | Color | The tint color to apply to the texture. | +| Texture | Output | Texture | The resulting texture. | + +## Additional resources + +- [Default Solid node](xref:default-solid-node) +- [Default Gradient node](xref:default-gradient-node) +- [Default SDF Text node](xref:default-sdf-text-node) +- [Default Bitmap Text node](xref:default-bitmap-text-node) \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/element-layout-uv-node.md b/Packages/com.unity.shadergraph/Documentation~/element-layout-uv-node.md new file mode 100644 index 00000000000..e13d1d67bad --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/element-layout-uv-node.md @@ -0,0 +1,20 @@ +--- +uid: element-layout-uv-node +--- + +# Element Layout UV node + +[!include[](include_note_uitk.md)] + +Outputs the geometric coordinates (UV) relative to the UI element, such as a button. It allows you to determine your position within the element itself, regardless of the texture applied. It represents the relative coordinates within the layout rect of the visual element, where `(0,0)` is the bottom-left corner and `(1,1)` is the top-right corner. + +## Ports + +| Name | Direction | Type | Description | +|--------------------|-----------|---------|--------------------------------------| +| Layout UV | Output | Vector2 | The UV coordinates for the element. | + +## Additional resources + +- [Element Texture UV node](xref:element-texture-uv-node) +- [Element Texture Size node](xref:element-texture-size-node) \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/element-texture-size-node.md b/Packages/com.unity.shadergraph/Documentation~/element-texture-size-node.md new file mode 100644 index 00000000000..58623497a19 --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/element-texture-size-node.md @@ -0,0 +1,31 @@ +--- +uid: element-texture-size-node +--- + +# Element Texture Size node + +[!include[](include_note_uitk.md)] + +Outputs the texture size that's assigned to the UI element. The output is undefined if the render type is solid. + +This node is similar to the [**Texture Size**](Texture-Size-node.md) node, but it specifically retrieves the size of the texture assigned to the UI element. This is important because UI elements can have textures assigned through styles or images, and these textures might differ from the material's main texture. For example, a button might have a background image set through its style, which is different from the material's texture. + +Follow these guidelines to decide which node to use: + +- Use the **Texture Size** node if you want to apply a texture-based effect that's not element-specific (for example, a soft mask). In this case, set the texture explicitly on the material and use the Texture Size node to get its size. +- Use the **Element Texture Size** node if you need the size of the texture assigned to a specific VisualElement, such as a background image or an image element. This includes textures set via styles or textures used in custom meshes drawn with `MeshGenerationContext.DrawMesh(texture)`. + +## Ports + +| Name | Direction | Type | Description | +|--------------------|-----------|---------|--------------------------------------| +| Width | Output | Float | The width of the texture. | +| Height | Output | Float | The height of the texture. | +| Texel Width | Output | Float | The texel width of the texture. | +| Texel Height | Output | Float | The texel height of the texture. | + +## Additional resources + +- [Element Texture UV node](xref:element-texture-uv-node) +- [Element Layout UV node](xref:element-layout-uv-node) +- [Texture Size node](Texture-Size-node.md) \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/element-texture-uv-node.md b/Packages/com.unity.shadergraph/Documentation~/element-texture-uv-node.md new file mode 100644 index 00000000000..85776dea3b3 --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/element-texture-uv-node.md @@ -0,0 +1,26 @@ +--- +uid: element-texture-uv-node +--- + +# Element Texture UV node + +[!include[](include_note_uitk.md)] + +Outputs the texture coordinates (UV) of the texture mapped onto a UI element. + +This node might output different coordinates than the [**Element Layout UV**](xref:element-layout-uv-node) node, which provides coordinates within the element's bounding rectangle. The coordinates are more likely to be different if you tile, offset, or transform the texture. + +If the texture is part of an atlas, its UV coordinates only map to a specific region within the atlas. If you repeat UV coordinates or sample outside them, the data comes from other textures in the atlas. Use texture coordinates (UV) when you need precise control over how a texture appears on a UI element, and be mindful of atlas constraints. + +The texture UV can also originate from a custom mesh when you call [`MeshGenerationContext.DrawMesh`](xref:UnityEngine.UIElements.MeshGenerationContext.DrawMesh(Unity.Collections.NativeSlice`1,Unity.Collections.NativeSlice`1,UnityEngine.Texture)). In such cases, the UV values might vary depending on the mesh data. + +## Ports + +| Name | Direction | Type | Description | +|-----------------|-----------|---------|--------------------------------------| +| Texture UV | Output | Vector2 | The UV coordinates for the texture. | + +## Additional resources + +- [Element Layout UV node](xref:element-layout-uv-node) +- [Element Texture Size node](xref:element-texture-size-node) \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/images/template-browser.png b/Packages/com.unity.shadergraph/Documentation~/images/template-browser.png new file mode 100644 index 00000000000..7a736e64d7f Binary files /dev/null and b/Packages/com.unity.shadergraph/Documentation~/images/template-browser.png differ diff --git a/Packages/com.unity.shadergraph/Documentation~/include_note_uitk.md b/Packages/com.unity.shadergraph/Documentation~/include_note_uitk.md new file mode 100644 index 00000000000..29add04c898 --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/include_note_uitk.md @@ -0,0 +1,2 @@ +> [!NOTE] +> Use this node only in shaders with **Material** set to **UI** for UI Toolkit. Using it elsewhere can lead to unexpected behavior or errors. For information on how to create shaders for UI Toolkit, refer to [UI Shader Graph](xref:uie-ui-shader-graph). \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/inside-shader-graph.md b/Packages/com.unity.shadergraph/Documentation~/inside-shader-graph.md new file mode 100644 index 00000000000..a435b42bfe5 --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/inside-shader-graph.md @@ -0,0 +1,24 @@ +# Inside Shader Graph + +Learn about Shader Graph concepts and features. + +| Topic | Description | +| :--- | :--- | +| [Shader Graph Asset](Shader-Graph-Asset.md) | Learn about the asset type that contains any shader graph you create. | +| [Graph Target](Graph-Target.md) | Determine the end point compatibility of a shader you generate with Shader Graph. | +| [Node](Node.md) | Create nodes in your shader graph and learn about node interconnection details with ports and edges. | +| [Sub Graph](Sub-graph.md) | Create sub graphs that you can reference from inside other graphs. | +| [Sub Graph Asset](Sub-graph-Asset.md) | Learn about the asset type that contains any sub graph you create. | +| [Sticky Notes](Sticky-Notes.md) | Use sticky notes to write comments within your shader graphs. | +| [Color Modes](Color-Modes.md) | Select color modes to improve your graph readability according to certain criteria like node category, relative performance cost, data precision mode, or custom colors. | +| [Precision Modes](Precision-Modes.md) | Set precision modes for graphs, subgraphs, and nodes to help you optimize your content for different platforms. | +| [Preview Mode Control](Preview-Mode-Control.md) | Manually select your preferred preview mode for nodes that have a preview. | +| [Custom Render Textures](Custom-Render-Texture.md) | Create shaders that are compatible with Custom Render Texture Update and Initialization materials. | +| [Material Variants](materialvariant-SG.md) | Create variations based on a single material. | +| [Property Types](Property-Types.md) | Use properties in your shader graph to expose them as material properties and make them editable in the material that uses the shader. | +| [Keywords](Keywords.md) | Use keywords to create different variants for your shader graph. | +| [Data Types](Data-Types.md) | Learn about all data types available in Shader Graph. | +| [Port Bindings](Port-Bindings.md) | Learn about port bindings, which ensure that some ports always meet data type expectations. | +| [Shader Stage](Shader-Stage.md) | Learn about shader stages that apply to specific ports according to their context compatibility. | +| [Surface options](surface-options.md) | Modify a specific set of properties for certain render pipeline targets. | +| [Custom Interpolators](Custom-Interpolators.md) | Pass custom data from the vertex context to the fragment context. | diff --git a/Packages/com.unity.shadergraph/Documentation~/install-and-upgrade.md b/Packages/com.unity.shadergraph/Documentation~/install-and-upgrade.md new file mode 100644 index 00000000000..60a8eaf99fa --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/install-and-upgrade.md @@ -0,0 +1,8 @@ +# Install and upgrade + +Install and upgrade Shader Graph. + +| Topic | Description | +| :--- | :--- | +| **[Install Shader Graph](install-shader-graph.md)** | Learn about the Shader Graph installation requirements and follow the installation instructions. | +| **[Upgrade to version 10.0.x of Shader Graph](Upgrade-Guide-10-0-x.md)** | Upgrade your project to make it compatible with Shader Graph 10.0 or later. | diff --git a/Packages/com.unity.shadergraph/Documentation~/install-shader-graph.md b/Packages/com.unity.shadergraph/Documentation~/install-shader-graph.md new file mode 100644 index 00000000000..06427688a16 --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/install-shader-graph.md @@ -0,0 +1,23 @@ +# Install Shader Graph + +Learn about the Shader Graph installation requirements and follow the installation instructions. + +## Requirements + +Use Shader Graph with either of the Scriptable Render Pipelines (SRPs) available in Unity version 2018.1 and later: + +- The [High Definition Render Pipeline (HDRP)](https://docs.unity3d.com/Packages/com.unity.render-pipelines.high-definition@latest) +- The [Universal Render Pipeline (URP)](https://docs.unity3d.com/Manual/urp/urp-introduction.html) + +As of Unity version 2021.2, you can also use Shader Graph with the [Built-In Render Pipeline](https://docs.unity3d.com/Documentation/Manual/built-in-render-pipeline.html). + +> [!NOTE] +> Shader Graph support for the Built-In Render Pipeline is for compatibility purposes only. Shader Graph doesn't receive updates for Built-In Render Pipeline support, aside from bug fixes for existing features. It's recommended to use Shader Graph with the Scriptable Render Pipelines. + +## Installation + +When you install HDRP or URP into your project, Unity also installs the Shader Graph package automatically. You can manually install Shader Graph for use with the Built-In Render Pipeline on Unity version 2021.2 and later with the Package Manager. + +* For more information about how to install a package, see [Adding and removing packages](https://docs.unity3d.com/Manual/upm-ui-actions.html) in the Unity User Manual. + +* For more information about how to set up a Scriptable Render Pipeline, see [Getting started with HDRP](https://docs.unity3d.com/Packages/com.unity.render-pipelines.high-definition@17.0/manual/getting-started-in-hdrp.html) or [Getting started with URP](https://docs.unity3d.com/Manual/urp/InstallingAndConfiguringURP). diff --git a/Packages/com.unity.shadergraph/Documentation~/render-type-branch-node.md b/Packages/com.unity.shadergraph/Documentation~/render-type-branch-node.md new file mode 100644 index 00000000000..1d0f66862cd --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/render-type-branch-node.md @@ -0,0 +1,32 @@ +--- +uid: render-type-branch-node +--- + +# Render Type Branch node + +[!include[](include_note_uitk.md)] + +The Render Type Branch node routes inputs based on the current render type and outputs the appropriate results for the Fragment node. You can connect the inputs to various nodes to define how each render type is processed. + +UI Shader Graph provides default nodes, such as the [Default Solid node](xref:default-solid-node) or [Default Texture node](xref:default-texture-node), for each render type. You can use these nodes as starting points when customizing your shaders. For best performance, if you want an input to use its default value for a render type, leave it disconnected rather than connecting it to a default node. The Render Type Branch node automatically uses the default values for that input and handles branching more efficiently when you disconnect inputs. Only connect these default nodes if you want to customize the shader’s behavior. + +## Ports + +| Name | Direction | Type | Description | +|------------|-----------|---------|--------------------------------------| +| Solid | Input | Color | The color to use for backgrounds and borders. | +| Texture | Input | Texture | The texture to use for texture graphics. | +| SDF Text | Input | Texture | The texture to use for SDF text. | +| Bitmap Text| Input | Texture | The texture to use for bitmap text. | +| Gradient | Input | Texture | The texture to use for vector graphic gradients.| +| Color | Output | Color | The output color. | +| Alpha | Output | Float | The output alpha value. | + +## Additional resources + +- [Render Type node](xref:render-type-node) +- [Default Solid node](xref:default-solid-node) +- [Default Texture node](xref:default-texture-node) +- [Default SDF Text node](xref:default-sdf-text-node) +- [Default Bitmap Text node](xref:default-bitmap-text-node) +- [Default Gradient node](xref:default-gradient-node) diff --git a/Packages/com.unity.shadergraph/Documentation~/render-type-node.md b/Packages/com.unity.shadergraph/Documentation~/render-type-node.md new file mode 100644 index 00000000000..8cd7243b431 --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/render-type-node.md @@ -0,0 +1,23 @@ +--- +uid: render-type-node +--- + +# Render Type node + +[!include[](include_note_uitk.md)] + +The Render Type node outputs the current render type the shader is processing. You can use this node to create custom logic based on the render type. For example, you can use the output of the Render Type node to control logic that changes behavior depending on the render type. + +## Ports + +| Name | Direction | Type | Description | +|------------|-----------|---------|--------------------------------------| +| Solid | Output | Boolean | True when the shader is processing the Solid render type. | +| Texture | Output | Boolean | True when the shader is processing the Texture render type. | +| SDF Text | Output | Boolean | True when the shader is processing the SDF Text render type. | +| Bitmap Text| Output | Boolean | True when the shader is processing the Bitmap Text render type. | +| Gradient | Output | Boolean | True when the shader is processing the Gradient render type. | + +## Additional resources + +- [Render Type Branch node](xref:render-type-branch-node) \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/sample-element-texture-node.md b/Packages/com.unity.shadergraph/Documentation~/sample-element-texture-node.md new file mode 100644 index 00000000000..1b7077916de --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/sample-element-texture-node.md @@ -0,0 +1,28 @@ +--- +uid: sample-element-texture-node +--- + +# Sample Element Texture node + +[!include[](include_note_uitk.md)] + +The Sample Element Texture node samples a texture at specific UV coordinates. You can use this node to get multiple samples of the texture assigned to the element, for example to create complex visual effects or manipulate the texture. + +Sampling multiple times with this node is more efficient than using several separate nodes for individual samples. This is because each node introduces overhead by traversing internal branches to select the correct texture slot. By combining multiple samples into a single node, you reduce this overhead and improve performance. + +## Ports + +| Name | Direction | Type | Description | +|---------|-----------|---------|--------------------------------------| +| UV 0 | Input | Vector2 | The UV coordinates to sample. | +| UV 1 | Input | Vector2 | The second set of UV coordinates to sample. | +| UV 2 | Input | Vector2 | The third set of UV coordinates to sample. | +| UV 3 | Input | Vector2 | The fourth set of UV coordinates to sample. | +| Color 0 | Output | Color | The sampled color from UV 0. | +| Color 1 | Output | Color | The sampled color from UV 1. | +| Color 2 | Output | Color | The sampled color from UV 2. | +| Color 3 | Output | Color | The sampled color from UV 3. | + +## Additional resources + +- [Create and apply custom shaders](xref:uie-create-apply-custom-shaders) diff --git a/Packages/com.unity.shadergraph/Documentation~/template-browser.md b/Packages/com.unity.shadergraph/Documentation~/template-browser.md new file mode 100644 index 00000000000..db9769b3d2c --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/template-browser.md @@ -0,0 +1,36 @@ +# Shader Graph template browser + +The Shader Graph template browser allows you to create a new shader graph from an existing template. + +To access the Shader Graph template browser, right-click in your Project window and select **Create** > **Shader Graph** > **From Template**. + +![The template browser](images/template-browser.png) + +| Label | Name | Description | +| :--- | :--- | :--- | +| **A** | Template list | Lists all the available templates you can select and start from to create a new shader graph. | +| **B** | Template details | Displays a picture and description of the selected template. | +| **C** | Action buttons | Finish the asset creation flow. The options are:
  • **Create**: Creates a new shader graph asset based on the selected template.
  • **Cancel**: Closes the window and cancels the shader graph asset creation.
| + +**Note**: The template browser displays only templates that are compatible with the current project. + +### Create a custom shader graph template + +You can create your own shader graph templates to have them available in the template browser. You can share these templates with your team to maintain consistency across shaders, for example in projects with unique lighting setups or specific shader requirements. + +To create a custom shader graph template, follow these steps: + +1. In the **Project** window, select the shader graph asset you want to use as a template. + +1. In the **Inspector** window, select **Use As Template**. + +1. Expand the **Template** section. + +1. Optional: Set the metadata that describes the template in the template browser: **Name**, **Category**, **Description**, **Icon**, and **Thumbnail**. + +> [!NOTE] +> By default, when you convert an existing shader graph asset into a template, you can no longer assign it to any materials through the [Material Inspector](https://docs.unity3d.com/Manual/class-Material.html). However, it remains active for materials that were already using it. To make the shader graph asset available again for any materials, enable the **Expose As Shader** option in the shader graph asset Inspector. + +## Additional resources + +* [Create a new shader graph from a template](create-shader-graph-template.md) diff --git a/Packages/com.unity.shadergraph/Documentation~/ui-nodes.md b/Packages/com.unity.shadergraph/Documentation~/ui-nodes.md new file mode 100644 index 00000000000..148d671143d --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/ui-nodes.md @@ -0,0 +1,20 @@ +--- +uid: ui-nodes +--- + +# UI nodes + +| **Topic** | **Description** | +|-------------|------------------| +| [Default Solid](default-solid-node.md) | Outputs the solid color specified for your UI elements. | +| [Default Texture](default-texture-node.md) | Provides a pre-defined texture for your UI elements. | +| [Default SDF Text](default-sdf-text-node.md) | Provides the text color set for SDF text rendering and includes a tint input to modify the color of the text. | +| [Default Bitmap Text](default-bitmap-text-node.md) | Provides the text color set for bitmap text rendering and includes a tint input to modify the color of the text. | +| [Default Gradient](default-gradient-node.md) | Outputs the gradient specified for your UI elements. | +| [Render Type](render-type-node.md) | Outputs the current render type for conditional logic in the shader. | +| [Render Type Branch](render-type-branch-node.md) | Routes inputs based on the current render type and outputs the appropriate result. | +| [Sample Element Texture](sample-element-texture-node.md) | Samples a texture at specific UV coordinates. | + +## Additional resources + +- [Create and apply custom shaders](xref:uie-create-apply-custom-shaders) \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/ui-reference.md b/Packages/com.unity.shadergraph/Documentation~/ui-reference.md new file mode 100644 index 00000000000..4abf26114eb --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/ui-reference.md @@ -0,0 +1,18 @@ +# Shader Graph UI reference + +Explore the main user interface elements you need to know to create and configure your shader graphs. + +| Topic | Description | +| :--- | :--- | +| [Shader Graph template browser](template-browser.md) | Browse the list of available templates to create your shader graphs from. | +| [Shader Graph Window](Shader-Graph-Window.md) | Display and edit your shader graph assets in Unity, including the Blackboard, the Main Preview, and the Graph Inspector. | +| [Create Node Menu](Create-Node-Menu.md) | Create nodes in your graph and create block nodes in the Master Stack. | +| [Graph Settings Tab](Graph-Settings-Tab.md) | Change settings that affect your shader graph as a whole. | +| [Master Stack](Master-Stack.md) | Explore the end point of a shader graph, which defines the final surface appearance of a shader. | +| [Shader Graph Preferences](Shader-Graph-Preferences.md) | Define shader graph settings for your system. | +| [Shader Graph Project Settings](Shader-Graph-Project-Settings.md) | Define shader graph settings for your entire project. | +| [Shader Graph Keyboard Shortcuts](Keyboard-shortcuts.md) | Use keyboard shortcuts to work more efficiently when you're using Shader Graph. | + +## Additional resources + +* [Node Library](Node-Library.md) \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/whats-new.md b/Packages/com.unity.shadergraph/Documentation~/whats-new.md new file mode 100644 index 00000000000..916386ba408 --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/whats-new.md @@ -0,0 +1,3 @@ +# What's new in Shader Graph + +For information about the latest updates and improvements to Shader Graph, refer to [What's new in Unity](https://docs.unity3d.com/Manual/WhatsNew.html). diff --git a/Packages/com.unity.shadergraph/Editor/Drawing/Blackboard/SGBlackboard.cs b/Packages/com.unity.shadergraph/Editor/Drawing/Blackboard/SGBlackboard.cs index 94db972375f..8dfff8b1d17 100644 --- a/Packages/com.unity.shadergraph/Editor/Drawing/Blackboard/SGBlackboard.cs +++ b/Packages/com.unity.shadergraph/Editor/Drawing/Blackboard/SGBlackboard.cs @@ -189,6 +189,7 @@ public SGBlackboard(BlackboardViewModel viewModel, BlackboardController controll isWindowScrollable = true; isWindowResizable = true; focusable = true; + scrollView.contentContainer.receivesHierarchyGeometryChangedEvents = false; m_DragIndicator = new VisualElement(); m_DragIndicator.name = "categoryDragIndicator"; diff --git a/Packages/com.unity.shadergraph/Editor/Generation/Targets/UITK/UIStructs.cs b/Packages/com.unity.shadergraph/Editor/Generation/Targets/UITK/UIStructs.cs index ca903dc6355..5fa16d03137 100644 --- a/Packages/com.unity.shadergraph/Editor/Generation/Targets/UITK/UIStructs.cs +++ b/Packages/com.unity.shadergraph/Editor/Generation/Targets/UITK/UIStructs.cs @@ -10,6 +10,8 @@ internal static class UIStructs fields = new[] { StructFields.Varyings.positionCS, + StructFields.Varyings.positionWS, + StructFields.Varyings.screenPosition, StructFields.Varyings.texCoord0, StructFields.Varyings.texCoord1, StructFields.Varyings.texCoord2, @@ -68,6 +70,11 @@ internal static class UIStructs // optionals StructFields.VertexDescriptionInputs.VertexID, StructFields.VertexDescriptionInputs.InstanceID, + + StructFields.VertexDescriptionInputs.ObjectSpaceNormal, + StructFields.VertexDescriptionInputs.NDCPosition, + StructFields.VertexDescriptionInputs.PixelPosition, + } }; public static StructDescriptor UITKSurfaceDescriptionInputs = new StructDescriptor() @@ -94,6 +101,11 @@ internal static class UIStructs StructFields.SurfaceDescriptionInputs.uv6, StructFields.SurfaceDescriptionInputs.uv7, + StructFields.SurfaceDescriptionInputs.WorldSpacePosition, + StructFields.SurfaceDescriptionInputs.ScreenPosition, + StructFields.SurfaceDescriptionInputs.NDCPosition, + StructFields.SurfaceDescriptionInputs.PixelPosition, + StructFields.SurfaceDescriptionInputs.TimeParameters, } }; diff --git a/Packages/com.unity.shadergraph/Samples~/Terrain/Textures/dry_soil_CH.png.meta b/Packages/com.unity.shadergraph/Samples~/Terrain/Textures/dry_soil_CH.png.meta deleted file mode 100644 index 080f2f7cd73..00000000000 --- a/Packages/com.unity.shadergraph/Samples~/Terrain/Textures/dry_soil_CH.png.meta +++ /dev/null @@ -1,117 +0,0 @@ -fileFormatVersion: 2 -guid: 5177befc12f3f8543828689be98cfb30 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 1 - enableMipMap: 1 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 2 - aniso: 16 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 0 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 4 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 2 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - customData: - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - spriteCustomMetadata: - entries: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/com.unity.visualeffectgraph/Documentation~/Images/library-of-ready-to-use-textures.jpg b/Packages/com.unity.visualeffectgraph/Documentation~/Images/library-of-ready-to-use-textures.jpg new file mode 100644 index 00000000000..0e4dd6f5b1c Binary files /dev/null and b/Packages/com.unity.visualeffectgraph/Documentation~/Images/library-of-ready-to-use-textures.jpg differ diff --git a/Packages/com.unity.visualeffectgraph/Documentation~/Images/lightmap-a.jpg b/Packages/com.unity.visualeffectgraph/Documentation~/Images/lightmap-a.jpg new file mode 100644 index 00000000000..789a52d835f Binary files /dev/null and b/Packages/com.unity.visualeffectgraph/Documentation~/Images/lightmap-a.jpg differ diff --git a/Packages/com.unity.visualeffectgraph/Documentation~/Images/lightmap-b.jpg b/Packages/com.unity.visualeffectgraph/Documentation~/Images/lightmap-b.jpg new file mode 100644 index 00000000000..e19ac8b807f Binary files /dev/null and b/Packages/com.unity.visualeffectgraph/Documentation~/Images/lightmap-b.jpg differ diff --git a/Packages/com.unity.visualeffectgraph/Documentation~/TableOfContents.md b/Packages/com.unity.visualeffectgraph/Documentation~/TableOfContents.md index db8547e804d..bb93a54f5ce 100644 --- a/Packages/com.unity.visualeffectgraph/Documentation~/TableOfContents.md +++ b/Packages/com.unity.visualeffectgraph/Documentation~/TableOfContents.md @@ -1,3 +1,4 @@ + * [Visual Effect Graph](index.md) * [Requirements](System-Requirements.md) * [What's new](whats-new.md) @@ -55,6 +56,13 @@ * [ExposedProperty Helper](ExposedPropertyHelper.md) * [Vector Fields](VectorFields.md) * [Spawner Callbacks](SpawnerCallbacks.md) + * [Realistic smoke lighting](six-way-lighting-landing.md) + * [Realistic smoke lighting with six-way lighting](six-way-lighting.md) + * [Use tools to generate six-way lightmap textures](use-tools-generate-six-way-lightmap-textures.md) + * [Import six-way lightmap textures into unity](import-six-way-lightmap-textures-unity.md) + * [Create and configure a six-way lit particle system](create-configure-six-way-lit-particle-system.md) + * [Customize free six-way lighting lightmap textures](create-effects-with-six-way-lighting.md) + * [Six-way smoke lit reference](six-way-lighting-reference.md) * [Node Library](node-library.md) * [Context](Context.md) * [Event](Context-Event.md) diff --git a/Packages/com.unity.visualeffectgraph/Documentation~/create-configure-six-way-lit-particle-system.md b/Packages/com.unity.visualeffectgraph/Documentation~/create-configure-six-way-lit-particle-system.md new file mode 100644 index 00000000000..d8208015585 --- /dev/null +++ b/Packages/com.unity.visualeffectgraph/Documentation~/create-configure-six-way-lit-particle-system.md @@ -0,0 +1,26 @@ +# Create a six-way lit particle system in Visual Effect Graph + +Set up a particle system in Visual Effect Graph that uses six-way lighting to achieve enhanced realism for smoke or explosion effects. + +To create and configure a six-way lit particle system, follow these steps: + +1. Open a **Visual Effect Graph** or create a new one. + +1. Set the system to burst a single particle, and allocate memory for one particle. + +1. Right-click the **Output Particle** context, then convert the output to a lit quad. + +1. Set **Material Type** to **Six-Way Smoke Lit** in the Inspector window. + +1. Drag and drop the two six-way lightmap textures from your `Assets` folder to the **Output Particle** context positive and negative axes lightmap slots, respectively. + +1. Set the **Output Particle** context **UV Mode** to **Flipbook**. + +1. Set the **Output Particle** context **Flip Book size** to match the number of frames. + +1. Configure the emissive settings in the Inspector window: + - Set **Emissive Mode** to **Single Channel**. This mode uses the alpha channel of the second texture. + - Adjust **Exposure Weight** and **Emissive Multiplier** as needed. + +1. Adjust six-way lighting settings as needed to achieve the desired effect. + diff --git a/Packages/com.unity.visualeffectgraph/Documentation~/create-effects-with-six-way-lighting.md b/Packages/com.unity.visualeffectgraph/Documentation~/create-effects-with-six-way-lighting.md new file mode 100644 index 00000000000..82ee11f49bd --- /dev/null +++ b/Packages/com.unity.visualeffectgraph/Documentation~/create-effects-with-six-way-lighting.md @@ -0,0 +1,42 @@ +# Customize existing six-way lightmap textures + +Customize lightmap textures to create smoke, dust, or explosions with six-way lighting. + +Unity provides a library of ready-to-use textures under the [CC0 license](https://creativecommons.org/public-domain/cc0/). These lightmap textures were created in an external DCC and exported using the tools provided in the [VFX Toolbox](https://github.com/Unity-Technologies/VFXToolbox). You can leverage these assets to create compact, game-ready effects with six-way lighting techniques. + +![A series of clouds and explosions in different shapes.](Images/library-of-ready-to-use-textures.jpg) + +To create an effect using built-in lightmaps and six-way lighting, follow these steps: + +1. Download the lightmaps from the [library of ready-to-use maps](https://drive.google.com/drive/folders/1_oh0UkAOW6hISqouCXjYwKQ0lkoj0CIF). + +1. Unzip the file you downloaded and place it in Unity's **Asset** folder. + +1. In the **Project** window, right-click and select **Create** > **Visual Effects** > **Visual Effect Graph**. + + The **Create new VFX Asset** window displays. + +1. Create a simple loop VFX asset. + +1. Double-click the new VFX asset. + + The VFX Graph editor displays. + +1. Open the [Blackboard](Blackboard.md). + +1. Right-click the **Output Particle Unlit** node. + +1. Select **Convert output**, then convert the node to an **Output Particle Lit Quad** node. + +1. With the **Output Particle Lit Quad** node selected, select **Six-Way Smoke Lit** from the Inspector **Material Type** dropdown. + +1. Drop the lightmaps you imported in the **Output Particle** context **Positive Axes Lightmap** and **Negative Axes Lightmap** fields. + +You can now test the effect in various lighting setups. + +## Additional resources + +- [VFX Graph](https://unity.com/features/visual-effect-graph) +- [The definitive guide to creating advanced visual effects in Unity](https://create.unity.com/definitive-guide-to-creating-advanced-visual-effects) +- [Realistic smoke lighting with six-way lighting in VFX Graph](https://unity.com/blog/engine-platform/realistic-smoke-with-6-way-lighting-in-vfx-graph) +- [VFX Graph: Six-way lighting workflow | Unity at GDC 2023](https://www.youtube.com/watch?v=uNzLQjpg6UE) diff --git a/Packages/com.unity.visualeffectgraph/Documentation~/import-six-way-lightmap-textures-unity.md b/Packages/com.unity.visualeffectgraph/Documentation~/import-six-way-lightmap-textures-unity.md new file mode 100644 index 00000000000..84b826a8fa0 --- /dev/null +++ b/Packages/com.unity.visualeffectgraph/Documentation~/import-six-way-lightmap-textures-unity.md @@ -0,0 +1,20 @@ +# Import six-way lightmap textures into Unity + +Import and configure six-way lightmap textures for use in Visual Effect Graph. + +To import and set up six-way lightmap textures, follow these steps: + +1. In the **Project** window, go to your **Assets** folder. + +1. Import the two six-way lightmap texture files into the folder. + +1. For each imported texture, set the following: + - Set **Max Size** to match the texture resolution (for example, 4096 for 4K textures). + - Set **Compression** to balance quality and memory usage (for example, **High Quality (BC7)**). + - Set **sRGB (Color Texture)** to match your export settings: + - If you exported the texture in gamma space, enable **sRGB (Color Texture)**. + - If you exported the texture in linear space, disable **sRGB (Color Texture)**. + +1. Select **Apply** to save the import settings. + +After you complete these steps, the six-way lightmap textures are ready for use in Visual Effect Graph. diff --git a/Packages/com.unity.visualeffectgraph/Documentation~/six-way-lighting-landing.md b/Packages/com.unity.visualeffectgraph/Documentation~/six-way-lighting-landing.md new file mode 100644 index 00000000000..99e733cb2d4 --- /dev/null +++ b/Packages/com.unity.visualeffectgraph/Documentation~/six-way-lighting-landing.md @@ -0,0 +1,17 @@ +# Realistic smoke lighting + +Implement custom lighting models to have more control over the visual style of smoke and explosions and achieve better performance. + +| Page | Description | +|-------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------| +| [Realistic smoke lighting with six-way lighting]( six-way-lighting.md) | Learn how and why to use six-way lighting in Unity to illuminate smoke. | +| [Use tools to generate six-way lightmap textures](use-tools-generate-six-way-lightmap-textures.md) | Learn how to create six-way lightmap textures in your preferred VFX tool for use in Unity. | +| [Import six-way lightmap textures into Unity](import-six-way-lightmap-textures-unity.md) | Learn how to import and configure six-way lightmap textures for use in Visual Effect Graph. | +| [Create and configure a six-way lit particle system](create-configure-six-way-lit-particle-system.md) | Learn how to achieve enhanced realism for smoke or explosion effects. | +| [Customize free six-way lighting lightmap textures](create-effects-with-six-way-lighting.md) | Learn how to generate high-quality smoke or dust effects with free lightmap textures. | + + +## Additional resources + +- [Realistic smoke lighting with six-way lighting in VFX Graph](https://unity.com/blog/engine-platform/realistic-smoke-with-6-way-lighting-in-vfx-graph) + diff --git a/Packages/com.unity.visualeffectgraph/Documentation~/six-way-lighting-reference.md b/Packages/com.unity.visualeffectgraph/Documentation~/six-way-lighting-reference.md new file mode 100644 index 00000000000..67a27b7c292 --- /dev/null +++ b/Packages/com.unity.visualeffectgraph/Documentation~/six-way-lighting-reference.md @@ -0,0 +1,88 @@ +# Six-way smoke lit reference + +Learn about the available properties to configure smoke rendering. + +These properties let you adjust lighting, animation, color, and performance. + +The **Smoke Shader UI** contains the following properties: + +## Lightmap Remapping + +The **Lightmap Remapping** section contains the following properties: + +| **Property** | Description | +| :-------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Lightmap Remap Mode (dropdown)** | Select how to remap lightmap values for the smoke. The following options are available:
  • **None**: Map lightmap values directly, with no remapping.
  • **Parametric Contrast**: Adjust lightmap contrast using parameter controls to boost or soften lighting transitions.
  • **Custom Curve**: Define a custom remap curve for precise control over lighting effects on the smoke.
| +| **Lightmap Remap Range** | Set the input/output range for lightmap remapping, clamping or stretching light values as needed. | +| **Use Alpha Remap** | Enable remapping of alpha values based on lighting to control transparency dynamically. | + +## Emissive + +The **Emissive** section contains the following properties: + +| **Property** | Description | +| :------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Emissive Mode (dropdown)** | Choose how the smoke emits light. The following options are available:
  • **None**: Disable emissive contribution, so smoke is only lit by external lights.
  • **Single Channel**: Use one channel to define emissive intensity, typically as a grayscale value.
  • **Map**: Apply a texture map to control emissive values for spatially varying glow.
| + +## Color and Alpha + +The **Color and Alpha** section contains the following properties: + +| **Property** | Description | +| :------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Use Color Absorption** | Enable simulation of color absorption to let smoke filter and tint passing light. | +| **Receive Shadows** | Allow smoke to receive shadows from other objects for added realism. | +| **Enable Cookie** | Apply light cookies (patterned masks) to affect light interaction with the smoke. | +| **Color Mode (dropdown)** | Control how color data is interpreted for rendering. The following options are available:
  • **None**: Use base color directly with no color processing.
  • **Everything**: Apply color processing to all channels.
  • **Base Color**: Process only the base color channel.
  • **Emissive**: Process only the emissive channel.
  • **Base Color And Emissive**: Process both base color and emissive channels.
| +| **Use Base Color Map** | Enable a texture map for base color to allow detailed color variation within the smoke. | +| **Base Color Map Mode (dropdown)** | Select which channels to use from the base color map. The following options are available:
  • **None**: Apply no base color map.
  • **Everything**: Use all color channels from the base color map.
  • **Color**: Use only color channels (RGB) from the map.
  • **Alpha**: Use only the alpha channel from the map for transparency.
  • **Color And Alpha**: Use both color and alpha channels from the map.
| + +## Texture and UV + +The **Texture and UV** section contains the following properties: + +| **Property** | Description | +| :------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Uv Mode (dropdown)** | Specify how UV coordinates are generated or used. The following options are available:
  • **Default**: Apply standard UV mapping for the texture.
  • **Flipbook**: Use flipbook animation for texture UVs, ideal for animated smoke sequences.
  • **Scale And Bias**: Scale and offset UVs for texture manipulation.
| +| **Flipbook Layout (dropdown)** | Define the layout of flipbook frames for animated textures. The following options are available:
  • **Texture 2D**: Use a standard 2D texture for smoke rendering.
  • **Texture 2D Array**: Use an array of 2D textures for complex animations or variations.
| +| **Base Color** | Set the base color for the smoke, as a constant or via a texture. | +| **Flipbook** | Specify the flipbook asset or parameters for animated texture sequences. | +| **Flipbook Blend Frames** | Control blending between flipbook frames for smooth animation. | + +## Particle Rendering + +The **Particle Rendering** section contains the following properties: + +| **Property** | Description | +| :------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Use Soft Particle** | Enable soft particle rendering to fade smoke edges near intersecting geometry for seamless integration. | +| **Sort (dropdown)** | Control particle sorting for correct transparency rendering. The following options are available:
  • **Auto**: Automatically determine the best sorting mode.
  • **Off**: Disable sorting, which might cause visual artifacts in transparency.
  • **On**: Enable sorting for correct draw order.
| +| **Sort Mode (dropdown)** | Specify sorting algorithm for particles. The following options are available:
  • **Distance To Camera**: Sort by distance to the camera, common for transparency.
  • **Youngest In Front**: Sort by particle age, with newest particles in front.
  • **Camera Depth**: Sort by camera depth buffer.
  • **Custom**: Use a custom sorting function.
| +| **Revert Sorting** | Reverse the sorting order when needed. | +| **Compute Culling** | Enable GPU culling of particles outside the view frustum for performance. | +| **Frustum Culling** | Cull smoke particles outside the camera frustum to optimize rendering. | +| **Cast Shadows** | Enable smoke particles to cast shadows onto other geometry. | + +## Render States + +The **Render States** section contains the following properties: + +| **Property** | Description | +| :---------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Render States** | Control advanced render state overrides for the smoke material. | +| **Blend Mode (dropdown)** | Set how smoke blends with the background. The following options are available:
  • **Additive**: Add smoke color to the background, ideal for light or glow effects.
  • **Alpha**: Use standard alpha blending for semi-transparent smoke.
  • **Alpha Premultiplied**: Use premultiplied alpha for improved compositing.
  • **Opaque**: Render smoke as fully opaque, with no blending.
| +| **Cull Mode (dropdown)** | Determine which faces are rendered. The following options are available:
  • **Default**: Apply standard culling (usually back-face).
  • **Front**: Render only front faces.
  • **Back**: Render only back faces.
  • **Off**: Disable face culling to render all faces.
| +| **Z Write Mode (dropdown)** | Control writing to the depth buffer (Z). The following options are available:
  • **Default**: Apply standard Z write behavior.
  • **Off**: Disable Z write, useful for transparency.
  • **On**: Enable Z write when needed for certain effects.
| +| **Z Test Mode (dropdown)** | Set the depth test function for rendering order. The following options are available:
  • **Default**: Use the default depth test (usually Less).
  • **Less**: Pass if incoming depth is less than stored.
  • **Greater**: Pass if incoming depth is greater than stored.
  • **L Equal**: Pass if less than or equal to stored.
  • **G Equal**: Pass if greater than or equal to stored.
  • **Equal**: Pass if depths are equal to stored.
  • **Not Equal**: Pass if depths are not equal to stored.
  • **Always**: Always pass, with no depth test.
| + +## Alpha and Motion + +The **Alpha and Motion** section contains the following properties: + +| **Property** | Description | +| :------------------------- | :----------------------------------------------------------------------------------------------------------- | +| **Alpha** | Set a global alpha value for smoke to control overall transparency. | +| **Use Alpha Clipping** | Enable alpha clipping to discard pixels below a certain alpha threshold for hard edges. | +| **Generate Motion Vector** | Enable motion vector output for the smoke to support motion blur. | +| **Exclude From TU And A** | Exclude smoke from certain rendering passes, such as temporal upscaling or anti-aliasing. | +| **Sorting Priority** | Set render queue priority to control draw order relative to other transparent objects. | diff --git a/Packages/com.unity.visualeffectgraph/Documentation~/six-way-lighting.md b/Packages/com.unity.visualeffectgraph/Documentation~/six-way-lighting.md new file mode 100644 index 00000000000..482feb6a7ac --- /dev/null +++ b/Packages/com.unity.visualeffectgraph/Documentation~/six-way-lighting.md @@ -0,0 +1,62 @@ +# Realistic smoke lighting with six-way lighting + +Blend pre-baked lightmaps and achieve dynamic lighting for smoke and other visual effects with six-way lighting. + +Six-way lighting stores lighting from six directions in textures. At runtime, Unity blends these textures based on scene lighting. Effects like smoke, explosions, and clouds thus respond to light sources. + +Six-way lighting enables the following: + +- Volumetric lighting for 2D or flipbook-based particle effects. +- Scaling for real-time visual effects (VFX). +- Adjustable color and emission. +- Compatibility with Unity's lighting system, including HDRP and URP. + +You can use six-way lighting in such scenarios as the folllowing: + +- Daytime smoke with sun and sky lighting. +- Nighttime effects with static or dynamic lights. +- Sandstorms and tornadoes. +- Glowing explosions. + +## How six-way lighting works + +Six-way lighting pre-bakes directional lighting into six sprite texture lightmaps. Each lightmap captures how the sprite is illuminated from a single direction: top, bottom, left, right, front, or back. + +At runtime, Unity shaders blend these six lightmaps based on the current scene lighting. Particles then react to light from any direction. + +## Supported lighting and Unity features + +You can use six-way lighting with the built-in VFX Graph Six-Way Smoke Lit output in both URP and HDRP. + +Six-way lighting supports indirect lighting from the following: +- Light Probes +- Adaptive Probe Volumes +- Ambient Probes +- Light Probe Proxy Volumes +- Dynamic point, spot, area, and directional lights + +**Note:** Six-way lighting does not support specular contributions from reflection probes. + +## Lightmap channel mapping + +Unity stores the six directional lightmaps in two RGBA textures. The channel mapping is as follows: + +- Lightmap A: + - Red: right + - Green: top + - Blue: back + - Alpha: transparency +- Lightmap B: + - Red: left + - Green: bottom + - Blue: front + - Alpha: emissive data + +![Five versions of the same smoke sprite. The first is red and lit from the right. The second is green and lit from the top. The third is blue and lit from the back. The fourth appears white and stores transparency in the Alpha channel. The fifth is a multicolored combination of all the previous sprites and stores the RGBA data in Lightmap A.](Images/lightmap-a.jpg) + + +![Five versions of the same smoke sprite. The first is red and lit from the left. The second is green and lit from the bottom. The third is blue and lit from the front. The fourth appears black and does not store any information in the Alpha channel. The fifth is a multicolored combination of all the previous sprites and stores the RGBA data in Lightmap B.](Images/lightmap-b.jpg) + +## Simulate fire and explosions + +To create glowing effects such as fire or explosions, store emissive data in the Alpha channel of Lightmap B to enable dynamic control over the effect's glow and color at runtime. diff --git a/Packages/com.unity.visualeffectgraph/Documentation~/use-tools-generate-six-way-lightmap-textures.md b/Packages/com.unity.visualeffectgraph/Documentation~/use-tools-generate-six-way-lightmap-textures.md new file mode 100644 index 00000000000..a28af0b1661 --- /dev/null +++ b/Packages/com.unity.visualeffectgraph/Documentation~/use-tools-generate-six-way-lightmap-textures.md @@ -0,0 +1,15 @@ +# Generate six-way lightmap textures for visual effects + +Create six-way lightmap textures in your preferred VFX tool for use in Unity. + +To create and export six-way lightmap textures for Unity, follow these steps: + +1. Simulate or paint the smoke or cloud effect in your preferred VFX tool. +2. Set six lighting directions: top, bottom, left, right, front, and back. +3. Render the lighting result from each direction. +4. Pack the lighting data into two textures: + - In the first texture, set the red, green, and blue channels to store lighting data, and set the alpha channel to store transparency. + - In the second texture, set the red, green, and blue channels to store lighting data, and set the alpha channel to store emissive or scattering effects. +5. Export the textures in a format that Unity supports. + +After you complete these steps, you can use the six-way lightmap textures in Unity. diff --git a/Packages/com.unity.visualeffectgraph/Editor/Controls/VFXEnumValuePopup.cs b/Packages/com.unity.visualeffectgraph/Editor/Controls/VFXEnumValuePopup.cs index 6363f3a6756..5a5c6e390cb 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/Controls/VFXEnumValuePopup.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/Controls/VFXEnumValuePopup.cs @@ -16,7 +16,7 @@ public VFXEnumValuePopup(string label, List values) { m_DropDownButton = new DropdownField(label); m_DropDownButton.choices = values; - m_DropDownButton.value = values[0]; + m_DropDownButton.value = values.Count > 0 ? values[0] : string.Empty; m_DropDownButton.RegisterCallback>(OnValueChanged); Add(m_DropDownButton); } diff --git a/Packages/com.unity.visualeffectgraph/Editor/Controls/VFXReorderableList.cs b/Packages/com.unity.visualeffectgraph/Editor/Controls/VFXReorderableList.cs index a12cd555e5c..854b0b6f4e6 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/Controls/VFXReorderableList.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/Controls/VFXReorderableList.cs @@ -129,10 +129,7 @@ public void Select(int index) } } - public virtual bool CanRemove() - { - return true; - } + protected virtual bool CanRemove() => itemCount > 1; public void Select(VisualElement item) { diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Blackboard/VFXBlackboard.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Blackboard/VFXBlackboard.cs index 7103b67098f..a40a35d9431 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Blackboard/VFXBlackboard.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Blackboard/VFXBlackboard.cs @@ -473,14 +473,23 @@ private DragVisualMode OnHandleDrop(HandleDragAndDropArgs arg) if (fieldId.Count > 0) { - foreach (var id in fieldId) + m_IsChangingSelection = true; + try { - m_Treeview.viewController.Move(id, arg.parentId, childIndex, true); - } + foreach (var id in fieldId) + { + m_Treeview.viewController.Move(id, arg.parentId, childIndex, true); + } - UpdateLastCategoryItem(arg.parentId); - m_Treeview.ClearSelection(); + UpdateLastCategoryItem(arg.parentId); + m_Treeview.ClearSelection(); + } + finally + { + m_IsChangingSelection = false; + } + return DragVisualMode.Move; } @@ -586,7 +595,19 @@ private void UnbindItem(VisualElement element, int index) element.parent.parent.RemoveFromClassList("sub-graph"); element.parent.parent.RemoveFromClassList("separator"); element.ClearClassList(); - element.Clear(); + + + // work around to avoid losing selection with virtualized treeview + bool oldChangingSelection = m_IsChangingSelection; + m_IsChangingSelection = true; + try + { + element.Clear(); + } + finally + { + m_IsChangingSelection = oldChangingSelection; + } } private void BindItem(VisualElement element, int index) diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Blackboard/VFXBlackboardPropertyView.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Blackboard/VFXBlackboardPropertyView.cs index 93f5396801f..3fcdf939e3f 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Blackboard/VFXBlackboardPropertyView.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Blackboard/VFXBlackboardPropertyView.cs @@ -18,6 +18,7 @@ class VFXBlackboardPropertyView : VisualElement, IControlledElement(OnAttachToPanel); + pickingMode = PickingMode.Ignore; // This fixes an issue where this element intercepts up event but not down, potentially putting the treeview incorrectly into drag mode. } public VFXBlackboardRow owner { get; set; } diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Elements/VFXEdgeConnector.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Elements/VFXEdgeConnector.cs index f346686a53f..eac939b6243 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Elements/VFXEdgeConnector.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Elements/VFXEdgeConnector.cs @@ -33,35 +33,6 @@ protected override void OnMouseMove(MouseMoveEvent e) s_PickedList.Clear(); view.panel.PickAll(e.mousePosition, s_PickedList); - - VFXDataAnchor anchor = s_PickedList.OfType().FirstOrDefault(); - - if (anchor != null) - view.StartEdgeDragInfo(this.edgeDragHelper.draggedPort as VFXDataAnchor, anchor); - else - view.StopEdgeDragInfo(); - } - - protected override void OnMouseUp(MouseUpEvent e) - { - base.OnMouseUp(e); - - if (!e.isPropagationStopped) - return; - - VFXView view = m_Anchor.GetFirstAncestorOfType(); - if (view == null) - return; - view.StopEdgeDragInfo(); - } - - protected override void Abort() - { - base.Abort(); - if (m_Anchor.GetFirstAncestorOfType() is { } view) - { - view.StopEdgeDragInfo(); - } } static List s_PickedList = new List(); diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Elements/VFXEdgeDragInfo.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Elements/VFXEdgeDragInfo.cs deleted file mode 100644 index eef2ca4f544..00000000000 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Elements/VFXEdgeDragInfo.cs +++ /dev/null @@ -1,144 +0,0 @@ -//#define OLD_COPY_PASTE -using System; -using System.Linq; -using System.Collections; -using System.Collections.Generic; -using UnityEditor.Experimental.GraphView; -using UnityEngine; -using UnityEngine.Rendering; -using UnityEditor.Experimental.VFX; -using UnityEngine.Experimental.VFX; -using UnityEngine.UIElements; -using UnityEngine.Profiling; -using System.Reflection; - -using PositionType = UnityEngine.UIElements.Position; - -namespace UnityEditor.VFX.UI -{ - class VFXEdgeDragInfo : VisualElement - { - VFXView m_View; - public VFXEdgeDragInfo(VFXView view) - { - m_View = view; - var tpl = VFXView.LoadUXML("VFXEdgeDragInfo"); - tpl.CloneTree(this); - - this.styleSheets.Add(VFXView.LoadStyleSheet("VFXEdgeDragInfo")); - - m_Text = this.Q