diff --git a/Packages/com.unity.render-pipelines.core/CHANGELOG.md b/Packages/com.unity.render-pipelines.core/CHANGELOG.md index 1b94923d9ec..abcc691caac 100644 --- a/Packages/com.unity.render-pipelines.core/CHANGELOG.md +++ b/Packages/com.unity.render-pipelines.core/CHANGELOG.md @@ -10,6 +10,94 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. Version Updated The version number for this package has increased due to a version update of a related graphics package. +## [17.0.3] - 2025-02-13 + +This version is compatible with Unity 6000.2.0a17. + +### Added +- Added Variable Rate Shading API support for (Raster)CommandBuffer(s), RenderGraph and RTHandles. +Various VRS utilities. +- helper functions to Render Graph. + +### Changed +- Modified the Rendering Debugger to prevent resource transfers in retail builds. +- Rendering Debugger - Moved the GPU Resident Drawer to the Rendering Section. +- Rendering Debugger - Moved Render Graph to the Rendering Section. +- Added an API to query the preferred depth-only format for target platforms. +- Improved Depth usage performance for some platforms. +- Improved the Native Render Pass CPU performance by implementing a Render Pass pooling system (URP RG). +- Reworked the additional properties. +- Improved Render Graph warning message in URP when missing RecordRenderGraph implementation. +- Displayed subpass and attachment index on Render Graph Viewer. +- Added a new icon and tooltip if there are multiple usage details for a resource block on Render Graph Viewer. +- Fixed Render Graph Viewer being called before Render Graph execution and its resource deallocation. +- Added What's New in Unity 6 to SRP Core Package. + +### Fixed +- Fixed an issue in Render Graph Viewer where text would overlap after searching in the Pass List. +- Fix pass culling corner case where resources are never deallocated when the last pass using them is culled +- Fix RenderGraphObjectPool and GetTempMaterialPropertyBlock() usage in URP RenderGraph +- Fix async compute corner case where URP RenderGraph was waiting for a resource not written by any pass +- Serialization errors are thrown when "com.unity.render-pipelines.core" is added as a custom package +- Add missing check for count parameter in DynamicArray.FindIndex +- Fixed incorrect format of default shadow texture +- Fixed render graph incorrectly handling rendering to array slices and mipmaps other than 0 in some cases. +- Fixed an issue where Lens Flare was not rendering properly in OpenGLES3. +- Fixed missing STP shaders & visual artifacts when targeting GLCore renderer. +- Render Graph Viewer - Improved UI lock when searching on side panels. +- Render Graph Viewer - Padding corrected on burger menu on the side panels. +- Fixed the crash happening when APV tried to stream in block data. +- Fixed VRS initialization errors. Now init may fail explicitly and must be checked by the user code. +- Fixed Rendering Debugger - Silent crash when selecting a Volume component with public RTHandles. +- Fixed Transient Resources support in Native RenderPass Render Graph (used in URP). +- Fixed an issue where the Adaptive Probe Volume (APV) streaming buffer could leak into the current pool when chunk sizes were mismatched, leading to memory contamination and potential crashes. +- Fixed an issue in the Render Graph Viewer where text overlapped after performing a search in the Pass List. +- Fixed an issue in pass culling where resources were not deallocated if the last pass using them was culled. +- Fixed `RenderGraphObjectPool` and `GetTempMaterialPropertyBlock()` usage in URP RenderGraph. +- Fixed an issue in URP Render Graph where, in an async compute edge case, it was waiting for a resource that was not written by any pass. +- Added messaging to the Rendering Debugger UI to make it clearer that GPU Resident Drawer settings do not work if GPU Resident Drawer is not enabled. +- GPU Resident Drawer: Changed BatchRendererGroup variants was not reinitializing the system. +- Improved the compiler logic that detects if the current render target is being used outside the current native render pass (e.g., when the pass is broken up by an unsafe pass), and determines the store action for this case. The fix now ensures that the `StoreAndResolve` action is used when the resource is read by an Unsafe Pass. +- Rendering Debugger - Keep the correct selected panel when entering and exiting from playmode. +- Removed "depth only surface" warning message appearing when using Game View Gizmos in URP RG. +- Render Graph Viewer: Fixed missing min height when resizing side panel vertical splitter. +- Render Graph Viewer: Fixed possible NullReferenceException when opening the project. +- Render Graph Viewer: Fixed side panel splitter state after returning from empty pass/resource filter. +- Render Graph Viewer: Fixed long resource name clipping issues in side panel. +- Render Graph Viewer: Fixed tooltip size bug and restructure tooltip messages. +- Fixed memory usage regression causing up to 150MB higher memory usage in URP player builds. +- Added missing user-facing text when inspecting volume profile when render pipeline has not been properly initialized yet. +- Game view background turn yellow after enable render graph. +- Fixed light.useViewFrustumForShadowCasterCull previously being ignored for shadow cascades. light.useViewFrustumForShadowCasterCull now works as expected. +- Fixed an exception thrown when Render Graph pass was missing its renderFunc but tried to compute its hash value. +- Fixed Render Graph Compiler logic bug where UnsafePass using MSAA texture could result in missing resolve surface errors. +- Fixed incorrect default source texture name for Render Graph blit util function. +- Fixed NullReferenceException when jumping to pass code from Render Graph Viewer. +- Fixed _FOVEATED_RENDERING_NON_UNIFORM_RASTER shader compilation errors. +- Fixed a null reference exception on the Graphics Settings stripper. +- Avoid that the same volume can be registered more than 1 time in the VolumeManager. +- Fixed crash caused by indirect argument buffer being one item too small. +- [GLES3] Fixed an issue where Blitter.GetBlitMaterial(TextureDimension.Tex2DArray) returns null. +- Fixed alignment of the columns on DebugUI.Foldouts. +- Fixed BlitTexture(RenderTargetIdentifier) to be affected by PostProcessing. +- Fixed errors that could happen when interacting with the Default Volume Profile context menu in Project Settings > Graphics. +- Fixed a numerical error of ComputeEdgeFactor(V1, V2) when two vectors are colinear. +- Fixed potential data corruption due to incorrect native render pass store action in NRP compiler. +- Added stencil flag to read-only depth logic in NRP compiler to avoid unintentional usage of depth read and stencil write states on some APIs. +- Added more error checking to `RenderGraph.ImportTexture` to prevent importing RenderTextures that have both color and depth. +An exception will now be thrown in this case. +- Fixed an issue when using multiple AddBlitPass would binds the _BlitTexture wrongly. +- Modified TextureDesc so it can now use GraphicsFormat to set the depthStencil format (TextureDesc.format). The TextureDesc.depthBufferBits and TextureDesc.colorFormat fields are now properties that call GraphicsFormatUtilities functions for backwards compatibility. The descriptor now unambiguously describes a single resource, either color or depth. Therefore, TextureHandle clearly represents a single resource. +- Modified RTHandle allocators so they can now use GraphicsFormat to set the depthStencil format (TextureDesc.format). The allocators take a single format for either color or depth stencil to avoid incorrectly creating depth instead of color or vice versa. +- Fixed a crash on DX12 due to invalid subpass flags passed by native render pass compiler. +- Fixed an issue where Lens Flare was not rendering properly in OpenGLES3. +- Fixed render graph incorrectly handling rendering to array slices and mipmaps other than 0 in some cases. +- Render Graph Viewer - Improved UI lock when searching on side panels. +- Render Graph Viewer - Padding corrected on burger menu on the side panels. +- Fixed missing STP shaders & visual artifacts when targeting GLCore renderer +- Rendering Debugger - Silent crash when selecting a Volume component with public RTHandles. +- Fixed a crash on leaking streaming scratch buffer differently sized into the current pool. + ## [17.0.2] - 2024-04-02 This version is compatible with Unity 6000.0.0b15. 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 0c7e971bc50..7ef2035d97e 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugState.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugState.cs @@ -179,7 +179,7 @@ public sealed class DebugStateInt : DebugState { } /// /// Object Debug State. /// - [Serializable, DebugState(typeof(DebugUI.ObjectPopupField))] + [Serializable, DebugState(typeof(DebugUI.ObjectPopupField), typeof(DebugUI.CameraSelector))] public sealed class DebugStateObject : DebugState { /// diff --git a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugUIDrawer.Builtins.cs b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugUIDrawer.Builtins.cs index f5bed0d0d3d..1ebe3a30e37 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugUIDrawer.Builtins.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugUIDrawer.Builtins.cs @@ -292,14 +292,40 @@ protected override UnityEngine.Object DoGUI(Rect rect, GUIContent label, DebugUI rect = EditorGUI.PrefixLabel(rect, label); var elements = field.getObjects(); - if (elements?.Any() ?? false) + var count = elements != null ? elements.Count() : -1; + if (count > 0) // Check if elements are not null and have any items { - var elementsArrayNames = elements.Select(e => e.name).ToArray(); - var elementsArrayIndices = Enumerable.Range(0, elementsArrayNames.Length).ToArray(); - var selectedIndex = selectedValue != null ? Array.IndexOf(elementsArrayNames, selectedValue.name) : 0; - var newSelectedIndex = EditorGUI.IntPopup(rect, selectedIndex, elementsArrayNames, elementsArrayIndices); + // Initialize arrays for names and indices, with +1 for the "None" option + string[] elementsArrayNames = new string[count + 1]; // +1 for the "None" option + int[] elementsArrayIndices = new int[elementsArrayNames.Length]; // Same size as elementsArrayNames + + // Add the "None" option at the beginning + elementsArrayNames[0] = "None"; + elementsArrayIndices[0] = 0; // "None" corresponds to index 0 + + // Populate the rest of the arrays with the element names and indices + int index = 1; + foreach (var element in elements) + { + elementsArrayNames[index] = element.name; + elementsArrayIndices[index] = index; // Set the index to match the element's position + index++; + } + + // Determine the selected index + int selectedIndex = selectedValue != null + ? Array.IndexOf(elementsArrayNames, selectedValue.name) + : 0; + + // Show the dropdown and get the new selected index + int newSelectedIndex = EditorGUI.IntPopup(rect, selectedIndex, elementsArrayNames, elementsArrayIndices); + + // If the selected index changed, update selectedValue if (selectedIndex != newSelectedIndex) - selectedValue = elements.ElementAt(newSelectedIndex); + { + // If "None" is selected, set selectedValue to null + selectedValue = newSelectedIndex == 0 ? null : elements.ElementAt(newSelectedIndex - 1); + } } else { @@ -476,7 +502,7 @@ public override void Begin(DebugUI.Widget widget, DebugState state) } bool previousValue = (bool)w.GetValue(); - bool value = CoreEditorUtils.DrawHeaderFoldout(title, previousValue, isTitleHeader: w.isHeader, customMenuContextAction: fillContextMenuAction); + bool value = CoreEditorUtils.DrawHeaderFoldout(title, previousValue, isTitleHeader: w.isHeader, customMenuContextAction: fillContextMenuAction, documentationURL: w.documentationUrl); if (previousValue != value) Apply(w, s, value); diff --git a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.cs b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.cs index 1ca095c6d56..b2f470f40c4 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.cs @@ -262,6 +262,32 @@ void UpdateWidgetStates() UpdateWidgetStates(panel); } + DebugState GetOrCreateDebugStateForValueField(DebugUI.Widget widget) + { + // Skip runtime & readonly only items + if (widget.isInactiveInEditor) + return null; + + if (widget is not DebugUI.IValueField valueField) + return null; + + string guid = widget.queryPath; + if (!m_WidgetStates.TryGetValue(guid, out var state) || state == null) + { + var widgetType = widget.GetType(); + if (s_WidgetStateMap.TryGetValue(widgetType, out Type stateType)) + { + Assert.IsNotNull(stateType); + state = (DebugState)CreateInstance(stateType); + state.queryPath = guid; + state.SetValue(valueField.GetValue(), valueField); + m_WidgetStates[guid] = state; + } + } + + return state; + } + void UpdateWidgetStates(DebugUI.IContainer container) { // Skip runtime only containers, we won't draw them so no need to serialize them either @@ -273,26 +299,10 @@ void UpdateWidgetStates(DebugUI.IContainer container) { // Skip non-serializable widgets but still traverse them in case one of their // children needs serialization support - if (widget is DebugUI.IValueField valueField) - { - // Skip runtime & readonly only items - if (widget.isInactiveInEditor) - return; + var state = GetOrCreateDebugStateForValueField(widget); - string guid = widget.queryPath; - if (!m_WidgetStates.TryGetValue(guid, out var state) || state == null) - { - var widgetType = widget.GetType(); - if (s_WidgetStateMap.TryGetValue(widgetType, out Type stateType)) - { - Assert.IsNotNull(stateType); - var inst = (DebugState)CreateInstance(stateType); - inst.queryPath = guid; - inst.SetValue(valueField.GetValue(), valueField); - m_WidgetStates[guid] = inst; - } - } - } + if (state != null) + continue; // Recurse if the widget is a container if (widget is DebugUI.IContainer containerField) @@ -317,7 +327,7 @@ public void ApplyStates(bool forceApplyAll = false) void ApplyState(string queryPath, DebugState state) { - if (!(DebugManager.instance.GetItem(queryPath) is DebugUI.IValueField widget)) + if (state == null || !(DebugManager.instance.GetItem(queryPath) is DebugUI.IValueField widget)) return; widget.SetValue(state.GetValue()); @@ -544,17 +554,26 @@ void OnWidgetGUI(DebugUI.Widget widget) if (widget.isInactiveInEditor || widget.isHidden) return; - // State will be null for stateless widget - m_WidgetStates.TryGetValue(widget.queryPath, out DebugState state); - GUILayout.Space(4); if (!s_WidgetDrawerMap.TryGetValue(widget.GetType(), out DebugUIDrawer drawer)) { - EditorGUILayout.LabelField("Drawer not found (" + widget.GetType() + ")."); + foreach (var pair in s_WidgetDrawerMap) + { + if (pair.Key.IsAssignableFrom(widget.GetType())) + { + drawer = pair.Value; + break; + } + } } + + if (drawer == null) + EditorGUILayout.LabelField("Drawer not found (" + widget.GetType() + ")."); else { + var state = GetOrCreateDebugStateForValueField(widget); + drawer.Begin(widget, state); if (drawer.OnGUI(widget, state)) 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 67d6182f5d9..46df8365cf4 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 @@ -151,13 +151,6 @@ public override bool Step() context.Dispose(); } - // Fixup lighting for probes part of bricks with different subdivision levels - // When baking reflection probes, we want to skip this step - if (m_BakingBatch != null) - { - FixSeams(s_BakeData.positionRemap, positions, irradiance, validity, renderingLayerMasks); - } - return true; } diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.cs b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.cs index 922c77f8979..dabbfc90e27 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.cs @@ -443,6 +443,7 @@ struct BakeData public int reflectionProbeCount; public NativeArray positionRemap; + public NativeArray originalPositions; public NativeArray sortedPositions; // Workers @@ -453,6 +454,9 @@ struct BakeData public RenderingLayerBaker layerMaskJob; public int cellIndex; + public Thread fixSeamsThread; + public bool doneFixingSeams; + // Progress reporting public BakingStep step; public ulong stepCount; @@ -466,6 +470,7 @@ public void Init(ProbeVolumeBakingSet bakingSet, NativeList probePositi reflectionProbeCount = requests.Count; jobs = CreateBakingJobs(bakingSet, requests.Count != 0); + originalPositions = probePositions.ToArray(Allocator.Persistent); SortPositions(probePositions, requests); virtualOffsetJob = virtualOffsetOverride ?? new DefaultVirtualOffset(); @@ -625,6 +630,7 @@ public void Dispose() job.Dispose(); positionRemap.Dispose(); + originalPositions.Dispose(); sortedPositions.Dispose(); skyOcclusionJob.encodedDirections.Dispose(); @@ -883,6 +889,7 @@ enum BakingStep SkyOcclusion, RenderingLayerMask, Integration, + FixSeams, FinalizeCells, Last = FinalizeCells + 1 @@ -1057,6 +1064,39 @@ static void BakeDelegate(ref float progress, ref bool done) } } + if (s_BakeData.step == BakingStep.FixSeams) + { + // Start fixing seams in the background + if (s_BakeData.fixSeamsThread == null) + { + s_BakeData.doneFixingSeams = false; + s_BakeData.fixSeamsThread = new Thread(() => + { + FixSeams( + s_BakeData.positionRemap, + s_BakeData.originalPositions, + s_BakeData.lightingJob.irradiance, + s_BakeData.lightingJob.validity, + s_BakeData.lightingJob.occlusion, + s_BakeData.skyOcclusionJob.occlusion, + s_BakeData.layerMaskJob.renderingLayerMasks); + + s_BakeData.doneFixingSeams = true; + }); + s_BakeData.fixSeamsThread.Start(); + } + // Wait until fixing seams is done + else + { + if (s_BakeData.doneFixingSeams) + { + s_BakeData.fixSeamsThread.Join(); + s_BakeData.fixSeamsThread = null; + s_BakeData.step++; + } + } + } + if (s_BakeData.step == BakingStep.FinalizeCells) { FinalizeCell(s_BakeData.cellIndex++, s_BakeData.positionRemap, @@ -1138,6 +1178,13 @@ static void OnBakeCancelled() LightingBaker.cancel = false; } + if (s_BakeData.fixSeamsThread != null) + { + LightingBaker.cancel = true; + s_BakeData.fixSeamsThread.Join(); + LightingBaker.cancel = false; + } + CleanBakeData(); } @@ -1227,13 +1274,22 @@ public Dictionary GetMap(in BakingCell cell) } } - static void FixSeams(NativeArray positionRemap, NativeArray positions, NativeArray sh, NativeArray validity, NativeArray renderingLayerMasks) + internal static void FixSeams( + NativeArray positionRemap, + NativeArray positions, + NativeArray sh, + NativeArray validity, + NativeArray probeOcclusion, + NativeArray skyOcclusion, + NativeArray renderingLayerMasks) { // Seams are caused are caused by probes on the boundary between two subdivision levels // The idea is to find first them and do a kind of dilation to smooth the values on the boundary // the dilation process consits in doing a trilinear sample of the higher subdivision brick and override the lower subdiv with that // We have to mark the probes on the boundary as valid otherwise leak reduction at runtime will interfere with this method + bool doProbeOcclusion = probeOcclusion.IsCreated && probeOcclusion.Length > 0; + bool doSkyOcclusion = skyOcclusion.IsCreated && skyOcclusion.Length > 0; // Use an indirection structure to ensure mem usage stays reasonable VoxelToBrickCache cache = new VoxelToBrickCache(); @@ -1326,7 +1382,9 @@ Vector3Int GetCellPositionFromVoxel(Vector3Int voxelToLookup, int cellSizeInBric if (bakedRenderingLayerMasks) probeRenderingLayerMask = renderingLayerMasks[i]; float weightSum = 0.0f; - SphericalHarmonicsL2 trilinear = default; + SphericalHarmonicsL2 shTrilinear = default; + Vector4 probeOcclusionTrilinear = Vector4.zero; + Vector4 skyOcclusionTrilinear = Vector4.zero; for (int o = 0; o < 8; o++) { Vector3Int offset = GetSampleOffset(o); @@ -1349,24 +1407,44 @@ Vector3Int GetCellPositionFromVoxel(Vector3Int voxelToLookup, int cellSizeInBric } // Do the lerp in compressed format to match result on GPU - var sample = sh[positionRemap[index]]; - BakingCell.CompressSH(ref sample, 1.0f, false); + var shSample = sh[positionRemap[index]]; + BakingCell.CompressSH(ref shSample, 1.0f, false); float trilinearW = ((offset.x == 1) ? fract.x : 1.0f - fract.x) * ((offset.y == 1) ? fract.y : 1.0f - fract.y) * ((offset.z == 1) ? fract.z : 1.0f - fract.z); - trilinear += sample * trilinearW; + shTrilinear += shSample * trilinearW; + + if (doProbeOcclusion) + probeOcclusionTrilinear += probeOcclusion[positionRemap[index]] * trilinearW; + + if (doSkyOcclusion) + skyOcclusionTrilinear += skyOcclusion[positionRemap[index]] * trilinearW; + weightSum += trilinearW; } } if (weightSum != 0.0f) { - trilinear *= 1.0f / weightSum; - BakingCell.DecompressSH(ref trilinear); - sh[i] = trilinear; + shTrilinear *= 1.0f / weightSum; + BakingCell.DecompressSH(ref shTrilinear); + sh[i] = shTrilinear; + + if (doProbeOcclusion) + { + probeOcclusionTrilinear *= 1.0f / weightSum; + probeOcclusion[i] = probeOcclusionTrilinear; + } + + if (doSkyOcclusion) + { + skyOcclusionTrilinear *= 1.0f / weightSum; + skyOcclusion[i] = skyOcclusionTrilinear; + } + validity[i] = k_MinValidityForLeaking; } } diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeLightingTab.cs b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeLightingTab.cs index 8aaa605c3c5..adeab0c8faa 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeLightingTab.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeLightingTab.cs @@ -48,6 +48,7 @@ static class Styles public static readonly string msgEnableAll = "Some loaded Scenes are disabled by this Baking Set. These Scenes will not contribute to the generation of probe data."; public static readonly string msgUnloadOther = "Scene(s) not belonging to this Baking Set are currently loaded in the Hierarchy. This might result in incorrect lighting."; public static readonly string msgLoadForBake = "Some scene(s) in this Baking Set are not currently loaded in the Hierarchy. This might result in missing or incomplete lighting."; + public static readonly string msgIncorrectBakingSet = "The currently loaded scenes do not match the assigned Baking Set. To resolve this, make sure to load the scenes that correspond to the assigned Baking Set, unload any scenes that don’t belong, and verify the scene setup before generating lighting to ensure everything bakes correctly."; public const float statusLabelWidth = 80; @@ -221,6 +222,19 @@ public override void OnGUI() Initialize(); var prv = ProbeReferenceVolume.instance; + // The CurrentBakingSet may change when you open an additional Scene with APV + if (prv.currentBakingSet != activeSet) + { + if (prv.currentBakingSet == null) + { + m_SingleSceneMode = true; + } + else + { + OpenBakingSet(prv.currentBakingSet); + } + } + // In single scene mode, user can't control active set, so we automatically create a new one // in case the active scene doesn't have a baking set so that we can display baking settings // Clone the current activeSet if possible so that it's seamless when eg. duplicating a scene @@ -358,6 +372,7 @@ void BakingGUI() { if (newSet != null) { EditorUtility.SetDirty(newSet); newSet.singleSceneMode = false; } activeSet = newSet; + ProbeReferenceVolume.instance.SetActiveBakingSet(activeSet); } if (activeSet != null) @@ -480,6 +495,24 @@ void ShowWarnings() } } + if (activeSet == ProbeReferenceVolume.instance.currentBakingSet) + { + hasWarnings = true; + foreach (var sceneDataList in ProbeReferenceVolume.instance.perSceneDataList) + { + if (sceneDataList.bakingSet == activeSet) + { + hasWarnings = false; + break; + } + } + + if (hasWarnings) + { + EditorGUILayout.HelpBox(Styles.msgIncorrectBakingSet, MessageType.Warning); + } + } + scenesForBake.Clear(); scenesToUnload.Clear(); scenesToEnable.Clear(); @@ -787,10 +820,14 @@ internal void OnSceneOpened(Scene scene, OpenSceneMode mode) // Find the set in which the new active scene belongs var set = ProbeVolumeBakingSet.GetBakingSetForScene(scene); - if (set != null) - { - activeSet = set; + activeSet = set; + if (set == null) + { + m_SingleSceneMode = true; + } + else + { // If we load a new scene that doesn't have the current scenario, change it if (!set.m_LightingScenarios.Contains(prv.lightingScenario)) prv.SetActiveScenario(set.m_LightingScenarios[0], false); diff --git a/Packages/com.unity.render-pipelines.core/Editor/SampleDependencyImportSystem/SampleDependencyImporter.cs b/Packages/com.unity.render-pipelines.core/Editor/SampleDependencyImportSystem/SampleDependencyImporter.cs index 65043e2048e..56d25b9aefb 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/SampleDependencyImportSystem/SampleDependencyImporter.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/SampleDependencyImportSystem/SampleDependencyImporter.cs @@ -48,7 +48,9 @@ static SampleDependencyImporter() PackageManagerExtensions.RegisterExtension(new SampleDependencyImporter()); } - const string k_srpPrefixPackage = "com.unity."; + const string k_unityPrefixPackage = "com.unity."; + bool importingTextMeshProEssentialResources = false; + PackageInfo m_PackageInfo; List m_Samples; SampleList m_SampleList; @@ -63,11 +65,15 @@ public void OnPackageRemoved(PackageInfo packageInfo) {} /// void IPackageManagerExtension.OnPackageSelectionChange(PackageInfo packageInfo) { - var isSrpPackage = packageInfo != null && packageInfo.name.StartsWith(k_srpPrefixPackage); + var isUnityPackage = packageInfo != null && packageInfo.name.StartsWith(k_unityPrefixPackage); - if (isSrpPackage) + if (isUnityPackage) { - m_PackageInfo = packageInfo; + + + + + m_PackageInfo = packageInfo; m_Samples = GetSamples(packageInfo); if (TryLoadSampleConfiguration(m_PackageInfo, out m_SampleList)) { @@ -104,6 +110,9 @@ static bool TryLoadSampleConfiguration(PackageInfo packageInfo, out SampleList c /// void LoadAssetDependencies(string assetPath) { + + ImportTextMeshProEssentialResources(); + if (m_SampleList != null) { var assetsImported = false; @@ -126,11 +135,32 @@ void LoadAssetDependencies(string assetPath) } } } + + if (assetsImported) AssetDatabase.Refresh(); } } + + /// + /// Import TMP Essential Resources folder to avoid having a popup on scene open. + /// + public void ImportTextMeshProEssentialResources() + { + string essentialResourcesFolder = Path.GetFullPath("Assets/TextMesh Pro"); + bool essentialResourcesImported = Directory.Exists(essentialResourcesFolder); + // If the folder exists and we were importing, this means the import is done. + if (importingTextMeshProEssentialResources && essentialResourcesImported) + importingTextMeshProEssentialResources = false; + + string packageFullPath = Path.GetFullPath("Packages/com.unity.ugui"); + if (Directory.Exists(packageFullPath) && !importingTextMeshProEssentialResources && !essentialResourcesImported) + { + importingTextMeshProEssentialResources = true; + AssetDatabase.ImportPackage(packageFullPath + "/Package Resources/TMP Essential Resources.unitypackage", interactive: false); + } + } /// /// Returns the properties of the samples based on the sample displayName diff --git a/Packages/com.unity.render-pipelines.core/Runtime/AssemblyInfo.cs b/Packages/com.unity.render-pipelines.core/Runtime/AssemblyInfo.cs index 8bf49b24911..96162f18722 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/AssemblyInfo.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/AssemblyInfo.cs @@ -5,3 +5,7 @@ [assembly: InternalsVisibleTo("Unity.RenderPipelines.Core.Runtime.Tests")] [assembly: InternalsVisibleTo("Unity.GraphicTests.Performance.RPCore.Runtime")] [assembly: InternalsVisibleTo("Unity.GraphicTests.Performance.Universal.Runtime")] // access to internal ProfileIds + +// Smoke test project visibility +[assembly: InternalsVisibleTo("SRPSmoke.Runtime.Tests")] +[assembly: InternalsVisibleTo("SRPSmoke.Editor.Tests")] diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Common/DynamicArray.cs b/Packages/com.unity.render-pipelines.core/Runtime/Common/DynamicArray.cs index 764d44b06e2..57f632ddb59 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Common/DynamicArray.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Common/DynamicArray.cs @@ -228,7 +228,7 @@ public void RemoveRange(int index, int count) /// The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, -1. public int FindIndex(int startIndex, int count, Predicate match) { - for (int i = startIndex; i < size; ++i) + for (int i = startIndex; i < size && count > 0; ++i, --count) { if (match(m_Array[i])) { @@ -238,6 +238,16 @@ public int FindIndex(int startIndex, int count, Predicate match) return -1; } + /// + /// Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the first occurrence within the range of elements in the DynamicArray. + /// + /// The Predicate delegate that defines the conditions of the element to search for. + /// The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, -1. + public int FindIndex(Predicate match) + { + return FindIndex(0, size, match); + } + /// /// Searches for the specified object and returns the zero-based index of the first occurrence within the range of elements in the DynamicArray that starts at the specified index and contains the specified number of elements. /// diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettings.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettings.cs index fb34429412b..d272c1a03b4 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettings.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettings.cs @@ -138,6 +138,11 @@ public void ForEach(Action onExecute) /// public virtual void Reset() { + foreach (IDebugDisplaySettingsData setting in m_Settings) + { + setting.Reset(); + } + m_Settings.Clear(); } 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 f7f88572b5f..c68319938f8 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettingsVolumes.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettingsVolumes.cs @@ -36,7 +36,6 @@ static class Styles static class Strings { public static readonly string none = "None"; - public static readonly string camera = "Camera"; public static readonly string parameter = "Parameter"; public static readonly string component = "Component"; public static readonly string debugViewNotSupported = "N/A"; @@ -96,16 +95,14 @@ public static DebugUI.EnumField CreateComponentSelector(SettingsPanel panel, Act public static DebugUI.ObjectPopupField CreateCameraSelector(SettingsPanel panel, Action, Object> refresh) { - return new DebugUI.ObjectPopupField + return new DebugUI.CameraSelector() { - displayName = Strings.camera, getter = () => panel.data.volumeDebugSettings.selectedCamera, setter = value => { var c = panel.data.volumeDebugSettings.cameras.ToArray(); panel.data.volumeDebugSettings.selectedCameraIndex = Array.IndexOf(c, value as Camera); }, - getObjects = () => panel.data.volumeDebugSettings.cameras, onValueChanged = refresh }; } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.Containers.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.Containers.cs index dc3d27bf579..1a484af82d4 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.Containers.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.Containers.cs @@ -166,7 +166,7 @@ public struct ContextMenuItem /// /// Opened state of the foldout. /// - public bool opened; + public bool opened { get; set; } /// /// Draw the foldout in full width using a header style. @@ -178,6 +178,11 @@ public struct ContextMenuItem /// public List contextMenuItems = null; + /// + /// Optional help URL for the editor UI + /// + public string documentationUrl { get; set; } + private bool m_Dirty; private string[] m_ColumnLabels; private string[] m_ColumnTooltips; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.Fields.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.Fields.cs index db504af0bcf..ee86b1ede28 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.Fields.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugUI.Fields.cs @@ -398,6 +398,64 @@ public class ObjectPopupField : Field public Func> getObjects { get; set; } } + /// + /// A dropdown that contains a list of cameras + /// + public class CameraSelector : ObjectPopupField + { + /// + /// A dropdown that contains a list of cameras + /// + public CameraSelector() + { + displayName = "Camera"; + getObjects = () => cameras; + } + + private Camera[] m_CamerasArray; + private List m_Cameras = new List(); + + IEnumerable cameras + { + get + { + m_Cameras.Clear(); + +#if UNITY_EDITOR + if (UnityEditor.SceneView.lastActiveSceneView != null) + { + var sceneCamera = UnityEditor.SceneView.lastActiveSceneView.camera; + if (sceneCamera != null) + m_Cameras.Add(sceneCamera); + } +#endif + + if (m_CamerasArray == null || m_CamerasArray.Length != Camera.allCamerasCount) + { + m_CamerasArray = new Camera[Camera.allCamerasCount]; + } + + Camera.GetAllCameras(m_CamerasArray); + + foreach (var camera in m_CamerasArray) + { + if (camera == null) + continue; + + if (camera.cameraType != CameraType.Preview && camera.cameraType != CameraType.Reflection) + { + if (!camera.TryGetComponent(out var additionalData)) + Debug.LogWarning($"Camera {camera.name} does not contain an additional camera data component. Open the Game Object in the inspector to add additional camera data."); + else + m_Cameras.Add(camera); + } + } + + return m_Cameras; + } + } + } + /// /// Enumerator field with history. /// diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/IDebugDisplaySettingsData.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/IDebugDisplaySettingsData.cs index daac1022757..13712d372e2 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/IDebugDisplaySettingsData.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/IDebugDisplaySettingsData.cs @@ -10,5 +10,10 @@ public interface IDebugDisplaySettingsData : IDebugDisplaySettingsQuery /// /// The debug UI panel created. IDebugDisplaySettingsPanelDisposable CreatePanel(); + + /// + /// Resets the values of the settings data + /// + void Reset() { } } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerCanvas.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerCanvas.cs index a9cd19bca5f..68de478b872 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerCanvas.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/Prefabs/Scripts/DebugUIHandlerCanvas.cs @@ -158,6 +158,18 @@ void Traverse(DebugUI.IContainer container, Transform parentTransform, DebugUIHa Transform prefab; if (!m_PrefabsMap.TryGetValue(child.GetType(), out prefab)) + { + foreach (var pair in m_PrefabsMap) + { + if (pair.Key.IsAssignableFrom(child.GetType())) + { + prefab = pair.Value; + break; + } + } + } + + if (prefab == null) { Debug.LogWarning("DebugUI widget doesn't have a prefab: " + child.GetType()); continue; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/Debug/DebugDisplayGPUResidentDrawer.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/Debug/DebugDisplayGPUResidentDrawer.cs index b71ac3963f1..e08d77d4c98 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/Debug/DebugDisplayGPUResidentDrawer.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/Debug/DebugDisplayGPUResidentDrawer.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Reflection; using Unity.Collections; using static UnityEngine.Rendering.DebugUI; using static UnityEngine.Rendering.DebugUI.Widget; @@ -9,6 +10,7 @@ namespace UnityEngine.Rendering /// /// GPU Resident Drawer Rendering Debugger settings. /// + [CurrentPipelineHelpURL("gpu-resident-drawer")] public class DebugDisplayGPUResidentDrawer : IDebugDisplaySettingsData { const string k_FormatString = "{0}"; @@ -224,14 +226,17 @@ private static DebugUI.Table.Row AddOcclusionContextDataRow(int index) } [DisplayInfo(name = "Rendering", order = 5)] - [CurrentPipelineHelpURL("gpu-resident-drawer")] private class SettingsPanel : DebugDisplaySettingsPanel { public override DebugUI.Flags Flags => DebugUI.Flags.EditorForceUpdate; public SettingsPanel(DebugDisplayGPUResidentDrawer data) { - var foldout = new DebugUI.Foldout() { displayName = Strings.drawerSettingsContainerName, }; + var foldout = new DebugUI.Foldout() + { + displayName = Strings.drawerSettingsContainerName, + documentationUrl = typeof(DebugDisplayGPUResidentDrawer).GetCustomAttribute()?.URL + }; AddWidget(foldout); var helpBox = new DebugUI.MessageBox() diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawer.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawer.cs index 666a7cb3706..aabf6728f7b 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawer.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/GPUResidentDrawer.cs @@ -334,7 +334,7 @@ private static void Recreate(GPUResidentDrawerSettings settings) private NativeList m_FrameCameraIDs; private bool m_FrameUpdateNeeded = false; - private bool m_SelectionChanged; + private bool m_IsSelectionDirty; static GPUResidentDrawer() { @@ -399,6 +399,7 @@ private GPUResidentDrawer(GPUResidentDrawerSettings settings, int maxInstanceCou #if UNITY_EDITOR AssemblyReloadEvents.beforeAssemblyReload += OnAssemblyReload; m_FrameCameraIDs = new NativeList(1, Allocator.Persistent); + m_IsSelectionDirty = true; // Force at least one selection update #endif SceneManager.sceneLoaded += OnSceneLoaded; @@ -429,6 +430,7 @@ private void Dispose() #endif SceneManager.sceneLoaded -= OnSceneLoaded; + // Note: Those RenderPipelineManager callbacks do not run when using built-in editor debug views such as lightmap, shadowmask etc RenderPipelineManager.beginContextRendering -= OnBeginContextRendering; RenderPipelineManager.endContextRendering -= OnEndContextRendering; RenderPipelineManager.beginCameraRendering -= OnBeginCameraRendering; @@ -487,6 +489,7 @@ private void OnBeginContextRendering(ScriptableRenderContext context, List cameras) { bool newFrame = false; @@ -508,21 +511,16 @@ private void EditorFrameUpdate(List cameras) else m_FrameUpdateNeeded = true; } - - ProcessSelection(); } private void OnSelectionChanged() { - m_SelectionChanged = true; + m_IsSelectionDirty = true; } - private void ProcessSelection() + private void UpdateSelection() { - if(!m_SelectionChanged) - return; - - m_SelectionChanged = false; + Profiler.BeginSample("GPUResidentDrawer.UpdateSelection"); Object[] renderers = Selection.GetFiltered(typeof(MeshRenderer), SelectionMode.Deep); @@ -532,8 +530,10 @@ private void ProcessSelection() rendererIDs[i] = renderers[i] ? renderers[i].GetInstanceID() : 0; m_Batcher.UpdateSelectedRenderers(rendererIDs); - + rendererIDs.Dispose(); + + Profiler.EndSample(); } #endif @@ -612,10 +612,15 @@ private void PostPostLateUpdate() supportedChangedPackedMaterialDatas.Dispose(); m_BatchersContext.UpdateInstanceMotions(); - m_Batcher.UpdateFrame(); #if UNITY_EDITOR + if (m_IsSelectionDirty) + { + UpdateSelection(); + m_IsSelectionDirty = false; + } + m_FrameUpdateNeeded = false; #endif } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.cs index a9eadd77de4..f6615975f95 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.cs @@ -727,6 +727,7 @@ public struct ExtraDataActionInput List m_ActiveScenes = new List(); ProbeVolumeBakingSet m_CurrentBakingSet = null; + ProbeVolumeBakingSet m_LazyBakingSet = null; bool m_NeedLoadAsset = false; bool m_ProbeReferenceVolumeInit = false; @@ -857,6 +858,39 @@ internal void RegisterPerSceneData(ProbeVolumePerSceneData data) } } + /// + /// Setting a BakingSet while it is uninitialized schedules it to be set after initialization. + /// + /// BakingSet to set. + /// Returns true when scheduled. + internal bool ScheduleBakingSet(ProbeVolumeBakingSet bakingSet) + { + if (m_IsInitialized) + { + return false; + } + + m_LazyBakingSet = bakingSet; + return true; + } + + /// + /// Set the scheduled BakingSet if it exists. + /// + /// Returns true if the scheduling is executed. + internal bool ProcessScheduledBakingSet() + { + if (m_LazyBakingSet == null) + { + return false; + } + + SetActiveBakingSet(m_LazyBakingSet); + m_LazyBakingSet = null; + + return true; + } + /// /// Loads the baking set the given scene is part of if it exists. /// @@ -877,6 +911,11 @@ public void SetActiveBakingSet(ProbeVolumeBakingSet bakingSet) if (m_CurrentBakingSet == bakingSet) return; + if (ScheduleBakingSet(bakingSet)) + { + return; + } + foreach (var data in perSceneDataList) data.QueueSceneRemoval(); @@ -1015,6 +1054,8 @@ public void Initialize(in ProbeVolumeSystemParameters parameters) foreach (var data in perSceneDataList) data.Initialize(); + + ProcessScheduledBakingSet(); } /// diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBlendStates.compute b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBlendStates.compute index 3376ed3489b..20b28b21c60 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBlendStates.compute +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBlendStates.compute @@ -1,4 +1,3 @@ -#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch webgpu gles3 //#pragma enable_d3d11_debug_symbols #pragma kernel BlendScenarios diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeUploadData.compute b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeUploadData.compute index f95fd582706..d80bf698404 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeUploadData.compute +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeUploadData.compute @@ -1,4 +1,3 @@ -#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch webgpu gles3 //#pragma enable_d3d11_debug_symbols #include "Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeUploadDataCommon.hlsl" diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeUploadDataL2.compute b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeUploadDataL2.compute index 881eeac7f32..5fbf608d11a 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeUploadDataL2.compute +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeUploadDataL2.compute @@ -1,4 +1,3 @@ -#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch webgpu gles3 //#pragma enable_d3d11_debug_symbols #include "Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeUploadDataCommon.hlsl" diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/LensFlareCommonSRP.cs b/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/LensFlareCommonSRP.cs index 8d8b04591af..20ecdb6bd7a 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/LensFlareCommonSRP.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/LensFlareCommonSRP.cs @@ -112,30 +112,47 @@ private LensFlareCommonSRP() { } - private static readonly bool s_SupportsLensFlare16bitsFormat = SystemInfo.IsFormatSupported(GraphicsFormat.R16_SFloat, GraphicsFormatUsage.Render); - private static readonly bool s_SupportsLensFlare32bitsFormat = SystemInfo.IsFormatSupported(GraphicsFormat.R32_SFloat, GraphicsFormatUsage.Render); + static readonly bool s_SupportsLensFlare16bitsFormat = SystemInfo.IsFormatSupported(GraphicsFormat.R16_SFloat, GraphicsFormatUsage.Render); + static readonly bool s_SupportsLensFlare32bitsFormat = SystemInfo.IsFormatSupported(GraphicsFormat.R32_SFloat, GraphicsFormatUsage.Render); + static readonly bool s_SupportsLensFlare16bitsFormatWithLoadStore = SystemInfo.IsFormatSupported(GraphicsFormat.R16_SFloat, GraphicsFormatUsage.LoadStore); + static readonly bool s_SupportsLensFlare32bitsFormatWithLoadStore = SystemInfo.IsFormatSupported(GraphicsFormat.R32_SFloat, GraphicsFormatUsage.LoadStore); - /// - /// Check if we can use an OcclusionRT - /// - /// return true if we can have the OcclusionRT - static public bool IsOcclusionRTCompatible() + // UUM-91313: Some Android Vulkan devices (Adreno 540) don't support R16_SFloat with GraphicsFormatUsage.LoadStore, + // which is required when creating a render texture with enableRandomWrite flag. Random writes are only needed by + // the merge step (compute shader using the texture as UAV), so we enable the flag only if merging is enabled. + static bool requireOcclusionRTRandomWrite => mergeNeeded > 0; + + static bool CheckOcclusionBasedOnDeviceType() { #if UNITY_SERVER return false; #else - return SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLES3 && - SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLCore && - SystemInfo.graphicsDeviceType != GraphicsDeviceType.Null && - SystemInfo.graphicsDeviceType != GraphicsDeviceType.WebGPU && - (s_SupportsLensFlare16bitsFormat || s_SupportsLensFlare32bitsFormat); //Caching this, because SupportsRenderTextureFormat allocates memory. Go figure. + return SystemInfo.graphicsDeviceType != GraphicsDeviceType.Null && + SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLES3 && + SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLCore && + SystemInfo.graphicsDeviceType != GraphicsDeviceType.WebGPU; #endif } + /// + /// Check if we can create OcclusionRT texture to be used as render target + /// + /// Returns true if a supported format is found + public static bool IsOcclusionRTCompatible() + { + if (requireOcclusionRTRandomWrite) + { + return CheckOcclusionBasedOnDeviceType() && + (s_SupportsLensFlare16bitsFormatWithLoadStore || s_SupportsLensFlare32bitsFormatWithLoadStore); + } + return CheckOcclusionBasedOnDeviceType() && + (s_SupportsLensFlare16bitsFormat || s_SupportsLensFlare32bitsFormat); + } + static GraphicsFormat GetOcclusionRTFormat() { // SystemInfo.graphicsDeviceType == {GraphicsDeviceType.Direct3D12, GraphicsDeviceType.GameCoreXboxSeries, GraphicsDeviceType.XboxOneD3D12, GraphicsDeviceType.PlayStation5, ...} - if (s_SupportsLensFlare16bitsFormat) + if (requireOcclusionRTRandomWrite ? s_SupportsLensFlare16bitsFormatWithLoadStore : s_SupportsLensFlare16bitsFormat) return GraphicsFormat.R16_SFloat; else // Needed a R32_SFloat for Metal or/and DirectX < 11.3 @@ -163,7 +180,7 @@ static public void Initialize() height: Mathf.Max(mergeNeeded * (maxLensFlareWithOcclusionTemporalSample + 1), 1), format: GetOcclusionRTFormat(), slices: TextureXR.slices, - enableRandomWrite: true, + enableRandomWrite: requireOcclusionRTRandomWrite, dimension: TextureDimension.Tex2DArray); } } 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 403298a0f8d..62fa39fd787 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 @@ -1514,14 +1514,16 @@ public void ExecuteGraph(InternalRenderGraphContext rgContext, RenderGraphResour rgContext.cmd.SetFoveatedRenderingMode(FoveatedRenderingMode.Disabled); } + rgContext.cmd.EndRenderPass(); + CommandBuffer.ThrowOnSetRenderTarget = false; + inRenderPass = false; + + // VRS ShadingRate(Image) cannot be set inside a render pass (cmdBuf). + // ShadingRate is set before BeginRenderPass and here we ResetShadingRate after EndRenderPass. if (nativePass.hasShadingRateStates || nativePass.hasShadingRateImage) { rgContext.cmd.ResetShadingRate(); } - - rgContext.cmd.EndRenderPass(); - CommandBuffer.ThrowOnSetRenderTarget = false; - inRenderPass = false; } } } 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 e7d1b458483..7b57e2fe2c0 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 @@ -4,6 +4,7 @@ using Unity.Collections.LowLevel.Unsafe; using UnityEngine.Rendering; using System.Collections.Generic; +using Unity.Collections; namespace UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler { @@ -646,7 +647,9 @@ public readonly ReadOnlySpan GraphPasses(CompilerContextData ctx) return ctx.passData.MakeReadOnlySpan(firstGraphPass, numGraphPasses); } - var actualPasses = new PassData[numGraphPasses]; + var actualPasses = + new NativeArray(numGraphPasses, Allocator.Temp, + NativeArrayOptions.UninitializedMemory); for (int i = firstGraphPass, index = 0; i < lastGraphPass + 1; ++i) { @@ -1222,7 +1225,7 @@ public static PassBreakAudit TryMerge(CompilerContextData contextData, int activ newAttachAccessFlags = newAttachAccessFlags & ~AccessFlags.Read; existingAttach.accessFlags |= newAttachAccessFlags; - + #if DEVELOPMENT_BUILD || UNITY_EDITOR if (existingAttach.resource.version > newAttach.resource.version) throw new Exception("Adding an older version while a higher version is already registered with the pass."); diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Debug/DebugDisplaySettingsRenderGraph.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Debug/DebugDisplaySettingsRenderGraph.cs index 6560edcdf30..3464f0bd9cf 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Debug/DebugDisplaySettingsRenderGraph.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Debug/DebugDisplaySettingsRenderGraph.cs @@ -1,4 +1,5 @@ using System; +using System.Reflection; using UnityEngine.Rendering.RenderGraphModule; using NameAndTooltip = UnityEngine.Rendering.DebugUI.Widget.NameAndTooltip; @@ -7,6 +8,7 @@ namespace UnityEngine.Rendering /// /// Render Graph-related Rendering Debugger settings. /// + [CurrentPipelineHelpURL(pageName: "features/rendering-debugger-reference", pageHash: "render-graph")] class DebugDisplaySettingsRenderGraph : IDebugDisplaySettingsData { public DebugDisplaySettingsRenderGraph() @@ -18,12 +20,15 @@ public DebugDisplaySettingsRenderGraph() } [DisplayInfo(name = "Rendering", order = 10)] - [CurrentPipelineHelpURL(pageName: "features/rendering-debugger-reference", pageHash: "render-graph")] private class SettingsPanel : DebugDisplaySettingsPanel { public SettingsPanel(DebugDisplaySettingsRenderGraph _) { - var foldout = new DebugUI.Foldout() { displayName = "Render Graph", }; + var foldout = new DebugUI.Foldout() + { + displayName = "Render Graph", + documentationUrl = typeof(DebugDisplaySettingsRenderGraph).GetCustomAttribute()?.URL + }; AddWidget(foldout); bool usingRenderGraph = false; 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 c5248f752fc..59eff1d522d 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilders.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilders.cs @@ -128,7 +128,8 @@ protected virtual void Dispose(bool disposing) { foreach (var texture in m_RenderGraph.AllGlobals()) { - this.UseTexture(texture, AccessFlags.Read); + if (texture.IsValid()) + this.UseTexture(texture, AccessFlags.Read); } } 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 d32a0baeea5..04bed65e761 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphCompilationCache.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphCompilationCache.cs @@ -49,7 +49,7 @@ bool GetCompilationCache(int hash, int frameIndex, out T outGraph, DynamicArr where T : RenderGraph.ICompiledGraph { s_Hash = hash; - int index = hashEntries.FindIndex(0, hashEntries.size, (value) => value.hash == s_Hash); + int index = hashEntries.FindIndex(value => value.hash == s_Hash); if (index != -1) { ref var entry = ref hashEntries[index]; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphDefaultResources.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphDefaultResources.cs index 2ac5a1ad1d6..5f5b7fef861 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphDefaultResources.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphDefaultResources.cs @@ -38,7 +38,7 @@ internal RenderGraphDefaultResources() { m_BlackTexture2D = RTHandles.Alloc(Texture2D.blackTexture); m_WhiteTexture2D = RTHandles.Alloc(Texture2D.whiteTexture); - m_ShadowTexture2D = RTHandles.Alloc(1, 1, CoreUtils.GetDefaultDepthStencilFormat(), isShadowMap: true, name: "DefaultShadowTexture"); + m_ShadowTexture2D = RTHandles.Alloc(1, 1, CoreUtils.GetDefaultDepthOnlyFormat(), isShadowMap: true, name: "DefaultShadowTexture"); } internal void Cleanup() diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphUtilsBlit.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphUtilsBlit.cs index ebd4505e7c1..a0600bd5d27 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphUtilsBlit.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphUtilsBlit.cs @@ -23,17 +23,20 @@ public static bool CanAddCopyPassMSAA() class CopyPassData { public bool isMSAA; + public bool force2DForXR; } + private const string DisableTexture2DXArray = "DISABLE_TEXTURE2D_X_ARRAY"; + /// /// Adds a pass to copy data from a source texture to a destination texture. The data in the texture is copied pixel by pixel. The copy function can only do 1:1 copies it will not allow scaling the data or - /// doing texture filtering. Furthermore it requires the source and destination surfaces to be the same size in pixels and have the same number of MSAA samples. If the textures are multi sampled - /// individual samples will be copied. + /// doing texture filtering. Furthermore it requires the source and destination surfaces to be the same size in pixels and have the same number of MSAA samples and array slices. + /// If the textures are multi sampled, individual samples will be copied. /// /// Copy is intentionally limited in functionally so it can be implemented using frame buffer fetch for optimal performance on tile based GPUs. If you are looking for a more generic /// function please use the AddBlitPass function. /// - /// For XR textures you will have to copy for each eye seperatly. + /// When XR is active, array textures containing both eyes will be automatically copied. /// /// For MSAA textures please use the CanAddCopyPassMSAA() function first to check if the CopyPass is supported on current platform. /// @@ -41,10 +44,6 @@ class CopyPassData /// The RenderGraph adding this pass to. /// The texture the data is copied from. /// The texture the data is copied to. This has to be different from souce. - /// The source slice of a Array of 3D texture to use. Must be 0 for regular 2D textures. - /// The destination slice of a Array of 3D texture to use. Must be 0 for regular 2D textures. - /// The first mipmap level to copy from. Must be zero for non-mipmapped textures. Must be a valid index for mipmapped textures. - /// The first mipmap level to copy to. Must be zero for non-mipmapped textures. Must be a valid index for mipmapped textures. /// A name to use for debugging and error logging. This name will be shown in the rendergraph debugger. /// File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it. /// File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it. @@ -52,10 +51,6 @@ public static void AddCopyPass( this RenderGraph graph, TextureHandle source, TextureHandle destination, - int sourceSlice = 0, - int destinationSlice = 0, - int sourceMip = 0, - int destinationMip = 0, string passName = "Copy Pass Utility" #if !CORE_PACKAGE_DOCTOOLS , [CallerFilePath] string file = "", @@ -64,29 +59,20 @@ public static void AddCopyPass( { if (!graph.nativeRenderPassesEnabled) throw new ArgumentException("CopyPass only supported for native render pass. Please use the blit functions instead for non native render pass platforms."); - + var sourceDesc = graph.GetTextureDesc(source); var destinationDesc = graph.GetTextureDesc(destination); - if (sourceSlice < 0 || sourceSlice >= sourceDesc.slices) - throw new ArgumentException("Invalid sourceSlice."); - - if (destinationSlice < 0 || destinationSlice >= destinationDesc.slices) - throw new ArgumentException("Invalid destinationSlice."); - - int sourceMaxWidth = math.max(math.max(sourceDesc.width, sourceDesc.height), sourceDesc.slices); - int sourceTotalMipChainLevels = (int)math.log2(sourceMaxWidth) + 1; - if (sourceMip < 0 || sourceMip >= sourceMaxWidth) - throw new ArgumentException("Invalid sourceMip."); - - int destinationMaxWidth = math.max(math.max(destinationDesc.width, destinationDesc.height), destinationDesc.slices); - int destinationTotalMipChainLevels = (int)math.log2(destinationMaxWidth) + 1; - if (destinationMip < 0 || destinationMip >= destinationMaxWidth) - throw new ArgumentException("Invalid destinationMip."); - if (sourceDesc.msaaSamples != destinationDesc.msaaSamples) throw new ArgumentException("MSAA samples from source and destination texture doesn't match."); + if (sourceDesc.width != destinationDesc.width || + sourceDesc.height != destinationDesc.height) + throw new ArgumentException("Dimensions for source and destination texture doesn't match."); + + if (sourceDesc.slices != destinationDesc.slices) + throw new ArgumentException("Slice count for source and destination texture doesn't match."); + var isMSAA = (int)sourceDesc.msaaSamples > 1; // Note: Needs shader model ps_4.1 to support SV_SampleIndex which means the copy pass isn't supported for MSAA on some platforms. @@ -100,15 +86,87 @@ public static void AddCopyPass( using (var builder = graph.AddRasterRenderPass(passName, out var passData, file, line)) { passData.isMSAA = isMSAA; - builder.SetInputAttachment(source, 0, AccessFlags.Read, sourceMip, sourceSlice); - builder.SetRenderAttachment(destination, 0, AccessFlags.Write, destinationMip, destinationSlice); + + bool isXRArrayTextureActive = TextureXR.useTexArray; + bool isArrayTexture = sourceDesc.slices > 1; + passData.force2DForXR = isXRArrayTextureActive && (isArrayTexture == false); + builder.SetInputAttachment(source, 0, AccessFlags.Read); + builder.SetRenderAttachment(destination, 0, AccessFlags.Write); builder.SetRenderFunc((CopyPassData data, RasterGraphContext context) => CopyRenderFunc(data, context)); + if (passData.force2DForXR) builder.AllowGlobalStateModification(true);// So we can set the keywords } } + /// + /// Adds a pass to copy data from a source texture to a destination texture. The data in the texture is copied pixel by pixel. The copy function can only do 1:1 copies it will not allow scaling the data or + /// doing texture filtering. Furthermore it requires the source and destination surfaces to be the same size in pixels and have the same number of MSAA samples. If the textures are multi sampled + /// individual samples will be copied. + /// + /// Copy is intentionally limited in functionally so it can be implemented using frame buffer fetch for optimal performance on tile based GPUs. If you are looking for a more generic + /// function please use the AddBlitPass function. Blit will automatically decide (based on the arguments) whether to use normal rendering or to instead call copy internally. + /// + /// The source/destination mip and slice arguments are ignored and were never used by this function therefore it is better to call the AddCopyPass overload without them. This function + /// is here for backwards compatibility with existing code. + /// + /// When XR is active, array textures containing both eyes will be automatically copied. + /// + /// For MSAA textures please use the CanAddCopyPassMSAA() function first to check if the CopyPass is supported on current platform. + /// + /// + /// The RenderGraph adding this pass to. + /// The texture the data is copied from. + /// The texture the data is copied to. This has to be different from souce. + /// This argument was never used. Please use the overload without this argument instead. If you want to work with mips or array slices you can use blit or write your own frame buffer fetch based implementation. + /// This argument was never used. Please use the overload without this argument instead. If you want to work with mips or array slices you can use blit or write your own frame buffer fetch based implementation. + /// This argument was never used. Please use the overload without this argument instead. If you want to work with mips or array slices you can use blit or write your own frame buffer fetch based implementation. + /// This argument was never used. Please use the overload without this argument instead. If you want to work with mips or array slices you can use blit or write your own frame buffer fetch based implementation. + /// A name to use for debugging and error logging. This name will be shown in the rendergraph debugger. + /// File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it. + /// File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it. + public static void AddCopyPass( + this RenderGraph graph, + TextureHandle source, + TextureHandle destination, + int sourceSlice, + int destinationSlice = 0, + int sourceMip = 0, + int destinationMip = 0, + string passName = "Copy Pass Utility" +#if !CORE_PACKAGE_DOCTOOLS + , [CallerFilePath] string file = "", + [CallerLineNumber] int line = 0) +#endif + { + AddCopyPass(graph, source, destination, passName, file, line); + } + static void CopyRenderFunc(CopyPassData data, RasterGraphContext rgContext) { - Blitter.CopyTexture(rgContext.cmd, data.isMSAA); + Blitter.CopyTexture(rgContext.cmd, data.isMSAA, data.force2DForXR); + } + + /// + /// Try to auto detect XR textures. + /// + /// + /// + /// + /// + /// + /// + internal static bool IsTextureXR(ref TextureDesc destDesc, int sourceSlice, int destinationSlice, int numSlices, int numMips) + { + if (TextureXR.useTexArray && + destDesc.dimension == TextureDimension.Tex2DArray && + destDesc.slices == TextureXR.slices && + sourceSlice == 0 && + destinationSlice == 0 && + numSlices == TextureXR.slices && + numMips == 1) + { + return true; + } + return false; } /// @@ -139,6 +197,7 @@ class BlitPassData public int destinationMip; public int numMips; public BlitFilterMode filterMode; + public bool isXR; } @@ -222,7 +281,7 @@ public static void AddBlitPass(this RenderGraph graph, passData.destinationMip = destinationMip; passData.numMips = numMips; passData.filterMode = filterMode; - + passData.isXR = IsTextureXR(ref destinationDesc, sourceSlice, destinationSlice, numSlices, numMips); builder.UseTexture(source, AccessFlags.Read); builder.UseTexture(destination, AccessFlags.Write); builder.SetRenderFunc((BlitPassData data, UnsafeGraphContext context) => BlitRenderFunc(data, context)); @@ -237,15 +296,24 @@ static void BlitRenderFunc(BlitPassData data, UnsafeGraphContext context) s_BlitScaleBias.w = data.offset.y; CommandBuffer unsafeCmd = CommandBufferHelpers.GetNativeCommandBuffer(context.cmd); - for (int currSlice = 0; currSlice < data.numSlices; currSlice++) + if (data.isXR) + { + // This is the magic that makes XR work for blit. We set the rendertargets passing -1 for the slices. This means it will bind all (both eyes) slices. + // The engine will then also automatically duplicate our draws and the vertex and pixel shader (through macros) will ensure those draws end up in the right eye. + context.cmd.SetRenderTarget(data.destination, 0, CubemapFace.Unknown, -1); + Blitter.BlitTexture(unsafeCmd, data.source, s_BlitScaleBias, data.sourceMip, data.filterMode == BlitFilterMode.ClampBilinear); + } + else { - for (int currMip = 0; currMip < data.numMips; currMip++) + for (int currSlice = 0; currSlice < data.numSlices; currSlice++) { - context.cmd.SetRenderTarget(data.destination, data.destinationMip + currMip, CubemapFace.Unknown, data.destinationSlice + currSlice); - Blitter.BlitTexture(unsafeCmd, data.source, s_BlitScaleBias, data.sourceMip + currMip, data.sourceSlice + currSlice, data.filterMode == BlitFilterMode.ClampBilinear); + for (int currMip = 0; currMip < data.numMips; currMip++) + { + context.cmd.SetRenderTarget(data.destination, data.destinationMip + currMip, CubemapFace.Unknown, data.destinationSlice + currSlice); + Blitter.BlitTexture(unsafeCmd, data.source, s_BlitScaleBias, data.sourceMip + currMip, data.sourceSlice + currSlice, data.filterMode == BlitFilterMode.ClampBilinear); + } } } - } /// @@ -277,7 +345,8 @@ public enum FullScreenGeometryType /// /// Use one of the constructor overloads for common use cases. /// - /// + /// By default most constructors will copy all array texture slices. This ensures XR textures are handled "automatically" without additional consideration. + /// /// The shader properties defined in the struct or constructors is used for most common usecases but they are not required to be used in the shader. /// By using the MaterialPropertyBlock can you add your shader properties with custom values. /// @@ -289,7 +358,8 @@ public struct BlitMaterialParameters private static readonly int blitScaleBias = Shader.PropertyToID("_BlitScaleBias"); /// - /// Simple constructor to set a few amount of parameters to blit. + /// Simple constructor that sets only the most common parameters to blit. The other parameters will be set to sensible default values. + /// /// /// The texture the data is copied from. /// The texture the data is copied to. @@ -299,7 +369,7 @@ public BlitMaterialParameters(TextureHandle source, TextureHandle destination, M : this(source, destination, Vector2.one, Vector2.zero, material, shaderPass) { } /// - /// Simple constructor to set a few amount of parameters to blit. + /// Simple constructor that sets only the most common parameters to blit. The other parameters will be set to sensible default values. /// /// The texture the data is copied from. /// The texture the data is copied to. @@ -315,7 +385,7 @@ public BlitMaterialParameters(TextureHandle source, TextureHandle destination, V this.offset = offset; sourceSlice = -1; destinationSlice = 0; - numSlices = 1; + numSlices = -1; sourceMip = -1; destinationMip = 0; numMips = 1; @@ -360,7 +430,7 @@ public BlitMaterialParameters(TextureHandle source, TextureHandle destination, M MaterialPropertyBlock mpb, int destinationSlice, int destinationMip, - int numSlices = 1, + int numSlices = -1, int numMips = 1, int sourceSlice = -1, int sourceMip = -1, @@ -388,7 +458,7 @@ public BlitMaterialParameters(TextureHandle source, TextureHandle destination, M /// Material property block to use to render the blit. This property should contain all data the shader needs. /// The first slice to copy to if the texture is an 3D or array texture. Must be zero for regular textures. /// The first mipmap level to copy to. Must be zero for non-mipmapped textures. Must be a valid index for mipmapped textures. - /// The number of slices to copy. -1 to copy all slices until the end of the texture. Arguments that copy invalid slices to be copied will lead to an error. + /// The number of slices to copy. -1 to copy all slices until the end of the texture. Arguments that copy invalid slices to be copied will lead to an error. If you are using an XR-array texture make sure you set this to -1 or the number of slices in the array our your XR texture will not be correctly copied. /// The number of mipmaps to copy. -1 to copy all mipmaps. Arguments that copy invalid mips to be copied will lead to an error. /// The first slice to copy from if the texture is an 3D or array texture. Must be zero for regular textures. Default is set to -1 to ignore source slices and set it to 0 without looping for each destination slice /// The first mipmap level to copy from. Must be zero for non-mipmapped textures. Must be a valid index for mipmapped textures. Defaults to -1 to ignore source mips and set it to 0 without looping for each destination mip. @@ -412,7 +482,7 @@ public BlitMaterialParameters(TextureHandle source, TextureHandle destination, V MaterialPropertyBlock mpb, int destinationSlice, int destinationMip, - int numSlices = 1, + int numSlices = -1, int numMips = 1, int sourceSlice = -1, int sourceMip = -1, @@ -542,7 +612,8 @@ public BlitMaterialParameters(TextureHandle source, TextureHandle destination, V public Vector2 offset; /// - /// The first slice of the source texture to blit from. -1 to ignore source slices and set it to 0 without looping for each destination slice. + /// The first slice of the source texture to blit from. -1 to ignore source slices. This will not set any values to the sourceSlicePropertyID texture parameters. + /// If not -1, the sourceSlicePropertyID will be set between sourceSlice and sourceSlice+numSlices for each slice that is blit. /// public int sourceSlice; @@ -557,7 +628,8 @@ public BlitMaterialParameters(TextureHandle source, TextureHandle destination, V public int numSlices; /// - /// The first source mipmap to blit from. -1 to ignore source mips and set it to 0 without looping for each destination mip. + /// The first source mipmap to blit from. -1 to ignore source mips. This will not set any values to the sourceMipPropertyID texture parameters. + /// If not -1, the sourceMipPropertyID will be set between sourceMip and sourceMip+numMips for each mip that is blit. /// public int sourceMip; @@ -596,12 +668,14 @@ public BlitMaterialParameters(TextureHandle source, TextureHandle destination, V /// /// The scalar property to set with the source slice index. If -1 the default "_BlitTexArraySlice" property will be used. Note: Use Shader.PropertyToID to convert a string property name to an ID. /// If more than one slice is rendered using the blit function (numSlices>1) several full screen quads will be rendered for each slice with different sourceSlicePropertyID values set. + /// If sourceSlice is -1, no values will be set on the property. /// public int sourceSlicePropertyID; /// /// The scalar property to set with the source mip index. If -1 the default "_BlitMipLevel" property will be used. Note: Use Shader.PropertyToID to convert a string property name to an ID. - /// If more than one mip is rendered using the blit function (numMips>1) several full screen quads will be rendered for each slice with different sourceMipPropertyID values set./// + /// If more than one mip is rendered using the blit function (numMips>1), several full screen quads will be rendered for each slice with different sourceMipPropertyID values set. + /// If sourceMip is -1, no values will be set on the property. /// public int sourceMipPropertyID; @@ -636,6 +710,7 @@ class BlitMaterialPassData public int sourceSlicePropertyID; public int sourceMipPropertyID; public int scaleBiasPropertyID; + public bool isXR; } /// @@ -680,27 +755,53 @@ public static void AddBlitPass(this RenderGraph graph, [CallerLineNumber] int line = 0) #endif { - var sourceDesc = graph.GetTextureDesc(blitParameters.source); - var destinationDesc = graph.GetTextureDesc(blitParameters.destination); + if (!blitParameters.destination.IsValid()) + { + throw new ArgumentException($"BlitPass: {passName} destination needs to be a valid texture handle."); + } - int sourceMaxWidth = math.max(math.max(sourceDesc.width, sourceDesc.height), sourceDesc.slices); - int sourceTotalMipChainLevels = (int)math.log2(sourceMaxWidth) + 1; + var destinationDesc = graph.GetTextureDesc(blitParameters.destination); + // Fill in unspecified parameters automatically based on the texture descriptor int destinationMaxWidth = math.max(math.max(destinationDesc.width, destinationDesc.height), destinationDesc.slices); int destinationTotalMipChainLevels = (int)math.log2(destinationMaxWidth) + 1; + if (blitParameters.numSlices == -1) + { + blitParameters.numSlices = destinationDesc.slices - blitParameters.destinationSlice; + } - if (blitParameters.numSlices == -1) blitParameters.numSlices = destinationDesc.slices - blitParameters.destinationSlice; - if (blitParameters.numSlices > destinationDesc.slices - blitParameters.destinationSlice - || (blitParameters.sourceSlice != -1 && blitParameters.numSlices > sourceDesc.slices - blitParameters.sourceSlice)) + if (blitParameters.numMips == -1) { - throw new ArgumentException($"BlitPass: {passName} attempts to blit too many slices. The pass will be skipped."); + blitParameters.numMips = destinationTotalMipChainLevels - blitParameters.destinationMip; } - if (blitParameters.numMips == -1) blitParameters.numMips = destinationTotalMipChainLevels - blitParameters.destinationMip; - if (blitParameters.numMips > destinationTotalMipChainLevels - blitParameters.destinationMip - || (blitParameters.sourceMip != -1 && blitParameters.numMips > sourceTotalMipChainLevels - blitParameters.sourceMip)) + // Validate against the source if available + if (blitParameters.source.IsValid()) { - throw new ArgumentException($"BlitPass: {passName} attempts to blit too many mips. The pass will be skipped."); + var sourceDesc = graph.GetTextureDesc(blitParameters.source); + int sourceMaxWidth = math.max(math.max(sourceDesc.width, sourceDesc.height), sourceDesc.slices); + int sourceTotalMipChainLevels = (int)math.log2(sourceMaxWidth) + 1; + + if (blitParameters.sourceSlice != -1 && blitParameters.numSlices > sourceDesc.slices - blitParameters.sourceSlice) + { + throw new ArgumentException($"BlitPass: {passName} attempts to blit too many slices. There are not enough slices in the source array. The pass will be skipped."); + } + + if (blitParameters.sourceMip != -1 && blitParameters.numMips > sourceTotalMipChainLevels - blitParameters.sourceMip) + { + throw new ArgumentException($"BlitPass: {passName} attempts to blit too many mips. There are not enough mips in the source texture. The pass will be skipped."); + } + } + + // Validate against destination + if (blitParameters.numSlices > destinationDesc.slices - blitParameters.destinationSlice) + { + throw new ArgumentException($"BlitPass: {passName} attempts to blit too many slices. There are not enough slices in the destination array. The pass will be skipped."); + } + + if (blitParameters.numMips > destinationTotalMipChainLevels - blitParameters.destinationMip) + { + throw new ArgumentException($"BlitPass: {passName} attempts to blit too many mips. There are not enough mips in the destination texture. The pass will be skipped."); } using (var builder = graph.AddUnsafePass(passName, out var passData, file, line)) @@ -723,8 +824,13 @@ public static void AddBlitPass(this RenderGraph graph, passData.sourceSlicePropertyID = blitParameters.sourceSlicePropertyID; passData.sourceMipPropertyID = blitParameters.sourceMipPropertyID; passData.scaleBiasPropertyID = blitParameters.scaleBiasPropertyID; + passData.isXR = IsTextureXR(ref destinationDesc, (passData.sourceSlice == -1) ? 0 : passData.sourceSlice, passData.destinationSlice, passData.numSlices, passData.numMips); + + if (blitParameters.source.IsValid()) + { + builder.UseTexture(blitParameters.source); + } - builder.UseTexture(blitParameters.source); builder.UseTexture(blitParameters.destination, AccessFlags.Write); builder.SetRenderFunc((BlitMaterialPassData data, UnsafeGraphContext context) => BlitMaterialRenderFunc(data, context)); } @@ -741,34 +847,61 @@ static void BlitMaterialRenderFunc(BlitMaterialPassData data, UnsafeGraphContext if (data.propertyBlock == null) data.propertyBlock = s_PropertyBlock; - data.propertyBlock.SetTexture(data.sourceTexturePropertyID, data.source); - if (data.sourceSlice == -1) - data.propertyBlock.SetInt(data.sourceSlicePropertyID, 0); - if (data.sourceMip == -1) - data.propertyBlock.SetInt(data.sourceMipPropertyID, 0); + if (data.source.IsValid()) + { + data.propertyBlock.SetTexture(data.sourceTexturePropertyID, data.source); + } + data.propertyBlock.SetVector(data.scaleBiasPropertyID, s_BlitScaleBias); - for (int currSlice = 0; currSlice < data.numSlices; currSlice++) + if (data.isXR) { - for (int currMip = 0; currMip < data.numMips; currMip++) + // This is the magic that makes XR work for blit. We set the rendertargets passing -1 for the slices. This means it will bind all (both eyes) slices. + // The engine will then also automatically duplicate our draws and the vertex and pixel shader (through macros) will ensure those draws end up in the right eye. + + if (data.sourceSlice != -1) + data.propertyBlock.SetInt(data.sourceSlicePropertyID, 0); + if (data.sourceMip != -1) + data.propertyBlock.SetInt(data.sourceMipPropertyID, data.sourceMip); + + context.cmd.SetRenderTarget(data.destination, 0, CubemapFace.Unknown, -1); + switch (data.geometry) { - if (data.sourceSlice != -1) - data.propertyBlock.SetInt(data.sourceSlicePropertyID, data.sourceSlice + currSlice); - if (data.sourceMip != -1) - data.propertyBlock.SetInt(data.sourceMipPropertyID, data.sourceMip + currMip); - - context.cmd.SetRenderTarget(data.destination, data.destinationMip + currMip, CubemapFace.Unknown, data.destinationSlice + currSlice); - switch (data.geometry) + case FullScreenGeometryType.Mesh: + Blitter.DrawQuadMesh(unsafeCmd, data.material, data.shaderPass, data.propertyBlock); + break; + case FullScreenGeometryType.ProceduralQuad: + Blitter.DrawQuad(unsafeCmd, data.material, data.shaderPass, data.propertyBlock); + break; + case FullScreenGeometryType.ProceduralTriangle: + Blitter.DrawTriangle(unsafeCmd, data.material, data.shaderPass, data.propertyBlock); + break; + } + } + else + { + for (int currSlice = 0; currSlice < data.numSlices; currSlice++) + { + for (int currMip = 0; currMip < data.numMips; currMip++) { - case FullScreenGeometryType.Mesh: - Blitter.DrawQuadMesh(unsafeCmd, data.material, data.shaderPass, data.propertyBlock); - break; - case FullScreenGeometryType.ProceduralQuad: - Blitter.DrawQuad(unsafeCmd, data.material, data.shaderPass, data.propertyBlock); - break; - case FullScreenGeometryType.ProceduralTriangle: - Blitter.DrawTriangle(unsafeCmd, data.material, data.shaderPass, data.propertyBlock); - break; + if (data.sourceSlice != -1) + data.propertyBlock.SetInt(data.sourceSlicePropertyID, data.sourceSlice + currSlice); + if (data.sourceMip != -1) + data.propertyBlock.SetInt(data.sourceMipPropertyID, data.sourceMip + currMip); + + context.cmd.SetRenderTarget(data.destination, data.destinationMip + currMip, CubemapFace.Unknown, data.destinationSlice + currSlice); + switch (data.geometry) + { + case FullScreenGeometryType.Mesh: + Blitter.DrawQuadMesh(unsafeCmd, data.material, data.shaderPass, data.propertyBlock); + break; + case FullScreenGeometryType.ProceduralQuad: + Blitter.DrawQuad(unsafeCmd, data.material, data.shaderPass, data.propertyBlock); + break; + case FullScreenGeometryType.ProceduralTriangle: + Blitter.DrawTriangle(unsafeCmd, data.material, data.shaderPass, data.propertyBlock); + break; + } } } } 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 1013ff02985..dfd48165890 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blitter.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blitter.cs @@ -4,6 +4,7 @@ using UnityEngine.Assertions; using System.Text.RegularExpressions; using UnityEngine.Rendering.RenderGraphModule.Util; +using UnityEngine.Rendering.RenderGraphModule; #if UNITY_EDITOR using UnityEditor; #endif @@ -340,6 +341,16 @@ static internal void DrawQuad(CommandBuffer cmd, Material material, int shaderPa internal static bool CanCopyMSAA() { + //Temporary disable most msaa copies as we fix UUM-67324 which is a bit more involved due to the internal work required + GraphicsDeviceType deviceType = SystemInfo.graphicsDeviceType; + if (deviceType != GraphicsDeviceType.Metal || deviceType != GraphicsDeviceType.Vulkan) + { + return false; + } + + // This test works since the second pass has the following pragmas and will not be compiled if they are not supported + // #pragma target 4.5 + // #pragma require msaatex return s_Copy.passCount == 2; } @@ -347,9 +358,17 @@ internal static bool CanCopyMSAA() /// Copies a texture to another texture using framebuffer fetch. /// /// Command Buffer used for rendering. - internal static void CopyTexture(RasterCommandBuffer cmd, bool isMSAA) + /// Disable the special handling when XR is active where the source and destination are considered array + /// textures with a slice for each eye. Setting this to true will consider source and destination as regular 2D textures. When XR is + /// disabled, textures are always 2D so forcing them to 2D has no impact. + internal static void CopyTexture(RasterCommandBuffer cmd, bool isMSAA, bool force2DForXR = false) { + if (force2DForXR) cmd.EnableShaderKeyword("DISABLE_TEXTURE2D_X_ARRAY"); + DrawTriangle(cmd, s_Copy, isMSAA ? 1 : 0); + + // Set back the XR texture for regular XR calls + if (force2DForXR) cmd.DisableShaderKeyword("DISABLE_TEXTURE2D_X_ARRAY"); } /// diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Utilities/CoreUtils.cs b/Packages/com.unity.render-pipelines.core/Runtime/Utilities/CoreUtils.cs index 98f4fce1a70..0255b52e0be 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Utilities/CoreUtils.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Utilities/CoreUtils.cs @@ -1830,6 +1830,20 @@ public static GraphicsFormat GetDefaultDepthStencilFormat() #endif } + /// + /// Return the GraphicsFormat of Depth-only RenderTarget preferred for the current platform. + /// + /// The GraphicsFormat of Depth-only RenderTarget preferred for the current platform. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static GraphicsFormat GetDefaultDepthOnlyFormat() + { +#if UNITY_SWITCH || UNITY_EMBEDDED_LINUX || UNITY_QNX || UNITY_ANDROID + return GraphicsFormatUtility.GetDepthStencilFormat(24, 0); // returns GraphicsFormat.D24_UNorm when hardware supports it +#else + return GraphicsFormat.D32_SFloat; +#endif + } + /// /// Return the number of DepthStencil RenderTarget depth bits preferred for the current platform. /// diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Utilities/HashFNV1A32.cs b/Packages/com.unity.render-pipelines.core/Runtime/Utilities/HashFNV1A32.cs index 3753a51897b..ed76b8f56de 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Utilities/HashFNV1A32.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Utilities/HashFNV1A32.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Runtime.CompilerServices; using Unity.Collections; @@ -112,26 +113,26 @@ public override int GetHashCode() static class DelegateHashCodeUtils { //Cache to prevent CompilerGeneratedAttribute extraction for known delegate - static NativeHashMap s_MethodHashCodeToSkipTargetHashMap = new(30, Allocator.Persistent); + static readonly Lazy> s_MethodHashCodeToSkipTargetHashMap = new(() => new Dictionary(64)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetFuncHashCode(Delegate del) { //Get MethodInfo hash code as the main one to be used - var methodHashCode = del.Method.GetHashCode(); + var methodHashCode = RuntimeHelpers.GetHashCode(del.Method); //Check if we are dealing with lambda or static delegates and skip target if we are. //Static methods have a null Target. //Lambdas have a CompilerGeneratedAttribute as they are generated by a compiler. //If Lambda have any captured variable Target hashcode will be different each time we re-create lambda. - if (!s_MethodHashCodeToSkipTargetHashMap.TryGetValue(methodHashCode, out var skipTarget)) + if (!s_MethodHashCodeToSkipTargetHashMap.Value.TryGetValue(methodHashCode, out var skipTarget)) { skipTarget = del.Target == null || ( del.Method.DeclaringType?.IsNestedPrivate == true && Attribute.IsDefined(del.Method.DeclaringType, typeof(CompilerGeneratedAttribute), false) ); - s_MethodHashCodeToSkipTargetHashMap.Add(methodHashCode, skipTarget); + s_MethodHashCodeToSkipTargetHashMap.Value[methodHashCode] = skipTarget; } //Combine method info hashcode and target hashcode if needed @@ -139,8 +140,8 @@ public static int GetFuncHashCode(Delegate del) } //used for testing - internal static int GetTotalCacheCount() => s_MethodHashCodeToSkipTargetHashMap.Count; + internal static int GetTotalCacheCount() => s_MethodHashCodeToSkipTargetHashMap.Value.Count; - internal static void ClearCache() => s_MethodHashCodeToSkipTargetHashMap.Clear(); + internal static void ClearCache() => s_MethodHashCodeToSkipTargetHashMap.Value.Clear(); } } \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureXR.hlsl b/Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureXR.hlsl index 0927aa67567..5200189db2d 100644 --- a/Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureXR.hlsl +++ b/Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureXR.hlsl @@ -107,7 +107,7 @@ #define GATHER_GREEN_TEXTURE2D_X GATHER_GREEN_TEXTURE2D #define GATHER_BLUE_TEXTURE2D_X GATHER_BLUE_TEXTURE2D #define GATHER_ALPHA_TEXTURE2D_X GATHER_ALPHA_TEXTURE2D -#endif +#endif //defined(USE_TEXTURE2D_X_AS_ARRAY) // see Unity\Shaders\Includes\UnityShaderVariables.cginc for impl used by the C++ renderer #if defined(USING_STEREO_MATRICES) && defined(UNITY_STEREO_INSTANCING_ENABLED) @@ -128,4 +128,104 @@ #define UNITY_STEREO_ASSIGN_COMPUTE_EYE_INDEX UNITY_XR_ASSIGN_VIEW_INDEX #endif +#if defined(SHADER_API_METAL) && defined(UNITY_NEEDS_RENDERPASS_FBFETCH_FALLBACK) + // Special metal fallback (allows branching per input to texture load or proper fbf) + +#if defined(USE_TEXTURE2D_X_AS_ARRAY) + +#define RENDERPASS_DECLARE_FALLBACK_X(T, idx) \ + Texture2DArray _UnityFBInput##idx; float4 _UnityFBInput##idx##_TexelSize; \ + inline T ReadFBInput_##idx(bool var, uint2 coord) { \ + [branch]if(var) { return hlslcc_fbinput_##idx; } \ + else { return _UnityFBInput##idx.Load(uint4(coord, SLICE_ARRAY_INDEX, 0)); } \ + } + +#define FRAMEBUFFER_INPUT_X_HALF(idx) cbuffer hlslcc_SubpassInput_f_##idx { half4 hlslcc_fbinput_##idx; bool hlslcc_fbfetch_##idx; }; \ + RENDERPASS_DECLARE_FALLBACK_X(half4, idx) + +#define FRAMEBUFFER_INPUT_X_FLOAT(idx) cbuffer hlslcc_SubpassInput_f_##idx { float4 hlslcc_fbinput_##idx; bool hlslcc_fbfetch_##idx; }; \ + RENDERPASS_DECLARE_FALLBACK_X(float4, idx) + +#define FRAMEBUFFER_INPUT_X_INT(idx) cbuffer hlslcc_SubpassInput_f_##idx { int4 hlslcc_fbinput_##idx; bool hlslcc_fbfetch_##idx; }; \ + RENDERPASS_DECLARE_FALLBACK_X(int4, idx) + +#define FRAMEBUFFER_INPUT_X_UINT(idx) cbuffer hlslcc_SubpassInput_f_##idx { uint4 hlslcc_fbinput_##idx; bool hlslcc_fbfetch_##idx; }; \ + RENDERPASS_DECLARE_FALLBACK_X(uint4, idx) + +#define LOAD_FRAMEBUFFER_INPUT_X(idx, v2fname) ReadFBInput_##idx(hlslcc_fbfetch_##idx, uint2(v2fname.xy)) + + +#define RENDERPASS_DECLARE_FALLBACK_MS_X(T, idx) \ + Texture2DMSArray _UnityFBInput##idx; float4 _UnityFBInput##idx##_TexelSize; \ + inline T ReadFBInput_##idx(bool var, uint2 coord, uint sampleIdx) { \ + [branch]if(var) { return hlslcc_fbinput_##idx[sampleIdx]; } \ + else { return _UnityFBInput##idx.Load(uint3(coord, SLICE_ARRAY_INDEX), sampleIdx); } \ + } + +#define FRAMEBUFFER_INPUT_X_FLOAT_MS(idx) \ + cbuffer hlslcc_SubpassInput_F_##idx { float4 hlslcc_fbinput_##idx[8]; bool hlslcc_fbfetch_##idx; }; \ + RENDERPASS_DECLARE_FALLBACK_MS_X(float4, idx) + +#define FRAMEBUFFER_INPUT_X_HALF_MS(idx) \ + cbuffer hlslcc_SubpassInput_H_##idx { half4 hlslcc_fbinput_##idx[8]; bool hlslcc_fbfetch_##idx; }; \ + RENDERPASS_DECLARE_FALLBACK_MS_X(half4, idx) + +#define FRAMEBUFFER_INPUT_X_INT_MS(idx) \ + cbuffer hlslcc_SubpassInput_I_##idx { int4 hlslcc_fbinput_##idx[8]; bool hlslcc_fbfetch_##idx; }; \ + RENDERPASS_DECLARE_FALLBACK_MS_X(int4, idx) + +#define FRAMEBUFFER_INPUT_X_UINT_MS(idx) \ + cbuffer hlslcc_SubpassInput_U_##idx { uint4 hlslcc_fbinput_##idx[8]; bool hlslcc_fbfetch_##idx; }; \ + UNITY_RENDERPASS_DECLARE_FALLBACK_MS_X(uint4, idx) + +#define LOAD_FRAMEBUFFER_INPUT_X_MS(idx, sampleIdx, v2fname) ReadFBInput_##idx(hlslcc_fbfetch_##idx, uint2(v2fname.xy), sampleIdx) + +#else + // X is just 2D texture so just use the existing macros that have all the metal magic for regular 2D textures + #define FRAMEBUFFER_INPUT_X_HALF(idx) FRAMEBUFFER_INPUT_HALF(idx) + #define FRAMEBUFFER_INPUT_X_FLOAT(idx) FRAMEBUFFER_INPUT_FLOAT(idx) + #define FRAMEBUFFER_INPUT_X_INT(idx) FRAMEBUFFER_INPUT_INT(idx) + #define FRAMEBUFFER_INPUT_X_UINT(idx) FRAMEBUFFER_INPUT_UINT(idx) + #define LOAD_FRAMEBUFFER_INPUT_X(idx, v2fname) LOAD_FRAMEBUFFER_INPUT(idx, v2fname) + + #define FRAMEBUFFER_INPUT_X_HALF_MS(idx) FRAMEBUFFER_INPUT_HALF_MS(idx) + #define FRAMEBUFFER_INPUT_X_FLOAT_MS(idx) FRAMEBUFFER_INPUT_FLOAT_MS(idx) + #define FRAMEBUFFER_INPUT_X_INT_MS(idx) FRAMEBUFFER_INPUT_INT_MS(idx) + #define FRAMEBUFFER_INPUT_X_UINT_MS(idx) FRAMEBUFFER_INPUT_UINT_MS(idx) + #define LOAD_FRAMEBUFFER_INPUT_X_MS(idx, sampleIdx, v2fvertexname) LOAD_FRAMEBUFFER_INPUT_MS(idx, sampleIdx, v2fvertexname) + +#endif //defined(USE_TEXTURE2D_X_AS_ARRAY) + +#elif !defined(PLATFORM_SUPPORTS_NATIVE_RENDERPASS) + + // Use regular texture loads as a fallback these can be either 2d or array depending on the TEXTURE2D_X (USE_TEXTURE2D_X_AS_ARRAY) macros +#define FRAMEBUFFER_INPUT_X_HALF(idx) TEXTURE2D_X_HALF(_UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize +#define FRAMEBUFFER_INPUT_X_FLOAT(idx) TEXTURE2D_X_FLOAT(_UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize +#define FRAMEBUFFER_INPUT_X_INT(idx) TEXTURE2D_X_INT(_UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize +#define FRAMEBUFFER_INPUT_X_UINT(idx) TEXTURE2D_X_UINT(_UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize +#define LOAD_FRAMEBUFFER_INPUT_X(idx, v2fvertexname) LOAD_TEXTURE2D_X(_UnityFBInput##idx,v2fvertexname.xy) + +#define FRAMEBUFFER_INPUT_X_FLOAT_MS(idx) TEXTURE2D_X_MSAA(float4, _UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize +#define FRAMEBUFFER_INPUT_X_HALF_MS(idx) TEXTURE2D_X_MSAA(float4, _UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize +#define FRAMEBUFFER_INPUT_X_INT_MS(idx) TEXTURE2D_X_MSAA(int4, _UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize +#define FRAMEBUFFER_INPUT_X_UINT_MS(idx) TEXTURE2D_X_MSAA(uint4, _UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize +#define LOAD_FRAMEBUFFER_INPUT_X_MS(idx, sampleIdx, v2fvertexname) LOAD_TEXTURE2D_X_MSAA(_UnityFBInput##idx, v2fvertexname.xy, sampleIdx) + +#else + + // Proper fbf, it will automatically ensure the correct eye is fb-fetched so we do not care if USE_TEXTURE2D_X_AS_ARRAY is enabled or not +#define FRAMEBUFFER_INPUT_X_HALF(idx) FRAMEBUFFER_INPUT_HALF(idx) +#define FRAMEBUFFER_INPUT_X_FLOAT(idx) FRAMEBUFFER_INPUT_FLOAT(idx) +#define FRAMEBUFFER_INPUT_X_INT(idx) FRAMEBUFFER_INPUT_INT(idx) +#define FRAMEBUFFER_INPUT_X_UINT(idx) FRAMEBUFFER_INPUT_UINT(idx) +#define LOAD_FRAMEBUFFER_INPUT_X(idx, v2fname) LOAD_FRAMEBUFFER_INPUT(idx, v2fname) + +#define FRAMEBUFFER_INPUT_X_HALF_MS(idx) FRAMEBUFFER_INPUT_HALF_MS(idx) +#define FRAMEBUFFER_INPUT_X_FLOAT_MS(idx) FRAMEBUFFER_INPUT_FLOAT_MS(idx) +#define FRAMEBUFFER_INPUT_X_INT_MS(idx) FRAMEBUFFER_INPUT_INT_MS(idx) +#define FRAMEBUFFER_INPUT_X_UINT_MS(idx) FRAMEBUFFER_INPUT_UINT_MS(idx) +#define LOAD_FRAMEBUFFER_INPUT_X_MS(idx, sampleIdx, v2fvertexname) LOAD_FRAMEBUFFER_INPUT_MS(idx, sampleIdx, v2fname) + +#endif //!defined(PLATFORM_SUPPORTS_NATIVE_RENDERPASS) + #endif // UNITY_TEXTUREXR_INCLUDED diff --git a/Packages/com.unity.render-pipelines.core/Shaders/CoreCopy.shader b/Packages/com.unity.render-pipelines.core/Shaders/CoreCopy.shader index e799f4edfaf..dc6870af200 100644 --- a/Packages/com.unity.render-pipelines.core/Shaders/CoreCopy.shader +++ b/Packages/com.unity.render-pipelines.core/Shaders/CoreCopy.shader @@ -14,22 +14,45 @@ Shader "Hidden/CoreSRP/CoreCopy" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureXR.hlsl" - #include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl" - + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl" + + #pragma multi_compile_fragment _ DISABLE_TEXTURE2D_X_ARRAY #pragma vertex Vert #pragma fragment CopyFrag // Declares the framebuffer input as a texture 2d containing half. - FRAMEBUFFER_INPUT_FLOAT(0); + FRAMEBUFFER_INPUT_X_FLOAT(0); + + struct Attributes + { + uint vertexID : SV_VertexID; + UNITY_VERTEX_INPUT_INSTANCE_ID + }; + + struct Varyings + { + float4 positionCS : SV_POSITION; + UNITY_VERTEX_OUTPUT_STEREO + }; + + Varyings Vert(Attributes input) + { + Varyings output; + UNITY_SETUP_INSTANCE_ID(input); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); + + output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID); + return output; + } // Out frag function takes as input a struct that contains the screen space coordinate we are going to use to sample our texture. It also writes to SV_Target0, this has to match the index set in the UseTextureFragment(sourceTexture, 0, …) we defined in our render pass script. float4 CopyFrag(Varyings input) : SV_Target0 - { - // read the current pixel from the framebuffer - float2 uv = input.texcoord.xy; + { + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); + // read previous subpasses directly from the framebuffer. - half4 color = LOAD_FRAMEBUFFER_INPUT(0, input.positionCS.xy); + half4 color = LOAD_FRAMEBUFFER_INPUT_X(0, input.positionCS.xy); // Modify the sampled color return color; @@ -49,23 +72,46 @@ Shader "Hidden/CoreSRP/CoreCopy" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureXR.hlsl" - #include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl" + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl" + #pragma multi_compile_fragment _ DISABLE_TEXTURE2D_X_ARRAY #pragma vertex Vert #pragma fragment CopyFragMS #pragma target 4.5 #pragma require msaatex // Declares the framebuffer input as a texture 2d containing half. - FRAMEBUFFER_INPUT_FLOAT_MS(0); + FRAMEBUFFER_INPUT_X_FLOAT_MS(0); + + struct Attributes + { + uint vertexID : SV_VertexID; + UNITY_VERTEX_INPUT_INSTANCE_ID + }; + + struct Varyings + { + float4 positionCS : SV_POSITION; + UNITY_VERTEX_OUTPUT_STEREO + }; + + Varyings Vert(Attributes input) + { + Varyings output; + UNITY_SETUP_INSTANCE_ID(input); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); + + output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID); + return output; + } // Out frag function takes as input a struct that contains the screen space coordinate we are going to use to sample our texture. It also writes to SV_Target0, this has to match the index set in the UseTextureFragment(sourceTexture, 0, …) we defined in our render pass script. float4 CopyFragMS(Varyings input, uint sampleID : SV_SampleIndex) : SV_Target0 { - // read the current pixel from the framebuffer - float2 uv = input.texcoord.xy; + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); + // read previous subpasses directly from the framebuffer. - half4 color = LOAD_FRAMEBUFFER_INPUT_MS(0, sampleID, input.positionCS.xy); + half4 color = LOAD_FRAMEBUFFER_INPUT_X_MS(0, sampleID, input.positionCS.xy); // Modify the sampled color return color; diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/AssemblyInfo.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/AssemblyInfo.cs new file mode 100644 index 00000000000..21d14073caf --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("SRPSmoke.Editor.Tests")] diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/AssemblyInfo.cs.meta b/Packages/com.unity.render-pipelines.core/Tests/Editor/AssemblyInfo.cs.meta new file mode 100644 index 00000000000..e8c59f801cb --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/AssemblyInfo.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 79d9da7a81239e744bc809717c68ae47 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/DynamicArrayTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/DynamicArrayTests.cs index e459dcbb889..5468c2dcb10 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Editor/DynamicArrayTests.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/DynamicArrayTests.cs @@ -214,6 +214,8 @@ public void TestFindIndexFailReturnMinusOne() m_DynamicArray.Add(2); Assert.AreEqual(-1, m_DynamicArray.FindIndex(0, m_DynamicArray.size, (x) => x == 4)); + + Assert.AreEqual(-1, m_DynamicArray.FindIndex((x) => x == 4)); } [Test] @@ -225,6 +227,23 @@ public void TestFindIndexSuccessReturnRightFirstIndex() m_DynamicArray.Add(2); Assert.AreEqual(1, m_DynamicArray.FindIndex(0, m_DynamicArray.size, (x) => x == 2)); + Assert.AreEqual(3, m_DynamicArray.FindIndex(2, 2, (x) => x == 2)); + + Assert.AreEqual(1, m_DynamicArray.FindIndex((x) => x == 2)); + } + + [Test] + public void TestFindIndexDoesNotFindOutsideCount() + { + m_DynamicArray.Add(1); + m_DynamicArray.Add(2); + m_DynamicArray.Add(3); + m_DynamicArray.Add(4); + + Assert.AreEqual(-1, m_DynamicArray.FindIndex(1, 2, (x) => x == 1)); + Assert.AreEqual(1, m_DynamicArray.FindIndex(1, 2, (x) => x == 2)); + Assert.AreEqual(2, m_DynamicArray.FindIndex(1, 2, (x) => x == 3)); + Assert.AreEqual(-1, m_DynamicArray.FindIndex(1, 2, (x) => x == 4)); } [Test] 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 8d9a96a6ae6..7dc8ad23e43 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Editor/NativePassCompilerRenderGraphTests.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/NativePassCompilerRenderGraphTests.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using UnityEngine.Experimental.Rendering; +using UnityEngine.Profiling; using UnityEngine.Rendering.RenderGraphModule; using UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler; @@ -9,6 +10,8 @@ namespace UnityEngine.Rendering.Tests { class NativePassCompilerRenderGraphTests { + static Recorder gcAllocRecorder = Recorder.Get("GC.Alloc"); + class RenderGraphTestPassData { public TextureHandle[] textures = new TextureHandle[8]; @@ -367,7 +370,7 @@ public void MergeWriteAllPassWithReadPass() Assert.AreEqual(RenderBufferLoadAction.Load, depthAttachment.loadAction); ref var extraAttachment = ref passes[0].attachments[1]; - Assert.AreEqual(RenderBufferLoadAction.DontCare, extraAttachment.loadAction); + Assert.AreEqual(RenderBufferLoadAction.DontCare, extraAttachment.loadAction); } [Test] @@ -1354,5 +1357,64 @@ public void DecreaseResourceVersionIfLastPassIsCulled() // extraBuffer version has decreased to 1 as it is only used by the first pass Assert.AreEqual(passes[0].attachments[0].handle.version, 1); } + + [Test] + public void GraphPassesDoesNotAlloc() + { + var g = AllocateRenderGraph(); + using (var builder = g.AddRasterRenderPass("TestPass0", out var passData)) + { + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(false); + } + using (var builder = g.AddRasterRenderPass("TestPass1_Culled", out var passData)) + { + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(true); + } + using (var builder = g.AddRasterRenderPass("TestPass2", out var passData)) + { + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + builder.AllowPassCulling(false); + } + + // First pass is preserved as requested but second pass is culled + var result = g.CompileNativeRenderGraph(g.ComputeGraphHash()); + var passes = result.contextData.GetNativePasses(); + + // Second pass has been culled + Assert.IsTrue(passes != null && passes.Count == 1 && passes[0].numGraphPasses == 2); + // Goes into possible alloc path + Assert.IsFalse(passes[0].lastGraphPass - passes[0].firstGraphPass + 1 == passes[0].numGraphPasses); + + + ValidateNoGCAllocs(() => + { + passes[0].GraphPasses(result.contextData); + }); + + // From RenderPassCullingTests.cs + void ValidateNoGCAllocs(Action action) + { + // Warmup - this will catch static c'tors etc. + CountGCAllocs(action); + + // Actual test. + var count = CountGCAllocs(action); + if (count != 0) + throw new AssertionException($"Expected 0 GC allocations but there were {count}"); + } + + int CountGCAllocs(Action action) + { + gcAllocRecorder.FilterToCurrentThread(); + gcAllocRecorder.enabled = true; + + action(); + + gcAllocRecorder.enabled = false; + return gcAllocRecorder.sampleBlockCount; + } + } } } diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/Unity.RenderPipelines.Core.Editor.Tests.asmdef b/Packages/com.unity.render-pipelines.core/Tests/Editor/Unity.RenderPipelines.Core.Editor.Tests.asmdef index cd34a7d1f6d..1d43eb285b9 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Editor/Unity.RenderPipelines.Core.Editor.Tests.asmdef +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/Unity.RenderPipelines.Core.Editor.Tests.asmdef @@ -9,7 +9,8 @@ "GUID:d8b63aba1907145bea998dd612889d6b", "GUID:4fd6538c1c56b409fb53fdf0183170ec", "GUID:e0cd26848372d4e5c891c569017e11f1", - "GUID:bf043f86dbf1bda4398ec83eebe40b8c" + "GUID:bf043f86dbf1bda4398ec83eebe40b8c", + "GUID:aa4a944c34c4c5449b84975fb1570dad" ], "includePlatforms": [ "Editor" @@ -26,4 +27,4 @@ ], "versionDefines": [], "noEngineReferences": false -} +} \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/Volumes/RenderPipelineTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/Volumes/RenderPipelineTests.cs index 02f7e8eb621..65a1988f560 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Editor/Volumes/RenderPipelineTests.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/Volumes/RenderPipelineTests.cs @@ -5,7 +5,7 @@ namespace UnityEditor.Rendering.Tests { - class RenderPipelineTests + internal class RenderPipelineTests { RenderPipelineAsset m_PreviousRenderPipelineAssetInGraphicsSettings; RenderPipelineAsset m_PreviousRenderPipelineAssetInQualitySettings; diff --git a/Packages/com.unity.render-pipelines.core/Tests/Runtime/AssemblyInfos.cs b/Packages/com.unity.render-pipelines.core/Tests/Runtime/AssemblyInfos.cs index 89789ef4a5e..d1f436bab46 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Runtime/AssemblyInfos.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Runtime/AssemblyInfos.cs @@ -1,3 +1,5 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Unity.RenderPipelines.Core.Editor.Tests")] +[assembly: InternalsVisibleTo("SRPSmoke.Runtime.Tests")] +[assembly: InternalsVisibleTo("SRPSmoke.Editor.Tests")] diff --git a/Packages/com.unity.render-pipelines.core/package.json b/Packages/com.unity.render-pipelines.core/package.json index 94cb2dbebe0..b2da79d5644 100644 --- a/Packages/com.unity.render-pipelines.core/package.json +++ b/Packages/com.unity.render-pipelines.core/package.json @@ -1,12 +1,12 @@ { "name": "com.unity.render-pipelines.core", "description": "SRP Core makes it easier to create or customize a Scriptable Render Pipeline (SRP). SRP Core contains reusable code, including boilerplate code for working with platform-specific graphics APIs, utility functions for common rendering operations, and shader libraries. The code in SRP Core is use by the High Definition Render Pipeline (HDRP) and Universal Render Pipeline (URP). If you are creating a custom SRP from scratch or customizing a prebuilt SRP, using SRP Core will save you time.", - "version": "17.0.3", - "unity": "6000.0", + "version": "17.2.0", + "unity": "6000.2", "displayName": "Core RP Library", "dependencies": { "com.unity.burst": "1.8.14", - "com.unity.mathematics": "1.3.2", + "com.unity.mathematics": "1.3.2", "com.unity.ugui": "2.0.0", "com.unity.collections": "2.4.3", "com.unity.modules.physics": "1.0.0", @@ -14,4 +14,4 @@ "com.unity.modules.jsonserialize": "1.0.0", "com.unity.rendering.light-transport": "1.0.1" } -} +} \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.high-definition-config/CHANGELOG.md b/Packages/com.unity.render-pipelines.high-definition-config/CHANGELOG.md index 5f061ba7a7c..192d2391b7c 100644 --- a/Packages/com.unity.render-pipelines.high-definition-config/CHANGELOG.md +++ b/Packages/com.unity.render-pipelines.high-definition-config/CHANGELOG.md @@ -10,6 +10,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. Version Updated The version number for this package has increased due to a version update of a related graphics package. +## [17.0.3] - 2025-02-13 + +This version is compatible with Unity 6000.2.0a17. + +Version Updated +The version number for this package has increased due to a version update of a related graphics package. + ## [17.0.2] - 2024-04-02 This version is compatible with Unity 6000.0.0b15. diff --git a/Packages/com.unity.render-pipelines.high-definition-config/package.json b/Packages/com.unity.render-pipelines.high-definition-config/package.json index a7d9c42a350..c4c32eefed7 100644 --- a/Packages/com.unity.render-pipelines.high-definition-config/package.json +++ b/Packages/com.unity.render-pipelines.high-definition-config/package.json @@ -1,10 +1,10 @@ { "name": "com.unity.render-pipelines.high-definition-config", "description": "Configuration files for the High Definition Render Pipeline.", - "version": "17.0.3", - "unity": "6000.0", + "version": "17.2.0", + "unity": "6000.2", "displayName": "High Definition RP Config", "dependencies": { - "com.unity.render-pipelines.core": "17.0.3" + "com.unity.render-pipelines.core": "17.2.0" } } \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.high-definition/CHANGELOG.md b/Packages/com.unity.render-pipelines.high-definition/CHANGELOG.md index 50c15881c72..35ab06a52c6 100644 --- a/Packages/com.unity.render-pipelines.high-definition/CHANGELOG.md +++ b/Packages/com.unity.render-pipelines.high-definition/CHANGELOG.md @@ -10,6 +10,172 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. Version Updated The version number for this package has increased due to a version update of a related graphics package. +## [17.0.3] - 2025-02-13 + +This version is compatible with Unity 6000.2.0a17. + +### Changed +- Rendering Debugger - Moved decals to the Rendering Section. +- Rendering Debugger - Moved lighting HDR settings to the Rendering Section. +- Wizard - Simplified the list of validations for IRenderPipelineGraphicsSettings. +- Improved the water sample by adding a cave scene using caustics and deformation texture. +- Improved Depth usage performance for some platforms. +- Added SG custom refraction example to Transparency sample. +- Added environment samples showcasing environment effects together. +- Optimised the water vertex shader. +- Improved decal region resolution on non-infinite surfaces. +- Reduced memory usage when foam is disabled. +- Improved the batching of the Lit shaders in HDRP. +- Allow using Solid Angle Culling Mode in Ray Tracing Settings volume override. This ray tracing culling mode rejects objects that are small enough or that are far away from the camera position based on their projected solid angle. These will not be added to the ray tracing acceleration structure. +- Added the option to compose hair before color pyramid but after clouds. +- Added a slider to High Quality Line Rendering Volume Component to specify when to omit depth and motion vector write if alpha is too low. +- Simplified the list of validations for `IRenderPipelineGraphicsSettings`. +- Improved water sample by adding a cave scene using caustics and deformation texture. + +### Fixed +- Fixed High Definition Render Pipeline's Wizard to no longer assume a check fail while waiting a reply from the Package Manager and will display a specific pending icon. +- Fixed an issue where the padding in the Lighting window was different between tabs. +- Fixed artifacts when blending cascade shadows and distance shadowmask. +- Fix Sensor SDK related compilation issue on DXR-enabled HDRP projects. +- Improved the error message when fog volumes on screen exceed the limit. Emit this error message only in editor and development builds. +- Fix a missing attenuation of the albedo when converting the decal albedo + metal into specular color. +- Rendering Debugger - Frame Settings - Adding 1 single panel for all cameras instead of having 1 panel per camera in the debugger. +- Fix underwater collider bounds check to be accurate when the collider is rotated +- Fixed rendering a black ground when opening a new HDRP scene. +- Fixed layer index out of range in LayeredLitGUI. +- Fixed advanced upsampler settings not visible on platforms where they are not supported. +- Fixed cloud layers not being drawn behind transparent refractive objects. +- Fixed HairVertex instancing-related shader-compilation issues. +- Ignore material variants with log message. +- Ensure custom post-processing effects are disabled when post-processing is disabled. +- Fixed black line artifacts on top of the screen with DRS and downsampled SSAO. +- Fixed wrong SSR when using a shader graph with a clear coat value of 0. +- Fixed Screen-Space Subsurface Scattering leaking from material with a subsurface mask set to 0. +- Fixed a bug that caused HDAdditionalLightData with preserveCachedShadow to be evicted from the cachedShadowManager. +- Fixed an issue where DebugDisplay Camera list grew beyond number of active cameras, every time a camera was registered or unregistered. +- Fixed a shader error when using water excluder with entities. +- Fixed an issue by adding clamp to HairAngleWorld to prevent nan from FastASin. +- Fixed an issue to avoid calling the Cleanup method twice so the celestial data remains. +- Fixed errors that would occur when building the XR player with Water System enabled. +- Removed the "Setting MRTs without a depth buffer is not supported" error in Volumetric Clouds Combine pass. +- Fixed visual artifacts when using the Graphics Compositor on the editor on MacOS. The issue occurred when changing the "Output Camera" and the "Clear Color" field was disabled. +- Fixed invalid global state pushed when using override camera rendering in the CustomPassUtils functions. +- Fixed shader warning in sub-surface scattering compute. +- Fixed color pyramid sampling when distortion is enabled after the distortion pass. +- Removed the FixAll button from the High Definition Render Pipeline (HDRP) Wizard when no automated fix is available. +- Added a condition to the Receiver Motion Rejection feature that checks whether a pixel has actually moved. +- Fixed an issue where High Definition Render Pipeline (HDRP) ambient scene lighting was leaking into the material preview window. +- Fixed an issue that prevented changing the Shadow Map resolution for `HDAdditionalLightData` when using `preserveCachedShadow`. +- Fixed an issue with High Definition Render Pipeline (HDRP) sky rendering when Camera Relative Rendering is disabled. + + +- Fixed visual artifacts that occurred when blending cascade shadows and distance shadow masks. +- Updated the High Definition Render Pipeline (HDRP) Wizard to no longer assume a check failure while awaiting a reply from the Package Manager. The Wizard now displays a specific pending icon during this process. +- Fixed an issue where the padding in the Lighting window was different between tabs. +- Fixed a Sensor SDK compilation issue in DXR-enabled HDRP projects. +- Fixed an issue where underwater collider bounds checks were inaccurate when the collider was rotated. +- Added framesettings to render volumetric clouds in half resolution to reduce jittering. +- Fixed invalid AABB errors for some projects. +- Fixed an issuse with viewport flickering when multi-frame rendering API is used with certain parameters. +- Optimized water foam reprojection when it's unused. +- Fixed `materialValidatorDebugModeEnumIndex` so that it does not get stuck in the Rendering Debugger when enabling another mode. +- Fixed a corruption issue when using a non square atlas and improve blit performance. +- Improved the Rendering Debugger to allow changing the mat cap values. +- Added a shortcut to modify the Advanced properties within the Water System Inspector: +- Fixed inconsistent text capitalizations in various parts of the Editor. +- Fixed reflection probe baking exception when fog multiple scattering is enabled in certain conditions. +- Fixed a potentially deadlocking StageRasterBin kernel in Hair system. +- Fixed Alpha missing from HQ line rendering. +- Fixed an icons used by the HDRP wizard issue. +- Fixed shader warnings from TAA shader on Metal. +- Fixed format error in public documentation. +- Fixed an issue where the default terrain shader for HDRP was outputting incorrect albedo values to the lightmapper. +- Fixed missing API to sync clouds over network. +- Fixed issue when directional light dimmer is set to 0. +- Fixed eye dropper not showing on the PBR sky inspector. +- XRMultipass - RenderPipelineManager.beginCameraRendering and RenderPipelineManager.endCameraRendering was called 1 time for each pass instead of 1 time for each camera. +- Fixed static lighting sky used when baking multiple scenes. +- Fixed artefacts on borders between volumetric clouds and geometry. +- Fixed perceptual blending option on volumetric clouds. +- Fixed graphical issue when resizing Reflection Probe sizes on macOS. +- Fixed an issue where Terrains with 4 layers or less displayed a checker texture when using debug views. +- Fixed volumetric fog samples broken link. +- Fixed material samples broken link. +- Fixed a crash when creating renderers in a Custom Pass (HDRP). +- Fixed volumetric fog reprojection buffers allocated even if the denoising mode is not set to Reprojection. +- Fixed world space UI not outputting motion vectors. +- Fixed an out of range exception in HDRP when reaching the max amount of shadows on screen. +- Fixed a crash in HDRP when reaching the max amount of shadows on screen. +- Fixed lens flare screen space and bloom frame settings confusion. +- Fixed range remap for decal materials. +- Fixed water mask applied before deformation. +- Fixed error when drawing water excluder gizmo. +- Cull water decals based on distance to camera. +- Fixed water decals not affecting simulation mask. +- Fixed foam and deformation using separate regions. +- Fixed deformation offset when water surface is rotated. +- Fixed water decal gizmo when scale is non uniform. +- Fixed decals not updated in atlas when ShaderGraph is saved. +- Changed `ProbeSettings.cubeResolution` field from internal to public. +- Fixed time of day script in environement sample. +- Fixed light culling for raytracing. +- Fixed a disc area light calculation used for light unit conversion, which was previously incorrect by a factor of Pi. +- Fixed clouds rendering on top of geometry. +- Fixed clouds interaction with thin geometry. +- Allowed TAAU, CAS, and STP to execute after the DoF or after all the post-processes like the other advanced upsamplers. +- Fixed broken link in fullscreen samples. +- Fixed missing UNITY_MATRIX_IT_MV define in HDRP shaders. +- Fixed an issue where UI images using render textures would not render properly with HDR enabled. +- Fixed an issue where reimporting ShaderGraph trigged a UnityVCS/Perfoce local checkout. +- Fixed SSMS slider not showing when volumetric fog was disabled. +- Fixed offscreen UI rendering when HDR is enabled. +- Set the 'Maximum Shadows on Screen' limit to 65536 in order not to exceed the maximum size of the buffer. +- Fixed an issue that caused the Disable Color Tint setting in a shader graph to have no effect. +- Fixed TAA Contrast Adaptive Sharpening when no upsampling was enabled. +- Fixed an issue with EndCameraRendering being called before renderContext submission. +- Fixed depth issues that occurred during transparent object rendering when dynamic scaling was used with fractional values. +- Fixed an issue to push the correct cascade shadow matrix for each cascade. +- Fixed an issue so light intensity now correctly increases when 'Lux at Distance' increases and vice versa. +- Fixed depth of field blocky artifacts when using a high blur radius. +- Fixed some depth of field jittering with objects in the near field and TAA enabled. +- PBR depth of field now has a bokeh shape that corresponds better to the aperture settings of the camera. +- Fixed an issue where alpha clamping to BloomPrefilter.compute was missing. +- Fixed volumetric cloud clipping through geometry. +- Fixed an issue where HDProbes created depth resources that were never used, leading to unnecessary GPU memory usage. +- Fixed an issue where HDRP CustomPass created an unnecessary color resource, leading to unnecessary GPU memory usage. +- Fixed a sun flicker where the sun is close to cloud boundaries. +- Fixed an issue where cascade shadows and distance shadowmask were not blended properly. +- Updated HDRP to use the new TextureDesc field format instead of colorFormat and depthBufferBits to avoid a performance regression and subtle issues. +- Fixed distortion in Unlit Shader Graph. +- Fixed the artifact of non-physical DOF if it's used with TAA and dynamic resolution; The artifacts appear for a frame after the screen resolution changes. +- Fixed UI overflow and stencil based effects not working in HDRP. +- Fixed uninitalized/unused shader warnings. +- Fixed `WorldLightManager.Collect` so it no longer has poor performance when a large amount of GameObjects are present in the scene. +- Fixed an issue that would cause volumetric shadow clipping issues in some camera angles. +- Fixed the option to edit advanced upsampling that aren't visible on platforms when they're not supported. +- Ensure custom post-processing effects are disabled when post-processing is disabled. +- Ignore material variants with log message. +- Fixed HairVertex instancing-related shader-compilation issues. +- Fixed cloud layers not being drawn behind transparent refractive objects. +- Fixed an issue that caused HDAdditionalLightData with preserveCachedShadow to be evicted from the cachedShadowManager. +- Fixed an issue with shader error when using water excluder with entities. +- Fixed to avoid calling the Cleanup method twice so the celestial data remains. +- Fixed errors when building XR player with Water System enabled. +- Removed 'Setting MRTs without a depth buffer is not supported' error in Volumetric Clouds Combine pass. +- Fixed an issue by adding clamp to HairAngleWorld to prevent nan from FastASin. +- Fixed layer index out of range in LayeredLitGUI. +- Fixed HDRP wizard to not show FixAll button anymore when no automated fix is available. +- Fixes the bug where DebugDisplay Camera list grew beyond number of active cameras, every time a camera was registered or unregistered. +- Fixed black line artifacts on top of the screen with DRS and downsampled SSAO +- Fixed invalid global state pushed when using override camera rendering in the CustomPassUtils functions. +- Fixed an issue that caused an inability to change the Shadow Map resolution for HDAdditionalLightData with preserveCachedShadow. +- Fixed HDRP sky rendering when Camera Relative Rendering is disabled. +- High Definition Render Pipeline's Wizard will no longer assume a check fail while waiting a reply from the Package Manager and will display a specific pending icon. +- Fixed wrong SSR when using a shader graph with a clear coat value of 0. +- Fixed artifacts when blending cascade shadows and distance shadowmask. +- Fixed an issue by adding a condition to the Receiver Motion Rejection function(feature) to check that the pixel has actually moved. +- Fixed an issue where the padding in the Lighting window was different between tabs. + ## [17.0.2] - 2024-04-02 This version is compatible with Unity 6000.0.0b15. diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/caustics-simulation-bands.jpg b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/caustics-simulation-bands.jpg new file mode 100644 index 00000000000..4bbfbf0ca6e Binary files /dev/null and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/caustics-simulation-bands.jpg differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/caustics.jpg b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/caustics.jpg new file mode 100644 index 00000000000..f648c821896 Binary files /dev/null and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/caustics.jpg differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Ray-Tracing-Getting-Started.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Ray-Tracing-Getting-Started.md index 6b8bae70c4d..ce88fca281c 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Ray-Tracing-Getting-Started.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Ray-Tracing-Getting-Started.md @@ -211,6 +211,7 @@ HDRP ray tracing in Unity isn't compatible with the following features: - Fully accurate shadow culling. You might see missing shadows in ray-traced effects. You can use **Extend Shadow Culling** to improve accuracy. See [Ray Tracing Settings](Ray-Tracing-Settings.md) for more information. - Data-Oriented Technology Stack (DOTS) - Entity Component System (ECS) +- Water #### Reflection Probes 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 8323f1d2ab4..68421eedb6c 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/TableOfContents.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/TableOfContents.md @@ -211,25 +211,24 @@ * [Configure swell, agitation, or ripples](add-swell-agitation-or-ripples.md) * [Simulating currents with water decals](simulating-currents-with-water-decals.md) * [Simulating ripples with masks](simulating-foam-or-ripples-with-masks.md) + * [Check waves and ripples](add-caustics-and-foam-and-check-waves-and-ripples.md) + * [Float objects on a water surface](float-objects-on-a-water-surface.md) + * [Align objects to the water surface using normals](align-objects-to-water-surface-using-normals.md) * [Decals and masking in the water system](water-decals-and-masking-in-the-water-system.md) * [Foam in the Water System](water-foam-in-the-water-system.md) * [Introduction to foam](introduction-to-foam.md) * [Create wind-driven foam on the whole water surface](create-wind-driven-foam-on-the-whole-water-surface.md) * [Create local foam in the wake of a GameObject](create-local-foam-in-the-wake-of-a-gameobject.md) * [Add foam with a script](add-foam-with-script.md) - * [Caustics in the Water System](water-caustics-in-the-water-system.md) + * [Customize caustics in the water system](water-caustics-in-the-water-system.md) * [Create a current in the Water System](water-create-a-current-in-the-water-system.md) * [Deform a water surface](water-deform-a-water-surface.md) * [Exclude part of a water surface](water-exclude-part-of-the-water-surface.md) * [Underwater view](water-underwater-view.md) * [Materials in the Water System](water-materials-in-the-water-system.md) - * [Scripting in the Water System](water-scripting-in-the-water-system.md) - * [Float objects on a water surface](float-objects-on-a-water-surface.md) - * [Align objects to the water surface using normals](align-objects-to-water-surface-using-normals.md) - * [Add caustics](add-caustics-and-foam-and-check-waves-and-ripples.md) - * [Synchronize water surfaces](synchronize-water-surfaces.md) + * [Synchronize multiple water surfaces](synchronize-water-surfaces.md) * [Debug in the Water System](water-debug-mode.md) - * [Environment limitations](Environment-Limitations.md) + * [Interaction between the water system and the VFX Graph](water-vfx-interaction.md) * [Camera and scene composition](camera-and-scene-composition.md) * [Graphics Compositor](graphics-compositor.md) * [Understand the Graphics Compositor](understand-the-graphics-compositor.md) diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/add-caustics-and-foam-and-check-waves-and-ripples.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/add-caustics-and-foam-and-check-waves-and-ripples.md index 7c5ba60a2fe..7e8e2fbc0ae 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/add-caustics-and-foam-and-check-waves-and-ripples.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/add-caustics-and-foam-and-check-waves-and-ripples.md @@ -1,49 +1,8 @@ -# Add caustics and check waves and ripples +# Check waves and ripples -To add caustics or get information about water surface displacement due to waves and ripples, get buffers from the [`WaterSurface`](xref:UnityEngine.Rendering.HighDefinition.WaterSurface) class: +To get information about water surface displacement due to waves and ripples, use the [GetDeformationBuffer](../api/UnityEngine.Rendering.HighDefinition.WaterSurface.html#UnityEngine_Rendering_HighDefinition_WaterSurface_GetDeformationBuffer) API. -| Action | API | -|-----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Add caustics | [GetCausticsBuffer](../api/UnityEngine.Rendering.HighDefinition.WaterSurface.html#UnityEngine_Rendering_HighDefinition_WaterSurface_GetCausticsBuffer_System_Single__) | -| Check waves and ripples | [GetDeformationBuffer](../api/UnityEngine.Rendering.HighDefinition.WaterSurface.html#UnityEngine_Rendering_HighDefinition_WaterSurface_GetDeformationBuffer) | - -## Example: Add caustics - -``` -using UnityEngine; -using UnityEngine.Rendering.HighDefinition; - -public class WaterCausticsExample : MonoBehaviour -{ - // Reference to the water surface component - public WaterSurface waterSurface; - - // Size of the region on the water surface from which the caustics effect is calculated - public float regionSize = 1.0f; - - // Material to apply the caustics effect - public Material waterMaterial; - - void Start() - { - // Get the caustics buffer for the specified region size on the water surface - Texture causticsBuffer = waterSurface.GetCausticsBuffer(out regionSize); - - if (causticsBuffer != null) - { - // Apply the caustics buffer as a texture to the water material - waterMaterial.SetTexture("_CausticsTex", causticsBuffer); - Debug.Log("Caustics buffer applied successfully."); - } - else - { - Debug.LogWarning("Caustics buffer could not be retrieved."); - } - } -} -``` - -## Example: Check waves and ripples +## Example ``` using UnityEngine; diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/fragment-context-reference.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/fragment-context-reference.md index d29dc48bbb7..ee993a467fe 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/fragment-context-reference.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/fragment-context-reference.md @@ -49,7 +49,7 @@ This section lists the Blocks that are compatible with Fragment Contexts in the [!include[](snippets/shader-graph-blocks/haze-extent.md)] [!include[](snippets/shader-graph-blocks/haziness.md)] [!include[](snippets/shader-graph-blocks/hazy-gloss-max-dielectric-f0.md)] -[!include[](snippets/shader-graph-blocks/ior.md)] +[!include[](snippets/shader-graph-blocks/eye-ior.md)] [!include[](snippets/shader-graph-blocks/iridescence-coat-fixup-tir.md)] [!include[](snippets/shader-graph-blocks/iridescence-coat-fixup-tir-clamp.md)] [!include[](snippets/shader-graph-blocks/iridescence-mask.md)] diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/path-tracing-limitations.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/path-tracing-limitations.md index cc773124a4f..17b6a069939 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/path-tracing-limitations.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/path-tracing-limitations.md @@ -24,6 +24,7 @@ HDRP path tracing in Unity currently has the following limitations: - MSAA. - [Graphics.DrawMesh](https://docs.unity3d.com/ScriptReference/Graphics.DrawMesh.html) or [Graphics.RenderMesh](https://docs.unity3d.com/2022.1/Documentation/ScriptReference/Graphics.RenderMesh.html), because rasterization and ray tracing are different ways of generating an image. - [Streaming Virtual Texturing](https://docs.unity3d.com/Documentation/Manual/svt-streaming-virtual-texturing.html). + - Vertex animation, for example wind deformation of vegetation. ### Unsupported shader graph nodes for path tracing diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/probevolumes-override-backend.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/probevolumes-override-backend.md index 32eaea39ca1..5327e2fcbf6 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/probevolumes-override-backend.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/probevolumes-override-backend.md @@ -29,7 +29,7 @@ To override the default Virtual Offset data baker: The default sky occlusion data baker computes the amount of lighting that comes from the sky in every direction as a spherical harmonic. It also optionally computes the direction from which APV should sample the sky lighting at runtime for every probe. -To override the default Virtual Offset data baker: +To override the default sky occlusion data: 1. Create a class that inherits from [SkyOcclusionBaker](https://docs.unity3d.com/Packages/com.unity.render-pipelines.core@17.0/api/UnityEngine.Rendering.AdaptiveProbeVolumes.SkyOcclusionBaker.html) class. In the HDRP Graphics repo, refer to [ProbeGIBaking.SkyOcclusion.cs](https://github.com/Unity-Technologies/Graphics/blob/master/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.SkyOcclusion.cs#L116) for reference implementation. 2. Use [SetSkyOcclusionBakerOverride](https://docs.unity3d.com/Packages/com.unity.render-pipelines.core@17.0/api/UnityEngine.Rendering.AdaptiveProbeVolumes.html#UnityEngine_Rendering_AdaptiveProbeVolumes_SetSkyOcclusionBakerOverride_UnityEngine_Rendering_AdaptiveProbeVolumes_SkyOcclusionBaker_) and set your new `SkyOcclusionBaker` class as the parameter. diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/rendering-debugger-window-reference.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/rendering-debugger-window-reference.md index 7cd61d6725d..0b3bb1b5be1 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/rendering-debugger-window-reference.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/rendering-debugger-window-reference.md @@ -648,12 +648,15 @@ The **Color monitors** are a set of industry-standard monitors to help artists c | **Size** | The size ratio of the color monitors. | | **Property** | **Description** | -| ----------------- | ------------------------------------------------------------ | -| **Clear Render Targets at creation** | Enable the checkbox to make the Render Graph system clear render targets the first time it uses them | -| **Disable Pass Culling** | Enable the checkbox to render passes which have no impact on the final render. | -| **Immediate Mode** | Enable the checkbox to make the Render Graph system evaluate passes immediately after it creates them. | -| **Log Frame Information** | Press the button to log in the Console informations about the passes rendered during a frame. | -| **Log Resources** | Press the button to log in the Console the list of resources used when rendering a frame. | +| --- | --- | +| **Clear Render Targets At Creation** | Clears render textures the first time the render graph system uses them. | +| **Clear Render Targets When Freed** | Clears render textures when they're no longer used by render graph. | +| **Disable Pass Culling** | Disables HDRP culling render passes that have no impact on the final render. | +| **Disable Pass Merging** | Disables HDRP merging render passes. | +| **Immediate Mode** | Enables the render graph system evaluating passes immediately after it creates them. | +| **Enable Logging** | Enables logging to the **Console** window. | +| **Log Frame Information** | Logs how HDRP uses the resources during the frame, in the **Console** window. | +| **Log Resources** | Logs the resources HDRP uses during the frame, in the **Console** window. | The **NVIDIA device debug view** is a panel that displays a list of the current feature states of NVIDIA Deep Learning Super Sampling (DLSS). Each row represents an active screen in which DLSS is running. diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/settings-and-properties-related-to-the-water-system.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/settings-and-properties-related-to-the-water-system.md index 24fd2f5e78c..f452ff2a24b 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/settings-and-properties-related-to-the-water-system.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/settings-and-properties-related-to-the-water-system.md @@ -91,7 +91,7 @@ The options are: Script Interactions -Enable to have the ability to query the water surface position and current direction from the simulation. Refer to Scripting in the water system for more information. +Enable to have the ability to query the water surface position and current direction from the simulation. diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/simulating-currents-with-water-decals.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/simulating-currents-with-water-decals.md index 058ba4944cb..8c860962b1a 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/simulating-currents-with-water-decals.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/simulating-currents-with-water-decals.md @@ -40,7 +40,7 @@ To enable horizontal deformation, go to the active [HDRP Asset](hdrp-asset.md), Enabling horizontal deformation has the following effects: - HDRP creates a new buffer, which increases the amount of memory HDRP uses. -- The results of [water scripts](water-scripting-in-the-water-system.md) and [underwater effects](water-underwater-view.md) might be less accurate. +- The results of water scripts and [underwater effects](water-underwater-view.md) might be less accurate. ## Additional resources diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/synchronize-water-surfaces.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/synchronize-water-surfaces.md index efed0df3f62..724f7f6494e 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/synchronize-water-surfaces.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/synchronize-water-surfaces.md @@ -1,4 +1,4 @@ -# Synchronize water surfaces +# Synchronize multiple water surfaces If you use multiple water surfaces, you can synchronize the water simulation of each surface. For example, if you need to make sure the water surface is the same for all the players in a multiplayer game. diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-capabilities-of-the-water-system.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-capabilities-of-the-water-system.md index a3f6172ba83..050b81887bb 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-capabilities-of-the-water-system.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-capabilities-of-the-water-system.md @@ -28,7 +28,7 @@ For more in-depth water Material customizations, you can use [the water ShaderGr ## Masking You can assign custom masks to attenuate or supress ripples, swells, and foam on specific portions of a water surface. You can also use them to adjust decal and light layers. ## Scripting -It is possible to create [scripts that interact with the water system](water-scripting-in-the-water-system.md), to imitate buoyancy, for example. +You can create scripts that interact with the water system, for example, to imitate buoyancy. ## Limitations and caveats The water system does not currently support: @@ -66,4 +66,3 @@ Also, **Affect Base Color** only produces monochromatic output. # Additional resources * [Settings and properties related to the water system](settings-and-properties-related-to-the-water-system.md) -* [Scripting in the water system](water-scripting-in-the-water-system.md) diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-caustics-in-the-water-system.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-caustics-in-the-water-system.md index 67099ecae34..e379a323308 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-caustics-in-the-water-system.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-caustics-in-the-water-system.md @@ -1,23 +1,63 @@ -# Caustics in the water system -Caustics are a consequence of light rays refracted or reflected by a curved surface and projected onto another object. +# Customize caustics in the water system -## Opacity -Water that is opaque or partially opaque due to particulates does not refract light as much as clear water. This is because water full of mud (for example) absorbs more light than it refracts. In the context of HDRP, this means that water with a lower **Absorption Distance** value has caustics that are less visible. +![](Images/caustics.jpg) -## Wave size -HDRP uses the **Ripples** **Simulation Band** for **Caustics** calculations by default if the **Ripples** band is active. If you wish to base caustics on larger waves in a **River** or **Ocean, Sea, or Lake** water surface, you need to adjust the **Simulation Band** setting. It may also be necessary to adjust the **Virtual Plane Distance** to ensure a plausible result. To prevent aliasing artifacts, you can increase the **Caustics Resolution**. +Customize the appearance of caustics, which are bright light patterns on GameObjects caused by the curved water surface reflecting and refracting light. -## Limitations -In the current water implementation, caustics do not have an effect above the water unless you script this behavior. For example, if you have a boat sitting in the water, HDRP does not project caustics on the part of its hull that is not submerged, and a swimming pool inside of a room does not bounce caustics off the walls or ceiling. -You can manually implement this effect by creating a **Decal Projector** in the following way: -```cs -this.GetComponent().material.SetTexture("_Base_Color", waterSurface.GetFoamBuffer(out Vector2 _)); +## Create caustics from larger waves + +By default, the High Definition Render Pipeline (HDRP) uses the ripples [simulation band](water-water-system-simulation.md#simulation-bands) to calculate caustics. + +To calculate caustics from larger waves in a river, ocean, sea, or lake, follow these steps: + +1. Select the water surface GameObject. +2. In the **Inspector** window, go to **Appearance**. In the **Caustics** section, set the **Simulation Band** to a different band. +3. Increase **Virtual Plane Distance** until you get the desired result. + +To prevent aliasing artifacts, set **Caustics Resolution** to a higher value. + +![](Images/caustics-simulation-bands.jpg)
+On the left, caustics with the simulation band set to **Ripples**. On the right, caustics with the simulation band set to **Swell First Band**. + +## Add caustics above water + +To add caustics to GameObjects above water, for example the parts of a boat that sit above the water surface, follow these steps: + +1. Create a [Decal Projector](understand-decals.md#decal-projector). +2. Add a script to the Decal Projector that uses the `GetCausticsBuffer` API to get the caustics texture from the water surface, and apply the texture as the Decal Projector texture. + +For example: + +```c# +using UnityEngine; +using UnityEngine.Rendering.HighDefinition; + +public class ProjectCaustics : MonoBehaviour +{ + public WaterSurface waterSurface; + + void Update() + { + this.GetComponent().material.SetTexture("_Base_Color", waterSurface.GetCausticsBuffer(out float regionSize)); + } +} ``` -Caustics have the following limitations with transparents GameObjects: -* When the camera is above a water surface, HDRP computes caustics using the position of any opaque object behind a transparent. +Caustics have the following limitations with transparent GameObjects: + +* When the camera is above a water surface, HDRP calculates caustics using the position of any opaque GameObject behind a transparent GameObject. * HDRP doesn't apply caustics to transparent GameObjects when the camera is underwater. -* Caustics do not react to current maps and simulation masks. +* Caustics don't react to current maps and water masks. + +## Make caustics less visible + +You can reduce the absorption distance of the water surface. When water has a lower absorption distance, it's muddier and refracts less light, which makes caustics less visible. + +To make caustics less visible, follow these steps: + +1. Select the water surface GameObject. +2. In the **Inspector** window, in the **Refraction** section, decrease **Absorption Distance**. ## Additional resources -* Settings and properties related to the water system + +- [Settings and properties related to the water system](settings-and-properties-related-to-the-water-system.md) diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-create-a-current-in-the-water-system.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-create-a-current-in-the-water-system.md index 20bb6a6f6be..1d60a0c4b37 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-create-a-current-in-the-water-system.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-create-a-current-in-the-water-system.md @@ -33,34 +33,6 @@ The following images display each channel of the current map included in the Riv * The green channel of a current map: ![](Images/watersystem-curent-g.png) * The blue channel of a current map: ![](Images/watersystem-curent-b.png) -## Create a current map texture in Krita - -> **Attention**: The following concerns a product or service (each a “Third Party Product”) that is not developed, owned, or operated by Unity. This information may not be up-to-date or complete, and is provided to you for your information and convenience only. Your access and use of any Third Party Product is governed solely by the terms and conditions of such Third Party Product. Unity makes no express or implied representations or warranties regarding such Third Party Products, and will not be responsible or liable, directly or indirectly, for any actual or alleged damage or loss arising from your use thereof (including damage or loss arising from any content, advertising, products or other materials on or available from the provider of any Third Party Products). - -The image-editing software Krita includes a brush type you can modify to author a current map: - -1. Open the Brush Editor. - -2. Select the arrow icon to open the **Presets** panel. - -3. In **Engine**, select **Tangent Normal**. - -4. Select the **Texture Normal Map preset** brush**.** - -5. In the **General** section, select **Tangent Tilt.** - -6. Set the **Tangent Encoding** properties to the following**:** - -7. 1. **Red**: **-X** - 2. **Green**: **-Y** - 3. **Blue**: **-Z** - -8. In **Tilt Options**, select **Direction**. - -9. Select **Save New Brush Preset.** - -This changes the color of the brush depending on the direction you draw in, allowing you to paint a current map. - ## Apply a current Map to a water surface To set the current map a water surface uses: @@ -77,7 +49,7 @@ Current maps behave in a different way depending on the type of water surface: ## Make an object follow a current map -When using [Script Interactions](water-scripting-in-the-water-system.md) to make an object float on the surface, you can get the current at the resulting location to make the object move with the flow of the water. +If you use a script to [float an object on the water surface](float-objects-on-a-water-surface.md), you can get the current at the resulting location to make the object move with the flow of the water. The [River sample scene](#river-sample-scene) includes a script that extends the Float script to make objects float along the current map. diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-decals-masking-landing.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-decals-masking-landing.md index 9892a8f17a8..7a6f35ba48a 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-decals-masking-landing.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-decals-masking-landing.md @@ -8,7 +8,10 @@ You can also add detailed visual effects to localized water areas with water dec | **Page** | **Description** | |---------------------------------------------------------------------------------------|-----------------------------------------------------------------------------| -| **[Enable mask and water decals](enable-mask-and-water-decals.md)** | Mask and current water decals are disabled by default. | -| **[Configure swell, agitation, or ripples with a water mask](add-swell-agitation-or-ripples.md)** | Configure swell, agitation, or ripples across the water surface. | -| **[Simulate currents with a water decal](simulating-currents-with-water-decals.md)** | Simulate water currents by projecting textures. | -| **[Simulate ripples with masks](simulating-foam-or-ripples-with-masks.md)** | Create effects like ripples. | +| [Enable mask and water decals](enable-mask-and-water-decals.md) | Mask and current water decals are disabled by default. | +| [Configure swell, agitation, or ripples with a water mask](add-swell-agitation-or-ripples.md) | Configure swell, agitation, or ripples across the water surface. | +| [Simulate currents with a water decal](simulating-currents-with-water-decals.md) | Simulate water currents by projecting textures. | +| [Simulate ripples with masks](simulating-foam-or-ripples-with-masks.md) | Create effects like ripples. | +| [Check waves and ripples](add-caustics-and-foam-and-check-waves-and-ripples.md) | Check or retrieve information about the displacement of the water surface. | +| [Float objects on a water surface](float-objects-on-a-water-surface.md) | Add buoyancy to the water simulation. | +| [Align objects to the water surface using normals](align-objects-to-water-surface-using-normals.md) | Make objects follow the curvature of the water in real time. | diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-scripting-in-the-water-system.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-scripting-in-the-water-system.md deleted file mode 100644 index c9c250d1f1e..00000000000 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-scripting-in-the-water-system.md +++ /dev/null @@ -1,12 +0,0 @@ -# Scripting in the water system - -You can make boats, floating debris, or other objects match the curvature of the water dynamically. - -To align objects correctly with the water surface you can retrieve the normal of the surface at a given point. You can thus ensure objects move or rotate appropriately relative to the surface's real-time changes. - -| **Page** | **Description** | -|----------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------| -| [Float objects on a water surface](float-objects-on-a-water-surface.md) | Add buoyancy to the water simulation. | -| [Align objects to the water surface using normals](align-objects-to-water-surface-using-normals.md) | Make objects follow the curvature of the water in real time. | -| [Add caustics and check waves and ripples](add-caustics-and-foam-and-check-waves-and-ripples.md) | Incorporate caustics and check or retrieve information about the displacement of the water surface. | -| [Synchronize water surfaces](synchronize-water-surfaces.md) | Synchronize water simulation across all clients in a multiplayer game. | diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-water-system-simulation.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-water-system-simulation.md index 3c0e0428fc7..a710932fc66 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-water-system-simulation.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-water-system-simulation.md @@ -91,7 +91,7 @@ To break up overly regular patterns of waves, you can increase the **Chaos** val The Volume Override uses the terms Patch and Grid. The Patch is the size of the area on which Unity runs the simulation for a particular Simulation Band. The Grid is the geometry Unity uses to render the water, which is always a rectangle. ## Scripting with the water simulation -You can query a water surface for position and current direction which you can use in scripts, for example to create a customized buoyancy effect that makes it possible to float a ball on the waves (for example). See [Scripting in the water system](water-scripting-in-the-water-system.md) for more information. +You can query a water surface for position and current direction which you can use in scripts, for example to create a customized buoyancy effect that makes it possible to float a ball on the waves (for example). The [River sample scene](#river-sample-scene) includes a script that extends the Float script to make objects float along the current map. ## Additional resources diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/water.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/water.md index 9980f9777cf..990275855b5 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/water.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/water.md @@ -9,13 +9,15 @@ Create water in the High Definition Render Pipeline (HDRP). | [Water system simulation](water-water-system-simulation.md) | How the water system simulation works. | | [Quality and performance decisions](water-quality-and-performance-decisions.md) | How to make quality decisions and optimize performance. | | [Water Override for Volumes](water-the-water-system-volume-override.md) | Purpose of the water Volume Override. | +| [Water surface fluctuations](water-decals-masking-landing.md) | Resources on applying effects like swell, agitation, and deformation across the water surface. | | [Decals and masking in the water system](water-decals-and-masking-in-the-water-system.md) | How decals and masks work in the water system. | | [Foam in the water system](water-foam-in-the-water-system.md) | Control how much foam appears on your water surface. | -| [Caustics in the water system](water-caustics-in-the-water-system.md) | What caustics are, how to adjust them, and their limitations. | +| [Customize caustics in the water system](water-caustics-in-the-water-system.md) | Customize the appearance of the bright light patterns caused by the curved water surface reflecting and refracting light. | | [Create a current in the water system](water-create-a-current-in-the-water-system.md) | Apply a current map to a water surface. | | [Deform a water surface](water-deform-a-water-surface.md) | Use a deformer to control the shape of a water surface | | [Exclude part of a water surface](water-exclude-part-of-the-water-surface.md) | Prevent water from appearing on top of other surfaces. | | [Underwater view](water-underwater-view.md) | Learn more about the underwater view of the water surface simulation. | | [Materials in the water system](water-materials-in-the-water-system.md) | The effects of water Material properties. | -| [Scripting in the water system](water-scripting-in-the-water-system.md) | How to write scripts that interact with the water system. | +| [Synchronize water surfaces](synchronize-water-surfaces.md) | Synchronize water simulation across all clients in a multiplayer game. | +| [Debug modes in the water system](water-debug-mode.md) | To place masks, deformation, and foam correctly, use the debug modes in the water system. | | [VFX Graph in the water system](water-vfx-interaction.md) | How to make VFX Graph interact with the water system. | diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Water/ShaderGraph/WaterSubTarget.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Water/ShaderGraph/WaterSubTarget.cs index fb38cedf2f2..860def892bd 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Water/ShaderGraph/WaterSubTarget.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Water/ShaderGraph/WaterSubTarget.cs @@ -461,8 +461,8 @@ PassCollection GetWaterPasses() GenerateWaterGBufferPass(false, true, systemData.debugSymbols), // Low res gbuffer GenerateWaterGBufferPass(true, false, systemData.debugSymbols), - // Debug pass, always use tessellation to reduce variants - GenerateWaterDebugPass(false, true, systemData.debugSymbols), + // Debug pass, never use tessellation to reduce variants + GenerateWaterDebugPass(false, false, systemData.debugSymbols), GenerateWaterDebugPass(true, false, systemData.debugSymbols), }; return passes; diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs index 3a5fbca892f..49bc23ec9ea 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs @@ -1774,11 +1774,13 @@ void RegisterRenderingDebug() widgetList.Add(new DebugUI.RuntimeDebugShadersMessageBox()); + string url = DocumentationInfo.GetPackageLink(Documentation.packageName, Documentation.version, "rendering-debugger-window-reference", "rendering-panel"); var renderingSettings = new DebugUI.Foldout { nameAndTooltip = RenderingStrings.RenderingSettings, opened = true, // By default this general section is opened - order = int.MinValue + order = int.MinValue, + documentationUrl = url, }; widgetList.Add(renderingSettings); @@ -2140,7 +2142,7 @@ void RegisterRenderingDebug() #endif m_DebugRenderingItems = widgetList.ToArray(); - var panel = DebugManager.instance.GetPanel(k_PanelRendering, true); + var panel = DebugManager.instance.GetPanel(k_PanelRendering,true); panel.children.Add(m_DebugRenderingItems); } @@ -2235,39 +2237,6 @@ void FillMipmapDebugMaterialTextureSlotArrays(ref GUIContent[] strings, ref int[ } } - internal static void RegisterCamera(IFrameSettingsHistoryContainer container) - { - string name = container.panelName; - if (s_CameraNames.FindIndex(x => x.text.Equals(name)) < 0) - { - s_CameraNames.Add(new GUIContent(name)); - needsRefreshingCameraFreezeList = true; - } - - if (!FrameSettingsHistory.IsRegistered(container)) - { - var history = FrameSettingsHistory.RegisterDebug(container); - DebugManager.instance.RegisterData(history); - } - } - - internal static void UnRegisterCamera(IFrameSettingsHistoryContainer container) - { - string name = container.panelName; - int indexOfCamera = s_CameraNames.FindIndex(x => x.text.Equals(name)); - if (indexOfCamera > 0) - { - s_CameraNames.RemoveAt(indexOfCamera); - needsRefreshingCameraFreezeList = true; - } - - if (FrameSettingsHistory.IsRegistered(container)) - { - DebugManager.instance.UnregisterData(container); - FrameSettingsHistory.UnRegisterDebug(container); - } - } - internal bool IsDebugDisplayRemovePostprocess() { return data.materialDebugSettings.IsDebugDisplayEnabled() || data.lightingDebugSettings.IsDebugDisplayRemovePostprocess() || data.mipMapDebugSettings.IsDebugDisplayEnabled(); 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 new file mode 100644 index 00000000000..46509f724a9 --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsCamera.cs @@ -0,0 +1,213 @@ +using System; +using System.Collections.Generic; +using UnityEngine.Rendering.HighDefinition; +using static UnityEngine.Rendering.DebugUI; + +namespace UnityEngine.Rendering +{ + 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 Dictionary registeredCameras = new (); + } + + public FrameSettingsDebugData frameSettingsData { get; } + + public bool IsCameraRegistered(Camera camera) => frameSettingsData.registeredCameras.ContainsKey(camera); + + public bool RegisterCamera(Camera camera) + { + if (!frameSettingsData.registeredCameras.TryGetValue(camera, out var data)) + { + if (camera.TryGetComponent(out var hdAdditionalCameraData)) + { + var debugData = FrameSettingsHistory.RegisterDebug(hdAdditionalCameraData); + frameSettingsData.registeredCameras.Add(camera, (hdAdditionalCameraData, debugData)); + DebugManager.instance.RegisterData(debugData); + } + else + { + // All scene view will share the same debug FrameSettings as the HDAdditionalData might not be present + if (camera.cameraType == CameraType.SceneView) + { + var debugData = FrameSettingsHistory.RegisterDebug(null, true); + frameSettingsData.registeredCameras.Add(camera, (null, debugData)); + } + else + { + Debug.LogWarning($"[Rendering Debugger] Unable to register camera {camera.name} due to missing {nameof(HDAdditionalCameraData)} component,"); + return false; + } + } + } + + return true; + } + + void IDebugDisplaySettingsData.Reset() + { + FrameSettingsHistory.Clear(); + frameSettingsData.registeredCameras.Clear(); + } + + public DebugDisplaySettingsCamera() + { + this.frameSettingsData = new (); + } + + const string k_PanelTitle = "Camera"; + + static class Strings + { + public static readonly string camera = "Frame Settings"; + } + + internal static class WidgetFactory + { + public static DebugUI.CameraSelector CreateCameraSelector(SettingsPanel panel, + Action, Object> refresh) + { + return new DebugUI.CameraSelector() + { + displayName = Strings.camera, + getter = () => panel.data.frameSettingsData.selectedCamera, + setter = value => + { + if (value is Camera cam && value != panel.data.frameSettingsData.selectedCamera) + panel.data.frameSettingsData.selectedCamera = cam; + }, + onValueChanged = refresh + }; + } + } + + [DisplayInfo(name = k_PanelTitle, order = 40)] + [HDRPHelpURL("rendering-debugger-window-reference", "CameraPanel")] + internal class SettingsPanel : DebugDisplaySettingsPanel + { + public override void Dispose() + { + // Unregister all the cameras from the history + foreach(var registeredCamera in data.frameSettingsData.registeredCameras) + { + FrameSettingsHistory.UnRegisterDebug(registeredCamera.Value.Item1); + } + + var panel = DebugManager.instance.GetPanel(PanelName); + if (panel != null) + { + panel.children.Clear(); + m_FrameSettingsWidgets.Clear(); + } + + base.Dispose(); + } + + DebugUI.CameraSelector m_CameraSelector; + Dictionary> m_FrameSettingsWidgets = new (); + public SettingsPanel(DebugDisplaySettingsCamera data) + : base(data) + { + m_CameraSelector = WidgetFactory.CreateCameraSelector(this, (_, __) => Refresh()); + AddWidget(m_CameraSelector); + + if (GetOrCreateFrameSettingsWidgets(out var frameSettingsWidgets)) + { + foreach (var c in frameSettingsWidgets) + AddWidget(c); + } + } + + bool GetOrCreateFrameSettingsWidgets(out List widgets) + { + widgets = new List(); + + if (data.frameSettingsData.selectedCamera == null) + return false; + + if (!data.IsCameraRegistered(data.frameSettingsData.selectedCamera)) + { + if (!data.RegisterCamera(data.frameSettingsData.selectedCamera)) + return false; + } + + if (!m_FrameSettingsWidgets.TryGetValue(data.frameSettingsData.selectedCamera, out widgets)) + { + widgets ??= new List(); + var cameraInfo = data.frameSettingsData.registeredCameras[data.frameSettingsData.selectedCamera]; + var panelContent = FrameSettingsHistory.GenerateFrameSettingsPanelContent(cameraInfo.Item1); + foreach (var foldout in panelContent) + { + widgets.Add(foldout); + } + + m_FrameSettingsWidgets[data.frameSettingsData.selectedCamera] = widgets; + } + + return widgets.Count != 0; + } + + void Refresh() + { + var panel = DebugManager.instance.GetPanel(PanelName); + if (panel == null) + return; + + panel.children.Clear(); + AddWidget(m_CameraSelector); + panel.children.Add(m_CameraSelector); + + bool needsRefresh = GetOrCreateFrameSettingsWidgets(out var frameSettingsWidgets); + if (needsRefresh) + { + foreach (var c in frameSettingsWidgets) + { + AddWidget(c); + panel.children.Add(c); + } + + DebugManager.instance.ReDrawOnScreenDebug(); + } + } + } + + #region IDebugDisplaySettingsData + /// + /// Checks whether ANY of the debug settings are currently active. + /// + public bool AreAnySettingsActive => false; // This Panel doesn't need to modify the renderer data, therefore this property returns false + + /// + public IDebugDisplaySettingsPanelDisposable CreatePanel() + { + return new SettingsPanel(this); + } + + #endregion + } +} diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsCamera.cs.meta b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsCamera.cs.meta new file mode 100644 index 00000000000..08034c855b6 --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsCamera.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ae2de05020cd37c4ba97bab787d93fd7 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsDecal.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsDecal.cs index 4d383721b5b..613cd4302d8 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsDecal.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplaySettingsDecal.cs @@ -1,4 +1,6 @@ using System; +using System.Reflection; +using UnityEditor; using NameAndTooltip = UnityEngine.Rendering.DebugUI.Widget.NameAndTooltip; namespace UnityEngine.Rendering.HighDefinition @@ -6,6 +8,7 @@ namespace UnityEngine.Rendering.HighDefinition /// /// Decal-related Rendering Debugger settings. /// + [HDRPHelpURL("understand-decals")] class DebugDisplaySettingsDecal : IDebugDisplaySettingsData { internal DecalsDebugSettings m_Data = new DecalsDebugSettings(); @@ -33,12 +36,16 @@ static class Strings } [DisplayInfo(name = "Rendering", order = 5)] - [HDRPHelpURL("understand-decals")] private class SettingsPanel : DebugDisplaySettingsPanel { public SettingsPanel(DebugDisplaySettingsDecal data) { - var foldout = new DebugUI.Foldout() { displayName = Strings.decals, opened = true }; + var foldout = new DebugUI.Foldout() + { + displayName = Strings.decals, + opened = true, + documentationUrl = typeof(DebugDisplaySettingsDecal).GetCustomAttribute()?.URL + }; AddWidget(foldout); foldout.children.Add(new DebugUI.RuntimeDebugShadersMessageBox()); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/HDDebugDisplaySettings.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/HDDebugDisplaySettings.cs index 9965c4dc7b8..15825b6e2e2 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/HDDebugDisplaySettings.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/HDDebugDisplaySettings.cs @@ -22,6 +22,8 @@ internal class HDDebugDisplaySettings : DebugDisplaySettings internal DebugDisplayGPUResidentDrawer gpuResidentDrawerSettings { get; private set; } + internal DebugDisplaySettingsCamera cameraSettings { get; private set; } + #if ENABLE_VIRTUALTEXTURES internal DebugDisplayVirtualTexturing vtSettings { get; private set; } #endif @@ -37,6 +39,7 @@ public override void Reset() volumeSettings = Add(new DebugDisplaySettingsVolume(new HDVolumeDebugSettings())); decalSettings = Add(new DebugDisplaySettingsDecal()); gpuResidentDrawerSettings = Add(new DebugDisplayGPUResidentDrawer()); + cameraSettings = Add(new DebugDisplaySettingsCamera()); #if ENABLE_VIRTUALTEXTURES vtSettings = Add(new DebugDisplayVirtualTexturing()); #endif diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Documentation.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Documentation.cs index cd104b6d69d..03e2f3219cb 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Documentation.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Documentation.cs @@ -9,6 +9,11 @@ public HDRPHelpURLAttribute(string pageName) : base(pageName, Documentation.packageName) { } + + public HDRPHelpURLAttribute(string pageName, string pageHash) + : base(pageName, pageHash, Documentation.packageName) + { + } } internal class Documentation : DocumentationInfo diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricClouds/HDRenderPipeline.VolumetricCloudsFullResolution.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricClouds/HDRenderPipeline.VolumetricCloudsFullResolution.cs index 3f710ba6dd9..8633f2affc8 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricClouds/HDRenderPipeline.VolumetricCloudsFullResolution.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricClouds/HDRenderPipeline.VolumetricCloudsFullResolution.cs @@ -1,4 +1,3 @@ -using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering.RenderGraphModule; namespace UnityEngine.Rendering.HighDefinition @@ -56,7 +55,6 @@ VolumetricCloudsParameters_FullResolution PrepareVolumetricCloudsParameters_Full static void TraceVolumetricClouds_FullResolution(CommandBuffer cmd, VolumetricCloudsParameters_FullResolution parameters, GraphicsBuffer ambientProbeBuffer, RTHandle colorBuffer, RTHandle depthPyramid, - RTHandle intermediateCloudsLighting, RTHandle intermediateCloudsDepth, RTHandle cloudsLighting, RTHandle cloudsDepth) { // Compute the number of tiles to evaluate @@ -74,10 +72,6 @@ static void TraceVolumetricClouds_FullResolution(CommandBuffer cmd, VolumetricCl // Ray-march the clouds for this frame DoVolumetricCloudsTrace(cmd, finalTX, finalTY, parameters.viewCount, in parameters.commonData, ambientProbeBuffer, colorBuffer, depthPyramid, - intermediateCloudsLighting, intermediateCloudsDepth); - - DoVolumetricCloudsUpscale(cmd, parameters.combineKernel, finalTX, finalTY, parameters.viewCount, in parameters.commonData, - intermediateCloudsLighting, intermediateCloudsDepth, colorBuffer, depthPyramid, cloudsLighting, cloudsDepth); } @@ -91,10 +85,6 @@ class VolumetricCloudsFullResolutionData public TextureHandle depthPyramid; public BufferHandle ambientProbeBuffer; - // Intermediate buffers - public TextureHandle tracedCloudsLighting; - public TextureHandle tracedCloudsDepth; - // Output buffer public TextureHandle cloudsLighting; public TextureHandle cloudsDepth; @@ -115,7 +105,6 @@ VolumetricCloudsOutput RenderVolumetricClouds_FullResolution(RenderGraph renderG passData.depthPyramid = builder.ReadTexture(depthPyramid); passData.ambientProbeBuffer = builder.ReadBuffer(renderGraph.ImportBuffer(m_CloudsDynamicProbeBuffer)); - CreateTracingTextures(renderGraph, builder, settings, 1.0f, out passData.tracedCloudsLighting, out passData.tracedCloudsDepth); CreateOutputTextures(renderGraph, builder, settings, out passData.cloudsLighting, out passData.cloudsDepth); builder.SetRenderFunc( @@ -123,7 +112,6 @@ VolumetricCloudsOutput RenderVolumetricClouds_FullResolution(RenderGraph renderG { TraceVolumetricClouds_FullResolution(ctx.cmd, data.parameters, data.ambientProbeBuffer, data.colorBuffer, data.depthPyramid, - data.tracedCloudsLighting, data.tracedCloudsDepth, data.cloudsLighting, data.cloudsDepth); }); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/HDRenderPipeline.VolumetricLighting.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/HDRenderPipeline.VolumetricLighting.cs index 71585fc1924..6aff7044b16 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/HDRenderPipeline.VolumetricLighting.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/HDRenderPipeline.VolumetricLighting.cs @@ -84,7 +84,7 @@ unsafe struct ShaderVariablesVolumetric public uint _VolumeCount; public uint _IsObliqueProjectionMatrix; - public uint _Padding1; + public float _HalfVoxelArcLength; public uint _Padding2; } @@ -903,7 +903,9 @@ void PrepareVisibleLocalVolumetricFogList(HDCamera hdCamera, CommandBuffer cmd) { if (m_VisibleLocalVolumetricFogVolumes.Count >= maxLocalVolumetricFogOnScreen) { - Debug.LogError($"The number of local volumetric fog in the view is above the limit: {m_VisibleLocalVolumetricFogVolumes.Count} instead of {maxLocalVolumetricFogOnScreen}. To fix this, please increase the maximum number of local volumetric fog in the view in the HDRP asset."); +#if UNITY_EDITOR || DEVELOPMENT_BUILD + Debug.LogError($"The number of local volumetric fog in the view is above the limit: {m_VisibleLocalVolumetricFogVolumes.Count + 1} instead of {maxLocalVolumetricFogOnScreen}. To fix this, please increase the maximum number of local volumetric fog in the view in the HDRP asset."); +#endif break; } @@ -988,6 +990,9 @@ unsafe void UpdateShaderVariableslVolumetrics(ref ShaderVariablesVolumetric cb, cb._MaxSliceCount = (uint)maxSliceCount; cb._MaxVolumetricFogDistance = fog.depthExtent.value; cb._VolumeCount = (uint)m_VisibleLocalVolumetricFogVolumes.Count; + // Compute the arc length of a single froxel at 1m from the camera. + // This value can be used to quickly compute the arc length of a single froxel + cb._HalfVoxelArcLength = Mathf.Deg2Rad * hdCamera.camera.fieldOfView / currParams.viewportSize.y / 2.0f; if (updateVoxelizationFields) { diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/HDRenderPipeline.VolumetricLighting.cs.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/HDRenderPipeline.VolumetricLighting.cs.hlsl index b86b1cb8dc2..ba3132f9546 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/HDRenderPipeline.VolumetricLighting.cs.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/HDRenderPipeline.VolumetricLighting.cs.hlsl @@ -61,7 +61,7 @@ CBUFFER_START(ShaderVariablesVolumetric) float4x4 _CameraInverseViewProjection_NO; uint _VolumeCount; uint _IsObliqueProjectionMatrix; - uint _Padding1; + float _HalfVoxelArcLength; uint _Padding2; CBUFFER_END diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/VolumetricLighting.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/VolumetricLighting.compute index 39c7edc9b89..6507bf51797 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/VolumetricLighting.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/VolumetricLighting.compute @@ -351,10 +351,15 @@ VoxelLighting EvaluateVoxelLightingLocal(LightLoopContext context, uint groupIdx // Is it worth evaluating the light? if (sampleLight) { - float lightSqRadius = light.size.x; + // Each froxel in the VBuffer is curved following a spherical shape around the camera position + // To compute the arc length of the froxel, we can take the arc length of a forxel at 1m from the camera and multiply it by + // the distance to the current froxel. + float voxelArcLength = _HalfVoxelArcLength * tEntr; + // Modify the light radius to ensure that it's at least the size of the froxel, reducing the aliasing close to the center of the light. + light.size.x = max(light.size.x, voxelArcLength); float t, distSq, rcpPdf; - ImportanceSamplePunctualLight(rndVal, light.positionRWS, lightSqRadius, + ImportanceSamplePunctualLight(rndVal, light.positionRWS, light.size.x, ray.originWS, ray.jitterDirWS, tEntr, tExit, t, distSq, rcpPdf); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitDecalData.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitDecalData.hlsl index b0ad13323ac..93f7935ee02 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitDecalData.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitDecalData.hlsl @@ -11,6 +11,7 @@ void ApplyDecalToSurfaceDataNoNormal(DecalSurfaceData decalSurfaceData, inout Su { float3 decalSpecularColor = ComputeFresnel0((decalSurfaceData.baseColor.w < 1.0) ? decalSurfaceData.baseColor.xyz : float3(1.0, 1.0, 1.0), decalSurfaceData.mask.x, DEFAULT_SPECULAR_VALUE); surfaceData.specularColor = surfaceData.specularColor * decalSurfaceData.MAOSBlend.x + decalSpecularColor * (1.0f - decalSurfaceData.MAOSBlend.x); + surfaceData.baseColor = ComputeDiffuseColor(surfaceData.baseColor, decalSurfaceData.mask.x); } #else surfaceData.metallic = surfaceData.metallic * decalSurfaceData.MAOSBlend.x + decalSurfaceData.mask.x; diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDAdditionalCameraData.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDAdditionalCameraData.cs index 1e03a638c13..3272cba7eee 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDAdditionalCameraData.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDAdditionalCameraData.cs @@ -524,9 +524,6 @@ FrameSettingsHistory IFrameSettingsHistoryContainer.frameSettingsHistory set => m_RenderingPathHistory = value; } - string IFrameSettingsHistoryContainer.panelName - => m_CameraRegisterName; - /// /// . /// @@ -634,14 +631,6 @@ public void SetAOVRequests(AOVRequestDataCollection aovRequests) public IEnumerable aovRequests => m_AOVRequestDataCollection ?? (m_AOVRequestDataCollection = new AOVRequestDataCollection(null)); - // Use for debug windows - // When camera name change we need to update the name in DebugWindows. - // This is the purpose of this class - [ExcludeCopy] - bool m_IsDebugRegistered = false; - [ExcludeCopy] - string m_CameraRegisterName; - // When we are a preview, there is no way inside Unity to make a distinction between camera preview and material preview. // This property allow to say that we are an editor camera preview when the type is preview. /// @@ -741,37 +730,6 @@ public Matrix4x4 GetNonObliqueProjection(Camera camera) return nonObliqueProjectionGetter(camera); } - void RegisterDebug() - { - if (!m_IsDebugRegistered) - { - // Note that we register FrameSettingsHistory, so manipulating FrameSettings in the Debug windows - // doesn't affect the serialized version - // Note camera's preview camera is registered with preview type but then change to game type that lead to issue. - // Do not attempt to not register them till this issue persist. - m_CameraRegisterName = name; - if (m_Camera.cameraType != CameraType.Preview && m_Camera.cameraType != CameraType.Reflection) - { - DebugDisplaySettings.RegisterCamera(this); - } - m_IsDebugRegistered = true; - } - } - - void UnRegisterDebug() - { - if (m_IsDebugRegistered) - { - // Note camera's preview camera is registered with preview type but then change to game type that lead to issue. - // Do not attempt to not register them till this issue persist. - if (m_Camera.cameraType != CameraType.Preview && m_Camera?.cameraType != CameraType.Reflection) - { - DebugDisplaySettings.UnRegisterCamera(this); - } - m_IsDebugRegistered = false; - } - } - void OnEnable() { if(GraphicsSettings.currentRenderPipelineAssetType != typeof(HDRenderPipelineAsset)) @@ -793,34 +751,6 @@ void OnEnable() FrameSettings dummy = new FrameSettings(); //don't require full init as will be fully reset in AggregateFrameSettings if (GraphicsSettings.TryGetRenderPipelineSettings(out var renderingPathFrameSettings)) FrameSettingsHistory.AggregateFrameSettings(renderingPathFrameSettings, ref dummy, m_Camera, this, HDRenderPipeline.currentAsset, null); - - RegisterDebug(); - -#if UNITY_EDITOR - UpdateDebugCameraName(); - UnityEditor.EditorApplication.hierarchyChanged += UpdateDebugCameraName; -#endif - } - - void UpdateDebugCameraName() - { - // Move the garbage generated by accessing name outside of HDRP - profilingSampler = new ProfilingSampler(HDUtils.ComputeCameraName(name)); - - if (name != m_CameraRegisterName) - { - UnRegisterDebug(); - RegisterDebug(); - } - } - - void OnDisable() - { - UnRegisterDebug(); - -#if UNITY_EDITOR - UnityEditor.EditorApplication.hierarchyChanged -= UpdateDebugCameraName; -#endif } // This is called at the creation of the HD Additional Camera Data, to convert the legacy camera settings to HD diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs index 616c14e106a..e07b59385b4 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs @@ -1588,7 +1588,7 @@ TransparentPrepassOutput RenderTransparentPrepass(RenderGraph renderGraph, Culli if (hasWater) { // Render the water gbuffer (and prepare for the transparent SSR pass) - output.waterGBuffer = m_WaterSystem.RenderWaterGBuffer(renderGraph, cullingResults, hdCamera, prepassOutput.depthBuffer, prepassOutput.normalBuffer, currentColorPyramid, prepassOutput.depthPyramidTexture, lightLists); + output.waterGBuffer = m_WaterSystem.RenderWaterGBuffer(renderGraph, cullingResults, hdCamera, prepassOutput.depthBuffer, prepassOutput.normalBuffer, currentColorPyramid, output.depthBufferPreRefraction, lightLists); // Render Water Line m_WaterSystem.RenderWaterLine(renderGraph, hdCamera, prepassOutput.depthBuffer, ref output); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs index 50ae35a200d..ffcbbf277fb 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -665,19 +665,6 @@ public HDRenderPipeline(HDRenderPipelineAsset asset) m_DebugDisplaySettingsUI.RegisterDebug(HDDebugDisplaySettings.Instance); #endif -#if UNITY_EDITOR - // We don't need the debug of Scene View at runtime (each camera have its own debug settings) - // All scene view will share the same FrameSettings for now as sometimes Dispose is called after - // another instance of HDRenderPipeline constructor is called. - - Camera firstSceneViewCamera = UnityEditor.SceneView.sceneViews.Count > 0 ? (UnityEditor.SceneView.sceneViews[0] as UnityEditor.SceneView).camera : null; - if (firstSceneViewCamera != null) - { - var history = FrameSettingsHistory.RegisterDebug(null, true); - DebugManager.instance.RegisterData(history); - } -#endif - m_DepthPyramidMipLevelOffsetsBuffer = new ComputeBuffer(15, sizeof(int) * 2); m_CustomPassColorBuffer = new Lazy(() => RTHandles.Alloc(Vector2.one, TextureXR.slices, dimension: TextureXR.dimension, colorFormat: GetCustomBufferFormat(), enableRandomWrite: true, useDynamicScale: true, name: "CustomPassColorBuffer")); @@ -2806,7 +2793,7 @@ AOVRequestData aovRequest cameraXRSettings.viewCount = (uint)hdCamera.viewCount; cameraXRSettings.viewOffset = (uint)hdCamera.xr.multipassId; - VFXManager.ProcessCameraCommand(camera, cmd, cameraXRSettings, cullingResults); + VFXManager.ProcessCameraCommand(camera, cmd, cameraXRSettings, cullingResults, customPassCullingResults); if (GL.wireframe) { diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettingsHistory.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettingsHistory.cs index c4a949ad3fa..be96530667a 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettingsHistory.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettingsHistory.cs @@ -24,7 +24,6 @@ internal interface IFrameSettingsHistoryContainer : IDebugData FrameSettingsOverrideMask frameSettingsMask { get; } FrameSettings frameSettings { get; } bool hasCustomFrameSettings { get; } - string panelName { get; } } struct FrameSettingsHistory @@ -65,9 +64,6 @@ FrameSettings IFrameSettingsHistoryContainer.frameSettings bool IFrameSettingsHistoryContainer.hasCustomFrameSettings => false; - string IFrameSettingsHistoryContainer.panelName - => "Scene Camera"; - public MinimalHistoryContainer() { m_FrameSettingsHistory.debug = GraphicsSettings.TryGetRenderPipelineSettings(out var renderingPathFrameSettings) @@ -81,6 +77,7 @@ Action IDebugData.GetReset() // => m_FrameSettingsHistory.TriggerReset => () => m_FrameSettingsHistory.TriggerReset(); } + internal static IFrameSettingsHistoryContainer sceneViewFrameSettingsContainer = new MinimalHistoryContainer(); #endif internal static HashSet containers = new HashSet(); @@ -291,32 +288,23 @@ static DebugUI.HistoryEnumField GenerateHistoryEnumField(RenderingPathFrameSetti return area; } - static DebugUI.Widget[] GenerateFrameSettingsPanelContent(IFrameSettingsHistoryContainer frameSettingsContainer) + internal static DebugUI.Widget[] GenerateFrameSettingsPanelContent(IFrameSettingsHistoryContainer frameSettingsContainer) { +#if UNITY_EDITOR + frameSettingsContainer ??= sceneViewFrameSettingsContainer; +#endif + if (frameSettingsContainer == null) + return Array.Empty(); + var panelContent = new DebugUI.Widget[foldoutNames.Length]; for (int index = 0; index < foldoutNames.Length; ++index) { - panelContent[index] = new DebugUI.Foldout(foldoutNames[index], GenerateHistoryArea(frameSettingsContainer, index), columnNames, columnTooltips); + panelContent[index] = new DebugUI.Foldout(foldoutNames[index], + GenerateHistoryArea(frameSettingsContainer, index), columnNames, columnTooltips); } return panelContent; } - static void GenerateFrameSettingsPanel(string menuName, IFrameSettingsHistoryContainer frameSettingsContainer) - { - List widgets = new List(); - widgets.AddRange(GenerateFrameSettingsPanelContent(frameSettingsContainer)); - var panel = DebugManager.instance.GetPanel( - menuName, - createIfNull: true, -#if UNITY_EDITOR - frameSettingsContainer == sceneViewFrameSettingsContainer - ? 100 : // Scene Camera -#endif - 101, // Other Cameras (from Camera component) - overrideIfExist: true); - panel.children.Add(widgets.ToArray()); - } - static Type RetrieveEnumTypeByField(FrameSettingsField field) { switch (field) @@ -334,16 +322,23 @@ public static IDebugData RegisterDebug(IFrameSettingsHistoryContainer frameSetti frameSettingsContainer = sceneViewFrameSettingsContainer; #endif - GenerateFrameSettingsPanel(frameSettingsContainer.panelName, frameSettingsContainer); containers.Add(frameSettingsContainer); return frameSettingsContainer; } + public static void Clear() + { +#if UNITY_EDITOR + sceneViewFrameSettingsContainer = new MinimalHistoryContainer(); +#endif + containers.Clear(); + } + /// Unregister FrameSettingsHistory for DebugMenu public static void UnRegisterDebug(IFrameSettingsHistoryContainer container) { - DebugManager.instance.RemovePanel(container.panelName); - containers.Remove(container); + if (container != null) + containers.Remove(container); } /// Check if a camera is registered. diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Sky/PhysicallyBasedSky/PhysicallyBasedSkyRenderer.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Sky/PhysicallyBasedSky/PhysicallyBasedSkyRenderer.cs index 1b00ab03e71..619efe2f353 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Sky/PhysicallyBasedSky/PhysicallyBasedSkyRenderer.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Sky/PhysicallyBasedSky/PhysicallyBasedSkyRenderer.cs @@ -384,6 +384,8 @@ public static void SetDefaultGlobalSkyData(CommandBuffer cmd) public override void Cleanup() { + s_DataFrameUpdate = -1; + if (m_PrecomputedData != null) { s_PrecomputationCache.Release(m_LastPrecomputationParamHash); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/HDRenderPipeline.WaterSystem.Decals.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/HDRenderPipeline.WaterSystem.Decals.cs index 9d1ee7a82aa..6fbcf34bd0e 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/HDRenderPipeline.WaterSystem.Decals.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/HDRenderPipeline.WaterSystem.Decals.cs @@ -439,34 +439,37 @@ void UpdateWaterDecals(CommandBuffer cmd, WaterSurface currentWater) } } - if ((currentWater.simulationMask || currentWater.supportSimulationFoamMask) && m_ActiveMask) + if (m_EnableDecalWorkflow) { - using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.WaterDecalMask))) + if ((currentWater.simulationMask || currentWater.supportSimulationFoamMask) && m_ActiveMask) { - CoreUtils.SetRenderTarget(cmd, currentWater.maskBuffer, clearFlag: ClearFlag.Color, Color.white); + using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.WaterDecalMask))) + { + CoreUtils.SetRenderTarget(cmd, currentWater.maskBuffer, clearFlag: ClearFlag.Color, Color.white); - cmd.DrawProcedural(Matrix4x4.identity, m_DecalMaterial, m_MaskDecalPass, MeshTopology.Quads, 4, m_NumActiveWaterDecals, currentWater.mpb); - currentWater.maskBuffer.rt.IncrementUpdateCount(); // For the CPU Simulation + cmd.DrawProcedural(Matrix4x4.identity, m_DecalMaterial, m_MaskDecalPass, MeshTopology.Quads, 4, m_NumActiveWaterDecals, currentWater.mpb); + currentWater.maskBuffer.rt.IncrementUpdateCount(); // For the CPU Simulation + } } - } - if (m_ActiveLargeCurrent || m_ActiveRipplesCurrent) - { - using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.WaterDecalCurrent))) + if (m_ActiveLargeCurrent || m_ActiveRipplesCurrent) { - if (currentWater.supportLargeCurrent && m_ActiveLargeCurrent) + using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.WaterDecalCurrent))) { - CoreUtils.SetRenderTarget(cmd, currentWater.largeCurrentBuffer, clearFlag: ClearFlag.Color, Color.black); + if (currentWater.supportLargeCurrent && m_ActiveLargeCurrent) + { + CoreUtils.SetRenderTarget(cmd, currentWater.largeCurrentBuffer, clearFlag: ClearFlag.Color, Color.black); - cmd.DrawProcedural(Matrix4x4.identity, m_DecalMaterial, m_LargeCurrentDecalPass, MeshTopology.Quads, 4, m_NumActiveWaterDecals, currentWater.mpb); - currentWater.largeCurrentBuffer.rt.IncrementUpdateCount(); // For the CPU Simulation - } - if (currentWater.supportRipplesCurrent && m_ActiveRipplesCurrent) - { - CoreUtils.SetRenderTarget(cmd, currentWater.ripplesCurrentBuffer, clearFlag: ClearFlag.Color, Color.black); + cmd.DrawProcedural(Matrix4x4.identity, m_DecalMaterial, m_LargeCurrentDecalPass, MeshTopology.Quads, 4, m_NumActiveWaterDecals, currentWater.mpb); + currentWater.largeCurrentBuffer.rt.IncrementUpdateCount(); // For the CPU Simulation + } + if (currentWater.supportRipplesCurrent && m_ActiveRipplesCurrent) + { + CoreUtils.SetRenderTarget(cmd, currentWater.ripplesCurrentBuffer, clearFlag: ClearFlag.Color, Color.black); - cmd.DrawProcedural(Matrix4x4.identity, m_DecalMaterial, m_RipplesCurrentDecalPass, MeshTopology.Quads, 4, m_NumActiveWaterDecals, currentWater.mpb); - currentWater.ripplesCurrentBuffer.rt.IncrementUpdateCount(); // For the CPU Simulation + cmd.DrawProcedural(Matrix4x4.identity, m_DecalMaterial, m_RipplesCurrentDecalPass, MeshTopology.Quads, 4, m_NumActiveWaterDecals, currentWater.mpb); + currentWater.ripplesCurrentBuffer.rt.IncrementUpdateCount(); // For the CPU Simulation + } } } } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/HDRenderPipeline.WaterSystem.Underwater.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/HDRenderPipeline.WaterSystem.Underwater.cs index 051de4e5590..6be6432bca8 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/HDRenderPipeline.WaterSystem.Underwater.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/HDRenderPipeline.WaterSystem.Underwater.cs @@ -84,8 +84,11 @@ void EvaluateUnderWaterSurface(HDCamera hdCamera) { if (currentWater.volumeBounds != null) { + var closestPointInVolumeBounds = currentWater.volumeBounds.ClosestPoint(cameraWSPos); + bool isInBounds = (closestPointInVolumeBounds - cameraWSPos).sqrMagnitude < float.Epsilon; + // If the specified bounds contains the camera, we found a match - if (currentWater.volumeBounds.bounds.Contains(cameraWSPos) && currentPriority < currentWater.volumePrority) + if (isInBounds && currentPriority < currentWater.volumePrority) { m_UnderWaterUpHeight = new Vector4(upDirection.x, upDirection.y, upDirection.z, float.MinValue); m_UnderWaterSurfaceIndex = surfaceIdx; diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/HDRenderPipeline.WaterSystem.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/HDRenderPipeline.WaterSystem.cs index be47212054e..e926414a59c 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/HDRenderPipeline.WaterSystem.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/HDRenderPipeline.WaterSystem.cs @@ -46,7 +46,7 @@ partial class WaterSystem internal const string k_TessellationPass = "Tessellation"; readonly static string[] k_PassesGBuffer = new string[] { k_WaterGBufferPass, k_LowResGBufferPass }; readonly static string[] k_PassesGBufferTessellation = new string[] { k_WaterGBufferPass + k_TessellationPass, k_LowResGBufferPass }; - readonly static string[] k_PassesWaterDebug = new string[] { k_WaterDebugPass + k_TessellationPass, k_WaterDebugPass + k_LowResGBufferPass }; + readonly static string[] k_PassesWaterDebug = new string[] { k_WaterDebugPass, k_WaterDebugPass + k_LowResGBufferPass }; // Other internal rendering data MaterialPropertyBlock m_WaterMaterialPropertyBlock; diff --git a/Packages/com.unity.render-pipelines.high-definition/package.json b/Packages/com.unity.render-pipelines.high-definition/package.json index da5ca48db35..c04ee9d714c 100644 --- a/Packages/com.unity.render-pipelines.high-definition/package.json +++ b/Packages/com.unity.render-pipelines.high-definition/package.json @@ -1,17 +1,17 @@ { "name": "com.unity.render-pipelines.high-definition", "description": "The High Definition Render Pipeline (HDRP) is a high-fidelity Scriptable Render Pipeline built by Unity to target modern (Compute Shader compatible) platforms. HDRP utilizes Physically-Based Lighting techniques, linear lighting, HDR lighting, and a configurable hybrid Tile/Cluster deferred/Forward lighting architecture and gives you the tools you need to create games, technical demos, animations, and more to a high graphical standard.", - "version": "17.0.3", - "unity": "6000.0", + "version": "17.2.0", + "unity": "6000.2", "displayName": "High Definition RP", "dependencies": { "com.unity.modules.video": "1.0.0", "com.unity.modules.animation": "1.0.0", "com.unity.modules.imageconversion": "1.0.0", - "com.unity.render-pipelines.core": "17.0.3", - "com.unity.shadergraph": "17.0.3", - "com.unity.visualeffectgraph": "17.0.3", - "com.unity.render-pipelines.high-definition-config": "17.0.3" + "com.unity.render-pipelines.core": "17.2.0", + "com.unity.shadergraph": "17.2.0", + "com.unity.visualeffectgraph": "17.2.0", + "com.unity.render-pipelines.high-definition-config": "17.2.0" }, "keywords": [ "graphics", diff --git a/Packages/com.unity.render-pipelines.universal/CHANGELOG.md b/Packages/com.unity.render-pipelines.universal/CHANGELOG.md index 2c02d55db0c..464748a33a3 100644 --- a/Packages/com.unity.render-pipelines.universal/CHANGELOG.md +++ b/Packages/com.unity.render-pipelines.universal/CHANGELOG.md @@ -4,16 +4,195 @@ uid: urp-changelog # Changelog -All notable changes to this package will be documented in this file. - -The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) -and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] Version Updated The version number for this package has increased due to a version update of a related graphics package. +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + + +## [17.0.3] - 2025-02-13 + +This version is compatible with Unity 6000.2.0a17. + +### Added +- `SetViewAndProjectionMatrices()` helper function is available within a RasterRenderPass in RenderGraph. +- RenderPipelineManager callbacks are raised from UniversalRenderPipeline.SingleCameraRequest. +- SetViewAndProjectionMatrices() helper function is available within a RasterRenderPass in RenderGraph. + +### Changed +- Implemented minor CPU optimizations for the Post-Processing Bloom effect. +Enhanced code quality by consistently using TextureDesc in place of RenderTextureDescriptor. +- Added the ability to turn Reflection Probe Atlas on or off for Universal Render Pipeline (URP) Forward+ renderers, regardless of blending. +- Improved Depth usage performance for some platforms. +- Updated the RenderGraph samples to use the new helper functions to reduce boilerplate code. +- Changed the URP render pass names for consistency in the RenderGraph viewer, the Profiler, and the frame debugger. +- Sprite Default Material - Moved to Graphics Settings, Sprite Settings from Renderer2DData. +- Improve the sample code in the URP Post Processing Effect (with Volume) template to remove a copy render pass. +- Improved the depth copy scheduling in render graph path to allow copying after skybox rendering to improve pass merging. +- Enabled foveated rendering for UberPost pass when it is the last pass and FinalPostBlit pass. +- In the Render Graph Viewer, you can now open the tool when the compatibility mode is enabled. + +### Fixed +- Fixed an issue where undoing GameObject creation didn't work when the GameObject was focused. +- Fixed unclear error message while updating volume stack before Universal Render Pipeline is created. +- Fixed preview for URP overlay camera not rendering correct view. Now an explicit message explain it is not possible for theses cameras. +- Fixed incorrect depth texture format exception when pressing the Ctrl key in the scene view with URP. +- Fixed an issue where blending DBuffer decal normals could causes NaNs. +- Fixed light cookie texture memory leak when entering Playmode. +- Fix continuous error printing in URP Samples when assigned pipeline asset is not correct +- Fix RenderTexture.Create failure on certain Android Vulkan devices +- Fixed exception spam when trying to use full screen render passes on visionOS +- Fixed a warning, "Missing types referenced from component UniversalRenderPipelineGlobalSettings..." which was caused by the URP Template project on platforms where ENABLE_VR is not defined. +- Fixed invalid viewport for post-process when using camera stacking with render scale. +- Fixed invalid alpha output for scaling setup shader when using camera stacking with render scale on URP compatibility path. +- Fixed incorrectly bright pixels by clamping alpha after additive blending to 0-1 range in post-processing when using camera stacking with render scale. +- Fixed black pixels (NaN) in Lens Distort post-processing effect. +- Fixed post-process FSR upscaling and _ScreenParams for stacked Overlay cameras. +- Remove "AssertionException The RenderTextureDescriptor used to create a TextureDesc contains both graphicsFormat and depthStencilFormat". +- Optimized finalblit pass load operation bandwidth cost for XR. +- Fixed a redundant empty line in a tooltip for Cast Shadows toggle in the URP Asset for Additional lights. +- Fixed an issue where WorldToCamera matrix wasn't set before rendering shadows. +- Fixed spamming errors and broken visual when resizing GameView with Free Aspect in DepthBlit sample. +- Fixed an issue where Forward Plus lighting in URP was causing rendering artifacts. +- Fixed an issue where Game View would flip upside down when using HDR Debug Mode. +- Removed 'implicit truncation of vector type' warnings at URP ScreenSpaceAmbientOcclusion.shader. +- Fixed a depth texture format used for URP 2D RenderPass with Android devices issue. +- Fixed the CameraDepthAttachment turning black for DX11. +- Fixed an issue where Transparent Receive Shadows setting didn't work for custom shaders. +- Modified final depth copy logic to read from depth attachment instead of depth texture to avoid errors when depth texture isn't available +- Fixed an issue where SS Shadow coord transform was missing from TransformWorldToShadowCoord. +- Fixed sorting the Reflection Probe by resolution. +- Fixed issue with URP lights where the Culling Mask property was ignored for shadow casters when using the GPU Resident Drawer. +- Fixed an issue with the viewport of stacked cameras in post-processing. +- Fixed an issue where creating a light and then undoing the action displayed a warning in the console. +- Fixed an issue where the Shadowmask mode didn't take Shadows > Shadow Type > Realtime Shadows > Strength setting into account. +- Fixed an issue where SoftShadowsHigh global shader keyword is not initialized properly. +- Fixed an issue where disabling *Strip Unused Variants* and *Strip Unused Post Processing Variants* still stripped out various keywords in builds. +- Fixed an issue with aliased shadows when using the medium or high soft shadow settings. +- Fixed an issue where variants were being stripped out in Scriptable Stripping when *Strip Unused Variants* was disabled. +- Fixed a URP RenderGraph case with multisample anti-aliasing (MSAA) and camera stacking on the Windows Player. +- Fixed an issue where undoing the creation of a GameObject didn't remove the GameObject when it had focus in the Editor. +- Fixed an issue where the preview for URP overlay cameras didn't render the correct view. An explicit message now explains that previewing is not possible for these cameras. +- Fixed an unclear error message that appeared when updating the volume stack before the Universal Render Pipeline was created. +- Fixed an issue where pressing the Ctrl key in the Scene view while using URP caused a depth texture format exception. +- Fixed light cookie texture memory leak when entering Playmode. +- Fix continuous error printing in URP Samples when assigned pipeline asset is not correct +- Fixed an issue where blending DBuffer decal normals could causes NaNs. +- Fixed the Preview Camera drawing grid that appears on top of preview mesh with URP Render Graph when depth priming is active. +- Fixed a broken setting related to the Shadow rendering layer that wasn't changing shadow when using `shadowRenderingLayers` in the script. +- Fixed Native Render Pass to render `RenderTextureDescriptor` with the correct dimensions when the render scale is not equal to one. +- Added a warning the Scene to inform users about light limits. +- Fixed inconsistent text capitalizations in various parts of the Editor. +- Fixed an issue with corrupt cookie sampling when targeting mobile platforms. +- Hide unused Native Render Pass checkbox in UniversalRenderer when using Render Graph. +- Fixed obsolete API usages in URP samples. +- Disabled fallback behavior on FSR EASU shader to prevent build errors on machines with old GPUs. +- Fixed an issue where Shadow maps sometimes leaked when switching between quality levels. +- Render Pipeline Converter - Built in materials where not found properly the first time the Initialize Converter was called. +- Fixed visual issues caused by edge cases in alpha clipping logic when MSAA is enabled. +- Fixed errors when inspecting Universal Renderer assets with URP not as the active pipeline. +- Fixed an incorrect motion vectors with URP Deferred due to missing camera depth binding. +- Fixed broken "Map Overlay" modes in RenderGraph and aspect ratios in RenderGraph and non-RG paths. +Added missing "Map Overlay" modes for Motion Vectors and Light Cookie Atlas. +- Disabled faulty NRP for Editor-only FinalCopyDepth pass in URP 3D. +- Reduced banding on FSR upscaled render target by changing render target formats. +- Fixed SRP per-XRPass control to disable FR for intermediate render passes on untethered XR device if renderViewportScale is active when using URP RenderGraph. +- Fixed an issue where shadows for additional lights would flicker if additional lights exceeded the maximum amount of shadow casting lights. +- Fixed an issue where shadows for additional lights were incorrectly ordered when using deferred rendering. +- Fixed an issue where shadows for additional lights were still rendering even though they were disabled in the URP Asset. +- Fixed a render graph bug where a pass-break between GBuffer and deferred lighting would cause an error. +- Made the gBuffer components non-global. +- Fixed render graph allocated textures not respecting dynamic scaling settings in some cases. +- Fixed render graph scheduling logic for CopyDepth pass when custom passes that read depth are present. +- Added warning box in the camera inspector when both TAA and MSAA is enabled to notify the user that TAA will be skiped with current settings. +- Fixed custom pass order in URP RenderGraph injected at AfterRenderingSkybox/BeforeRenderingTransparents. +- Fixed an issue where if the profiling sampler of a render graph pass is null, use an empty string instead of the name of the profiling sampler. +- Fixed an issue where multiview support for the XR Occlusion Mesh pass was missing. +- Fixed an issue where Shadow Near Plane on Spot Lights was incorrectly culling shadow casters. +- Fixed an issue with enabling instancing at runtime for a Decal material. +- Fixed the yflip issue when depth texture is required and color texture is not required in RenderGraph compatibility mode. +- Fixed CopyDepthPass setup causing Vulkan validation errors under specific circumstances. +- Fixed ScriptableRenderPass.profilerSampler being null in Compatibility mode. This will now only be null in release (non-dev) when using RenderGraph. This nullification was done previously as a small performance optimization. +- Fixed BlitAndSwapColorPass sample. +- Fixed an issue where reflection probes would render incorrectly on some platforms. +- Updated template (Create > Rendering > URP Post-Processing Effect (Renderer Feature with Volume). +- Fixed a shader compilation error on Apple platforms without Metal. +- Fixed an issue with the Inspector of Render2DData when selecting custom default material. +- Fixed URP Lens Flare with scaled pixelRect. +- Fixed an incorrect depth copy scheduling in deferred path when render graph was enabled. +- Fixed an issue by avoiding overwriting the cameraDepthTexture handle with gbuffer4 in deferred render graph path. +- Fixed an issue where glClientWaitSync: Expected application to have kicked everything until job: 96089 (possibly by calling glFlush)" are thrown in the Android Player on some devices with PowerVR Rogue GE8320 GPU. +- Fixed an issue where Directional Light Shadows rendered incorrectly at close distance. +- Removed msaa sample count mismatch warning at first frame in IOS player. +- Fixed shadow-map sampling artifacts present when using the Unlit DrawMode in the SceneView. +- Fixed URP Full Screen Render Feature with RenderGraph to limit the use of global resources and improve memory usage. +- Fixed XR isLastCamera check. +- Fixed an issue with `XRCopyDepth` not working when running in RenderGraph. +- Fixed Forward+ always blending reflection probes regardless of setting. +- Fixed an issue where Color Lookup caused GC.Alloc every frame. +- Fixed camera offset in the UI editor for the RenderObject RenderFeature. +- Fixed an issue where lights would leak through objects when using Point Lights. +- Fixed an issue where Shader Prefiltering data wasn't updated properly for Asset Bundles. +- Fixed a RenderGraph issue where Invalid Depth format errors appeared when pressing CTRL in scene view. +- Fixed an issue scene-view wireframe rendering when using depth-priming. +- Fixed some shader warnings in builds. +- Fixed camera gizmos frustum that was not rendered correctly in the presence of a monobehaviour containing an OnGUI method. +- Fixed an issue where URP RawDepthHistory buffer created an unnecessary color resource, leading to unnecessary GPU memory usage. +- Fixed an issue to prevent repetitive error logs about C-buffer layout mispatch in GPU-instancing-enabled Speed Tree materials when enabling Rendering Layers. +- Enabled Native RenderPass option to follow Universal Renderer Data when rendering Game view. +- Fixed an issue with a missing depth prepass in deferred render graph path. +- Modified the scheduling of a motion vector pass in render graph path in order to ensure motion and depth data are always available together. +- Fixed an issue in RenderGraph where an extra copy was made of the Main and Additional light shadow textures. +- Fixed an issue with the depthStencil format for the `_CameraDepthAttachment` and the `_CameraDepthTexture` resource so they are now correctly set by the format settings on the Renderer asset. +- Fixed SpeedTree8 ShaderLab shader issue. +- Fixed render graph global textures persisting after graph execution. +- Fixed an issue in URP Forward Plus lighting where extra tiles were being incorrectly masked to be lit by spot lights that did not in fact affect them. +- Fixed camera stacking rendering to system backbuffer with Render Graph on iOS/macOS. +- Fixed an issue where shadows were rendering incorrectly when light sources were placed near shadow casting objects. +- Fixed the use of a potentially uninitialized variable warning in Core2D issue. +- Added shader stripping logic for STP to avoid URP project build failures when targeting Windows from a non-Windows platform. +- Updated RenderGraph samples (install through Package Manager) to the latest APIs and best practices. +- Fixed compile error in the lighting debug views when using APV with Shadowmask. +- Fixed missing geometry on Adreno GPUs by disabling GPU occlusion culling as a workaround. +- Removed usage of legacy `depthBufferBits` on `RenderTextureDescriptor` in URP 2D and 3D renderers to fix issues with incorrect depth stencil format for render textures. +- Fixed TAA frame index mismatch which was causing incorrect visuals when the camera history reset system was used with STP. +- Fixed the depth bias for motion vectors that was causing objects to leak through geometry. +- Fixed invalid viewport for post-process when using camera stacking with render scale. +- Fixed invalid alpha output for scaling setup shader when using camera stacking with render scale on URP compatibility path. +- Fixed incorrectly bright pixels by clamping alpha after additive blending to 0-1 range in post-processing when using camera stacking with render scale. +- Fixed black pixels (NaN) in Lens Distort post-processing effect. +- Fixed post-process FSR upscaling and _ScreenParams for stacked Overlay cameras. +- Remove "AssertionException The RenderTextureDescriptor used to create a TextureDesc contains both graphicsFormat and depthStencilFormat". +- Fixed spamming errors and broken visual when resizing GameView with Free Aspect in DepthBlit sample. +- Fixed an issue where WorldToCamera matrix wasn't set before rendering shadows. +- Fixed a redundant empty line in a tooltip for Cast Shadows toggle in the URP Asset for Additional lights. +- Fixed issue with spot light clipping incorrectly in URP Forward+. +- Remove 'implicit truncation of vector type' warnings at URP ScreenSpaceAmbientOcclusion.shader. +- Fixed an issue where Game View would flip upside down when using HDR Debug Mode. +- Fixed an issue with warning (Missing types referenced from component UniversalRenderPipelineGlobalSettings...) caused by URP Template project on platforms where ENABLE_VR is not defined. +- Fixed an issue where Transparent Receive Shadows setting didn't work for custom shaders. +- Fixed depth texture format used for URP 2D RenderPass with Android devices. +- Fixed the CameraDepthAttachment turning black for DX11. +- Fixed an issue by modifing final depth copy logic to read from depth attachment instead of depth texture to avoid errors when depth texture isn't available. +- Fixed sorting the Reflection Probe by resolution. +- Fixed an issue by adding SS Shadow coord transform to TransformWorldToShadowCoord. +- Fixed issue with URP lights where the Culling Mask property was ignored for shadow casters when using the GPU Resident Drawer. +- Fixed an issue where creating a light and undoing displayed a warning in the console. +- Fixed an issue where the shadow strength setting on lights did not work with shadow masks. +- Fixed an issue where SoftShadowsHigh global shader keyword is not initialized properly. +- Fixed an issue with aliased shadows when using medium or high soft shadow setting. +- Fixed an issue where variants were being stripped out in Scriptable Stripping when "Strip Unused Variants" was disabled. +- Fixed URP RenderGraph case with MSAA and camera stacking on Windows Player. +- Fixed an issue where undoing GameObject creation didn't work when the GameObject was focused. +- Fixed unclear error message while updating volume stack before Universal Render Pipeline is created. +- Fixed depth texture format exception when pressing the Ctrl key in the scene view with URP. +- Fixed light cookie texture memory leak when entering Playmode. +- Fixed an issue where blending DBuffer decal normals could causes NaNs. + ## [17.0.2] - 2024-04-02 This version is compatible with Unity 6000.0.0b15. diff --git a/Packages/com.unity.render-pipelines.universal/Editor/2D/Renderer2DDataEditor.cs b/Packages/com.unity.render-pipelines.universal/Editor/2D/Renderer2DDataEditor.cs index a59f2d74237..ced1ddbee80 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/2D/Renderer2DDataEditor.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/2D/Renderer2DDataEditor.cs @@ -13,6 +13,9 @@ class Styles public static readonly GUIContent lightBlendStylesHeader = EditorGUIUtility.TrTextContent("Light Blend Styles", "A Light Blend Style is a collection of properties that describe a particular way of applying lighting."); public static readonly GUIContent postProcessHeader = EditorGUIUtility.TrTextContent("Post-processing"); + public static readonly GUIContent filteringSectionLabel = EditorGUIUtility.TrTextContent("Filtering", "Settings that controls and define which layers the renderer draws."); + public static readonly GUIContent layerMask = EditorGUIUtility.TrTextContent("Layer Mask", "Controls which transparent layers this renderer draws."); + public static readonly GUIContent transparencySortMode = EditorGUIUtility.TrTextContent("Transparency Sort Mode", "Default sorting mode used for transparent objects"); public static readonly GUIContent transparencySortAxis = EditorGUIUtility.TrTextContent("Transparency Sort Axis", "Axis used for custom axis sorting mode"); public static readonly GUIContent hdrEmulationScale = EditorGUIUtility.TrTextContent("HDR Emulation Scale", "Describes the scaling used by lighting to remap dynamic range between LDR and HDR"); @@ -43,6 +46,7 @@ struct LightBlendStyleProps public SerializedProperty blendFactorAdditive; } + SerializedProperty m_LayerMask; SerializedProperty m_TransparencySortMode; SerializedProperty m_TransparencySortAxis; SerializedProperty m_HDREmulationScale; @@ -60,6 +64,7 @@ struct LightBlendStyleProps SerializedProperty m_CameraSortingLayersTextureBound; SerializedProperty m_CameraSortingLayerDownsamplingMethod; + SavedBool m_FilteringFoldout; SavedBool m_GeneralFoldout; SavedBool m_LightRenderTexturesFoldout; SavedBool m_LightBlendStylesFoldout; @@ -84,6 +89,7 @@ void OnEnable() m_WasModified = false; m_Renderer2DData = (Renderer2DData)serializedObject.targetObject; + m_LayerMask = serializedObject.FindProperty("m_LayerMask"); m_TransparencySortMode = serializedObject.FindProperty("m_TransparencySortMode"); m_TransparencySortAxis = serializedObject.FindProperty("m_TransparencySortAxis"); m_HDREmulationScale = serializedObject.FindProperty("m_HDREmulationScale"); @@ -121,6 +127,7 @@ void OnEnable() m_DefaultMaterialType = serializedObject.FindProperty("m_DefaultMaterialType"); m_DefaultCustomMaterial = serializedObject.FindProperty("m_DefaultCustomMaterial"); + m_FilteringFoldout = new SavedBool($"{target.GetType()}.FilteringFoldout", true); m_GeneralFoldout = new SavedBool($"{target.GetType()}.GeneralFoldout", true); m_LightRenderTexturesFoldout = new SavedBool($"{target.GetType()}.LightRenderTexturesFoldout", true); m_LightBlendStylesFoldout = new SavedBool($"{target.GetType()}.LightBlendStylesFoldout", true); @@ -137,6 +144,7 @@ public override void OnInspectorGUI() { serializedObject.Update(); + DrawFiltering(); DrawGeneral(); DrawLightRenderTextures(); DrawLightBlendStyles(); @@ -184,6 +192,18 @@ public void DrawCameraSortingLayerTexture() EditorGUI.EndDisabledGroup(); } + private void DrawFiltering() + { + CoreEditorUtils.DrawSplitter(); + m_FilteringFoldout.value = CoreEditorUtils.DrawHeaderFoldout(Styles.filteringSectionLabel, m_FilteringFoldout.value); + if (!m_FilteringFoldout.value) + return; + + EditorGUILayout.PropertyField(m_LayerMask, Styles.layerMask); + + EditorGUILayout.Space(); + } + private void DrawGeneral() { CoreEditorUtils.DrawSplitter(); diff --git a/Packages/com.unity.render-pipelines.universal/Editor/2D/ShaderGraph/Targets/UniversalSpriteCustomLitSubTarget.cs b/Packages/com.unity.render-pipelines.universal/Editor/2D/ShaderGraph/Targets/UniversalSpriteCustomLitSubTarget.cs index 6978d6c9d0e..9bc26816a6d 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/2D/ShaderGraph/Targets/UniversalSpriteCustomLitSubTarget.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/2D/ShaderGraph/Targets/UniversalSpriteCustomLitSubTarget.cs @@ -112,6 +112,9 @@ public static PassDescriptor Lit(UniversalTarget target) defines = new DefineCollection(), keywords = SpriteLitKeywords.Lit, includes = SpriteLitIncludes.Lit, + + // Custom Interpolator Support + customInterpolators = CoreCustomInterpDescriptors.Common }; if (target.disableTint) @@ -150,6 +153,9 @@ public static PassDescriptor Normal(UniversalTarget target) pragmas = CorePragmas._2DDefault, defines = new DefineCollection(), includes = SpriteLitIncludes.Normal, + + // Custom Interpolator Support + customInterpolators = CoreCustomInterpDescriptors.Common }; if (target.disableTint) diff --git a/Packages/com.unity.render-pipelines.universal/Editor/2D/Shadows/ShadowProvider/ShadowShape2DProvider_ProperyDrawer.cs b/Packages/com.unity.render-pipelines.universal/Editor/2D/Shadows/ShadowProvider/ShadowShape2DProvider_ProperyDrawer.cs index d9eda738cf4..f7744662b62 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/2D/Shadows/ShadowProvider/ShadowShape2DProvider_ProperyDrawer.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/2D/Shadows/ShadowProvider/ShadowShape2DProvider_ProperyDrawer.cs @@ -15,13 +15,24 @@ public class ShadowShape2DProvider_ProperyDrawer : PropertyDrawer { delegate void ProcessChild(SerializedProperty child); + bool IsChildVisible(Type parentType, SerializedProperty child) + { + // Check to see if the child is public and not hidden in the inspector + FieldInfo fieldInfo = parentType.GetField(child.name, BindingFlags.Public | BindingFlags.Instance); + HideInInspector hideInInspector = parentType.GetCustomAttribute(); + return fieldInfo != null && hideInInspector == null; + } + void ProcessChildren(SerializedProperty parentProperty, ProcessChild onProcessChild) { var enumerator = parentProperty.GetEnumerator(); + object parentObj = parentProperty.managedReferenceValue; + Type parentType = parentObj.GetType(); + while (enumerator.MoveNext()) { - SerializedProperty child = enumerator.Current as SerializedProperty; - if (child != null) + SerializedProperty child = enumerator.Current as SerializedProperty; + if (child != null && IsChildVisible(parentType, child)) { onProcessChild(child); } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/LayerUtility.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/LayerUtility.cs index 586b32a2d5e..edee92d883a 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/LayerUtility.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Utility/LayerUtility.cs @@ -217,7 +217,7 @@ public static void GetFilterSettings(Renderer2DData rendererData, ref LayerBatch { filterSettings = FilteringSettings.defaultValue; filterSettings.renderQueueRange = RenderQueueRange.all; - filterSettings.layerMask = -1; + filterSettings.layerMask = rendererData.layerMask; filterSettings.renderingLayerMask = 0xFFFFFFFF; filterSettings.sortingLayerRange = layerBatch.layerRange; } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Renderer2DData.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Renderer2DData.cs index e561721c773..d3bc0b7af17 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Renderer2DData.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Renderer2DData.cs @@ -25,6 +25,9 @@ internal enum Renderer2DDefaultMaterialType Custom } + [SerializeField] + LayerMask m_LayerMask = -1; + [SerializeField] TransparencySortMode m_TransparencySortMode = TransparencySortMode.Default; @@ -80,6 +83,7 @@ internal enum Renderer2DDefaultMaterialType internal bool useCameraSortingLayerTexture => m_UseCameraSortingLayersTexture; internal int cameraSortingLayerTextureBound => m_CameraSortingLayersTextureBound; internal Downsampling cameraSortingLayerDownsamplingMethod => m_CameraSortingLayerDownsamplingMethod; + internal LayerMask layerMask => m_LayerMask; /// /// Creates the instance of the Renderer2D. 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 06bbea1f30e..463a2d7881c 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 @@ -265,7 +265,6 @@ public void Render(RenderGraph graph, ContextContainer frameData, Renderer2DData passData.isVolumetric = isVolumetric; passData.normalMap = layerBatch.lightStats.useNormalMap ? universal2DResourceData.normalsTexture[batchIndex] : TextureHandle.nullHandle; - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); builder.SetRenderFunc((PassData data, UnsafeGraphContext context) => @@ -309,7 +308,6 @@ public void Render(RenderGraph graph, ContextContainer frameData, Renderer2DData passData.isVolumetric = isVolumetric; passData.normalMap = layerBatch.lightStats.useNormalMap ? universal2DResourceData.normalsTexture[batchIndex] : TextureHandle.nullHandle; - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); builder.SetRenderFunc((PassData data, RasterGraphContext context) => diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawRenderer2DPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawRenderer2DPass.cs index 1e4c00e4dc1..7c034d71162 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawRenderer2DPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawRenderer2DPass.cs @@ -104,7 +104,6 @@ public void Render(RenderGraph graph, ContextContainer frameData, Renderer2DData SetGlobalLightTextures(graph, builder, passData.lightTextures, cameraData, ref layerBatch, rendererData); - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); builder.SetRenderFunc((SetGlobalPassData data, RasterGraphContext context) => @@ -152,7 +151,6 @@ public void Render(RenderGraph graph, ContextContainer frameData, Renderer2DData builder.SetRenderAttachment(commonResourceData.activeColorTexture, 0); builder.SetRenderAttachmentDepth(commonResourceData.activeDepthTexture); - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); builder.UseAllGlobalTextures(true); @@ -194,7 +192,8 @@ void SetGlobalLightTextures(RenderGraph graph, IRasterRenderGraphBuilder builder } else if (rendererData.lightCullResult.IsSceneLit()) { - builder.SetGlobalTextureAfterPass(graph.defaultResources.blackTexture, Shader.PropertyToID(RendererLighting.k_ShapeLightTextureIDs[0])); + for (var i = 0; i < RendererLighting.k_ShapeLightTextureIDs.Length; i++) + builder.SetGlobalTextureAfterPass(graph.defaultResources.blackTexture, Shader.PropertyToID(RendererLighting.k_ShapeLightTextureIDs[i])); } } } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawShadow2DPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawShadow2DPass.cs index 24c1ea64d6a..1116cee424c 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawShadow2DPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/DrawShadow2DPass.cs @@ -62,7 +62,6 @@ public void Render(RenderGraph graph, ContextContainer frameData, Renderer2DData builder.UseTexture(passData.shadowDepth, AccessFlags.Write); - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); builder.SetRenderFunc((PassData data, UnsafeGraphContext context) => diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/GlobalPropertiesPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/GlobalPropertiesPass.cs index fb1e2c41f3d..2eafb72663d 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/GlobalPropertiesPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/GlobalPropertiesPass.cs @@ -41,7 +41,6 @@ internal static void Setup(RenderGraph graph, ContextContainer frameData, Render if (rendererData.useCameraSortingLayerTexture) builder.SetGlobalTextureAfterPass(universal2DResourceData.cameraSortingLayerTexture, CopyCameraSortingLayerPass.k_CameraSortingLayerTextureId); - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); builder.SetRenderFunc((PassData data, RasterGraphContext context) => diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/Renderer2DRendergraph.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/Renderer2DRendergraph.cs index d49e919ceee..1448578b59d 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/Renderer2DRendergraph.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Rendergraph/Renderer2DRendergraph.cs @@ -59,16 +59,28 @@ private RTHandle nextRenderGraphCameraColorHandle } } + private bool IsPixelPerfectCameraEnabled(UniversalCameraData cameraData) + { + cameraData.camera.TryGetComponent(out var ppc); + return ppc != null && ppc.enabled && ppc.cropFrame != PixelPerfectCamera.CropFrame.None; + } + ImportResourceSummary GetImportResourceSummary(RenderGraph renderGraph, UniversalCameraData cameraData) { ImportResourceSummary output = new ImportResourceSummary(); bool clearColor = cameraData.renderType == CameraRenderType.Base; bool clearDepth = cameraData.renderType == CameraRenderType.Base || cameraData.clearDepth; - bool clearBackbufferOnFirstUse = (cameraData.renderType == CameraRenderType.Base) && !m_CreateColorTexture; + + // Clear back buffer color if pixel perfect crop frame is used + // Non-base cameras the back buffer should never be cleared + bool ppcEnabled = IsPixelPerfectCameraEnabled(cameraData); + bool clearColorBackbufferOnFirstUse = (cameraData.renderType == CameraRenderType.Base) && (!m_CreateColorTexture || ppcEnabled); + bool clearDepthBackbufferOnFirstUse = (cameraData.renderType == CameraRenderType.Base) && !m_CreateColorTexture; // if the camera background type is "uninitialized" clear using a yellow color, so users can clearly understand the underlying behaviour Color cameraBackgroundColor = (cameraData.camera.clearFlags == CameraClearFlags.Nothing) ? Color.yellow : cameraData.backgroundColor; + Color backBufferBackgroundColor = ppcEnabled ? Color.black : cameraBackgroundColor; if (IsSceneFilteringEnabled(cameraData.camera)) { @@ -92,12 +104,12 @@ ImportResourceSummary GetImportResourceSummary(RenderGraph renderGraph, Universa output.cameraDepthParams.clearColor = cameraBackgroundColor; output.cameraDepthParams.discardOnLastUse = false; - output.backBufferColorParams.clearOnFirstUse = clearBackbufferOnFirstUse; - output.backBufferColorParams.clearColor = cameraBackgroundColor; + output.backBufferColorParams.clearOnFirstUse = clearColorBackbufferOnFirstUse; + output.backBufferColorParams.clearColor = backBufferBackgroundColor; output.backBufferColorParams.discardOnLastUse = false; - output.backBufferDepthParams.clearOnFirstUse = clearBackbufferOnFirstUse; - output.backBufferDepthParams.clearColor = cameraBackgroundColor; + output.backBufferDepthParams.clearOnFirstUse = clearDepthBackbufferOnFirstUse; + output.backBufferDepthParams.clearColor = backBufferBackgroundColor; output.backBufferDepthParams.discardOnLastUse = true; if (cameraData.targetTexture != null) @@ -620,8 +632,7 @@ private void OnAfterRendering(RenderGraph renderGraph) bool anyPostProcessing = postProcessingData.isEnabled && m_PostProcessPasses.isCreated; cameraData.camera.TryGetComponent(out var ppc); - bool isPixelPerfectCameraEnabled = ppc != null && ppc.enabled && ppc.cropFrame != PixelPerfectCamera.CropFrame.None; - bool requirePixelPerfectUpscale = isPixelPerfectCameraEnabled && ppc.requiresUpscalePass; + bool requirePixelPerfectUpscale = IsPixelPerfectCameraEnabled(cameraData) && ppc.requiresUpscalePass; // When using Upscale Render Texture on a Pixel Perfect Camera, we want all post-processing effects done with a low-res RT, // and only upscale the low-res RT to fullscreen when blitting it to camera target. Also, final post processing pass is not run in this case, diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowCaster2D.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowCaster2D.cs index 73f5622be63..6f106123cad 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowCaster2D.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowCaster2D.cs @@ -197,7 +197,7 @@ public ShadowCastingOptions castingOption /// /// If selfShadows is true, useRendererSilhoutte specifies that the renderer's sihouette should be considered part of the shadow. If selfShadows is false, useRendererSilhoutte specifies that the renderer's sihouette should be excluded from the shadow /// - [Obsolete("useRendererSilhoutte is deprecated. Use rendererSilhoutte instead")] + [Obsolete("useRendererSilhoutte is deprecated. Use selfShadows instead")] public bool useRendererSilhouette { set { m_UseRendererSilhouette = value; } @@ -405,7 +405,7 @@ private void Awake() protected void OnEnable() { if (m_ShadowShape2DProvider != null) - m_ShadowShape2DProvider.Enabled(m_ShadowShape2DComponent); + m_ShadowShape2DProvider.Enabled(m_ShadowShape2DComponent, m_ShadowMesh); m_ShadowCasterGroup = null; @@ -423,7 +423,7 @@ protected void OnDisable() ShadowCasterGroup2DManager.RemoveFromShadowCasterGroup(this, m_ShadowCasterGroup); if (m_ShadowShape2DProvider != null) - m_ShadowShape2DProvider.Disabled(m_ShadowShape2DComponent); + m_ShadowShape2DProvider.Disabled(m_ShadowShape2DComponent, m_ShadowMesh); #if UNITY_EDITOR SortingLayer.onLayerAdded -= OnSortingLayerAdded; diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowProvider/Providers/ShadowShape2DProvider_SpriteRenderer.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowProvider/Providers/ShadowShape2DProvider_SpriteRenderer.cs index 1f4cb30ce92..0a95d24f37c 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowProvider/Providers/ShadowShape2DProvider_SpriteRenderer.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowProvider/Providers/ShadowShape2DProvider_SpriteRenderer.cs @@ -111,8 +111,7 @@ public override void OnPersistantDataCreated(Component sourceComponent, ShadowSh { SpriteRenderer spriteRenderer = (SpriteRenderer)sourceComponent; - m_PersistantShapeData = persistantShadowShape; - spriteRenderer.RegisterSpriteChangeCallback(UpdatePersistantShapeData); + m_PersistantShapeData = persistantShadowShape as ShadowMesh2D; if (spriteRenderer.sprite != null) { @@ -129,5 +128,19 @@ public override void OnBeforeRender(Component sourceComponent, Bounds worldCulli persistantShadowShape.SetFlip(spriteRenderer.flipX, spriteRenderer.flipY); TryToSetPersistantShapeData(spriteRenderer, persistantShadowShape, false); } + + public override void Enabled(Component sourceComponent, ShadowShape2D persistantShadowShape) + { + SpriteRenderer spriteRenderer = (SpriteRenderer)sourceComponent; + + m_PersistantShapeData = persistantShadowShape; + spriteRenderer.RegisterSpriteChangeCallback(UpdatePersistantShapeData); + } + + public override void Disabled(Component sourceComponent, ShadowShape2D persistantShadowShape) + { + SpriteRenderer spriteRenderer = (SpriteRenderer)sourceComponent; + spriteRenderer.UnregisterSpriteChangeCallback(UpdatePersistantShapeData); + } } } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowProvider/Providers/ShadowShape2DProvider_SpriteShape.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowProvider/Providers/ShadowShape2DProvider_SpriteShape.cs index 94fb0b921e0..c9220148a3f 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowProvider/Providers/ShadowShape2DProvider_SpriteShape.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowProvider/Providers/ShadowShape2DProvider_SpriteShape.cs @@ -65,12 +65,12 @@ internal void UpdateShadows(SpriteShapeController spriteShapeController, ShadowS public override int Priority() { return 10; } // give higher than default menu priority - public override void Enabled(Component sourceComponent) + public override void Enabled(Component sourceComponent, ShadowShape2D persistantShadowShape) { ((SpriteShapeController)sourceComponent).ForceShadowShapeUpdate(true); } - public override void Disabled(Component sourceComponent) + public override void Disabled(Component sourceComponent, ShadowShape2D persistantShadowShape) { ((SpriteShapeController)sourceComponent).ForceShadowShapeUpdate(false); } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowProvider/ShadowShape2DProvider.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowProvider/ShadowShape2DProvider.cs index eb75f7f31a6..80b18e26f0d 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowProvider/ShadowShape2DProvider.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowProvider/ShadowShape2DProvider.cs @@ -31,13 +31,15 @@ public abstract class ShadowShape2DProvider /// Called for the active ShadowShape2DProvider when the ShadowCaster2D becomes enabled /// /// The component associated with the provider - public virtual void Enabled(Component sourceComponent) {} + /// An instance of ShadowShape2D that is used by the ShadowCaster2D + public virtual void Enabled(Component sourceComponent, ShadowShape2D persistantShadowShape) {} /// /// Called for the active ShadowShape2DProvider when the ShadowCaster2D becomes disabled /// /// The component associated with the provider - public virtual void Disabled(Component sourceComponent) {} + /// An instance of ShadowShape2D that is used by the ShadowCaster2D + public virtual void Disabled(Component sourceComponent, ShadowShape2D persistantShadowShape) {} /// /// Called for each component on a ShadowCaster2D's GameObject. Returns true if the provided component is the data source of the ShadowShapeProvider. diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAsset.DefaultResources.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAsset.DefaultResources.cs index efafc3c419b..68af2ba6540 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAsset.DefaultResources.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAsset.DefaultResources.cs @@ -135,49 +135,82 @@ public override Shader defaultShader } } -#if UNITY_EDITOR - - #region Autodesk + #region Terrain /// - /// Returns the Autodesk Interactive shader that this asset uses. + /// Returns the terrain detail lit shader that this asset uses. /// - /// Returns the Autodesk Interactive shader that this asset uses. - public override Shader autodeskInteractiveShader => defaultShaders?.autodeskInteractiveShader; + public override Shader terrainDetailLitShader + { + get + { + if (GraphicsSettings.TryGetRenderPipelineSettings( + out var shadersResources)) + { + return shadersResources.terrainDetailLitShader; + } + + return null; + } + } /// - /// Returns the Autodesk Interactive transparent shader that this asset uses. + /// Returns the terrain detail grass shader that this asset uses. /// - /// Returns the Autodesk Interactive transparent shader that this asset uses. - public override Shader autodeskInteractiveTransparentShader => defaultShaders?.autodeskInteractiveTransparentShader; + public override Shader terrainDetailGrassShader + { + get + { + if (GraphicsSettings.TryGetRenderPipelineSettings( + out var shadersResources)) + { + return shadersResources.terrainDetailGrassShader; + } + + return null; + } + } /// - /// Returns the Autodesk Interactive mask shader that this asset uses. + /// Returns the terrain detail grass billboard shader that this asset uses. /// - /// Returns the Autodesk Interactive mask shader that this asset uses - public override Shader autodeskInteractiveMaskedShader => defaultShaders?.autodeskInteractiveMaskedShader; + public override Shader terrainDetailGrassBillboardShader + { + get + { + if (GraphicsSettings.TryGetRenderPipelineSettings( + out var shadersResources)) + { + return shadersResources.terrainDetailGrassBillboardShader; + } + + return null; + } + } #endregion - #region Terrain +#if UNITY_EDITOR + + #region Autodesk /// - /// Returns the terrain detail lit shader that this asset uses. + /// Returns the Autodesk Interactive shader that this asset uses. /// - /// Returns the terrain detail lit shader that this asset uses. - public override Shader terrainDetailLitShader => defaultShaders?.terrainDetailLitShader; + /// Returns the Autodesk Interactive shader that this asset uses. + public override Shader autodeskInteractiveShader => defaultShaders?.autodeskInteractiveShader; /// - /// Returns the terrain detail grass shader that this asset uses. + /// Returns the Autodesk Interactive transparent shader that this asset uses. /// - /// Returns the terrain detail grass shader that this asset uses. - public override Shader terrainDetailGrassShader => defaultShaders?.terrainDetailGrassShader; + /// Returns the Autodesk Interactive transparent shader that this asset uses. + public override Shader autodeskInteractiveTransparentShader => defaultShaders?.autodeskInteractiveTransparentShader; /// - /// Returns the terrain detail grass billboard shader that this asset uses. + /// Returns the Autodesk Interactive mask shader that this asset uses. /// - /// Returns the terrain detail grass billboard shader that this asset uses. - public override Shader terrainDetailGrassBillboardShader => defaultShaders?.terrainDetailGrassBillboardShader; + /// Returns the Autodesk Interactive mask shader that this asset uses + public override Shader autodeskInteractiveMaskedShader => defaultShaders?.autodeskInteractiveMaskedShader; #endregion diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Debug/DebugDisplaySettingsLighting.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Debug/DebugDisplaySettingsLighting.cs index 03a888db3ac..31fcceb8ea0 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Debug/DebugDisplaySettingsLighting.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Debug/DebugDisplaySettingsLighting.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Reflection; using UnityEngine; using NameAndTooltip = UnityEngine.Rendering.DebugUI.Widget.NameAndTooltip; @@ -7,6 +8,7 @@ namespace UnityEngine.Rendering.Universal /// /// Lighting-related Rendering Debugger settings. /// + [URPHelpURL("features/rendering-debugger-reference", "lighting")] public class DebugDisplaySettingsLighting : IDebugDisplaySettingsData { /// @@ -63,7 +65,6 @@ internal static class WidgetFactory } [DisplayInfo(name = "Lighting", order = 3)] - [URPHelpURL("features/rendering-debugger-reference", "lighting")] internal class SettingsPanel : DebugDisplaySettingsPanel { public SettingsPanel(DebugDisplaySettingsLighting data) @@ -82,7 +83,8 @@ public SettingsPanel(DebugDisplaySettingsLighting data) WidgetFactory.CreateLightingDebugMode(this), WidgetFactory.CreateHDRDebugMode(this), WidgetFactory.CreateLightingFeatures(this) - } + }, + documentationUrl = typeof(DebugDisplaySettingsLighting).GetCustomAttribute()?.URL }); } } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Debug/DebugHandler.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Debug/DebugHandler.cs index 8ac8e1c019f..5dd9f3492a6 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Debug/DebugHandler.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Debug/DebugHandler.cs @@ -438,7 +438,6 @@ internal void UpdateShaderGlobalPropertiesForFinalValidationPass(RenderGraph ren if (m_DebugFontTexture != null) passData.debugFontTextureHandle = renderGraph.ImportTexture(m_DebugFontTexture); - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); if (passData.debugRenderTargetHandle.IsValid()) @@ -538,7 +537,6 @@ internal void Setup(RenderGraph renderGraph, bool isPreviewCamera) using (var builder = renderGraph.AddRasterRenderPass(s_DebugSetupSampler.name, out var passData, s_DebugSetupSampler)) { InitDebugSetupPassData(passData, isPreviewCamera); - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); builder.SetRenderFunc(static (DebugSetupPassData data, RasterGraphContext context) => { diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Decal/DBuffer/DBufferRenderPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Decal/DBuffer/DBufferRenderPass.cs index f739bec90be..7fa4078e103 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Decal/DBuffer/DBufferRenderPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Decal/DBuffer/DBufferRenderPass.cs @@ -294,7 +294,6 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer builder.SetGlobalTextureAfterPass(dbufferHandles[i], Shader.PropertyToID(s_DBufferNames[i])); } - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); builder.SetRenderFunc((PassData data, RasterGraphContext rgContext) => diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/ForwardLights.cs b/Packages/com.unity.render-pipelines.universal/Runtime/ForwardLights.cs index e6e5e141728..725db6cdd9a 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/ForwardLights.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/ForwardLights.cs @@ -158,13 +158,19 @@ void CreateForwardPlusBuffers() static int AlignByteCount(int count, int align) => align * ((count + align - 1) / align); // Calculate view planes and viewToViewportScaleBias. This handles projection center in case the projection is off-centered - void GetViewParams(Camera camera, float4x4 viewToClip, out float viewPlaneBot, out float viewPlaneTop, out float4 viewToViewportScaleBias) + static void GetViewParams( + bool isOrthographic, + float4x4 viewToClip, + out float viewPlaneBot, + out float viewPlaneTop, + out float4 viewToViewportScaleBias + ) { // We want to calculate `fovHalfHeight = tan(fov / 2)` // `projection[1][1]` contains `1 / tan(fov / 2)` var viewPlaneHalfSizeInv = math.float2(viewToClip[0][0], viewToClip[1][1]); var viewPlaneHalfSize = math.rcp(viewPlaneHalfSizeInv); - var centerClipSpace = camera.orthographic ? -math.float2(viewToClip[3][0], viewToClip[3][1]): math.float2(viewToClip[2][0], viewToClip[2][1]); + var centerClipSpace = isOrthographic ? -math.float2(viewToClip[3][0], viewToClip[3][1]): math.float2(viewToClip[2][0], viewToClip[2][1]); viewPlaneBot = centerClipSpace.y * viewPlaneHalfSize.y - viewPlaneHalfSize.y; viewPlaneTop = centerClipSpace.y * viewPlaneHalfSize.y + viewPlaneHalfSize.y; @@ -174,6 +180,180 @@ void GetViewParams(Camera camera, float4x4 viewToClip, out float viewPlaneBot, o ); } + /// + /// This function is a purely functional (i.e. no global state mutation) + /// way of invoking light clustering. It is used while actual rendering, + /// but also in unit testing. + /// + internal static JobHandle ScheduleClusteringJobs( + NativeArray lights, + NativeArray probes, + NativeArray zBins, + NativeArray tileMasks, + Fixed2 worldToViews, + Fixed2 viewToClips, + int viewCount, + int2 screenResolution, + float nearClipPlane, + float farClipPlane, + bool isOrthographic, + out int localLightCount, + out int directionalLightCount, + out int binCount, + out float zBinScale, + out float zBinOffset, + out int2 tileResolution, + out int actualTileWidth, + out int wordsPerTile + ) + { + localLightCount = lights.Length; + // The lights array first has directional lights, and then local lights. We traverse the list to find the + // index of the first local light. + var firstLocalLightIdx = 0; + while (firstLocalLightIdx < localLightCount && lights[firstLocalLightIdx].lightType == LightType.Directional) + { + firstLocalLightIdx++; + } + localLightCount -= firstLocalLightIdx; + + // If there's 1 or more directional lights, one of them must be the main light + directionalLightCount = firstLocalLightIdx > 0 ? firstLocalLightIdx - 1 : 0; + + var localLights = lights.GetSubArray(firstLocalLightIdx, localLightCount); + + var reflectionProbeCount = math.min(probes.Length, UniversalRenderPipeline.maxVisibleReflectionProbes); + var itemsPerTile = localLights.Length + reflectionProbeCount; + wordsPerTile = (itemsPerTile + 31) / 32; + + actualTileWidth = 8 >> 1; + do + { + actualTileWidth <<= 1; + tileResolution = (screenResolution + actualTileWidth - 1) / actualTileWidth; + } + while ((tileResolution.x * tileResolution.y * wordsPerTile * viewCount) > UniversalRenderPipeline.maxTileWords); + + if (!isOrthographic) + { + // Use to calculate binIndex = log2(z) * zBinScale + zBinOffset + zBinScale = (UniversalRenderPipeline.maxZBinWords / viewCount) / ((math.log2(farClipPlane) - math.log2(nearClipPlane)) * (2 + wordsPerTile)); + zBinOffset = -math.log2(nearClipPlane) * zBinScale; + binCount = (int)(math.log2(farClipPlane) * zBinScale + zBinOffset); + } + else + { + // Use to calculate binIndex = z * zBinScale + zBinOffset + zBinScale = (UniversalRenderPipeline.maxZBinWords / viewCount) / ((farClipPlane - nearClipPlane) * (2 + wordsPerTile)); + zBinOffset = -nearClipPlane * zBinScale; + binCount = (int)(farClipPlane * zBinScale + zBinOffset); + } + + // Necessary to avoid negative bin count when the farClipPlane is set to Infinity in the editor. + binCount = Math.Max(binCount, 0); + + // Should probe come after otherProbe? + static bool IsProbeGreater(VisibleReflectionProbe probe, VisibleReflectionProbe otherProbe) + { + return probe.importance < otherProbe.importance || + (probe.importance == otherProbe.importance && probe.bounds.extents.sqrMagnitude > otherProbe.bounds.extents.sqrMagnitude); + } + + for (var i = 1; i < reflectionProbeCount; i++) + { + var probe = probes[i]; + var j = i - 1; + while (j >= 0 && IsProbeGreater(probes[j], probe)) + { + probes[j + 1] = probes[j]; + j--; + } + + probes[j + 1] = probe; + } + + var minMaxZs = new NativeArray(itemsPerTile * viewCount, Allocator.TempJob); + + var lightMinMaxZJob = new LightMinMaxZJob + { + worldToViews = worldToViews, + lights = localLights, + minMaxZs = minMaxZs.GetSubArray(0, localLightCount * viewCount) + }; + // Innerloop batch count of 32 is not special, just a handwavy amount to not have too much scheduling overhead nor too little parallelism. + var lightMinMaxZHandle = lightMinMaxZJob.ScheduleParallel(localLightCount * viewCount, 32, new JobHandle()); + + var reflectionProbeMinMaxZJob = new ReflectionProbeMinMaxZJob + { + worldToViews = worldToViews, + reflectionProbes = probes, + minMaxZs = minMaxZs.GetSubArray(localLightCount * viewCount, reflectionProbeCount * viewCount) + }; + var reflectionProbeMinMaxZHandle = reflectionProbeMinMaxZJob.ScheduleParallel(reflectionProbeCount * viewCount, 32, lightMinMaxZHandle); + + + var zBinningBatchCount = (binCount + ZBinningJob.batchSize - 1) / ZBinningJob.batchSize; + var zBinningJob = new ZBinningJob + { + bins = zBins, + minMaxZs = minMaxZs, + zBinScale = zBinScale, + zBinOffset = zBinOffset, + binCount = binCount, + wordsPerTile = wordsPerTile, + lightCount = localLightCount, + reflectionProbeCount = reflectionProbeCount, + batchCount = zBinningBatchCount, + viewCount = viewCount, + isOrthographic = isOrthographic + }; + var zBinningHandle = zBinningJob.ScheduleParallel(zBinningBatchCount * viewCount, 1, reflectionProbeMinMaxZHandle); + + reflectionProbeMinMaxZHandle.Complete(); + + GetViewParams(isOrthographic, viewToClips[0], out float viewPlaneBottom0, out float viewPlaneTop0, out float4 viewToViewportScaleBias0); + GetViewParams(isOrthographic, viewToClips[1], out float viewPlaneBottom1, out float viewPlaneTop1, out float4 viewToViewportScaleBias1); + + // Each light needs 1 range for Y, and a range per row. Align to 128-bytes to avoid false sharing. + var rangesPerItem = AlignByteCount((1 + tileResolution.y) * UnsafeUtility.SizeOf(), 128) / UnsafeUtility.SizeOf(); + var tileRanges = new NativeArray(rangesPerItem * itemsPerTile * viewCount, Allocator.TempJob); + var tilingJob = new TilingJob + { + lights = localLights, + reflectionProbes = probes, + tileRanges = tileRanges, + itemsPerTile = itemsPerTile, + rangesPerItem = rangesPerItem, + worldToViews = worldToViews, + tileScale = (float2)screenResolution / actualTileWidth, + tileScaleInv = actualTileWidth / (float2)screenResolution, + viewPlaneBottoms = new Fixed2(viewPlaneBottom0, viewPlaneBottom1), + viewPlaneTops = new Fixed2(viewPlaneTop0, viewPlaneTop1), + viewToViewportScaleBiases = new Fixed2(viewToViewportScaleBias0, viewToViewportScaleBias1), + tileCount = tileResolution, + near = nearClipPlane, + isOrthographic = isOrthographic + }; + + var tileRangeHandle = tilingJob.ScheduleParallel(itemsPerTile * viewCount, 1, reflectionProbeMinMaxZHandle); + + var expansionJob = new TileRangeExpansionJob + { + tileRanges = tileRanges, + tileMasks = tileMasks, + rangesPerItem = rangesPerItem, + itemsPerTile = itemsPerTile, + wordsPerTile = wordsPerTile, + tileResolution = tileResolution, + }; + + var tilingHandle = expansionJob.ScheduleParallel(tileResolution.y * viewCount, 1, tileRangeHandle); + JobHandle cullingHandle = JobHandle.CombineDependencies( + minMaxZs.Dispose(zBinningHandle), + tileRanges.Dispose(tilingHandle)); + return cullingHandle; + } + internal void PreSetup(UniversalRenderingData renderingData, UniversalCameraData cameraData, UniversalLightData lightData) { if (m_UseForwardPlus) @@ -202,159 +382,36 @@ internal void PreSetup(UniversalRenderingData renderingData, UniversalCameraData } } - var camera = cameraData.camera; - - var screenResolution = math.int2(cameraData.pixelWidth, cameraData.pixelHeight); #if ENABLE_VR && ENABLE_XR_MODULE var viewCount = cameraData.xr.enabled && cameraData.xr.singlePassEnabled ? 2 : 1; #else var viewCount = 1; #endif - m_LightCount = lightData.visibleLights.Length; - var lightOffset = 0; - while (lightOffset < m_LightCount && lightData.visibleLights[lightOffset].lightType == LightType.Directional) - { - lightOffset++; - } - m_LightCount -= lightOffset; - - // If there's 1 or more directional lights, one of them must be the main light - m_DirectionalLightCount = lightOffset > 0 ? lightOffset - 1 : 0; - - var visibleLights = lightData.visibleLights.GetSubArray(lightOffset, m_LightCount); - var reflectionProbes = renderingData.cullResults.visibleReflectionProbes; - var reflectionProbeCount = math.min(reflectionProbes.Length, UniversalRenderPipeline.maxVisibleReflectionProbes); - var itemsPerTile = visibleLights.Length + reflectionProbeCount; - m_WordsPerTile = (itemsPerTile + 31) / 32; - - m_ActualTileWidth = 8 >> 1; - do - { - m_ActualTileWidth <<= 1; - m_TileResolution = (screenResolution + m_ActualTileWidth - 1) / m_ActualTileWidth; - } - while ((m_TileResolution.x * m_TileResolution.y * m_WordsPerTile * viewCount) > UniversalRenderPipeline.maxTileWords); - - if (!camera.orthographic) - { - // Use to calculate binIndex = log2(z) * zBinScale + zBinOffset - m_ZBinScale = (UniversalRenderPipeline.maxZBinWords / viewCount) / ((math.log2(camera.farClipPlane) - math.log2(camera.nearClipPlane)) * (2 + m_WordsPerTile)); - m_ZBinOffset = -math.log2(camera.nearClipPlane) * m_ZBinScale; - m_BinCount = (int)(math.log2(camera.farClipPlane) * m_ZBinScale + m_ZBinOffset); - } - else - { - // Use to calculate binIndex = z * zBinScale + zBinOffset - m_ZBinScale = (UniversalRenderPipeline.maxZBinWords / viewCount) / ((camera.farClipPlane - camera.nearClipPlane) * (2 + m_WordsPerTile)); - m_ZBinOffset = -camera.nearClipPlane * m_ZBinScale; - m_BinCount = (int)(camera.farClipPlane * m_ZBinScale + m_ZBinOffset); - } - - // Necessary to avoid negative bin count when the farClipPlane is set to Infinity in the editor. - m_BinCount = Math.Max(m_BinCount, 0); - var worldToViews = new Fixed2(cameraData.GetViewMatrix(0), cameraData.GetViewMatrix(math.min(1, viewCount - 1))); var viewToClips = new Fixed2(cameraData.GetProjectionMatrix(0), cameraData.GetProjectionMatrix(math.min(1, viewCount - 1))); - // Should probe come after otherProbe? - static bool IsProbeGreater(VisibleReflectionProbe probe, VisibleReflectionProbe otherProbe) - { - return probe.importance < otherProbe.importance || - (probe.importance == otherProbe.importance && probe.bounds.extents.sqrMagnitude > otherProbe.bounds.extents.sqrMagnitude); - } - - for (var i = 1; i < reflectionProbeCount; i++) - { - var probe = reflectionProbes[i]; - var j = i - 1; - while (j >= 0 && IsProbeGreater(reflectionProbes[j], probe)) - { - reflectionProbes[j + 1] = reflectionProbes[j]; - j--; - } - - reflectionProbes[j + 1] = probe; - } - - var minMaxZs = new NativeArray(itemsPerTile * viewCount, Allocator.TempJob); - - var lightMinMaxZJob = new LightMinMaxZJob - { - worldToViews = worldToViews, - lights = visibleLights, - minMaxZs = minMaxZs.GetSubArray(0, m_LightCount * viewCount) - }; - // Innerloop batch count of 32 is not special, just a handwavy amount to not have too much scheduling overhead nor too little parallelism. - var lightMinMaxZHandle = lightMinMaxZJob.ScheduleParallel(m_LightCount * viewCount, 32, new JobHandle()); - - var reflectionProbeMinMaxZJob = new ReflectionProbeMinMaxZJob - { - worldToViews = worldToViews, - reflectionProbes = reflectionProbes, - minMaxZs = minMaxZs.GetSubArray(m_LightCount * viewCount, reflectionProbeCount * viewCount) - }; - var reflectionProbeMinMaxZHandle = reflectionProbeMinMaxZJob.ScheduleParallel(reflectionProbeCount * viewCount, 32, lightMinMaxZHandle); - - var zBinningBatchCount = (m_BinCount + ZBinningJob.batchSize - 1) / ZBinningJob.batchSize; - var zBinningJob = new ZBinningJob - { - bins = m_ZBins, - minMaxZs = minMaxZs, - zBinScale = m_ZBinScale, - zBinOffset = m_ZBinOffset, - binCount = m_BinCount, - wordsPerTile = m_WordsPerTile, - lightCount = m_LightCount, - reflectionProbeCount = reflectionProbeCount, - batchCount = zBinningBatchCount, - viewCount = viewCount, - isOrthographic = camera.orthographic - }; - var zBinningHandle = zBinningJob.ScheduleParallel(zBinningBatchCount * viewCount, 1, reflectionProbeMinMaxZHandle); - - reflectionProbeMinMaxZHandle.Complete(); - - GetViewParams(camera, viewToClips[0], out float viewPlaneBottom0, out float viewPlaneTop0, out float4 viewToViewportScaleBias0); - GetViewParams(camera, viewToClips[1], out float viewPlaneBottom1, out float viewPlaneTop1, out float4 viewToViewportScaleBias1); - - // Each light needs 1 range for Y, and a range per row. Align to 128-bytes to avoid false sharing. - var rangesPerItem = AlignByteCount((1 + m_TileResolution.y) * UnsafeUtility.SizeOf(), 128) / UnsafeUtility.SizeOf(); - var tileRanges = new NativeArray(rangesPerItem * itemsPerTile * viewCount, Allocator.TempJob); - var tilingJob = new TilingJob - { - lights = visibleLights, - reflectionProbes = reflectionProbes, - tileRanges = tileRanges, - itemsPerTile = itemsPerTile, - rangesPerItem = rangesPerItem, - worldToViews = worldToViews, - tileScale = (float2)screenResolution / m_ActualTileWidth, - tileScaleInv = m_ActualTileWidth / (float2)screenResolution, - viewPlaneBottoms = new Fixed2(viewPlaneBottom0, viewPlaneBottom1), - viewPlaneTops = new Fixed2(viewPlaneTop0, viewPlaneTop1), - viewToViewportScaleBiases = new Fixed2(viewToViewportScaleBias0, viewToViewportScaleBias1), - tileCount = m_TileResolution, - near = camera.nearClipPlane, - isOrthographic = camera.orthographic - }; - - var tileRangeHandle = tilingJob.ScheduleParallel(itemsPerTile * viewCount, 1, reflectionProbeMinMaxZHandle); - - var expansionJob = new TileRangeExpansionJob - { - tileRanges = tileRanges, - tileMasks = m_TileMasks, - rangesPerItem = rangesPerItem, - itemsPerTile = itemsPerTile, - wordsPerTile = m_WordsPerTile, - tileResolution = m_TileResolution, - }; - - var tilingHandle = expansionJob.ScheduleParallel(m_TileResolution.y * viewCount, 1, tileRangeHandle); - m_CullingHandle = JobHandle.CombineDependencies( - minMaxZs.Dispose(zBinningHandle), - tileRanges.Dispose(tilingHandle)); + m_CullingHandle = ScheduleClusteringJobs( + lightData.visibleLights, + renderingData.cullResults.visibleReflectionProbes, + m_ZBins, + m_TileMasks, + worldToViews, + viewToClips, + viewCount, + math.int2(cameraData.pixelWidth, cameraData.pixelHeight), + cameraData.camera.nearClipPlane, + cameraData.camera.farClipPlane, + cameraData.camera.orthographic, + out m_LightCount, + out m_DirectionalLightCount, + out m_BinCount, + out m_ZBinScale, + out m_ZBinOffset, + out m_TileResolution, + out m_ActualTileWidth, + out m_WordsPerTile + ); JobHandle.ScheduleBatchedJobs(); } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/AdditionalLightsShadowCasterPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/AdditionalLightsShadowCasterPass.cs index 0f55988759a..2f9da5cd1e0 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/AdditionalLightsShadowCasterPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/AdditionalLightsShadowCasterPass.cs @@ -974,8 +974,6 @@ internal TextureHandle Render(RenderGraph graph, ContextContainer frameData) TextureDesc descriptor = shadowTexture.GetDescriptor(graph); passData.allocatedShadowAtlasSize = new Vector2Int(descriptor.width, descriptor.height); - // RENDERGRAPH TODO: Need this as shadowmap is only used as Global Texture and not a buffer, so would get culled by RG - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); if (shadowTexture.IsValid()) diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/CopyDepthPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/CopyDepthPass.cs index 137e37c7891..00f8991a4b8 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/CopyDepthPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/CopyDepthPass.cs @@ -19,7 +19,7 @@ public class CopyDepthPass : ScriptableRenderPass private RTHandle destination { get; set; } // TODO RENDERGRAPH: The Render method overwrites this property with -1 before doing anything else. It should only be used in Compatibility Mode! - internal int MssaSamples { get; set; } + internal int MsaaSamples { get; set; } // In some cases (Scene view, XR and etc.) we actually want to output to depth buffer // So this variable needs to be set to true to enable the correct copy shader semantic internal bool CopyToDepth { get; set; } @@ -75,7 +75,7 @@ public void Setup(RTHandle source, RTHandle destination) { this.source = source; this.destination = destination; - this.MssaSamples = -1; + this.MsaaSamples = -1; } /// @@ -125,7 +125,7 @@ public override void Execute(ScriptableRenderContext context, ref RenderingData var cameraData = renderingData.frameData.Get(); m_PassData.copyDepthMaterial = m_CopyDepthMaterial; - m_PassData.msaaSamples = MssaSamples; + m_PassData.msaaSamples = MsaaSamples; m_PassData.copyResolvedDepth = m_CopyResolvedDepth; m_PassData.copyToDepth = CopyToDepth || CopyToDepthXR; m_PassData.isDstBackbuffer = CopyToBackbuffer || CopyToDepthXR; @@ -158,17 +158,20 @@ private static void ExecutePass(RasterCommandBuffer cmd, PassData passData, RTHa using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.CopyDepth))) { int cameraSamples = 0; - if (msaaSamples == -1) + + // When depth resolve is supported and requested, or multisampled texture is not supported, force camera samples to 1 + if (copyResolvedDepth || SystemInfo.supportsMultisampledTextures == 0) + { + cameraSamples = 1; + } + else if (msaaSamples == -1) // RG path { - RTHandle sourceTex = source; - cameraSamples = sourceTex.rt.antiAliasing; + cameraSamples = source.rt.antiAliasing; } else + { cameraSamples = msaaSamples; - - // When depth resolve is supported or multisampled texture is not supported, set camera samples to 1 - if (SystemInfo.supportsMultisampledTextures == 0 || copyResolvedDepth) - cameraSamples = 1; + } switch (cameraSamples) { @@ -190,7 +193,7 @@ private static void ExecutePass(RasterCommandBuffer cmd, PassData passData, RTHa cmd.SetKeyword(ShaderGlobalKeywords.DepthMsaa8, false); break; - // MSAA disabled, auto resolve supported or ms textures not supported + // MSAA disabled, auto resolve supported, resolve texture requested, or ms textures not supported default: cmd.SetKeyword(ShaderGlobalKeywords.DepthMsaa2, false); cmd.SetKeyword(ShaderGlobalKeywords.DepthMsaa4, false); @@ -201,7 +204,7 @@ private static void ExecutePass(RasterCommandBuffer cmd, PassData passData, RTHa cmd.SetKeyword(ShaderGlobalKeywords._OUTPUT_DEPTH, copyToDepth); // We must perform a yflip if we're rendering into the backbuffer and we have a flipped source texture. - bool yflip = passData.cameraData.IsHandleYFlipped(source) && passData.isDstBackbuffer; + bool yflip = passData.isDstBackbuffer && passData.cameraData.IsHandleYFlipped(source); Vector2 viewportScale = source.useScaling ? new Vector2(source.rtHandleProperties.rtHandleScale.x, source.rtHandleProperties.rtHandleScale.y) : Vector2.one; Vector4 scaleBias = yflip ? new Vector4(viewportScale.x, -viewportScale.y, 0, viewportScale.y) : new Vector4(viewportScale.x, viewportScale.y, 0, 0); @@ -257,13 +260,13 @@ public void Render(RenderGraph renderGraph, ContextContainer frameData, TextureH public void Render(RenderGraph renderGraph, TextureHandle destination, TextureHandle source, UniversalResourceData resourceData, UniversalCameraData cameraData, bool bindAsCameraDepth = false, string passName = "Copy Depth") { // TODO RENDERGRAPH: should call the equivalent of Setup() to initialise everything correctly - MssaSamples = -1; + MsaaSamples = -1; - //Having a different pass name than profilingSampler.name is bad practice but this method was public before we cleaned up this naming + // Having a different pass name than profilingSampler.name is bad practice but this method was public before we cleaned up this naming using (var builder = renderGraph.AddRasterRenderPass(passName, out var passData, profilingSampler)) { passData.copyDepthMaterial = m_CopyDepthMaterial; - passData.msaaSamples = MssaSamples; + passData.msaaSamples = MsaaSamples; passData.cameraData = cameraData; passData.copyResolvedDepth = m_CopyResolvedDepth; passData.copyToDepth = CopyToDepth || CopyToDepthXR; @@ -304,8 +307,6 @@ public void Render(RenderGraph renderGraph, TextureHandle destination, TextureHa if (bindAsCameraDepth && destination.IsValid()) builder.SetGlobalTextureAfterPass(destination, ShaderConstants._CameraDepthTexture); - // TODO RENDERGRAPH: culling? force culling off for testing - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); builder.SetRenderFunc((PassData data, RasterGraphContext context) => diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/DeferredPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/DeferredPass.cs index 9cd57241662..eb2e42477fc 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/DeferredPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/DeferredPass.cs @@ -112,7 +112,6 @@ internal void Render(RenderGraph renderGraph, ContextContainer frameData, Textur } } - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); builder.SetRenderFunc((PassData data, RasterGraphContext context) => diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/DepthNormalOnlyPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/DepthNormalOnlyPass.cs index e151bb9d0a0..0a3dec13878 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/DepthNormalOnlyPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/DepthNormalOnlyPass.cs @@ -226,8 +226,6 @@ internal void Render(RenderGraph renderGraph, ContextContainer frameData, Textur if (setGlobalDepth) builder.SetGlobalTextureAfterPass(cameraDepthTexture, s_CameraDepthTextureID); - // TODO RENDERGRAPH: culling? force culling off for testing - builder.AllowPassCulling(false); // Required here because of RenderingLayerUtils.SetupProperties builder.AllowGlobalStateModification(true); diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/DepthOnlyPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/DepthOnlyPass.cs index febbf7605d9..292570578fa 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/DepthOnlyPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/DepthOnlyPass.cs @@ -140,8 +140,6 @@ internal void Render(RenderGraph renderGraph, ContextContainer frameData, ref Te if (setGlobalDepth) builder.SetGlobalTextureAfterPass(cameraDepthTexture, s_CameraDepthTextureID); - // TODO RENDERGRAPH: culling? force culling off for testing - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); if (cameraData.xr.enabled) builder.EnableFoveatedRasterization(cameraData.xr.supportsFoveatedRendering && cameraData.xrUniversal.canFoveateIntermediatePasses); diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/DrawObjectsPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/DrawObjectsPass.cs index 68e1fb17c8e..e430314f467 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/DrawObjectsPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/DrawObjectsPass.cs @@ -301,7 +301,6 @@ internal void Render(RenderGraph renderGraph, ContextContainer frameData, Textur builder.UseRendererList(passData.objectsWithErrorRendererListHdl); } - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); if (cameraData.xr.enabled) @@ -452,7 +451,6 @@ internal void Render(RenderGraph renderGraph, ContextContainer frameData, Textur builder.UseRendererList(passData.basePassData.objectsWithErrorRendererListHdl); } - builder.AllowPassCulling(false); // Required here because of RenderingLayerUtils.SetupProperties builder.AllowGlobalStateModification(true); diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/GBufferPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/GBufferPass.cs index 6594c1a6efd..db569365561 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/GBufferPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/GBufferPass.cs @@ -288,7 +288,6 @@ internal void Render(RenderGraph renderGraph, ContextContainer frameData, Textur builder.SetGlobalTextureAfterPass(resourceData.renderingLayersTexture, s_CameraRenderingLayersTextureID); } - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); builder.SetRenderFunc((PassData data, RasterGraphContext context) => diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/MainLightShadowCasterPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/MainLightShadowCasterPass.cs index 94dbc15c07a..3ee18b31856 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/MainLightShadowCasterPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/MainLightShadowCasterPass.cs @@ -458,8 +458,6 @@ internal TextureHandle Render(RenderGraph graph, ContextContainer frameData) shadowTexture = graph.defaultResources.defaultShadowTexture; } - // Need this as shadowmap is only used as Global Texture and not a buffer, so would get culled by RG - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); if (shadowTexture.IsValid()) diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/MotionVectorRenderPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/MotionVectorRenderPass.cs index 47f2c60bed8..97b388749cf 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/MotionVectorRenderPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/MotionVectorRenderPass.cs @@ -222,8 +222,6 @@ internal void Render(RenderGraph renderGraph, ContextContainer frameData, Textur { builder.UseAllGlobalTextures(true); - // TODO RENDERGRAPH: culling? force culling off for testing - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); if (cameraData.xr.enabled) builder.EnableFoveatedRasterization(cameraData.xr.supportsFoveatedRendering && cameraData.xrUniversal.canFoveateIntermediatePasses); @@ -280,7 +278,6 @@ internal static void SetRenderGraphMotionVectorGlobalMatrices(RenderGraph render passData.motionData = additionalCameraData.motionVectorsPersistentData; passData.xr = cameraData.xr; - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); builder.SetRenderFunc(static (MotionMatrixPassData data, RasterGraphContext context) => { diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPass.cs index 811586b292d..11faeacdc28 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPass.cs @@ -22,6 +22,8 @@ internal partial class PostProcessPass : ScriptableRenderPass RTHandle m_PongTexture; RTHandle[] m_BloomMipDown; RTHandle[] m_BloomMipUp; + string[] m_BloomMipDownName; + string[] m_BloomMipUpName; TextureHandle[] _BloomMipUp; TextureHandle[] _BloomMipDown; RTHandle m_BlendTexture; @@ -139,23 +141,19 @@ public PostProcessPass(RenderPassEvent evt, PostProcessData data, ref PostProces m_Data = data; m_Materials = new MaterialLibrary(data); - // Bloom pyramid shader ids - can't use a simple stackalloc in the bloom function as we - // unfortunately need to allocate strings - ShaderConstants._BloomMipUp = new int[k_MaxPyramidSize]; - ShaderConstants._BloomMipDown = new int[k_MaxPyramidSize]; m_BloomMipUp = new RTHandle[k_MaxPyramidSize]; m_BloomMipDown = new RTHandle[k_MaxPyramidSize]; + m_BloomMipDownName = new string[k_MaxPyramidSize]; + m_BloomMipUpName = new string[k_MaxPyramidSize]; + // Bloom pyramid TextureHandles _BloomMipUp = new TextureHandle[k_MaxPyramidSize]; _BloomMipDown = new TextureHandle[k_MaxPyramidSize]; for (int i = 0; i < k_MaxPyramidSize; i++) { - ShaderConstants._BloomMipUp[i] = Shader.PropertyToID("_BloomMipUp" + i); - ShaderConstants._BloomMipDown[i] = Shader.PropertyToID("_BloomMipDown" + i); - // Get name, will get Allocated with descriptor later - m_BloomMipUp[i] = RTHandles.Alloc(ShaderConstants._BloomMipUp[i], name: "_BloomMipUp" + i); - m_BloomMipDown[i] = RTHandles.Alloc(ShaderConstants._BloomMipDown[i], name: "_BloomMipDown" + i); + m_BloomMipUpName[i] = "_BloomMipUp" + i; + m_BloomMipDownName[i] = "_BloomMipDown" + i; } m_MRT2 = new RenderTargetIdentifier[2]; @@ -635,7 +633,7 @@ void Swap(ref ScriptableRenderer r) // Setup other effects constants SetupLensDistortion(m_Materials.uber, isSceneViewCamera); SetupChromaticAberration(m_Materials.uber); - SetupVignette(m_Materials.uber, cameraData.xr); + SetupVignette(m_Materials.uber, cameraData.xr, m_Descriptor.width, m_Descriptor.height); SetupColorGrading(cmd, ref renderingData, m_Materials.uber); // Only apply dithering & grain if there isn't a final pass. @@ -1257,8 +1255,8 @@ void DoMotionBlur(CommandBuffer cmd, RTHandle source, RTHandle destination, RTHa void DoPaniniProjection(Camera camera, CommandBuffer cmd, RTHandle source, RTHandle destination) { float distance = m_PaniniProjection.distance.value; - var viewExtents = CalcViewExtents(camera); - var cropExtents = CalcCropExtents(camera, distance); + var viewExtents = CalcViewExtents(camera, m_Descriptor.width, m_Descriptor.height); + var cropExtents = CalcCropExtents(camera, distance, m_Descriptor.width, m_Descriptor.height); float scaleX = cropExtents.x / viewExtents.x; float scaleY = cropExtents.y / viewExtents.y; @@ -1276,10 +1274,10 @@ void DoPaniniProjection(Camera camera, CommandBuffer cmd, RTHandle source, RTHan Blitter.BlitCameraTexture(cmd, source, destination, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, material, 0); } - Vector2 CalcViewExtents(Camera camera) + Vector2 CalcViewExtents(Camera camera, int width, int height) { float fovY = camera.fieldOfView * Mathf.Deg2Rad; - float aspect = m_Descriptor.width / (float)m_Descriptor.height; + float aspect = width / (float)height; float viewExtY = Mathf.Tan(0.5f * fovY); float viewExtX = aspect * viewExtY; @@ -1287,7 +1285,7 @@ Vector2 CalcViewExtents(Camera camera) return new Vector2(viewExtX, viewExtY); } - Vector2 CalcCropExtents(Camera camera, float d) + Vector2 CalcCropExtents(Camera camera, float d, int width, int height) { // given // S----------- E--X------- @@ -1313,7 +1311,7 @@ Vector2 CalcCropExtents(Camera camera, float d) float viewDist = 1f + d; - var projPos = CalcViewExtents(camera); + var projPos = CalcViewExtents(camera, width, height); var projHyp = Mathf.Sqrt(projPos.x * projPos.x + 1f); float cylDistMinusD = 1f / projHyp; @@ -1366,8 +1364,8 @@ void SetupBloom(CommandBuffer cmd, RTHandle source, Material uberMaterial, bool var desc = GetCompatibleDescriptor(tw, th, m_DefaultColorFormat); for (int i = 0; i < mipCount; i++) { - RenderingUtils.ReAllocateHandleIfNeeded(ref m_BloomMipUp[i], desc, FilterMode.Bilinear, TextureWrapMode.Clamp, name: m_BloomMipUp[i].name); - RenderingUtils.ReAllocateHandleIfNeeded(ref m_BloomMipDown[i], desc, FilterMode.Bilinear, TextureWrapMode.Clamp, name: m_BloomMipDown[i].name); + RenderingUtils.ReAllocateHandleIfNeeded(ref m_BloomMipUp[i], desc, FilterMode.Bilinear, TextureWrapMode.Clamp, name: m_BloomMipUpName[i]); + RenderingUtils.ReAllocateHandleIfNeeded(ref m_BloomMipDown[i], desc, FilterMode.Bilinear, TextureWrapMode.Clamp, name: m_BloomMipDownName[i]); desc.width = Mathf.Max(1, desc.width >> 1); desc.height = Mathf.Max(1, desc.height >> 1); } @@ -1485,11 +1483,11 @@ void SetupChromaticAberration(Material material) #region Vignette - void SetupVignette(Material material, XRPass xrPass) + void SetupVignette(Material material, XRPass xrPass, int width, int height) { var color = m_Vignette.color.value; var center = m_Vignette.center.value; - var aspectRatio = m_Descriptor.width / (float)m_Descriptor.height; + var aspectRatio = width / (float)height; #if ENABLE_VR && ENABLE_XR_MODULE @@ -1983,9 +1981,6 @@ static class ShaderConstants public static readonly int _FlareData5 = Shader.PropertyToID("_FlareData5"); public static readonly int _FullscreenProjMat = Shader.PropertyToID("_FullscreenProjMat"); - - public static int[] _BloomMipUp; - public static int[] _BloomMipDown; } #endregion diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPassRenderGraph.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPassRenderGraph.cs index 4f216d8390b..e79ad85437c 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPassRenderGraph.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPassRenderGraph.cs @@ -18,9 +18,7 @@ private class UpdateCameraResolutionPassData // This should be called immediately after the resolution changes mid-frame (typically after an upscaling operation). void UpdateCameraResolution(RenderGraph renderGraph, UniversalCameraData cameraData, Vector2Int newCameraTargetSize) { - // Update the local descriptor and the camera data descriptor to reflect post-upscaled sizes - m_Descriptor.width = newCameraTargetSize.x; - m_Descriptor.height = newCameraTargetSize.y; + // Update the camera data descriptor to reflect post-upscaled sizes cameraData.cameraTargetDescriptor.width = newCameraTargetSize.x; cameraData.cameraTargetDescriptor.height = newCameraTargetSize.y; @@ -29,9 +27,8 @@ void UpdateCameraResolution(RenderGraph renderGraph, UniversalCameraData cameraD { passData.newCameraTargetSize = newCameraTargetSize; - // This pass only modifies shader constants so we need to set some special flags to ensure it isn't culled or optimized away + // This pass only modifies shader constants builder.AllowGlobalStateModification(true); - builder.AllowPassCulling(false); builder.SetRenderFunc(static (UpdateCameraResolutionPassData data, UnsafeGraphContext ctx) => { @@ -48,6 +45,52 @@ void UpdateCameraResolution(RenderGraph renderGraph, UniversalCameraData cameraD } } + internal static TextureHandle CreateCompatibleTexture(RenderGraph renderGraph, in TextureHandle source, string name, bool clear, FilterMode filterMode) + { + var desc = source.GetDescriptor(renderGraph); + MakeCompatible(ref desc); + desc.name = name; + desc.clearBuffer = clear; + desc.filterMode = filterMode; + return renderGraph.CreateTexture(desc); + } + + internal static TextureHandle CreateCompatibleTexture(RenderGraph renderGraph, in TextureDesc desc, string name, bool clear, FilterMode filterMode) + { + var descCompatible = GetCompatibleDescriptor(desc); + descCompatible.name = name; + descCompatible.clearBuffer = clear; + descCompatible.filterMode = filterMode; + return renderGraph.CreateTexture(descCompatible); + } + + internal static TextureDesc GetCompatibleDescriptor(TextureDesc desc, int width, int height, GraphicsFormat format) + { + desc.width = width; + desc.height = height; + desc.format = format; + + MakeCompatible(ref desc); + + return desc; + } + + internal static TextureDesc GetCompatibleDescriptor(TextureDesc desc) + { + MakeCompatible(ref desc); + + return desc; + } + + internal static void MakeCompatible(ref TextureDesc desc) + { + desc.msaaSamples = MSAASamples.None; + desc.useMipMap = false; + desc.autoGenerateMips = false; + desc.anisoLevel = 0; + desc.discardBuffer = false; + } + #region StopNaNs private class StopNaNsPassData { @@ -56,15 +99,9 @@ private class StopNaNsPassData internal Material stopNaN; } - public void RenderStopNaN(RenderGraph renderGraph, RenderTextureDescriptor cameraTargetDescriptor, in TextureHandle activeCameraColor, out TextureHandle stopNaNTarget) + public void RenderStopNaN(RenderGraph renderGraph, in TextureHandle activeCameraColor, out TextureHandle stopNaNTarget) { - var desc = PostProcessPass.GetCompatibleDescriptor(cameraTargetDescriptor, - cameraTargetDescriptor.width, - cameraTargetDescriptor.height, - cameraTargetDescriptor.graphicsFormat, - GraphicsFormat.None); - - stopNaNTarget = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, "_StopNaNsTarget", true, FilterMode.Bilinear); + stopNaNTarget = CreateCompatibleTexture(renderGraph, activeCameraColor, "_StopNaNsTarget", true, FilterMode.Bilinear); using (var builder = renderGraph.AddRasterRenderPass("Stop NaNs", out var passData, ProfilingSampler.Get(URPProfileId.RG_StopNaNs))) @@ -99,7 +136,6 @@ private class SMAASetupPassData private class SMAAPassData { - internal TextureHandle destinationTexture; internal TextureHandle sourceTexture; internal TextureHandle depthStencilTexture; internal TextureHandle blendTexture; @@ -108,34 +144,24 @@ private class SMAAPassData public void RenderSMAA(RenderGraph renderGraph, UniversalResourceData resourceData, AntialiasingQuality antialiasingQuality, in TextureHandle source, out TextureHandle SMAATarget) { + var destDesc = renderGraph.GetTextureDesc(source); + + SMAATarget = CreateCompatibleTexture(renderGraph, destDesc, "_SMAATarget", true, FilterMode.Bilinear); + + destDesc.clearColor = Color.black; + destDesc.clearColor.a = 0.0f; + + var edgeTextureDesc = destDesc; + edgeTextureDesc.format = m_SMAAEdgeFormat; + var edgeTexture = CreateCompatibleTexture(renderGraph, edgeTextureDesc, "_EdgeStencilTexture", true, FilterMode.Bilinear); - var desc = PostProcessPass.GetCompatibleDescriptor(m_Descriptor, - m_Descriptor.width, - m_Descriptor.height, - m_Descriptor.graphicsFormat, - GraphicsFormat.None); - SMAATarget = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, "_SMAATarget", true, FilterMode.Bilinear); - - var edgeTextureDesc = PostProcessPass.GetCompatibleDescriptor(m_Descriptor, - m_Descriptor.width, - m_Descriptor.height, - m_SMAAEdgeFormat, - GraphicsFormat.None); - var edgeTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, edgeTextureDesc, "_EdgeStencilTexture", true, FilterMode.Bilinear); - - var edgeTextureStencilDesc = PostProcessPass.GetCompatibleDescriptor(m_Descriptor, - m_Descriptor.width, - m_Descriptor.height, - GraphicsFormat.None, - GraphicsFormatUtility.GetDepthStencilFormat(24)); - var edgeTextureStencil = UniversalRenderer.CreateRenderGraphTexture(renderGraph, edgeTextureStencilDesc, "_EdgeTexture", true, FilterMode.Bilinear); - - var blendTextureDesc = PostProcessPass.GetCompatibleDescriptor(m_Descriptor, - m_Descriptor.width, - m_Descriptor.height, - GraphicsFormat.R8G8B8A8_UNorm, - GraphicsFormat.None); - var blendTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, blendTextureDesc, "_BlendTexture", true, FilterMode.Point); + var edgeTextureStencilDesc = destDesc; + edgeTextureStencilDesc.format = GraphicsFormatUtility.GetDepthStencilFormat(24); + var edgeTextureStencil = CreateCompatibleTexture(renderGraph, edgeTextureStencilDesc, "_EdgeTexture", true, FilterMode.Bilinear); + + var blendTextureDesc = destDesc; + blendTextureDesc.format = GraphicsFormat.R8G8B8A8_UNorm; + var blendTexture = CreateCompatibleTexture(renderGraph, blendTextureDesc, "_BlendTexture", true, FilterMode.Point); // Anti-aliasing var material = m_Materials.subpixelMorphologicalAntialiasing; @@ -144,7 +170,7 @@ public void RenderSMAA(RenderGraph renderGraph, UniversalResourceData resourceDa { const int kStencilBit = 64; // TODO RENDERGRAPH: handle dynamic scaling - passData.metrics = new Vector4(1f / m_Descriptor.width, 1f / m_Descriptor.height, m_Descriptor.width, m_Descriptor.height); + passData.metrics = new Vector4(1f / destDesc.width, 1f / destDesc.height, destDesc.width, destDesc.height); passData.areaTexture = m_Data.textures.smaaAreaTex; passData.searchTexture = m_Data.textures.smaaSearchTex; passData.stencilRef = (float)kStencilBit; @@ -183,7 +209,6 @@ public void RenderSMAA(RenderGraph renderGraph, UniversalResourceData resourceDa using (var builder = renderGraph.AddRasterRenderPass("SMAA Edge Detection", out var passData, ProfilingSampler.Get(URPProfileId.RG_SMAAEdgeDetection))) { - passData.destinationTexture = edgeTexture; builder.SetRenderAttachment(edgeTexture, 0, AccessFlags.Write); passData.depthStencilTexture = edgeTextureStencil; builder.SetRenderAttachmentDepth(edgeTextureStencil, AccessFlags.Write); @@ -206,7 +231,6 @@ public void RenderSMAA(RenderGraph renderGraph, UniversalResourceData resourceDa using (var builder = renderGraph.AddRasterRenderPass("SMAA Blend weights", out var passData, ProfilingSampler.Get(URPProfileId.RG_SMAABlendWeight))) { - passData.destinationTexture = blendTexture; builder.SetRenderAttachment(blendTexture, 0, AccessFlags.Write); passData.depthStencilTexture = edgeTextureStencil; builder.SetRenderAttachmentDepth(edgeTextureStencil, AccessFlags.Read); @@ -229,7 +253,6 @@ public void RenderSMAA(RenderGraph renderGraph, UniversalResourceData resourceDa using (var builder = renderGraph.AddRasterRenderPass("SMAA Neighborhood blending", out var passData, ProfilingSampler.Get(URPProfileId.RG_SMAANeighborhoodBlend))) { builder.AllowGlobalStateModification(true); - passData.destinationTexture = SMAATarget; builder.SetRenderAttachment(SMAATarget, 0, AccessFlags.Write); passData.sourceTexture = source; builder.UseTexture(source, AccessFlags.Read); @@ -264,9 +287,9 @@ private class UberSetupBloomPassData internal Material uberMaterial; } - public void UberPostSetupBloomPass(RenderGraph rendergraph, in TextureHandle bloomTexture, Material uberMaterial) + public void UberPostSetupBloomPass(RenderGraph rendergraph, Material uberMaterial, in TextureDesc srcDesc) { - using (var builder = rendergraph.AddRasterRenderPass("Setup Bloom Post Processing", out var passData, ProfilingSampler.Get(URPProfileId.RG_UberPostSetupBloomPass))) + using (new ProfilingScope(ProfilingSampler.Get(URPProfileId.RG_UberPostSetupBloomPass))) { // Setup bloom on uber var tint = m_Bloom.tint.value.linear; @@ -279,7 +302,7 @@ public void UberPostSetupBloomPass(RenderGraph rendergraph, in TextureHandle blo // stretched or squashed var dirtTexture = m_Bloom.dirtTexture.value == null ? Texture2D.blackTexture : m_Bloom.dirtTexture.value; float dirtRatio = dirtTexture.width / (float)dirtTexture.height; - float screenRatio = m_Descriptor.width / (float)m_Descriptor.height; + float screenRatio = srcDesc.width / (float)srcDesc.height; var dirtScaleOffset = new Vector4(1f, 1f, 0f, 0f); float dirtIntensity = m_Bloom.dirtIntensity.value; @@ -294,35 +317,18 @@ public void UberPostSetupBloomPass(RenderGraph rendergraph, in TextureHandle blo dirtScaleOffset.w = (1f - dirtScaleOffset.y) * 0.5f; } - passData.bloomParams = bloomParams; - passData.dirtScaleOffset = dirtScaleOffset; - passData.dirtIntensity = dirtIntensity; - passData.dirtTexture = dirtTexture; - passData.highQualityFilteringValue = m_Bloom.highQualityFiltering.value; - - passData.bloomTexture = bloomTexture; - builder.UseTexture(bloomTexture, AccessFlags.Read); - passData.uberMaterial = uberMaterial; + var highQualityFilteringValue = m_Bloom.highQualityFiltering.value; - // TODO RENDERGRAPH: properly setup dependencies between passes - builder.AllowPassCulling(false); - - builder.SetRenderFunc(static (UberSetupBloomPassData data, RasterGraphContext context) => - { - var uberMaterial = data.uberMaterial; - uberMaterial.SetVector(ShaderConstants._Bloom_Params, data.bloomParams); - uberMaterial.SetVector(ShaderConstants._LensDirt_Params, data.dirtScaleOffset); - uberMaterial.SetFloat(ShaderConstants._LensDirt_Intensity, data.dirtIntensity); - uberMaterial.SetTexture(ShaderConstants._LensDirt_Texture, data.dirtTexture); - - // Keyword setup - a bit convoluted as we're trying to save some variants in Uber... - if (data.highQualityFilteringValue) - uberMaterial.EnableKeyword(data.dirtIntensity > 0f ? ShaderKeywordStrings.BloomHQDirt : ShaderKeywordStrings.BloomHQ); - else - uberMaterial.EnableKeyword(data.dirtIntensity > 0f ? ShaderKeywordStrings.BloomLQDirt : ShaderKeywordStrings.BloomLQ); + uberMaterial.SetVector(ShaderConstants._Bloom_Params, bloomParams); + uberMaterial.SetVector(ShaderConstants._LensDirt_Params, dirtScaleOffset); + uberMaterial.SetFloat(ShaderConstants._LensDirt_Intensity, dirtIntensity); + uberMaterial.SetTexture(ShaderConstants._LensDirt_Texture, dirtTexture); - uberMaterial.SetTexture(ShaderConstants._Bloom_Texture, data.bloomTexture); - }); + // Keyword setup - a bit convoluted as we're trying to save some variants in Uber... + if (highQualityFilteringValue) + uberMaterial.EnableKeyword(dirtIntensity > 0f ? ShaderKeywordStrings.BloomHQDirt : ShaderKeywordStrings.BloomHQ); + else + uberMaterial.EnableKeyword(dirtIntensity > 0f ? ShaderKeywordStrings.BloomLQDirt : ShaderKeywordStrings.BloomLQ); } } @@ -355,6 +361,8 @@ internal bool Equals(ref BloomMaterialParams other) public void RenderBloomTexture(RenderGraph renderGraph, in TextureHandle source, out TextureHandle destination, bool enableAlphaOutput) { + var srcDesc = source.GetDescriptor(renderGraph); + // Start at half-res int downres = 1; switch (m_Bloom.downscale.value) @@ -371,8 +379,8 @@ public void RenderBloomTexture(RenderGraph renderGraph, in TextureHandle source, //We should set the limit the downres result to ensure we dont turn 1x1 textures, which should technically be valid //into 0x0 textures which will be invalid - int tw = Mathf.Max(1, m_Descriptor.width >> downres); - int th = Mathf.Max(1, m_Descriptor.height >> downres); + int tw = Mathf.Max(1, srcDesc.width >> downres); + int th = Mathf.Max(1, srcDesc.height >> downres); // Determine the iteration count int maxSize = Mathf.Max(tw, th); @@ -420,9 +428,9 @@ public void RenderBloomTexture(RenderGraph renderGraph, in TextureHandle source, // Create bloom mip pyramid textures { - var desc = GetCompatibleDescriptor(tw, th, m_DefaultColorFormat); - _BloomMipDown[0] = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, m_BloomMipDown[0].name, false, FilterMode.Bilinear); - _BloomMipUp[0] = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, m_BloomMipUp[0].name, false, FilterMode.Bilinear); + var desc = GetCompatibleDescriptor(srcDesc, tw, th, m_DefaultColorFormat); + _BloomMipDown[0] = CreateCompatibleTexture(renderGraph, desc, m_BloomMipDownName[0], false, FilterMode.Bilinear); + _BloomMipUp[0] = CreateCompatibleTexture(renderGraph, desc, m_BloomMipUpName[0], false, FilterMode.Bilinear); for (int i = 1; i < mipCount; i++) { @@ -434,9 +442,8 @@ public void RenderBloomTexture(RenderGraph renderGraph, in TextureHandle source, desc.width = tw; desc.height = th; - // NOTE: Reuse RTHandle names for TextureHandles - mipDown = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, m_BloomMipDown[i].name, false, FilterMode.Bilinear); - mipUp = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, m_BloomMipUp[i].name, false, FilterMode.Bilinear); + mipDown = CreateCompatibleTexture(renderGraph, desc, m_BloomMipDownName[i], false, FilterMode.Bilinear); + mipUp = CreateCompatibleTexture(renderGraph, desc, m_BloomMipUpName[i], false, FilterMode.Bilinear); } } } @@ -526,12 +533,7 @@ public void RenderDoF(RenderGraph renderGraph, UniversalResourceData resourceDat { var dofMaterial = m_DepthOfField.mode.value == DepthOfFieldMode.Gaussian ? m_Materials.gaussianDepthOfField : m_Materials.bokehDepthOfField; - var desc = PostProcessPass.GetCompatibleDescriptor(m_Descriptor, - m_Descriptor.width, - m_Descriptor.height, - m_Descriptor.graphicsFormat, - GraphicsFormat.None); - destination = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, "_DoFTarget", true, FilterMode.Bilinear); + destination = CreateCompatibleTexture(renderGraph, source, "_DoFTarget", true, FilterMode.Bilinear); CoreUtils.SetKeyword(dofMaterial, ShaderKeywordStrings._ENABLE_ALPHA_OUTPUT, cameraData.isAlphaOutputEnabled); @@ -569,20 +571,22 @@ private class DoFGaussianPassData public void RenderDoFGaussian(RenderGraph renderGraph, UniversalResourceData resourceData, UniversalCameraData cameraData, in TextureHandle source, TextureHandle destination, ref Material dofMaterial) { + var srcDesc = source.GetDescriptor(renderGraph); + var material = dofMaterial; int downSample = 2; - int wh = m_Descriptor.width / downSample; - int hh = m_Descriptor.height / downSample; + int wh = srcDesc.width / downSample; + int hh = srcDesc.height / downSample; // Pass Textures - var fullCoCTextureDesc = PostProcessPass.GetCompatibleDescriptor(m_Descriptor, m_Descriptor.width, m_Descriptor.height, m_GaussianCoCFormat); - var fullCoCTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, fullCoCTextureDesc, "_FullCoCTexture", true, FilterMode.Bilinear); - var halfCoCTextureDesc = PostProcessPass.GetCompatibleDescriptor(m_Descriptor, wh, hh, m_GaussianCoCFormat); - var halfCoCTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, halfCoCTextureDesc, "_HalfCoCTexture", true, FilterMode.Bilinear); - var pingTextureDesc = PostProcessPass.GetCompatibleDescriptor(m_Descriptor, wh, hh, m_DefaultColorFormat); - var pingTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, pingTextureDesc, "_PingTexture", true, FilterMode.Bilinear); - var pongTextureDesc = PostProcessPass.GetCompatibleDescriptor(m_Descriptor, wh, hh, m_DefaultColorFormat); - var pongTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, pongTextureDesc, "_PongTexture", true, FilterMode.Bilinear); + var fullCoCTextureDesc = GetCompatibleDescriptor(srcDesc, srcDesc.width, srcDesc.height, m_GaussianCoCFormat); + var fullCoCTexture = CreateCompatibleTexture(renderGraph, fullCoCTextureDesc, "_FullCoCTexture", true, FilterMode.Bilinear); + var halfCoCTextureDesc = GetCompatibleDescriptor(srcDesc, wh, hh, m_GaussianCoCFormat); + var halfCoCTexture = CreateCompatibleTexture(renderGraph, halfCoCTextureDesc, "_HalfCoCTexture", true, FilterMode.Bilinear); + var pingTextureDesc = GetCompatibleDescriptor(srcDesc, wh, hh, m_DefaultColorFormat); + var pingTexture = CreateCompatibleTexture(renderGraph, pingTextureDesc, "_PingTexture", true, FilterMode.Bilinear); + var pongTextureDesc = GetCompatibleDescriptor(srcDesc, wh, hh, m_DefaultColorFormat); + var pongTexture = CreateCompatibleTexture(renderGraph, pongTextureDesc, "_PongTexture", true, FilterMode.Bilinear); using (var builder = renderGraph.AddUnsafePass("Depth of Field - Gaussian", out var passData)) { @@ -722,18 +726,20 @@ private class DoFBokehPassData public void RenderDoFBokeh(RenderGraph renderGraph, UniversalResourceData resourceData, UniversalCameraData cameraData, in TextureHandle source, in TextureHandle destination, ref Material dofMaterial) { + var srcDesc = source.GetDescriptor(renderGraph); + int downSample = 2; var material = dofMaterial; - int wh = m_Descriptor.width / downSample; - int hh = m_Descriptor.height / downSample; + int wh = srcDesc.width / downSample; + int hh = srcDesc.height / downSample; // Pass Textures - var fullCoCTextureDesc = PostProcessPass.GetCompatibleDescriptor(m_Descriptor, m_Descriptor.width, m_Descriptor.height, GraphicsFormat.R8_UNorm); - var fullCoCTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, fullCoCTextureDesc, "_FullCoCTexture", true, FilterMode.Bilinear); - var pingTextureDesc = PostProcessPass.GetCompatibleDescriptor(m_Descriptor, wh, hh, GraphicsFormat.R16G16B16A16_SFloat); - var pingTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, pingTextureDesc, "_PingTexture", true, FilterMode.Bilinear); - var pongTextureDesc = PostProcessPass.GetCompatibleDescriptor(m_Descriptor, wh, hh, GraphicsFormat.R16G16B16A16_SFloat); - var pongTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, pongTextureDesc, "_PongTexture", true, FilterMode.Bilinear); + var fullCoCTextureDesc = GetCompatibleDescriptor(srcDesc, srcDesc.width, srcDesc.height, GraphicsFormat.R8_UNorm); + var fullCoCTexture = CreateCompatibleTexture(renderGraph, fullCoCTextureDesc, "_FullCoCTexture", true, FilterMode.Bilinear); + var pingTextureDesc = GetCompatibleDescriptor(srcDesc, wh, hh, GraphicsFormat.R16G16B16A16_SFloat); + var pingTexture = CreateCompatibleTexture(renderGraph, pingTextureDesc, "_PingTexture", true, FilterMode.Bilinear); + var pongTextureDesc = GetCompatibleDescriptor(srcDesc, wh, hh, GraphicsFormat.R16G16B16A16_SFloat); + var pongTexture = CreateCompatibleTexture(renderGraph, pongTextureDesc, "_PongTexture", true, FilterMode.Bilinear); using (var builder = renderGraph.AddUnsafePass("Depth of Field - Bokeh", out var passData)) { @@ -743,7 +749,7 @@ public void RenderDoFBokeh(RenderGraph renderGraph, UniversalResourceData resour float A = m_DepthOfField.focalLength.value / m_DepthOfField.aperture.value; float P = m_DepthOfField.focusDistance.value; float maxCoC = (A * F) / (P - F); - float maxRadius = GetMaxBokehRadiusInPixels(m_Descriptor.height); + float maxRadius = GetMaxBokehRadiusInPixels(srcDesc.height); float rcpAspect = 1f / (wh / (float)hh); // Prepare the bokeh kernel constant buffer @@ -755,7 +761,7 @@ public void RenderDoFBokeh(RenderGraph renderGraph, UniversalResourceData resour m_BokehRCPAspect = rcpAspect; PrepareBokehKernel(maxRadius, rcpAspect); } - float uvMargin = (1.0f / m_Descriptor.height) * downSample; + float uvMargin = (1.0f / srcDesc.height) * downSample; passData.bokehKernel = m_BokehKernel; passData.downSample = downSample; @@ -854,7 +860,6 @@ private class PaniniProjectionPassData { internal TextureHandle destinationTexture; internal TextureHandle sourceTexture; - internal RenderTextureDescriptor sourceTextureDesc; internal Material material; internal Vector4 paniniParams; internal bool isPaniniGeneric; @@ -862,17 +867,13 @@ private class PaniniProjectionPassData public void RenderPaniniProjection(RenderGraph renderGraph, Camera camera, in TextureHandle source, out TextureHandle destination) { - var desc = PostProcessPass.GetCompatibleDescriptor(m_Descriptor, - m_Descriptor.width, - m_Descriptor.height, - m_Descriptor.graphicsFormat, - GraphicsFormat.None); - - destination = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, "_PaniniProjectionTarget", true, FilterMode.Bilinear); + destination = CreateCompatibleTexture(renderGraph, source, "_PaniniProjectionTarget", true, FilterMode.Bilinear); + // Use source width/height for aspect ratio which can be different from camera aspect. (e.g. viewport) + var desc = source.GetDescriptor(renderGraph); float distance = m_PaniniProjection.distance.value; - var viewExtents = CalcViewExtents(camera); - var cropExtents = CalcCropExtents(camera, distance); + var viewExtents = CalcViewExtents(camera, desc.width, desc.height); + var cropExtents = CalcCropExtents(camera, distance, desc.width, desc.height); float scaleX = cropExtents.x / viewExtents.x; float scaleY = cropExtents.y / viewExtents.y; @@ -891,7 +892,6 @@ public void RenderPaniniProjection(RenderGraph renderGraph, Camera camera, in Te passData.material = m_Materials.paniniProjection; passData.paniniParams = new Vector4(viewExtents.x, viewExtents.y, paniniD, paniniS); passData.isPaniniGeneric = 1f - Mathf.Abs(paniniD) > float.Epsilon; - passData.sourceTextureDesc = m_Descriptor; builder.SetRenderFunc(static (PaniniProjectionPassData data, RasterGraphContext context) => { @@ -915,12 +915,7 @@ public void RenderPaniniProjection(RenderGraph renderGraph, Camera camera, in Te private const string _TemporalAATargetName = "_TemporalAATarget"; private void RenderTemporalAA(RenderGraph renderGraph, UniversalResourceData resourceData, UniversalCameraData cameraData, ref TextureHandle source, out TextureHandle destination) { - var desc = PostProcessPass.GetCompatibleDescriptor(m_Descriptor, - m_Descriptor.width, - m_Descriptor.height, - m_Descriptor.graphicsFormat, - GraphicsFormat.None); - destination = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, _TemporalAATargetName, false, FilterMode.Bilinear); + destination = CreateCompatibleTexture(renderGraph, source, _TemporalAATargetName, false, FilterMode.Bilinear); TextureHandle cameraDepth = resourceData.cameraDepth; TextureHandle motionVectors = resourceData.motionVectorColor; @@ -933,7 +928,7 @@ private void RenderTemporalAA(RenderGraph renderGraph, UniversalResourceData res #region STP - private const string _UpscaledColorTargetName = "_UpscaledColorTarget"; + private const string _UpscaledColorTargetName = "_UpscaledCameraColor"; private void RenderSTP(RenderGraph renderGraph, UniversalResourceData resourceData, UniversalCameraData cameraData, ref TextureHandle source, out TextureHandle destination) { @@ -942,18 +937,18 @@ private void RenderSTP(RenderGraph renderGraph, UniversalResourceData resourceDa Debug.Assert(motionVectors.IsValid(), "MotionVectors are invalid. STP requires a motion vector texture."); - var desc = GetCompatibleDescriptor(cameraData.cameraTargetDescriptor, + var srcDesc = source.GetDescriptor(renderGraph); + + var destDesc = GetCompatibleDescriptor(srcDesc, cameraData.pixelWidth, cameraData.pixelHeight, - cameraData.cameraTargetDescriptor.graphicsFormat); + // Avoid enabling sRGB because STP works with compute shaders which can't output sRGB automatically. + GraphicsFormatUtility.GetLinearFormat(srcDesc.format)); // STP uses compute shaders so all render textures must enable random writes - desc.enableRandomWrite = true; - - // Avoid enabling sRGB because STP works with compute shaders which can't output sRGB automatically. - desc.sRGB = false; + destDesc.enableRandomWrite = true; - destination = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, _UpscaledColorTargetName, false, FilterMode.Bilinear); + destination = CreateCompatibleTexture(renderGraph, destDesc, _UpscaledColorTargetName, false, FilterMode.Bilinear); int frameIndex = Time.frameCount; var noiseTexture = m_Data.textures.blueNoise16LTex[frameIndex & (m_Data.textures.blueNoise16LTex.Length - 1)]; @@ -961,14 +956,13 @@ private void RenderSTP(RenderGraph renderGraph, UniversalResourceData resourceDa StpUtils.Execute(renderGraph, resourceData, cameraData, source, cameraDepth, motionVectors, destination, noiseTexture); // Update the camera resolution to reflect the upscaled size - UpdateCameraResolution(renderGraph, cameraData, new Vector2Int(desc.width, desc.height)); + UpdateCameraResolution(renderGraph, cameraData, new Vector2Int(destDesc.width, destDesc.height)); } #endregion #region MotionBlur private class MotionBlurPassData { - internal TextureHandle destinationTexture; internal TextureHandle sourceTexture; internal TextureHandle motionVectors; internal Material material; @@ -983,13 +977,8 @@ private class MotionBlurPassData public void RenderMotionBlur(RenderGraph renderGraph, UniversalResourceData resourceData, UniversalCameraData cameraData, in TextureHandle source, out TextureHandle destination) { var material = m_Materials.cameraMotionBlur; - var desc = PostProcessPass.GetCompatibleDescriptor(m_Descriptor, - m_Descriptor.width, - m_Descriptor.height, - m_Descriptor.graphicsFormat, - GraphicsFormat.None); - destination = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, "_MotionBlurTarget", true, FilterMode.Bilinear); + destination = CreateCompatibleTexture(renderGraph, source, "_MotionBlurTarget", true, FilterMode.Bilinear); TextureHandle motionVectorColor = resourceData.motionVectorColor; TextureHandle cameraDepthTexture = resourceData.cameraDepthTexture; @@ -1001,7 +990,6 @@ public void RenderMotionBlur(RenderGraph renderGraph, UniversalResourceData reso using (var builder = renderGraph.AddRasterRenderPass("Motion Blur", out var passData, ProfilingSampler.Get(URPProfileId.RG_MotionBlur))) { builder.AllowGlobalStateModification(true); - passData.destinationTexture = destination; builder.SetRenderAttachment(destination, 0, AccessFlags.Write); passData.sourceTexture = source; builder.UseTexture(source, AccessFlags.Read); @@ -1053,7 +1041,6 @@ public void RenderMotionBlur(RenderGraph renderGraph, UniversalResourceData reso private class LensFlarePassData { internal TextureHandle destinationTexture; - internal RenderTextureDescriptor sourceDescriptor; internal UniversalCameraData cameraData; internal Material material; internal Rect viewport; @@ -1064,7 +1051,7 @@ private class LensFlarePassData internal bool usePanini; } - void LensFlareDataDrivenComputeOcclusion(RenderGraph renderGraph, UniversalResourceData resourceData, UniversalCameraData cameraData) + void LensFlareDataDrivenComputeOcclusion(RenderGraph renderGraph, UniversalResourceData resourceData, UniversalCameraData cameraData, in TextureDesc srcDesc) { if (!LensFlareCommonSRP.IsOcclusionRTCompatible()) return; @@ -1078,8 +1065,8 @@ void LensFlareDataDrivenComputeOcclusion(RenderGraph renderGraph, UniversalResou passData.cameraData = cameraData; passData.viewport = cameraData.pixelRect; passData.material = m_Materials.lensFlareDataDriven; - passData.width = (float)m_Descriptor.width; - passData.height = (float)m_Descriptor.height; + passData.width = (float)srcDesc.width; + passData.height = (float)srcDesc.height; if (m_PaniniProjection.IsActive()) { passData.usePanini = true; @@ -1165,7 +1152,7 @@ void LensFlareDataDrivenComputeOcclusion(RenderGraph renderGraph, UniversalResou } } - public void RenderLensFlareDataDriven(RenderGraph renderGraph, UniversalResourceData resourceData, UniversalCameraData cameraData, in TextureHandle destination) + public void RenderLensFlareDataDriven(RenderGraph renderGraph, UniversalResourceData resourceData, UniversalCameraData cameraData, in TextureHandle destination, in TextureDesc srcDesc) { using (var builder = renderGraph.AddUnsafePass("Lens Flare Data Driven Pass", out var passData, ProfilingSampler.Get(URPProfileId.LensFlareDataDriven))) { @@ -1173,15 +1160,14 @@ public void RenderLensFlareDataDriven(RenderGraph renderGraph, UniversalResource // TODO RENDERGRAPH: convert SRP core lens flare to be rendergraph friendly passData.destinationTexture = destination; builder.UseTexture(destination, AccessFlags.Write); - passData.sourceDescriptor = m_Descriptor; passData.cameraData = cameraData; passData.material = m_Materials.lensFlareDataDriven; - passData.width = (float)m_Descriptor.width; - passData.height = (float)m_Descriptor.height; + passData.width = (float)srcDesc.width; + passData.height = (float)srcDesc.height; passData.viewport.x = 0.0f; passData.viewport.y = 0.0f; - passData.viewport.width = (float)m_Descriptor.width; - passData.viewport.height = (float)m_Descriptor.height; + passData.viewport.width = (float)srcDesc.width; + passData.viewport.height = (float)srcDesc.height; if (m_PaniniProjection.IsActive()) { passData.usePanini = true; @@ -1262,37 +1248,37 @@ public void RenderLensFlareDataDriven(RenderGraph renderGraph, UniversalResource private class LensFlareScreenSpacePassData { - internal TextureHandle destinationTexture; internal TextureHandle streakTmpTexture; internal TextureHandle streakTmpTexture2; internal TextureHandle originalBloomTexture; internal TextureHandle screenSpaceLensFlareBloomMipTexture; internal TextureHandle result; - internal RenderTextureDescriptor sourceDescriptor; + internal int actualWidth; + internal int actualHeight; internal Camera camera; internal Material material; internal ScreenSpaceLensFlare lensFlareScreenSpace; internal int downsample; } - public TextureHandle RenderLensFlareScreenSpace(RenderGraph renderGraph, Camera camera, in TextureHandle destination, TextureHandle originalBloomTexture, TextureHandle screenSpaceLensFlareBloomMipTexture, bool enableXR) + public TextureHandle RenderLensFlareScreenSpace(RenderGraph renderGraph, Camera camera, in TextureDesc srcDesc, TextureHandle originalBloomTexture, TextureHandle screenSpaceLensFlareBloomMipTexture) { var downsample = (int) m_LensFlareScreenSpace.resolution.value; - int width = Math.Max(m_Descriptor.width / downsample, 1); - int height = Math.Max(m_Descriptor.height / downsample, 1); + int flareRenderWidth = Math.Max( srcDesc.width / downsample, 1); + int flareRenderHeight = Math.Max( srcDesc.height / downsample, 1); + + var streakTextureDesc = GetCompatibleDescriptor(srcDesc, flareRenderWidth, flareRenderHeight, m_DefaultColorFormat); + var streakTmpTexture = CreateCompatibleTexture(renderGraph, streakTextureDesc, "_StreakTmpTexture", true, FilterMode.Bilinear); + var streakTmpTexture2 = CreateCompatibleTexture(renderGraph, streakTextureDesc, "_StreakTmpTexture2", true, FilterMode.Bilinear); - var streakTextureDesc = GetCompatibleDescriptor(m_Descriptor, width, height, m_DefaultColorFormat); - var streakTmpTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, streakTextureDesc, "_StreakTmpTexture", true, FilterMode.Bilinear); - var streakTmpTexture2 = UniversalRenderer.CreateRenderGraphTexture(renderGraph, streakTextureDesc, "_StreakTmpTexture2", true, FilterMode.Bilinear); - var resultTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, streakTextureDesc, "Lens Flare Screen Space Result", true, FilterMode.Bilinear); + // NOTE: Result texture is the result of the flares/streaks only. Not the final output which is "bloom + flares". + var resultTexture = CreateCompatibleTexture(renderGraph, streakTextureDesc, "_LensFlareScreenSpace", true, FilterMode.Bilinear); - using (var builder = renderGraph.AddUnsafePass("Lens Flare Screen Space Pass", out var passData, ProfilingSampler.Get(URPProfileId.LensFlareScreenSpace))) + using (var builder = renderGraph.AddUnsafePass("Blit Lens Flare Screen Space", out var passData, ProfilingSampler.Get(URPProfileId.LensFlareScreenSpace))) { // Use WriteTexture here because DoLensFlareScreenSpaceCommon will call SetRenderTarget internally. // TODO RENDERGRAPH: convert SRP core lensflare to be rendergraph friendly - passData.destinationTexture = destination; - builder.UseTexture(destination, AccessFlags.Write); passData.streakTmpTexture = streakTmpTexture; builder.UseTexture(streakTmpTexture, AccessFlags.ReadWrite); passData.streakTmpTexture2 = streakTmpTexture2; @@ -1301,13 +1287,14 @@ public TextureHandle RenderLensFlareScreenSpace(RenderGraph renderGraph, Camera builder.UseTexture(screenSpaceLensFlareBloomMipTexture, AccessFlags.ReadWrite); passData.originalBloomTexture = originalBloomTexture; builder.UseTexture(originalBloomTexture, AccessFlags.ReadWrite); - passData.sourceDescriptor = m_Descriptor; + passData.actualWidth = srcDesc.width; + passData.actualHeight = srcDesc.height; passData.camera = camera; passData.material = m_Materials.lensFlareScreenSpace; passData.lensFlareScreenSpace = m_LensFlareScreenSpace; // NOTE: reference, assumed constant until executed. passData.downsample = downsample; passData.result = resultTexture; - builder.UseTexture(resultTexture, AccessFlags.Write); + builder.UseTexture(resultTexture, AccessFlags.ReadWrite); builder.SetRenderFunc(static (LensFlareScreenSpacePassData data, UnsafeGraphContext context) => { @@ -1318,8 +1305,8 @@ public TextureHandle RenderLensFlareScreenSpace(RenderGraph renderGraph, Camera LensFlareCommonSRP.DoLensFlareScreenSpaceCommon( data.material, camera, - (float)data.sourceDescriptor.width, - (float)data.sourceDescriptor.height, + (float)data.actualWidth, + (float)data.actualHeight, data.lensFlareScreenSpace.tintColor.value, data.originalBloomTexture, data.screenSpaceLensFlareBloomMipTexture, @@ -1355,8 +1342,8 @@ public TextureHandle RenderLensFlareScreenSpace(RenderGraph renderGraph, Camera data.result, false); }); - return passData.originalBloomTexture; } + return originalBloomTexture; } #endregion @@ -1450,13 +1437,14 @@ public void RenderFinalSetup(RenderGraph renderGraph, UniversalCameraData camera private class PostProcessingFinalFSRScalePassData { - internal TextureHandle destinationTexture; internal TextureHandle sourceTexture; internal Material material; internal bool enableAlphaOutput; + internal Vector2 fsrInputSize; + internal Vector2 fsrOutputSize; } - public void RenderFinalFSRScale(RenderGraph renderGraph, in TextureHandle source, in TextureHandle destination, bool enableAlphaOutput) + public void RenderFinalFSRScale(RenderGraph renderGraph, in TextureHandle source, in TextureDesc srcDesc, in TextureHandle destination, in TextureDesc dstDesc, bool enableAlphaOutput) { // FSR upscale m_Materials.easu.shaderKeywords = null; @@ -1464,26 +1452,23 @@ public void RenderFinalFSRScale(RenderGraph renderGraph, in TextureHandle source using (var builder = renderGraph.AddRasterRenderPass("Postprocessing Final FSR Scale Pass", out var passData, ProfilingSampler.Get(URPProfileId.RG_FinalFSRScale))) { builder.AllowGlobalStateModification(true); - passData.destinationTexture = destination; builder.SetRenderAttachment(destination, 0, AccessFlags.Write); passData.sourceTexture = source; builder.UseTexture(source, AccessFlags.Read); passData.material = m_Materials.easu; passData.enableAlphaOutput = enableAlphaOutput; + passData.fsrInputSize = new Vector2(srcDesc.width, srcDesc.height); + passData.fsrOutputSize = new Vector2(dstDesc.width, dstDesc.height); builder.SetRenderFunc(static (PostProcessingFinalFSRScalePassData data, RasterGraphContext context) => { var cmd = context.cmd; var sourceTex = data.sourceTexture; - var destTex = data.destinationTexture; var material = data.material; var enableAlphaOutput = data.enableAlphaOutput; RTHandle sourceHdl = (RTHandle)sourceTex; - RTHandle destHdl = (RTHandle)destTex; - var fsrInputSize = new Vector2(sourceHdl.referenceSize.x, sourceHdl.referenceSize.y); - var fsrOutputSize = new Vector2(destHdl.referenceSize.x, destHdl.referenceSize.y); - FSRUtils.SetEasuConstants(cmd, fsrInputSize, fsrInputSize, fsrOutputSize); + FSRUtils.SetEasuConstants(cmd, data.fsrInputSize, data.fsrInputSize, data.fsrOutputSize); CoreUtils.SetKeyword(material, ShaderKeywordStrings._ENABLE_ALPHA_OUTPUT, enableAlphaOutput); @@ -1557,7 +1542,7 @@ public void RenderFinalBlit(RenderGraph renderGraph, UniversalCameraData cameraD passData.material = m_Materials.finalPass; passData.settings = settings; - if (settings.requireHDROutput && m_EnableColorEncodingIfNeeded) + if (settings.requireHDROutput && m_EnableColorEncodingIfNeeded && cameraData.rendersOverlayUI) builder.UseTexture(overlayUITexture, AccessFlags.Read); #if ENABLE_VR && ENABLE_XR_MODULE @@ -1641,7 +1626,6 @@ public void RenderFinalPassRenderGraph(RenderGraph renderGraph, ContextContainer var stack = VolumeManager.instance.stack; m_Tonemapping = stack.GetComponent(); m_FilmGrain = stack.GetComponent(); - m_Tonemapping = stack.GetComponent(); UniversalCameraData cameraData = frameData.Get(); @@ -1651,6 +1635,12 @@ public void RenderFinalPassRenderGraph(RenderGraph renderGraph, ContextContainer FinalBlitSettings settings = FinalBlitSettings.Create(); + var srcDesc = renderGraph.GetTextureDesc(source); + + var upscaledDesc = srcDesc; + upscaledDesc.width = cameraData.pixelWidth; + upscaledDesc.height = cameraData.pixelHeight; + // TODO RENDERGRAPH: when we remove the old path we should review the naming of these variables... // m_HasFinalPass is used to let FX passes know when they are not being called by the actual final pass, so they can skip any "final work" m_HasFinalPass = false; @@ -1664,7 +1654,7 @@ public void RenderFinalPassRenderGraph(RenderGraph renderGraph, ContextContainer PostProcessUtils.ConfigureFilmGrain( m_Data, m_FilmGrain, - cameraData.pixelWidth, cameraData.pixelHeight, + upscaledDesc.width, upscaledDesc.height, material ); } @@ -1675,7 +1665,7 @@ public void RenderFinalPassRenderGraph(RenderGraph renderGraph, ContextContainer m_DitheringTextureIndex = PostProcessUtils.ConfigureDithering( m_Data, m_DitheringTextureIndex, - cameraData.pixelWidth, cameraData.pixelHeight, + upscaledDesc.width, upscaledDesc.height, material ); } @@ -1710,24 +1700,16 @@ public void RenderFinalPassRenderGraph(RenderGraph renderGraph, ContextContainer // If STP is enabled, then TAA sharpening has already been performed inside STP. settings.isTaaSharpeningEnabled = (cameraData.IsTemporalAAEnabled() && cameraData.taaSettings.contrastAdaptiveSharpening > 0.0f) && !settings.isFsrEnabled && !cameraData.IsSTPEnabled(); - var tempRtDesc = cameraData.cameraTargetDescriptor; - tempRtDesc.msaaSamples = 1; - tempRtDesc.depthStencilFormat = GraphicsFormat.None; + var tempRtDesc = srcDesc; // Select a UNORM format since we've already performed tonemapping. (Values are in 0-1 range) // This improves precision and is required if we want to avoid excessive banding when FSR is in use. if (!settings.requireHDROutput) - tempRtDesc.graphicsFormat = UniversalRenderPipeline.MakeUnormRenderTextureGraphicsFormat(); - - var scalingSetupTarget = UniversalRenderer.CreateRenderGraphTexture(renderGraph, tempRtDesc, "scalingSetupTarget", true, FilterMode.Point); + tempRtDesc.format = UniversalRenderPipeline.MakeUnormRenderTextureGraphicsFormat(); - var upscaleRtDesc = cameraData.cameraTargetDescriptor; - upscaleRtDesc.msaaSamples = 1; - upscaleRtDesc.depthStencilFormat = GraphicsFormat.None; - upscaleRtDesc.width = cameraData.pixelWidth; - upscaleRtDesc.height = cameraData.pixelHeight; + var scalingSetupTarget = CreateCompatibleTexture(renderGraph, tempRtDesc, "scalingSetupTarget", true, FilterMode.Point); - var upScaleTarget = UniversalRenderer.CreateRenderGraphTexture(renderGraph, upscaleRtDesc, "_UpscaledTexture", true, FilterMode.Point); + var upScaleTarget = CreateCompatibleTexture(renderGraph, upscaledDesc, "_UpscaledTexture", true, FilterMode.Point); var currentSource = source; if (cameraData.imageScalingMode != ImageScalingMode.None) @@ -1770,7 +1752,7 @@ public void RenderFinalPassRenderGraph(RenderGraph renderGraph, ContextContainer } case ImageUpscalingFilter.FSR: { - RenderFinalFSRScale(renderGraph, in currentSource, in upScaleTarget, settings.isAlphaOutputEnabled); + RenderFinalFSRScale(renderGraph, in currentSource, in srcDesc, in upScaleTarget, in upscaledDesc, settings.isAlphaOutputEnabled); currentSource = upScaleTarget; break; } @@ -1804,6 +1786,7 @@ private class UberPostPassData internal TextureHandle destinationTexture; internal TextureHandle sourceTexture; internal TextureHandle lutTexture; + internal TextureHandle bloomTexture; internal Vector4 lutParams; internal TextureHandle userLutTexture; internal Vector4 userLutParams; @@ -1837,7 +1820,9 @@ TextureHandle TryGetCachedUserLutTextureHandle(RenderGraph renderGraph) return m_UserLut != null ? renderGraph.ImportTexture(m_UserLut) : TextureHandle.nullHandle; } - public void RenderUberPost(RenderGraph renderGraph, ContextContainer frameData, UniversalCameraData cameraData, UniversalPostProcessingData postProcessingData, in TextureHandle sourceTexture, in TextureHandle destTexture, in TextureHandle lutTexture, in TextureHandle overlayUITexture, bool requireHDROutput, bool enableAlphaOutput, bool resolveToDebugScreen, bool hasFinalPass) + public void RenderUberPost(RenderGraph renderGraph, ContextContainer frameData, UniversalCameraData cameraData, UniversalPostProcessingData postProcessingData, + in TextureHandle sourceTexture, in TextureHandle destTexture, in TextureHandle lutTexture, in TextureHandle bloomTexture, in TextureHandle overlayUITexture, + bool requireHDROutput, bool enableAlphaOutput, bool resolveToDebugScreen, bool hasFinalPass) { var material = m_Materials.uber; bool hdrGrading = postProcessingData.gradingMode == ColorGradingMode.HighDynamicRange; @@ -1885,7 +1870,11 @@ public void RenderUberPost(RenderGraph renderGraph, ContextContainer frameData, } if (m_Bloom.IsActive()) - builder.UseTexture(_BloomMipUp[0], AccessFlags.Read); + { + builder.UseTexture(bloomTexture, AccessFlags.Read); + passData.bloomTexture = bloomTexture; + } + if (requireHDROutput && m_EnableColorEncodingIfNeeded && overlayUITexture.IsValid()) builder.UseTexture(overlayUITexture, AccessFlags.Read); @@ -1909,6 +1898,11 @@ public void RenderUberPost(RenderGraph renderGraph, ContextContainer frameData, material.SetTexture(ShaderConstants._UserLut, data.userLutTexture); material.SetVector(ShaderConstants._UserLut_Params, data.userLutParams); + if (data.bloomTexture.IsValid()) + { + material.SetTexture(ShaderConstants._Bloom_Texture, data.bloomTexture); + } + if (data.isHdrGrading) { material.EnableKeyword(ShaderKeywordStrings.HDRGrading); @@ -1959,9 +1953,7 @@ public void RenderPostProcessingRenderGraph(RenderGraph renderGraph, ContextCont m_UseFastSRGBLinearConversion = postProcessingData.useFastSRGBLinearConversion; m_SupportDataDrivenLensFlare = postProcessingData.supportDataDrivenLensFlare; m_SupportScreenSpaceLensFlare = postProcessingData.supportScreenSpaceLensFlare; - m_Descriptor = cameraData.cameraTargetDescriptor; - m_Descriptor.useMipMap = false; - m_Descriptor.autoGenerateMips = false; + m_HasFinalPass = hasFinalPass; m_EnableColorEncodingIfNeeded = enableColorEndingIfNeeded; @@ -2012,8 +2004,6 @@ public void RenderPostProcessingRenderGraph(RenderGraph renderGraph, ContextCont using (var builder = renderGraph.AddRasterRenderPass("Setup PostFX passes", out var passData, ProfilingSampler.Get(URPProfileId.RG_SetupPostFX))) { - // TODO RENDERGRAPH: properly setup dependencies between passes - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); builder.SetRenderFunc(static (PostFXSetupPassData data, RasterGraphContext context) => { @@ -2028,7 +2018,7 @@ public void RenderPostProcessingRenderGraph(RenderGraph renderGraph, ContextCont // stopNaN may be null on Adreno 3xx. It doesn't support full shader level 3.5, but SystemInfo.graphicsShaderLevel is 35. if (useStopNan) { - RenderStopNaN(renderGraph, cameraData.cameraTargetDescriptor, in currentSource, out var stopNaNTarget); + RenderStopNaN(renderGraph, in currentSource, out var stopNaNTarget); currentSource = stopNaNTarget; } @@ -2079,33 +2069,36 @@ public void RenderPostProcessingRenderGraph(RenderGraph renderGraph, ContextCont // Reset uber keywords m_Materials.uber.shaderKeywords = null; + var srcDesc = currentSource.GetDescriptor(renderGraph); + // Bloom goes first + TextureHandle bloomTexture = TextureHandle.nullHandle; bool bloomActive = m_Bloom.IsActive(); //Even if bloom is not active we need the texture if the lensFlareScreenSpace pass is active. if (bloomActive || useLensFlareScreenSpace) { - RenderBloomTexture(renderGraph, currentSource, out var BloomTexture, cameraData.isAlphaOutputEnabled); + RenderBloomTexture(renderGraph, currentSource, out bloomTexture, cameraData.isAlphaOutputEnabled); if (useLensFlareScreenSpace) { int maxBloomMip = Mathf.Clamp(m_LensFlareScreenSpace.bloomMip.value, 0, m_Bloom.maxIterations.value/2); - BloomTexture = RenderLensFlareScreenSpace(renderGraph, cameraData.camera, in currentSource, _BloomMipUp[0], _BloomMipUp[maxBloomMip], cameraData.xr.enabled); + bloomTexture = RenderLensFlareScreenSpace(renderGraph, cameraData.camera, srcDesc, bloomTexture, _BloomMipUp[maxBloomMip]); } - UberPostSetupBloomPass(renderGraph, in BloomTexture, m_Materials.uber); + UberPostSetupBloomPass(renderGraph, m_Materials.uber, srcDesc); } if (useLensFlare) { - LensFlareDataDrivenComputeOcclusion(renderGraph, resourceData, cameraData); - RenderLensFlareDataDriven(renderGraph, resourceData, cameraData, in currentSource); + LensFlareDataDrivenComputeOcclusion(renderGraph, resourceData, cameraData, srcDesc); + RenderLensFlareDataDriven(renderGraph, resourceData, cameraData, in currentSource, in srcDesc); } // TODO RENDERGRAPH: Once we started removing the non-RG code pass in URP, we should move functions below to renderfunc so that material setup happens at // the same timeline of executing the rendergraph. Keep them here for now so we cound reuse non-RG code to reduce maintainance cost. SetupLensDistortion(m_Materials.uber, isSceneViewCamera); SetupChromaticAberration(m_Materials.uber); - SetupVignette(m_Materials.uber, cameraData.xr); + SetupVignette(m_Materials.uber, cameraData.xr, srcDesc.width, srcDesc.height); SetupGrain(cameraData, m_Materials.uber); SetupDithering(cameraData, m_Materials.uber); @@ -2132,7 +2125,7 @@ public void RenderPostProcessingRenderGraph(RenderGraph renderGraph, ContextCont DebugHandler debugHandler = GetActiveDebugHandler(cameraData); debugHandler?.UpdateShaderGlobalPropertiesForFinalValidationPass(renderGraph, cameraData, !m_HasFinalPass && !resolveToDebugScreen); - RenderUberPost(renderGraph, frameData, cameraData, postProcessingData, in currentSource, in postProcessingTarget, in lutTexture, in overlayUITexture, requireHDROutput, enableAlphaOutput, resolveToDebugScreen, hasFinalPass); + RenderUberPost(renderGraph, frameData, cameraData, postProcessingData, in currentSource, in postProcessingTarget, in lutTexture, in bloomTexture, in overlayUITexture, requireHDROutput, enableAlphaOutput, resolveToDebugScreen, hasFinalPass); } } } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/RenderObjectsPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/RenderObjectsPass.cs index 8c3f1b87532..285ceb0ed67 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/RenderObjectsPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/RenderObjectsPass.cs @@ -313,7 +313,6 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer builder.UseRendererList(passData.rendererListHdl); } - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); if (cameraData.xr.enabled) builder.EnableFoveatedRasterization(cameraData.xr.supportsFoveatedRendering && cameraData.xrUniversal.canFoveateIntermediatePasses); diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/ScreenSpaceAmbientOcclusionPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/ScreenSpaceAmbientOcclusionPass.cs index 655d40c7e7f..f78867f3741 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/ScreenSpaceAmbientOcclusionPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/ScreenSpaceAmbientOcclusionPass.cs @@ -339,7 +339,6 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer { // Shader keyword changes are considered as global state modifications builder.AllowGlobalStateModification(true); - builder.AllowPassCulling(false); // Fill in the Pass data... InitSSAOPassData(ref passData); diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/XROcclusionMeshPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/XROcclusionMeshPass.cs index da2b2f0462b..e8597ee2023 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/XROcclusionMeshPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/XROcclusionMeshPass.cs @@ -68,8 +68,6 @@ internal void Render(RenderGraph renderGraph, ContextContainer frameData, in Tex passData.isActiveTargetBackBuffer = resourceData.isActiveTargetBackBuffer; - // TODO RENDERGRAPH: culling? force culling off for testing - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); if (cameraData.xr.enabled) { diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/RenderPipelineResources/UniversalRenderPipelineEditorShaders.cs b/Packages/com.unity.render-pipelines.universal/Runtime/RenderPipelineResources/UniversalRenderPipelineEditorShaders.cs index 70f80224ae9..7a7bc8e3f9a 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/RenderPipelineResources/UniversalRenderPipelineEditorShaders.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/RenderPipelineResources/UniversalRenderPipelineEditorShaders.cs @@ -43,39 +43,6 @@ public Shader autodeskInteractiveMaskedShader } #endregion - #region Terrain - [Header("Terrain")] - [SerializeField] - [ResourcePath("Shaders/Terrain/TerrainDetailLit.shader")] - private Shader m_TerrainDetailLit; - - public Shader terrainDetailLitShader - { - get => m_TerrainDetailLit; - set => this.SetValueAndNotify(ref m_TerrainDetailLit, value); - } - - [SerializeField] - [ResourcePath("Shaders/Terrain/WavingGrassBillboard.shader")] - private Shader m_TerrainDetailGrassBillboard; - - public Shader terrainDetailGrassBillboardShader - { - get => m_TerrainDetailGrassBillboard; - set => this.SetValueAndNotify(ref m_TerrainDetailGrassBillboard, value); - } - - [SerializeField] - [ResourcePath("Shaders/Terrain/WavingGrass.shader")] - private Shader m_TerrainDetailGrass; - - public Shader terrainDetailGrassShader - { - get => m_TerrainDetailGrass; - set => this.SetValueAndNotify(ref m_TerrainDetailGrass, value); - } - #endregion - #region SpeedTree [Header("SpeedTree")] [SerializeField] diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/RenderPipelineResources/UniversalRenderPipelineRuntimeShaders.cs b/Packages/com.unity.render-pipelines.universal/Runtime/RenderPipelineResources/UniversalRenderPipelineRuntimeShaders.cs index 697b7587159..54a40494d54 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/RenderPipelineResources/UniversalRenderPipelineRuntimeShaders.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/RenderPipelineResources/UniversalRenderPipelineRuntimeShaders.cs @@ -15,7 +15,7 @@ namespace UnityEngine.Rendering.Universal /// /// using UnityEngine.Rendering; /// using UnityEngine.Rendering.Universal; - /// + /// /// public static class URPUniversalRendererRuntimeShadersHelper /// { /// public static Shader blit @@ -106,5 +106,47 @@ public Shader samplingPS get => m_SamplingPS; set => this.SetValueAndNotify(ref m_SamplingPS, value, nameof(m_SamplingPS)); } + + #region Terrain + [Header("Terrain")] + [SerializeField] + [ResourcePath("Shaders/Terrain/TerrainDetailLit.shader")] + private Shader m_TerrainDetailLit; + + /// + /// Returns the terrain detail lit shader that this asset uses. + /// + public Shader terrainDetailLitShader + { + get => m_TerrainDetailLit; + set => this.SetValueAndNotify(ref m_TerrainDetailLit, value); + } + + [SerializeField] + [ResourcePath("Shaders/Terrain/WavingGrassBillboard.shader")] + private Shader m_TerrainDetailGrassBillboard; + + /// + /// Returns the terrain detail grass billboard shader that this asset uses. + /// + public Shader terrainDetailGrassBillboardShader + { + get => m_TerrainDetailGrassBillboard; + set => this.SetValueAndNotify(ref m_TerrainDetailGrassBillboard, value); + } + + [SerializeField] + [ResourcePath("Shaders/Terrain/WavingGrass.shader")] + private Shader m_TerrainDetailGrass; + + /// + /// Returns the terrain detail grass shader that this asset uses. + /// + public Shader terrainDetailGrassShader + { + get => m_TerrainDetailGrass; + set => this.SetValueAndNotify(ref m_TerrainDetailGrass, value); + } + #endregion } } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/DecalRendererFeature.cs b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/DecalRendererFeature.cs index 8df0db2da4d..c7e0777e248 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/DecalRendererFeature.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/RendererFeatures/DecalRendererFeature.cs @@ -509,7 +509,7 @@ public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingD else { m_CopyDepthPass.CopyToDepth = true; - m_CopyDepthPass.MssaSamples = 1; + m_CopyDepthPass.MsaaSamples = 1; } } @@ -567,7 +567,7 @@ public override void SetupRenderPasses(ScriptableRenderer renderer, in Rendering m_DBufferRenderPass.dBufferDepth ); m_CopyDepthPass.CopyToDepth = true; - m_CopyDepthPass.MssaSamples = 1; + m_CopyDepthPass.MsaaSamples = 1; } } else if (m_Technique == DecalTechnique.GBuffer && m_DeferredLights.UseFramebufferFetch) diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/ScriptableRenderer.cs b/Packages/com.unity.render-pipelines.universal/Runtime/ScriptableRenderer.cs index cc175be64a7..cb184013bb3 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/ScriptableRenderer.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/ScriptableRenderer.cs @@ -929,7 +929,6 @@ internal void SetupRenderGraphCameraProperties(RenderGraph renderGraph, bool isT passData.cameraTargetSizeCopy = new Vector2Int(passData.cameraData.cameraTargetDescriptor.width, passData.cameraData.cameraTargetDescriptor.height); passData.isTargetBackbuffer = isTargetBackbuffer; - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); builder.SetRenderFunc((PassData data, RasterGraphContext context) => @@ -1068,7 +1067,6 @@ internal void BeginRenderGraphXRRendering(RenderGraph renderGraph) { passData.cameraData = cameraData; - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); builder.SetRenderFunc((BeginXRPassData data, RasterGraphContext context) => @@ -1109,7 +1107,6 @@ internal void EndRenderGraphXRRendering(RenderGraph renderGraph) { passData.cameraData = cameraData; - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); builder.SetRenderFunc((EndXRPassData data, RasterGraphContext context) => diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs index f1f39336eb7..a5af9c1000d 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs @@ -1547,7 +1547,7 @@ public override void Setup(ScriptableRenderContext context, ref RenderingData re { // Scene view camera should always resolve target (not stacked) m_FinalDepthCopyPass.Setup(m_DepthTexture, k_CameraTarget); - m_FinalDepthCopyPass.MssaSamples = 0; + m_FinalDepthCopyPass.MsaaSamples = 0; m_FinalDepthCopyPass.CopyToBackbuffer = cameraData.isGameCamera; // Turning off unnecessary NRP in Editor because of MSAA mistmatch between CameraTargetDescriptor vs camera backbuffer // NRP layer considers this being a pass with MSAA samples by checking CameraTargetDescriptor taken from RP asset @@ -1940,6 +1940,7 @@ bool RequiresIntermediateColorTexture(UniversalCameraData cameraData, ref Render var cameraTargetDescriptor = cameraData.cameraTargetDescriptor; int msaaSamples = cameraTargetDescriptor.msaaSamples; bool isScaledRender = cameraData.imageScalingMode != ImageScalingMode.None; + bool isScalableBufferManagerUsed = IsScalableBufferManagerUsed(cameraData); bool isCompatibleBackbufferTextureDimension = cameraTargetDescriptor.dimension == TextureDimension.Tex2D; bool requiresExplicitMsaaResolve = msaaSamples > 1 && PlatformRequiresExplicitMsaaResolve(); bool isOffscreenRender = cameraData.targetTexture != null && !isSceneViewCamera; @@ -1949,6 +1950,7 @@ bool RequiresIntermediateColorTexture(UniversalCameraData cameraData, ref Render if (cameraData.xr.enabled) { isScaledRender = false; + isScalableBufferManagerUsed = false; isCompatibleBackbufferTextureDimension = cameraData.xr.renderTargetDesc.dimension == cameraTargetDescriptor.dimension; } #endif @@ -1957,9 +1959,27 @@ bool RequiresIntermediateColorTexture(UniversalCameraData cameraData, ref Render if (isOffscreenRender) return requiresBlitForOffscreenCamera; - return requiresBlitForOffscreenCamera || isScaledRender || cameraData.isHdrEnabled || + return requiresBlitForOffscreenCamera || isScaledRender || isScalableBufferManagerUsed || cameraData.isHdrEnabled || !isCompatibleBackbufferTextureDimension || isCapturing || cameraData.requireSrgbConversion || - renderPassInputs.requiresColorTexture || renderPassInputs.requiresColorTextureCreated; + renderPassInputs.requiresColorTexture || renderPassInputs.requiresColorTextureCreated ; + } + + // There is two ways to control the dynamic resolution in URP: + // - By using the ScalableBufferManager API (https://docs.unity3d.com/2022.2/Documentation/Manual/DynamicResolution.html). + // - By using the cameraData.renderScale property on the URP asset. + // When checking the requirements to use an intermediate texture, we only consider the cameraData.renderScale property and not the ScalableBufferManager API. + // When Dynamic Resolution is enabled on the camera and a scale factor (from ScalableBufferManager) is different than 1, we need to use an intermediate texture. + // Note: cameraData.renderScale resizes screen space textures, while dynamic resolution (ScalableBufferManager) doesn't and instead uses memory aliasing. + // These features are different and should work independently, though they can be used together at the same time. + bool IsScalableBufferManagerUsed(UniversalCameraData cameraData) + { + const float epsilon = 0.0001f; + + bool dynamicResEnabled = cameraData.camera.allowDynamicResolution; + bool scaledWidthActive = Mathf.Abs(ScalableBufferManager.widthScaleFactor - 1.0f) > epsilon; + bool scaledHeightActive = Mathf.Abs(ScalableBufferManager.heightScaleFactor - 1.0f) > epsilon; + + return dynamicResEnabled && (scaledWidthActive || scaledHeightActive); } bool CanCopyDepth(UniversalCameraData cameraData) diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs index e08f51c0c1c..3acb713de02 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs @@ -286,7 +286,7 @@ bool CameraHasPostProcessingWithDepth(UniversalCameraData cameraData) bool RequiresIntermediateAttachments(UniversalCameraData cameraData, ref RenderPassInputSummary renderPassInputs) { - bool requiresDepthPrepass = RequireDepthPrepass(cameraData, ref renderPassInputs); + var requiresDepthPrepass = RequireDepthPrepass(cameraData, ref renderPassInputs); var requireColorTexture = HasActiveRenderFeatures() && m_IntermediateTextureMode == IntermediateTextureMode.Always; requireColorTexture |= HasPassesRequiringIntermediateTexture(); @@ -634,7 +634,7 @@ void CreateRenderGraphCameraRenderTargets(RenderGraph renderGraph, bool isCamera resourceData.activeDepthID = UniversalResourceData.ActiveID.Camera; // Configure the copy depth pass based on the allocated depth texture - m_CopyDepthPass.MssaSamples = depthDescriptor.msaaSamples; + m_CopyDepthPass.MsaaSamples = depthDescriptor.msaaSamples; m_CopyDepthPass.CopyToDepth = depthTextureIsDepthFormat; var copyResolvedDepth = !depthDescriptor.bindMS; @@ -1668,7 +1668,7 @@ private void OnAfterRendering(RenderGraph renderGraph) if (!xrDepthTargetResolved && cameraData.xr.copyDepth) { m_XRCopyDepthPass.CopyToDepthXR = true; - m_XRCopyDepthPass.MssaSamples = 1; + m_XRCopyDepthPass.MsaaSamples = 1; m_XRCopyDepthPass.Render(renderGraph, frameData, resourceData.backBufferDepth, resourceData.cameraDepth, bindAsCameraDepth: false, "XR Depth Copy"); } } @@ -1690,7 +1690,7 @@ private void OnAfterRendering(RenderGraph renderGraph) bool backbufferDepthRequired = (cameraData.isSceneViewCamera || cameraData.isPreviewCamera || UnityEditor.Handles.ShouldRenderGizmos()); if (m_RequiresIntermediateAttachments && backbufferDepthRequired) { - m_FinalDepthCopyPass.MssaSamples = 0; + m_FinalDepthCopyPass.MsaaSamples = 0; m_FinalDepthCopyPass.CopyToBackbuffer = cameraData.isGameCamera; m_FinalDepthCopyPass.Render(renderGraph, frameData, resourceData.backBufferDepth, resourceData.cameraDepth, false, "Final Depth Copy"); } @@ -1907,7 +1907,6 @@ public static void SetGlobalTexture(RenderGraph graph, int nameId, TextureHandle passData.texture = handle; builder.UseTexture(handle, AccessFlags.Read); - builder.AllowPassCulling(false); builder.AllowGlobalStateModification(true); builder.SetGlobalTextureAfterPass(handle, nameId); diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPPackageSamples/RendererFeatures/DepthBlit/DepthBlitCopyDepthPass.cs b/Packages/com.unity.render-pipelines.universal/Samples~/URPPackageSamples/RendererFeatures/DepthBlit/DepthBlitCopyDepthPass.cs index 1d126cff0bd..7f9389fa072 100644 --- a/Packages/com.unity.render-pipelines.universal/Samples~/URPPackageSamples/RendererFeatures/DepthBlit/DepthBlitCopyDepthPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPPackageSamples/RendererFeatures/DepthBlit/DepthBlitCopyDepthPass.cs @@ -128,7 +128,6 @@ public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer builder.UseTexture(src, AccessFlags.Read); builder.SetRenderAttachment(dest, 0, AccessFlags.Write); builder.AllowGlobalStateModification(true); - builder.AllowPassCulling(false); builder.SetRenderFunc((PassData data, RasterGraphContext context) => { diff --git a/Packages/com.unity.render-pipelines.universal/Samples~/URPPackageSamples/SharedAssets/Scripts/CheckAssignedRenderPipelineAsset.cs b/Packages/com.unity.render-pipelines.universal/Samples~/URPPackageSamples/SharedAssets/Scripts/CheckAssignedRenderPipelineAsset.cs index 0d577e3d5f3..5a39ee48731 100644 --- a/Packages/com.unity.render-pipelines.universal/Samples~/URPPackageSamples/SharedAssets/Scripts/CheckAssignedRenderPipelineAsset.cs +++ b/Packages/com.unity.render-pipelines.universal/Samples~/URPPackageSamples/SharedAssets/Scripts/CheckAssignedRenderPipelineAsset.cs @@ -9,7 +9,7 @@ public class CheckAssignedRenderPipelineAsset : MonoBehaviour [SerializeField] private UniversalRenderPipelineAsset m_PipelineAsset; [SerializeField] private GameObject m_WarningGameObject; - private bool m_LastCorrectPipelineResults = false; + private bool? m_LastCorrectPipelineResults; private bool isCorrectAssetAssigned => QualitySettings.renderPipeline == m_PipelineAsset || QualitySettings.renderPipeline == null && GraphicsSettings.defaultRenderPipeline == m_PipelineAsset; @@ -24,14 +24,31 @@ private void Update() CheckIfCorrectAssetIsAssigned(); } + private void SetAllCamerasEnabled(bool enable) + { + Camera[] allCameras = FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None); + foreach (Camera c in allCameras) + c.enabled = enable; + } + private void CheckIfCorrectAssetIsAssigned() { if (m_PipelineAsset == null) return; bool correctAssetAssigned = isCorrectAssetAssigned; - if (!correctAssetAssigned && m_LastCorrectPipelineResults != correctAssetAssigned) - Debug.LogError("Incorrect/missing Universal Renderpipeline Asset assigned in Quality or Graphics Settings.\nPlease assign \"" + m_PipelineAsset.name + "\" to it."); + if (!m_LastCorrectPipelineResults.HasValue || m_LastCorrectPipelineResults != correctAssetAssigned) + { + if (!correctAssetAssigned) + { + Debug.LogError("Incorrect/missing Universal Render Pipeline Asset assigned in Quality or Graphics Settings. Please assign \"" + m_PipelineAsset.name + "\" to view the sample."); + SetAllCamerasEnabled(false); // Disable cameras to prevent error spam when the RP asset is not expected + } + else + { + SetAllCamerasEnabled(true); + } + } m_LastCorrectPipelineResults = correctAssetAssigned; if (m_WarningGameObject != null) diff --git a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceInput.hlsl b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceInput.hlsl index dd9cb75f7b8..effb2fdd04a 100644 --- a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceInput.hlsl +++ b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceInput.hlsl @@ -9,7 +9,6 @@ TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap); -float4 _BaseMap_TexelSize; UNITY_TEXTURE_STREAMING_DEBUG_VARS_FOR_TEX(_BaseMap); TEXTURE2D(_BumpMap); SAMPLER(sampler_BumpMap); diff --git a/Packages/com.unity.render-pipelines.universal/Shaders/BakedLitInput.hlsl b/Packages/com.unity.render-pipelines.universal/Shaders/BakedLitInput.hlsl index 624aaa66579..735e3d27493 100644 --- a/Packages/com.unity.render-pipelines.universal/Shaders/BakedLitInput.hlsl +++ b/Packages/com.unity.render-pipelines.universal/Shaders/BakedLitInput.hlsl @@ -6,6 +6,7 @@ CBUFFER_START(UnityPerMaterial) float4 _BaseMap_ST; + float4 _BaseMap_TexelSize; half4 _BaseColor; half _Cutoff; half _Glossiness; diff --git a/Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl b/Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl index 1e60617e86f..f5032e24fe1 100644 --- a/Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl +++ b/Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl @@ -15,6 +15,7 @@ // NOTE: Do not ifdef the properties here as SRP batcher can not handle different layouts. CBUFFER_START(UnityPerMaterial) float4 _BaseMap_ST; +float4 _BaseMap_TexelSize; float4 _DetailAlbedoMap_ST; half4 _BaseColor; half4 _SpecColor; diff --git a/Packages/com.unity.render-pipelines.universal/Shaders/Particles/ParticlesLitInput.hlsl b/Packages/com.unity.render-pipelines.universal/Shaders/Particles/ParticlesLitInput.hlsl index 2d3b6ba70b0..30d54e1a1c3 100644 --- a/Packages/com.unity.render-pipelines.universal/Shaders/Particles/ParticlesLitInput.hlsl +++ b/Packages/com.unity.render-pipelines.universal/Shaders/Particles/ParticlesLitInput.hlsl @@ -9,6 +9,7 @@ CBUFFER_START(UnityPerMaterial) float4 _SoftParticleFadeParams; float4 _CameraFadeParams; float4 _BaseMap_ST; +float4 _BaseMap_TexelSize; half4 _BaseColor; half4 _EmissionColor; half4 _BaseColorAddSubDiff; diff --git a/Packages/com.unity.render-pipelines.universal/Shaders/Particles/ParticlesSimpleLitInput.hlsl b/Packages/com.unity.render-pipelines.universal/Shaders/Particles/ParticlesSimpleLitInput.hlsl index 28ea72a5995..c1486ecb939 100644 --- a/Packages/com.unity.render-pipelines.universal/Shaders/Particles/ParticlesSimpleLitInput.hlsl +++ b/Packages/com.unity.render-pipelines.universal/Shaders/Particles/ParticlesSimpleLitInput.hlsl @@ -9,6 +9,7 @@ CBUFFER_START(UnityPerMaterial) float4 _SoftParticleFadeParams; float4 _CameraFadeParams; float4 _BaseMap_ST; + float4 _BaseMap_TexelSize; half4 _BaseColor; half4 _EmissionColor; half4 _BaseColorAddSubDiff; diff --git a/Packages/com.unity.render-pipelines.universal/Shaders/Particles/ParticlesUnlitInput.hlsl b/Packages/com.unity.render-pipelines.universal/Shaders/Particles/ParticlesUnlitInput.hlsl index ea096bf4678..b1766f2d10d 100644 --- a/Packages/com.unity.render-pipelines.universal/Shaders/Particles/ParticlesUnlitInput.hlsl +++ b/Packages/com.unity.render-pipelines.universal/Shaders/Particles/ParticlesUnlitInput.hlsl @@ -9,6 +9,7 @@ CBUFFER_START(UnityPerMaterial) float4 _SoftParticleFadeParams; float4 _CameraFadeParams; float4 _BaseMap_ST; + float4 _BaseMap_TexelSize; half4 _BaseColor; half4 _EmissionColor; half4 _BaseColorAddSubDiff; diff --git a/Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitInput.hlsl b/Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitInput.hlsl index 02cacb5c3a3..56b869627fa 100644 --- a/Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitInput.hlsl +++ b/Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitInput.hlsl @@ -7,6 +7,7 @@ CBUFFER_START(UnityPerMaterial) float4 _BaseMap_ST; + float4 _BaseMap_TexelSize; half4 _BaseColor; half4 _SpecColor; half4 _EmissionColor; diff --git a/Packages/com.unity.render-pipelines.universal/Shaders/Terrain/WavingGrass.shader b/Packages/com.unity.render-pipelines.universal/Shaders/Terrain/WavingGrass.shader index 6ebb3822262..f7b7cb78ac1 100644 --- a/Packages/com.unity.render-pipelines.universal/Shaders/Terrain/WavingGrass.shader +++ b/Packages/com.unity.render-pipelines.universal/Shaders/Terrain/WavingGrass.shader @@ -10,7 +10,7 @@ Shader "Hidden/TerrainEngine/Details/UniversalPipeline/WavingDoublePass" } SubShader { - Tags {"Queue" = "Geometry+200" "RenderType" = "Grass" "IgnoreProjector" = "True" "RenderPipeline" = "UniversalPipeline" "UniversalMaterialType" = "SimpleLit" }//"DisableBatching"="True" + Tags {"Queue" = "Geometry+200" "RenderType" = "Grass" "IgnoreProjector" = "True" "RenderPipeline" = "UniversalPipeline" "UniversalMaterialType" = "SimpleLit" "DisableBatching" = "True" } Cull Off LOD 200 diff --git a/Packages/com.unity.render-pipelines.universal/Shaders/Terrain/WavingGrassBillboard.shader b/Packages/com.unity.render-pipelines.universal/Shaders/Terrain/WavingGrassBillboard.shader index e50b8c3523c..b961e6985bd 100644 --- a/Packages/com.unity.render-pipelines.universal/Shaders/Terrain/WavingGrassBillboard.shader +++ b/Packages/com.unity.render-pipelines.universal/Shaders/Terrain/WavingGrassBillboard.shader @@ -10,7 +10,7 @@ Shader "Hidden/TerrainEngine/Details/UniversalPipeline/BillboardWavingDoublePass } SubShader { - Tags {"Queue" = "Geometry+200" "RenderType" = "GrassBillBoard" "IgnoreProjector" = "True" "RenderPipeline" = "UniversalPipeline" "UniversalMaterialType" = "SimpleLit" }//"DisableBatching"="True" + Tags {"Queue" = "Geometry+200" "RenderType" = "GrassBillBoard" "IgnoreProjector" = "True" "RenderPipeline" = "UniversalPipeline" "UniversalMaterialType" = "SimpleLit" "DisableBatching" = "True" } Cull Off LOD 200 diff --git a/Packages/com.unity.render-pipelines.universal/Shaders/UnlitInput.hlsl b/Packages/com.unity.render-pipelines.universal/Shaders/UnlitInput.hlsl index a71ec239f74..04939d7b162 100644 --- a/Packages/com.unity.render-pipelines.universal/Shaders/UnlitInput.hlsl +++ b/Packages/com.unity.render-pipelines.universal/Shaders/UnlitInput.hlsl @@ -6,6 +6,7 @@ CBUFFER_START(UnityPerMaterial) float4 _BaseMap_ST; + float4 _BaseMap_TexelSize; half4 _BaseColor; half _Cutoff; half _Surface; 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 fc5c568f359..f64393291de 100644 --- a/Packages/com.unity.render-pipelines.universal/Tests/Editor/EditorTests.cs +++ b/Packages/com.unity.render-pipelines.universal/Tests/Editor/EditorTests.cs @@ -160,7 +160,7 @@ public void UseReAllocateIfNeededWithoutTextureLeak() Object[] posttestTextures = Resources.FindObjectsOfTypeAll(typeof(Texture)); - Assert.AreEqual(pretestTextures.Length, posttestTextures.Length, "A texture leak is detected when using RenderingUtils.ReAllocateIfNeeded."); + Assert.That(posttestTextures, Is.EquivalentTo(pretestTextures), "A texture leak is detected when using RenderingUtils.ReAllocateIfNeeded."); } [TestCase(ShaderPathID.Lit)] diff --git a/Packages/com.unity.render-pipelines.universal/Tests/Runtime/Light2DTests.cs b/Packages/com.unity.render-pipelines.universal/Tests/Runtime/Light2DTests.cs index c42f754acad..cc65f17420d 100644 --- a/Packages/com.unity.render-pipelines.universal/Tests/Runtime/Light2DTests.cs +++ b/Packages/com.unity.render-pipelines.universal/Tests/Runtime/Light2DTests.cs @@ -14,6 +14,18 @@ class MultipleObjectLight2DTests GameObject m_TestObject4; GameObject m_TestObjectCached; + // Some residual Game Objects from previous test scenes can be left over, + // We destroy everything so they don't interfere with these tests + [OneTimeSetUp] + public void OneTimeSetup() + { + var allGameObjectsInScene = Object.FindObjectsByType(FindObjectsSortMode.None); + foreach (var go in allGameObjectsInScene) + { + Object.DestroyImmediate(go); + } + } + [SetUp] public void Setup() { diff --git a/Packages/com.unity.render-pipelines.universal/Tests/Runtime/LightClusteringTests.cs b/Packages/com.unity.render-pipelines.universal/Tests/Runtime/LightClusteringTests.cs new file mode 100644 index 00000000000..2ebcf991d8f --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Tests/Runtime/LightClusteringTests.cs @@ -0,0 +1,217 @@ +// Unit tests for light clustering code used in Forward+ and Deferred+ rendering +// modes. + +using NUnit.Framework; +using Unity.Collections; +using Unity.Jobs; +using Unity.Mathematics; +using UnityEngine.Rendering.Universal.Internal; +using UnityEngine.TestTools; + +namespace UnityEngine.Rendering.Universal.Tests +{ + class LightClusteringTests + { + [Description("Test that an orthographic camera tilted down at a 45 degree angle clusters reflection probes properly. This test specifically focuses on making sure that the convex hull logic in the tiling jobs works as intended, because the reflection probe volume forms collinear points. This test was added due to UUM-58983.")] + [UnityPlatform(include = new RuntimePlatform[] { RuntimePlatform.WindowsEditor, RuntimePlatform.WindowsPlayer, RuntimePlatform.OSXEditor, RuntimePlatform.OSXPlayer })] + [Test] + public void LightClustering_WithOrthographicCameraAndCollinearConvexHull_ZBinsAndTileMasksAreCorrect() + { + NativeArray lights = new(0, Allocator.TempJob); + NativeArray probes = new(1, Allocator.TempJob); + probes[0] = new VisibleReflectionProbe() + { + bounds = new Bounds(Vector3.zero, new Vector3(5, 5, 5)), + localToWorldMatrix = Matrix4x4.identity, + center = Vector3.zero, + blendDistance = 0, + }; + NativeArray zBins = new(UniversalRenderPipeline.maxZBinWords, Allocator.TempJob); + NativeArray tileMasks = new (UniversalRenderPipeline.maxTileWords, Allocator.TempJob); + + float4x4 worldToView = new float4x4( + new float4(1, 0, 0, 0), + new float4(0, 0.707106709f, 0.707106829f, 0), + new float4(0, 0.707106829f, -0.707106709f, 0), + new float4(0, 0, -10, 1) + ); + var worldToViews = new Fixed2(worldToView, worldToView); + float4x4 viewToClip = new float4x4( + new float4(0.0985474288f, 0, 0, 0), + new float4(0, 0.200000003f, 0, 0), + new float4(0, 0, -0.0200601816f, 0), + new float4(0, 0, -1.00601816f, 1) + ); + var viewToClips = new Fixed2(viewToClip, viewToClip); + int2 screenResolution = new(128, 128); + float nearPlane = 0.3f; + float farPlane = 100f; + + JobHandle handle = ForwardLights.ScheduleClusteringJobs( + lights, + probes, + zBins, + tileMasks, + worldToViews, + viewToClips, + 1, + screenResolution, + nearPlane, + farPlane, + true, + out int localLightCount, + out int directionalLightCount, + out int binCount, + out float zBinScale, + out float zBinOffset, + out int2 tileResolution, + out int actualTileWidth, + out int wordsPerTile + ); + JobHandle.ScheduleBatchedJobs(); + handle.Complete(); + + // Uncomment temporarily if the reference arrays need to be updated. + // Debug.Log(string.Join(",", zBins)); + // Debug.Log(string.Join(",", tileMasks)); + + // If the following assertions fail, there isn't currently good + // tooling to visualize the difference. A 3D texture slice viewer + // can be built that would fix this issue. But the cost-benefit is + // not worth it at the moment, since the diff of a PR that fails + // this test can be enough to go on. + // + // Also, these assertions can fail if a change is made includes more + // false positives, i.e. lights contributing to _more_ clusters than + // expected due to increased conservatism, or lights contributing to + // _less_ clusters due increased accuracy. In either of these cases, + // it is up to the author of these code changes to update the + // expected values. + CollectionAssert.AreEqual(expectedZBins0, zBins); + CollectionAssert.AreEqual(expectedTileMasks0, tileMasks); + + lights.Dispose(); + probes.Dispose(); + zBins.Dispose(); + tileMasks.Dispose(); + } + + static readonly uint[] expectedZBins0 = + { + 65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,0,1,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,0 + }; + + static readonly uint[] expectedTileMasks0 = + { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + }; + + [Description("The tiling job calculates an intersection between an XZ plane and the light volume to determine the range of tiles that the light affects. In the cases where this range falls completely outside of the screen, this test ensures that the ranges are clamped correctly to screen boundaries. If not tested, this bug affects the cone section of spot lights, the cap section of spot lights, and also point lights. This test was added due to UUM-84591.")] + [UnityPlatform(include = new RuntimePlatform[] { RuntimePlatform.WindowsEditor, RuntimePlatform.WindowsPlayer, RuntimePlatform.OSXEditor, RuntimePlatform.OSXPlayer })] + [Test] + public void LightClustering_WhenLightVolumeIntersectionWithXZPlaneIsOutsideTheScreen_ZBinsAndTileMasksAreCorrect() + { + NativeArray lights = new(1, Allocator.TempJob); + // Light world transform: + // UnityEditor.TransformWorldPlacementJSON:{"position":{"x":3.0,"y":3.0,"z":0.0},"rotation":{"x":0.511572539806366,"y":0.3068491518497467,"z":-0.7767189145088196,"w":0.20210090279579163},"scale":{"x":1.0,"y":1.0,"z":1.0}} + lights[0] = new VisibleLight() + { + lightType = LightType.Spot, + finalColor = Color.white, + screenRect = new Rect(0, 0, 1, 1), + localToWorldMatrix = new Matrix4x4( + new Vector4(-0.394897342f, 0, -0.918725133f, 0), + new Vector4(0.627902389f, -0.729997516f, -0.269892514f, 0), + new Vector4(-0.670667171f, -0.683449626f, 0.288274288f, 0), + new Vector4(3, 3, 0, 1) + ), + range = 10, + spotAngle = 100, + intersectsNearPlane = true, + intersectsFarPlane = false, + }; + NativeArray probes = new(0, Allocator.TempJob); + NativeArray zBins = new(UniversalRenderPipeline.maxZBinWords, Allocator.TempJob); + NativeArray tileMasks = new (UniversalRenderPipeline.maxTileWords, Allocator.TempJob); + + // Camera world transform: + // UnityEditor.TransformWorldPlacementJSON:{"position":{"x":-4.0,"y":1.0,"z":2.0},"rotation":{"x":0.32139381766319277,"y":0.663413941860199,"z":-0.3830222189426422,"w":0.5566704273223877},"scale":{"x":1.0,"y":1.0,"z":1.0}} + float4x4 worldToView = new float4x4( + new float4(-0.1736481f, 0.8528686f, -0.4924039f, 0f), + new float4(0f, 0.5f, 0.8660254f, 0f), + new float4(-0.9848078f, -0.1503837f, 0.08682406f, 0f), + new float4(1.275023f, 3.212242f, -3.009289f, 1f) + ); + var worldToViews = new Fixed2(worldToView, worldToView); + float4x4 viewToClip = new float4x4( + new float4(0.7968904f, 0f, 0f, 0f), + new float4(0f, 1.732051f, 0f, 0f), + new float4(0f, 0f, -1.0006f, -1f), + new float4(0f, 0f, -0.60018f, 0f) + ); + var viewToClips = new Fixed2(viewToClip, viewToClip); + int2 screenResolution = new(128, 128); + float nearPlane = 0.3f; + float farPlane = 1000f; + + JobHandle handle = ForwardLights.ScheduleClusteringJobs( + lights, + probes, + zBins, + tileMasks, + worldToViews, + viewToClips, + 1, + screenResolution, + nearPlane, + farPlane, + false, + out int localLightCount, + out int directionalLightCount, + out int binCount, + out float zBinScale, + out float zBinOffset, + out int2 tileResolution, + out int actualTileWidth, + out int wordsPerTile + ); + JobHandle.ScheduleBatchedJobs(); + handle.Complete(); + + // Uncomment temporarily if the reference arrays need to be updated. + // Debug.Log(string.Join(",", zBins)); + // Debug.Log(string.Join(",", tileMasks)); + + // If the following assertions fail, there isn't currently good + // tooling to visualize the difference. A 3D texture slice viewer + // can be built that would fix this issue. But the cost-benefit is + // not worth it at the moment, since the diff of a PR that fails + // this test can be enough to go on. + // + // Also, these assertions can fail if a change is made includes more + // false positives, i.e. lights contributing to _more_ clusters than + // expected due to increased conservatism, or lights contributing to + // _less_ clusters due increased accuracy. In either of these cases, + // it is up to the author of these code changes to update the + // expected values. + CollectionAssert.AreEqual(expectedZBins1, zBins); + CollectionAssert.AreEqual(expectedTileMasks1, tileMasks); + + lights.Dispose(); + probes.Dispose(); + zBins.Dispose(); + tileMasks.Dispose(); + } + + static readonly uint[] expectedZBins1 = + { + 0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,0,65535,1,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,65535,65535,0,0 + }; + + static readonly uint[] expectedTileMasks1 = + { + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + }; + + } +} diff --git a/Packages/com.unity.render-pipelines.universal/Tests/Runtime/LightClusteringTests.cs.meta b/Packages/com.unity.render-pipelines.universal/Tests/Runtime/LightClusteringTests.cs.meta new file mode 100644 index 00000000000..64efedcef1c --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Tests/Runtime/LightClusteringTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a545bf4d761e01b42818d52899606ced \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.universal/Tests/Runtime/RuntimeTests.cs b/Packages/com.unity.render-pipelines.universal/Tests/Runtime/RuntimeTests.cs index f342f82a0e9..1bca05b7aa3 100644 --- a/Packages/com.unity.render-pipelines.universal/Tests/Runtime/RuntimeTests.cs +++ b/Packages/com.unity.render-pipelines.universal/Tests/Runtime/RuntimeTests.cs @@ -38,7 +38,7 @@ public IEnumerator PipelineHasCorrectColorSpace() var rr = new UnityEngine.Rendering.RenderPipeline.StandardRequest(); rr.destination = new RenderTexture(128, 128, UnityEngine.Experimental.Rendering.GraphicsFormat.R8G8B8A8_SRGB, - CoreUtils.GetDefaultDepthStencilFormat()); + CoreUtils.GetDefaultDepthOnlyFormat()); rr.mipLevel = 0; rr.slice = 0; rr.face = CubemapFace.Unknown; @@ -58,7 +58,7 @@ public IEnumerator PipelineSetsAndRestoreGlobalShaderTagCorrectly() AssetCheck(); var rr = new UnityEngine.Rendering.RenderPipeline.StandardRequest(); - rr.destination = new RenderTexture(128, 128, UnityEngine.Experimental.Rendering.GraphicsFormat.R8G8B8A8_SRGB, UnityEngine.Experimental.Rendering.GraphicsFormat.D32_SFloat); + rr.destination = new RenderTexture(128, 128, UnityEngine.Experimental.Rendering.GraphicsFormat.R8G8B8A8_SRGB, CoreUtils.GetDefaultDepthOnlyFormat()); rr.mipLevel = 0; rr.slice = 0; rr.face = CubemapFace.Unknown; diff --git a/Packages/com.unity.render-pipelines.universal/ValidationExceptions.json b/Packages/com.unity.render-pipelines.universal/ValidationExceptions.json index c80a047a6f5..11ccc691265 100644 --- a/Packages/com.unity.render-pipelines.universal/ValidationExceptions.json +++ b/Packages/com.unity.render-pipelines.universal/ValidationExceptions.json @@ -2,7 +2,7 @@ "Exceptions": [ { "ValidationTest": "API Updater Configuration Validation", - "PackageVersion": "17.0.3" + "PackageVersion": "17.2.0" } ] } \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.universal/package.json b/Packages/com.unity.render-pipelines.universal/package.json index 8ca0a24e8c1..b9f2a6fbdb9 100644 --- a/Packages/com.unity.render-pipelines.universal/package.json +++ b/Packages/com.unity.render-pipelines.universal/package.json @@ -1,12 +1,12 @@ { "name": "com.unity.render-pipelines.universal", "description": "The Universal Render Pipeline (URP) is a prebuilt Scriptable Render Pipeline, made by Unity. URP provides artist-friendly workflows that let you quickly and easily create optimized graphics across a range of platforms, from mobile to high-end consoles and PCs.", - "version": "17.0.3", - "unity": "6000.0", + "version": "17.2.0", + "unity": "6000.2", "displayName": "Universal RP", "dependencies": { - "com.unity.render-pipelines.core": "17.0.3", - "com.unity.shadergraph": "17.0.3", + "com.unity.render-pipelines.core": "17.2.0", + "com.unity.shadergraph": "17.2.0", "com.unity.render-pipelines.universal-config": "17.0.3" }, "keywords": [ diff --git a/Packages/com.unity.shadergraph/CHANGELOG.md b/Packages/com.unity.shadergraph/CHANGELOG.md index 1b4d279a76b..41a16873cbe 100644 --- a/Packages/com.unity.shadergraph/CHANGELOG.md +++ b/Packages/com.unity.shadergraph/CHANGELOG.md @@ -10,6 +10,101 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. Version Updated The version number for this package has increased due to a version update of a related graphics package. +## [17.0.3] - 2025-02-13 + +This version is compatible with Unity 6000.2.0a17. + +### Changed +- Added a new *Shader Graph UGUI Shaders* sample content set to the Shader Graph package. This sample demonstrates how to use the new Canvas target in Shader Graph to create dynamic UI elements. You can import this sample from the *Samples* tab in the Package Manager after selecting the Shader Graph package. +- Added support for spacewarp to Shader Graph. +- Added a new *Shader Graph UGUI Shaders* sample content set to the Shader Graph package. This sample demonstrates how to use the new Canvas target in Shader Graph to create dynamic UI elements. You can import this sample from the *Samples* tab in the Package Manager after selecting the Shader Graph package. +- Removed duplicate LIGHTMAP_ON and DIRLIGHTMAP_COMBINED variants when generating shaders for builtin-deferred. +- Added a new set of sample content - Shader Graph UGUI Shaders - to the Shader Graph package that contains examples of how to use the new Canvas target in Shader Graph to create dynamic UI elements. This new sample can be imported from the Sample tab of the Package Manager after selecting the Shader Graph package + +### Fixed +- Fixed "Element 'UnityEditor.UIElements.VisualSplitter' is missing a UxmlElementAttribute" error logged in the Console when creating a new Node in ShaderGraph +- Fixed an issue where horizontal scrollbars did not work as expected in the Blackboard or Graph Inspector. +- Fixed an issue where certain warning messages did not display with enough contrast in the Blackboard and Graph Inspector. +- Fixed "Shader error in 'ProBuilder6/Standard Vertex Color': 'PBRDeferredFragment'" error logged in the console when compiling the shader. +- Fixed the generation of new artifact ID of ShaderGraph on every reimport. +- Fixed an issue where the Main Preview could be resized beyond its containing Shader Graph window +- Allowed latin alphabet for variable names. +- Correct sticky note context menu shortcut display text. +- Color properties now default to opaque (alpha = 1). +- Forum link in info replaced with link to unity discussions. +- Exposed aniso setting on blackboard sampler state properties. +- Added SHADERGRAPH_PREVIEW_MAIN define specifically for main previews. +- Addressed issue where HDR Colors would cause errors when used with custom render to texture target. +- Fixed issue where some resources failed to dispose properly when entering play mode in editor. +- Addressed an issue where the property sheet could complain about type mismatch for preview properties. +- Fixed null reference when shadergraph editor is open while entering playmode. +- Custom function node previews are hidden unless the first output is a previewable type (vector or float). +- Fixed issue where graphs with groups in them would sometimes become modified upon opening the shader graph editor. +- Enabled custom interpolators for custom sprite lit target. +- Fixed an issue where the Blackboard would not scroll to show newly-created properties. +- Fixed a bug that a shader graph is reverted to its last saved state when entering Play Mode without saving changes. +- Added missing documentation about the Custom Render Texture in Shader Graph. +- [Metal] Fix shader compilation errors due to Foveated Rendering when building URP 3D template. +- Fixed an issue where the Main Light Direction node always returned 0 on the built-in render pipeline. +- Added new manipulator for ShaderGraph MainPreview to fix wrong drag handing on OSX. +- Fixed an issue where Unity pragmas were not used in files included by the Custom Function Node, and added a "Use Pragmas" toggle to enable/disable them as needed. +- Mark a shader graph dirty when toggling checkboxes in its Graph Settings. +- Fixed Shader warnings in URP ShaderGraph when using the Normal From Texture node. +- Fixed an issue with addding a Vector4 slot in a sub-graph when converting from a node. +- Fixed an issue where an unnecessary error message was generated for non-conflicting duplicate property declarations when using multiple targets. +- Fixed an issue where right-clicking on the Blackboard or Graph Inspector displayed an incorrect context menu. +- Fixed an issue where the Create Node menu remained visible on screen when closing a Shader Graph window. +- Fixed an issue where the Console logged the error "Element 'UnityEditor.UIElements.VisualSplitter' is missing a UxmlElementAttribute" when creating a new node in Shader Graph. +- Fixed "Shader error in 'ProBuilder6/Standard Vertex Color': 'PBRDeferredFragment'" error logged in the console when compiling the shader. +- Allowed latin alphabet for variable names. +- Correct sticky note context menu shortcut display text. +- Color properties now default to opaque (alpha = 1). +- Forum link in info replaced with link to unity discussions. +- Exposed aniso setting on blackboard sampler state properties. +- Added SHADERGRAPH_PREVIEW_MAIN define specifically for main previews. +- Fixed an issue where the Main Preview could be resized beyond its containing Shader Graph window. +- Fixed an issue where using HDR colors with custom Render Texture targets caused errors. +- Fixed an issue where some resources were not properly disposed of when entering Play mode in the Editor. +- Fixed an issue where the property sheet displayed an incorrect type mismatch error for preview properties. +- Fixed a null reference exception that occurred when the Shader Graph Editor was open while entering Play mode. +- Updated the Custom Function Node so that previews are hidden unless the first output is a previewable type, such as a vector or float. +- Fixed an issue where graphs containing groups were unintentionally modified when opening the Shader Graph Editor. +- Enabled custom interpolators for custom sprite lit targets. The shader's *Sprite Custom Lit* material mode now changes the sprite to the desired color instead of remaining black. +- Added an issue where convert-to subgraph would sometimes result in an exception. +- Added an issue where the GI Node would only display correctly after deserialization. +- Added support for perceptual color mode for gradients in shader graph. +- Fixed an issue where an HDRP fullscreen shader graph imported into a URP project would fail to import under some circumstances. +- Fixed shader graph built-in pipeline variants not getting stripped when an SRP is active. +- Fixed an issue where moving a property node in a Shader Graph with no targets would log an error. +- Fixed an issue where the Custom Function node's "Body" field would expand off-screen instead of scrolling. +- Disallowed shader variant related settings to be set to negative values. +- Fixed a null reference exception when shader variant project settings were changed under certain circumstances. +- Fixed an issue where the Graph Inspector would not update after changing a node's precision from the context menu. +- Fixed an issue where using a color picker would cause the main preview to display cyan until the color picker was closed. +- Fixed an issue where some keyboard shortcuts did not display with the correct alignment in context menus. +- Fixed an issue so users can no longer select 'Delete' for context blocks. +- Fixed identifier collision detection on properties. +- Added sticky note checks to the group shortcuts. +- Fixed node previews toggle shortcut. +- Fixed an issue in ShaderGraph where undoing changes to a property after modifying its value in the Graph Inspector would cause the property to become deselected. +- Fixed an issue in Shader Graph with an undeclared identifier error around foveated rendering area. +- Fixed a bug that Normal From Height node in a shader graph might return an invalid value when using 16-bit half precision. +- Fixed 'Objects are trying to be loaded during a domain backup' errors due to invalid serialization of some shader graphs. +- Changed the name displayed in a Graph inspector when a selected BlockNode has changed. +- Fixed an issue so that pasting an empty group positions it based on the cursor's location. +- Fixed an issue with low quality Graph Inspector and Open Shader Graph User Manual icons. +- Added padding to Shader Graph Preferences settings. +- Addressed an issue where precision mismatch could result in an asset failing to import. +- Fixed an issue that caused errors in the Feature Examples sample content for Shader Graph. +- Fixed the issue with `NullReferenceException` when updating a legacy node for second time through undo. +- Fixed an issue where a shader graph was reverted to its last saved state when entering Play Mode without saving changes. +- [Metal] Fix shader compilation errors due to Foveated Rendering when building URP 3D template. +- Fixed an issue where Unity pragmas were not used in files included by the Custom Function Node, and added a "Use Pragmas" toggle to enable/disable them as needed. +- Fixed an issue where the Main Light Direction node always returned 0 on the built-in render pipeline. +- Fixed an issue where the shader graph was not marked dirty when toggling checkboxes in its Graph Settings. +- Fixed missing documentation about the Custom Render Texture in Shader Graph. +- Fixed "Shader error in 'ProBuilder6/Standard Vertex Color': 'PBRDeferredFragment'" error logged in the console when compiling the shader. + ## [17.0.2] - 2024-04-02 This version is compatible with Unity 6000.0.0b15. diff --git a/Packages/com.unity.shadergraph/Documentation~/Color-Modes.md b/Packages/com.unity.shadergraph/Documentation~/Color-Modes.md index 630ac204f20..c5204fe4826 100644 --- a/Packages/com.unity.shadergraph/Documentation~/Color-Modes.md +++ b/Packages/com.unity.shadergraph/Documentation~/Color-Modes.md @@ -8,11 +8,12 @@ Shader Graph can display colors on nodes in your graph to improve readability. T ## Modes -| Name | Description | -|:-----|:------------| -| None | Does not display colors on the nodes. All nodes use the default gray. | -| Category | Displays colors on the nodes based on their assigned category. See **Category Colors** below. | -| Precision | Displays colors on the nodes based on the current [Precision Mode](Precision-Modes) in use. | +| Name | Description | +|:-------------|:------------| +| None | Does not display colors on the nodes. All nodes use the default gray. | +| Category | Displays colors on the nodes based on their assigned category. See **Category Colors** below. | +| Heatmap | Displays colors on the nodes based on the nodes relative performance cost. By default, dark colored nodes contribute very little to the overall GPU performance cost of the shader and brighter colored nodes require more GPU computation to run. | +| Precision | Displays colors on the nodes based on the current [Precision Mode](Precision-Modes) in use. | | User Defined | Lets you set the display colors on a per-node basis. These are custom colors for your graph. See **User Defined Colors** below. | ### Category Colors @@ -23,15 +24,15 @@ This mode displays colors on the nodes based on their category. See the [Node Li The table below lists current categories and their corresponding colors. -| Name | Color | Hex Value | -|:-----|:------|:----------| -| Artistic | ![#DB773B](https://placehold.it/15/DB773B/000000?text=+) | #DB773B | -| Channel | ![#97D13D](https://placehold.it/15/97D13D/000000?text=+) | #97D13D | -| Input | ![#CB3022](https://placehold.it/15/CB3022/000000?text=+) | #CB3022 | -| Math | ![#4B92F3](https://placehold.it/15/4B92F3/000000?text=+) | #4B92F3 | -| Procedural | ![#9C4FFF](https://placehold.it/15/9C4FFF/000000?text=+) | #9C4FFF | -| Utility | ![#AEAEAE](https://placehold.it/15/AEAEAE/000000?text=+) | #AEAEAE | -| UV | ![#08D78B](https://placehold.it/15/08D78B/000000?text=+) | #08D78B | +| Name | Color | Hex Value | +|:-----------|:---------------------------------------------------------|:----------| +| Artistic | ![#DB773B](https://placehold.it/15/DB773B/000000?text=+) | #DB773B | +| Channel | ![#97D13D](https://placehold.it/15/97D13D/000000?text=+) | #97D13D | +| Input | ![#CB3022](https://placehold.it/15/CB3022/000000?text=+) | #CB3022 | +| Math | ![#4B92F3](https://placehold.it/15/4B92F3/000000?text=+) | #4B92F3 | +| Procedural | ![#9C4FFF](https://placehold.it/15/9C4FFF/000000?text=+) | #9C4FFF | +| Utility | ![#AEAEAE](https://placehold.it/15/AEAEAE/000000?text=+) | #AEAEAE | +| UV | ![#08D78B](https://placehold.it/15/08D78B/000000?text=+) | #08D78B | **Note:** [Sub Graph](Sub-Graph.md) nodes in a main [Shader Graph](index.md) fall in the Utility category. If you select **Category** mode, all Sub Graphs use the Utility color. @@ -45,10 +46,10 @@ This mode displays colors on the nodes based on user preferences. In this mode, To set a custom color for a node, right-click on the target node to bring up the the context menu, and select **Color**. -| Option | Description | -|:-------|:------------| +| Option | Description | +|:------- |:------------| | Change... |Brings up a color picker menu and lets you set your own custom color on the node. | -| Reset | Removes the currently selected color and sets it to the default gray. | +| Reset | Removes the currently selected color and sets it to the default gray. | ![](images/Color-Mode-User-Defined.png) diff --git a/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-Custom-UI-components.md b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-Custom-UI-components.md new file mode 100644 index 00000000000..4cebeac35bd --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-Custom-UI-components.md @@ -0,0 +1,13 @@ +# Custom UI components + +The sample contains a few custom UI components to reproduce the behavior of some elements such as buttons, toggles and sliders, passing data to the material assigned. +You can add these components from the main menu **Component** > **UI** > **Shader Graph Samples**. + +| Component | Description | +|:------------|:-------------------| +| **RectTransform Size** | Passes the gameObject's RectTransform's size to the graphic's material, as a _RectTransformSize Vector2 property. This is then fetched in a Shader Graph or Subgraph by using the RectTransform Size custom node (see below).| +| **Button** | Reproduces the behavior of a UI Button component. The button state is fetched in a Shader Graph or Subgraph by using the Selectable State custom node (see below). | +| **Toggle** | Reproduces the behavior of a UI Toggle component. The toggle 'on' state is fetched in a Shader Graph or Subgraph by using the Toggle State custom node (see below). Its state as a selectable is fetched in a Shader Graph or Subgraph by using the Selectable State custom node (see below).| +| **Meter** | A passive meter to be used as a progress indicator or gauge. It passes a normalized value to the Graphics material as a float "_MeterValue" property. Use the MeterValue node to fetch the value in a Shader Graph or Subgraph.| +| **RangeBar** | A passive range bar to be used as a progress bar, or in combination with a Range Slider.| +| **Slider** | A custom slider, handling drag events. Its value is fetched in a Shader Graph or Subgraph by using the Slider Value custom node (see below). Its state as a selectable is fetched in a Shader Graph or Subgraph by using the Selectable State custom node (see below).| \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-Custom-nodes.md b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-Custom-nodes.md new file mode 100644 index 00000000000..0eb3908039a --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-Custom-nodes.md @@ -0,0 +1,26 @@ +# Custom nodes + +The sample contains a few custom shader graph nodes to facilitate the setup. +The custom nodes are broken into two categories: +- **Inline Properties** - These nodes automatically add a hidden property to the shader graph and fetch its value. +- **Branch** - These nodes enable branching on the value of specific inputs such as a Button state. + +## Inline Property Nodes +These nodes automatically add a hidden property to the shader graph and fetch its value. +You can also just manually add the property to the shader graph, but these custom nodes let you nest them in subgraphs. + +| Node | Description | +|:---------------|:-------------------| +| **RectTransform Size** | Adds a _RectTransformSize Vector2 hidden property to the graph and outputs its value. This is fed by the RectTransformSize component required by some subgraphs to perform aspect ratio based math. +| **Selectable State** | Adds a _State float hidden property to the graph and outputs its value. This is fed by the Selectable components (CustomButton, CustomToggle and Slider). The value represents the mutually exclusive state such as: **0 - Normal**, **1 - Highlighted**, **2 - Pressed**, **3 - Selected**, **4 - Disabled** | +| **Toggle State** | Adds a _isOn Boolean hidden property to the graph and outputs its value. This is fed by the CustomToggle component. | +| **Meter Value** | Adds a _MeterValue float hidden property to the graph and outputs its value. This is fed by the Meter component and allows creating progress, health or other indicators. | +| **Slider Value** | Adds a _SliderValue Vector3 hidden property to the graph and outputs its value as: **Value** - The normalized Slider Value as float. **Direction** - The normalized Slider Direction as Vector2. This is fed by the Slider component and allows creating sliders of which the direction and value can be set from the component. | +| **Range Bar** | Adds a _RangeBar Vector4 hidden property to the graph and outputs its value as: **Min** - The normalized Slider Min Value as float. **Max** - The normalized Slider Max Value as float. **Direction** - The normalized Slider Direction as Vector2. This is fed by the RangeBar component and allows creating range bars of which the direction and min/max values can be set from the component. | + +## Branch Nodes +These nodes let you branch on the value of specific inputs such as a Button state. +The motivation behind making them custom nodes rather than subgraphs lies in the ability to feature dynamic ports. + +### SelectableBranch +This node lets you branch depending on the state of a Selectable element such as a CustomButton. \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-Examples.md b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-Examples.md new file mode 100644 index 00000000000..54bd2f1a785 --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-Examples.md @@ -0,0 +1,222 @@ +# Examples +These example shaders are built using the subgraph nodes. They show how the subgraph nodes work and how you can combine them to create backgrounds, buttons, and meters. + +## Backgrounds +The background examples are shaders that you can assign to Canvas Image objects that serve as backgrounds for other UI elements. + +### 80sSunset +This example combines the LinearTime, Perspective, Move, SquareTiles, Bars, and AntiAliasing nodes to generate a perspective grid that scrolls into the distance. + +Library Subgraph Nodes used in this example: +- Perspective +- LinearTime +- Move +- SquareTiles +- LinearGradient +- Bars +- AntiAliasing +- Gradients + +### Animated Clouds +This example combines animated procedural noise to create interesting dynamic patterns. + +### Blurred Hexagon +This example uses the SceneColorBlurred node to create a blurred version of the scene behind the user interface. It also uses the HexagonTiles node to generate a hexagon grid pattern. You can use the HexagonDisolve parameter to shrink and grow the size of the hexagons, which makes the pattern appear to dissolve. + +Library Subgraph Nodes used in this example: +- SceneColorBlurred +- HexagonTiles + +### Halftone +This example uses the Halftone node to convert the rendered scene behind the UI elements into a halftone pattern. It converts each of the three channels (red, green, and blue) into a halftone dot pattern, then recombines them to create the final image. + +Library Subgraph Nodes used in this example: +- Halftone + +### LavaLamp +This is an illustration of how distorted circle shapes can be animated to move around in random directions, and how signed distance field shapes can be blended together using the Smooth output of the SDFUnite node to merge the shapes. + +Library Subgraph Nodes used in this example: +- SineTime +- Move +- Circle +- SDFUnite + +### Pixelation +This example shows how to use the PosterizeUV node to quantize the UV coordinates used to sample the scene. The result is a version of the scene that appears to be made of larger pixels. + +Library Subgraph Nodes used in this sample: +- PosterizeUV + +### RoundedRectangleBubble +This example shows how to create a rounded frame as a background, including an outline and a drop shadow, for other UI elements. To maintain the correct aspect ratio of the rounded corners in this shader, connect the exposed WidthHeight parameter of this shader to the UI Image element’s Width and Height parameters. You can do this with the ImageSize script. Refer to [How to make shapes that adapt to the aspect ratio of the UI element](Shader-Graph-Sample-UGUI-Shaders-How-tos-aspect-ratio.md) for details on how to accomplish this. + +Library Subgraph Nodes used in this sample: +- Scale +- LinearGradient +- Move +- Rectangle + +### TechGrid +This example uses the SquareTiles node to generate a grid pattern and the AnimatedClouds node to create a smooth noise. These effects together create a nice tech grid for a background. + +Library Subgraph Nodes used in this sample: +- AnimatedClouds +- SquareTiles + +### WarpedGradient +This example shows how to warp UV coordinates with procedural noise and then use those warped coordinates to generate a deformed and blurry circle. It also darkens the corners of the screen using the Vignette node. + +Library Subgraph Nodes used in this sample: +- Move +- Circle +- Vignette + +## Buttons +![](images/UITools-buttons.png) +These examples show how to create buttons of various visual styles. Each button has exposed parameters that control the button’s visual states - selected, pressed, and active. In the example scene, you can take a look at how these material parameters are connected to the button’s state events to drive the appearance of the button. + +Many shape elements of the buttons use the AntiAliasing node which converts SDFs and gradients to perfectly anti-aliased shapes, regardless of scale or camera position. For more details on how to accomplish this, refer to [How to create a resolution-independent shape](Shader-Graph-Sample-UGUI-Shaders-How-tos-Res-indepenent.md). + +### AquaButton +This example shows how to create an aqua-style button and includes a specular highlight, gradient shading, a fresnel outline, and a colored drop shadow. It adjusts to the aspect ratio of the button object it’s assigned to using the WidthHeight parameter. In the sample scene, notice that this material parameter is connected to the UI object’s width and height values using the ImageSize script. + +Library Subgraph Nodes used in this sample: +- Move +- AspectRatio +- AnimatedSheen +- Pill + +### SciFiButton +This example uses multiple circular elements and illustrates how multiple elements can be combined with subtract, maximum, lerp, and multiply. + +Library Subgraph Nodes used in this sample: +- Circle +- CircleSegments +- AntiAliasing +- Scale +- PlayerIcon + +### SciFiButton2 +This button example is similar to the Tech Grid background. It uses the SquareTiles node to create a grid and the AnimatedClouds node to create a smooth noise background. It also illustrates the use of the Tilt node to turn the rectangle shape into a parallelogram. + +Library Subgraph Nodes used in this sample: +- AspectRatio +- LinearTime +- CircleSegments +- Rectangle +- AntiAliasing +- AnimatedSheen +- SquareTiles + +### SimpleButton +This is an example of how you can create a simple button with a smooth gradient color, a drop shadow, and Selected, Pressed, and Active states. + +Library Subgraph Nodes used in this sample: +- Move +- Scale +- LinearGradient +- Rectangle +- AntiAliasing + +## Indicators +![](images/UITools-meters2.png) +These UI elements indicate things to the player visually such as health level, ammo count, shield power, etc. All of them have an exposed material parameter called “Health” that drives the level of the meter. Using a script, you can connect this parameter to any value in your project to indicate its level to the player. + +### AquaMeter +The style of this meter matches the AquaButton example - but instead of exposing button states, it has a controllable fill meter. + +Library Subgraph Nodes used in this sample: +- AspectRatio +- Pill +- AntiAliasing +- HistogramScan + +### DialMeter +This example uses polar coordinates to create a circular-shaped meter. It also uses drop-shadows on both the inner circle and the outer shape. The player icon at the center could be replaced with a texture sample or another SDF shape. + +Library Subgraph Nodes used in this sample: +- AspectRatio +- Pill +- AntiAliasing +- HistogramScan + +### FantasyMeter +This example could be used as a health or mana indicator for a fantasy game. It uses the SphereGradient node to generate fake lighting and reflections based on a procedurally-generated sphere shape. The sphere defaults to being filled with red liquid, but you can easily change the color to anything you like by using the exposed Color parameter. + +Library Subgraph Nodes used in this sample: +- LinearGradient +- PosterizeGradient +- Hash11 +- LinearTime +- GridTiles +- Move +- Circle +- HistogramScan +- Waves +- AntiAliasing +- Gradients +- SphereGradient + +### SciFiMeter +This meter could be used to indicate ammo or shield level in a sci-fi-themed game. The cool thing about this one is that it starts to shake when the indicator gets low - to emphasize the urgency of low ammo or shields. + +Library Subgraph Nodes used in this sample: +- Shake +- AspectRatio +- Tilt +- Rectangle +- AntiAliasing +- WindowBlinds +- PosterizeGradient +- HistogramScan + +## Progress Bars +![](images/UITools-meters.png) + +### FancyLoading +This is a circle that’s made of circles. Each circle starts large and then gets smaller over time and the effect is offset so it happens in a wave pattern. The larger circle pattern also appears to move and change perspective over time as if it were tilting around in a 3D space. These effects are all achieved by chaining together various nodes from the Subgraph Library. + +Library Subgraph Nodes used in this sample: +- SineTime +- Perspective +- Scale +- Move +- LinearTime +- GridTiles +- Circle +- AntiAliasing + +### GradientBar +This is a pill-shaped bar that fills up as the progress parameter increases from zero to one. The aspect ratio adapts if it’s correctly connected to the width and height parameters of the Canvas Image element it’s assigned to. + +Library Subgraph Nodes used in this sample: +- Move +- Pill +- AntiAliasing +- Invert +- LinearGradient +- Scale +- Gradients + +### ProgressCircle +This is a round dial that fills up in a circle shape as the progress parameter increases from zero to one. The start color and end color are exposed as parameters and can be adjusted to create different looks. + +Library Subgraph Nodes used in this sample: +- Invert +- PosterizeGradient +- HistogramScan +- Circle +- AntiAliasing +- CircleSegments + +### SimpleLoading +This is a circle made of pill-shaped elements that fade from white to black over time. Each element fades in a wave-like pattern that appears to go around the circle. This type of animation is very commonly used as a loading indicator. + +Library Subgraph Nodes used in this sample: +- Tilt +- Scale +- LinearTime +- GridTiles +- Pill +- AntiAliasing \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-Getting-Started.md b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-Getting-Started.md new file mode 100644 index 00000000000..6502f581dfe --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-Getting-Started.md @@ -0,0 +1,22 @@ +# Getting Started +After you import the sample from the Package Manager open this scene: + + - `Assets\Samples\Shader Graph\\UGUI Shaders\Scenes\UISampleScene.unity` + +Here you can see some sample buttons, indicators, and backgrounds. All of these UI elements were constructed in Shader Graph using the subgraphs in this sample. + +To see the subgraphs in a gallery, open this Shader Graph file: + - `Assets/Samples/Shader Graph//UGUI Shaders/Subgraphs/SubgraphLibrary.shadergraph` + +Here you’ll see all of the subgraphs grouped according to the category they’re in. You can double-click any of them to jump into the subgraph to see what it does. +You can also right click in any Shader Graph shader and find the subgraphs in the UI category in the Add Node window. + +To see examples of how to use the subgraphs, open the following Shader Graph asset: + - `Assets/Samples/Shader Graph/17.0.3/UGUI Shaders/Examples/SimpleExamples.shadergraph` + +This file contains several simple examples that show how the UI subgraphs can be used together to create interesting effects. It’s a good demonstration of the functionality of the subgraph nodes. + +To see examples of how to create UI buttons and indicators, open this Shader Graph file: + - `Assets/Samples/Shader Graph/17.0.3/UGUI Shaders/Examples/ButtonsAndIndicators.shadergraph` + +This file contains several example buttons and indicators. You can double click on any of them to open the Shader Graph assets and see how they’re constructed. \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-How-tos-Button.md b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-How-tos-Button.md new file mode 100644 index 00000000000..bf87b216d0e --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-How-tos-Button.md @@ -0,0 +1,16 @@ +# How to create a functioning button +Buttons have multiple states depending on the user’s interaction with them. The button may change its appearance when the user’s mouse is hovering over the button. And when it’s pressed, the button may also change to indicate the press. That means that the shader needs to create the various visual styles and expose parameters to trigger them. You’ll then need to connect those exposed parameters to the button’s events. Follow these steps to learn how to do that. + +1. Create a new Shader Graph asset. +1. In the Graph Inspector, make sure that the Shader Graph’s Material setting is set to **Canvas**. +1. Open the shader’s Blackboard and add two boolean parameters. +1. Name the parameters **Selected** and **Pressed**. +1. Drag these parameters into your graph and use them to create a shader that changes depending on if the values are true or false. The SimpleButton Shader Graph asset is a good example of this. Find it here: `Assets/Samples/Shader Graph//UGUI Shaders/Examples/Buttons/SimpleButton` +1. In your scene, create a new Canvas element (if there isn’t one already) in the **Hierarchy** panel. (Right click in the Hierarchy panel and select **UI** > **Canvas**). +1. Add a Button element to the Canvas. (Right click on the Canvas element and select **UI** > **Button - TextMeshPro**) Then select the Button element. +1. Select the material associated with your shader in the Project panel and drag and drop it into the Material slot in the Inspector for the Image UI element. Now your shader’s material is assigned to the UI element. +1. Set the button’s **Source Image** and **Transition** to None. The shader provides these. +- Now click the **Add Component** button at the bottom of the Inspector and add the script called **UI Material**. This script exposes the Selected and Pressed parameters so they can be used by other scripts. +1. Click **Add Component** again and add the script called **ButtonMaterial**. This script connects the material’s exposed button parameters to the button’s events. + +Now you have a button that correctly passes information to its material when the mouse pointer hovers over the button, presses down on the button, stops pressing the button, and moves off of the button. You can set up the shader to respond to these events visually in whatever way makes sense for the style. For example, when the button is pressed, you might move the button down slightly, invert its color, or get darker. When the mouse is hovering over the button, you might make an outline appear around it, or turn on an animated sheen effect. \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-How-tos-Res-indepenent.md b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-How-tos-Res-indepenent.md new file mode 100644 index 00000000000..3e753b36c7b --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-How-tos-Res-indepenent.md @@ -0,0 +1,12 @@ +# How to create a resolution-independent shape +When creating a UI element, it’s very useful to be able to make it resolution-independent - meaning that it looks sharp and crisp regardless of if it’s rendered at very high resolution or very low resolution. UI elements that are based on textures are resolution dependent. The texture itself has a specific resolution - so if the UI element is rendered at a higher resolution than the texture, the result will be blurry, and if the texture is a higher resolution than the UI element is rendered, you’ll get filtering artifacts and waste texture memory. + +With the nodes in the library included with this sample set, you can generate shapes procedurally instead of with textures. You can render these shapes at any resolution and they will always look perfectly sharp and smoothly anti-aliased. Here’s how to do it: + +1. Add one of the SDF shape nodes (Circle, Hexagon, Pill, Rectangle, Star, or Triangle) to your graph. You can find them in the Add Node menu under UI/SDFs. These nodes generate shapes using signed distance fields. If you grab the output from the Fill output port, you’ll get a shape, but you can also get the raw SDF output from the SDF output port. Each pixel in the SDF is a value that represents the distance to the nearest edge of the shape. Pixels that are inside the shape have a negative value to indicate that. +1. Add an AntiAliasing node to your graph. You can find it in the Add Node menu under UI/Helpers. The AntiAliasing node is designed to “resolve” an SDF into an anti-aliased shape in a resolution-independent way. +1. Connect the SDF output port of your SDF shape node to the Gradient input port of the AntiAliasing node. +1. Set the Cutoff port to a default value of zero. The AntiAliasing node will convert the shape’s SDF into a solid shape using a method that correctly adapts to the number of pixels on the screen. +1. To make your shape white and the background black, connect the **Out** port of the AntiAliasing node to a One Minus node to invert the result. + +You now have a resolution-independent shape. You can fill the whole screen with this shape and render it at 8k, or scale it down to a tiny portion of the screen and render it on a low-end smartphone and it will have a sharp, anti-aliased edge in all cases. \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-How-tos-aspect-ratio.md b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-How-tos-aspect-ratio.md new file mode 100644 index 00000000000..aa4597e78e4 --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-How-tos-aspect-ratio.md @@ -0,0 +1,18 @@ +# How to make shapes that adapt to the aspect ratio of the UI element +Buttons and other UI elements come in all shapes and sizes. Frequently, the same style of button or background element needs to work with many different shapes or adapt to a changing width and height. Many of the UI elements in this sample are designed to adapt to changing dimensions. Follow these steps to create a UI element that can do that. + +1. Create a new Shader Graph asset. +1. In the Graph Inspector, set the Shader Graph’s Material setting to **Canvas**. +1. Add an SDF Pill node to the new Shader Graph file. ( You can find this node in the **Add Node** menu under **UI/SDFs**.) +1. Connect the Pill node’s **Fill** output port to the **Base Color** input port of the **Master Stack**. Now you’ve created a shader for a UI element that’s meant to be square. If you assign this shader to a non-square UI element, it will stretch and not look like a proper pill shape. +Notice that the Pill node’s last input port is called **WidthHeight**. This is an input for the width and height data of the UI element that the shader will be assigned to. By default, the Pill node assumes the UI element will be square, but if you plan to use a different aspect ratio, you can enter other values. Rather than entering the values manually, it’s best to connect them to the actual UI element values. That’s what we’ll do next. +1. Open the **Blackboard** and add a new Vector2 parameter. +1. Name the parameter **WidthHeight**. +1. Drag the parameter into the graph and connect it to the **WidthHeight** input port on the Pill node. You’ve now exposed the **WidthHeight** parameter so it can be connected outside the shaders. +1. In your scene, create a new **Canvas** element (if there isn’t one already) in the **Hierarchy** panel. (Right click in the **Hierarchy** panel and select **UI** > **Canvas**). +1. Then add an Image element to the Canvas. (Right click on the **Canvas** element and select **UI** > **Image**) Select the Image element. +1. Select the material associated with your shader in the Project panel and drag and drop it into the Material slot in the Inspector for the Image UI element. Now your shader’s material is assigned to the UI element. +1. Click the **Add Component** button at the bottom of the Inspector. +1. Select and assign the **Image Size** script to the Image element. This script connects the Image element’s Width and Height parameters to the WidthHeight parameter of your shader, so when the Width or Height values change, the shader adapts. + +Now you have a shader that will adapt to the aspect ratio of the UI element it’s assigned to. You can adjust the Width and Height parameters of the Image element and the Pill shape will maintain its rounded shape. This same feature is also available on many of the other nodes in the node library. You can control any subgraph node with a WidthHeight input port in this same way. \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-How-tos.md b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-How-tos.md new file mode 100644 index 00000000000..e7d31191470 --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-How-tos.md @@ -0,0 +1,9 @@ +# How Tos + +The following topics provide examples of UI elements that you can create with shader graph. + +| Topic | Description | +|:---------------------------|:-----------------------------------------------------------------| +| [How to create a resolution-independent shape](Shader-Graph-Sample-UGUI-Shaders-How-tos-Res-indepenent.md) | Learn how to create UI elements based on textures. | +| [How to create a functioning button](Shader-Graph-Sample-UGUI-Shaders-How-tos-Button.md) | Learn how to create a button that changes appearance depending on the user action. | +| [How to make shapes that adapt to the aspect ratio of the UI element](Shader-Graph-Sample-UGUI-Shaders-How-tos-aspect-ratio.md) | Learn how to create UI elements that can adapt to changing dimensions. | diff --git a/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-Notes-on-performance.md b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-Notes-on-performance.md new file mode 100644 index 00000000000..73c46ed1875 --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-Notes-on-performance.md @@ -0,0 +1,6 @@ +# Notes On Performance +The techniques on display in these example shaders use pure math to generate visuals (procedural generation) instead of sampling texture maps. While it’s obvious that these methods will use less memory than texture map based methods, the main question is whether it’s cheaper to sample a texture map, or generate the visuals procedurally. + +In our internal testing, the performance difference between rendering a texture-based button and a procedurally-generated button was less than 0.01 milliseconds so the difference was so small that it was almost not measurable. Of course it would be possible to create a significantly more complex shader that would be more expensive than a texture sample, but at the level of complexity of the examples we’ve created, there’s almost no performance difference between these and traditional texture-based UI elements. + +Given this understanding, in addition to the other benefits of these techniques (described at the top of this documentation), it seems obvious that this is a very efficient and effective way to create UI elements. \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-Subgraph-nodes.md b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-Subgraph-nodes.md new file mode 100644 index 00000000000..3c9b56c5c8b --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders-Subgraph-nodes.md @@ -0,0 +1,351 @@ +# Subgraph Nodes + +The subgraphs have been created to help speed up the process of creating user interface elements. They’re building blocks that can be strung together quickly to achieve various appearances and functionalities. You can see all of the subgraph nodes in the collection by opening this shader file: +Assets/Samples/Shader Graph//UGUI Shaders/Subgraphs/SubgraphLibrary + +The subgraphs are broken into the following categories: + - **Inputs** - These subgraphs provide input data. + - **Utilities** - These subgraphs feature simple utilities to help with input data. + - **Gradients** - These nodes generate gradients in various shapes including linear, spherical, square, and custom. + - **Helpers** - these subgraphs provide commonly-used operations for building UI elements + - **Patterns** - These nodes generate procedural patterns that can be used as backgrounds or masks. The patterns include clouds, bars, checkers, circle segments, hexagon tiles, player icon, rings, ring segments, square tiles, wedges, and window blinds. + - **SDFs** - Signed Distance Field shapes are the basis for UI elements. The value of each pixel in an SDF represents the distance to the edge of the shape. You can use the SDF data to create resolution-independent shapes that are either sharp or blurry. Shapes in the set include circle, hexagon, pill, rectangle, star, and triangle. This collection also contains operators for combining SDF shapes. + - **Time** - These nodes output time in various forms - looping, mirroredm, sine wave, etc. + - **UV** - These nodes manipulate UV coordinates including move, scale, tilt, mirror, invert, and more. Shapes and elements can be transformed by adjusting their UV coordinates with these nodes. + ![](images/UITools-subgraphs.png) + +## Inputs + +### Canvas Color +This subgraph outputs the UI element color in linear space, performing color space conversion on vertex color if the Canvas is set to store vertex colors in gamma space. +Make sure to check "Disable Color Tint" in the Graph Settings when using the Canvas Color node, to not tint the final output. + +## Utilities + +### SelectableStateCompare +This subgraph takes a Selectable State as a float and outputs Boolean values to inform on the states. + +### SelectableStatePreview +This subgraph takes a Selectable State as a float input and features a dropdown to override its value withing Shader Graph only. This allows previewing what things look like when in a given state. +This has no effect on the final shader that will always use the provided input. + +### SliderDirectionCompare +This subgraph takes a Direction as a Vector2 and outputs Boolean values to inform on cardinals. + +### SliderDirectionPreview +This subgraph takes a Direction as a Vector2 input and features a dropdown to override its value withing Shader Graph only. This allows previewing what things look like with a different direction is used. +This has no effect on the final shader that will always use the provided input. + +### Gradients +This node is a collection of commonly used gradients. You can select the gradient you want to use from the Style dropdown. By default, a horizontal LinearGradient is used as the input, but you can pass in any input gradient you want. + +#### Cone Gradient +Creates a Gradient, Normals, Height, and a Mask for a procedurally-generated cone. This allows you to create 3d effects in a 2d environment. The Size input port controls the size of the generated cone relative to the UV space. ConeHeight input controls the height above the base of the cone’s center point. The LightDirection input port is a vector that determines the direction the light is coming from for the Diffuse gradient output. The Diffuse output uses the cone’s normals and the incoming LightDirection to calculate diffuse lighting. Areas of the Diffuse gradient facing away from the LightDirection will have negative values, so you may need to use a Saturate node to limit the range of the output to zero to one. The NormalTS output is a normalized vector that indicates the direction each pixel on the cone’s surface is facing. The Height output is a heightmap for the cone. The Mask output is white inside the cone and black outside. + +Usage Examples: +- Examples/Backgrounds/80sSunset +- Examples/Indicators/FantasyMeter + +#### Linear Gradient +This node uses UV coordinates to create a vertical or horizontal gradient from black to white. By default, the node uses the UV coordinates from the UI element, but you can also pass in your own coordinates to the UV input port. The U output port creates a horizontal gradient and the V output port creates a vertical gradient. + +Usage Examples: +- Examples/Backgrounds/80sSunset +- Examples/ProgressBars/GradientBar + +#### Cube Gradient +Creates a gradient, normals, height, and a mask for a procedurally-generated cube. This allows you to create 3d effects in a 2d environment. The InnerSize and OuterSize input ports control the size of the generated cube relative to the UV space. The LightDirection input port is a vector that determines the direction the light is coming from for the Diffuse gradient output. The Diffuse output uses the cube’s normals and the incoming LightDirection to calculate diffuse lighting. Areas of the Diffuse gradient facing away from the LightDirection will have negative values, so you may need to use a Saturate node to limit the range of the output to zero to one. The NormalTS output is a normalized vector that indicates the direction each pixel on the sphere’s surface is facing. The Mask output is white inside the sphere and black outside. + +#### Sphere Gradient +Creates a gradient, normals, height, and a mask for a procedurally-generated sphere. This allows you to create 3d effects in a 2d environment. The Size input port controls the size of the generated sphere relative to the UV space. The LightDirection input port is a vector that determines the direction the light is coming from for the Diffuse gradient output. The Diffuse output uses the sphere’s normals and the incoming LightDirection to calculate diffuse lighting. Areas of the Diffuse gradient facing away from the LightDirection will have negative values, so you may need to use a Saturate node to limit the range of the output to zero to one. The NormalTS output is a normalized vector that indicates the direction each pixel on the sphere’s surface is facing. The Mask output is white inside the sphere and black outside. + +Usage Examples: +- Examples/Indicators/FantasyMeter + +### Helpers + +#### Anti Aliasing +You can use this node to create a perfectly anti-aliased edge from any SDF shape or gradient regardless of the size of the shape or the camera’s distance from the UI element. You can use it to create resolution-independent UI elements. The Cutoff input controls the point along the input gradient where the hard edge should be. See the documentation section entitled “How to create a resolution-independent shape” for instructions on using this node. + +Usage Examples: +- Examples/Indicators/FantasyMeter +- Examples/Backgrounds/LavaLamp + + +#### Aspect Ratio +Given the Width and Height of the UI element, this node calculates the aspect ratio of the UI element. It can be used to create buttons and widgets that correctly adapt to changes in the width or height of the assigned UI element. It works best when the WidthHeight input port is connected to the Width and Height parameters of the assigned UI element. See the documentation section entitled “How to make shapes that adapt to the aspect ratio of the UI element” for more information. + +Usage Examples: +- Examples/Indicators/AquaMeter +- Subgraphs/SDFs/Pill + +#### Ease Curves +This node adjusts the falloff curve of the input gradient. There are 9 available falloff curves. More information on the falloff curves can be found here: https://easings.net/ By default, the input Gradient is LinearTimeMirror, but you can use any type of gradient you want. + +#### Hash11 +Given an input value In and a Seed, this node generates a deterministic random value in the 0 to 1 range as output. Time is used as the default input, but you can use any input value you want. + +Usage Examples: +- Examples/Indicators/FantasyMeter + +#### Hash21 +Given a vector2 value UV (such as UV coordinates) and a Seed, this node generates a deterministic random value as output. UV0 is the default UV input, but you can use any vector 2 value you want. + +#### Histogram Scan +This node allows you to convert a gradient or SDF into a solid shape. You can control the Position along the gradient where the solid edge forms as well as the hardness of the edge using Contrast input. The lower the Contrast value, the softer the edge. + +Usage Examples: +- Examples/ProgressBars/ProgressCircle +- Examples/Indicators/DialMeter + +#### Lerp Multiple +This node works in a similar way as the Lerp node, but allows you to blend between 3 or 4 values instead of just 2. FracTime is used as the default for the T value but you can use any value you want. + +#### Mirror +This node flips the input value back and forth. The number of times to repeat the back and forth pattern is determined by the Subdivisions input. + +Usage Examples: +- Subgraphs/SDFs/Wave + +#### PosterizeGradient +This node quantizes gradients into discrete steps. The number of steps is controlled by the Steps input. The step divisions can be divided to preserve the overall range or to preserve the step distance. + +Usage Examples: +- Examples/ProgressBars/ProgressCircle +- Examples/Indicators/SciFiMeter + +#### Random +Given UV coordinates and a Seed, this node generates random values - either Vector 2 or Float. Because the method used to generate the values uses a sine function, it is non-deterministic, may vary on various hardware platforms (depending on the hardware implementation of sine), and may exhibit repetitive patterns when given large input values. If you are seeing these issues, use the Hash11 or Hash21 nodes instead. + +Usage Examples: +- Subgraphs/UV/Shake.shadersubgraph + +#### RoundedCorners +This is a helper node used by the SDF Rectangle node. It helps to generate the rounded corners of the rectangle. + +Usage Examples: +- Subgraphs/SDFs/Rectangle + +#### Scene Color Blurred +This node samples the Scene Color node in a spiral pattern and averages the result to create the appearance of blurring the scene background behind the UI element. Cycles is the number of turns of the spiral. Use Samples Per Cycle to control the number of samples in each cycle. The total number of samples is Cycles times Samples Per Cycle. Higher numbers of samples result in smoother blur appearance but higher cost. Lower sample numbers give better performance but grainier results. See the Sticky Notes inside the subgraph for more information. + +Usage Examples: +- Examples/Backgrounds/BlurredHexagon + +### Patterns + +#### Animated Clouds +Generates an animated cloud pattern. By default, the clouds are generated in screen space, but you can also pass in your own UV coordinates. You can control the color of the clouds with the Color1 and Color2 inputs. The speed of cloud movement is controlled with the Speed input. And the size of the clouds can be controlled with the Scale input. + +Usage Examples: +- Examples/Backgrounds/TechGrid +- Examples/Buttons/SciFiButton2 + +#### Animated Sheen +This node creates a scrolling highlight gradient. It’s intended to create the animated sheen on buttons - especially when the button is selected or the user’s mouse is hovering over the button. You can control the size of the effect with the Scale input. The angle of tilt can be adjusted with the Tilt input value. And you can control the Speed that the effect scrolls with the Speed input. + +Usage Examples: +- Examples/Buttons/AquaButton +- Examples/Buttons/SciFiButton2 + +#### Bars +This node generates vertical or horizontal bars (an alternating black and white pattern) depending on the output port you use. You can control the number of bars using the Bars input. + +#### Checkers +This node generates a simple checkerboard pattern. You can control the scale of the pattern using the Tiles input. + +#### Circle Segments +This node divides a circle into the given number of segments and alternates them between black and white. The width and blur of the segments can be controlled with the Spacing and Blur inputs. The segments can be output as triangles or lines. You can also rotate the pattern using the Rotation input. + +Usage Example: +- Examples/Buttons/SciFiButton + +#### Hexagon Tiles +This node creates a hexagon grid. The Tiles input controls the scale of the hexagon tiles. The Thickness input controls the width of the Stroke outlines. The Distance input controls the size of the white parts of the tiles relative to the black lines. The Blur input controls the blurriness of the tile outlines. An interesting and useful inverse SDF effect can be achieved by setting the Distance input to 0 and the Blur input to 0.5. + +Usage Examples: +- Examples/Backgrounds/BlurredHexagon + +#### Player Icon +This node creates an avatar icon. It combines the Circle and Pill SDF nodes. It’s a good example of how SDFs can be combined to create other shapes. + +Usage Examples: +- Examples/Buttons/SciFiButton +- Examples/Indicators/DialMeter + +#### Rings +This subgraph generates a series of concentric rings. You can select the number of rings with the Segments input. You can control how sharp or blurry the rings are with the Glow Min Max input. You can crop the rings at the edges with the Mask To Bounds input. The Offset input moves the rings toward or away from the center. By default it’s set to LinearTime but you can use any input value. + +#### Ring Segments +This node generates a set of rotating ring segments. You can control the number of segments with the Segments input. The Size input controls how far the segments are from the center. The Blur input controls how sharp or blurry the edges of the segments are. The Thickness input controls the width of the segments. The Contrast input controls the falloff of the segment’s tail. The Rotation input controls the movement or position around the circle of the segments. + +#### Square Tiles +This node generates a grid pattern of square tiles. The Tiles input controls the number of tiles in each dimension. Size controls the size of the white squares vs black lines in both dimensions. The lower these values are, the thicker the black outlines will be. Blur controls the sharpness/blurriness of the white squares. You’ll most likely need to turn the Size value down in order to make room for blurry edges. + +Usage Examples: +- Examples/Backgrounds/TechGrid +- Examples/Buttons/SciFiButton2 + +#### Wedges +This node generates wedge patterns of various types. The type can be selected with the dropdown box. + +Usage Examples: +- Subgraphs/Gradients/SquareGradient + +#### Window Blinds +This node generates a bar pattern that can expand or contract to give the appearance of opening and closing window blinds. The Rotation input controls the orientation of the blinds in degrees. The Segments input controls the number of blinds. The Progress input controls the balance between black and white. Higher values make the white bars larger and lower values make the black bars larger. Blur controls the sharpness/blurriness of the bard edges. + +Usage Example: +- Examples/Indicators/SciFiMeter + +### SDFs +SDFs or Signed Distance Fields are a very useful way of representing procedurally-generated shapes. The value of each pixel in the SDF represents the distance to the nearest shape edges. Pixels inside the shape have negative values - also indicating the distance to the nearest edge. + +SDFs can be used to create a final shape using the Fill output of the SDF node, using the Histogram Scan node, or the AntiAliasing node. The AntiAliasing node specifically will create shapes that are perfectly anti-aliased regardless of scale, camera distance, or resolution. + +Each of the SDF shape nodes outputs the shape from the Fill output. The Stroke port outputs an outline of the shape. The Stroke Thickness input parameter controls the width of the Stroke outline. The nodes also output the SDF itself as well as the Stroke SDF. + +You can control the sharpness or blurriness of the Fill shape by using the Edge Min and Edge Max controls. The closer together the values are, the sharper the edge of the shape will be. The farther apart the values are, the softer/blurrier the edges will be. A blurry SDF shape makes a great drop shadow. + +#### Circle +Creates a circle shape. + +- Usage Examples: +- Examples/Buttons/SciFiButton +- Examples/Indicators/FantasyMeter +- Examples/Indicators/DialMeter + +#### Hexagon +Creates a hexagon shape. It’s possible to round the corners of the hexagon using the Corner Radius input parameter. + +#### Pill +Generates a pill shape. You can control the height of the pill with the Size parameter. You can control the width of the pill with the Width parameter. To control the aspect ratio of the pill, use the WidthHeight parameter to enter the dimensions of the UI element. + +Usage Examples: +- Examples/Buttons/AquaButton +- Examples/ProgressBars/GradientBar + +#### Rectangle +Creates a rectangle shape. You can round the corners of the rectangle using the four Corner Radii input values. To control the aspect ratio of the rectangle, use the WidthHeight parameter to enter the dimensions of the UI element. + +Usage Examples: +- Examples/Buttons/SimpleButton +- Examples/Backgrounds/RoundedRectangleBubble + +#### Star +Creates a star shape. You can control the number of points and the point distance. + +#### Triangle +Creates a triangle shape. It’s possible to round the corners of the triangle using the Corner Radius input parameter. + +#### Waves +Generates an animated wave pattern from any SDF. You can control the number of waves and the movement of the waves using the Repetitions and Movement parameters. + +Usage Example: +- Examples/Indicators/FantasyMeter + +#### SDF Intersect +This is a basic boolean intersection operation between two SDFs. The result is the intersection where the two shapes overlap. Using the Smooth output allows the result to have a soft blend instead of the hard edge. + +#### SDF Subtract +This is a basic boolean intersection operation between two SDFs. The result is the second SDF subtracted from the first. Using the Smooth output allows the result to have a soft blend instead of the hard edge. + +#### SDF Unite +This is a basic boolean intersection operation between two SDFs. The result is the two SDF shapes combined together. Using the Smooth output allows the result to have a soft blend instead of the hard edge. + +Usage Example: +- Examples/Backgrounds/LavaLamp + +### Time + +#### LinearTime +Outputs time values that increase linearly. The Loop output increases linearly from 0 to 1 and then jumps back to zero. The Mirror output increases linearly from 0 to 1 and then decreases linearly back to 0 and repeats this back and forth cycle. The Switch output jumps from 0 directly to 1 and then back to 0 again. + +Usage Examples: +- Examples/Backgrounds/80sSunset +- Examples/Buttons/SciFiButton2 +- Examples/Indicators/FantasyMeter + +#### SineTime +The Raw output flows in a smooth curve from -1 to 1 and back. The Normalized output flows in a smooth curve between 0 and 1. + +Usage Examples: +- Examples/ProgressBars/FancyLoading +- Examples/Backgrounds/LavaLamp + +#### TimeOffset +Allows you to use a mask to determine areas where time is offset. The maximum offset value is defined by the Offset input. Areas where the Mask is 1 are time offset by the maximum amount. Areas where the Mask is 0 are not time offset. + +### UV +#### GridTiles +Divides the UV space into the number of tiles defined by Tile U and Tile V. Aspect ratio can be maintained by inputting correct values into WidthHeight + +Usage Examples: +- Examples/Indicators/FantasyMeter +- Examples/ProgressBars/FancyLoading + +#### Halftone +Divides the UV space into halftone space or outputs a halftone pattern based on the input gradient where the size of the dots are determined by the shades in the input gradient. Areas where the input gradient is white have the largest halftone dots. + +Usage Example: +- Examples/Backgrounds/Halftone + +#### Invert +Flips the U coordinate, the V coordinate, or both. + +Usage Example: +- Examples/Indicators/DialMeter +- Examples/ProgressBars/GradientBar +- Examples/ProgressBars/ProgressCircle + +#### MirrorUV +Takes UV coordinates in the 0 to 1 range and converts them to go from 0 to 1 to 0 again. You can control the offset, rotation, scale, and axis to mirror. + +#### Move +Moves UV coordinates the amount specified by the Move input. + +Usage Examples: +- Examples/Backgrounds/80sSunset +- Examples/Backgrounds/LavaLamp +- Examples/Backgrounds/WarpedGradient +- Examples/Buttons/SimpleButton + +#### Perspective +Distorts UV coordinates to make it look like perspective is applied as if the object were rotated away from the camera. Because of the perspective warping, some empty space is created around the edges. This empty space is black in the Alpha output. The Alpha Threshold and Alpha Feather inputs control the edges of the empty space. + +Usage Examples: +- Examples/ProgressBars/FancyLoading +- Examples/Backgrounds/80sSunset + +#### PosterizeUV +Divides smooth UV coordinates into discrete, quantized units. The number of units can be specified with the Steps input. This node works well to convert a high resolution image into a low resolution one. + +Usage Example: +- Examples/Backgrounds/Pixelation + +#### Scale +Scales texture coordinates by the amount specified in Scale around the point specified by Pivot Point. + +Usage Examples: +- Examples/Backgrounds/RoundedRectangleBubble +- Examples/Buttons/SciFiButton +- Examples/Indicators/DialMeter + +#### Shake +Oscillates UV coordinates back and forth quickly by a random amount and using the Speed and Strength inputs. + +Usage Example: +- Examples/Indicators/SciFiMeter + +#### Tilt +Tilts the UV coordinates so that the resulting object slants to the left or right. + +Usage Examples: +- Examples/Indicators/SciFiMeter +- Examples/ProgressBars/SimpleLoading + +#### Waves +Distorts the UV coordinates in a wave pattern. The strength and size of the waves can be controlled with the Amplitude and Frequency inputs. + +Usage Example: +- Examples/Indicators/FantasyMeter \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders.md b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders.md new file mode 100644 index 00000000000..38627e6fd2c --- /dev/null +++ b/Packages/com.unity.shadergraph/Documentation~/Shader-Graph-Sample-UGUI-Shaders.md @@ -0,0 +1,35 @@ +# UGUI Shaders +![](images/UIToolsSample.png) + +The Shader Graph UGUI Shaders sample is a collection of Shader Graph subgraphs that serve as building blocks for building user interface elements. They speed up the process of building widgets, buttons, and backgrounds for the user interface of your project. Using these tools, you can build dynamic, procedural UI elements that don’t require any texture memory and scale correctly for any resolution screen. + +In addition to the subgraphs, the sample also includes example buttons, indicators, and backgrounds built using the subgraphs. The examples show how the subgraphs function in context and help you learn how to use them. + +We have two main objectives with this sample set: + + + - Demonstrate Shader Graph’s ability to create dynamic, resolution-independent user interface elements in a wide variety of shapes and styles. + - Make it easier and faster to create UI elements by providing a large set of UI-specific subgraph nodes that can be used as building blocks to speed up the creation process. + + Using Shader Graph and UGUI, you can create user interface elements that are resolution independent, require zero texture memory, can be authored and edited directly in Shader Graph inside of Unity, automatically adapt to aspect ratio, and contain all visual states and behaviors. That’s a lot, so let’s unpack it! + + - **Resolution Independent** - These UI elements are procedurally-generated, so they look perfectly crisp whether displayed on a small smartphone screen or a 100 inch 8k TV. You can zoom in on them as close as you want and they’ll always be tack sharp. + - **Zero Texture Memory** - The visuals for these UI elements are created using math, so they don’t rely on textures at all. That means they require zero texture memory. + - **Authored In Shader Graph** - If you’re frustrated by the back and forth workflow of editing your UI images outside of Unity, chopping them up into textures, importing them, and then going back to make adjustments, you’ll be glad to hear that these UI elements are created entirely in Shader Graph, so there’s no export/import loop. Adjustments require simply changing shader parameters or re-wiring a few nodes. + - **Automatically Adapt To Aspect Ratio** - By passing the width and height values of the assigned UI element into the shader, the shader can automatically adapt the visuals to fit that ratio. No more making different button shapes to fit different size buttons or fiddling with 9 slicing. + - **Contain all visual states and behaviors** - One shader can contain all the information needed for a hover state, and active/inactive state, a pressed down state, etc, so you don’t need to manage multiple image assets for each button or widget. + + This set of samples demonstrates how to use all of these advanced techniques for generating UI, and provides tools to make the process easier. + + Documentation for this set of samples is broken into the following pages: + +* [Getting started](Shader-Graph-Sample-UGUI-Shaders-Getting-Started.md) +* [Custom UI componenents](Shader-Graph-Sample-UGUI-Shaders-Custom-UI-components.md) +* [Custom nodes](Shader-Graph-Sample-UGUI-Shaders-Custom-nodes.md) +* [Subgraph nodes](Shader-Graph-Sample-UGUI-Shaders-Subgraph-nodes.md) +* [Examples](Shader-Graph-Sample-UGUI-Shaders-Examples.md) +* [How tos](Shader-Graph-Sample-UGUI-Shaders-How-tos.md) + * [How to create a resolution-independent shape](Shader-Graph-Sample-UGUI-Shaders-How-tos-Res-indepenent.md) + * [How to create a functioning button](Shader-Graph-Sample-UGUI-Shaders-How-tos-Button.md) + * [How to make shapes that adapt to the aspect ratio of the UI element](Shader-Graph-Sample-UGUI-Shaders-How-tos-aspect-ratio.md) +* [Notes on performance](Shader-Graph-Sample-UGUI-Shaders-Notes-on-performance.md) \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Documentation~/ShaderGraph-Samples.md b/Packages/com.unity.shadergraph/Documentation~/ShaderGraph-Samples.md index ba2fa149faf..1afdc48443f 100644 --- a/Packages/com.unity.shadergraph/Documentation~/ShaderGraph-Samples.md +++ b/Packages/com.unity.shadergraph/Documentation~/ShaderGraph-Samples.md @@ -38,3 +38,9 @@ The following samples are currently available for Shader Graph. |:--------------------| |![](images/ProductionReadySample.png) | | The Shader Graph Production Ready Shaders sample is a collection of Shader Graph shader assets that are ready to be used out of the box or modified to suit your needs. You can take them apart and learn from them, or just drop them directly into your project and use them as they are. The sample includes the Shader Graph versions of the HDRP and URP Lit shaders. It also includes a step-by-step tutorial for how to combine several of the shaders to create a forest stream environment. + +| [UGUI Shaders](Shader-Graph-Sample-UGUI-Shaders.md) | +|:--------------------| +|![](images/UIToolsSample.png) | +| The Shader Graph UGUI Shaders sample is a collection of Shader Graph subgraphs that you can use to build user interface elements. They speed up the process of building widgets, buttons, and backgrounds for the user interface of your project. With these tools, you can build dynamic, procedural UI elements that don’t require any texture memory and scale correctly for any resolution screen. In addition to the subgraphs, the sample also includes example buttons, indicators, and backgrounds built with the subgraphs. The examples show how the subgraphs function in context and help you learn how to use them. + diff --git a/Packages/com.unity.shadergraph/Documentation~/TableOfContents.md b/Packages/com.unity.shadergraph/Documentation~/TableOfContents.md index f0e3a3263af..3ee1cf68408 100644 --- a/Packages/com.unity.shadergraph/Documentation~/TableOfContents.md +++ b/Packages/com.unity.shadergraph/Documentation~/TableOfContents.md @@ -21,18 +21,6 @@ * [Shader Graph Preferences](Shader-Graph-Preferences) * [Shader Graph Project Settings](Shader-Graph-Project-Settings.md) * [Shader Graph Keyboard Shortcuts](Keyboard-shortcuts) - * [Samples](ShaderGraph-Samples.md) - * [Feature Examples](Shader-Graph-Sample-Feature-Examples.md) - * [Production Ready Shaders](Shader-Graph-Sample-Production-Ready.md) - * [Lit Shaders](Shader-Graph-Sample-Production-Ready-Lit.md) - * [Decal shaders](Shader-Graph-Sample-Production-Ready-Decal.md) - * [Detail shaders](Shader-Graph-Sample-Production-Ready-Detail.md) - * [Rock shaders](Shader-Graph-Sample-Production-Ready-Rock.md) - * [Water shaders](Shader-Graph-Sample-Production-Ready-Water.md) - * [Post-process shaders](Shader-Graph-Sample-Production-Ready-Post.md) - * [Weather shaders](Shader-Graph-Sample-Production-Ready-Weather.md) - * [Miscellaneous shaders](Shader-Graph-Sample-Production-Ready-Misc.md) - * [Forest Stream Construction Tutorial ](Shader-Graph-Sample-Production-Ready-Tutorial.md) * [Material Variants](materialvariant-SG) * Upgrade Guides * [Upgrade to Shader Graph 10.0.x](Upgrade-Guide-10-0-x) @@ -307,3 +295,26 @@ * [Parallax Occlusion Mapping](Parallax-Occlusion-Mapping-Node) * [Block Nodes](Block-Node) * [Built In Blocks](Built-In-Blocks) +* [Samples](ShaderGraph-Samples.md) + * [Feature Examples](Shader-Graph-Sample-Feature-Examples.md) + * [Production Ready Shaders](Shader-Graph-Sample-Production-Ready.md) + * [Lit Shaders](Shader-Graph-Sample-Production-Ready-Lit.md) + * [Decal shaders](Shader-Graph-Sample-Production-Ready-Decal.md) + * [Detail shaders](Shader-Graph-Sample-Production-Ready-Detail.md) + * [Rock shaders](Shader-Graph-Sample-Production-Ready-Rock.md) + * [Water shaders](Shader-Graph-Sample-Production-Ready-Water.md) + * [Post-process shaders](Shader-Graph-Sample-Production-Ready-Post.md) + * [Weather shaders](Shader-Graph-Sample-Production-Ready-Weather.md) + * [Miscellaneous shaders](Shader-Graph-Sample-Production-Ready-Misc.md) + * [Forest Stream Construction Tutorial ](Shader-Graph-Sample-Production-Ready-Tutorial.md) + * [UGUI Shaders](Shader-Graph-Sample-UGUI-Shaders.md) + * [Getting started](Shader-Graph-Sample-UGUI-Shaders-Getting-Started.md) + * [Custom UI componenents](Shader-Graph-Sample-UGUI-Shaders-Custom-UI-components.md) + * [Custom nodes](Shader-Graph-Sample-UGUI-Shaders-Custom-nodes.md) + * [Subgraph nodes](Shader-Graph-Sample-UGUI-Shaders-Subgraph-nodes.md) + * [Examples](Shader-Graph-Sample-UGUI-Shaders-Examples.md) + * [How tos](Shader-Graph-Sample-UGUI-Shaders-How-tos.md) + * [How to create a resolution-independent shape](Shader-Graph-Sample-UGUI-Shaders-How-tos-Res-indepenent.md) + * [How to create a functioning button](Shader-Graph-Sample-UGUI-Shaders-How-tos-Button.md) + * [How to make shapes that adapt to the aspect ratio of the UI element](Shader-Graph-Sample-UGUI-Shaders-How-tos-aspect-ratio.md) + * [Notes on performance](Shader-Graph-Sample-UGUI-Shaders-Notes-on-performance.md) diff --git a/Packages/com.unity.shadergraph/Documentation~/images/UITools-buttons.png b/Packages/com.unity.shadergraph/Documentation~/images/UITools-buttons.png new file mode 100644 index 00000000000..eaf6f072217 Binary files /dev/null and b/Packages/com.unity.shadergraph/Documentation~/images/UITools-buttons.png differ diff --git a/Packages/com.unity.shadergraph/Documentation~/images/UITools-meters.png b/Packages/com.unity.shadergraph/Documentation~/images/UITools-meters.png new file mode 100644 index 00000000000..391f60b73d9 Binary files /dev/null and b/Packages/com.unity.shadergraph/Documentation~/images/UITools-meters.png differ diff --git a/Packages/com.unity.shadergraph/Documentation~/images/UITools-meters2.png b/Packages/com.unity.shadergraph/Documentation~/images/UITools-meters2.png new file mode 100644 index 00000000000..0208be38ff8 Binary files /dev/null and b/Packages/com.unity.shadergraph/Documentation~/images/UITools-meters2.png differ diff --git a/Packages/com.unity.shadergraph/Documentation~/images/UITools-subgraphs.png b/Packages/com.unity.shadergraph/Documentation~/images/UITools-subgraphs.png new file mode 100644 index 00000000000..d66619be5c4 Binary files /dev/null and b/Packages/com.unity.shadergraph/Documentation~/images/UITools-subgraphs.png differ diff --git a/Packages/com.unity.shadergraph/Documentation~/images/UIToolsSample.png b/Packages/com.unity.shadergraph/Documentation~/images/UIToolsSample.png new file mode 100644 index 00000000000..69dd1070535 Binary files /dev/null and b/Packages/com.unity.shadergraph/Documentation~/images/UIToolsSample.png differ diff --git a/Packages/com.unity.shadergraph/Editor/Data/Graphs/ColorShaderProperty.cs b/Packages/com.unity.shadergraph/Editor/Data/Graphs/ColorShaderProperty.cs index 9f768ca0cb4..7a8c51696bb 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Graphs/ColorShaderProperty.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Graphs/ColorShaderProperty.cs @@ -20,6 +20,7 @@ public sealed class ColorShaderProperty : AbstractShaderProperty internal ColorShaderProperty() { displayName = "Color"; + value = Color.black; } internal ColorShaderProperty(int version) : this() diff --git a/Packages/com.unity.shadergraph/Editor/Data/Graphs/GraphData.cs b/Packages/com.unity.shadergraph/Editor/Data/Graphs/GraphData.cs index 8b64acbf2c7..e5e6f21fb4c 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Graphs/GraphData.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Graphs/GraphData.cs @@ -2048,7 +2048,7 @@ public void ReplaceWith(GraphData other) { removedNodeEdges.AddRange(m_Edges); foreach (var edge in removedNodeEdges) - RemoveEdgeNoValidate(edge); + RemoveEdgeNoValidate(edge, false); } using (var nodesToRemove = PooledList.Get()) diff --git a/Packages/com.unity.shadergraph/Editor/Data/Implementation/NodeUtils.cs b/Packages/com.unity.shadergraph/Editor/Data/Implementation/NodeUtils.cs index d593322dfad..13ed5baa147 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Implementation/NodeUtils.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Implementation/NodeUtils.cs @@ -864,9 +864,11 @@ public static string ConvertToValidHLSLIdentifier(string originalId, Func(); - if (addBlackboardItemAction.addInputActionType == AddShaderInputAction.AddActionSource.AddMenu) + if (addedInteractively) propertyView.OpenTextEditor(); } break; @@ -174,7 +177,7 @@ protected override void ModelChanged(GraphData graphData, IGraphDataAction chang // In the specific case of only-one keywords like Material Quality and Raytracing, they can get copied, but because only one can exist, the output copied value is null if (copyShaderInputAction.copiedShaderInput != null && IsInputInCategory(copyShaderInputAction.copiedShaderInput)) { - var blackboardRow = InsertBlackboardRow(copyShaderInputAction.copiedShaderInput, copyShaderInputAction.insertIndex); + var blackboardRow = InsertBlackboardRow(copyShaderInputAction.copiedShaderInput, copyShaderInputAction.insertIndex, ensureVisible: true); if (blackboardRow != null) { var graphView = ViewModel.parentView.GetFirstAncestorOfType(); @@ -188,7 +191,8 @@ protected override void ModelChanged(GraphData graphData, IGraphDataAction chang // If item was added to category that this controller manages, then add blackboard row to represent that item if (addItemToCategoryAction.itemToAdd != null && addItemToCategoryAction.categoryGuid == ViewModel.associatedCategoryGuid) { - InsertBlackboardRow(addItemToCategoryAction.itemToAdd, addItemToCategoryAction.indexToAddItemAt); + var dragged = addItemToCategoryAction.addActionSource == AddItemToCategoryAction.AddActionSource.DragDrop; + InsertBlackboardRow(addItemToCategoryAction.itemToAdd, addItemToCategoryAction.indexToAddItemAt, ensureVisible: !dragged); } else { @@ -246,7 +250,7 @@ internal SGBlackboardRow FindBlackboardRow(ShaderInput shaderInput) // Creates controller, view and view model for a blackboard item and adds the view to the specified index in the category // By default adds it to the end of the list if no insertionIndex specified - internal SGBlackboardRow InsertBlackboardRow(BlackboardItem shaderInput, int insertionIndex = -1) + internal SGBlackboardRow InsertBlackboardRow(BlackboardItem shaderInput, int insertionIndex = -1, bool ensureVisible = false) { var shaderInputViewModel = new ShaderInputViewModel() { @@ -258,16 +262,23 @@ internal SGBlackboardRow InsertBlackboardRow(BlackboardItem shaderInput, int ins m_BlackboardItemControllers.TryGetValue(shaderInput.objectId, out var existingItemController); if (existingItemController == null) { + var itemView = blackboardItemController.BlackboardItemView; m_BlackboardItemControllers.Add(shaderInput.objectId, blackboardItemController); + // If no index specified, or if trying to insert at last index, add to end of category - if (insertionIndex == -1 || insertionIndex == m_BlackboardItemControllers.Count() - 1) + if (insertionIndex == -1 || insertionIndex == m_BlackboardItemControllers.Count - 1) blackboardCategoryView.Add(blackboardItemController.BlackboardItemView); else blackboardCategoryView.Insert(insertionIndex, blackboardItemController.BlackboardItemView); blackboardCategoryView.MarkDirtyRepaint(); - return blackboardItemController.BlackboardItemView; + if (ensureVisible) + { + blackboard.scrollView.ScrollToElementAfterGeometryChange(itemView); + } + + return itemView; } else { diff --git a/Packages/com.unity.shadergraph/Editor/Drawing/Controllers/BlackboardController.cs b/Packages/com.unity.shadergraph/Editor/Drawing/Controllers/BlackboardController.cs index 155658d38e2..c5ea520a9ad 100644 --- a/Packages/com.unity.shadergraph/Editor/Drawing/Controllers/BlackboardController.cs +++ b/Packages/com.unity.shadergraph/Editor/Drawing/Controllers/BlackboardController.cs @@ -5,6 +5,7 @@ using UnityEngine.UIElements; using System; using UnityEditor.Graphing; +using UnityEditor.Graphing.Util; using UnityEditor.ShaderGraph.Internal; using GraphDataStore = UnityEditor.ShaderGraph.DataStore; using BlackboardItem = UnityEditor.ShaderGraph.Internal.ShaderInput; @@ -569,7 +570,7 @@ internal BlackboardController(GraphData model, BlackboardViewModel inViewModel, internal string editorPrefsBaseKey => "unity.shadergraph." + DataStore.State.objectId; - BlackboardCategoryController AddBlackboardCategory(GraphDataStore graphDataStore, CategoryData categoryInfo) + BlackboardCategoryController AddBlackboardCategory(GraphDataStore graphDataStore, CategoryData categoryInfo, bool ensureVisible = false) { var blackboardCategoryViewModel = new BlackboardCategoryViewModel(); blackboardCategoryViewModel.parentView = blackboard; @@ -583,19 +584,26 @@ BlackboardCategoryController AddBlackboardCategory(GraphDataStore graphDataStore { m_BlackboardCategoryControllers.Add(categoryInfo.categoryGuid, blackboardCategoryController); m_DefaultCategoryController = m_BlackboardCategoryControllers.Values.FirstOrDefault(); + + if (ensureVisible) + { + blackboard.scrollView.ScrollToElementAfterGeometryChange(blackboardCategoryController.blackboardCategoryView); + } + } else { AssertHelpers.Fail("Failed to add category controller due to category with same GUID already having been added."); return null; } + return blackboardCategoryController; } // Creates controller, view and view model for a blackboard item and adds the view to the specified index in the category - SGBlackboardRow InsertBlackboardRow(BlackboardItem shaderInput, int insertionIndex = -1) + SGBlackboardRow InsertBlackboardRow(BlackboardItem shaderInput, int insertionIndex = -1, bool ensureVisible = false) { - return m_DefaultCategoryController.InsertBlackboardRow(shaderInput, insertionIndex); + return m_DefaultCategoryController.InsertBlackboardRow(shaderInput, insertionIndex, ensureVisible); } public void UpdateBlackboardTitle(string newTitle) @@ -612,6 +620,7 @@ protected override void RequestModelChange(IGraphDataAction changeAction) // Called by GraphDataStore.Subscribe after the model has been changed protected override void ModelChanged(GraphData graphData, IGraphDataAction changeAction) { + if (ViewModel == null) return; // Reconstruct view-model first // TODO: hide this more generically for category types. bool useDropdowns = graphData.isSubGraph; @@ -625,11 +634,12 @@ protected override void ModelChanged(GraphData graphData, IGraphDataAction chang case AddShaderInputAction addBlackboardItemAction: if (IsInputUncategorized(addBlackboardItemAction.shaderInputReference)) { - var blackboardRow = InsertBlackboardRow(addBlackboardItemAction.shaderInputReference); + var addedInteractively = addBlackboardItemAction.addInputActionType == AddShaderInputAction.AddActionSource.AddMenu; + var blackboardRow = InsertBlackboardRow(addBlackboardItemAction.shaderInputReference, ensureVisible: addedInteractively); if (blackboardRow != null) { var propertyView = blackboardRow.Q(); - if (addBlackboardItemAction.addInputActionType == AddShaderInputAction.AddActionSource.AddMenu) + if (addedInteractively) propertyView.OpenTextEditor(); } } @@ -654,7 +664,7 @@ protected override void ModelChanged(GraphData graphData, IGraphDataAction chang // In the specific case of only-one keywords like Material Quality and Raytracing, they can get copied, but because only one can exist, the output copied value is null if (copyShaderInputAction.copiedShaderInput != null && IsInputUncategorized(copyShaderInputAction.copiedShaderInput)) { - var blackboardRow = InsertBlackboardRow(copyShaderInputAction.copiedShaderInput, copyShaderInputAction.insertIndex); + var blackboardRow = InsertBlackboardRow(copyShaderInputAction.copiedShaderInput, copyShaderInputAction.insertIndex, ensureVisible: true); var propertyView = blackboardRow.Q(); graphView?.AddToSelectionNoUndoRecord(propertyView); } @@ -662,7 +672,7 @@ protected override void ModelChanged(GraphData graphData, IGraphDataAction chang break; case AddCategoryAction addCategoryAction: - AddBlackboardCategory(DataStore, addCategoryAction.categoryDataReference); + AddBlackboardCategory(DataStore, addCategoryAction.categoryDataReference, ensureVisible: true); // Iterate through anything that is selected currently foreach (var selectedElement in blackboard.selection.ToList()) { @@ -695,7 +705,7 @@ protected override void ModelChanged(GraphData graphData, IGraphDataAction chang break; case CopyCategoryAction copyCategoryAction: - var blackboardCategory = AddBlackboardCategory(graphData.owner.graphDataStore, copyCategoryAction.newCategoryDataReference); + var blackboardCategory = AddBlackboardCategory(graphData.owner.graphDataStore, copyCategoryAction.newCategoryDataReference, ensureVisible: true); if (blackboardCategory != null) graphView?.AddToSelectionNoUndoRecord(blackboardCategory.blackboardCategoryView); break; diff --git a/Packages/com.unity.shadergraph/Editor/Drawing/Inspector/InspectorView.cs b/Packages/com.unity.shadergraph/Editor/Drawing/Inspector/InspectorView.cs index 28b22a01aee..2b2336ab472 100644 --- a/Packages/com.unity.shadergraph/Editor/Drawing/Inspector/InspectorView.cs +++ b/Packages/com.unity.shadergraph/Editor/Drawing/Inspector/InspectorView.cs @@ -31,7 +31,10 @@ class InspectorView : GraphSubWindow public override string UxmlName => "GraphInspector"; public override string layoutKey => "UnityEditor.ShaderGraph.InspectorWindow"; - TabbedView m_GraphInspectorView; + TabView m_GraphInspectorView; + Tab m_GraphSettingsTab; + Tab m_NodeSettingsTab; + protected VisualElement m_GraphSettingsContainer; protected VisualElement m_NodeSettingsContainer; @@ -80,14 +83,18 @@ void RegisterPropertyDrawer(Type newPropertyDrawerType) public InspectorView(InspectorViewModel viewModel) : base(viewModel) { - m_GraphInspectorView = m_MainContainer.Q("GraphInspectorView"); + m_GraphInspectorView = m_MainContainer.Q("GraphInspectorView"); + m_GraphSettingsTab = m_GraphInspectorView.Q("GraphSettingsTab"); + m_NodeSettingsTab = m_GraphInspectorView.Q("NodeSettingsTab"); + m_GraphSettingsContainer = m_GraphInspectorView.Q("GraphSettingsContainer"); m_NodeSettingsContainer = m_GraphInspectorView.Q("NodeSettingsContainer"); m_MaxItemsMessageLabel = m_GraphInspectorView.Q