diff --git a/Packages/com.unity.render-pipelines.core/Documentation~/render-graph-writing-a-render-pipeline.md b/Packages/com.unity.render-pipelines.core/Documentation~/render-graph-writing-a-render-pipeline.md index 4c1f399ae7f..4856c311442 100644 --- a/Packages/com.unity.render-pipelines.core/Documentation~/render-graph-writing-a-render-pipeline.md +++ b/Packages/com.unity.render-pipelines.core/Documentation~/render-graph-writing-a-render-pipeline.md @@ -7,6 +7,7 @@ This page covers the process of how to use the RenderGraph API to write a render To begin, your render pipeline needs to maintain at least one instance of [RenderGraph](../api/UnityEngine.Rendering.RenderGraphModule.RenderGraph.html). This is the main entry point for the API. You can use more than one instance of a render graph, but be aware that Unity does not share resources across `RenderGraph` instances so for optimal memory usage, only use one instance. ```c# +using UnityEngine.Rendering; using UnityEngine.Rendering.RenderGraphModule; public class MyRenderPipeline : RenderPipeline @@ -21,8 +22,11 @@ public class MyRenderPipeline : RenderPipeline void CleanupRenderGraph() { m_RenderGraph.Cleanup(); - m_RenderGraph = null; + m_RenderGraph = null; } + + ... + } ``` diff --git a/Packages/com.unity.render-pipelines.core/Editor/CommandBuffers/CommandBufferGenerator/CommandBufferGenerator.cs b/Packages/com.unity.render-pipelines.core/Editor/CommandBuffers/CommandBufferGenerator/CommandBufferGenerator.cs index a0fe400df12..74075bafa61 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/CommandBuffers/CommandBufferGenerator/CommandBufferGenerator.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/CommandBuffers/CommandBufferGenerator/CommandBufferGenerator.cs @@ -110,7 +110,9 @@ class CommandBufferGenerator new FunctionInfo("SetFoveatedRenderingMode", textureArg: "", modifiesGlobalState: true), new FunctionInfo("ConfigureFoveatedRendering", textureArg: "", modifiesGlobalState: true), new FunctionInfo("SetWireframe", textureArg: "", modifiesGlobalState: true), - }; + new FunctionInfo("SetShadingRateFragmentSize", textureArg: "", modifiesGlobalState: false), + new FunctionInfo("SetShadingRateCombiner", textureArg: "", modifiesGlobalState: false), + }; // Functions for unsafe (wrapper around Commandbuffer) only static List unsafeFunctions = new List { diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/DynamicGI/DynamicGISkyOcclusion.urtshader b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/DynamicGI/DynamicGISkyOcclusion.urtshader index 7460bf116cc..13b0330dd00 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/DynamicGI/DynamicGISkyOcclusion.urtshader +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/DynamicGI/DynamicGISkyOcclusion.urtshader @@ -1,4 +1,4 @@ -#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal +#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal webgpu #define UNIFIED_RT_GROUP_SIZE_X 64 #define UNIFIED_RT_GROUP_SIZE_Y 1 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 a0be9e1a2b9..67d6182f5d9 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 @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Runtime.CompilerServices; using Unity.Collections; using UnityEditor; @@ -8,7 +9,7 @@ using UnityEngine.LightTransport.PostProcessing; using UnityEngine.Rendering.Sampling; using UnityEngine.Rendering.UnifiedRayTracing; - +using UnityEngine.SceneManagement; using TouchupVolumeWithBoundsList = System.Collections.Generic.List<(UnityEngine.Rendering.ProbeReferenceVolume.Volume obb, UnityEngine.Bounds aabb, UnityEngine.Rendering.ProbeAdjustmentVolume volume)>; namespace UnityEngine.Rendering @@ -584,13 +585,16 @@ public void Dispose() } } + // The contribution from all Baked and Mixed lights in the scene should be disabled to avoid double contribution. static void UpdateLightStatus() { var lightingSettings = ProbeVolumeLightingTab.GetLightingSettings(); - // The contribution from all Baked and Mixed lights in the scene should be disabled to avoid double contribution. - var lights = Object.FindObjectsByType(FindObjectsSortMode.None); - foreach (var light in lights) + var sceneLights = new Dictionary>(); + + // Modify each baked light, take note of which scenes they belong to. + var allLights = Object.FindObjectsByType(FindObjectsSortMode.None); + foreach (var light in allLights) { if (light.lightmapBakeType != LightmapBakeType.Realtime) { @@ -600,6 +604,56 @@ static void UpdateLightStatus() bakingOutput.mixedLightingMode = lightingSettings.mixedBakeMode; light.bakingOutput = bakingOutput; } + + // Take note of the lights from each scene + var scene = light.gameObject.scene; + if (!sceneLights.TryGetValue(scene, out var sceneLightList)) + { + sceneLightList = new List(); + sceneLights.Add(scene, sceneLightList); + } + sceneLightList.Add(light); + } + + // Now we make the modifications persistent by modifying Lighting Data Assets (LDA) on disk. + string ldaFolderPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(m_BakingSet)); + for (int i = 0; i < m_BakingSet.sceneGUIDs.Count; i++) + { + string guid = m_BakingSet.sceneGUIDs[i]; + Scene scene = SceneManager.GetSceneByPath(AssetDatabase.GUIDToAssetPath(guid)); + if (!scene.isLoaded) + continue; + + LightingDataAsset prevLDA = Lightmapping.GetLightingDataAssetForScene(scene); + LightingDataAsset newLDA = prevLDA; + + // If the scene has no (modifiable) LDA, create a new one. + bool isDefaultLDA = prevLDA && prevLDA.hideFlags.HasFlag(HideFlags.NotEditable); + if (prevLDA == null || isDefaultLDA) + { + newLDA = new LightingDataAsset(scene); + } + + // Update the LDA with the new light settings + if (sceneLights.TryGetValue(scene, out var lights)) + newLDA.SetLights(lights.ToArray()); + else + newLDA.SetLights(Array.Empty()); + + // If the scene was using the builtin/default LDA before, copy over environment lighting, so it doesn't change. + if (prevLDA != null) + { + newLDA.SetAmbientProbe(prevLDA.GetAmbientProbe()); + newLDA.SetDefaultReflectionCubemap(prevLDA.GetDefaultReflectionCubemap()); + } + + // Save the LDA to disk and assign it to the scene. + if (newLDA != prevLDA) + { + string ldaPath = $"{ldaFolderPath}/LightingData-{i}.asset".Replace('\\', '/'); + AssetDatabase.CreateAsset(newLDA, ldaPath); + Lightmapping.SetLightingDataAssetForScene(scene, newLDA); + } } } 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 e54acb2bfd8..922c77f8979 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 @@ -1234,7 +1234,7 @@ static void FixSeams(NativeArray positionRemap, NativeArray positi // 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 - + // Use an indirection structure to ensure mem usage stays reasonable VoxelToBrickCache cache = new VoxelToBrickCache(); diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeBuildProcessor.cs b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeBuildProcessor.cs index 65fbc5026a8..7e751855587 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeBuildProcessor.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeBuildProcessor.cs @@ -4,11 +4,10 @@ using UnityEditor.Build.Reporting; using UnityEngine; using UnityEngine.Rendering; -using UnityEngine.SceneManagement; namespace UnityEditor.Rendering { - class ProbeVolumeBuildProcessor : BuildPlayerProcessor, IProcessSceneWithReport + class ProbeVolumeBuildProcessor : BuildPlayerProcessor, IPostprocessBuildWithReport { const string kTempAPVStreamingAssetsPath = "TempAPVStreamingAssets"; @@ -18,15 +17,27 @@ string GetTempAPVStreamingAssetsPath() return Path.Combine(libraryPath, kTempAPVStreamingAssetsPath); } - void PrepareStreamableAsset(ProbeVolumeStreamableAsset asset, string basePath, bool useStreamingAsset) + // Include an asset in the build. The mechanism for doing so depends on whether we are using StreamingAssets path. + static void IncludeStreamableAsset(ProbeVolumeStreamableAsset asset, string basePath, bool useStreamingAsset) { - asset.UpdateAssetReference(useStreamingAsset); - if (useStreamingAsset) + { + asset.ClearAssetReferenceForBuild(); CopyStreamableAsset(asset, basePath); + } + else + { + asset.EnsureAssetLoaded(); + } + } + + // Ensure that an asset is not included in the build. + static void StripStreambleAsset(ProbeVolumeStreamableAsset asset) + { + asset.ClearAssetReferenceForBuild(); } - void CopyStreamableAsset(ProbeVolumeStreamableAsset asset, string basePath) + static void CopyStreamableAsset(ProbeVolumeStreamableAsset asset, string basePath) { var assetPath = asset.GetAssetPath(); if (!File.Exists(assetPath)) @@ -60,6 +71,9 @@ void GetProbeVolumeProjectSettings(BuildTarget target, out bool supportProbeVolu } } + // Keep track of which assets we touched during the build, so we can restore them after the build. + private static HashSet s_BakingSetsProcessedLastBuild = new(); + public override void PrepareForBuild(BuildPlayerContext buildPlayerContext) { GetProbeVolumeProjectSettings(buildPlayerContext.BuildPlayerOptions.target, out bool supportProbeVolume, out var maxSHBands); @@ -89,8 +103,7 @@ public override void PrepareForBuild(BuildPlayerContext buildPlayerContext) Directory.CreateDirectory(tempStreamingAssetsPath); - HashSet processedBakingSets = new HashSet(); - + s_BakingSetsProcessedLastBuild.Clear(); foreach (var scene in buildPlayerContext.BuildPlayerOptions.scenes) { var sceneGUID = AssetDatabase.AssetPathToGUID(scene); @@ -98,7 +111,7 @@ public override void PrepareForBuild(BuildPlayerContext buildPlayerContext) if (bakingSet != null) { // Already processed (different scenes can belong to the same baking set). - if (processedBakingSets.Contains(bakingSet)) + if (s_BakingSetsProcessedLastBuild.Contains(bakingSet)) continue; if (!bakingSet.cellSharedDataAsset.IsValid()) // Not baked @@ -111,89 +124,53 @@ public override void PrepareForBuild(BuildPlayerContext buildPlayerContext) bool useStreamingAsset = !GraphicsSettings.GetRenderPipelineSettings().probeVolumeDisableStreamingAssets; - PrepareStreamableAsset(bakingSet.cellSharedDataAsset, basePath, useStreamingAsset); - PrepareStreamableAsset(bakingSet.cellBricksDataAsset, basePath, useStreamingAsset); + IncludeStreamableAsset(bakingSet.cellSharedDataAsset, basePath, useStreamingAsset); + IncludeStreamableAsset(bakingSet.cellBricksDataAsset, basePath, useStreamingAsset); // For now we always strip support data in build as it's mostly unsupported. // Later we'll need a proper option to strip it or not. bool stripSupportData = true; - if (!stripSupportData) - PrepareStreamableAsset(bakingSet.cellSupportDataAsset, basePath, useStreamingAsset); + if (stripSupportData) + StripStreambleAsset(bakingSet.cellSupportDataAsset); + else + IncludeStreamableAsset(bakingSet.cellSupportDataAsset, basePath, useStreamingAsset); foreach (var scenario in bakingSet.scenarios) { - PrepareStreamableAsset(scenario.Value.cellDataAsset, basePath, useStreamingAsset); + IncludeStreamableAsset(scenario.Value.cellDataAsset, basePath, useStreamingAsset); if (maxSHBands == ProbeVolumeSHBands.SphericalHarmonicsL2) - PrepareStreamableAsset(scenario.Value.cellOptionalDataAsset, basePath, useStreamingAsset); - PrepareStreamableAsset(scenario.Value.cellProbeOcclusionDataAsset, basePath, useStreamingAsset); + IncludeStreamableAsset(scenario.Value.cellOptionalDataAsset, basePath, useStreamingAsset); + else + StripStreambleAsset(scenario.Value.cellOptionalDataAsset); + IncludeStreamableAsset(scenario.Value.cellProbeOcclusionDataAsset, basePath, useStreamingAsset); } - processedBakingSets.Add(bakingSet); + s_BakingSetsProcessedLastBuild.Add(bakingSet); } } buildPlayerContext.AddAdditionalPathToStreamingAssets(tempStreamingAssetsPath, AdaptiveProbeVolumes.kAPVStreamingAssetsPath); } - private static bool IsBundleBuild(BuildReport report, bool isPlaying) - { - // We are entering playmode, so not building a bundle. - if (isPlaying) - return false; - - // Addressable builds do not provide a BuildReport. Because the Addressables package - // only supports AssetBundle builds, we infer that this is not a player build. - if (report == null) - return true; - - return report.summary.buildType == BuildType.AssetBundle; - } - - // This codepath handles the case of building asset bundles, i.e. not a full player build. It updates the references - // to individual data assets in the baking sets for each scene, such that the assets are included in the bundle. - public override int callbackOrder => 1; - public void OnProcessScene(Scene scene, BuildReport report) + public void OnPostprocessBuild(BuildReport report) { - // Only run for bundle builds. - if (!IsBundleBuild(report, Application.isPlaying)) - return; - - // Only run when APV is enabled. - GetProbeVolumeProjectSettings(EditorUserBuildSettings.activeBuildTarget, out bool supportProbeVolume, out var maxSHBands); - if (!supportProbeVolume) - return; - - // Reload the map from scene to baking set if we couldn't find the specific baking set. - if (ProbeVolumeBakingSet.sceneToBakingSet == null || ProbeVolumeBakingSet.sceneToBakingSet.Count == 0) - ProbeVolumeBakingSet.SyncBakingSets(); - - // Get the baking set for the scene. - var bakingSet = ProbeVolumeBakingSet.GetBakingSetForScene(scene.GetGUID()); - if (bakingSet == null || !bakingSet.cellSharedDataAsset.IsValid()) + if (s_BakingSetsProcessedLastBuild == null || s_BakingSetsProcessedLastBuild.Count == 0) return; - bool useStreamingAsset = !GraphicsSettings.GetRenderPipelineSettings().probeVolumeDisableStreamingAssets; - if (useStreamingAsset) + // Go over each asset reference we touched during the last build, make sure asset references are intact. + foreach (var bakingSet in s_BakingSetsProcessedLastBuild) { - Debug.LogWarning( - "Attempted to build an Asset Bundle containing Adaptive Probe Volume data, but streaming assets are enabled. This is unsupported. " + - "To use Adaptive Probe Volumes with Asset Bundles, please check 'Probe Volume Disable Streaming Assets' under Graphics Settings."); + bakingSet.cellBricksDataAsset.EnsureAssetLoaded(); + bakingSet.cellSharedDataAsset.EnsureAssetLoaded(); + bakingSet.cellSupportDataAsset.EnsureAssetLoaded(); + foreach (var scenario in bakingSet.scenarios) + { + scenario.Value.cellDataAsset.EnsureAssetLoaded(); + scenario.Value.cellOptionalDataAsset.EnsureAssetLoaded(); + scenario.Value.cellProbeOcclusionDataAsset.EnsureAssetLoaded(); + } } - // Update all the asset references. - bakingSet.cellSharedDataAsset.UpdateAssetReference(useStreamingAsset); - bakingSet.cellBricksDataAsset.UpdateAssetReference(useStreamingAsset); - - bool stripSupportData = true; - if (!stripSupportData) - bakingSet.cellSupportDataAsset.UpdateAssetReference(false); - - foreach (var scenario in bakingSet.scenarios) - { - scenario.Value.cellDataAsset.UpdateAssetReference(useStreamingAsset); - if (maxSHBands == ProbeVolumeSHBands.SphericalHarmonicsL2) - scenario.Value.cellOptionalDataAsset.UpdateAssetReference(useStreamingAsset); - scenario.Value.cellProbeOcclusionDataAsset.UpdateAssetReference(useStreamingAsset); - } + s_BakingSetsProcessedLastBuild.Clear(); } } } diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeCellDilation.compute b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeCellDilation.compute index eb87df797ce..04dd0fa3d1f 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeCellDilation.compute +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeCellDilation.compute @@ -1,6 +1,6 @@ #pragma kernel DilateCell -#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch +#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch webgpu #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonLighting.hlsl" 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 6da03237a47..fca2f9f3be1 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 @@ -2,6 +2,7 @@ using System.Linq; using System.Reflection; using System.Collections.Generic; +using System.IO; using UnityEditor; using UnityEditor.Rendering; using UnityEditor.SceneManagement; @@ -510,7 +511,9 @@ void SaveTempBakingSetIfNeeded() string path = string.IsNullOrEmpty(scene.path) ? ProbeVolumeBakingSet.GetDirectory("Assets/", "Untitled") : ProbeVolumeBakingSet.GetDirectory(scene.path, scene.name); - path = System.IO.Path.Combine(path, activeSet.name + ".asset"); + if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + path = Path.Combine(path, activeSet.name + ".asset"); path = AssetDatabase.GenerateUniqueAssetPath(path); AssetDatabase.CreateAsset(activeSet, path); diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeSubdivide.compute b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeSubdivide.compute index ba7e4d63718..2b7fb853aee 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeSubdivide.compute +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeSubdivide.compute @@ -6,7 +6,7 @@ #pragma kernel VoxelizeProbeVolumeData #pragma kernel Subdivide -#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch +#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch webgpu // #pragma enable_d3d11_debug_symbols diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/VirtualOffset/TraceVirtualOffset.urtshader b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/VirtualOffset/TraceVirtualOffset.urtshader index 45f7011a9fc..f15265fdf19 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/VirtualOffset/TraceVirtualOffset.urtshader +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/VirtualOffset/TraceVirtualOffset.urtshader @@ -1,4 +1,4 @@ -#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal +#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal webgpu switch #define UNIFIED_RT_GROUP_SIZE_X 64 #define UNIFIED_RT_GROUP_SIZE_Y 1 diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_Lighting/Assets/EditModeTestAssets/Lighting_ReflectionProbeBaking.meta b/Packages/com.unity.render-pipelines.core/Editor/PropertyDrawers.meta similarity index 77% rename from Tests/SRPTests/Projects/UniversalGraphicsTest_Lighting/Assets/EditModeTestAssets/Lighting_ReflectionProbeBaking.meta rename to Packages/com.unity.render-pipelines.core/Editor/PropertyDrawers.meta index 394dcc49351..c2f69514a6e 100644 --- a/Tests/SRPTests/Projects/UniversalGraphicsTest_Lighting/Assets/EditModeTestAssets/Lighting_ReflectionProbeBaking.meta +++ b/Packages/com.unity.render-pipelines.core/Editor/PropertyDrawers.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 56025fa4f03396e4c9af3da741ad94dd +guid: 5f6f204246726d84a87fac671dba9b53 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Packages/com.unity.render-pipelines.core/Editor/PropertyDrawers/VrsLutDrawer.cs b/Packages/com.unity.render-pipelines.core/Editor/PropertyDrawers/VrsLutDrawer.cs new file mode 100644 index 00000000000..7a6675e1044 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/PropertyDrawers/VrsLutDrawer.cs @@ -0,0 +1,60 @@ +using System; +using System.Reflection; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEditor.UIElements; +using UnityEngine.UIElements; + +namespace UnityEditor.Rendering +{ + /// + /// Displays UI for a VrsLut lookup table. Each entry is a + /// ShadingRateFragmentSize enum value that maps to a Color. + /// + [CustomPropertyDrawer(typeof(VrsLut))] + sealed class VrsLutDrawer : PropertyDrawer + { + /// + public override VisualElement CreatePropertyGUI(SerializedProperty property) + { + var foldout = new Foldout() + { + text = property.displayName, + value = property.isExpanded, + }; + + var vrsLutData = GetVrsLutData(property); + VrsLutDataGUI(foldout.contentContainer, vrsLutData); + + VisualElement root = new(); + root.Add(foldout); + return root; + } + + /// + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + if (property.isExpanded) + return (GetVrsLutData(property).arraySize + 1) * EditorGUIUtility.singleLineHeight; + + return EditorGUIUtility.singleLineHeight; + } + + void VrsLutDataGUI(VisualElement contentContainer, SerializedProperty vrsLutData) + { + foreach (var fragmentSizeInfo in shadingRateFragmentSizeFields) + { + var fragmentSizeValue = (ShadingRateFragmentSize) fragmentSizeInfo.GetValue(null); + var inspectorNameAttribute = fragmentSizeInfo.GetCustomAttribute(); + var displayName = inspectorNameAttribute == null ? ObjectNames.NicifyVariableName(fragmentSizeValue.ToString()) : inspectorNameAttribute.displayName; + var lutProp = vrsLutData.GetArrayElementAtIndex((int) fragmentSizeValue); + var propertyField = new PropertyField(lutProp, displayName); + contentContainer.Add(propertyField); + } + } + + static SerializedProperty GetVrsLutData(SerializedProperty property) => property.FindPropertyRelative("m_Data"); + + static FieldInfo[] shadingRateFragmentSizeFields => typeof(ShadingRateFragmentSize).GetFields(BindingFlags.Static | BindingFlags.Public); + } +} diff --git a/Packages/com.unity.render-pipelines.core/Editor/PropertyDrawers/VrsLutDrawer.cs.meta b/Packages/com.unity.render-pipelines.core/Editor/PropertyDrawers/VrsLutDrawer.cs.meta new file mode 100644 index 00000000000..4eb1244d094 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/PropertyDrawers/VrsLutDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f271dd66b05804343bbd8ff052f767a0 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Camera/CameraHistory.cs b/Packages/com.unity.render-pipelines.core/Runtime/Camera/CameraHistory.cs index 8c45638e9bb..d21c93177cd 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Camera/CameraHistory.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Camera/CameraHistory.cs @@ -151,11 +151,29 @@ protected int MakeId(uint index) protected RTHandle AllocHistoryFrameRT(int id, int count, ref RenderTextureDescriptor desc, string name = "") { - RenderTextureDescriptor d = desc; // Simplified for typical history textures: // Sampling is usually bilinear & clamp. Point sample can be a texture.Load() or done with inline samplers. + return AllocHistoryFrameRT(id, count, ref desc, FilterMode.Bilinear, name); + } + + /// + /// Allocate a history frame RTHandle[] using a descriptor. + /// + /// Id for the history RTHandle storage. + /// Number of RTHandles allocated for the id. + /// Texture descriptor used for each RTHandle in the allocation. + /// Filtering mode of the texture. + /// User visible debug name of the texture. + /// Current frame RTHandle in the allocation. + protected RTHandle AllocHistoryFrameRT(int id, int count, + ref RenderTextureDescriptor desc, + FilterMode filterMode, + string name = "") + { + RenderTextureDescriptor d = desc; + // Simplified for typical history textures: // No shadows, no mipmaps, no aniso. - m_owner.AllocBuffer(id, count, ref desc, FilterMode.Bilinear, TextureWrapMode.Clamp, false, 0, 0, name); + m_owner.AllocBuffer(id, count, ref desc, filterMode, TextureWrapMode.Clamp, false, 0, 0, name); return GetCurrentFrameRT(0); } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/CommandBuffers/ComputeCommandBuffer.cs b/Packages/com.unity.render-pipelines.core/Runtime/CommandBuffers/ComputeCommandBuffer.cs index 05a98a3c35d..f074eca5418 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/CommandBuffers/ComputeCommandBuffer.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/CommandBuffers/ComputeCommandBuffer.cs @@ -763,6 +763,14 @@ internal ComputeCommandBuffer(CommandBuffer wrapped, RenderGraphPass executingPa /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DispatchRays.html) public void DispatchRays(RayTracingShader rayTracingShader, string rayGenName, uint width, uint height, uint depth, Camera camera) { m_WrappedCommandBuffer.DispatchRays(rayTracingShader, rayGenName, width, height, depth, camera); } + /// Wraps [DispatchRays](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DispatchRays.html) on a CommandBuffer. + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DispatchRays.html) + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DispatchRays.html) + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DispatchRays.html) + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DispatchRays.html) + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DispatchRays.html) + public void DispatchRays(RayTracingShader rayTracingShader, string rayGenName, GraphicsBuffer argsBuffer, uint argsOffset, Camera camera) { m_WrappedCommandBuffer.DispatchRays(rayTracingShader, rayGenName, argsBuffer, argsOffset, camera); } + /// Wraps [CopyCounterValue](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.CopyCounterValue.html) on a CommandBuffer. /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.CopyCounterValue.html) /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.CopyCounterValue.html) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/CommandBuffers/IComputeCommandBuffer.cs b/Packages/com.unity.render-pipelines.core/Runtime/CommandBuffers/IComputeCommandBuffer.cs index 061e776c416..a3c7066828b 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/CommandBuffers/IComputeCommandBuffer.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/CommandBuffers/IComputeCommandBuffer.cs @@ -588,6 +588,14 @@ public interface IComputeCommandBuffer : IBaseCommandBuffer /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DispatchRays.html) public void DispatchRays(RayTracingShader rayTracingShader, string rayGenName, uint width, uint height, uint depth, Camera camera) ; + /// Wraps [DispatchRays](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DispatchRays.html) on a CommandBuffer. + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DispatchRays.html) + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DispatchRays.html) + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DispatchRays.html) + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DispatchRays.html) + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DispatchRays.html) + public void DispatchRays(RayTracingShader rayTracingShader, string rayGenName, GraphicsBuffer argsBuffer, uint argsOffset, Camera camera) ; + /// Wraps [CopyCounterValue](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.CopyCounterValue.html) on a CommandBuffer. /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.CopyCounterValue.html) /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.CopyCounterValue.html) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/CommandBuffers/IRasterCommandBuffer.cs b/Packages/com.unity.render-pipelines.core/Runtime/CommandBuffers/IRasterCommandBuffer.cs index 853393be47f..07fea04ef9c 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/CommandBuffers/IRasterCommandBuffer.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/CommandBuffers/IRasterCommandBuffer.cs @@ -83,6 +83,15 @@ public interface IRasterCommandBuffer : IBaseCommandBuffer /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.ConfigureFoveatedRendering.html) public void ConfigureFoveatedRendering(IntPtr platformData) ; + /// Wraps [SetShadingRateFragmentSize](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetShadingRateFragmentSize.html) on a CommandBuffer. + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetShadingRateFragmentSize.html) + public void SetShadingRateFragmentSize(ShadingRateFragmentSize shadingRateFragmentSize) ; + + /// Wraps [SetShadingRateCombiner](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetShadingRateCombiner.html) on a CommandBuffer. + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetShadingRateCombiner.html) + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetShadingRateCombiner.html) + public void SetShadingRateCombiner(ShadingRateCombinerStage stage, ShadingRateCombiner combiner) ; + /// Wraps [DrawMesh](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DrawMesh.html) on a CommandBuffer. /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DrawMesh.html) /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DrawMesh.html) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/CommandBuffers/RasterCommandBuffer.cs b/Packages/com.unity.render-pipelines.core/Runtime/CommandBuffers/RasterCommandBuffer.cs index bba9327e2a1..9adcb5aa6e6 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/CommandBuffers/RasterCommandBuffer.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/CommandBuffers/RasterCommandBuffer.cs @@ -258,6 +258,15 @@ internal RasterCommandBuffer(CommandBuffer wrapped, RenderGraphPass executingPas public void InvokeOnRenderObjectCallbacks() { m_WrappedCommandBuffer.InvokeOnRenderObjectCallbacks(); } + /// Wraps [SetShadingRateFragmentSize](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetShadingRateFragmentSize.html) on a CommandBuffer. + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetShadingRateFragmentSize.html) + public void SetShadingRateFragmentSize(ShadingRateFragmentSize shadingRateFragmentSize) { m_WrappedCommandBuffer.SetShadingRateFragmentSize(shadingRateFragmentSize); } + + /// Wraps [SetShadingRateCombiner](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetShadingRateCombiner.html) on a CommandBuffer. + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetShadingRateCombiner.html) + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetShadingRateCombiner.html) + public void SetShadingRateCombiner(ShadingRateCombinerStage stage, ShadingRateCombiner combiner) { m_WrappedCommandBuffer.SetShadingRateCombiner(stage, combiner); } + /// Wraps [DrawMesh](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DrawMesh.html) on a CommandBuffer. /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DrawMesh.html) /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DrawMesh.html) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/CommandBuffers/UnsafeCommandBuffer.cs b/Packages/com.unity.render-pipelines.core/Runtime/CommandBuffers/UnsafeCommandBuffer.cs index 6141d802b43..bbea01e9676 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/CommandBuffers/UnsafeCommandBuffer.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/CommandBuffers/UnsafeCommandBuffer.cs @@ -598,6 +598,15 @@ internal UnsafeCommandBuffer(CommandBuffer wrapped, RenderGraphPass executingPas public void InvokeOnRenderObjectCallbacks() { m_WrappedCommandBuffer.InvokeOnRenderObjectCallbacks(); } + /// Wraps [SetShadingRateFragmentSize](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetShadingRateFragmentSize.html) on a CommandBuffer. + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetShadingRateFragmentSize.html) + public void SetShadingRateFragmentSize(ShadingRateFragmentSize shadingRateFragmentSize) { m_WrappedCommandBuffer.SetShadingRateFragmentSize(shadingRateFragmentSize); } + + /// Wraps [SetShadingRateCombiner](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetShadingRateCombiner.html) on a CommandBuffer. + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetShadingRateCombiner.html) + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetShadingRateCombiner.html) + public void SetShadingRateCombiner(ShadingRateCombinerStage stage, ShadingRateCombiner combiner) { m_WrappedCommandBuffer.SetShadingRateCombiner(stage, combiner); } + /// Wraps [SetComputeFloatParam](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetComputeFloatParam.html) on a CommandBuffer. /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetComputeFloatParam.html) /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetComputeFloatParam.html) @@ -1022,6 +1031,14 @@ internal UnsafeCommandBuffer(CommandBuffer wrapped, RenderGraphPass executingPas /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DispatchRays.html) public void DispatchRays(RayTracingShader rayTracingShader, string rayGenName, uint width, uint height, uint depth, Camera camera) { m_WrappedCommandBuffer.DispatchRays(rayTracingShader, rayGenName, width, height, depth, camera); } + /// Wraps [DispatchRays](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DispatchRays.html) on a CommandBuffer. + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DispatchRays.html) + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DispatchRays.html) + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DispatchRays.html) + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DispatchRays.html) + /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DispatchRays.html) + public void DispatchRays(RayTracingShader rayTracingShader, string rayGenName, GraphicsBuffer argsBuffer, uint argsOffset, Camera camera) { m_WrappedCommandBuffer.DispatchRays(rayTracingShader, rayGenName, argsBuffer, argsOffset, camera); } + /// Wraps [DrawMesh](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DrawMesh.html) on a CommandBuffer. /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DrawMesh.html) /// [See CommandBuffer documentation](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DrawMesh.html) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debug/ProbeVolumeDebugBase.hlsl b/Packages/com.unity.render-pipelines.core/Runtime/Debug/ProbeVolumeDebugBase.hlsl index a7d3ed205dd..9e124643602 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debug/ProbeVolumeDebugBase.hlsl +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debug/ProbeVolumeDebugBase.hlsl @@ -35,6 +35,7 @@ float GetCurrentExposureMultiplier() return LOAD_TEXTURE2D(_ExposureTexture, int2(0, 0)).x; } +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureXR.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl" #include "Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/DecodeSH.hlsl" #include "Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolume.hlsl" diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystem.Jobs.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystem.Jobs.cs index 9909408ef61..27c3fd30ed1 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystem.Jobs.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystem.Jobs.cs @@ -379,7 +379,6 @@ private unsafe struct ProbesUpdateJob : IJobParallelForBatch { public const int k_BatchSize = 64; - [ReadOnly] public bool initialize; [NativeDisableContainerSafetyRestriction, NoAlias][ReadOnly] public NativeArray instances; [NativeDisableParallelForRestriction][NativeDisableContainerSafetyRestriction, NoAlias] public CPUInstanceData instanceData; [ReadOnly] public CPUSharedInstanceData sharedInstanceData; @@ -403,11 +402,6 @@ public void Execute(int startIndex, int count) int sharedInstanceIndex = sharedInstanceData.InstanceToIndex(instanceData, instance); TransformUpdateFlags flags = sharedInstanceData.flags[sharedInstanceIndex].transformUpdateFlags; - bool isStaticObject = (flags & TransformUpdateFlags.IsPartOfStaticBatch) != 0; - - if (!initialize && isStaticObject) - continue; - bool hasLightProbe = (flags & TransformUpdateFlags.HasLightProbeCombined) != 0; if (!hasLightProbe) @@ -976,7 +970,7 @@ public void Execute(int index) instanceData.editorData.selectedBits.Set(instanceData.InstanceToIndex(instance), true); } } - + #endif } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystem.cs b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystem.cs index 20525c1d85b..9ed79f922ae 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystem.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/InstanceData/InstanceDataSystem.cs @@ -351,7 +351,6 @@ private unsafe void UpdateInstanceTransformsData(bool initialize, NativeArray instanc new ProbesUpdateJob() { - initialize = false, instances = instances, instanceData = m_InstanceData, sharedInstanceData = m_SharedInstanceData, diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.Streaming.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.Streaming.cs index abb57ee39f4..37613e48df2 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.Streaming.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.Streaming.cs @@ -1231,7 +1231,7 @@ unsafe bool ProcessDiskStreamingRequest(CellStreamingRequest request) var brickDataAsset = m_CurrentBakingSet.cellBricksDataAsset; cellStreamingDesc = brickDataAsset.streamableCellDescs[cellIndex]; - request.brickStreamingRequest.AddReadCommand(cellStreamingDesc.offset, brickDataAsset.elementSize * cellStreamingDesc.elementCount, (byte*)cellData.bricks.GetUnsafePtr()); + request.brickStreamingRequest.AddReadCommand(cellStreamingDesc.offset, brickDataAsset.elementSize * Mathf.Min(cellStreamingDesc.elementCount, cellDesc.bricksCount), (byte*)cellData.bricks.GetUnsafePtr()); request.brickStreamingRequest.RunCommands(brickDataAsset.OpenFile()); // Support Data diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBakingSet.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBakingSet.cs index d6d9a6d0c48..17e19c83793 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBakingSet.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBakingSet.cs @@ -31,7 +31,8 @@ public sealed partial class ProbeVolumeBakingSet : ScriptableObject, ISerializat internal enum Version { Initial, - RemoveProbeVolumeSceneData + RemoveProbeVolumeSceneData, + AssetsAlwaysReferenced, } [Serializable] @@ -345,6 +346,28 @@ internal void Migrate() #endif } + // Upgrade baking sets from before we always stored asset references. + if (version < Version.AssetsAlwaysReferenced && ProbeReferenceVolume.instance.isInitialized) + { +#if UNITY_EDITOR + cellBricksDataAsset.EnsureAssetLoaded(); + cellSharedDataAsset.EnsureAssetLoaded(); + cellSupportDataAsset.EnsureAssetLoaded(); + foreach (var scenario in scenarios) + { + scenario.Value.cellDataAsset.EnsureAssetLoaded(); + scenario.Value.cellOptionalDataAsset.EnsureAssetLoaded(); + scenario.Value.cellProbeOcclusionDataAsset.EnsureAssetLoaded(); + } + + version = Version.AssetsAlwaysReferenced; + + // Save immediately since these references must be written to disk for certain functionality + // to work, such as exporting a .unitypackage. Changing in memory is not enough. + UnityEditor.EditorUtility.SetDirty(this); + UnityEditor.AssetDatabase.SaveAssetIfDirty(this); +#endif + } #pragma warning restore 618 } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeStreamableAsset.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeStreamableAsset.cs index 4f60b151350..e3806ed3f96 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeStreamableAsset.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeStreamableAsset.cs @@ -43,6 +43,9 @@ public ProbeVolumeStreamableAsset(string apvStreamingAssetsPath, SerializedDicti m_StreamableCellDescs = cellDescs; m_ElementSize = elementSize; m_StreamableAssetPath = Path.Combine(Path.Combine(apvStreamingAssetsPath, bakingSetGUID), m_AssetGUID + ".bytes"); +#if UNITY_EDITOR + EnsureAssetLoaded(); +#endif } internal void RefreshAssetPath() @@ -89,9 +92,16 @@ public void RenameAsset(string newName) m_FinalAssetPath = ""; } - public void UpdateAssetReference(bool useStreamingAsset) + // Ensures that the asset is referenced via Unity's serialization layer. + public void EnsureAssetLoaded() + { + m_Asset = AssetDatabase.LoadAssetAtPath(GetAssetPath()); + } + + // Temporarily clear the asset reference. Used to prevent serialization of the asset when we are using the StreamingAssets codepath. + public void ClearAssetReferenceForBuild() { - m_Asset = useStreamingAsset ? null : AssetDatabase.LoadAssetAtPath(GetAssetPath()); + m_Asset = null; } #endif diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/CompilerContextData.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/CompilerContextData.cs index 9c0e78b479d..324109f60b7 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/CompilerContextData.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/CompilerContextData.cs @@ -98,7 +98,7 @@ public ref ResourceVersionedData VersionedResourceData(ResourceHandle h) [MethodImpl(MethodImplOptions.AggressiveInlining)] public ReadOnlySpan Readers(ResourceHandle h) { - int firstReader = ResourcesData.IndexReader(h, 0); + int firstReader = resources.IndexReader(h, 0); int numReaders = resources[h].numReaders; return resources.readerData[h.iType].MakeReadOnlySpan(firstReader, numReaders); } @@ -114,7 +114,7 @@ public ref ResourceReaderData ResourceReader(ResourceHandle h, int i) throw new Exception("Invalid reader id"); } #endif - return ref resources.readerData[h.iType].ElementAt(ResourcesData.IndexReader(h, 0) + i); + return ref resources.readerData[h.iType].ElementAt(resources.IndexReader(h, 0) + i); } // Data per graph level renderpass diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/NativePassCompiler.Debug.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/NativePassCompiler.Debug.cs index 7a337e9e77d..25c61409a1c 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/NativePassCompiler.Debug.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/NativePassCompiler.Debug.cs @@ -93,6 +93,12 @@ internal static string MakePassMergeMessage(CompilerContextData ctx, in PassData case PassBreakReason.EndOfGraph: message += "The pass is the last pass in the graph."; break; + case PassBreakReason.DifferentShadingRateImages: + message += $"{prevPassName} uses a different shading rate image than {passName}."; + break; + case PassBreakReason.DifferentShadingRateStates: + message += $"{prevPassName} uses different shading rate states than {passName}."; + break; default: throw new ArgumentOutOfRangeException(); } @@ -206,6 +212,8 @@ internal void GenerateNativeCompilerDebugData(ref RenderGraph.DebugData debugDat debugResource.textureData.depth = resourceUnversioned.volumeDepth; debugResource.textureData.samples = resourceUnversioned.msaaSamples; debugResource.textureData.format = info.format; + debugResource.textureData.bindMS = resourceUnversioned.bindMS; + debugResource.textureData.clearBuffer = resourceUnversioned.clear; debugResource.memoryless = resourceUnversioned.memoryLess; debugResource.consumerList = new List(); @@ -349,7 +357,7 @@ internal void GenerateNativeCompilerDebugData(ref RenderGraph.DebugData debugDat var numReaders = outputDataVersioned.numReaders; for (var i = 0; i < numReaders; ++i) { - var depIdx = ResourcesData.IndexReader(output.resource, i); + var depIdx = ctx.resources.IndexReader(output.resource, i); ref var dep = ref ctx.resources.readerData[output.resource.iType].ElementAt(depIdx); var outputDependencyPass = ctx.passData[dep.passId]; 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 57bc3c19b51..dbcaca53392 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 @@ -14,7 +14,8 @@ internal struct RenderGraphInputInfo public RenderGraphResourceRegistry m_ResourcesForDebugOnly; public List m_RenderPasses; public string debugName; - public bool disableCulling; + public bool disablePassCulling; + public bool disablePassMerging; } internal RenderGraphInputInfo graph; @@ -59,7 +60,7 @@ void Cleanup() } } - public bool Initialize(RenderGraphResourceRegistry resources, List renderPasses, bool disableCulling, string debugName, bool useCompilationCaching, int graphHash, int frameIndex) + public bool Initialize(RenderGraphResourceRegistry resources, List renderPasses, RenderGraphDebugParams debugParams, string debugName, bool useCompilationCaching, int graphHash, int frameIndex) { bool cached = false; if (!useCompilationCaching) @@ -69,7 +70,8 @@ public bool Initialize(RenderGraphResourceRegistry resources, List shadingRateImageIndex > 0; public bool insertGraphicsFence; // Whether this pass should insert a fence into the command buffer + public bool hasShadingRateStates; [MethodImpl(MethodImplOptions.AggressiveInlining)] public Name GetName(CompilerContextData ctx) => ctx.GetFullPassName(passId); @@ -162,6 +169,12 @@ public PassData(in RenderGraphPass pass, int passIndex) insertGraphicsFence = false; waitOnGraphicsFencePassId = -1; + + hasShadingRateStates = pass.hasShadingRateStates; + shadingRateFragmentSize = pass.shadingRateFragmentSize; + primitiveShadingRateCombiner = pass.primitiveShadingRateCombiner; + fragmentShadingRateCombiner = pass.fragmentShadingRateCombiner; + shadingRateImageIndex = -1; } // Helper func to reset and initialize existing PassData struct directly in a data container without costly deep copy (~120bytes) when adding it @@ -205,6 +218,12 @@ public void ResetAndInitialize(in RenderGraphPass pass, int passIndex) insertGraphicsFence = false; waitOnGraphicsFencePassId = -1; + + hasShadingRateStates = pass.hasShadingRateStates; + shadingRateFragmentSize = pass.shadingRateFragmentSize; + primitiveShadingRateCombiner = pass.primitiveShadingRateCombiner; + fragmentShadingRateCombiner = pass.fragmentShadingRateCombiner; + shadingRateImageIndex = -1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -219,6 +238,10 @@ public readonly ReadOnlySpan Inputs(CompilerContextData ctx) public readonly ReadOnlySpan Fragments(CompilerContextData ctx) => ctx.fragmentData.MakeReadOnlySpan(firstFragment, numFragments); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public PassFragmentData ShadingRateImage(CompilerContextData ctx) + => ctx.fragmentData[shadingRateImageIndex]; + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly ReadOnlySpan FragmentInputs(CompilerContextData ctx) => ctx.fragmentData.MakeReadOnlySpan(firstFragmentInput, numFragmentInputs); @@ -473,6 +496,9 @@ internal enum PassBreakReason SubPassLimitReached, // Addind the next pass would have generated more subpasses than allowed EndOfGraph, // The last pass in the graph was reached FRStateMismatch, // One pass is using foveated rendering and the other not + DifferentShadingRateImages, // The next pass uses a different shading rate image (and we only allow one in a whole NRP) + DifferentShadingRateStates, // The next pass uses different shading rate states (and we only allow one set in a whole NRP) + PassMergingDisabled, // Wasn't merged because pass merging is disabled Merged, // I actually got merged Count @@ -504,7 +530,10 @@ public PassBreakAudit(PassBreakReason reason, int breakPass) $"The limit of {FixedAttachmentArray.MaxAttachments} native pass attachments would be exceeded when merging with the next pass.", $"The limit of {NativePassCompiler.k_MaxSubpass} native subpasses would be exceeded when merging with the next pass.", "This is the last pass in the graph, there are no other passes to merge.", - "The the next pass uses a different foveated rendering state", + "The next pass uses a different foveated rendering state", + "The next pass uses a different shading rate image", + "The next pass uses a different shading rate rendering state", + "Pass merging is disabled so this pass was not merged", "The next pass got merged into this pass.", }; } @@ -530,8 +559,16 @@ internal struct NativePassData public int height; public int volumeDepth; public int samples; + public int shadingRateImageIndex; + public bool hasDepth; public bool hasFoveatedRasterization; + public bool hasShadingRateImage => shadingRateImageIndex >= 0; + public bool hasShadingRateStates; + + public ShadingRateFragmentSize shadingRateFragmentSize; + public ShadingRateCombiner primitiveShadingRateCombiner; + public ShadingRateCombiner fragmentShadingRateCombiner; public NativePassData(ref PassData pass, CompilerContextData ctx) { @@ -565,6 +602,21 @@ public NativePassData(ref PassData pass, CompilerContextData ctx) fragments.Add(fragment); } + // Shading rate and foveation are distinct systems and mutually exclusive. + // Foveation always taking precedence over VRS. + if (pass.fragmentInfoHasShadingRateImage && !hasFoveatedRasterization) + { + shadingRateImageIndex = fragments.size; + fragments.Add(pass.ShadingRateImage(ctx)); + } + else + shadingRateImageIndex = -1; + + hasShadingRateStates = pass.hasShadingRateStates && !hasFoveatedRasterization; + shadingRateFragmentSize = pass.shadingRateFragmentSize; + primitiveShadingRateCombiner = pass.primitiveShadingRateCombiner; + fragmentShadingRateCombiner = pass.fragmentShadingRateCombiner; + // Graph pass is added as the first native subpass TryMergeNativeSubPass(ctx, ref this, ref pass); } @@ -666,6 +718,38 @@ public static PassBreakAudit CanMerge(CompilerContextData contextData, int activ { return new PassBreakAudit(PassBreakReason.FRStateMismatch, passIdToMerge); } + + // Different shading rate images; only allow one per NRP + if (nativePass.hasShadingRateImage != passToMerge.fragmentInfoHasShadingRateImage) + { + return new PassBreakAudit(PassBreakReason.DifferentShadingRateImages, passIdToMerge); + } + + if (nativePass.hasShadingRateImage) + { + var passToMergeSRI = passToMerge.ShadingRateImage(contextData); + var nativePassSRI = nativePass.fragments[nativePass.shadingRateImageIndex]; + if (nativePassSRI.resource.index != passToMergeSRI.resource.index) + { + return new PassBreakAudit(PassBreakReason.DifferentShadingRateImages, passIdToMerge); + } + } + + // Different shading rate states; only allow one set per NRP + if (nativePass.hasShadingRateStates != passToMerge.hasShadingRateStates) + { + return new PassBreakAudit(PassBreakReason.DifferentShadingRateStates, passIdToMerge); + } + + if (nativePass.hasShadingRateStates) + { + if (nativePass.shadingRateFragmentSize != passToMerge.shadingRateFragmentSize || + nativePass.primitiveShadingRateCombiner != passToMerge.primitiveShadingRateCombiner || + nativePass.fragmentShadingRateCombiner != passToMerge.fragmentShadingRateCombiner) + { + return new PassBreakAudit(PassBreakReason.DifferentShadingRateStates, passIdToMerge); + } + } } // Check the non-fragment inputs of this pass, if they are generated by the current open native pass we can't merge @@ -974,6 +1058,14 @@ public static void TryMergeNativeSubPass(CompilerContextData contextData, ref Na } } + // Shading rate images + { + if (passToMerge.fragmentInfoHasShadingRateImage) + { + desc.flags |= SubPassFlags.UseShadingRateImage; + } + } + if (nativePass.numNativeSubPasses == 0 || !NativePassCompiler.IsSameNativeSubPass(ref desc, ref contextData.nativeSubPassData.ElementAt( nativePass.firstNativeSubPass + diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/ResourcesData.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/ResourcesData.cs index a6e6e1f1245..fba9b1f2320 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/ResourcesData.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/ResourcesData.cs @@ -146,14 +146,14 @@ public void SetWritingPass(CompilerContextData ctx, ResourceHandle h, int passId public void RegisterReadingPass(CompilerContextData ctx, ResourceHandle h, int passId, int index) { #if DEVELOPMENT_BUILD || UNITY_EDITOR - if (numReaders >= ResourcesData.MaxReaders) + if (numReaders >= ctx.resources.MaxReaders) { string passName = ctx.GetPassName(passId); string resourceName = ctx.GetResourceName(h); - throw new Exception($"Maximum '{ResourcesData.MaxReaders}' passes can use a single graph output as input. Pass {passName} is trying to read {resourceName}."); + throw new Exception($"Maximum '{ctx.resources.MaxReaders}' passes can use a single graph output as input. Pass {passName} is trying to read {resourceName}."); } #endif - ctx.resources.readerData[h.iType][ResourcesData.IndexReader(h, numReaders)] = new ResourceReaderData + ctx.resources.readerData[h.iType][ctx.resources.IndexReader(h, numReaders)] = new ResourceReaderData { passId = passId, inputSlot = index @@ -167,13 +167,13 @@ public void RemoveReadingPass(CompilerContextData ctx, ResourceHandle h, int pas { for (int r = 0; r < numReaders;) { - ref var reader = ref ctx.resources.readerData[h.iType].ElementAt(ResourcesData.IndexReader(h, r)); + ref var reader = ref ctx.resources.readerData[h.iType].ElementAt(ctx.resources.IndexReader(h, r)); if (reader.passId == passId) { // It should be removed, switch with the end of the list if we're not already at the end of it if (r < numReaders - 1) { - reader = ctx.resources.readerData[h.iType][ResourcesData.IndexReader(h, numReaders - 1)]; + reader = ctx.resources.readerData[h.iType][ctx.resources.IndexReader(h, numReaders - 1)]; } numReaders--; @@ -193,8 +193,9 @@ internal class ResourcesData public NativeList[] unversionedData; // Flattened fixed size array storing info per resource id shared between all versions. public NativeList[] versionedData; // Flattened fixed size array storing up to MaxVersions versions per resource id. public NativeList[] readerData; // Flattened fixed size array storing up to MaxReaders per resource id per version. - public const int MaxVersions = 20; // A quite arbitrary limit should be enough for most graphs. Increasing it shouldn't be a problem but will use more memory as these lists use a fixed size upfront allocation. - public const int MaxReaders = 100; // A quite arbitrary limit should be enough for most graphs. Increasing it shouldn't be a problem but will use more memory as these lists use a fixed size upfront allocation. + + public int MaxVersions; + public int MaxReaders; public DynamicArray[] resourceNames; @@ -229,6 +230,9 @@ public void Clear() public void Initialize(RenderGraphResourceRegistry resources) { + uint maxReaders = 0; + uint maxWriters = 0; + for (int t = 0; t < (int)RenderGraphResourceType.Count; t++) { RenderGraphResourceType resourceType = (RenderGraphResourceType) t; @@ -287,8 +291,15 @@ public void Initialize(RenderGraphResourceRegistry resources) default: throw new Exception("Unsupported resource type: " + t); } + + maxReaders = Math.Max(maxReaders, rll.readCount); + maxWriters = Math.Max(maxWriters, rll.writeCount); } + // The first resource is a null resource, so we need to add 1 to the count. + MaxReaders = (int)maxReaders + 1; + MaxVersions = (int)maxWriters + 1; + // Clear the other caching structures, they will be filled later versionedData[t].Resize(MaxVersions * numResources, NativeArrayOptions.ClearMemory); readerData[t].Resize(MaxVersions * MaxReaders * numResources, NativeArrayOptions.ClearMemory); @@ -297,7 +308,7 @@ public void Initialize(RenderGraphResourceRegistry resources) // Flatten array index [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int Index(ResourceHandle h) + public int Index(ResourceHandle h) { #if UNITY_EDITOR // Hot path if (h.version < 0 || h.version >= MaxVersions) @@ -308,7 +319,7 @@ public static int Index(ResourceHandle h) // Flatten array index [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int IndexReader(ResourceHandle h, int readerID) + public int IndexReader(ResourceHandle h, int readerID) { #if UNITY_EDITOR // Hot path if (h.version < 0 || h.version >= MaxVersions) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Debug/RenderGraphDebugParams.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Debug/RenderGraphDebugParams.cs index edc3ccdc78b..be738e2cf7b 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Debug/RenderGraphDebugParams.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Debug/RenderGraphDebugParams.cs @@ -11,6 +11,7 @@ class RenderGraphDebugParams : IDebugDisplaySettingsQuery public bool clearRenderTargetsAtCreation; public bool clearRenderTargetsAtRelease; public bool disablePassCulling; + public bool disablePassMerging; public bool immediateMode; public bool enableLogging; public bool logFrameInformation; @@ -21,6 +22,7 @@ internal void Reset() clearRenderTargetsAtCreation = false; clearRenderTargetsAtRelease = false; disablePassCulling = false; + disablePassMerging = false; immediateMode = false; enableLogging = false; logFrameInformation = false; @@ -32,6 +34,7 @@ private static class Strings public static readonly NameAndTooltip ClearRenderTargetsAtCreation = new() { name = "Clear Render Targets At Creation", tooltip = "Enable to clear all render textures before any rendergraph passes to check if some clears are missing." }; public static readonly NameAndTooltip ClearRenderTargetsAtFree = new() { name = "Clear Render Targets When Freed", tooltip = "Enable to clear all render textures when textures are freed by the graph to detect use after free of textures." }; public static readonly NameAndTooltip DisablePassCulling = new() { name = "Disable Pass Culling", tooltip = "Enable to temporarily disable culling to assess if a pass is culled." }; + public static readonly NameAndTooltip DisablePassMerging = new() { name = "Disable Pass Merging", tooltip = "Enable to temporarily disable pass merging to diagnose issues or analyze performance." }; public static readonly NameAndTooltip ImmediateMode = new() { name = "Immediate Mode", tooltip = "Enable to force render graph to execute all passes in the order you registered them." }; public static readonly NameAndTooltip EnableLogging = new() { name = "Enable Logging", tooltip = "Enable to allow HDRP to capture information in the log." }; public static readonly NameAndTooltip LogFrameInformation = new() { name = "Log Frame Information", tooltip = "Enable to log information output from each frame." }; @@ -69,6 +72,12 @@ private static class Strings setter = value => disablePassCulling = value }, new DebugUI.BoolField + { + nameAndTooltip = Strings.DisablePassMerging, + getter = () => disablePassMerging, + setter = value => disablePassMerging = value + }, + new DebugUI.BoolField { nameAndTooltip = Strings.ImmediateMode, getter = () => immediateMode, @@ -144,6 +153,7 @@ public bool AreAnySettingsActive return clearRenderTargetsAtCreation || clearRenderTargetsAtRelease || disablePassCulling || + disablePassMerging || immediateMode || enableLogging; } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/IRenderGraphBuilder.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/IRenderGraphBuilder.cs index 932cfdde1b0..cb9e6d8e235 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/IRenderGraphBuilder.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/IRenderGraphBuilder.cs @@ -327,6 +327,25 @@ void SetRenderAttachmentDepth(TextureHandle tex, AccessFlags flags = AccessFlags /// The value passed to 'input'. You should not use the returned value it will be removed in the future. BufferHandle UseBufferRandomAccess(BufferHandle tex, int index, bool preserveCounterValue, AccessFlags flags = AccessFlags.Read); + /// + /// Enables Variable Rate Shading (VRS) on the current rasterization pass. Rasterization will use the texture to determine the rate of fragment shader invocation. + /// + /// Shading rate image (SRI) Texture to use during this pass. + void SetShadingRateImageAttachment(in TextureHandle tex); + + /// + /// Set shading rate fragment size. + /// + /// Shading rate fragment size to set. + void SetShadingRateFragmentSize(ShadingRateFragmentSize shadingRateFragmentSize); + + /// + /// Set shading rate combiner. + /// + /// Shading rate combiner stage to apply combiner to. + /// Shading rate combiner to set. + void SetShadingRateCombiner(ShadingRateCombinerStage stage, ShadingRateCombiner combiner); + /// /// Specify the render function to use for this pass. /// A call to this is mandatory for the pass to be valid. diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.Compiler.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.Compiler.cs index 6fac60ecafd..9a49da1624d 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.Compiler.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.Compiler.cs @@ -15,7 +15,7 @@ internal NativePassCompiler CompileNativeRenderGraph(int graphHash) if (nativeCompiler == null) nativeCompiler = new NativePassCompiler(m_CompilationCache); - bool compilationIsCached = nativeCompiler.Initialize(m_Resources, m_RenderPasses, m_DebugParameters.disablePassCulling, name, m_EnableCompilationCaching, graphHash, m_ExecutionCount); + bool compilationIsCached = nativeCompiler.Initialize(m_Resources, m_RenderPasses, m_DebugParameters, name, m_EnableCompilationCaching, graphHash, m_ExecutionCount); if (!compilationIsCached) nativeCompiler.Compile(m_Resources); diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.DebugData.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.DebugData.cs index e2ccb7922b0..a533c2b7870 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.DebugData.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.DebugData.cs @@ -212,7 +212,7 @@ void AddPassDebugMetadata(RenderGraphPass renderPass, string file, int line) if (renderPass.name == k_PassNameDebugIgnoreList[i]) return; - DebugData.s_PassScriptMetadata.Add(renderPass, new DebugData.PassScriptInfo { filePath = file, line = line }); + DebugData.s_PassScriptMetadata.TryAdd(renderPass, new DebugData.PassScriptInfo { filePath = file, line = line }); } [Conditional("UNITY_EDITOR")] diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs index 5903b45bba1..409da6758d1 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs @@ -284,6 +284,8 @@ internal struct CompiledPassInfo public bool culledByRendererList; public bool hasSideEffect; public bool enableFoveatedRasterization; + public bool hasShadingRateImage; + public bool hasShadingRateStates; public void Reset(RenderGraphPass pass, int index) { @@ -293,6 +295,8 @@ public void Reset(RenderGraphPass pass, int index) enableAsyncCompute = pass.enableAsyncCompute; allowPassCulling = pass.allowPassCulling; enableFoveatedRasterization = pass.enableFoveatedRasterization; + hasShadingRateImage = pass.hasShadingRateImage && !pass.enableFoveatedRasterization; + hasShadingRateStates = pass.hasShadingRateStates && !pass.enableFoveatedRasterization; if (resourceCreateList == null) { @@ -601,6 +605,20 @@ public TextureHandle ImportTexture(RTHandle rt) return m_Resources.ImportTexture(rt); } + /// + /// Import an external Variable Rate Shading (VRS) textures to the RenderGraph. + /// Any pass writing to an imported texture will be considered having side effects and can't be automatically culled. + /// + /// External shading rate image RTHandle that needs to be imported. + /// New TextureHandle that represents the imported shading rate images in the context of this rendergraph. + public TextureHandle ImportShadingRateImageTexture(RTHandle rt) + { + if (Vrs.IsShadingRateImageSupported()) + return m_Resources.ImportTexture(rt); + + return TextureHandle.nullHandle; + } + /// /// Import an external texture to the Render Graph. /// Any pass writing to an imported texture will be considered having side effects and can't be automatically culled. @@ -1096,7 +1114,7 @@ public RenderGraphBuilder AddRenderPass(string passName, out PassData [CallerLineNumber] int line = 0) where PassData : class, new() #endif { - var renderPass = m_RenderGraphPool.Get>(); + var renderPass = m_RenderGraphPool.Get>(); renderPass.Initialize(m_RenderPasses.Count, m_RenderGraphPool.Get(), passName, RenderGraphPassType.Legacy, sampler); renderPass.AllowGlobalState(true);// Old pass types allow global state by default as HDRP relies on it @@ -2149,6 +2167,18 @@ void ExecuteRenderGraph() void PreRenderPassSetRenderTargets(in CompiledPassInfo passInfo, RenderGraphPass pass, InternalRenderGraphContext rgContext) { + if (passInfo.hasShadingRateImage) + { +#if DEVELOPMENT_BUILD || UNITY_EDITOR + if (!pass.shadingRateAccess.textureHandle.IsValid()) + { + throw new InvalidOperationException("MRT setup with invalid variable rate shading images."); + } +#endif + + CoreUtils.SetShadingRateImage(rgContext.cmd, m_Resources.GetTexture(pass.shadingRateAccess.textureHandle)); + } + var depthBufferIsValid = pass.depthAccess.textureHandle.IsValid(); if (depthBufferIsValid || pass.colorBufferMaxIndex != -1) { @@ -2219,6 +2249,13 @@ void PreRenderPassExecute(in CompiledPassInfo passInfo, RenderGraphPass pass, In if (passInfo.enableFoveatedRasterization) rgContext.cmd.SetFoveatedRenderingMode(FoveatedRenderingMode.Enabled); + if (passInfo.hasShadingRateStates) + { + rgContext.cmd.SetShadingRateFragmentSize(pass.shadingRateFragmentSize); + rgContext.cmd.SetShadingRateCombiner(ShadingRateCombinerStage.Primitive, pass.primitiveShadingRateCombiner); + rgContext.cmd.SetShadingRateCombiner(ShadingRateCombinerStage.Fragment, pass.fragmentShadingRateCombiner); + } + PreRenderPassSetRenderTargets(passInfo, pass, rgContext); if (passInfo.enableAsyncCompute) @@ -2253,6 +2290,9 @@ void PreRenderPassExecute(in CompiledPassInfo passInfo, RenderGraphPass pass, In void PostRenderPassExecute(ref CompiledPassInfo passInfo, RenderGraphPass pass, InternalRenderGraphContext rgContext) { + if (passInfo.hasShadingRateStates || passInfo.hasShadingRateImage) + rgContext.cmd.ResetShadingRate(); + foreach (var tex in pass.setGlobalsList) { rgContext.cmd.SetGlobalTexture(tex.Item2, tex.Item1); @@ -2472,6 +2512,7 @@ void GenerateCompilerDebugData(ref DebugData debugData) textureData.depth = renderTargetInfo.volumeDepth; textureData.samples = renderTargetInfo.msaaSamples; textureData.format = renderTargetInfo.format; + textureData.bindMS = renderTargetInfo.bindMS; newResource.textureData = textureData; } 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 80a65179171..c5248f752fc 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilders.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilders.cs @@ -219,6 +219,7 @@ private ResourceHandle UseResource(in ResourceHandle handle, AccessFlags flags, } m_RenderPass.AddResourceRead(versioned); + m_Resources.IncrementReadCount(handle); if ((flags & AccessFlags.Read) == 0) { @@ -232,6 +233,7 @@ private ResourceHandle UseResource(in ResourceHandle handle, AccessFlags flags, if ((flags & AccessFlags.Read) != 0) { m_RenderPass.AddResourceRead(m_Resources.GetZeroVersionedHandle(handle)); + m_Resources.IncrementReadCount(handle); } } @@ -511,5 +513,26 @@ void CheckResource(in ResourceHandle res, bool checkTransientReadWrite = false) } } } + + public void SetShadingRateImageAttachment(in TextureHandle sriTextureHandle) + { + CheckNotUseFragment(sriTextureHandle); + + // shading rate image access flag is always read, only 1 mip and 1 slice + var newSriTextureHandle = new TextureHandle(); + newSriTextureHandle.handle = UseResource(sriTextureHandle.handle, AccessFlags.Read); + + m_RenderPass.SetShadingRateImage(newSriTextureHandle, AccessFlags.Read, 0, 0); + } + + public void SetShadingRateFragmentSize(ShadingRateFragmentSize shadingRateFragmentSize) + { + m_RenderPass.SetShadingRateFragmentSize(shadingRateFragmentSize); + } + + public void SetShadingRateCombiner(ShadingRateCombinerStage stage, ShadingRateCombiner combiner) + { + m_RenderPass.SetShadingRateCombiner(stage, combiner); + } } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphPass.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphPass.cs index 093e6d82437..f5049691ac0 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphPass.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphPass.cs @@ -29,6 +29,14 @@ abstract class RenderGraphPass public TextureAccess[] colorBufferAccess { get; protected set; } = new TextureAccess[RenderGraph.kMaxMRTCount]; public int colorBufferMaxIndex { get; protected set; } = -1; + public bool hasShadingRateImage { get; protected set; } + public TextureAccess shadingRateAccess { get; protected set; } + + public bool hasShadingRateStates { get; protected set; } + public ShadingRateFragmentSize shadingRateFragmentSize { get; protected set; } + public ShadingRateCombiner primitiveShadingRateCombiner { get; protected set; } + public ShadingRateCombiner fragmentShadingRateCombiner { get; protected set; } + // Used by native pass compiler only public TextureAccess[] fragmentInputAccess { get; protected set; } = new TextureAccess[RenderGraph.kMaxMRTCount]; public int fragmentInputMaxIndex { get; protected set; } = -1; @@ -96,6 +104,16 @@ public void Clear() colorBufferMaxIndex = -1; fragmentInputMaxIndex = -1; randomAccessResourceMaxIndex = -1; + + // We do not need to clear colorBufferAccess and fragmentInputAccess as we have the colorBufferMaxIndex and fragmentInputMaxIndex + // which are reset above so we only clear depthAccess here. + depthAccess = default(TextureAccess); + + hasShadingRateImage = false; + hasShadingRateStates = false; + shadingRateFragmentSize = ShadingRateFragmentSize.FragmentSize1x1; + primitiveShadingRateCombiner = ShadingRateCombiner.Keep; + fragmentShadingRateCombiner = ShadingRateCombiner.Keep; } // Check if the pass has any render targets set-up @@ -431,6 +449,22 @@ public void ComputeHash(ref HashFNV1A32 generator, RenderGraphResourceRegistry r generator.Append(colorBufferMaxIndex); + generator.Append(hasShadingRateImage); + if (hasShadingRateImage) + { + var handle = shadingRateAccess.textureHandle.handle; + if (handle.IsValid()) + { + ComputeTextureHash(ref generator, handle, resources); + ComputeHashForTextureAccess(ref generator, handle, shadingRateAccess); + } + } + + generator.Append(hasShadingRateStates); + generator.Append((int)shadingRateFragmentSize); + generator.Append((int)primitiveShadingRateCombiner); + generator.Append((int)fragmentShadingRateCombiner); + for (int i = 0; i < fragmentInputMaxIndex + 1; ++i) { var fragmentInputAccessElement = fragmentInputAccess[i]; @@ -488,6 +522,44 @@ public void ComputeHash(ref HashFNV1A32 generator, RenderGraphResourceRegistry r generator.Append(GetRenderFuncHash()); } + public void SetShadingRateImage(in TextureHandle shadingRateImage, AccessFlags accessFlags, int mipLevel, int depthSlice) + { + if (Vrs.IsShadingRateImageSupported()) + { + hasShadingRateImage = true; + shadingRateAccess = new TextureAccess(shadingRateImage, accessFlags, mipLevel, depthSlice); + AddResourceRead(shadingRateAccess.textureHandle.handle); + } + } + + public void SetShadingRateFragmentSize(ShadingRateFragmentSize shadingRateFragmentSize) + { + if (Vrs.IsSupported()) + { + hasShadingRateStates = true; + this.shadingRateFragmentSize = shadingRateFragmentSize; + } + } + + public void SetShadingRateCombiner(ShadingRateCombinerStage stage, ShadingRateCombiner combiner) + { + if (Vrs.IsShadingRateImageSupported()) + { + switch (stage) + { + case ShadingRateCombinerStage.Primitive: + hasShadingRateStates = true; + primitiveShadingRateCombiner = combiner; + break; + + case ShadingRateCombinerStage.Fragment: + hasShadingRateStates = true; + fragmentShadingRateCombiner = combiner; + break; + } + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] static void ComputeHashForTextureAccess(ref HashFNV1A32 generator, in ResourceHandle handle, in TextureAccess textureAccess) { diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceRegistry.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceRegistry.cs index c1aa76d80c7..d34c6212f04 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceRegistry.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceRegistry.cs @@ -349,6 +349,12 @@ internal void IncrementWriteCount(in ResourceHandle res) m_RenderGraphResources[res.iType].resourceArray[res.index].IncrementWriteCount(); } + internal void IncrementReadCount(in ResourceHandle res) + { + CheckHandleValidity(res); + m_RenderGraphResources[res.iType].resourceArray[res.index].IncrementReadCount(); + } + internal void NewVersion(in ResourceHandle res) { CheckHandleValidity(res); @@ -680,7 +686,7 @@ internal TextureHandle ImportBackbuffer(RenderTargetIdentifier rt, in RenderTarg return texHandle; } - static RenderTargetIdentifier emptyId = new RenderTargetIdentifier(); + static RenderTargetIdentifier emptyId = RenderTargetIdentifier.Invalid; static RenderTargetIdentifier builtinCameraRenderTarget = new RenderTargetIdentifier(BuiltinRenderTextureType.CameraTarget); [Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")] diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceTexture.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceTexture.cs index ce22c2e771d..ec00acf40ae 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceTexture.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceTexture.cs @@ -200,6 +200,16 @@ public struct TextureDesc public RenderTextureMemoryless memoryless; ///Special treatment of the VR eye texture used in stereoscopic rendering. public VRTextureUsage vrUsage; + + /// + /// Set to true if the texture is to be used as a shading rate image. + /// + /// + /// Width and height are usually in pixels but if enableShadingRate is set to true, width and height are in tiles. + /// See also Variable Rate Shading. + /// + public bool enableShadingRate; + ///Texture name. public string name; #if UNITY_2020_2_OR_NEWER @@ -229,7 +239,7 @@ public DepthBits depthBufferBits { get { return (DepthBits)GraphicsFormatUtility.GetDepthBits(format); } set - { + { if (value == DepthBits.None) { if( !GraphicsFormatUtility.IsDepthStencilFormat(format) ) @@ -240,7 +250,7 @@ public DepthBits depthBufferBits else { format = GraphicsFormatUtility.GetDepthStencilFormat((int)value); - } + } } } @@ -372,6 +382,7 @@ public TextureDesc(RenderTextureDescriptor input) clearBuffer = true; clearColor = Color.black; discardBuffer = false; + enableShadingRate = input.enableShadingRate; } /// @@ -429,6 +440,7 @@ public override int GetHashCode() #if UNITY_2020_2_OR_NEWER hashCode.Append(fastMemoryDesc.inFastMemory); #endif + hashCode.Append(enableShadingRate); return hashCode.value; } @@ -474,21 +486,42 @@ public override void CreateGraphicsResource() // Textures are going to be reused under different aliases along the frame so we can't provide a specific name upon creation. // The name in the desc is going to be used for debugging purpose and render graph visualization. if (name == "") - name = $"RenderGraphTexture_{m_TextureCreationIndex++}"; + name = $"RenderGraphTexture_{m_TextureCreationIndex++}"; + + RTHandleAllocInfo rtAllocInfo = new RTHandleAllocInfo(name) + { + slices = desc.slices, + format = desc.format, + filterMode = desc.filterMode, + wrapModeU = desc.wrapMode, + wrapModeV = desc.wrapMode, + wrapModeW = desc.wrapMode, + dimension = desc.dimension, + enableRandomWrite = desc.enableRandomWrite, + useMipMap = desc.useMipMap, + autoGenerateMips = desc.autoGenerateMips, + anisoLevel = desc.anisoLevel, + mipMapBias = desc.mipMapBias, + isShadowMap = desc.isShadowMap, + msaaSamples = (MSAASamples)desc.msaaSamples, + bindTextureMS = desc.bindTextureMS, + useDynamicScale = desc.useDynamicScale, + useDynamicScaleExplicit = desc.useDynamicScaleExplicit, + memoryless = desc.memoryless, + vrUsage = desc.vrUsage, + enableShadingRate = desc.enableShadingRate, + }; switch (desc.sizeMode) { case TextureSizeMode.Explicit: - graphicsResource = RTHandles.Alloc(desc.width, desc.height, desc.format, desc.slices, desc.filterMode, desc.wrapMode, desc.dimension, desc.enableRandomWrite, - desc.useMipMap, desc.autoGenerateMips, desc.isShadowMap, desc.anisoLevel, desc.mipMapBias, desc.msaaSamples, desc.bindTextureMS, desc.useDynamicScale, desc.useDynamicScaleExplicit, desc.memoryless, desc.vrUsage, name); + graphicsResource = RTHandles.Alloc(desc.width, desc.height, rtAllocInfo); break; case TextureSizeMode.Scale: - graphicsResource = RTHandles.Alloc(desc.scale, desc.format, desc.slices, desc.filterMode, desc.wrapMode, desc.dimension, desc.enableRandomWrite, - desc.useMipMap, desc.autoGenerateMips, desc.isShadowMap, desc.anisoLevel, desc.mipMapBias, desc.msaaSamples, desc.bindTextureMS, desc.useDynamicScale, desc.useDynamicScaleExplicit, desc.memoryless, desc.vrUsage, name); + graphicsResource = RTHandles.Alloc(desc.scale, rtAllocInfo); break; case TextureSizeMode.Functor: - graphicsResource = RTHandles.Alloc(desc.func, desc.format, desc.slices, desc.filterMode, desc.wrapMode, desc.dimension, desc.enableRandomWrite, - desc.useMipMap, desc.autoGenerateMips, desc.isShadowMap, desc.anisoLevel, desc.mipMapBias, desc.msaaSamples, desc.bindTextureMS, desc.useDynamicScale, desc.useDynamicScaleExplicit, desc.memoryless, desc.vrUsage, name); + graphicsResource = RTHandles.Alloc(desc.func, rtAllocInfo); break; } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResources.cs b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResources.cs index 5df755d4fe5..df4c4ccc562 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResources.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResources.cs @@ -128,6 +128,7 @@ class IRenderGraphResource public bool requestFallBack; public bool forceRelease; public uint writeCount; + public uint readCount; public int cachedHash; public int transientPassIndex; public int sharedResourceLastFrameUsed; @@ -145,6 +146,7 @@ public virtual void Reset(IRenderGraphResourcePool _ = null) requestFallBack = false; forceRelease = false; writeCount = 0; + readCount = 0; version = 0; } @@ -166,6 +168,13 @@ public virtual void IncrementWriteCount() writeCount++; } + // readCount is currently not used in the HDRP Compiler. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void IncrementReadCount() + { + readCount++; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual int NewVersion() { diff --git a/Packages/com.unity.render-pipelines.core/Runtime/STP/StpPreTaa.compute b/Packages/com.unity.render-pipelines.core/Runtime/STP/StpPreTaa.compute index 9cdd13b7817..5c89ff78bfc 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/STP/StpPreTaa.compute +++ b/Packages/com.unity.render-pipelines.core/Runtime/STP/StpPreTaa.compute @@ -9,13 +9,6 @@ #pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch glcore -// TODO: Remove explicit randomwrite shader requirement -// -// The randomwrite requirement isn't automatically included in compute shaders even though they cannot work without it. -// We must explicitly require it here to avoid breaking code that checks against the SHADER_AVAILABLE_RANDOMWRITE define. -// This code should be removed when the underlying compiler code is updated to implicitly require randomwrite in compute shaders. -#pragma require randomwrite - #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl" diff --git a/Packages/com.unity.render-pipelines.core/Runtime/STP/StpSetup.compute b/Packages/com.unity.render-pipelines.core/Runtime/STP/StpSetup.compute index e64b916626f..4d98f8bb130 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/STP/StpSetup.compute +++ b/Packages/com.unity.render-pipelines.core/Runtime/STP/StpSetup.compute @@ -16,13 +16,6 @@ #pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch glcore -// TODO: Remove explicit randomwrite shader requirement -// -// The randomwrite requirement isn't automatically included in compute shaders even though they cannot work without it. -// We must explicitly require it here to avoid breaking code that checks against the SHADER_AVAILABLE_RANDOMWRITE define. -// This code should be removed when the underlying compiler code is updated to implicitly require randomwrite in compute shaders. -#pragma require randomwrite - #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl" diff --git a/Packages/com.unity.render-pipelines.core/Runtime/STP/StpTaa.compute b/Packages/com.unity.render-pipelines.core/Runtime/STP/StpTaa.compute index feab80e85d1..c9904044acc 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/STP/StpTaa.compute +++ b/Packages/com.unity.render-pipelines.core/Runtime/STP/StpTaa.compute @@ -9,13 +9,6 @@ #pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch glcore -// TODO: Remove explicit randomwrite shader requirement -// -// The randomwrite requirement isn't automatically included in compute shaders even though they cannot work without it. -// We must explicitly require it here to avoid breaking code that checks against the SHADER_AVAILABLE_RANDOMWRITE define. -// This code should be removed when the underlying compiler code is updated to implicitly require randomwrite in compute shaders. -#pragma require randomwrite - #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl" diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Textures/BufferedRTHandleSystem.cs b/Packages/com.unity.render-pipelines.core/Runtime/Textures/BufferedRTHandleSystem.cs index 0a8ae2c0d88..96a948556e8 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Textures/BufferedRTHandleSystem.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Textures/BufferedRTHandleSystem.cs @@ -156,40 +156,17 @@ public void AllocBuffer(int bufferId, int bufferCount, var buffer = new RTHandle[bufferCount]; m_RTHandles.Add(bufferId, buffer); - var format = RTHandles.GetFormat(descriptor.graphicsFormat, descriptor.depthStencilFormat); - - RTHandle Alloc(ref RenderTextureDescriptor d, FilterMode fMode, TextureWrapMode wMode, bool isShadow, int aniso, float mipBias, string n) - { - return m_RTHandleSystem.Alloc( - d.width, - d.height, - format, - d.volumeDepth, - fMode, - wMode, - d.dimension, - d.enableRandomWrite, - d.useMipMap, - d.autoGenerateMips, - isShadow, - aniso, - mipBias, - (MSAASamples)d.msaaSamples, - d.bindMS, - d.useDynamicScale, - d.useDynamicScaleExplicit, - d.memoryless, - d.vrUsage, - n); - } + RTHandleAllocInfo allocInfo = RTHandles.GetRTHandleAllocInfo(descriptor, filterMode, + wrapMode, anisoLevel, mipMapBias, name); + allocInfo.isShadowMap = isShadowMap; // First is autoresized - buffer[0] = Alloc(ref descriptor, filterMode, wrapMode, isShadowMap, anisoLevel, mipMapBias, name); + buffer[0] = m_RTHandleSystem.Alloc(descriptor.width, descriptor.height, allocInfo); // Other are resized on demand for (int i = 1, c = buffer.Length; i < c; ++i) { - buffer[i] = Alloc(ref descriptor, filterMode, wrapMode, isShadowMap, anisoLevel, mipMapBias, name); + buffer[i] = m_RTHandleSystem.Alloc(descriptor.width, descriptor.height, allocInfo); m_RTHandleSystem.SwitchResizeMode(buffer[i], RTHandleSystem.ResizeMode.OnDemand); } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Textures/RTHandleSystem.cs b/Packages/com.unity.render-pipelines.core/Runtime/Textures/RTHandleSystem.cs index 8f3745d791e..cc04a46523d 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Textures/RTHandleSystem.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Textures/RTHandleSystem.cs @@ -79,6 +79,9 @@ public struct RTHandleAllocInfo /// Set to true to automatically generate mipmaps. public bool autoGenerateMips { get; set; } + /// Set to true if the texture is sampled as a shadow map. + public bool isShadowMap { get; set; } + /// Anisotropic filtering level. public int anisoLevel { get; set; } @@ -94,12 +97,24 @@ public struct RTHandleAllocInfo /// See Dynamic Resolution documentation](https://docs.unity3d.com/Manual/DynamicResolution.html) public bool useDynamicScale { get; set; } + /// See Dynamic Resolution documentation](https://docs.unity3d.com/Manual/DynamicResolution-control-when-occurs.html) + public bool useDynamicScaleExplicit { get; set; } + /// Use this property to set the render texture memoryless modes. public RenderTextureMemoryless memoryless { get; set; } /// Special treatment of the VR eye texture used in stereoscopic rendering. public VRTextureUsage vrUsage { get; set; } + /// + /// Set to true if the texture is to be used as a shading rate image. + /// + /// + /// Width and height are usually in pixels but if enableShadingRate is set to true, width and height are in tiles. + /// See also Variable Rate Shading. + /// + public bool enableShadingRate { get; set; } + /// Name of the RTHandle. public string name { get; set; } @@ -119,13 +134,16 @@ public RTHandleAllocInfo(string name = "") this.enableRandomWrite = false; this.useMipMap = false; this.autoGenerateMips = true; + this.isShadowMap = false; this.anisoLevel = 1; this.mipMapBias = 0f; this.msaaSamples = MSAASamples.None; this.bindTextureMS = false; this.useDynamicScale = false; + this.useDynamicScaleExplicit = false; this.memoryless = RenderTextureMemoryless.None; this.vrUsage = VRTextureUsage.None; + this.enableShadingRate = false; this.name = name; } } @@ -519,7 +537,7 @@ void Resize(int width, int height, bool sizeChanged) /// Allocate a new fixed sized RTHandle. /// /// With of the RTHandle. - /// Heigh of the RTHandle. + /// height of the RTHandle. /// Number of slices of the RTHandle. /// Bit depths of a depth buffer. /// GraphicsFormat of a color buffer. @@ -574,7 +592,7 @@ public RTHandle Alloc( /// Allocate a new fixed sized RTHandle. /// /// With of the RTHandle. - /// Heigh of the RTHandle. + /// height of the RTHandle. /// GraphicsFormat of a color or depth stencil buffer. /// Number of slices of the RTHandle. /// Filtering mode of the RTHandle. @@ -598,7 +616,7 @@ public RTHandle Alloc( int width, int height, GraphicsFormat format, - int slices = 1, + int slices = 1, FilterMode filterMode = FilterMode.Point, TextureWrapMode wrapMode = TextureWrapMode.Repeat, TextureDimension dimension = TextureDimension.Tex2D, @@ -625,7 +643,7 @@ public RTHandle Alloc( /// Allocate a new fixed sized RTHandle. /// /// With of the RTHandle. - /// Heigh of the RTHandle. + /// height of the RTHandle. /// U coordinate wrapping mode of the RTHandle. /// V coordinate wrapping mode of the RTHandle. /// W coordinate wrapping mode of the RTHandle. @@ -683,7 +701,7 @@ public RTHandle Alloc( wrapModeU, wrapModeV, wrapModeW, - slices, + slices, filterMode, dimension, enableRandomWrite, @@ -706,7 +724,7 @@ public RTHandle Alloc( /// Allocate a new fixed sized RTHandle. /// /// With of the RTHandle. - /// Heigh of the RTHandle. + /// height of the RTHandle. /// GraphicsFormat of the color or a depth stencil buffer. /// U coordinate wrapping mode of the RTHandle. /// V coordinate wrapping mode of the RTHandle. @@ -735,7 +753,7 @@ public RTHandle Alloc( TextureWrapMode wrapModeU, TextureWrapMode wrapModeV, TextureWrapMode wrapModeW = TextureWrapMode.Repeat, - int slices = 1, + int slices = 1, FilterMode filterMode = FilterMode.Point, TextureDimension dimension = TextureDimension.Tex2D, bool enableRandomWrite = false, @@ -756,7 +774,7 @@ public RTHandle Alloc( var rt = CreateRenderTexture( width, height, format, slices, filterMode, wrapModeU, wrapModeV, wrapModeW, dimension, enableRandomWrite, useMipMap , autoGenerateMips, isShadowMap, anisoLevel, mipMapBias, msaaSamples, bindTextureMS - , useDynamicScale, useDynamicScaleExplicit, memoryless, vrUsage, name); + , useDynamicScale, useDynamicScaleExplicit, memoryless, vrUsage, false, name); var newRT = new RTHandle(this); newRT.SetRenderTexture(rt); @@ -793,6 +811,7 @@ private RenderTexture CreateRenderTexture( bool useDynamicScaleExplicit, RenderTextureMemoryless memoryless, VRTextureUsage vrUsage, + bool enableShadingRate, string name) { bool enableMSAA = msaaSamples != MSAASamples.None; @@ -811,6 +830,13 @@ private RenderTexture CreateRenderTexture( } bool isDepthStencilFormat = GraphicsFormatUtility.IsDepthStencilFormat(format); + + if (enableShadingRate && (isShadowMap || isDepthStencilFormat)) + { + Debug.LogWarning("RTHandle allocated with incompatible enableShadingRate, forcing enableShadingRate to false."); + enableShadingRate = false; + } + string fullName; GraphicsFormat colorFormat, depthStencilFormat, stencilFormat; ShadowSamplingMode shadowSamplingMode = ShadowSamplingMode.None; @@ -822,7 +848,7 @@ private RenderTexture CreateRenderTexture( int depthBits = GraphicsFormatUtility.GetDepthBits(format); if (depthBits < 16) depthBits = 16; - depthStencilFormat = GraphicsFormatUtility.GetDepthStencilFormat(depthBits, 0); + depthStencilFormat = GraphicsFormatUtility.GetDepthStencilFormat(depthBits, 0); colorFormat = GraphicsFormat.None; stencilFormat = GraphicsFormat.None; shadowSamplingMode = ShadowSamplingMode.CompareDepths; @@ -859,10 +885,11 @@ private RenderTexture CreateRenderTexture( memoryless = memoryless, useMipMap = useMipMap, autoGenerateMips = autoGenerateMips, - enableRandomWrite = enableRandomWrite, + enableRandomWrite = enableRandomWrite, bindMS = bindTextureMS, useDynamicScale = m_HardwareDynamicResRequested && useDynamicScale, - useDynamicScaleExplicit = m_HardwareDynamicResRequested && useDynamicScaleExplicit + useDynamicScaleExplicit = m_HardwareDynamicResRequested && useDynamicScaleExplicit, + enableShadingRate = enableShadingRate, }; var rt = new RenderTexture(desc); @@ -876,7 +903,7 @@ private RenderTexture CreateRenderTexture( rt.wrapModeU = wrapModeU; rt.wrapModeV = wrapModeV; - rt.wrapModeW = wrapModeW; + rt.wrapModeW = wrapModeW; rt.Create(); return rt; @@ -889,15 +916,16 @@ private RenderTexture CreateRenderTexture( /// Height of the RTHandle. /// Struct containing details of allocation /// A new RTHandle. + /// + /// Width and height are usually in pixels but if enableShadingRate is set to true, width and height are in tiles. + /// See also Variable Rate Shading. + /// public RTHandle Alloc(int width, int height, RTHandleAllocInfo info) { - bool isShadowMap = false; - bool useDynamicScaleExplicit = false; - var rt = CreateRenderTexture( width, height, info.format, info.slices, info.filterMode, info.wrapModeU, info.wrapModeV, info.wrapModeW, info.dimension, info.enableRandomWrite, info.useMipMap - , info.autoGenerateMips, isShadowMap, info.anisoLevel, info.mipMapBias, info.msaaSamples, info.bindTextureMS - , info.useDynamicScale, useDynamicScaleExplicit, info.memoryless, info.vrUsage, info.name); + , info.autoGenerateMips, info.isShadowMap, info.anisoLevel, info.mipMapBias, info.msaaSamples, info.bindTextureMS + , info.useDynamicScale, info.useDynamicScaleExplicit, info.memoryless, info.vrUsage, info.enableShadingRate, info.name); var newRT = new RTHandle(this); newRT.SetRenderTexture(rt); @@ -909,6 +937,14 @@ public RTHandle Alloc(int width, int height, RTHandleAllocInfo info) newRT.referenceSize = new Vector2Int(width, height); + if (info.enableShadingRate) + { + // even though allocation ask for an explicit size, it's possible the + // resize mode is changed afterward hence assigning the scaling function + // because shading rate image resolution is in tiles + newRT.scaleFunc = (refSize) => ShadingRateImage.GetAllocTileSize(refSize); + } + return newRT; } @@ -923,10 +959,15 @@ public RTHandle Alloc(int width, int height, RTHandleAllocInfo info) /// The scale factor to use when calculating the dimensions. The base unscaled size used, is the sizes passed to the last ResetReferenceSize call. /// The calculated dimensions. public Vector2Int CalculateDimensions(Vector2 scaleFactor) + { + return CalculateDimensions(scaleFactor, new Vector2Int(GetMaxWidth(), GetMaxHeight())); + } + + static Vector2Int CalculateDimensions(Vector2 scaleFactor, Vector2Int size) { return new Vector2Int( - Mathf.Max(Mathf.RoundToInt(scaleFactor.x * GetMaxWidth()), 1), - Mathf.Max(Mathf.RoundToInt(scaleFactor.y * GetMaxHeight()), 1) + Mathf.Max(Mathf.RoundToInt(scaleFactor.x * size.x), 1), + Mathf.Max(Mathf.RoundToInt(scaleFactor.y * size.y), 1) ); } @@ -956,7 +997,7 @@ public Vector2Int CalculateDimensions(Vector2 scaleFactor) public RTHandle Alloc( Vector2 scaleFactor, GraphicsFormat format, - int slices = 1, + int slices = 1, FilterMode filterMode = FilterMode.Point, TextureWrapMode wrapMode = TextureWrapMode.Repeat, TextureDimension dimension = TextureDimension.Tex2D, @@ -977,6 +1018,7 @@ public RTHandle Alloc( { var actualDimensions = CalculateDimensions(scaleFactor); + bool enableShadingRate = false; // Not supported, use RTHandleAllocInfo API instead. var rth = AllocAutoSizedRenderTexture(actualDimensions.x, actualDimensions.y, slices, @@ -996,12 +1038,13 @@ public RTHandle Alloc( useDynamicScaleExplicit, memoryless, vrUsage, + enableShadingRate, name ); rth.referenceSize = actualDimensions; - rth.scaleFactor = scaleFactor; + return rth; } @@ -1082,6 +1125,11 @@ public RTHandle Alloc( /// Constant scale for the RTHandle size computation. /// Struct containing details of allocation /// A new RTHandle. + /// + /// scaleFactor is expected to be based on the reference size in pixels. If enableShadingRate is set to true, + /// conversion in tiles is implicitly done prior to allocation. + /// See also Variable Rate Shading. + /// public RTHandle Alloc(Vector2 scaleFactor, RTHandleAllocInfo info) { int width = Mathf.Max(Mathf.RoundToInt(scaleFactor.x * GetMaxWidth()), 1); @@ -1089,7 +1137,18 @@ public RTHandle Alloc(Vector2 scaleFactor, RTHandleAllocInfo info) var rth = AllocAutoSizedRenderTexture(width, height, info); rth.referenceSize = new Vector2Int(width, height); - rth.scaleFactor = scaleFactor; + + if (info.enableShadingRate) + { + // shading rate image resolution is in tiles; adjust refSize + rth.scaleFunc = (refSize) => + { + var dimensions = CalculateDimensions(scaleFactor, refSize); + return ShadingRateImage.GetAllocTileSize(dimensions); + }; + } + else + rth.scaleFactor = scaleFactor; return rth; } @@ -1195,7 +1254,7 @@ public RTHandle Alloc( /// /// Function used for the RTHandle size computation. /// GraphicsFormat of a color or depth stencil buffer. - /// Number of slices of the RTHandle. + /// Number of slices of the RTHandle. /// Filtering mode of the RTHandle. /// Addressing mode of the RTHandle. /// Texture dimension of the RTHandle. @@ -1216,7 +1275,7 @@ public RTHandle Alloc( public RTHandle Alloc( ScaleFunc scaleFunc, GraphicsFormat format, - int slices = 1, + int slices = 1, FilterMode filterMode = FilterMode.Point, TextureWrapMode wrapMode = TextureWrapMode.Repeat, TextureDimension dimension = TextureDimension.Tex2D, @@ -1237,9 +1296,10 @@ public RTHandle Alloc( { var actualDimensions = CalculateDimensions(scaleFunc); + bool enableShadingRate = false; // Not supported, use RTHandleAllocInfo API instead. var rth = AllocAutoSizedRenderTexture(actualDimensions.x, actualDimensions.y, - slices, + slices, format, filterMode, wrapMode, @@ -1256,12 +1316,13 @@ public RTHandle Alloc( useDynamicScaleExplicit, memoryless, vrUsage, + enableShadingRate, name ); rth.referenceSize = actualDimensions; - rth.scaleFunc = scaleFunc; + return rth; } @@ -1271,6 +1332,11 @@ public RTHandle Alloc( /// Function used for the RTHandle size computation. /// Struct containing details of allocation /// A new RTHandle. + /// + /// scaleFunc is expected to receive pixel values. If enableShadingRate is set to true, + /// conversion in tiles is done prior to allocation so that scaleFunc does not have to handle it. + /// See also Variable Rate Shading. + /// public RTHandle Alloc(ScaleFunc scaleFunc, RTHandleAllocInfo info) { var scaleFactor = scaleFunc(new Vector2Int(GetMaxWidth(), GetMaxHeight())); @@ -1279,16 +1345,29 @@ public RTHandle Alloc(ScaleFunc scaleFunc, RTHandleAllocInfo info) var rth = AllocAutoSizedRenderTexture(width, height, info); rth.referenceSize = new Vector2Int(width, height); - rth.scaleFunc = scaleFunc; + + if (info.enableShadingRate) + { + rth.scaleFunc = (refSize) => + { + var dimensions = scaleFunc(refSize); + + // shading rate image resolution is in tiles and current values are in pixels. + // Alloc() with a scaling function is based on refSize which is in pixels. + // adjust dimensions + return ShadingRateImage.GetAllocTileSize(dimensions); + }; + } + else + rth.scaleFunc = scaleFunc; return rth; } - // Internal function - RTHandle AllocAutoSizedRenderTexture( + internal RTHandle AllocAutoSizedRenderTexture( int width, int height, - int slices, + int slices, GraphicsFormat format, FilterMode filterMode, TextureWrapMode wrapMode, @@ -1305,13 +1384,24 @@ RTHandle AllocAutoSizedRenderTexture( bool useDynamicScaleExplicit, RenderTextureMemoryless memoryless, VRTextureUsage vrUsage, + bool enableShadingRate, string name ) { + if (enableShadingRate) + { + // this function is called when auto scaling is needed and always expect size in pixels. + // shading rate image resolution is in tiles and current values are in pixels. + // then must adjust width and height + var actualDimensions = ShadingRateImage.GetAllocTileSize(width, height); + width = actualDimensions.x; + height = actualDimensions.y; + } + var rt = CreateRenderTexture( width, height, format, slices, filterMode, wrapMode, wrapMode, wrapMode, dimension, enableRandomWrite, useMipMap , autoGenerateMips, isShadowMap, anisoLevel, mipMapBias, msaaSamples, bindTextureMS - , useDynamicScale, useDynamicScaleExplicit, memoryless, vrUsage, name); + , useDynamicScale, useDynamicScaleExplicit, memoryless, vrUsage, enableShadingRate, name); var rth = new RTHandle(this); rth.SetRenderTexture(rt); @@ -1324,15 +1414,22 @@ string name return rth; } - RTHandle AllocAutoSizedRenderTexture(int width, int height, RTHandleAllocInfo info) + internal RTHandle AllocAutoSizedRenderTexture(int width, int height, RTHandleAllocInfo info) { - bool isShadowMap = false; - bool useDynamicScaleExplicit = false; + if (info.enableShadingRate) + { + // this function is called when auto scaling is needed and always expect size in pixels. + // shading rate image resolution is in tiles and current values are in pixels. + // then must adjust width and height + var actualDimensions = ShadingRateImage.GetAllocTileSize(width, height); + width = actualDimensions.x; + height = actualDimensions.y; + } var rt = CreateRenderTexture( width, height, info.format, info.slices, info.filterMode, info.wrapModeU, info.wrapModeV, info.wrapModeW, info.dimension, info.enableRandomWrite, info.useMipMap - , info.autoGenerateMips, isShadowMap, info.anisoLevel, info.mipMapBias, info.msaaSamples, info.bindTextureMS - , info.useDynamicScale, useDynamicScaleExplicit, info.memoryless, info.vrUsage, info.name); + , info.autoGenerateMips, info.isShadowMap, info.anisoLevel, info.mipMapBias, info.msaaSamples, info.bindTextureMS + , info.useDynamicScale, info.useDynamicScaleExplicit, info.memoryless, info.vrUsage, info.enableShadingRate, info.name); var rth = new RTHandle(this); rth.SetRenderTexture(rt); diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Textures/RTHandles.cs b/Packages/com.unity.render-pipelines.core/Runtime/Textures/RTHandles.cs index 35698efb05a..1cd7b308ea4 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Textures/RTHandles.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Textures/RTHandles.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.CompilerServices; using UnityEngine.Assertions; using UnityEngine.Experimental.Rendering; @@ -48,7 +49,7 @@ public static Vector2Int CalculateDimensions(ScaleFunc scaleFunc) /// Allocate a new fixed sized RTHandle with the default RTHandle System. /// /// With of the RTHandle. - /// Heigh of the RTHandle. + /// height of the RTHandle. /// Number of slices of the RTHandle. /// Bit depths of a depth buffer. /// GraphicsFormat of a color buffer. @@ -122,9 +123,9 @@ public static RTHandle Alloc( /// Allocate a new fixed sized RTHandle with the default RTHandle System. /// /// With of the RTHandle. - /// Heigh of the RTHandle. + /// height of the RTHandle. /// GraphicsFormat of a color or depth stencil buffer. - /// Number of slices of the RTHandle. + /// Number of slices of the RTHandle. /// Filtering mode of the RTHandle. /// Addressing mode of the RTHandle. /// Texture dimension of the RTHandle. @@ -146,7 +147,7 @@ public static RTHandle Alloc( int width, int height, GraphicsFormat format, - int slices = 1, + int slices = 1, FilterMode filterMode = FilterMode.Point, TextureWrapMode wrapMode = TextureWrapMode.Repeat, TextureDimension dimension = TextureDimension.Tex2D, @@ -169,7 +170,7 @@ public static RTHandle Alloc( width, height, format, - slices, + slices, filterMode, wrapMode, dimension, @@ -193,7 +194,7 @@ public static RTHandle Alloc( /// Allocate a new fixed sized RTHandle with the default RTHandle System. /// /// With of the RTHandle. - /// Heigh of the RTHandle. + /// height of the RTHandle. /// U coordinate wrapping mode of the RTHandle. /// V coordinate wrapping mode of the RTHandle. /// W coordinate wrapping mode of the RTHandle. @@ -302,38 +303,49 @@ public static RTHandle Alloc( string name = "" ) { - var format = GetFormat(descriptor.graphicsFormat, descriptor.depthStencilFormat); - - var result = s_DefaultInstance.Alloc( - descriptor.width, - descriptor.height, - format, - descriptor.volumeDepth, - filterMode, - wrapMode, - descriptor.dimension, - descriptor.enableRandomWrite, - descriptor.useMipMap, - descriptor.autoGenerateMips, - isShadowMap, - anisoLevel, - mipMapBias, - (MSAASamples)descriptor.msaaSamples, - descriptor.bindMS, - descriptor.useDynamicScale, - descriptor.useDynamicScaleExplicit, - descriptor.memoryless, - descriptor.vrUsage, - name - ); - return result; + return s_DefaultInstance.Alloc(descriptor.width, descriptor.height, + GetRTHandleAllocInfo(descriptor, filterMode, wrapMode, anisoLevel, mipMapBias, name)); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] static internal GraphicsFormat GetFormat(GraphicsFormat colorFormat, GraphicsFormat depthStencilFormat) { return (depthStencilFormat==GraphicsFormat.None) ? colorFormat : depthStencilFormat; } + // Internal RtDesc to RtAllocInfo conversion utility function. + // Keep internal for future changes. + // + // NOTE: It has no default values to avoid param ambiguity of the flat RtHandleAlloc API. + // NOTE: There isn't 100% field to field mapping, so some fields might need manual adjustment afterwards. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static RTHandleAllocInfo GetRTHandleAllocInfo(in RenderTextureDescriptor desc, FilterMode filterMode, TextureWrapMode wrapMode, int anisoLevel, float mipMapBias, string name) + { + return new RTHandleAllocInfo(name) + { + slices = desc.volumeDepth, + format = RTHandles.GetFormat(desc.graphicsFormat, desc.depthStencilFormat), + filterMode = filterMode, + wrapModeU = wrapMode, + wrapModeV = wrapMode, + wrapModeW = wrapMode, + dimension = desc.dimension, + enableRandomWrite = desc.enableRandomWrite, + useMipMap = desc.useMipMap, + autoGenerateMips = desc.autoGenerateMips, + isShadowMap = desc.shadowSamplingMode != ShadowSamplingMode.None, + anisoLevel = anisoLevel, + mipMapBias = mipMapBias, + msaaSamples = (MSAASamples)desc.msaaSamples, + bindTextureMS = desc.bindMS, + useDynamicScale = desc.useDynamicScale, + useDynamicScaleExplicit = desc.useDynamicScaleExplicit, + memoryless = desc.memoryless, + vrUsage = desc.vrUsage, + enableShadingRate = desc.enableShadingRate, + }; + } + /// /// Allocate a new automatically sized RTHandle for the default RTHandle System. /// @@ -431,7 +443,7 @@ public static RTHandle Alloc( public static RTHandle Alloc( Vector2 scaleFactor, GraphicsFormat format, - int slices = 1, + int slices = 1, FilterMode filterMode = FilterMode.Point, TextureWrapMode wrapMode = TextureWrapMode.Repeat, TextureDimension dimension = TextureDimension.Tex2D, @@ -496,29 +508,8 @@ public static RTHandle Alloc( string name = "" ) { - var format = GetFormat(descriptor.graphicsFormat, descriptor.depthStencilFormat); - - return s_DefaultInstance.Alloc( - scaleFactor, - format, - descriptor.volumeDepth, - filterMode, - wrapMode, - descriptor.dimension, - descriptor.enableRandomWrite, - descriptor.useMipMap, - descriptor.autoGenerateMips, - isShadowMap, - anisoLevel, - mipMapBias, - (MSAASamples)descriptor.msaaSamples, - descriptor.bindMS, - descriptor.useDynamicScale, - descriptor.useDynamicScaleExplicit, - descriptor.memoryless, - descriptor.vrUsage, - name - ); + return s_DefaultInstance.Alloc(scaleFactor, + GetRTHandleAllocInfo(descriptor, filterMode, wrapMode, anisoLevel, mipMapBias, name)); } /// @@ -697,29 +688,8 @@ public static RTHandle Alloc( Assert.IsFalse(descriptor.graphicsFormat != GraphicsFormat.None && descriptor.depthStencilFormat != GraphicsFormat.None, "The RenderTextureDescriptor used to create RTHandle " + name + " contains both graphicsFormat and depthStencilFormat which is not allowed."); - var format = GetFormat( descriptor.graphicsFormat, descriptor.depthStencilFormat); - - return s_DefaultInstance.Alloc( - scaleFunc, - format, - descriptor.volumeDepth, - filterMode, - wrapMode, - descriptor.dimension, - descriptor.enableRandomWrite, - descriptor.useMipMap, - descriptor.autoGenerateMips, - isShadowMap, - anisoLevel, - mipMapBias, - (MSAASamples)descriptor.msaaSamples, - descriptor.bindMS, - descriptor.useDynamicScale, - descriptor.useDynamicScaleExplicit, - descriptor.memoryless, - descriptor.vrUsage, - name - ); + return s_DefaultInstance.Alloc(scaleFunc, + GetRTHandleAllocInfo(descriptor, filterMode, wrapMode, anisoLevel, mipMapBias, name)); } /// 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 a7464021326..27d7fa2be8d 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blitter.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blitter.cs @@ -249,7 +249,6 @@ static internal void DrawTriangle(RasterCommandBuffer cmd, Material material, in static internal void DrawTriangle(CommandBuffer cmd, Material material, int shaderPass) { DrawTriangle(cmd, material, shaderPass, s_PropertyBlock); - s_PropertyBlock.Clear(); } static internal void DrawTriangle(CommandBuffer cmd, Material material, int shaderPass, MaterialPropertyBlock propertyBlock) @@ -273,7 +272,6 @@ static internal void DrawQuad(RasterCommandBuffer cmd, Material material, int sh static internal void DrawQuad(CommandBuffer cmd, Material material, int shaderPass) { DrawQuad(cmd, material, shaderPass, s_PropertyBlock); - s_PropertyBlock.Clear(); } static internal void DrawQuad(CommandBuffer cmd, Material material, int shaderPass, MaterialPropertyBlock propertyBlock) 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 141a63c62b1..c949dcb100d 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Utilities/CoreUtils.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Utilities/CoreUtils.cs @@ -772,6 +772,37 @@ public static void SetRenderTarget(CommandBuffer cmd, RTHandle colorBuffer, Rend SetViewportAndClear(cmd, colorBuffer, clearFlag, clearColor); } + /// + /// Set the current shading rate fragment size + /// + /// CommandBuffer used for rendering commands. + /// Shading rate fragment size to set + public static void SetShadingRateFragmentSize(CommandBuffer cmd, ShadingRateFragmentSize baseShadingRateFragmentSize) + { + cmd.SetShadingRateFragmentSize(baseShadingRateFragmentSize); + } + + /// + /// Set the current shading rate combiner + /// + /// CommandBuffer used for rendering commands. + /// Combiner stage to set + /// Combiner to set + public static void SetShadingRateCombiner(CommandBuffer cmd, ShadingRateCombinerStage stage, ShadingRateCombiner combiner) + { + cmd.SetShadingRateCombiner(stage, combiner); + } + + /// + /// Set the current shading rate image + /// + /// CommandBuffer used for rendering commands. + /// Shading rate image render target identifier to set + public static void SetShadingRateImage(CommandBuffer cmd, in RenderTargetIdentifier shadingRateImage) + { + cmd.SetShadingRateImage(shadingRateImage); + } + /// /// Set the current multiple render texture. /// diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_Lighting/Assets/EditModeTestAssets/Lighting_ReflectionProbeBaking/settings.meta b/Packages/com.unity.render-pipelines.core/Runtime/Vrs.meta similarity index 77% rename from Tests/SRPTests/Projects/UniversalGraphicsTest_Lighting/Assets/EditModeTestAssets/Lighting_ReflectionProbeBaking/settings.meta rename to Packages/com.unity.render-pipelines.core/Runtime/Vrs.meta index 99a6674b288..3bef098266f 100644 --- a/Tests/SRPTests/Projects/UniversalGraphicsTest_Lighting/Assets/EditModeTestAssets/Lighting_ReflectionProbeBaking/settings.meta +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: c50e63497ab07be44a980db33267bf58 +guid: cc1099d95a4ee3849a01da5826056b1f folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/.buginfo b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/.buginfo new file mode 100644 index 00000000000..fbd5f8466e1 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/.buginfo @@ -0,0 +1 @@ +area: Post-processing and UI Features diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_Lighting/Assets/Test/Editor/LightBaker.meta b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders.meta similarity index 77% rename from Tests/SRPTests/Projects/UniversalGraphicsTest_Lighting/Assets/Test/Editor/LightBaker.meta rename to Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders.meta index 0088da70797..eca032eb0e1 100644 --- a/Tests/SRPTests/Projects/UniversalGraphicsTest_Lighting/Assets/Test/Editor/LightBaker.meta +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 7d4af2980ccb34c42ad025adf329cbbb +guid: 77658d0b0e15bb342a01e17ef1b2172a folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsImage.hlsl b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsImage.hlsl new file mode 100644 index 00000000000..e89a0c2e0d1 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsImage.hlsl @@ -0,0 +1,21 @@ +#ifndef VRS_IMAGE_INCLUDED +#define VRS_IMAGE_INCLUDED + +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" + +RW_TEXTURE2D(uint, _ShadingRateImage); + +uniform float4 _VrsScaleBias; + +void ImageStore(uint shadingRateNativeValue, uint2 gid) +{ +#if !defined(APPLY_Y_FLIP) + // compute shader introduce a natural y-flip + // hence the reverse test + gid.y = _VrsScaleBias.w - 1 - gid.y; +#endif + + _ShadingRateImage[gid] = shadingRateNativeValue; +} + +#endif // VRS_IMAGE_INCLUDED diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsImage.hlsl.meta b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsImage.hlsl.meta new file mode 100644 index 00000000000..e3d8c0e5afc --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsImage.hlsl.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3cc7957ff84646bbbb849b88919e2109 +timeCreated: 1710958387 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsMainTex.hlsl b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsMainTex.hlsl new file mode 100644 index 00000000000..545ccebbb52 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsMainTex.hlsl @@ -0,0 +1,23 @@ +#ifndef VRS_MAINTEX_INCLUDED +#define VRS_MAINTEX_INCLUDED + +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureXR.hlsl" +#include "Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsShadingRates.hlsl" +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/GlobalSamplers.hlsl" + +TEXTURE2D_X(_VrsMainTex); + +StructuredBuffer _VrsMainTexLut; + +float4 LoadVrsMainTex(uint2 tid) +{ + return LOAD_TEXTURE2D_X(_VrsMainTex, tid); +} + +float4 SampleVrsMainTexFromCoords(float2 coords) +{ + return SAMPLE_TEXTURE2D_X_LOD(_VrsMainTex, sampler_PointClamp, coords, 0); +} + +#endif // VRS_MAINTEX_INCLUDED diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsMainTex.hlsl.meta b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsMainTex.hlsl.meta new file mode 100644 index 00000000000..2cda9558f7f --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsMainTex.hlsl.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 08b9525dab8d497cb640174e593275d1 +timeCreated: 1710958899 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsShadingRates.hlsl b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsShadingRates.hlsl new file mode 100644 index 00000000000..a4dade3e996 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsShadingRates.hlsl @@ -0,0 +1,45 @@ +#ifndef VRS_SHADING_RATES_INCLUDED +#define VRS_SHADING_RATES_INCLUDED + +// Must be kept in sync with ShadingRateFragmentSize +#define SHADING_RATE_FRAGMENT_SIZE_1X1 0 // native value = 0b0000 -> 0 +#define SHADING_RATE_FRAGMENT_SIZE_1X2 1 // native value = 0b0001 -> 1 +#define SHADING_RATE_FRAGMENT_SIZE_2X1 2 // native value = 0b0100 -> 4 +#define SHADING_RATE_FRAGMENT_SIZE_2X2 3 // native value = 0b0101 -> 5 +#define SHADING_RATE_FRAGMENT_SIZE_1x4 4 // native value = 0b0010 -> 2 +#define SHADING_RATE_FRAGMENT_SIZE_4x1 5 // native value = 0b1000 -> 8 +#define SHADING_RATE_FRAGMENT_SIZE_2x4 6 // native value = 0b0110 -> 6 +#define SHADING_RATE_FRAGMENT_SIZE_4x2 7 // native value = 0b1001 -> 9 +#define SHADING_RATE_FRAGMENT_SIZE_4x4 8 // native value = 0b1010 -> 10 +#define SHADING_RATE_FRAGMENT_SIZE_COUNT 9 + +StructuredBuffer _ShadingRateNativeValues; + +/// +/// Unpack a shading rate native value into its horizontal and vertical components. +/// +/// Shading rate native value to unpack. +/// Unpacked value where x component is the horizontal shading rate and y is the vertical shading rate. +uint2 UnpackShadingRate(uint shadingRateNativeValue) +{ + return uint2((shadingRateNativeValue >> 2) & 0x03, shadingRateNativeValue & 0x03); +} + +/// +/// Pack an unpacked shading rates into its native value. +/// +/// Unpacked shading rate. +/// Shading rate native value. +uint PackShadingRate(uint2 unpackedShadingRate) +{ + // If using 4x4 rate, be careful to check for invalid rates + // if (shadingRate.x == 2 && shadingRate.y == 0) + // shadingRate.y = 1; + // + // if (shadingRate.x == 0 && shadingRate.y == 2) + // shadingRate.x = 1; + + return (unpackedShadingRate.x << 2) | unpackedShadingRate.y; +} + +#endif // VRS_SHADING_RATES_INCLUDED diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsShadingRates.hlsl.meta b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsShadingRates.hlsl.meta new file mode 100644 index 00000000000..303e9a6b16f --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsShadingRates.hlsl.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: dbb73cb4c1954036a32ce1ade17ac0fd +timeCreated: 1710965275 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsTexture.compute b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsTexture.compute new file mode 100644 index 00000000000..bcd6023263d --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsTexture.compute @@ -0,0 +1,69 @@ +// #pragma enable_d3d11_debug_symbols + +#pragma only_renderers d3d11 xboxone vulkan + +#pragma multi_compile VRS_TILE_SIZE_8 VRS_TILE_SIZE_16 VRS_TILE_SIZE_32 +#pragma multi_compile _ DISABLE_TEXTURE2D_X_ARRAY +#pragma multi_compile _ APPLY_Y_FLIP + +#pragma kernel TextureCopy +#pragma kernel TextureReduce + + +#include "Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsTileSize.hlsl" +#include "Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsImage.hlsl" +#include "Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsMainTex.hlsl" +#include "Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsShadingRates.hlsl" + + +uint GetShadingRateNativeValueFromColor(float3 color) +{ + for (uint i = 0; i < SHADING_RATE_FRAGMENT_SIZE_COUNT; ++i) + { + float3 delta = abs(color - _VrsMainTexLut[i].rgb); + if (all(delta < 0.01f)) + return _ShadingRateNativeValues[i]; + } + + return _ShadingRateNativeValues[SHADING_RATE_FRAGMENT_SIZE_1X1]; +} + +[numthreads(1, 1, 1)] +void TextureCopy(uint2 tid : SV_DispatchThreadID) +{ + float3 color = LoadVrsMainTex(tid).rgb; + uint shadingRateNativeValue = GetShadingRateNativeValueFromColor(color); + ImageStore(shadingRateNativeValue, tid); +} + + +groupshared uint2 ldsShadingRate; + +[numthreads(VRS_TILE_SIZE, VRS_TILE_SIZE, 1)] +void TextureReduce(uint2 tid : SV_DispatchThreadID, uint2 gid: SV_GroupID, uint gidx: SV_GroupIndex) +{ + // initialize lds: only 1st thread of group does it + if (gidx == 0) + ldsShadingRate = UnpackShadingRate(_ShadingRateNativeValues[SHADING_RATE_FRAGMENT_SIZE_4x4]); + + // read: 1 thread == 1 pixel in main tex, each thread in group must read + float3 color = SampleVrsMainTexFromCoords(tid * _VrsScaleBias.xy).rgb; + uint shadingRateNativeValue = GetShadingRateNativeValueFromColor(color); + uint2 shadingRate = UnpackShadingRate(shadingRateNativeValue); + + GroupMemoryBarrierWithGroupSync(); + + // parallel reduce: 1 group == 1 pixel in vrs image + // conservative reduce: pick highest rate (hence min) + InterlockedMin(ldsShadingRate.x, shadingRate.x); + InterlockedMin(ldsShadingRate.y, shadingRate.y); + + GroupMemoryBarrierWithGroupSync(); + + // store result: only 1st thread of group does it + if (gidx == 0) + { + shadingRateNativeValue = PackShadingRate(ldsShadingRate); + ImageStore(shadingRateNativeValue, gid); + } +} diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsTexture.compute.meta b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsTexture.compute.meta new file mode 100644 index 00000000000..5fbb7b28e01 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsTexture.compute.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cacb30de6c40c7444bbc78cb0a81fd2a +ComputeShaderImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsTileSize.hlsl b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsTileSize.hlsl new file mode 100644 index 00000000000..2838b032183 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsTileSize.hlsl @@ -0,0 +1,14 @@ +#ifndef VRS_TILE_SIZE_INCLUDED +#define VRS_TILE_SIZE_INCLUDED + +#if defined(VRS_TILE_SIZE_8) + #define VRS_TILE_SIZE 8 +#elif defined(VRS_TILE_SIZE_16) + #define VRS_TILE_SIZE 16 +#elif defined(VRS_TILE_SIZE_32) + #define VRS_TILE_SIZE 32 +#else + #error Unsupported tile size +#endif + +#endif // VRS_TILE_SIZE_INCLUDED diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsTileSize.hlsl.meta b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsTileSize.hlsl.meta new file mode 100644 index 00000000000..457e40f1147 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsTileSize.hlsl.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 234c0613ab6043a7852e6ab1a268352a +timeCreated: 1710957835 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsVisualization.shader b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsVisualization.shader new file mode 100644 index 00000000000..d8dccd83e6d --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsVisualization.shader @@ -0,0 +1,44 @@ +Shader "Hidden/Core/VrsVisualization" +{ + SubShader + { + Pass + { + Name "VrsVisualization" + ZTest Always + ZWrite Off + Cull Off + + HLSLPROGRAM + //#pragma enable_d3d11_debug_symbols + + #pragma only_renderers d3d11 xboxone vulkan + + #pragma vertex Vert + #pragma fragment Fragment + + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureXR.hlsl" + #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/Runtime/Utilities/Blit.hlsl" + + TYPED_TEXTURE2D(uint, _ShadingRateImage); + StructuredBuffer _VisualizationLut; + + uniform float4 _VisualizationParams; + + #define PixelToTileScale _VisualizationParams.xy + + float4 Fragment(Varyings input) : SV_Target + { + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); + + uint2 pixel = (uint2)(input.positionCS.xy * PixelToTileScale); + uint shadingRate = LOAD_TEXTURE2D_LOD(_ShadingRateImage, pixel, 0); + + return _VisualizationLut[shadingRate]; + } + ENDHLSL + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsVisualization.shader.meta b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsVisualization.shader.meta new file mode 100644 index 00000000000..0f80dc6f42e --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsVisualization.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 620b55b8040a88d468e94abe55bed5ba +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Vrs.cs b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Vrs.cs new file mode 100644 index 00000000000..ea445398bbf --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Vrs.cs @@ -0,0 +1,259 @@ +using System; +using UnityEngine.Rendering.RenderGraphModule; + +namespace UnityEngine.Rendering +{ + /// + /// Encapsulates variable shading rate support (VRS) and texture conversion to shading rate image + /// + public static class Vrs + { + class ConversionPassData + { + public TextureHandle sriTextureHandle; + public TextureHandle mainTexHandle; + public TextureDimension mainTexDimension; + public BufferHandle mainTexLutHandle; + public BufferHandle validatedShadingRateFragmentSizeHandle; + public ComputeShader computeShader; + public int kernelIndex; + public Vector4 scaleBias; + public Vector2Int dispatchSize; + public bool yFlip; + } + + class VisualizationPassData + { + public Material material; + public TextureHandle source; + public BufferHandle lut; + public TextureHandle dummy; + public Vector4 visualizationParams; + } + + internal static readonly int shadingRateFragmentSizeCount = Enum.GetNames(typeof(ShadingRateFragmentSize)).Length; + + /// + /// Checks if shading rate is supported. + /// Convenience to abstract tier checks. + /// + /// True if shading rate is supported, false otherwise. + public static bool IsSupported() + { + return (ShadingRateInfo.supportsPerDrawCall || ShadingRateInfo.supportsPerImageTile); + } + + /// + /// Checks if shading rate images are supported. + /// Convenience to abstract tier checks + /// + /// True if shading rate images are supported, false otherwise. + public static bool IsShadingRateImageSupported() + { + return ShadingRateInfo.supportsPerImageTile; + } + + /// + /// Check if conversion of color texture to shading rate image is supported. + /// Convenience to abstract all capabilities checks. + /// + /// Returns true if conversion of color texture to shading rate image is supported, false otherwise. + public static bool IsColorMaskTextureConversionSupported() + { + return SystemInfo.supportsComputeShaders && + IsShadingRateImageSupported() && + s_VrsResources?.textureComputeShader != null; + } + + static VrsResources s_VrsResources; + + /// + /// Preprocess resources found in VrsRenderPipelineRuntimeResources for use at runtime. + /// + public static void InitializeResources() + { + if (IsSupported()) + { + var pipelineRuntimeResources = GraphicsSettings.GetRenderPipelineSettings(); + s_VrsResources = new VrsResources(pipelineRuntimeResources); + } + } + + /// + /// Cleanup resources. + /// + public static void DisposeResources() + { + s_VrsResources?.Dispose(); + s_VrsResources = null; + } + + /// + /// Converts a color mask texture to a shading rate image. + /// + /// Render graph to record conversion commands + /// Shading rate images to convert to. + /// Texture to convert from. + /// True if shading rate image should be generated flipped. + /// Shading rate image texture handle created. + /// + /// sriRtHandle and colorMaskRtHandle are imported with renderGraph before doing the conversion. + /// + public static TextureHandle ColorMaskTextureToShadingRateImage(RenderGraph renderGraph, RTHandle sriRtHandle, RTHandle colorMaskRtHandle, bool yFlip) + { + if (renderGraph == null || sriRtHandle == null || colorMaskRtHandle == null) + { + Debug.LogError($"TextureToShadingRateImage: invalid argument."); + return TextureHandle.nullHandle; + } + + var sriTextureHandle = renderGraph.ImportShadingRateImageTexture(sriRtHandle); + var colorMaskHandle = renderGraph.ImportTexture(colorMaskRtHandle); + + return ColorMaskTextureToShadingRateImage(renderGraph, + sriTextureHandle, + colorMaskHandle, + ((Texture)colorMaskRtHandle).dimension, + yFlip); + } + + /// + /// Converts a color mask texture to a shading rate image. + /// + /// Render graph to record conversion commands + /// Shading rate images to convert to. + /// Texture to convert from. + /// Texture's dimension. + /// True if shading rate image should be generated flipped. + /// Shading rate image texture handle created. + /// + /// sriRtHandle and colorMaskHandle are expected to be imported by renderGraph prior to this call. + /// + public static TextureHandle ColorMaskTextureToShadingRateImage(RenderGraph renderGraph, TextureHandle sriTextureHandle, TextureHandle colorMaskHandle, TextureDimension colorMaskDimension, bool yFlip) + { + if (!IsColorMaskTextureConversionSupported()) + { + Debug.LogError($"TextureToShadingRateImage: conversion not supported."); + return TextureHandle.nullHandle; + } + + var sriDesc = sriTextureHandle.GetDescriptor(renderGraph); + if (sriDesc.dimension != TextureDimension.Tex2D) + { + Debug.LogError($"TextureToShadingRateImage: Vrs image not a texture 2D."); + return TextureHandle.nullHandle; + } + + if (colorMaskDimension != TextureDimension.Tex2D && colorMaskDimension != TextureDimension.Tex2DArray) + { + Debug.LogError($"TextureToShadingRateImage: Input texture dimension not supported."); + return TextureHandle.nullHandle; + } + + using (var builder = renderGraph.AddComputePass("TextureToShadingRateImage", out var outerPassData, s_VrsResources.conversionProfilingSampler)) + { + outerPassData.sriTextureHandle = sriTextureHandle; + outerPassData.mainTexHandle = colorMaskHandle; + outerPassData.mainTexDimension = colorMaskDimension; + outerPassData.mainTexLutHandle = renderGraph.ImportBuffer(s_VrsResources.conversionLutBuffer); + outerPassData.validatedShadingRateFragmentSizeHandle = renderGraph.ImportBuffer(s_VrsResources.validatedShadingRateFragmentSizeBuffer); + + outerPassData.computeShader = s_VrsResources.textureComputeShader; + outerPassData.kernelIndex = s_VrsResources.textureReduceKernel; + outerPassData.scaleBias = new Vector4() + { + x = 1.0f / (sriDesc.width * s_VrsResources.tileSize.x), + y = 1.0f / (sriDesc.height * s_VrsResources.tileSize.y), + z = sriDesc.width, + w = sriDesc.height, + }; + outerPassData.dispatchSize = new Vector2Int(sriDesc.width, sriDesc.height); + outerPassData.yFlip = yFlip; + + builder.UseTexture(outerPassData.sriTextureHandle, AccessFlags.Write); + builder.UseTexture(outerPassData.mainTexHandle); + builder.UseBuffer(outerPassData.mainTexLutHandle); + + builder.AllowGlobalStateModification(true); + + builder.SetRenderFunc((ConversionPassData innerPassData, ComputeGraphContext context) => + { + ConversionDispatch(context.cmd, innerPassData); + }); + + return outerPassData.sriTextureHandle; + } + } + + /// + /// Converts a shading rate image to a color texture for visualization. + /// + /// Render graph to record conversion commands + /// Texture to convert from. + /// Output of conversion. + public static void ShadingRateImageToColorMaskTexture(RenderGraph renderGraph, in TextureHandle sriTextureHandle, in TextureHandle colorMaskHandle) + { + using (var builder = renderGraph.AddRasterRenderPass("ShadingRateImageToTexture", out var outerPassData, s_VrsResources.visualizationProfilingSampler)) + { + outerPassData.material = s_VrsResources.visualizationMaterial; + + if (sriTextureHandle.IsValid()) + outerPassData.source = sriTextureHandle; + else + outerPassData.source = renderGraph.defaultResources.blackTexture; + + outerPassData.lut = renderGraph.ImportBuffer(s_VrsResources.visualizationLutBuffer); + outerPassData.dummy = renderGraph.defaultResources.blackTexture; + outerPassData.visualizationParams = new Vector4( + 1.0f / s_VrsResources.tileSize.x, + 1.0f / s_VrsResources.tileSize.y, + 0, + 0);; + + builder.UseTexture(outerPassData.source); + builder.UseBuffer(outerPassData.lut); + builder.UseTexture(outerPassData.dummy); + builder.SetRenderAttachment(colorMaskHandle, 0); + + builder.AllowPassCulling(false); + + builder.SetRenderFunc((VisualizationPassData innerPassData, RasterGraphContext context) => + { + // must setup blitter source via the material: it's a typed texture (uint) + innerPassData.material.SetTexture(VrsShaders.s_ShadingRateImage, innerPassData.source); + innerPassData.material.SetBuffer(VrsShaders.s_VisualizationLut, innerPassData.lut); + innerPassData.material.SetVector(VrsShaders.s_VisualizationParams, innerPassData.visualizationParams); + + Blitter.BlitTexture(context.cmd, + innerPassData.dummy, + new Vector4(1, 1, 0, 0), + innerPassData.material, + 0); + }); + } + } + + static void ConversionDispatch(ComputeCommandBuffer cmd, ConversionPassData conversionPassData) + { + var disableTexture2dXArray = new LocalKeyword(conversionPassData.computeShader, VrsShaders.k_DisableTexture2dXArray); + if (conversionPassData.mainTexDimension == TextureDimension.Tex2DArray) + cmd.DisableKeyword(conversionPassData.computeShader, disableTexture2dXArray); + else + cmd.EnableKeyword(conversionPassData.computeShader, disableTexture2dXArray); + + var yFlip = new LocalKeyword(conversionPassData.computeShader, VrsShaders.k_YFlip); + if (conversionPassData.yFlip) + cmd.EnableKeyword(conversionPassData.computeShader, yFlip); + else + cmd.DisableKeyword(conversionPassData.computeShader, yFlip); + + cmd.SetComputeTextureParam(conversionPassData.computeShader, conversionPassData.kernelIndex, VrsShaders.s_MainTex, conversionPassData.mainTexHandle); + cmd.SetComputeBufferParam(conversionPassData.computeShader, conversionPassData.kernelIndex, VrsShaders.s_MainTexLut, conversionPassData.mainTexLutHandle); + cmd.SetComputeBufferParam(conversionPassData.computeShader, conversionPassData.kernelIndex, VrsShaders.s_ShadingRateNativeValues, conversionPassData.validatedShadingRateFragmentSizeHandle); + cmd.SetComputeTextureParam(conversionPassData.computeShader, conversionPassData.kernelIndex, VrsShaders.s_ShadingRateImage, conversionPassData.sriTextureHandle); + cmd.SetComputeVectorParam(conversionPassData.computeShader, VrsShaders.s_ScaleBias, conversionPassData.scaleBias); + + cmd.DispatchCompute(conversionPassData.computeShader, conversionPassData.kernelIndex, conversionPassData.dispatchSize.x, conversionPassData.dispatchSize.x, 1); + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Vrs.cs.meta b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Vrs.cs.meta new file mode 100644 index 00000000000..828f6274104 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/Vrs.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a5153735ff79d6149a038ac6417b9301 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsLut.cs b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsLut.cs new file mode 100644 index 00000000000..7f53faf674e --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsLut.cs @@ -0,0 +1,124 @@ +using System; +using System.Runtime.InteropServices; + +namespace UnityEngine.Rendering +{ + /// + /// Variable rate shading lookup table. Use to convert shading rate fragment size and color back and forth. + /// + [Serializable] + public class VrsLut + { + /// + /// Get a new instance of default VrsLut + /// + /// New instance of default VrsLut + public static VrsLut CreateDefault() + { + return new VrsLut() + { + [ShadingRateFragmentSize.FragmentSize1x1] = Color.red, + [ShadingRateFragmentSize.FragmentSize1x2] = Color.yellow, + [ShadingRateFragmentSize.FragmentSize2x1] = Color.white, + [ShadingRateFragmentSize.FragmentSize2x2] = Color.green, + [ShadingRateFragmentSize.FragmentSize1x4] = new Color(0.75f, 0.75f, 0.00f, 1), + [ShadingRateFragmentSize.FragmentSize4x1] = new Color(0.00f, 0.75f, 0.55f, 1), + [ShadingRateFragmentSize.FragmentSize2x4] = new Color(0.50f, 0.00f, 0.50f, 1), + [ShadingRateFragmentSize.FragmentSize4x2] = Color.grey, + [ShadingRateFragmentSize.FragmentSize4x4] = Color.blue, + }; + } + + [SerializeField] + Color[] m_Data = new Color[Vrs.shadingRateFragmentSizeCount]; + + /// + /// Indexing data with ShadingRateFragmentSize enum. + /// + /// Shading rate fragment size to set/get + public Color this[ShadingRateFragmentSize fragmentSize] + { + get => m_Data[(int)fragmentSize]; + set => m_Data[(int)fragmentSize] = value; + } + + /// + /// Create a compute buffer from the lookup table. + /// + /// If true, the buffer will be created with the visualization shader in mind + /// Graphics buffer representing this lookup table + public GraphicsBuffer CreateBuffer(bool forVisualization = false) + { + GraphicsBuffer buffer; + Color[] bufferData; + + if (forVisualization) + { + // lookup table will be used to map shading rate native values to colors + var fragmentSizes = Enum.GetValues(typeof(ShadingRateFragmentSize)); + // Get the encoded binary value associated of the max shading rate supported by our LUT. + // The encoded value will not be sequential. For example, 4x4 is encoded as 0b1010 = 10. + // We do this manually as ShadingRateInfo.QueryNativeValue will return 0 for rates that are + // not supported, which can lead to overflow on devices that support only up to 2x2. + var maxNativeValue = MapFragmentShadingRateToBinary(ShadingRateFragmentSize.FragmentSize4x4); + + bufferData = new Color[maxNativeValue + 1]; + + for (int i = fragmentSizes.Length - 1; i >= 0; --i) + { + var fragmentSize = (ShadingRateFragmentSize)fragmentSizes.GetValue(i); + var nativeValue = ShadingRateInfo.QueryNativeValue(fragmentSize); + bufferData[nativeValue] = m_Data[(int) fragmentSize].linear; + } + } + else + { + // lookup table will be used to map colors to shading rate index + bufferData = new Color[m_Data.Length]; + for (int i = 0; i < m_Data.Length; ++i) + { + bufferData[i] = m_Data[i].linear; + } + } + + buffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, bufferData.Length, Marshal.SizeOf(typeof(Color))); + buffer.SetData(bufferData); + + return buffer; + } + + private const uint Rate1x = 0; + private const uint Rate2x = 1; + private const uint Rate4x = 2; + private uint MapFragmentShadingRateToBinary(ShadingRateFragmentSize fs) + { + switch (fs) + { + default: + case ShadingRateFragmentSize.FragmentSize1x1: + return EncodeShadingRate(Rate1x, Rate1x); + case ShadingRateFragmentSize.FragmentSize1x2: + return EncodeShadingRate(Rate1x, Rate2x); + case ShadingRateFragmentSize.FragmentSize2x1: + return EncodeShadingRate(Rate2x, Rate1x); + case ShadingRateFragmentSize.FragmentSize2x2: + return EncodeShadingRate(Rate2x, Rate2x); + case ShadingRateFragmentSize.FragmentSize1x4: + return EncodeShadingRate(Rate1x, Rate4x); + case ShadingRateFragmentSize.FragmentSize4x1: + return EncodeShadingRate(Rate4x, Rate1x); + case ShadingRateFragmentSize.FragmentSize2x4: + return EncodeShadingRate(Rate2x, Rate4x); + case ShadingRateFragmentSize.FragmentSize4x2: + return EncodeShadingRate(Rate4x, Rate2x); + case ShadingRateFragmentSize.FragmentSize4x4: + return EncodeShadingRate(Rate4x, Rate4x); + } + } + + private uint EncodeShadingRate(uint x, uint y) + { + return ((x << 2) | (y)); + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsLut.cs.meta b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsLut.cs.meta new file mode 100644 index 00000000000..0842d30f959 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsLut.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 022af1b7cce79be46aec3272d72bf1f8 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsRenderPipelineRuntimeResources.cs b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsRenderPipelineRuntimeResources.cs new file mode 100644 index 00000000000..95b724b6094 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsRenderPipelineRuntimeResources.cs @@ -0,0 +1,72 @@ +using System; + +namespace UnityEngine.Rendering +{ + /// + /// Class that stores the Variable Rate Shading common global resources + /// + [Serializable] + [SupportedOnRenderPipeline] + [Categorization.CategoryInfo(Name = "R: VRS - Runtime Resources", Order = 1000), HideInInspector] + public sealed class VrsRenderPipelineRuntimeResources : IRenderPipelineResources + { + /// + /// Version of the Vrs Resources + /// + public int version => 0; + + bool IRenderPipelineGraphicsSettings.isAvailableInPlayerBuild => true; + + [SerializeField] + [ResourcePath("Runtime/Vrs/Shaders/VrsTexture.compute")] + ComputeShader m_TextureComputeShader; + + /// + /// General Vrs compute shader. + /// + public ComputeShader textureComputeShader + { + get => m_TextureComputeShader; + set => this.SetValueAndNotify(ref m_TextureComputeShader, value, nameof(m_TextureComputeShader)); + } + + [SerializeField] + [ResourcePath("Runtime/Vrs/Shaders/VrsVisualization.shader")] + Shader m_VisualizationShader; + + /// + /// Show resource shader. + /// + public Shader visualizationShader + { + get => m_VisualizationShader; + set => this.SetValueAndNotify(ref m_VisualizationShader, value, nameof(m_VisualizationShader)); + } + + [SerializeField] + [Tooltip("Colors to visualize the shading rates")] + VrsLut m_VisualizationLookupTable = VrsLut.CreateDefault(); + + /// + /// Shading rate visualization lookup table. + /// + public VrsLut visualizationLookupTable + { + get => m_VisualizationLookupTable; + set => this.SetValueAndNotify(ref m_VisualizationLookupTable, value, nameof(m_VisualizationLookupTable)); + } + + [SerializeField] + [Tooltip("Colors to convert between shading rates and textures")] + VrsLut m_ConversionLookupTable = VrsLut.CreateDefault(); + + /// + /// texture to/from Shading rate conversion lookup table. + /// + public VrsLut conversionLookupTable + { + get => m_ConversionLookupTable; + set => this.SetValueAndNotify(ref m_ConversionLookupTable, value, nameof(m_ConversionLookupTable)); + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsRenderPipelineRuntimeResources.cs.meta b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsRenderPipelineRuntimeResources.cs.meta new file mode 100644 index 00000000000..8c90930ccb5 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsRenderPipelineRuntimeResources.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c75bfa9127302bc4cbc67983804a44ac \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsResources.cs b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsResources.cs new file mode 100644 index 00000000000..2652f87755a --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsResources.cs @@ -0,0 +1,145 @@ +using System; + +namespace UnityEngine.Rendering +{ + class VrsResources : IDisposable + { + internal ProfilingSampler conversionProfilingSampler = new ProfilingSampler("VrsConversion"); + internal ProfilingSampler visualizationProfilingSampler = new ProfilingSampler("VrsVisualization"); + internal GraphicsBuffer conversionLutBuffer; + internal GraphicsBuffer visualizationLutBuffer; + + internal ComputeShader textureComputeShader; + internal int textureReduceKernel = -1; + internal int textureCopyKernel = -1; + + internal Vector2Int tileSize; + + internal GraphicsBuffer validatedShadingRateFragmentSizeBuffer; + + Shader m_VisualizationShader; + Material m_VisualizationMaterial; + internal Material visualizationMaterial + { + get + { + // explicit check here: handle case where m_Material is set to null when editor reloads + if (m_VisualizationMaterial == null) + m_VisualizationMaterial = new Material(m_VisualizationShader); + + return m_VisualizationMaterial; + } + } + + internal VrsResources(VrsRenderPipelineRuntimeResources resources) + { + InitializeResources(resources); + +#if UNITY_EDITOR + GraphicsSettings.Unsubscribe(OnVrsResourcesChanged); + GraphicsSettings.Subscribe(OnVrsResourcesChanged); +#endif + } + +#if UNITY_EDITOR + void OnVrsResourcesChanged(VrsRenderPipelineRuntimeResources resources, string propertyName) + { + DisposeResources(); + InitializeResources(resources); + } +#endif + + ~VrsResources() + { + Dispose(); + GC.SuppressFinalize(this); + } + + public void Dispose() + { +#if UNITY_EDITOR + GraphicsSettings.Unsubscribe(OnVrsResourcesChanged); +#endif + DisposeResources(); + } + + void InitializeResources(VrsRenderPipelineRuntimeResources resources) + { + m_VisualizationShader = resources.visualizationShader; + conversionLutBuffer = resources.conversionLookupTable.CreateBuffer(); + visualizationLutBuffer = resources.visualizationLookupTable.CreateBuffer(true); + InitComputeShader(resources); + AllocFragmentSizeBuffer(); + } + + void DisposeResources() + { + conversionLutBuffer?.Dispose(); + conversionLutBuffer = null; + + visualizationLutBuffer?.Dispose(); + visualizationLutBuffer = null; + + validatedShadingRateFragmentSizeBuffer?.Dispose(); + validatedShadingRateFragmentSizeBuffer = null; + + m_VisualizationShader = null; + m_VisualizationMaterial = null; + } + + void AllocFragmentSizeBuffer() + { + // Get available shading rate fragment sizes; unsupported ones + // will be mapped to the closest supported one. + var fragmentSize = new uint[Vrs.shadingRateFragmentSizeCount]; + + var lastAvailableFragmentSize = ShadingRateFragmentSize.FragmentSize1x1; + uint fragmentSizeNativeValue = ShadingRateInfo.QueryNativeValue(lastAvailableFragmentSize); + + foreach (var availableFragmentSize in ShadingRateInfo.availableFragmentSizes) + { + Array.Fill(fragmentSize, + fragmentSizeNativeValue, + (int)lastAvailableFragmentSize, + availableFragmentSize - lastAvailableFragmentSize + 1); + + lastAvailableFragmentSize = availableFragmentSize; + fragmentSizeNativeValue = ShadingRateInfo.QueryNativeValue(lastAvailableFragmentSize); + } + + Array.Fill(fragmentSize, + fragmentSizeNativeValue, + (int)lastAvailableFragmentSize, + ShadingRateFragmentSize.FragmentSize4x4 - lastAvailableFragmentSize + 1); + + validatedShadingRateFragmentSizeBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, fragmentSize.Length, sizeof(uint)); + validatedShadingRateFragmentSizeBuffer.SetData(fragmentSize); + } + + void InitComputeShader(VrsRenderPipelineRuntimeResources resources) + { + // This Compute Shader resource is used for converting an RGB texture to an R8 SRI + // Don't initialize it if the device does not support image-based VRS + if (!ShadingRateInfo.supportsPerImageTile) + { + return; + } + + tileSize = ShadingRateInfo.imageTileSize; + var tileSizeOk = tileSize.x == tileSize.y && (tileSize.x == 8 || tileSize.x == 16 || tileSize.x == 32); + if (!tileSizeOk) + { + Debug.LogError($"VRS unsupported tile size: {tileSize.x}x{tileSize.y}."); + return; + } + + textureComputeShader = resources.textureComputeShader; + + // this keyword need only be set once + textureComputeShader.EnableKeyword($"{VrsShaders.k_TileSizePrefix}{tileSize.x}"); + + textureReduceKernel = textureComputeShader.FindKernel(VrsShaders.k_KernelTextureReduce); + textureCopyKernel = textureComputeShader.FindKernel(VrsShaders.k_KernelTextureCopy); + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsResources.cs.meta b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsResources.cs.meta new file mode 100644 index 00000000000..86967c09c94 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsResources.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 785d30f91e90dd2448cb87e5f026e49a \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsShaders.cs b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsShaders.cs new file mode 100644 index 00000000000..ae683d60c25 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsShaders.cs @@ -0,0 +1,24 @@ +namespace UnityEngine.Rendering +{ + static class VrsShaders + { + internal const string k_TileSizePrefix = "VRS_TILE_SIZE_"; + + internal const string k_DisableTexture2dXArray = "DISABLE_TEXTURE2D_X_ARRAY"; + internal const string k_YFlip = "APPLY_Y_FLIP"; + + internal static readonly int s_ScaleBias = Shader.PropertyToID("_VrsScaleBias"); + + internal static readonly int s_MainTex = Shader.PropertyToID("_VrsMainTex"); + internal static readonly int s_MainTexLut = Shader.PropertyToID("_VrsMainTexLut"); + + internal static readonly int s_ShadingRateNativeValues = Shader.PropertyToID("_ShadingRateNativeValues"); + internal static readonly int s_ShadingRateImage = Shader.PropertyToID("_ShadingRateImage"); + + internal const string k_KernelTextureCopy = "TextureCopy"; + internal const string k_KernelTextureReduce = "TextureReduce"; + + internal static readonly int s_VisualizationLut = Shader.PropertyToID("_VisualizationLut"); + internal static readonly int s_VisualizationParams = Shader.PropertyToID("_VisualizationParams"); + } +} diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsShaders.cs.meta b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsShaders.cs.meta new file mode 100644 index 00000000000..21b075a571f --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/Vrs/VrsShaders.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4ba9dce31226373439673a105ffbaef2 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/XR/XRSystem.cs b/Packages/com.unity.render-pipelines.core/Runtime/XR/XRSystem.cs index 6be5c7b846d..91ad9d7744a 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/XR/XRSystem.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/XR/XRSystem.cs @@ -436,6 +436,9 @@ static bool CanUseSinglePass(Camera camera, XRDisplaySubsystem.XRRenderPass rend if (renderParam0.textureArraySlice != 0 || renderParam1.textureArraySlice != 1) return false; + if (renderParam0.viewport != renderParam1.viewport) + return false; + return true; } diff --git a/Packages/com.unity.render-pipelines.core/ShaderLibrary/API/GLES3.hlsl b/Packages/com.unity.render-pipelines.core/ShaderLibrary/API/GLES3.hlsl index b5e9d13e745..9dacf8d91c3 100644 --- a/Packages/com.unity.render-pipelines.core/ShaderLibrary/API/GLES3.hlsl +++ b/Packages/com.unity.render-pipelines.core/ShaderLibrary/API/GLES3.hlsl @@ -38,6 +38,15 @@ #define GLES3_1_AEP 0 #endif +// GLES3 causes a performance regression in some devices when using CBUFFER. +// WebGL needs to put LightShadow uniforms into a uniform buffer, +// despite being a GLES3 API. Some mobile devices, such as Adreno GPUs, +// have a small GL_MAX_FRAGMENT_UNIFORM_VECTORS limit, causing Lit shaders +// to fail on those devices. https://jira.unity3d.com/browse/UUM-87232 +#if !defined(UNITY_PLATFORM_WEBGL) +#define LIGHT_SHADOWS_NO_CBUFFER +#endif + // Initialize arbitrary structure with zero values. // Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0 #define ZERO_INITIALIZE(type, name) name = (type)0; diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/NativePassCompilerRenderGraphTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/NativePassCompilerRenderGraphTests.cs index 6664980c909..3ad5f36cfb1 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Editor/NativePassCompilerRenderGraphTests.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/NativePassCompilerRenderGraphTests.cs @@ -785,6 +785,126 @@ public void FencesWork() Assert.False(passData[3].insertGraphicsFence); } + [Test] + public void MaxReadersAndMaxVersionsAreCorrectForBuffers() + { + var g = AllocateRenderGraph(); + var rendertargets = ImportAndCreateBuffers(g); + + var desc = new BufferDesc(1024, 16); + var buffer = g.CreateBuffer(desc); + var buffer2 = g.CreateBuffer(desc); + + // Render something to extra 0 and write uav + using (var builder = g.AddRasterRenderPass("TestPass0", out var passData)) + { + builder.UseBufferRandomAccess(buffer, 0, AccessFlags.Write); + builder.UseBufferRandomAccess(buffer2, 1, AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + } + + // Render extra bits to 0 reading from the uav + using (var builder = g.AddRasterRenderPass("TestPass1", out var passData)) + { + builder.UseBuffer(buffer, AccessFlags.Read); + builder.UseBufferRandomAccess(buffer2, 1, AccessFlags.ReadWrite); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + } + + var result = g.CompileNativeRenderGraph(g.ComputeGraphHash()); + + // The resource with the biggest MaxReaders is buffer2: + // 1 implicit read (TestPass0) + 1 explicit read (TestPass1) + 1 for the offset. + Assert.AreEqual(result.contextData.resources.MaxReaders, 3); + + // The resource with the biggest MaxVersion is buffer2: + // 1 explicit write (TestPass0) + 1 explicit readwrite (TestPass1) + 1 for the offset + Assert.AreEqual(result.contextData.resources.MaxVersions, 3); + } + + [Test] + public void MaxReadersAndMaxVersionsAreCorrectForTextures() + { + var g = AllocateRenderGraph(); + var rendertargets = ImportAndCreateBuffers(g); + + // Render something to extra 0 and write uav + using (var builder = g.AddRasterRenderPass("TestPass0", out var passData)) + { + builder.SetRenderAttachmentDepth(rendertargets.depthBuffer, AccessFlags.Write); + builder.UseTexture(rendertargets.extraBuffers[0], AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + } + + // Render extra bits to 0 reading from the uav + using (var builder = g.AddRasterRenderPass("TestPass1", out var passData)) + { + builder.SetRenderAttachmentDepth(rendertargets.depthBuffer, AccessFlags.Read); + builder.UseTexture(rendertargets.extraBuffers[0], AccessFlags.ReadWrite); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + } + + // Render extra bits to 0 reading from the uav + using (var builder = g.AddRasterRenderPass("TestPass2", out var passData)) + { + builder.AllowPassCulling(false); + builder.UseTexture(rendertargets.extraBuffers[0], AccessFlags.Read); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + } + + var result = g.CompileNativeRenderGraph(g.ComputeGraphHash()); + + // Resources with the biggest MaxReaders are extraBuffers[0] and depthBuffer (both being equal): + // 1 implicit read (TestPass0) + 2 explicit read (TestPass1 & TestPass2) + 1 for the offset + Assert.AreEqual(result.contextData.resources.MaxReaders, 4); + + // The resource with the biggest MaxVersion is extraBuffers[0]: + // 1 explicit write (TestPass0) + 1 explicit read-write (TestPass1) + 1 for the offset + Assert.AreEqual(result.contextData.resources.MaxVersions, 3); + } + + [Test] + public void MaxReadersAndMaxVersionsAreCorrectForBuffersMultiplePasses() + { + var g = AllocateRenderGraph(); + var rendertargets = ImportAndCreateBuffers(g); + + var desc = new BufferDesc(1024, 16); + var buffer = g.CreateBuffer(desc); + var buffer2 = g.CreateBuffer(desc); + + int indexName = 0; + + for (int i = 0; i < 5; ++i) + { + // Render something to extra 0 and write uav + using (var builder = g.AddRasterRenderPass("TestPass" + indexName++, out var passData)) + { + builder.UseBufferRandomAccess(buffer, 0, AccessFlags.Write); + builder.UseBufferRandomAccess(buffer2, 1, AccessFlags.Write); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + } + + // Render extra bits to 0 reading from the uav + using (var builder = g.AddRasterRenderPass("TestPass" + indexName++, out var passData)) + { + builder.UseBuffer(buffer, AccessFlags.Read); + builder.UseBufferRandomAccess(buffer2, 1, AccessFlags.ReadWrite); + builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { }); + } + } + + var result = g.CompileNativeRenderGraph(g.ComputeGraphHash()); + + // The resource with the biggest MaxReaders is buffer2: + // 5 implicit read (TestPass0-2-4-6-8) + 5 explicit read (TestPass1-3-5-7-9) + 1 for the offset. + Assert.AreEqual(result.contextData.resources.MaxReaders, 11); + + // The resource with the biggest MaxVersion is buffer2: + // 5 explicit write (TestPass0-2-4-6-8) + 5 explicit readwrite (TestPass1-3-5-7-9) + 1 for the offset + Assert.AreEqual(result.contextData.resources.MaxVersions, 11); + } + [Test] public void BuffersWork() { diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/ShaderStripping/DummyPipelineShader.shader b/Packages/com.unity.render-pipelines.core/Tests/Editor/ShaderStripping/DummyPipelineShader.shader index 610d7e26803..de0c09abbce 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Editor/ShaderStripping/DummyPipelineShader.shader +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/ShaderStripping/DummyPipelineShader.shader @@ -1,4 +1,4 @@ -Shader "DummyPipeline/VariantStrippingTestsShader" +Shader "Hidden/DummyPipeline/VariantStrippingTestsShader" { Properties { diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/ShaderStripping/ShaderExtensionsTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/ShaderStripping/ShaderExtensionsTests.cs index 94232d91cbd..9a51708fd6f 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Editor/ShaderStripping/ShaderExtensionsTests.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/ShaderStripping/ShaderExtensionsTests.cs @@ -10,7 +10,7 @@ class ShaderExtensionsTests new TestCaseData(Shader.Find("Hidden/Internal-Colored")) .SetName("Given a shader from Built-in, the render pipeline tag is not found and is empty") .Returns((false,string.Empty)), - new TestCaseData(Shader.Find("DummyPipeline/VariantStrippingTestsShader")) + new TestCaseData(Shader.Find("Hidden/DummyPipeline/VariantStrippingTestsShader")) .SetName("Given a shader with a render pipeline tag, the pipeline is found") .Returns((true, "DummyPipeline")) }; diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/ShaderStripping/ShaderStrippingTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/ShaderStripping/ShaderStrippingTests.cs index 661061cefb3..9fe634e399c 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Editor/ShaderStripping/ShaderStrippingTests.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/ShaderStripping/ShaderStrippingTests.cs @@ -130,7 +130,7 @@ public void TearDown() new TestCaseData(typeof(StripHalf), Shader.Find("Hidden/Internal-Colored"), 6) .SetName("Given a stripper that reduces the variants to the half, just half of the variants are stripped") .Returns(3), - new TestCaseData(typeof(StripNothing), Shader.Find("DummyPipeline/VariantStrippingTestsShader"), 2) + new TestCaseData(typeof(StripNothing), Shader.Find("Hidden/DummyPipeline/VariantStrippingTestsShader"), 2) .SetName("Given a shader that is not from the current pipeline, all the variants are stripped") .Returns(0), }; diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/AOVs.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/AOVs.md index 249b938a182..03d17c75033 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/AOVs.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/AOVs.md @@ -8,7 +8,7 @@ Here is an example of three AOVs, containing from left to right the Albedo, Norm In HDRP, you can access and configure AOVs in the following ways: - Using the [HDRP Compositor tool](graphics-compositor.md). -- Using the [Unity Recorder](https://docs.unity3d.com/Packages/com.unity.recorder@latest/index.html) and the [AOV Recorder](https://docs.unity3d.com/Packages/com.unity.aovrecorder@latest/index.html) packages. +- Using the [Unity Recorder](https://docs.unity3d.com/Packages/com.unity.recorder@latest/index.html) package. - Using the scripting API to set up a custom AOV request in any HDRP Camera in your Scene. The first two options offer a limited selection of AOVs in their User Interface, while the third option allows for much more flexibility on what data an HDRP Camera can output. diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Default-Settings-Window.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Default-Settings-Window.md index e933c76c5d0..74248e7696a 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Default-Settings-Window.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Default-Settings-Window.md @@ -11,8 +11,7 @@ You can also add your own settings. Refer to [Add custom settings](https://docs. | **Property** | **Description** | | --------------------------| ------------------------------------------------------------ | | Shader Variant Log Level | Use the drop-down to select what information HDRP logs about Shader variants when you build your Unity Project. • Disabled: HDRP doesn’t log any Shader variant information.• Only SRP Shaders: Only log Shader variant information for HDRP Shaders.• All Shaders: Log Shader variant information for every Shader type. | -| Export Shader Variants | Controls whether to output shader variant information to a file. | - +| Export Shader Variants | Controls whether to output shader variant information to a file. Unity saves the information to the folder with your project files, in `Temp/graphics-settings-stripping.json` and `Temp/shader-stripping.json`. | ## Custom Post Process Orders @@ -20,9 +19,6 @@ Use this section to select which custom post processing effect HDRP uses in the HDRP provides one list for each post processing injection point. See the [Custom Post Process](Custom-Post-Process.md) documentation for more details. -![](Images/HDRPgs_Custom_PP.png) - - ## Frame Settings (Default Values) The [Frame Settings](Frame-Settings.md) control the rendering passes that Cameras perform at runtime. @@ -48,7 +44,7 @@ You can use the **Volume Profiles** section to assign and edit a [Volume Profile The **Default Volume Profile Asset** (A) references a Volume Profile in the HDRP package folder called `DefaultSettingsVolumeProfile` by default. Below it, you can add [Volume overrides](volume-component.md), and edit their properties. You can assign your own Volume Profile to this property field. Be aware that this property must always reference a Volume Profile. If you assign your own Volume Profile and then delete it, HDRP automatically re-assigns the `DefaultSettingsVolumeProfile` from the HDRP package folder. -The **LookDev Volume Profile Asset** (B) references the Volume Profile HDRP uses in the [LookDev window](test-and-debug-materials-in-different-lighting-conditions-look-dev.md). This Asset works in almost the same way as the Default Volume Profile Asset, except that it overrides [Visual Environment Components](visual-environment-volume-override-reference.md) and sky components.![](Images/HDRPgs_Volume_Profiles.png) +The **LookDev Volume Profile Asset** (B) references the Volume Profile HDRP uses in the [LookDev window](test-and-debug-materials-in-different-lighting-conditions-look-dev.md). This Asset works in almost the same way as the Default Volume Profile Asset, except that it overrides [Visual Environment Components](visual-environment-volume-override-reference.md) and sky components. ## Resources diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Dynamic-Resolution.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Dynamic-Resolution.md index 731e64df2b2..4c764a0f016 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Dynamic-Resolution.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Dynamic-Resolution.md @@ -19,11 +19,13 @@ HDRP always uses a software method to upscale the result. The method HDRP uses i To use dynamic resolution in your Project, you must enable dynamic resolution in your [HDRP Asset](HDRP-Asset.md) and then enable it for each [Camera](hdrp-camera-component-reference.md) you want to use it with. To do this: -1. In the Inspector for your HDRP Asset, go to **Rendering** **> Dynamic Resolution** and enable the **Enable** checkbox. For information on how to customize the rest of the HDRP Asset’s global dynamic resolution properties, see the dynamic resolution section of the [HDRP Asset documentation](HDRP-Asset.md#DynamicResolution). -2. For every [Camera](hdrp-camera-component-reference.md) you want to perform dynamic resolution, go to the **General** section and enable **Allow Dynamic Resolution**. -3. Add a HD Dynamic Resolution component. +1. In the Inspector for your HDRP Asset, go to **Rendering** > **Dynamic Resolution** and enable the **Enable** checkbox. For information on how to customize the rest of the HDRP Asset’s global dynamic resolution properties, see the dynamic resolution section of the [HDRP Asset documentation](HDRP-Asset.md#DynamicResolution). -For information about the HD Dynamic Resolution component properties refer to [HD Dynamic Resolution component properties](reference-dynamic-resolution.md). +2. For each [Camera](hdrp-camera-component-reference.md) you want to perform dynamic resolution, go to the **Rendering** section of the Camera's Inspector and enable the **Allow Dynamic Resolution** checkbox. + +3. Add a **HD Dynamic Resolution** component to any GameObject in your scene. Adding this component once in the scene is sufficient, as it globally manages dynamic resolution settings. + +For information about the HD Dynamic Resolution component properties, refer to [HD Dynamic Resolution component properties](reference-dynamic-resolution.md). ## Custom dynamic resolution @@ -149,3 +151,7 @@ The intensity of the sharpening filter used by FSR can be controlled using the * > [!NOTE] > This setting is not available in the editor if the **Override FSR Sharpness** checkbox is not checked. The checkbox itself is not available if the default upscaling filter is set to FSR. + +## Additional resources + +- [Introduction to changing resolution scale](https://docs.unity3d.com/6000.0/Documentation/Manual/resolution-scale-introduction.html) diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Frame-Settings.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Frame-Settings.md index c6580132ba0..7bd7e208da9 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Frame-Settings.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Frame-Settings.md @@ -2,7 +2,7 @@ Frame Settings are settings HDRP uses to render Cameras, real-time, baked, and custom reflections. To find the right balance between render quality and runtime performance, adjust the Frame Settings for your [Cameras](hdrp-camera-component-reference.md) to enable or disable effects at runtime on a per-Camera basis. -You can set the default values for Frame Settings for each of these three individually from within the the [HDRP Graphics settings window](Default-Settings-Window.md). +You can set the default values for Frame Settings for each of these three individually from within the [HDRP Graphics settings window](Default-Settings-Window.md). ![](Images/FrameSettings1.png) diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/fog-color-black.jpg b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/fog-color-black.jpg new file mode 100644 index 00000000000..aa43aa46974 Binary files /dev/null and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/fog-color-black.jpg differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/fog-color-sky-color.jpg b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/fog-color-sky-color.jpg new file mode 100644 index 00000000000..7927b47ae1a Binary files /dev/null and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/fog-color-sky-color.jpg differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot__directional_shadow_fallback_0.jpg b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot__directional_shadow_fallback_0.jpg new file mode 100644 index 00000000000..a58ac6c9d62 Binary files /dev/null and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot__directional_shadow_fallback_0.jpg differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot__directional_shadow_fallback_1.jpg b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot__directional_shadow_fallback_1.jpg new file mode 100644 index 00000000000..cfeee4477e0 Binary files /dev/null and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot__directional_shadow_fallback_1.jpg differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot_ambient-probe-dimmer-0.jpg b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot_ambient-probe-dimmer-0.jpg new file mode 100644 index 00000000000..c9a1e165f80 Binary files /dev/null and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot_ambient-probe-dimmer-0.jpg differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot_ambient-probe-dimmer-1.jpg b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot_ambient-probe-dimmer-1.jpg new file mode 100644 index 00000000000..1ecce9c3f9c Binary files /dev/null and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot_ambient-probe-dimmer-1.jpg differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot_apartment_indirect_specular_reflection_probe_off.jpg b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot_apartment_indirect_specular_reflection_probe_off.jpg new file mode 100644 index 00000000000..2dbf2e456a8 Binary files /dev/null and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot_apartment_indirect_specular_reflection_probe_off.jpg differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot_apartment_indirect_specular_reflection_probe_on.jpg b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot_apartment_indirect_specular_reflection_probe_on.jpg new file mode 100644 index 00000000000..457cf1ad0ad Binary files /dev/null and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot_apartment_indirect_specular_reflection_probe_on.jpg differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot_apartment_shadow_culling_off.jpg b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot_apartment_shadow_culling_off.jpg new file mode 100644 index 00000000000..754b09e7748 Binary files /dev/null and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot_apartment_shadow_culling_off.jpg differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot_apartment_shadow_culling_on.jpg b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot_apartment_shadow_culling_on.jpg new file mode 100644 index 00000000000..c822d26049e Binary files /dev/null and b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Images/ray_tracing_troubleshoot_apartment_shadow_culling_on.jpg differ diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Mask-Map-and-Detail-Map.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Mask-Map-and-Detail-Map.md index 5534281d2ea..87261c9b382 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Mask-Map-and-Detail-Map.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Mask-Map-and-Detail-Map.md @@ -19,6 +19,9 @@ The mask map contains four grayscale textures, one in each color channel. The de | **Blue** | Detail mask | | **Alpha** | Smoothness | + +**Note:** The detail mask texture allows you to control where the detail texture is applied on your model. This means you can decide which areas should display the detail texture and which should not. For instance, if your model has skin pores, you might mask the lips and eyebrows to prevent the pores from appearing in those areas. + To create a mask map, create a linear composited map in a photo editor, using the channels as described in the table above. The following example image demonstrates the individual components of a full mask map. diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Physical-Light-Units.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Physical-Light-Units.md index fc75271c170..015b5a03685 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Physical-Light-Units.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Physical-Light-Units.md @@ -30,7 +30,7 @@ The unit of [illuminance](Glossary.md#Illuminance). A light source that emits 1 #### Nits (candela per square meter): -The unit of luminance. Describes the surface power of a visible light source. When you use this unit, the overall power of a light source depends the size of the light source, meaning the the illumination level of a Scene changes depending on the size of the light source. Highlights that a light source produces conserve their intensity regardless of the size of the surface. +The unit of luminance. Describes the surface power of a visible light source. When you use this unit, the overall power of a light source depends the size of the light source, meaning the illumination level of a Scene changes depending on the size of the light source. Highlights that a light source produces conserve their intensity regardless of the size of the surface. A light source that emits 1 candela of [luminous intensity](Glossary.md#LuminousIntensity) onto an area of 1 square meter has a luminance of 1 candela per square meter. diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Planar-Reflection-Probe.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Planar-Reflection-Probe.md index 2e644aa0907..d5b8fef13c8 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/Planar-Reflection-Probe.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/Planar-Reflection-Probe.md @@ -4,7 +4,7 @@ The Planar Reflection Probe component is one of the types of [Reflection Probe]( ## Properties -Planar Reflection Probes share many properties with the the [built-in render pipeline Reflection Probe](https://docs.unity3d.com/Manual/class-ReflectionProbe.html), and the [HDRP cubemap Reflection Probe](Reflection-Probe.md). +Planar Reflection Probes share many properties with the [built-in render pipeline Reflection Probe](https://docs.unity3d.com/Manual/class-ReflectionProbe.html), and the [HDRP cubemap Reflection Probe](Reflection-Probe.md). Planar Reflection Probes use the same texture format than the one selected in [HDRP Asset](HDRP-Asset.md) for Color Buffer Format. diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/SRPBatcher-Materials.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/SRPBatcher-Materials.md index 8350d44af94..32896e226ee 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/SRPBatcher-Materials.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/SRPBatcher-Materials.md @@ -14,7 +14,7 @@ A GameObject must meet the following requirements to be compatible with the SRP ## Shader compatibility -All lit and unlit shaders in the the Universal Render Pipeline (URP) and the High Definition Render Pipeline (HDRP) fit this requirement (except for the particle versions of these shaders). +All lit and unlit shaders in the Universal Render Pipeline (URP) and the High Definition Render Pipeline (HDRP) fit this requirement (except for the particle versions of these shaders). For a custom shader to be compatible with the SRP Batcher it must meet the following requirements: @@ -23,4 +23,4 @@ For a custom shader to be compatible with the SRP Batcher it must meet the follo You can check the compatibility status of a shader in the Inspector panel. -![You can check the compatibility of your shaders in the Inspector panel for the specific shader.](Images/SRP_batcher_shader_compatibility.png) \ No newline at end of file +![You can check the compatibility of your shaders in the Inspector panel for the specific shader.](Images/SRP_batcher_shader_compatibility.png) 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 741fb15f49d..adfb0f48d9e 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/TableOfContents.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/TableOfContents.md @@ -1,4 +1,4 @@ -* [HDRP Packge](index.md) +* [HDRP Package](index.md) * [What's new](whats-new.md) * [What's new in HDRP 17](whats-new-17.md) * [What's new in HDRP 16](whats-new-16.md) @@ -83,9 +83,9 @@ * [Configure the size and density of Adaptive Probe Volumes](probevolumes-changedensity.md) * [Bake multiple scenes together with Baking Sets](probevolumes-usebakingsets.md) * [Changing lighting at runtime](change-lighting-at-runtime.md) - * [Choose how to change lighting at runtime](probevolumes-understand-changing-lighting-at-runtime.md) - * [Bake different lighting setups with Lighting Scenarios](probevolumes-bakedifferentlightingsetups.md) - * [Update light from the sky at runtime with sky occlusion](probevolumes-skyocclusion.md) + * [Choose how to change lighting at runtime](probevolumes-understand-changing-lighting-at-runtime.md) + * [Bake different lighting setups with Lighting Scenarios](probevolumes-bakedifferentlightingsetups.md) + * [Update light from the sky at runtime with sky occlusion](probevolumes-skyocclusion.md) * [Optimize loading Adaptive Probe Volume data](probevolumes-streaming.md) * [Fix issues with Adaptive Probe Volumes](probevolumes-fixissues.md) * [Adaptive Probe Volume Inspector window reference](probevolumes-inspector-reference.md) @@ -111,6 +111,7 @@ * [Path tracing limitations](path-tracing-limitations.md) * [Ray Tracing Settings](Ray-Tracing-Settings.md) * [Ray tracing hardware requirements](raytracing-requirements.md) + * [Troubleshoot ray tracing issues](raytracing-troubleshooting.md) * [Volumetric lighting](lighting-volumetric.md) * [Enable and configure volumtetric lights](Volumetric-Lighting.md) * [Screen space lens flare](shared/lens-flare/Override-Screen-Space-Lens-Flare.md) @@ -205,21 +206,26 @@ * [Water system simulation](water-water-system-simulation.md) * [Quality and performance decisions](water-quality-and-performance-decisions.md) * [Water Override for Volumes](water-the-water-system-volume-override.md) + * [Water surface fluctuations](water-decals-masking-landing.md) + * [Enable mask and water decals](enable-mask-and-water-decals.md) + * [Add swell, agitation, or ripples](add-swell-agitation-or-ripples.md) + * [Simulating currents with water decals](simulating-currents-with-water-decals.md) + * [Simulating foam or ripples with masks](simulating-foam-or-ripples-with-masks.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) - * [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) + * [Foam in the Water System](water-foam-in-the-water-system.md) + * [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) - * [Debug in the water system](water-debug-mode.md) - * [Environment limitations](Environment-Limitations.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) + * [Debug in the Water System](water-debug-mode.md) + * [Environment limitations](Environment-Limitations.md) * [Camera and scene composition](camera-and-scene-composition.md) * [Graphics Compositor](graphics-compositor.md) * [Understand the Graphics Compositor](understand-the-graphics-compositor.md) @@ -299,7 +305,7 @@ * [Understand custom pass variables](AOVs.md) * [Manage a custom pass without a GameObject](Global-Custom-Pass-API.md) * [Injection points](Custom-Pass-Injection-Points.md) - * [Customize the the High Definition Render Pipeline (HDRP)](render-graph.md) + * [Customize the High Definition Render Pipeline (HDRP)](render-graph.md) * [Test and debug rendering and post-processing](rendering-troubleshoot.md) * [Troubleshoot a custom pass](Custom-Pass-Troubleshooting.md) * [View a custom pass in the Frame Debugger](Custom-Pass-Frame-Debugger.md) diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/add-swell-agitation-or-ripples.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/add-swell-agitation-or-ripples.md new file mode 100644 index 00000000000..4b9d265d7c1 --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/add-swell-agitation-or-ripples.md @@ -0,0 +1,40 @@ +# Add swell, agitation, or ripples + +To add swell, agitation or ripples, use a Water Mask to affect the influence the simulation has on specific areas of the water surface. + +Masks take into account the Wrap Mode of the texture. For Ocean, Sea, or Lake water surface types, select **Clamp** rather than the default **Repeat** value. + +To add a Water Mask: + +1. Create and import a texture where the color channels represent the fluctuations. + + Refer to the following table: + + | Water surface type | Red channel | Green channel | Blue channel | + |---------------------|-------------|---------------|--------------| + | Ocean | Swell | Agitation | Ripples | + | River | Agitation | Ripples | Not used | + | Pool | Ripples | Not used | Not used | + + > [!NOTE] + > The water types use different channels for different effects to optimize texture packing, and use the first channel for the widest simulation band. + + The darker the color of a channel, the lesser the effect. For example, use white for 100% intensity and black for 0% intensity. + +1. In the Water Volume Inspector window, drag the texture to the **Water Mask** property. + + + + + + + + + +
+ + + +
+In this example, the red channel has a gradient that reduces the first and second simulation bands. The noise on the green channel reduces ripples. For more information, refer to the Water Mask property description. +
diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/batch-renderer-group-creating-draw-commands.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/batch-renderer-group-creating-draw-commands.md index 3d2fe8ed04d..5ddef7d1a61 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/batch-renderer-group-creating-draw-commands.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/batch-renderer-group-creating-draw-commands.md @@ -8,7 +8,7 @@ To create draw commands, use the [BatchRendererGroup.OnPerformCulling](https://d Your `OnPerformCulling` implementation can generate as many or as few draw commands as you want. A simple implementation that only uses a single mesh and material could only output a single draw command, a more complex implementation could output thousands, each with different meshes and materials. -**Note**: To provide maximum flexibility, Unity doesn't preallocate the arrays in the `BatchCullingOutputDrawCommands` output struct and stores them as raw pointers so you can easily allocate them and use them from [Burst](https://docs.unity3d.com/Packages/com.unity.burst@latest) jobs. You must allocate the arrays using [UnsafeUtility.Malloc](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.UnsafeUtility.Malloc) with the the [Allocator.TempJob](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/Unity.Collections.Allocator.TempJob) allocator. The callback shouldn't release the memory. Instead, Unity releases the memory after it finishes rendering using the draw commands. +**Note**: To provide maximum flexibility, Unity doesn't preallocate the arrays in the `BatchCullingOutputDrawCommands` output struct and stores them as raw pointers so you can easily allocate them and use them from [Burst](https://docs.unity3d.com/Packages/com.unity.burst@latest) jobs. You must allocate the arrays using [UnsafeUtility.Malloc](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/Unity.Collections.LowLevel.Unsafe.UnsafeUtility.Malloc) with the [Allocator.TempJob](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/Unity.Collections.Allocator.TempJob) allocator. The callback shouldn't release the memory. Instead, Unity releases the memory after it finishes rendering using the draw commands. See the following code sample for an example of how to create draw commands. This code sample builds on the one in [Creating batches](batch-renderer-group-creating-batches.md). @@ -256,4 +256,4 @@ public class SimpleBRGExample : MonoBehaviour } ``` -This is the final, complete, code sample for BRG. If you attach this Component to a GameObject, set a mesh and [DOTS Instancing](dots-instancing-shaders.md)-compatible material in the Inspector, and enter Play Mode, Unity renders three instances of the mesh using the material. \ No newline at end of file +This is the final, complete, code sample for BRG. If you attach this Component to a GameObject, set a mesh and [DOTS Instancing](dots-instancing-shaders.md)-compatible material in the Inspector, and enter Play Mode, Unity renders three instances of the mesh using the material. diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/convert-project-from-built-in-render-pipeline.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/convert-project-from-built-in-render-pipeline.md index fb91338ace9..c1f0bf75e32 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/convert-project-from-built-in-render-pipeline.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/convert-project-from-built-in-render-pipeline.md @@ -5,6 +5,6 @@ The High Definition Render Pipeline (HDRP) uses a new set of shaders and lightin | Topic | Description | |-|-| | [Convert post-processing scripts](convert-from-built-in-convert-post-processing-scripts.md) | Remove the Post-Processing Version 2 package from a project and update your scripts to work with HDRP's own implementation for post processing. | -| [Convert lighting and shadows](convert-from-built-in-convert-lighting-and-shadows.md) | Convert a project to physical Light units to control the intensity of Lights, instead of the the arbitrary units the Built-in Render Pipeline uses. | +| [Convert lighting and shadows](convert-from-built-in-convert-lighting-and-shadows.md) | Convert a project to physical Light units to control the intensity of Lights, instead of the arbitrary units the Built-in Render Pipeline uses. | | [Convert materials and shaders](convert-from-built-in-convert-materials-and-shaders.md) | Upgrade the materials in your scene to HDRP-compatible materials, either automatically or manually. | | [Convert project with HDRP wizard](convert-from-built-in-convert-project-with-hdrp-wizard.md) | Add the HDRP package to a Built-in Render Pipeline project and set up HDRP. | diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/create-an-hdri-sky.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/create-an-hdri-sky.md index 1f3b7fc0124..7114b93b2da 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/create-an-hdri-sky.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/create-an-hdri-sky.md @@ -15,7 +15,7 @@ Tip: [Unity HDRI Pack](https://assetstore.unity.com/packages/essentials/beta-pro After you add an **HDRI Sky** override, you must set the Volume to use **HDRI Sky**. The [Visual Environment](visual-environment-volume-override-reference.md) override controls which type of sky the Volume uses. To set the Volume to use **HDRI Sky**: -1. In the **Visual Environment** override, go to the **Sky** > **Sky Type** +1. In the **Visual Environment** override, go to **Sky** > **Sky Type**. 2. Set **Sky Type** to **HDRI Sky**. HDRP now renders an **HDRI Sky** for any Camera this Volume affects. @@ -23,4 +23,3 @@ HDRP now renders an **HDRI Sky** for any Camera this Volume affects. Refer to the [HDRI Sky Volume Override Reference](hdri-sky-volume-override-reference.md) for more information. [!include[](snippets/volume-override-api.md)] - diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/custom-pass-reference.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/custom-pass-reference.md index 8d13c48af61..655306dcae3 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/custom-pass-reference.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/custom-pass-reference.md @@ -35,7 +35,7 @@ Configure a draw renderers Custom Pass in the **Custom Passes** panel using the | Target Depth Buffer | | | The target buffer where Unity writes and tests the depth and stencil data:

•**Camera:** Targets the current camera depth buffer that renders the Custom Pass.
•**Custom:** Uses the Custom Pass buffer allocated in the HDRP Asset.
•**None:** Doesn’t write the data to a buffer.

This buffer does not contain transparent objects that have **Depth Write** enabled in the [shader properties](https://docs.unity3d.com/Packages/com.unity.render-pipelines.high-definition@10.2/manual/Lit-Shader.html). | | Clear Flags | | | Discards the contents of a buffer before Unity executes this Custom Pass.
Assign a clear flag to one of the following buffers:

•**None:** Doesn’t clear any buffers in this pass.
•**Color:** Clears the depth buffer.
•**Depth:** Clears the depth buffer and the stencil buffer.
•**All:** Clears the data in the color, depth and stencil buffers. | | Filters | | | Properties in this section determine the GameObjects that Unity renders in this Custom Pass. | -| | Queue | | Determines the kind of materials that this Custom Pass renders:
•**Opaque No Alpha test**: Opaque GameObjects without alpha test only.
•**Opaque Alpha Test: **Opaque GameObjects with alpha test only.
•**All Opaque**: All opaque GameObjects.
•**After Post Process Opaque**: Opaque GameObjects that use the after post process render pass.
•**Pre Refraction**: Transparent GameObjects that use the the pre refraction render pass.
•**Transparent**: Transparent GameObjects that use the default render pass.
•**Low Transparent**: Transparent GameObjects that use the low resolution render pass.
•**All Transparent**: All Transparent GameObjects.
•**All Transparent With Low Res**: Transparent GameObjects that use the Pre-refraction, Default, or Low resolution render pass.
•**After Post Process Transparent**: Transparent GameObjects that use after post process render pass.
•**Overlay**: All GameObjects that use the overlay render pass.
•**All:** All GameObjects. | +| | Queue | | Determines the kind of materials that this Custom Pass renders:
•**Opaque No Alpha test**: Opaque GameObjects without alpha test only.
•**Opaque Alpha Test: **Opaque GameObjects with alpha test only.
•**All Opaque**: All opaque GameObjects.
•**After Post Process Opaque**: Opaque GameObjects that use the after post process render pass.
•**Pre Refraction**: Transparent GameObjects that use the pre refraction render pass.
•**Transparent**: Transparent GameObjects that use the default render pass.
•**Low Transparent**: Transparent GameObjects that use the low resolution render pass.
•**All Transparent**: All Transparent GameObjects.
•**All Transparent With Low Res**: Transparent GameObjects that use the Pre-refraction, Default, or Low resolution render pass.
•**After Post Process Transparent**: Transparent GameObjects that use after post process render pass.
•**Overlay**: All GameObjects that use the overlay render pass.
•**All:** All GameObjects. | | | Layer Mask | | Determines the GameObject layer that this Custom Pass applies to. | | Overrides | | | | | | Override Mode | | Determines what this Custom Pass volume uses to render GameObjects included in this Custom Pass:
•**Material**
•**Shader**
•**Pass Name** | diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/deep-learning-super-sampling-in-hdrp.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/deep-learning-super-sampling-in-hdrp.md index 2d63a398267..993a539074f 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/deep-learning-super-sampling-in-hdrp.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/deep-learning-super-sampling-in-hdrp.md @@ -82,3 +82,8 @@ Out = SAMPLE_TEXTURE2D_BIAS(TextureInput, SamplerInput, UV, MipBias); ![](Images/CustomMipSupportNodeExample.png) + +## Additional resources + +- [Introduction to changing resolution scale](https://docs.unity3d.com/6000.0/Documentation/Manual/resolution-scale-introduction.html) + diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/dots-instancing-shaders-access.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/dots-instancing-shaders-access.md index b53992bda2d..81e2327f32e 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/dots-instancing-shaders-access.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/dots-instancing-shaders-access.md @@ -6,6 +6,6 @@ To access DOTS Instanced properties, your shader can use one of the access macro * If the most significant bit of the metadata value is `0`, every instance uses the value from instance index zero. This means each instance loads directly from the byte address in the metadata value. In this case, the buffer only needs to store a single value, instead of one value per instance. * If the most significant bit of the metadata value is `1`, the address should contain an array where you can find the value for instance index `instanceID` using `AddressOfInstance0 + sizeof(PropertyType) * instanceID`. In this case, you should ensure that every rendered instance index has valid data in buffer. Otherwise, out-of-bounds access and undefined behavior can occur. -You can also set the the metadata value directly which is useful if you want to use a custom data source that doesn't use the above layout, such as a texture. +You can also set the metadata value directly which is useful if you want to use a custom data source that doesn't use the above layout, such as a texture. For an example of how to use these macros, see [Access macro example](dots-instancing-shaders-samples.md). diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/enable-mask-and-water-decals.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/enable-mask-and-water-decals.md new file mode 100644 index 00000000000..3e61be290e2 --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/enable-mask-and-water-decals.md @@ -0,0 +1,7 @@ +# Enable mask and water decals + +To enable mask and water decals, follow these steps: + +1. Go to **Edit** > **Project Settings**. + +1. In the **Project Settings** window, select the **Graphics** tab and enable **Enable Mask and Current Water Decals** in the **Water System** section. diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/hdri-sky-volume-override-reference.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/hdri-sky-volume-override-reference.md index 0f20a632f1f..d96406ed937 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/hdri-sky-volume-override-reference.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/hdri-sky-volume-override-reference.md @@ -1,6 +1,6 @@ # HDRI Sky Volume Override reference -The HDRI Sky Volume Override component exposes options that you can use to define how the High Definition Render Pipeline (HDRP) renders an HDRI sky. +The HDRI Sky Volume Override component provides options to define how the High Definition Render Pipeline (HDRP) renders an HDRI sky. Refer to [Create an HDRI sky](create-an-HDRI-sky.md) for more information. @@ -22,51 +22,52 @@ Refer to [Create an HDRI sky](create-an-HDRI-sky.md) for more information. HDRI Sky - Assign a HDRI Texture that HDRP uses to render the sky. + Assign an HDRI texture to render the sky in HDRP. Distortion Mode - Use the drop-down to select the method that HDRP uses to calculate the sky distortion.
None: No distortion.
Procedural: HDRP distorts the sky using a uniform wind direction.
Flowmap: HDRP distorts the sky with a user provided flowmap. + Select how HDRP calculates sky distortion:
None: No distortion.
Procedural: Distorts the sky using uniform wind direction.
Flowmap: Uses a user-provided flowmap for distortion. Orientation - The orientation of the distortion relative to the X world vector (in degrees).
This value can be relative to the Global Wind Orientation defined in the Visual Environment. + Set the distortion orientation relative to the X-world vector (degrees).
This can be relative to the Global Wind Orientation in the Visual Environment. Speed - The speed at which HDRP scrolls the distortion texture.
This value can be relative to the Global Wind Speed defined in the Visual Environment. + Define how fast HDRP scrolls the distortion texture.
This value can be relative to the Global Wind Speed defined in the Visual Environment. Flowmap - Assign a flowmap, in LatLong layout, that HDRP uses to distort UVs when rendering the sky.
This property only appears when you select Flowmap from the Distortion Mode drop-down. + Assign a LatLong flowmap for sky UV distortion.
Visible only when you select Flowmap from the Distortion Mode drop-down. Upper Hemisphere Only - Check the box if the flowmap contains distortion for the sky above the horizon only.
This property only appears when you select Flowmap from the Distortion Mode drop-down. + Enable if the flowmap distorts only the sky above the horizon.
Visible only when you select Flowmap from the Distortion Mode drop-down. Intensity Mode - Use the drop-down to select the method that HDRP uses to calculate the sky intensity.
Exposure: HDRP calculates intensity from an exposure value in EV100.
Multiplier: HDRP calculates intensity from a flat multiplier.
Lux: HDRP calculates intensity in terms of a target Lux value. + Choose how HDRP calculates sky intensity:
Exposure: Based on EV100 exposure.
Multiplier: Applies a flat multiplier.
Lux: Targets a specific Lux value. Exposure - Set the amount of light per unit area that HDRP applies to the HDRI Sky cubemap.
This property only appears when you select Exposure from the Intensity Mode drop-down. + Set the light per unit area applied to the HDRI Sky cubemap.
Visible only when you set Exposure in Intensity Mode from the Intensity Mode drop-down. Multiplier - Set the multiplier for HDRP to apply to the Scene as environmental light. HDRP multiplies the environment light in your Scene by this value.
This property only appears when you select Multiplier from the Intensity Mode drop-down. + Set a multiplier for environment light in the scene.
Visible only when you select Multiplier from the Intensity Mode drop-down. + Desired Lux Value - Set an absolute intensity for the HDR Texture you set in HDRI Sky, in Lux. This value represents the light received in a direction perpendicular to the ground. This is similar to the Lux unit you use to represent the Sun, so it's complimentary.
This property only appears when you select Lux from the Intensity Mode drop-down. + Set an absolute intensity for the HDR Texture you set in HDRI Sky, in Lux. This value represents the light received in a direction perpendicular to the ground. This is similar to the Lux unit you use to represent the Sun, so it's complimentary.
Visible only when you select Lux from the Intensity Mode drop-down. @@ -78,10 +79,10 @@ Refer to [Create an HDRI sky](create-an-HDRI-sky.md) for more information. Use the slider to set the angle to rotate the cubemap, in degrees. - + Lock Sun - Make the Sun rotate automatically when you move the HDRI Sky, and the HDRI Sky rotate automatically when you rotate the Sun. + Make the Sun rotate automatically when you move the HDRI Sky, and the HDRI Sky rotate automatically when you rotate the sun. Update Mode @@ -91,7 +92,7 @@ Refer to [Create an HDRI sky](create-an-HDRI-sky.md) for more information. Update Period - Set the period (in seconds) for HDRP to update the sky environment. Set the value to 0 if you want HDRP to update the sky environment every frame. This property only appears when you set the Update Mode to Realtime. + Set the update interval in seconds. Use 0 for per-frame updates. Visible only when you set the Update Mode to Realtime. @@ -116,19 +117,19 @@ These properties only appear if you enable [advanced properties](https://docs.un Backplate - Indicates whether to project the bottom part of the HDRI onto a plane with various shapes such as a Rectangle, Circle, Ellipse, or Infinite plane. + Projects the lower hemisphere of the HDRI onto a selected shape (Rectangle, Circle, Ellipse, or Infinite plane). Type - Specifies the shape of the backplate.

Disc: Projects the bottom of the HDRI texture onto a disc.

Rectangle: rojects the bottom of the HDRI texture onto a rectangle.

Ellipse: Projects the bottom of the HDRI texture onto an ellipse.

Infinite: Projects the bottom of the HDRI texture onto an infinite plane. + Specifies the shape of the backplate.

Disc: Projects the bottom of the HDRI texture onto a disc.

Rectangle: Projects the bottom of the HDRI texture onto a rectangle.

Ellipse: Projects the bottom of the HDRI texture onto an ellipse.

Infinite: Projects the bottom of the HDRI texture onto an infinite plane. Ground Level - The height of the ground level in the scene. + Specifies the height of the ground in the scene. @@ -140,25 +141,25 @@ These properties only appear if you enable [advanced properties](https://docs.un Projection - HDRP uses this number to control the projection of the bottom hemisphere of the HDRI on the backplate. Small projection distance implies higher pixels density with more distortion, large projection distance implies less pixels density with less distortion. + HDRP uses this number to control the projection of the bottom hemisphere of the HDRI on the backplate. Small projection distance implies higher pixel density with more distortion, large projection distance implies less pixel density with less distortion. Rotation - The rotation of the physical backplate. + Rotates the physical backplate. Texture Rotation - The rotation of the HDRI texture HDRP projects onto the backplate. + Rotates the HDRI texture projected onto the backplate. Texture Offset - The offset value to apply to the texture HDRP projects onto the backplate. + Offsets the texture projected onto the backplate. @@ -176,7 +177,7 @@ These properties only appear if you enable [advanced properties](https://docs.un Directional Shadow - Indicates whether the backplate receives shadows from the main directional Light. + Enables shadows from the main directional light on the backplate. @@ -201,4 +202,4 @@ These properties only appear if you enable [advanced properties](https://docs.un **Note**: To use ambient occlusion in the backplate, increase the value of the **Direct Lighting Strength** property on the [Ambient Occlusion](Override-Ambient-Occlusion.md) component override. As the backplate doesn't have global illumination, it can only get ambient occlusion from direct lighting. -**Limitation**: The backplate only appears in local reflection probes and it doesn't appear in the default sky reflection. This is because the default sky reflection is a cubemap projected at infinity which is incompatible with how Unity renders the backplate. +**Limitation**: The backplate only appears in local reflection probes and doesn't appear in the default sky reflection. This is because the default sky reflection is a cubemap projected at infinity which is incompatible with how Unity renders the backplate. diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/raytracing-troubleshooting.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/raytracing-troubleshooting.md new file mode 100644 index 00000000000..6e79d2e5e05 --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/raytracing-troubleshooting.md @@ -0,0 +1,233 @@ +# Troubleshooting HDRP DXR/real-time ray tracing lighting + +Incorrect lighting, such as missing shadows or lighting leaks, can occur if the camera's field of view, shadow map configurations, or light clusters don't align properly with the scene's geometry. The causes of these issues can be the following: + +- Shadows from directional or punctual lights can be missing if the camera's frustum is misaligned or too narrow, and doesn't cover the shadow map area. + +- Lighting leaks and insufficient light contributions can occur in scenes with closed environments, improper probe placement, or incorrect fallback settings. + + > [!NOTE] + > For each rasterized pixel, the lighting comes from at least five distinct sources: + > * Bullet text. + > * Directional (global) lights and their shadows + > * Direct local lights (point, spot, area) and their shadows + > * Indirect specular lighting: + > * Screen Space Reflection (SSR)/Ray Traced Reflection (RTR) + > * Planar reflection + > * Reflection probes + > * Sky cubemap + +- Indirect diffuse lighting: + + - Screen Space Global Illumination (SSGI)/Ray-Traced Global Illumination (RTGI) + + - Adaptive Probe Volumes (APV) + + - Light probe groups + + - Lightmaps + + - Ambient probes + +- Fog + +## Fix missing shadows from directional lights + +### Symptoms + +You might notice the following symptoms when shadows from directional lights are missing: + +- Shadows from directional lights don't appear, even though the light source is visible. + +- Certain areas of the scene appear overly bright without proper shading or occlusion. + +- The lighting feels flat or unrealistic, especially in large outdoor scenes with sunlight. + + + + + + +### Cause + +Shadows cast by directional light don't render if the camera's field of view (frustum) is narrower than the cascade shadow map's coverage area. + +### Resolution + +To fix missing shadows from directional lights, adjust the **Directional Shadow Fallback Intensity** in the [Ray Tracing settings](reference-ray-tracing-settings.html). This setting allows HDRP to apply a fallback shadow value to points in the scene geometry where rays from the camera intersect objects but fall outside the coverage area of the shadow map. Depending on your setup, use 0.0 (in shadow) or 1.0 (fully lit) as the fallback shadow value. + +## Fix missing shadows from punctual lights + +### Symptoms + +The following symptoms indicate missing shadows from punctual lights: + +- Shadows from point lights or spot lights are missing, causing illuminated objects to look as though they're lit from all directions. + +- Scenes appear washed out or lack depth, particularly when using small, concentrated light sources. + +- Light leaks occur in areas where shadows are meant to be cast by nearby objects. + + + + + + +### Cause + +Shadows cast by punctual lights don't render if the camera's field of view (frustum) is narrower than the cascade shadow map's coverage area. + +### Resolution + +To fix missing shadows from punctual lights, enable **Extend Shadow Culling** in the [Ray Tracing settings](reference-ray-tracing-settings.html). + +Extended shadow culling provides the following benefits: + +- The [extended frustum culling region](reference-ray-tracing-settings.html#extended-culling) includes more objects in the shadow maps, even if their shadows don't affect pixels inside the frustum. + +- Extended frustum culling doesn't increase the size of the cascade shadow map (only for directional lights). + +However, extended shadow culling increases memory use and computational load. + +## Fix insufficient local light contributions + +### Symptoms + +If local lights, such as point or area lights, aren't contributing properly to the scene, you might observe the following: + +- Local lights seem too dim or fail to light nearby objects properly. + +- Certain objects appear unlit or underlit despite being close to a light source. + +- Ray-traced global illumination (RTGI) or RTR lighting doesn't seem to take local lights into account. + +### Cause + +The [light cluster's](Ray-Tracing-Light-Cluster.html) configuration can cause issues with the impact of direct local lights on real-time ray tracing (RTR) and ray-traced global illumination (RTGI). + +### Resolution + +To fix insufficient local light contributions, diagnose the issue in the [Rendering Debugger window](use-the-rendering-debugger.md). + +- If the number of lights in each cell exceeds the default limit, reduce the number of lights in **Edit** > **Project Settings** > **Quality** > **HDRP** > **Lights**. + +- If lights outside the camera range aren't contributing as expected, enlarge the camera cluster range in the volume's **Inspector** window under **Override** > **Ray Tracing** > **Light Cluster**. + +## Fix indirect specular light leaks + +### Symptoms + +The following symptoms might occur when an indirect specular light leaks: + +- Reflections, especially on glossy or metallic surfaces, are either missing or overly bright, as though they reflect the sky or environment instead of the intended object. + +- Unrealistic or random bright spots appear on surfaces with specular highlights, especially in interior scenes. + +- Reflections seem disconnected from nearby objects or appear out of place. + + + + + + +### Cause + +Common causes for indirect specular light leaks include the absence of reflection probes and incorrect fallback settings in the last bounce of screen-space reflections (SSR) and real-time ray tracing (RTR). + +### Resolution + +To fix indirect specular light leaks, add reflection probes and configure the **Ray Miss** and **Last Bounce** settings in the volume's Inspector window under **Override** > **Lighting** > **Screen Space Reflection** > **Tracing** > **Ray Tracing**. + +## Fix lighting leaks that occur when the sky lights the scene + +### Symptoms + +You might encounter the following issues when the sky lights the scene: + +- Bright light leaks from outside or from the sky into enclosed interiors, particularly in areas with no windows or other direct openings. + +- Overexposed or unnaturally bright spots appear on surfaces in closed spaces, even when no visible light sources are present. + +- Lighting feels uneven, with areas illuminated by the sky despite being fully enclosed. + +### Cause + +When the camera is in a closed environment, and no data is sampled from reflection probes at a ray intersection, the sky becomes the only light source. + +### Resolution + +To fix lighting leaks that occur when the sky lights the scene, create, place, and bake reflection probes, or use real-time reflection probes. + +- In the **Last Bounce** dropdown menu, select **Reflection Probes** or **None**. + +- Even in **Quality** mode and with more than the default number of bounces, you must specify a valid source of indirect specular light for the last bounce. + +## Fix indirect diffuse light leaks + +### Symptoms + +The following symptoms can indicate indirect diffuse light leaks: + +- Diffuse lighting appears to seep through walls or barriers, creating bright patches in areas meant to be shaded. + +- Areas in closed environments are lit by ambient or external light sources, producing an unrealistic lighting effect. + +- Objects near walls or other occlusions might appear brighter than intended, disrupting the desired lighting mood. + + + + + + +### Cause + +Common causes of indirect diffuse light leaks include improper use of ambient probes, deprecated light probes, and lightmaps in real-time ray tracing (RTR). + +### Resolution + +To fix indirect diffuse light leaks, follow one or both of these steps: + +- Adjust the **Ambient Probe Dimmer** in the Inspector window under **Override** > **Lighting** > **Screen Space Global Illumination** > **Tracing** > **Ray Tracing**. + +- Bake probes via adaptive probe volumes. + +## Fix fog light leaks + +### Symptoms + +Fog light leaks have the following symptoms: + +- Interior scenes have a tinted or colored fog effect that seems unnatural or overly bright, especially in areas with no visible sky. + +- The color of the fog in enclosed spaces appears inconsistent with the intended lighting setup, creating a disjointed visual effect. + +- Fog might seem to have a glowing or leaking effect, as though it's illuminated by a non-existent light source from outside. + + + + + + +### Cause + +Setting the fog color mode to **Sky Color** can cause unintended tinting in closed interiors. + +### Resolution + +To fix fog light leaks, set the fog's color to a constant black in closed environments. In the Sky and Fog Global Volume's Inspector window, select **Color mode** > **Constant color**, check the **Color box**, and select black in the color wheel. Bake probes via adaptive probe volumes. + +## Additional resources + +- [Unity ray tracing guide](Ray-Tracing-Getting-Started.html) + +- [Ray tracing settings](Ray-Tracing-Settings.html) + +- [Ray-traced global illumination](Ray-Traced-Global-Illumination.html) + +- [Ray-traced reflections](Ray-Traced-Reflections.html) + +- [Understand reflection in HDRP](reflection-understand.html) diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/reference-path-tracing.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/reference-path-tracing.md index 0c1c65de963..fdb2786fdde 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/reference-path-tracing.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/reference-path-tracing.md @@ -12,7 +12,7 @@ | **Maximum Intensity** | Set a value to clamp the intensity of the light value each bounce returns. This avoids bright, isolated pixels in the final result.
**Note**: This property can make the final image dimmer, so if the result looks dark, increase the value of this property. | | **Sky Importance Sampling** | Set the sky sampling mode. Importance sampling favors the brightest directions, which is beneficial when using a sky model with high contrast and intense spots (like a sun, or street lights). On the other hand, it can be slightly detrimental when using a smooth, uniform sky. It's active by default for HDRI skies only, but can also be turned On and Off, regardless of the type of sky in use. | | **Seed Mode** | Set how the path tracer generates random numbers. The seed is the pattern the noise has. When accumulating samples, every frame needs a different seed. Otherwise, the same noisy image gets accumulated over and over. **Seed Mode** has the following options:
• **Non Repeating**: This is the default option. The seed is chosen based on the camera frame count. When the accumulation resets, it is not reset to zero.
• **Repeating**: The seed is reset every time the accumulation is reset. Rendering of every image is done using the same random numbers.
• **Custom**: Set the seed using a custom script. For more information, see the example in [Understand path tracing](path-tracing-understand.md).| -| **Denoising** | Denoises the output of the the path tracer. This setting is only available when you install the **Unity Denoising** Package. **Denoising** has the following options:
• **None**: Does not denoise (this is the default option).
• **Intel Open Image Denoise** : Uses the Intel Open Image Denoise library to denoise the frame.
• **NVIDIA OptiX** : Uses NVIDIA OptiX to denoise the frame.

You can also enable the following additional settings:
• **Use AOVs** (Arbitrary Output Variables): Increases the amount of detail kept in the frame after HDRP denoises it.
• **Temporal**: Improves the temporal consistency of denoised frame sequences.
• **Separate Volumetrics**: Denoises the volumetric scattering effect separately for a smoother fog. When Separate Volumetrics is enabled, the Temporal setting will not improve volumetric fog temporal stability. | +| **Denoising** | Denoises the output of the path tracer. This setting is only available when you install the **Unity Denoising** Package. **Denoising** has the following options:
• **None**: Does not denoise (this is the default option).
• **Intel Open Image Denoise** : Uses the Intel Open Image Denoise library to denoise the frame.
• **NVIDIA OptiX** : Uses NVIDIA OptiX to denoise the frame.

You can also enable the following additional settings:
• **Use AOVs** (Arbitrary Output Variables): Increases the amount of detail kept in the frame after HDRP denoises it.
• **Temporal**: Improves the temporal consistency of denoised frame sequences.
• **Separate Volumetrics**: Denoises the volumetric scattering effect separately for a smoother fog. When Separate Volumetrics is enabled, the Temporal setting will not improve volumetric fog temporal stability. | ![](Images/RayTracingPathTracing4.png) diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/render-graph.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/render-graph.md index 1caa8dff8b1..1b63f398632 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/render-graph.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/render-graph.md @@ -1,4 +1,4 @@ -# Customize the the High Definition Render Pipeline (HDRP) +# Customize the High Definition Render Pipeline (HDRP) The High Definition Render Pipeline (HDRP) uses the [render graph system](https://docs.unity3d.com/Packages/com.unity.render-pipelines.core@latest/index.html?subfolder=/manual/render-graph-system.html) in its implementation. This means that if you want to extend HDRP and implement your own render pipeline features, you need to learn how the render graph system works and how to write rendering code using it. For information on the render graph system and how to use it to write render pipeline features, see the [render graph system](https://docs.unity3d.com/Packages/com.unity.render-pipelines.core@latest/index.html?subfolder=/manual/render-graph-system.html) documentation. diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/rendering-and-post-processing.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/rendering-and-post-processing.md index 6514c19389b..e5bd1fced6f 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/rendering-and-post-processing.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/rendering-and-post-processing.md @@ -16,6 +16,6 @@ Control how the High Definition Render Pipeline (HDRP) renders a scene and apply |[Motion effects](motion-effects.md)|Apply effects to simulate the appearance of objects moving at speed.| |[Runtime effects](runtime-effects.md)|Use HDRP's API to control properties in a script at runtime.| |[Custom rendering effects](Custom-rendering.md)|Create an effect in a script and control when and how HDRP renders it.| -|[Customize the the High Definition Render Pipeline (HDRP)](render-graph.md)|Uses the [render graph system](https://docs.unity3d.com/Packages/com.unity.render-pipelines.core@latest/index.html?subfolder=/manual/render-graph-system.html) to add render pipeline features to HDRP.| +|[Customize the High Definition Render Pipeline (HDRP)](render-graph.md)|Uses the [render graph system](https://docs.unity3d.com/Packages/com.unity.render-pipelines.core@latest/index.html?subfolder=/manual/render-graph-system.html) to add render pipeline features to HDRP.| |[Troubleshoot rendering and post-processing issues]()|Fix common issues with custom effects.| diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/rendering-multiframe-recording-api.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/rendering-multiframe-recording-api.md index 3087b8efc65..0fc503b335f 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/rendering-multiframe-recording-api.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/rendering-multiframe-recording-api.md @@ -25,4 +25,4 @@ The only call that takes any parameters is **BeginRecording**. Here is an explan | **ShutterInterval** | The amount of time the shutter is open between two subsequent frames. A value of **0** results in an instant shutter (no motion blur). A value of **1** means there is no (time) gap between two subsequent frames. | | **ShutterProfile** | An animation curve that specifies the shutter position during the shutter interval. Alternatively, you can also provide the time the shutter was fully open; and when the shutter begins closing. | -Before calling the accumulation API, the application should also set the desired `Time.captureDeltaTime`. The example script below demonstrates how to use these API calls. +Before calling the accumulation API, the application should also set the desired `Time.captureDeltaTime`. Refer to [Combine animations in a script](rendering-combine-animation-sequences-in-script) for an example. diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/rendering-understand-multiframe-rendering.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/rendering-understand-multiframe-rendering.md index b01241ffbe6..0137a96e7c4 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/rendering-understand-multiframe-rendering.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/rendering-understand-multiframe-rendering.md @@ -6,6 +6,6 @@ The High Definition Render Pipeline (HDRP) provides a scripting API that allows This API is particularly useful when recording path-traced movies. Normally, when editing a Scene, the convergence of path tracing restarts every time the Scene changes, to provide artists an interactive editing workflow that allows them to quickly visualize their changes. However such behavior isn't desirable during recording. -The following image shows a rotating GameObject with path tracing and accumulation motion blur, recorded using the [multi-frame recording API](rendering-multiframe recording API) +The following image shows a rotating GameObject with path tracing and accumulation motion blur, recorded using the [multi-frame recording API](rendering-multiframe-recording-API.md) [](Images/path_tracing_recording.png) \ No newline at end of file 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 f123b4dc77e..20580625e0a 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 @@ -48,16 +48,13 @@ Water type - - + +X + +X + X - -X - - -X - General @@ -82,7 +79,7 @@ Specifies the shape of the water surface. The options are:
  • Quad: Based on a square.
  • -
  • InstanceQuads: Creates a finite water surface with multiple instanced grids to keep a higher vertex density.
  • +
  • Instanced Quads: Creates a finite water surface with multiple instanced grids to keep a higher vertex density.
  • Custom Mesh: Based on a Mesh you provide. Overrides the vertical position of the vertices to keep the surface of the water consistently level.
  • Infinite (Ocean, Sea, or Lake only): Bounds the water surface with the Global Volume.
@@ -94,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. See 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. Refer to Scripting in the water system for more information. @@ -116,6 +113,42 @@ Only available if Script Interactions is active. Enable to have HDRP incl + + +Tessellation + + +Enable to implement tessellation. + + + + + +- Max Tessellation Factor + + +Set the level of detail HDRP applies to the surface geometry relative to the camera's position. A higher maximum tessellation factor makes the water surface more detailed and responsive to waves but increases the computational load. + + + + + +- Tessellation Factor Fade Start + + +Set the distance from the camera where the tessellation detail begins to decrease. + + + + + +- Tessellation Factor Fade Range + + +Set the distance from the camera at which the tessellation factor reaches 0. + + + X @@ -123,7 +156,7 @@ X X - + X @@ -143,10 +176,64 @@ Determines the speed at which HDRP presents the water simulation. Values above 1 -Water Mask +Water Mask -A texture HDRP uses to attenuate or supress Ripple (green channel) and Swell or Agitation (red channel) water frequencies. For more information, see Decals and masking in the water system. +Set the texture HDRP uses to reduce or stop water frequencies depending on the water surface type.
  • Ocean: Reduces swell (red channel), agitation (green), and ripples (blue).
  • River: Reduces agitation (red channel) and ripples (green channel).
  • Pool: Reduces ripples (red channel).
The Water Mask reduces the intensity of these water effects by multiplying the mask values with the corresponding water properties in the shader. Darker areas (closer to black) reduce the intensity, while lighter areas (closer to white) increase it.
For more information, refer to Decals and masking in the Water System. + + + + + +X + + +X + + +X + + +Water Decals + + + + + +Region Size + + +Set the width and length in meters of the region HDRP applies the Water Decal to. + + + + + + +Region Anchor + + +Anchor the Water Decal to a GameObject. By default, the region follows the camera. To make the region static, anchor it to the water surface. + + + + + + +Deformation + + +Enable to activate the option for creating a deformation decal. + + + + + + +Foam + + +Enable to activate the option for creating a foam decal. @@ -171,7 +258,7 @@ X Repetition Size -The size of the water patch in meters. Higher values result in less visible repetition. Also affects the Maximum Amplitude of Swell or Agitation frequency bands. +The size of the water patch in meters. Higher values result in less visible repetition. Also affects the Maximum Amplitude of Swell or Agitation simulation bands. @@ -241,12 +328,12 @@ Simulation Band properties Amplitude Dimmer (Ocean, Sea, or Lake)
    -
  • First band: The degree to which amplitude attenuates on the first frequency band of the Swell.
  • -
  • Second Band: The degree to which amplitude attenuates on the second frequency band of the Swell.
+
  • First band: The degree to which amplitude reduces on the first simulation band of the Swell.
  • +
  • Second Band: The degree to which amplitude reduces on the second simulation band of the Swell.

  • Amplitude Dimmer (River)
    -A dimmer that determines the degree to which amplitude can attenuate on the Agitation frequency band. For example, if your Amplitude value is 10 meters and you set this property to 0.5, your Agitation is 5 meters high.
    +A dimmer that determines the degree to which amplitude can reduce on the Agitation simulation band. For example, if your Amplitude value is 10 meters and you set this property to 0.5, your Agitation is 5 meters high.
    @@ -257,7 +344,7 @@ A dimmer that determines the degree to which amplitude can attenuate on the Agit Fade -Additional property. When this option is active, HDRP begins fading the contribution of this frequency band at the distance from the camera that the Range value specifies. This helps minimize distant aliasing artifacts. +Additional property. When this option is active, HDRP begins fading the contribution of this simulation band at the distance from the camera that the Range value specifies. This helps minimize distant aliasing artifacts. @@ -266,7 +353,7 @@ A dimmer that determines the degree to which amplitude can attenuate on the Agit - Range -Additional property. The distance from the camera in meters at which HDRP begins to fade the contribution of this frequency band. +Additional property. The distance from the camera in meters at which HDRP begins to fade the contribution of this simulation band. @@ -372,7 +459,7 @@ Determines the orientation and constant speed of the current that displaces ripp Fade -Additional property. When this option is active, HDRP begins fading the contribution of this frequency band at the distance from the camera that corresponds to the Range value in meters. This helps minimize distant aliasing artifacts. +Additional property. When this option is active, HDRP begins fading the contribution of this simulation band at the distance from the camera that corresponds to the Range value in meters. This helps minimize distant aliasing artifacts. @@ -381,7 +468,7 @@ Determines the orientation and constant speed of the current that displaces ripp - Range -Additional property. The distance from the camera, in meters, at which HDRP begins to fade the contribution of this frequency band. +Additional property. The distance from the camera, in meters, at which HDRP begins to fade the contribution of this simulation band. @@ -419,7 +506,7 @@ X - + Area Size @@ -452,7 +539,7 @@ X Simulation Foam Amount -Determines the amount of surface foam. Higher values generate larger foam patches. The Wind Speed Dimmer configuration determines which Distant Wind Speed values generate foam, and how much; see Foam in the water system. +Determines the amount of surface foam. Higher values generate larger foam patches. The Wind Speed Dimmer configuration determines which Distant Wind Speed values generate foam, and how much; refer to Foam in the water system. @@ -480,14 +567,14 @@ X Mask -Select a texture whose red channel Unity uses to attenuate and suppress foam. +Select a texture whose red channel Unity uses to reduce or remove foam. Wind Speed Dimmer -Determines foam intensity. The normalized Distant Wind Speed determines the X axis value. The spline editor configures the Y axis value. See Foam in the water system for more information. +Determines foam intensity. The normalized Distant Wind Speed determines the X axis value. The spline editor configures the Y axis value. Refer to Foam in the water system for more information. @@ -870,7 +957,7 @@ Specifies the view of the debug mode used for the water surface. To use a Volume Override, you must first add a Volume Profile. -See The water system Volume Override for more information.
    +Refer to The water system Volume Override for more information.
    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 new file mode 100644 index 00000000000..bc1f9509f89 --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/simulating-currents-with-water-decals.md @@ -0,0 +1,42 @@ +# Simulate currents with water decals + +To add deformation, foam, or current effects to a water surface, use a water decal, which is a texture projected onto the surface. + +A water decal is a shader graph Master Stack. It's applied in world space, allowing it to project across the water surface and integrate with the entire environment, not just a single area. + +By default, water decal regions are anchored to the camera. You can also anchor them to a GameObject. + +> [!NOTE] +> For backward compatibility, water decals are disabled by default. + +## Water decal shader graph Master Stack + +By default, the water decal shader graph Master Stack contains the following properties: + +- **Deformation** +- **SurfaceFoam** +- **DeepFoam** + +Once you have [enabled mask and current water decals](enable-mask-and-water-decals.md), you can add the following water features through the Graph Inspector: + +- **SimulationMask** +- **SimulationFoamMask** +- **LargeCurrent** +- **LargeCurrentInfluence** +- **RipplesCurrent** +- **RipplesCurrentInfluence** + +## Decal layer masks + +To add foam, you can change material properties (base color, smoothness, normals, etc.) by using a [decal](decals.md) on a water surface. For example, you might use this technique to imitate debris floating on the water. +**Global Opacity** determines the amount of influence the decal has on the appearance of the water surface. + +The following [Decal Shader](decal-material-inspector-reference.md) Surface Options don't work with water surfaces: +* **Affect Metal** +* **Affect Ambient Occlusion** +* **Affect Emission** +* **Affect Base Color** only produces monochromatic output. + +## Additional resources + +- [Shader Graph](https://docs.unity3d.com/Packages/com.unity.shadergraph@latest) diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/simulating-foam-or-ripples-with-masks.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/simulating-foam-or-ripples-with-masks.md new file mode 100644 index 00000000000..9301d45e17c --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/simulating-foam-or-ripples-with-masks.md @@ -0,0 +1,10 @@ +# Simulate foam or ripples with masks + +A simulation mask defines areas of influence for specific water simulation effects, such as foam or ripples. + +By using a simulation mask, you can restrict these effects to particular regions on the water surface, enabling localized interactions. + +For example, if you're simulating debris or objects affecting the water, a simulation mask will allow you to define where foam or other effects appear based on those interactions. + +> [!NOTE] +> For backward compatibility, simulation masks are disabled by default. diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/skin-and-diffusive-surfaces-subsurface-scattering.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/skin-and-diffusive-surfaces-subsurface-scattering.md index 4f1c395f8ee..8782d61bcdf 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/skin-and-diffusive-surfaces-subsurface-scattering.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/skin-and-diffusive-surfaces-subsurface-scattering.md @@ -22,6 +22,24 @@ For HDRP to detect it, you must add it to the **Diffusion Profile List** of the Refer to [Diffusion Profile reference](diffusion-profile-reference.md) for more information. +### Subsurface border attenuation + +HDRP includes support for an approximation of occlusion in Subsurface Scattering (SSS), referred to as **Border Attenuation**. When enabled, **Border Attenuation** darkens the Subsurface Scattering effect near the borders of an object. A border is defined as an area where the material transitions to another material without Subsurface Scattering or to a material with a different diffusion profile. + +To enable **Border Attenuation**, in the HDRP asset go in the Material Section, under the Subsurface scattering toggle, enable **Support Border Attenuation**. + +#### Use cases + +Border Attenuation is particularly useful when working with diffusion profiles that have a large radius. It enhances detail in the light simulation, making it especially beneficial for rendering complex surfaces like eyes, which typically present challenges for Subsurface Scattering. + +#### Performances + +Enabling Border Attenuation incurs a minor performance cost on the GPU. This cost scales linearly with the number of samples used in the Subsurface Scattering process. + +#### Border Attenuation Color + +When border attenuation is enabled, a new option is available in the diffusion profile allowing you to specify the color for samples that hit the border. This simulates the effect of light being transmitted from one surface to another through Subsurface Scattering. It only affects Subsurface Scattering when two materials with different diffusion profiles are adjacent to each other. + ## Add subsurface scattering to a Material To add subsurface scattering to a Material: diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/snippets/shader-properties/surface-options/shadow-matte.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/snippets/shader-properties/surface-options/shadow-matte.md index d6cb6c832f5..b7e08041c98 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/snippets/shader-properties/surface-options/shadow-matte.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/snippets/shader-properties/surface-options/shadow-matte.md @@ -2,5 +2,8 @@ - + diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/stp/stp-upscaler.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/stp/stp-upscaler.md index a5276cadf21..1db366b1a29 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/stp/stp-upscaler.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/stp/stp-upscaler.md @@ -33,3 +33,8 @@ To enable STP in the High Definition Render Pipeline (HDRP), do the following: 3. Set **Dynamic Resolution Type** to **Hardware**. STP remains active when **Render Scale** is set to **1.0** as it applies temporal anti-aliasing (TAA) to the final rendered output. + +## Additional resources + +- [Introduction to changing resolution scale](https://docs.unity3d.com/6000.0/Documentation/Manual/resolution-scale-introduction.html) + diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/volumetric-clouds-volume-override-reference.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/volumetric-clouds-volume-override-reference.md index ba0e9c1df21..44b22b7e9fa 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/volumetric-clouds-volume-override-reference.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/volumetric-clouds-volume-override-reference.md @@ -65,6 +65,7 @@ Refer to [Create realistic clouds (volumetric clouds)](create-realistic-clouds-v | -------------------------------- | ------------------------------------------------------------ | | **Temporal Accumulation Factor** | The amount of temporal accumulation to apply to the clouds. Temporal accumulation increases the visual quality of clouds by decreasing the noise. A higher value produces better quality clouds, but can create [ghosting](Glossary.md#ghosting). | | **Ghosting Reduction** | When you enable this property, HDRP removes the ghosting caused by temporal accumulation. This effect might cause a flickering effect when the **Temporal Accumulation Factor** value is low. | +| **Perceptual Blending** | Blend the clouds with the environment. This might cause artifacts if the sky is overexposed. This setting only has an effect when you disable multi-sample antialiasing (MSAA). | | **Num Primary Steps** | The number of steps to use to evaluate the clouds' transmittance. Higher values linearly increase the resource intensity of the effect. | | **Num Light Steps** | The number of steps to use to evaluate the clouds' lighting. Higher values exponent increase the resource intensity of the effect. | 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 936ce5375c2..a62595d6c6e 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 @@ -17,7 +17,7 @@ this.GetComponent().material.SetTexture("_Base_Color", waterSurf 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. * HDRP doesn't apply caustics to transparent GameObjects when the camera is underwater. -* Caustics do not react to current maps and water mask. +* Caustics do not react to current maps and Water Mask. ## Additional resources * Settings and properties related to the water system diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-debug-mode.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-debug-mode.md index c57a8cf4913..4afccf381bc 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-debug-mode.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-debug-mode.md @@ -4,7 +4,7 @@ For authoring purposes, the water surface component has debug view modes. Those They are especially useful for placing the different areas (Mask, Deformation, Foam) precisely. ## Water Mask -The Water Mask mode shows the attenuation of each frequency band. White color means no attenuation, black color means 100% masking. +The Water Mask mode displays the reduction of each simulation band. White means no reduction. Black means 100% reduction. You can select which channel of the water mask to debug by using the **Water Mask Mode** dropdown. Note that, for saving texture space, the red channel always attenuate the first band (First swell band for oceans, Agitation for rivers, Ripples for pools), green channel, the second band (Second swell band for oceans, ripples for rivers)... etc 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 new file mode 100644 index 00000000000..208ace00cbd --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-decals-masking-landing.md @@ -0,0 +1,14 @@ +# Water surface fluctuations + +You can apply effects like swell, agitation, deformation, and foam across the water surface. + +You can add fluctuations such as swell, agitation, or ripples to the whole of a water surface based on texture channels with a Water Mask. + +You can also add detailed visual effects to localized water areas with water decals, a type of shader graph nodes. + +| **Page** | **Description** | +|---------------------------------------------------------------------------------------|-----------------------------------------------------------------------------| +| **[Enable mask and water decals](enable-mask-and-water-decals.md)** | Mask and current water decals are disabled by default. | +| **[Add swell, agitation, or ripples](add-swell-agitation-or-ripples.md)** | Add swell, agitation, or ripples across the water surface. | +| **[Simulating currents with water decals](simulating-currents-with-water-decals.md)** | Simulate water currents by projecting textures. | +| **[Simulating foam or ripples with masks](simulating-foam-or-ripples-with-masks.md)** | Create effects like foam or ripples. | diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-vfx-interaction.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-vfx-interaction.md index e3f4224c56e..396ac631f6f 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-vfx-interaction.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/water-vfx-interaction.md @@ -1,6 +1,6 @@ # Interaction between the water system and the VFX Graph -The water system supports being evaluated from the VFX Graph, to access data such as the the water height at a given point, the surface normal, or the current value. +The water system supports being evaluated from the VFX Graph, to access data such as the water height at a given point, the surface normal, or the current value. ![](Images/SampleWaterVFX.png) diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Decal/DecalProjectorEditor.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Decal/DecalProjectorEditor.cs index 302aa95b93f..78c94c8aa18 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Decal/DecalProjectorEditor.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Decal/DecalProjectorEditor.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; using UnityEditor.IMGUI.Controls; +using UnityEditor.Rendering.HighDefinition.ShaderGraph; using UnityEditor.ShaderGraph; using UnityEditor.ShortcutManagement; using UnityEngine; +using UnityEngine.Rendering; using UnityEngine.Rendering.HighDefinition; using static UnityEditorInternal.EditMode; using RenderingLayerMask = UnityEngine.RenderingLayerMask; @@ -17,6 +19,16 @@ partial class DecalProjectorEditor : Editor const float k_Limit = 100000; const float k_LimitInv = 1 / k_Limit; + + static public readonly GUIContent k_NewDecalMaterialButtonText = EditorGUIUtility.TrTextContent("New", "Creates a new Decal material."); + static public readonly string k_NewDecalText = "HDRP Decal"; + static public readonly string k_NewSGDecalText = "ShaderGraph Decal"; + + internal enum DefaultDecal + { + HDRPDecal, + SGDecal + } static Color fullColor { get @@ -715,7 +727,7 @@ public override void OnInspectorGUI() ReinitSavedRatioSizePivotPosition(); EditorGUI.EndProperty(); - EditorGUILayout.PropertyField(m_MaterialProperty, k_MaterialContent); + DecalMaterialFieldWithButton(m_MaterialProperty); bool decalLayerEnabled = false; if (hdrp != null) @@ -837,6 +849,54 @@ public override void OnInspectorGUI() } } + internal void DecalMaterialFieldWithButton(SerializedProperty prop) + { + const int k_NewFieldWidth = 70; + + var rect = EditorGUILayout.GetControlRect(); + rect.xMax -= k_NewFieldWidth + 2; + + EditorGUI.PropertyField(rect, prop); + + var newFieldRect = rect; + newFieldRect.x = rect.xMax + 2; + newFieldRect.width = k_NewFieldWidth; + + if (!EditorGUI.DropdownButton(newFieldRect, k_NewDecalMaterialButtonText, FocusType.Keyboard)) + return; + + GenericMenu menu = new GenericMenu(); + menu.AddItem(new GUIContent(k_NewDecalText), false, () => CreateDefaultDecalMaterial(target as MonoBehaviour, DefaultDecal.HDRPDecal)); + menu.AddItem(new GUIContent(k_NewSGDecalText), false, () => CreateDefaultDecalMaterial(target as MonoBehaviour, DefaultDecal.SGDecal)); + menu.DropDown(newFieldRect); + } + + public static void CreateDefaultDecalMaterial(MonoBehaviour obj, DefaultDecal defaultDecal) + { + string materialName = ""; + var materialIcon = AssetPreview.GetMiniTypeThumbnail(typeof(Material)); + + var action = ScriptableObject.CreateInstance(); + action.decalProjector = obj as DecalProjector; + + switch (defaultDecal) + { + case DefaultDecal.HDRPDecal: + materialName = "New " + k_NewDecalText; + action.isShaderGraph = false; + break; + case DefaultDecal.SGDecal: + materialName = "New " + k_NewSGDecalText; + action.isShaderGraph = true; + break; + default: + Debug.LogError("Decal creation failed."); + break; + } + + ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, action, materialName, materialIcon, null); + } + [Shortcut("HDRP/Decal: Handle changing size stretching UV", typeof(SceneView), KeyCode.Keypad1, ShortcutModifiers.Action)] static void EnterEditModeWithoutPreservingUV(ShortcutArguments args) { @@ -904,4 +964,33 @@ static void ExitEditMode(ShortcutArguments args) QuitEditMode(); } } + + class DoCreateDecalDefaultMaterial : ProjectWindowCallback.EndNameEditAction + { + public DecalProjector decalProjector; + public bool isShaderGraph = false; + public override void Action(int instanceId, string pathName, string resourceFile) + { + string shaderGraphName = AssetDatabase.GenerateUniqueAssetPath(pathName + ".shadergraph"); + string materialName = AssetDatabase.GenerateUniqueAssetPath(pathName + ".mat"); + Shader shader = null; + + if (isShaderGraph) + { + shader = DecalSubTarget.CreateDecalGraphAtPath(shaderGraphName); + } + else + { + shader = Shader.Find("HDRP/Decal"); + } + + if (shader != null) + { + var material = new Material(shader); + AssetDatabase.CreateAsset(material, materialName); + ProjectWindowUtil.ShowCreatedAsset(material); + decalProjector.material = material; + } + } + } } diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Decal/ShaderGraph/DecalSubTarget.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Decal/ShaderGraph/DecalSubTarget.cs index a1b1e2317ec..dc4ee23b8da 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Decal/ShaderGraph/DecalSubTarget.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Decal/ShaderGraph/DecalSubTarget.cs @@ -8,6 +8,7 @@ using static UnityEngine.Rendering.HighDefinition.HDMaterial; using static UnityEngine.Rendering.HighDefinition.HDMaterialProperties; using static UnityEditor.Rendering.HighDefinition.HDFields; +using UnityEngine; namespace UnityEditor.Rendering.HighDefinition.ShaderGraph { @@ -224,6 +225,38 @@ void AddColorMaskProperty(string referenceName) } } + internal static Shader CreateDecalGraphAtPath(string path) + { + var target = (HDTarget)Activator.CreateInstance(typeof(HDTarget)); + target.TrySetActiveSubTarget(typeof(DecalSubTarget)); + + var blockDescriptors = new[] + { + BlockFields.VertexDescription.Position, + BlockFields.VertexDescription.Normal, + BlockFields.VertexDescription.Tangent, + BlockFields.SurfaceDescription.BaseColor, + BlockFields.SurfaceDescription.Alpha, + BlockFields.SurfaceDescription.NormalTS, + HDBlockFields.SurfaceDescription.NormalAlpha, + BlockFields.SurfaceDescription.Metallic, + BlockFields.SurfaceDescription.Occlusion, + BlockFields.SurfaceDescription.Smoothness, + HDBlockFields.SurfaceDescription.MAOSAlpha, + BlockFields.SurfaceDescription.Emission, + }; + + var graph = new GraphData(); + graph.AddContexts(); + graph.InitializeOutputs(new[] { target }, blockDescriptors); + + graph.path = "Shader Graphs"; + FileUtilities.WriteShaderGraphToDisk(path, graph); + AssetDatabase.Refresh(); + + return AssetDatabase.LoadAssetAtPath(path); + } + #region SubShaders static class SubShaders { diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/DiffusionProfile/DiffusionProfileSettingsEditor.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/DiffusionProfile/DiffusionProfileSettingsEditor.cs index f5f9a9a156b..06891343528 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/DiffusionProfile/DiffusionProfileSettingsEditor.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/DiffusionProfile/DiffusionProfileSettingsEditor.cs @@ -160,6 +160,8 @@ void DrawSSS() DualSliderWithFields(Styles.smoothnessMultipliers, m_SerializedDiffusionProfileSettings.smoothnessMultipliers, 0.0f, 2.0f); EditorGUILayout.PropertyField(m_SerializedDiffusionProfileSettings.lobeMix); EditorGUILayout.PropertyField(m_SerializedDiffusionProfileSettings.diffusePower); + if (HDRenderPipeline.currentAsset == null || HDRenderPipeline.currentAsset.currentPlatformRenderPipelineSettings.subsurfaceScatteringAttenuation) + EditorGUILayout.PropertyField(m_SerializedDiffusionProfileSettings.borderAttenuationColor); } EditorGUILayout.Space(); diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/DiffusionProfile/SerializedDiffusionProfileSettings.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/DiffusionProfile/SerializedDiffusionProfileSettings.cs index 0313664532d..9bb5c5027b2 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/DiffusionProfile/SerializedDiffusionProfileSettings.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/DiffusionProfile/SerializedDiffusionProfileSettings.cs @@ -18,6 +18,7 @@ internal sealed class SerializedDiffusionProfileSettings : IDisposable internal SerializedProperty smoothnessMultipliers; internal SerializedProperty lobeMix; internal SerializedProperty diffusePower; + internal SerializedProperty borderAttenuationColor; internal SerializedProperty transmissionMode; internal SerializedProperty thicknessRemap; internal SerializedProperty worldScale; @@ -47,6 +48,7 @@ internal SerializedDiffusionProfileSettings(DiffusionProfileSettings settings, smoothnessMultipliers = rp.Find(x => x.smoothnessMultipliers); lobeMix = rp.Find(x => x.lobeMix); diffusePower = rp.Find(x => x.diffuseShadingPower); + borderAttenuationColor = rp.Find(x => x.borderAttenuationColor); transmissionMode = rp.Find(x => x.transmissionMode); thicknessRemap = rp.Find(x => x.thicknessRemap); worldScale = rp.Find(x => x.worldScale); diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Lit/ShaderGraph/ShaderPass.template.hlsl b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Lit/ShaderGraph/ShaderPass.template.hlsl index cbd72ac752e..c9a5e99713d 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Lit/ShaderGraph/ShaderPass.template.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Lit/ShaderGraph/ShaderPass.template.hlsl @@ -50,6 +50,7 @@ void BuildSurfaceData(FragInputs fragInputs, inout SurfaceDescription surfaceDes // These static material feature allow compile time optimization surfaceData.materialFeatures = MATERIALFEATUREFLAGS_LIT_STANDARD; #ifdef _MATERIAL_FEATURE_SUBSURFACE_SCATTERING + if (surfaceData.subsurfaceMask > 0) surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_LIT_SUBSURFACE_SCATTERING; #endif diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Water/ShaderGraph/WaterDecalSubTarget.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Water/ShaderGraph/WaterDecalSubTarget.cs index 9ad5c1d60d7..e4d66212586 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Water/ShaderGraph/WaterDecalSubTarget.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Water/ShaderGraph/WaterDecalSubTarget.cs @@ -260,6 +260,8 @@ PassDescriptor GeneratePass(WaterDecal.PassType type) StructFields.Varyings.texCoord0, StructFields.Varyings.texCoord1, StructFields.Varyings.instanceID, + StructFields.Varyings.stereoTargetEyeIndexAsBlendIdx0, + StructFields.Varyings.stereoTargetEyeIndexAsRTArrayIdx, } }, @@ -280,6 +282,8 @@ PassDescriptor GeneratePass(WaterDecal.PassType type) { Pragma.Vertex("Vert") }, { Pragma.Fragment("Frag") }, { Pragma.EditorSyncCompilation }, + { Pragma.DOTSInstancing }, + Pragma.MultiCompileInstancing, //{ Pragma.DebugSymbols }, }, defines = WaterDecalDefines.GetPassDefines(type), diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.Skin.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.Skin.cs index 082b96aee28..8cd14bc5cfd 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.Skin.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.Skin.cs @@ -155,6 +155,7 @@ public class Styles public static readonly GUIContent supportSSGIContent = EditorGUIUtility.TrTextContent("Screen Space Global Illumination", "When enabled, HDRP allocates memory for processing screen space global illumination (SSGI). This allows you to use SSGI in your Unity Project."); public static readonly GUIContent renderingLayerMaskBuffer = EditorGUIUtility.TrTextContent("Rendering Layer Mask Buffer", "When enabled, HDRP writes Rendering Layer Mask of Renderers to a buffer target that can be sampled in a shader in order to create fullscreen effects.\nThis comes with a performance and a memory cost."); public static readonly GUIContent supportedSSSContent = EditorGUIUtility.TrTextContent("Subsurface Scattering", "When enabled, HDRP allocates memory for processing subsurface scattering (SSS). This allows you to use SSS in your Unity Project."); + public static readonly GUIContent subsurfaceScatteringBorderAttenuation = EditorGUIUtility.TrTextContent("Support Border Attenuation", "When enabled, the subsurface scattering takes into account the occlusion of near objects with no subsurface-scattering or a different diffusion profile."); public static readonly GUIContent sssSampleBudget = EditorGUIUtility.TrTextContent("Sample Budget", "Maximum number of samples the Subsurface Scattering algorithm is allowed to take."); public static readonly GUIContent sssDownsampleSteps = EditorGUIUtility.TrTextContent("Downsample Level", "The number of downsample steps done to the source irradance textrure before it is used by the Subsurface Scattering algorithm. Higher value will improve performance, but might lower quality."); public static readonly GUIContent supportVolumetricFogContent = EditorGUIUtility.TrTextContent("Volumetric Fog", "When enabled, HDRP allocates Shader variants and memory for volumetric effects. This allows you to use volumetric lighting and fog in your Unity Project."); diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs index 01ec774ecd4..0305f9ae22e 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs @@ -1385,6 +1385,9 @@ static void Drawer_SectionMaterialUnsorted(SerializedHDRenderPipelineAsset seria || !serialized.renderPipelineSettings.supportSubsurfaceScattering.boolValue)) { ++EditorGUI.indentLevel; + + EditorGUILayout.PropertyField(serialized.renderPipelineSettings.subsurfaceScatteringBorderAttenuation, Styles.subsurfaceScatteringBorderAttenuation); + serialized.renderPipelineSettings.sssSampleBudget.ValueGUI(Styles.sssSampleBudget); EditorGUI.BeginChangeCheck(); diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/SerializedRenderPipelineSettings.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/SerializedRenderPipelineSettings.cs index bf9aaae6f76..3430661bc37 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/SerializedRenderPipelineSettings.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/SerializedRenderPipelineSettings.cs @@ -24,6 +24,7 @@ class SerializedRenderPipelineSettings public SerializedProperty supportSSAO; public SerializedProperty supportSSGI; public SerializedProperty supportSubsurfaceScattering; + public SerializedProperty subsurfaceScatteringBorderAttenuation; public SerializedScalableSetting sssSampleBudget; public SerializedScalableSetting sssDownsampleSteps; [FormerlySerializedAs("supportVolumetric")] @@ -82,7 +83,7 @@ class SerializedRenderPipelineSettings public SerializedProperty supportScreenSpaceLensFlare; public SerializedProperty supportDataDrivenLensFlare; - + public SerializedGlobalLightLoopSettings lightLoopSettings; public SerializedHDShadowInitParameters hdShadowInitParams; public SerializedGlobalDecalSettings decalSettings; @@ -116,6 +117,7 @@ public SerializedRenderPipelineSettings(SerializedProperty root) supportSSAO = root.Find((RenderPipelineSettings s) => s.supportSSAO); supportSSGI = root.Find((RenderPipelineSettings s) => s.supportSSGI); supportSubsurfaceScattering = root.Find((RenderPipelineSettings s) => s.supportSubsurfaceScattering); + subsurfaceScatteringBorderAttenuation = root.Find((RenderPipelineSettings s) => s.subsurfaceScatteringAttenuation); sssSampleBudget = new SerializedScalableSetting(root.Find((RenderPipelineSettings s) => s.sssSampleBudget)); sssDownsampleSteps = new SerializedScalableSetting(root.Find((RenderPipelineSettings s) => s.sssDownsampleSteps)); supportVolumetrics = root.Find((RenderPipelineSettings s) => s.supportVolumetrics); @@ -179,7 +181,7 @@ public SerializedRenderPipelineSettings(SerializedProperty root) lowresTransparentSettings = new SerializedLowResTransparencySettings(root.Find((RenderPipelineSettings s) => s.lowresTransparentSettings)); xrSettings = new SerializedXRSettings(root.Find((RenderPipelineSettings s) => s.xrSettings)); postProcessQualitySettings = new SerializedPostProcessingQualitySettings(root.Find((RenderPipelineSettings s) => s.postProcessQualitySettings)); - + supportScreenSpaceLensFlare = root.Find((RenderPipelineSettings s) => s.supportScreenSpaceLensFlare); supportDataDrivenLensFlare = root.Find((RenderPipelineSettings s) => s.supportDataDrivenLensFlare); diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Sky/PhysicallyBasedSky/PhysicallyBasedSkyEditor.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Sky/PhysicallyBasedSky/PhysicallyBasedSkyEditor.cs index 635c6296ee4..6ec7c5a1fe0 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Sky/PhysicallyBasedSky/PhysicallyBasedSkyEditor.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Sky/PhysicallyBasedSky/PhysicallyBasedSkyEditor.cs @@ -1,5 +1,5 @@ -using UnityEditor.Rendering; using UnityEngine; +using UnityEngine.Rendering; using UnityEngine.Rendering.HighDefinition; namespace UnityEditor.Rendering.HighDefinition @@ -47,6 +47,11 @@ class PhysicallyBasedSkyEditor : SkySettingsEditor GUIContent[] m_ModelTypes = { new GUIContent("Earth (Simple)"), new GUIContent("Earth (Advanced)"), new GUIContent("Custom Planet") }; int[] m_ModelTypeValues = { (int)PhysicallyBasedSkyModel.EarthSimple, (int)PhysicallyBasedSkyModel.EarthAdvanced, (int)PhysicallyBasedSkyModel.Custom }; + static public readonly GUIContent k_NewMaterialButtonText = EditorGUIUtility.TrTextContent("New", "Creates a new Physically Based Sky Material asset template."); + static public readonly GUIContent k_CustomMaterial = EditorGUIUtility.TrTextContent("Material", "Sets a custom material that will be used to render the PBR Sky. If set to None, the default Rendering Mode is used."); + + static public readonly string k_NewSkyMaterialText = "Physically Based Sky"; + public override void OnEnable() { base.OnEnable(); @@ -130,7 +135,10 @@ public override void OnInspectorGUI() if (hasMaterial) { using (new IndentLevelScope()) - PropertyField(m_Material); + { + MaterialFieldWithButton(m_Material, k_CustomMaterial); + } + } DrawHeader("Planet"); @@ -200,5 +208,47 @@ public override void OnInspectorGUI() base.CommonSkySettingsGUI(); } + + internal void MaterialFieldWithButton(SerializedDataParameter prop, GUIContent label) + { + using (var scope = new OverridablePropertyScope(prop, prop.displayName, this)) + { + if (!scope.displayed) + return; + + const int k_NewFieldWidth = 70; + var rect = EditorGUILayout.GetControlRect(); + rect.xMax -= k_NewFieldWidth + 2; + + var newFieldRect = rect; + newFieldRect.x = rect.xMax + 2; + newFieldRect.width = k_NewFieldWidth; + + EditorGUI.PropertyField(rect, prop.value, label); + + if (GUI.Button(newFieldRect, k_NewMaterialButtonText)) + { + string materialName = "New " + k_NewSkyMaterialText + ".mat"; + var materialIcon = AssetPreview.GetMiniTypeThumbnail(typeof(Material)); + var action = ScriptableObject.CreateInstance(); + action.physicallyBasedSky = target as PhysicallyBasedSky; + ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, action, materialName, materialIcon, null); + } + } + } + } + + class DoCreatePBRSkyDefaultMaterial : ProjectWindowCallback.EndNameEditAction + { + public PhysicallyBasedSky physicallyBasedSky; + public Material material = null; + public override void Action(int instanceId, string pathName, string resourceFile) + { + var shader = GraphicsSettings.GetRenderPipelineSettings().pbrSkyMaterial; + material = new Material(shader); + AssetDatabase.CreateAsset(material, pathName); + ProjectWindowUtil.ShowCreatedAsset(material); + physicallyBasedSky.material.value = material; + } } } diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Outputs/VFXLitSphereOutput.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Outputs/VFXLitSphereOutput.cs index f1cbf74a66a..8caac1c7f40 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Outputs/VFXLitSphereOutput.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Outputs/VFXLitSphereOutput.cs @@ -43,7 +43,7 @@ protected override IEnumerable implicitPostBlock { get { - var orient = VFXBlock.CreateImplicitBlock(GetData()); + var orient = GetOrCreateImplicitBlock(GetData()); orient.mode = Orient.Mode.FaceCameraPosition; yield return orient; } diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/Mesh/PassDepthOrMV.template b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/Mesh/PassDepthOrMV.template index d99129094b0..b003e52fb7d 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/Mesh/PassDepthOrMV.template +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/Mesh/PassDepthOrMV.template @@ -99,4 +99,4 @@ ${VFXHDRPLitFillVaryings} ${VFXEnd} ${VFXInclude("Shaders/ParticleMeshes/Pass.template")} -${VFXPassDepthCommonFragmentLit} +${VFXIncludeRP("Templates/VFXPassDepthCommonFragmentLit.template")} diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/Mesh/PassForward.template b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/Mesh/PassForward.template index b63ab12d534..f10abbe1b74 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/Mesh/PassForward.template +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/Mesh/PassForward.template @@ -20,10 +20,9 @@ Pass #pragma multi_compile_fragment _ PROBE_VOLUMES_L1 PROBE_VOLUMES_L2 #endif #pragma multi_compile _ DEBUG_DISPLAY - //#pragma enable_d3d11_debug_symbols ${VFXIncludeRP("VFXLitVaryings.template")} - ${VFXIncludeRP("VFXVertexProbeSampling.template"),VFX_MATERIAL_TYPE_SIX_WAY_SMOKE} + ${VFXIncludeRP("VFXSixWayIncludes.template"),VFX_MATERIAL_TYPE_SIX_WAY_SMOKE} struct ps_input { float4 pos : SV_POSITION; diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/PlanarPrimitive/PassDepthOrMV.template b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/PlanarPrimitive/PassDepthOrMV.template index ef88ff7eb83..8f5181313c5 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/PlanarPrimitive/PassDepthOrMV.template +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/PlanarPrimitive/PassDepthOrMV.template @@ -102,4 +102,4 @@ ${VFXHDRPLitFillVaryings} ${VFXEnd} ${VFXInclude("Shaders/ParticlePlanarPrimitives/Pass.template")} -${VFXPassDepthCommonFragmentLit} +${VFXIncludeRP("Templates/VFXPassDepthCommonFragmentLit.template")} diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/PlanarPrimitive/PassForward.template b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/PlanarPrimitive/PassForward.template index 184fa7c1dde..565d670870e 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/PlanarPrimitive/PassForward.template +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/PlanarPrimitive/PassForward.template @@ -21,10 +21,9 @@ Pass #pragma multi_compile_fragment _ PROBE_VOLUMES_L1 PROBE_VOLUMES_L2 #endif #pragma multi_compile _ DEBUG_DISPLAY - //#pragma enable_d3d11_debug_symbols ${VFXIncludeRP("VFXLitVaryings.template")} - ${VFXIncludeRP("VFXVertexProbeSampling.template"),VFX_MATERIAL_TYPE_SIX_WAY_SMOKE} + ${VFXIncludeRP("VFXSixWayIncludes.template"),VFX_MATERIAL_TYPE_SIX_WAY_SMOKE} struct ps_input { diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/VFXPassDepthCommonFragmentLit.template b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/VFXPassDepthCommonFragmentLit.template new file mode 100644 index 00000000000..bc8a47a3adf --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/VFXPassDepthCommonFragmentLit.template @@ -0,0 +1,117 @@ +#if VFX_PASSDEPTH == VFX_PASSDEPTH_MOTION_VECTOR +${VFXPassVelocityDefine} +#elif VFX_PASSDEPTH == VFX_PASSDEPTH_SHADOW +${VFXPassShadowDefine} +#else +${VFXPassDepthDefine} +#endif +${VFXIncludeRP("VFXLit.template")} + +${SHADERGRAPH_PIXEL_CODE_DEPTHONLY} + +#if VFX_PASSDEPTH == VFX_PASSDEPTH_SELECTION +int _ObjectId; +int _PassValue; +#elif VFX_PASSDEPTH == VFX_PASSDEPTH_PICKING +float4 _SelectionID; +#endif + +#pragma fragment frag +void frag(ps_input i +#if USE_DOUBLE_SIDED + , bool frontFace : SV_IsFrontFace +#endif +#if VFX_PASSDEPTH == VFX_PASSDEPTH_MOTION_VECTOR + #ifdef WRITE_MSAA_DEPTH + // We need the depth color as SV_Target0 for alpha to coverage + , out float4 outDepthColor : SV_Target0 + , out float4 outMotionVector : SV_Target1 + #ifdef WRITE_NORMAL_BUFFER + , out float4 outNormalBuffer : SV_Target2 + #endif + #else + // When no MSAA, the motion vector is always the first buffer + , out float4 outMotionVector : SV_Target0 + #ifdef WRITE_NORMAL_BUFFER + , out float4 outNormalBuffer : SV_Target1 + #endif + #endif +#elif VFX_PASSDEPTH == VFX_PASSDEPTH_ACTUAL + #ifdef WRITE_MSAA_DEPTH + // We need the depth color as SV_Target0 for alpha to coverage + , out float4 outDepthColor : SV_Target0 + #ifdef WRITE_NORMAL_BUFFER + , out float4 outNormalBuffer : SV_Target1 + #endif + #elif defined(WRITE_NORMAL_BUFFER) + , out float4 outNormalBuffer : SV_Target0 + #endif +#elif VFX_PASSDEPTH == VFX_PASSDEPTH_SELECTION || VFX_PASSDEPTH == VFX_PASSDEPTH_PICKING + , out float4 outColor : SV_Target0 +#endif +) +{ + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); + VFXTransformPSInputs(i); + ${VFXComputeNormalWS} + + #ifdef VFX_SHADERGRAPH + ${VFXAdditionalInterpolantsPreparation} + ${SHADERGRAPH_PIXEL_CALL_DEPTHONLY} + float alpha = OUTSG.${SHADERGRAPH_PARAM_ALPHA}; + #else + + float alpha = VFXGetFragmentColor(i).a; + + #if HDRP_USE_BASE_COLOR_MAP_ALPHA + alpha *= VFXGetTextureColor(VFX_SAMPLER(baseColorMap),i).a; + #endif + #if VFX_MATERIAL_TYPE_SIX_WAY_SMOKE + #ifndef VFX_VARYING_NORMAL + const VFXUVData uvData = GetUVData(i); + #endif + alpha *= SampleTexture(VFX_SAMPLER(positiveAxesLightmap),uvData).a; + #if VFX_SIX_WAY_USE_ALPHA_REMAP + alpha = SampleCurve(i.VFX_VARYING_ALPHA_REMAP, alpha); + #endif + #endif + #endif + VFXClipFragmentColor(alpha,i); + + #ifdef WRITE_NORMAL_BUFFER + #ifndef VFX_SHADERGRAPH + VFXComputePixelOutputToNormalBuffer(i,normalWS,uvData,outNormalBuffer); + #else + #if HAS_SHADERGRAPH_PARAM_NORMAL + float3 n = OUTSG.Normal_8; + normalWS = mul(n,tbn); + #endif + SurfaceData surface = (SurfaceData)0; + surface.normalWS = normalWS; + EncodeIntoNormalBuffer(ConvertSurfaceDataToNormalData(surface), outNormalBuffer); + #endif + #endif + + #ifdef WRITE_MSAA_DEPTH + outDepthColor = i.VFX_VARYING_POSCS.z; + #if VFX_USE_ALPHA_TO_MASK + outDepthColor.a = alpha; + #endif + #endif + + #if VFX_PASSDEPTH == VFX_PASSDEPTH_MOTION_VECTOR + ${VFXComputeOutputMotionVector} + outMotionVector = encodedMotionVector; + #elif VFX_PASSDEPTH == VFX_PASSDEPTH_SELECTION + // We use depth prepass for scene selection in the editor, this code allow to output the outline correctly + outColor = float4(_ObjectId, _PassValue, 1.0, 1.0); + #elif VFX_PASSDEPTH == VFX_PASSDEPTH_PICKING + outColor = _SelectionID; + #elif VFX_PASSDEPTH == VFX_PASSDEPTH_ACTUAL + //void + #elif VFX_PASSDEPTH == VFX_PASSDEPTH_SHADOW + //void + #else + #error VFX_PASSDEPTH undefined + #endif +} diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/VFXPassDepthCommonFragmentLit.template.meta b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/VFXPassDepthCommonFragmentLit.template.meta new file mode 100644 index 00000000000..54c62fd312a --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/VFXPassDepthCommonFragmentLit.template.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 897583fdf4fd456992f4162e0c64ceb2 +timeCreated: 1720611237 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXLitVaryings.template b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXLitVaryings.template index 93f1da5dce7..6ee83352b64 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXLitVaryings.template +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXLitVaryings.template @@ -1,6 +1,7 @@ #define HDRP_NEEDS_UVS (HDRP_USE_BASE_COLOR_MAP || HDRP_USE_MASK_MAP || USE_NORMAL_MAP || HDRP_USE_EMISSIVE_MAP) #define HDRP_USE_EMISSIVE (HDRP_USE_EMISSIVE_MAP || HDRP_USE_EMISSIVE_COLOR || HDRP_USE_ADDITIONAL_EMISSIVE_COLOR) +${VFXIncludeRP("VFXVertexProbeSampling.template"), VFX_MATERIAL_TYPE_SIX_WAY_SMOKE} ${VFXInclude("Shaders/SixWay/SixWayVaryings.template"), VFX_MATERIAL_TYPE_SIX_WAY_SMOKE} ${VFXBegin:VFXHDRPLitVaryingsMacros} diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXPasses.template b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXPasses.template index 1ce02c7d304..e88ce588060 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXPasses.template +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXPasses.template @@ -22,139 +22,6 @@ ${VFXBegin:VFXPassDepthAdditionalPragma}#pragma multi_compile _ WRITE_MSAA_DEPTH ${VFXBegin:VFXPassForwardAdditionalPragma}#pragma multi_compile _ DEBUG_DISPLAY${VFXEnd} ${VFXBegin:VFXPassVelocityAdditionalPragma}#pragma multi_compile _ WRITE_MSAA_DEPTH${VFXEnd} -${VFXBegin:VFXShaderGraphFunctionsInclude} -#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" -#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Texture.hlsl" -#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl" -#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" -#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlsl" -#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/BuiltinGIUtilities.hlsl" -#ifndef SHADERPASS -#error Shaderpass should be defined at this stage. -#endif -#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderGraphFunctions.hlsl" -${VFXEnd} - -${VFXBegin:VFXPassDepthCommonFragmentLit} -#if VFX_PASSDEPTH == VFX_PASSDEPTH_MOTION_VECTOR -${VFXPassVelocityDefine} -#elif VFX_PASSDEPTH == VFX_PASSDEPTH_SHADOW -${VFXPassShadowDefine} -#else -${VFXPassDepthDefine} -#endif -${VFXIncludeRP("VFXLit.template")} - -${SHADERGRAPH_PIXEL_CODE_DEPTHONLY} - -#if VFX_PASSDEPTH == VFX_PASSDEPTH_SELECTION -int _ObjectId; -int _PassValue; -#elif VFX_PASSDEPTH == VFX_PASSDEPTH_PICKING -float4 _SelectionID; -#endif - -#pragma fragment frag -void frag(ps_input i -#if USE_DOUBLE_SIDED - , bool frontFace : SV_IsFrontFace -#endif -#if VFX_PASSDEPTH == VFX_PASSDEPTH_MOTION_VECTOR - #ifdef WRITE_MSAA_DEPTH - // We need the depth color as SV_Target0 for alpha to coverage - , out float4 outDepthColor : SV_Target0 - , out float4 outMotionVector : SV_Target1 - #ifdef WRITE_NORMAL_BUFFER - , out float4 outNormalBuffer : SV_Target2 - #endif - #else - // When no MSAA, the motion vector is always the first buffer - , out float4 outMotionVector : SV_Target0 - #ifdef WRITE_NORMAL_BUFFER - , out float4 outNormalBuffer : SV_Target1 - #endif - #endif -#elif VFX_PASSDEPTH == VFX_PASSDEPTH_ACTUAL - #ifdef WRITE_MSAA_DEPTH - // We need the depth color as SV_Target0 for alpha to coverage - , out float4 outDepthColor : SV_Target0 - #ifdef WRITE_NORMAL_BUFFER - , out float4 outNormalBuffer : SV_Target1 - #endif - #elif defined(WRITE_NORMAL_BUFFER) - , out float4 outNormalBuffer : SV_Target0 - #endif -#elif VFX_PASSDEPTH == VFX_PASSDEPTH_SELECTION || VFX_PASSDEPTH == VFX_PASSDEPTH_PICKING - , out float4 outColor : SV_Target0 -#endif -) -{ - UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); - VFXTransformPSInputs(i); - ${VFXComputeNormalWS} - - #ifdef VFX_SHADERGRAPH - ${VFXAdditionalInterpolantsPreparation} - ${SHADERGRAPH_PIXEL_CALL_DEPTHONLY} - float alpha = OUTSG.${SHADERGRAPH_PARAM_ALPHA}; - #else - - float alpha = VFXGetFragmentColor(i).a; - - #if HDRP_USE_BASE_COLOR_MAP_ALPHA - alpha *= VFXGetTextureColor(VFX_SAMPLER(baseColorMap),i).a; - #endif - #if VFX_MATERIAL_TYPE_SIX_WAY_SMOKE - #ifndef VFX_VARYING_NORMAL - const VFXUVData uvData = GetUVData(i); - #endif - alpha *= SampleTexture(VFX_SAMPLER(positiveAxesLightmap),uvData).a; - #if VFX_SIX_WAY_USE_ALPHA_REMAP - alpha = SampleCurve(i.VFX_VARYING_ALPHA_REMAP, alpha); - #endif - #endif - #endif - VFXClipFragmentColor(alpha,i); - - #ifdef WRITE_NORMAL_BUFFER - #ifndef VFX_SHADERGRAPH - VFXComputePixelOutputToNormalBuffer(i,normalWS,uvData,outNormalBuffer); - #else - #if HAS_SHADERGRAPH_PARAM_NORMAL - float3 n = OUTSG.Normal_8; - normalWS = mul(n,tbn); - #endif - SurfaceData surface = (SurfaceData)0; - surface.normalWS = normalWS; - EncodeIntoNormalBuffer(ConvertSurfaceDataToNormalData(surface), outNormalBuffer); - #endif - #endif - - #ifdef WRITE_MSAA_DEPTH - outDepthColor = i.VFX_VARYING_POSCS.z; - #if VFX_USE_ALPHA_TO_MASK - outDepthColor.a = alpha; - #endif - #endif - - #if VFX_PASSDEPTH == VFX_PASSDEPTH_MOTION_VECTOR - ${VFXComputeOutputMotionVector} - outMotionVector = encodedMotionVector; - #elif VFX_PASSDEPTH == VFX_PASSDEPTH_SELECTION - // We use depth prepass for scene selection in the editor, this code allow to output the outline correctly - outColor = float4(_ObjectId, _PassValue, 1.0, 1.0); - #elif VFX_PASSDEPTH == VFX_PASSDEPTH_PICKING - outColor = _SelectionID; - #elif VFX_PASSDEPTH == VFX_PASSDEPTH_ACTUAL - //void - #elif VFX_PASSDEPTH == VFX_PASSDEPTH_SHADOW - //void - #else - #error VFX_PASSDEPTH undefined - #endif -} -${VFXEnd} - ${VFXBegin:VFXPassFullScreenDebugCommonVertex} #if !defined(SHADER_API_METAL) if (_DebugFullScreenMode == FULLSCREENDEBUGMODE_VERTEX_DENSITY) @@ -174,7 +41,7 @@ ${VFXBegin:VFXPassFullScreenDebugCommonFragment} UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); VFXTransformPSInputs(i); VFX_FRAG_SETUP_INSTANCE_ID(i); - + #ifdef PLATFORM_SUPPORTS_PRIMITIVE_ID_IN_PIXEL_SHADER if (_DebugFullScreenMode == FULLSCREENDEBUGMODE_QUAD_OVERDRAW) { diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXSixWayIncludes.template b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXSixWayIncludes.template new file mode 100644 index 00000000000..c0168dcaf0a --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXSixWayIncludes.template @@ -0,0 +1,6 @@ +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Material.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Lighting.hlsl" +#define HAS_LIGHTLOOP +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoopDef.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SixWayLit/SixWaySmokeLit.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.hlsl" diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXSixWayIncludes.template.meta b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXSixWayIncludes.template.meta new file mode 100644 index 00000000000..8b356853aa1 --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXSixWayIncludes.template.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c85765940feb499eb9a99878c4c7eea6 +timeCreated: 1720611358 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXVertexProbeSampling.template b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXVertexProbeSampling.template index ef731b899e7..677c8516037 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXVertexProbeSampling.template +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/VFXVertexProbeSampling.template @@ -26,13 +26,3 @@ float4 inTangent = o.VFX_VARYING_TANGENT; o.VFX_VARYING_BAKE_DIFFUSE_LIGHTING[2]); #endif ${VFXEnd} - - -#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Material.hlsl" -#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Lighting.hlsl" -#define HAS_LIGHTLOOP -#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoopDef.hlsl" -#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SixWayLit/SixWaySmokeLit.hlsl" -#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.hlsl" - - diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Wizard/HDWizard.UserSettings.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Wizard/HDWizard.UserSettings.cs index 198b21763c8..f69d0c220c4 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Wizard/HDWizard.UserSettings.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Wizard/HDWizard.UserSettings.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using UnityEditorInternal; using UnityEngine; namespace UnityEditor.Rendering.HighDefinition @@ -81,7 +82,13 @@ public static bool wizardNeedRestartAfterChangingToDX12 public static bool wizardIsStartPopup { - get => instance.m_WizardPopupAtStart; + get + { + if (!InternalEditorUtility.isHumanControllingUs || AssetDatabase.IsAssetImportWorkerProcess()) + return false; + + return instance.m_WizardPopupAtStart; + } set { instance.m_WizardPopupAtStart = value; diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Compositor/CompositionLayer.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Compositor/CompositionLayer.cs index c75a63ad8e0..5e2e61e2809 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Compositor/CompositionLayer.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Compositor/CompositionLayer.cs @@ -247,7 +247,7 @@ public void Init(string layerID = "", bool allowUndo = false) // - is not shared between layers // - is not used in an mage/video layer (in this case the camera is not exposed at all, so it makes sense to let the compositor manage it) // - it does not force-clear the RT (the first layer of a stack, even if disabled by the user), still clears the RT - bool shouldClear = !enabled && m_LayerPositionInStack == 0 && m_Camera; + bool shouldClear = m_LayerPositionInStack == 0 && m_Camera; bool isImageOrVideo = (m_Type == LayerType.Image || m_Type == LayerType.Video); if (!isImageOrVideo && !hasLayerOverrides && !shouldClear && !compositor.IsThisCameraShared(m_Camera)) { @@ -287,7 +287,7 @@ public void Init(string layerID = "", bool allowUndo = false) if (m_OutputTarget != OutputTarget.CameraStack && m_RenderTarget == null) { // If we don't have a valid camera (zero width or height) avoid creating the RT - if (compositor.outputCamera.pixelWidth > 0 && compositor.outputCamera.pixelHeight > 0) + if (compositor.outputCamera && compositor.outputCamera.pixelWidth > 0 && compositor.outputCamera.pixelHeight > 0) { float resScale = EnumToScale(m_ResolutionScale); int scaledWidth = (int)(resScale * compositor.outputCamera.pixelWidth); @@ -615,15 +615,19 @@ public void SetupClearColor() { if (m_LayerCamera && m_Camera) { - m_LayerCamera.enabled = true; - m_LayerCamera.cullingMask = 0; var cameraData = m_LayerCamera.GetComponent(); var cameraDataOrig = m_Camera.GetComponent(); - cameraData.clearColorMode = cameraDataOrig.clearColorMode; - cameraData.clearDepth = true; + if (cameraData && cameraDataOrig) + { + m_LayerCamera.enabled = true; + m_LayerCamera.cullingMask = 0; + + cameraData.clearColorMode = cameraDataOrig.clearColorMode; + cameraData.clearDepth = true; - m_ClearsBackGround = true; + m_ClearsBackGround = true; + } } } 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 c8173c9842c..1c5c84ccc5f 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 @@ -272,7 +272,7 @@ public partial class DebugDisplaySettings : IDebugData static GUIContent[] s_RenderingMipmapDebugMaterialTextureSlotStrings = null; static int[] s_RenderingMipmapDebugMaterialTextureSlotValues = null; - static List s_CameraNames = new List(); + static List s_CameraNames = new List() { new("None") }; static GUIContent[] s_CameraNamesStrings = { new ("No Visible Camera") }; static int[] s_CameraNamesValues = { 0 }; @@ -2289,8 +2289,6 @@ internal void UpdateCameraFreezeOptions() { if (needsRefreshingCameraFreezeList) { - s_CameraNames.Insert(0, new GUIContent("None")); - s_CameraNamesStrings = s_CameraNames.ToArray(); s_CameraNamesValues = Enumerable.Range(0, s_CameraNames.Count()).ToArray(); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Light/HDAdditionalLightData.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Light/HDAdditionalLightData.cs index f61e54ba8ce..2342bb73623 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Light/HDAdditionalLightData.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Light/HDAdditionalLightData.cs @@ -3347,7 +3347,7 @@ internal void UpdateAllLightValues(bool fromTimeLine) internal void RefreshCachedShadow() { bool wentThroughCachedShadowSystem = lightIdxForCachedShadows >= 0; - if (wentThroughCachedShadowSystem) + if (!preserveCachedShadow && wentThroughCachedShadowSystem) HDShadowManager.cachedShadowManager.EvictLight(this, legacyLight.type); RegisterCachedShadowLightOptional(); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.hlsl index 1d161358578..bfc959234ea 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.hlsl @@ -192,6 +192,9 @@ void LightLoop( float3 V, PositionInputs posInput, PreLightData preLightData, BS // With XR single-pass and camera-relative: offset position to do lighting computations from the combined center view (original camera matrix). // This is required because there is only one list of lights generated on the CPU. Shadows are also generated once and shared between the instanced views. + // We keep the unmodified per-eye position around since we use it to sample APV. Passing the modified world space position to GetAbsolutePositionWS after + // this point would give incorrect results. + float3 unmodifiedPositionWS = posInput.positionWS; ApplyCameraRelativeXR(posInput.positionWS); LightLoopContext context; @@ -477,7 +480,7 @@ void LightLoop( float3 V, PositionInputs posInput, PreLightData preLightData, BS // Reflect normal to get lighting for reflection probe tinting float3 R = reflect(-V, bsdfData.normalWS); - EvaluateAdaptiveProbeVolume(GetAbsolutePositionWS(posInput.positionWS), + EvaluateAdaptiveProbeVolume(GetAbsolutePositionWS(unmodifiedPositionWS), bsdfData.normalWS, -bsdfData.normalWS, R, diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricClouds/HDRenderPipeline.VolumetricClouds.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricClouds/HDRenderPipeline.VolumetricClouds.cs index 4f9d1543dd0..e9b32a04a78 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricClouds/HDRenderPipeline.VolumetricClouds.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricClouds/HDRenderPipeline.VolumetricClouds.cs @@ -591,7 +591,7 @@ internal void CombineVolumetricClouds(RenderGraph renderGraph, HDCamera hdCamera if (passData.perPixelSorting) { - builder.UseDepthBuffer(transparentPrepass.beforeRefraction, DepthAccess.Read); // Dummy buffer to avoid 'Setting MRT without a depth buffer is not supported' + builder.UseDepthBuffer(transparentPrepass.depthBufferPreRefraction, DepthAccess.Read); // Dummy buffer to avoid 'Setting MRT without a depth buffer is not supported' builder.UseColorBuffer(transparentPrepass.beforeRefraction, 1); builder.UseColorBuffer(transparentPrepass.beforeRefractionAlpha, 2); opticalFogBufferIndex = 3; @@ -604,6 +604,7 @@ internal void CombineVolumetricClouds(RenderGraph renderGraph, HDCamera hdCamera { if (!opticalFogTransmittance.IsValid()) opticalFogTransmittance = renderGraph.CreateTexture(HDRenderPipeline.GetOpticalFogTransmittanceDesc(hdCamera)); + builder.UseDepthBuffer(transparentPrepass.depthBufferPreRefraction, DepthAccess.Read); // Dummy buffer to avoid 'Setting MRT without a depth buffer is not supported' builder.UseColorBuffer(opticalFogTransmittance, opticalFogBufferIndex); } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/DiffusionProfile/DiffusionProfileSettings.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/DiffusionProfile/DiffusionProfileSettings.cs index c9e63dabda7..564ea5a0960 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/DiffusionProfile/DiffusionProfileSettings.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/DiffusionProfile/DiffusionProfileSettings.cs @@ -64,6 +64,9 @@ public enum TransmissionMode : uint public float lobeMix; [Range(1.0f, 3.0f), Tooltip("Exponent on the cosine component of the diffuse lobe.\nHelps to simulate surfaces with strong subsurface scattering.")] public float diffuseShadingPower; + [ColorUsage(false, false)] + [Tooltip("The color used when a subsurface scattering sample encounters a border. A border is defined by a material not having the same diffusion profile.")] + public Color borderAttenuationColor; public TransmissionMode transmissionMode; public Vector2 thicknessRemap; // X = min, Y = max (in millimeters) public float worldScale; // Size of the world unit in meters @@ -95,6 +98,7 @@ public void ResetToDefault() thicknessRemap = new Vector2(0f, 5f); worldScale = 1f; ior = 1.4f; // Typical value for skin specular reflectance + borderAttenuationColor = Color.black; } internal void Validate() @@ -228,6 +232,7 @@ public bool Equals(DiffusionProfile other) transmissionTint == other.transmissionTint && texturingMode == other.texturingMode && transmissionMode == other.transmissionMode && + borderAttenuationColor == other.borderAttenuationColor && thicknessRemap == other.thicknessRemap && worldScale == other.worldScale && ior == other.ior; @@ -249,6 +254,7 @@ public partial class DiffusionProfileSettings : ScriptableObject [NonSerialized] internal Vector4 transmissionTintAndFresnel0; // RGB = color, A = fresnel0 [NonSerialized] internal Vector4 disabledTransmissionTintAndFresnel0; // RGB = black, A = fresnel0 - For debug to remove the transmission [NonSerialized] internal Vector4 dualLobeAndDiffusePower; // R = Smoothness A, G = Smoothness B, B = Lobe Mix, A = Diffuse Power - 1 (to have 0 as neutral value) + [NonSerialized] internal Vector4 borderAttenuationColorMultiplier; // RGB = color, A = not used [NonSerialized] internal int updateCount; /// @@ -335,6 +341,17 @@ public Color transmissionTint set { profile.transmissionTint = value; profile.Validate(); UpdateCache(); } } + /// + /// Color used when the diffusion profile samples encounters a different diffusion profile index. + /// Setting this color to black have the same effect as occluding the subsurface scattering. + /// This property only works if the "Support Border Attenuation" property is enabled in the HDRP asset. + /// + public Color borderAttenuationColor + { + get => profile.borderAttenuationColor; + set { profile.borderAttenuationColor = value; profile.Validate(); UpdateCache(); } + } + void OnEnable() { if (profile == null) @@ -387,6 +404,7 @@ internal void UpdateCache() disabledTransmissionTintAndFresnel0 = new Vector4(0.0f, 0.0f, 0.0f, fresnel0); float smoothnessB = profile.lobeMix == 0.0f ? 1.0f : profile.smoothnessMultipliers.y; // this helps shader determine if dual lobe is active dualLobeAndDiffusePower = new Vector4(profile.smoothnessMultipliers.x, smoothnessB, profile.lobeMix, profile.diffuseShadingPower - 1.0f); + borderAttenuationColorMultiplier = profile.borderAttenuationColor; updateCount++; } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Hair/Hair.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Hair/Hair.hlsl index 53baba429c3..38c4f586024 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Hair/Hair.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Hair/Hair.hlsl @@ -595,8 +595,9 @@ void GetHairAngleLocal(float3 wo, float3 wi, inout HairAngle angles) void GetHairAngleWorld(float3 V, float3 L, float3 T, inout HairAngle angles) { - angles.sinThetaO = dot(T, V); - angles.sinThetaI = dot(T, L); + // It might exceed the range [-1, 1], so explicitly clamp here to prevent nan output from FastASin. + angles.sinThetaO = clamp(dot(T, V), -1.0, 1.0); + angles.sinThetaI = clamp(dot(T, L), -1.0, 1.0); half thetaO = FastASin(angles.sinThetaO); half thetaI = FastASin(angles.sinThetaI); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/LayeredLit/LayeredLitData.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/LayeredLit/LayeredLitData.hlsl index a0c055f3ca9..ccf39a8e4e4 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/LayeredLit/LayeredLitData.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/LayeredLit/LayeredLitData.hlsl @@ -783,7 +783,8 @@ void GetSurfaceAndBuiltinData(FragInputs input, float3 V, inout PositionInputs p surfaceData.materialFeatures = MATERIALFEATUREFLAGS_LIT_STANDARD; #ifdef _MATERIAL_FEATURE_SUBSURFACE_SCATTERING - surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_LIT_SUBSURFACE_SCATTERING; + if (surfaceData.subsurfaceMask > 0) + surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_LIT_SUBSURFACE_SCATTERING; #endif #ifdef _MATERIAL_FEATURE_TRANSMISSION surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_LIT_TRANSMISSION; diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.hlsl index 305b47e6e3f..fb73c092f7a 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.hlsl @@ -585,6 +585,10 @@ void EncodeIntoGBuffer( SurfaceData surfaceData float encodedSpecularOcclusion = surfaceData.specularOcclusion; #endif + // Remove SSS in case the mask is 0 + if (surfaceData.subsurfaceMask == 0) + surfaceData.materialFeatures &= ~(MATERIALFEATUREFLAGS_LIT_SUBSURFACE_SCATTERING); + // Ensure that surfaceData.coatMask is 0 if the feature is not enabled // Warning: overriden by Translucent if using a transmission tint float coatMask = HasFlag(surfaceData.materialFeatures, MATERIALFEATUREFLAGS_LIT_CLEAR_COAT) ? surfaceData.coatMask : 0.0; @@ -909,13 +913,7 @@ uint DecodeFromGBuffer(uint2 positionSS, uint tileFeatureFlags, out BSDFData bsd SSSData sssData; float transmissionMask; - #ifdef DEBUG_DISPLAY - // Note that we don't use sssData.subsurfaceMask here. But it is still assign so we can have - // the information in the material debug view. UnpackFloatInt8bit(inGBuffer0.a, 16, sssData.subsurfaceMask, sssData.diffusionProfileIndex); - #else - sssData.subsurfaceMask = 0.0f; // Initialize to prevent compiler error, but value is never used - #endif // We read profile from G-Buffer 2 so the compiler can optimize away the read from the G-Buffer 0 to the very end (in PostEvaluateBSDF) // When using translucency, we exchange diffusion profile and coat mask diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitDataIndividualLayer.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitDataIndividualLayer.hlsl index 40d31a37686..8fda2e5454f 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitDataIndividualLayer.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitDataIndividualLayer.hlsl @@ -290,7 +290,8 @@ float ADD_IDX(GetSurfaceData)(FragInputs input, LayerTexCoord layerTexCoord, out surfaceData.materialFeatures = MATERIALFEATUREFLAGS_LIT_STANDARD; #ifdef _MATERIAL_FEATURE_SUBSURFACE_SCATTERING - surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_LIT_SUBSURFACE_SCATTERING; + if (surfaceData.subsurfaceMask > 0) + surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_LIT_SUBSURFACE_SCATTERING; #endif #ifdef _MATERIAL_FEATURE_TRANSMISSION surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_LIT_TRANSMISSION; diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SubsurfaceScattering/CombineLighting.shader b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SubsurfaceScattering/CombineLighting.shader index 795922a763e..b2ae0f27954 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SubsurfaceScattering/CombineLighting.shader +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SubsurfaceScattering/CombineLighting.shader @@ -64,7 +64,9 @@ Shader "Hidden/HDRP/CombineLighting" float4 Frag(Varyings input) : SV_Target { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); - return LOAD_TEXTURE2D_X(_IrradianceSource, input.positionCS.xy); + float3 color = LOAD_TEXTURE2D_X(_IrradianceSource, input.positionCS.xy).rgb; + // avoid to additive blend the alpha which tends to make it above 1 and cause issues in later passes. + return float4(color, 0); } ENDHLSL } @@ -88,7 +90,9 @@ Shader "Hidden/HDRP/CombineLighting" float4 Frag(Varyings input) : SV_Target { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); - return LOAD_TEXTURE2D_X(_IrradianceSource, input.positionCS.xy) * GetCurrentExposureMultiplier(); + float3 color = LOAD_TEXTURE2D_X(_IrradianceSource, input.positionCS.xy).rgb * GetCurrentExposureMultiplier(); + // avoid to additive blend the alpha which tends to make it above 1 and cause issues in later passes. + return float4(color, 0); } ENDHLSL } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SubsurfaceScattering/SubsurfaceScattering.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SubsurfaceScattering/SubsurfaceScattering.compute index 54c7aaf7439..fb712f0dcde 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SubsurfaceScattering/SubsurfaceScattering.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SubsurfaceScattering/SubsurfaceScattering.compute @@ -8,9 +8,11 @@ #pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch #pragma kernel SubsurfaceScattering +#pragma kernel PackDiffusionProfile PACK_DIFFUSION_PROFILE #pragma multi_compile _ ENABLE_MSAA #pragma multi_compile _ USE_DOWNSAMPLE +#pragma multi_compile _ USE_SSS_OCCLUSION // TODO: use sharp load hoisting on PS4. @@ -71,6 +73,12 @@ StructuredBuffer _CoarseStencilBuffer; RW_TEXTURE2D_X(float4, _CameraColorTexture); // Target texture #endif +#ifdef PACK_DIFFUSION_PROFILE + RW_TEXTURE2D_X(uint, _DiffusionProfileIndexTexture); +#else + TYPED_TEXTURE2D_X(uint, _DiffusionProfileIndexTexture); +#endif + //-------------------------------------------------------------------------------------------------- // Implementation //-------------------------------------------------------------------------------------------------- @@ -187,9 +195,31 @@ struct DebugInfo #endif }; +bool SameProfiles(uint sampleProfileIndex, uint currentProfileIndex) +{ +#ifdef USE_SSS_OCCLUSION + return sampleProfileIndex == currentProfileIndex; +#endif + return true; +} + +int GetDiffusionProfileIndexAtPosition(int2 position) +{ + uint p = LOAD_TEXTURE2D_X_LOD(_DiffusionProfileIndexTexture, uint2(position.x >> 1, position.y), 0); + int sampleProfileIndex; + + if ((position.x & 1) == 0) + sampleProfileIndex = p & 0xF; + else + sampleProfileIndex = p >> 4; + + return sampleProfileIndex; +} + void EvaluateSample(uint i, uint n, int2 pixelCoord, int2 cacheOffset, float3 S, float d, float3 centerPosVS, float mmPerUnit, float pixelsPerMm, - float phase, float3 tangentX, float3 tangentY, float4x4 projMatrix, float linearDepth, inout DebugInfo debugInfo, + float phase, float3 tangentX, float3 tangentY, float4x4 projMatrix, float linearDepth, + int currentProfileIndex, float3 borderAttenuationColor, inout DebugInfo debugInfo, inout float3 totalIrradiance, inout float3 totalWeight) { // The sample count is loop-invariant. @@ -234,17 +264,33 @@ void EvaluateSample(uint i, uint n, int2 pixelCoord, int2 cacheOffset, float4 textureSample = LoadSample(position, cacheOffset); float3 irradiance = textureSample.rgb; + // Compute bilateral weighting. + float viewZ = textureSample.a; + float relZ = viewZ - linearDepth; + float3 weight = ComputeBilateralWeight(xy2, relZ, mmPerUnit, S, rcpPdf); + + // For the SSS Occlusion, we take in account all the samples as weight + // This is required if we want darkening on zones where less samples are available due to masking. + #if USE_SSS_OCCLUSION + totalWeight += weight; + #endif + // Check the results of the stencil test. if (TestLightingForSSS(irradiance)) { - // Apply bilateral weighting. - float viewZ = textureSample.a; - float relZ = viewZ - linearDepth; - float3 weight = ComputeBilateralWeight(xy2, relZ, mmPerUnit, S, rcpPdf); - - // Note: if the texture sample if off-screen, (z = 0) -> (viewZ = far) -> (weight ≈ 0). - totalIrradiance += weight * irradiance; - totalWeight += weight; + int sampleProfileIndex = GetDiffusionProfileIndexAtPosition(position); + if (SameProfiles(sampleProfileIndex, currentProfileIndex)) + { + // Note: if the texture sample if off-screen, (z = 0) -> (viewZ = far) -> (weight ≈ 0). + totalIrradiance += weight * irradiance; + #if !USE_SSS_OCCLUSION + totalWeight += weight; + #endif + } + else + { + totalIrradiance += weight * irradiance * borderAttenuationColor; + } } else { @@ -302,6 +348,7 @@ void EvaluateSss(uint2 pixelCoord, CacheInfo cacheInfo, CenterInfo centerInfo, i float distScale = sssData.subsurfaceMask; float3 S = _ShapeParamsAndMaxScatterDists[profileIndex].rgb; float d = _ShapeParamsAndMaxScatterDists[profileIndex].a; + float3 borderAttenuationColor = _BorderAttenuationColor[profileIndex].rgb; float metersPerUnit = _WorldScalesAndFilterRadiiAndThicknessRemaps[profileIndex].x; float filterRadius = _WorldScalesAndFilterRadiiAndThicknessRemaps[profileIndex].y; // In millimeters @@ -393,8 +440,8 @@ void EvaluateSss(uint2 pixelCoord, CacheInfo cacheInfo, CenterInfo centerInfo, i // Integrate over the image or tangent plane in the view space. EvaluateSample(i, n, pixelCoord, cacheInfo.cacheOffset, S, d, centerPosVS, mmPerUnit, pixelsPerMm, - phase, tangentX, tangentY, projMatrix, linearDepth, debugInfo, - totalIrradiance, totalWeight); + phase, tangentX, tangentY, projMatrix, linearDepth, profileIndex, + borderAttenuationColor, debugInfo, totalIrradiance, totalWeight); } // Total weight is 0 for color channels without scattering. @@ -459,7 +506,9 @@ void SubsurfaceScattering(uint3 groupId : SV_GroupID, bool passedStencilTest = TestLightingForSSS(centerInfo.irradiance); // Save some bandwidth by only loading depth values for SSS pixels. +#if !USE_SSS_OCCLUSION // When Occlusion is enabled we need all the samples in the cache to be valid. if (passedStencilTest) +#endif { centerInfo.depth = LOAD_TEXTURE2D_X(_DepthTexture, pixelCoord).r; } @@ -559,3 +608,27 @@ void SubsurfaceScattering(uint3 groupId : SV_GroupID, StoreResult(pixelCoord, irradiance); } + +#ifdef PACK_DIFFUSION_PROFILE +[numthreads(8, 8, 1)] +void PackDiffusionProfile(uint3 groupId : SV_GroupID, + uint groupThreadId : SV_GroupThreadID, + uint3 dispatchThreadId : SV_DispatchThreadID) +{ + + UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z); + uint2 pixelCoord0 = uint2(dispatchThreadId.x * 2, dispatchThreadId.y); + uint2 pixelCoord1 = pixelCoord0 + uint2(1, 0); + uint packedProfiles = 0; + + // The result of the stencil test allows us to statically determine the material type (SSS). + SSSData sssData; + DECODE_FROM_SSSBUFFER(pixelCoord0, sssData); + packedProfiles |= sssData.diffusionProfileIndex & 0xF; + + DECODE_FROM_SSSBUFFER(pixelCoord1, sssData); + packedProfiles |= (sssData.diffusionProfileIndex & 0xF) << 4; + + _DiffusionProfileIndexTexture[COORD_TEXTURE2D_X(dispatchThreadId.xy)] = packedProfiles; +} +#endif diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SubsurfaceScattering/SubsurfaceScattering.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SubsurfaceScattering/SubsurfaceScattering.hlsl index 72f9b6cec40..c40f147f4bc 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SubsurfaceScattering/SubsurfaceScattering.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SubsurfaceScattering/SubsurfaceScattering.hlsl @@ -174,7 +174,8 @@ void FillMaterialSSS(uint diffusionProfileIndex, float subsurfaceMask, inout BSD bsdfData.diffusionProfileIndex = diffusionProfileIndex; bsdfData.fresnel0 = _TransmissionTintsAndFresnel0[diffusionProfileIndex].a; bsdfData.subsurfaceMask = subsurfaceMask; - bsdfData.materialFeatures |= MATERIALFEATUREFLAGS_SSS_OUTPUT_SPLIT_LIGHTING; + if (subsurfaceMask != 0) + bsdfData.materialFeatures |= MATERIALFEATUREFLAGS_SSS_OUTPUT_SPLIT_LIGHTING; bsdfData.materialFeatures |= GetSubsurfaceScatteringTexturingMode(diffusionProfileIndex) << MATERIALFEATUREFLAGS_SSS_TEXTURING_MODE_OFFSET; } @@ -186,8 +187,15 @@ bool ShouldOutputSplitLighting(BSDFData bsdfData) float3 GetModifiedDiffuseColorForSSS(BSDFData bsdfData) { // Subsurface scattering mode - uint texturingMode = (bsdfData.materialFeatures >> MATERIALFEATUREFLAGS_SSS_TEXTURING_MODE_OFFSET) & 3; - return ApplySubsurfaceScatteringTexturingMode(texturingMode, bsdfData.diffuseColor); + if (bsdfData.subsurfaceMask != 0) + { + uint texturingMode = (bsdfData.materialFeatures >> MATERIALFEATUREFLAGS_SSS_TEXTURING_MODE_OFFSET) & 3; + return ApplySubsurfaceScatteringTexturingMode(texturingMode, bsdfData.diffuseColor); + } + else + { + return bsdfData.diffuseColor; + } } bool GetDualLobeParameters(uint diffusionProfileIndex, out float multiplierA, out float multiplierB, out float lobeMix) diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.SubsurfaceScattering.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.SubsurfaceScattering.cs index c23c8b10c20..81d881bd977 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.SubsurfaceScattering.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.SubsurfaceScattering.cs @@ -9,6 +9,7 @@ public partial class HDRenderPipeline ComputeShader m_SubsurfaceScatteringCS; ComputeShader m_SubsurfaceScatteringDownsampleCS; int m_SubsurfaceScatteringKernel; + int m_PackDiffusionProfileKernel; int m_SubsurfaceScatteringKernelMSAA; int m_SubsurfaceScatteringDownsampleKernel; Material m_CombineLightingPass; @@ -23,6 +24,7 @@ public partial class HDRenderPipeline Vector4[] m_SSSDisabledTransmissionTintsAndFresnel0; Vector4[] m_SSSWorldScalesAndFilterRadiiAndThicknessRemaps; Vector4[] m_SSSDualLobeAndDiffusePower; + Vector4[] m_SSSBorderAttenuationColor; uint[] m_SSSDiffusionProfileHashes; int[] m_SSSDiffusionProfileUpdate; DiffusionProfileSettings[] m_SSSSetDiffusionProfiles; @@ -37,6 +39,7 @@ void InitializeSubsurfaceScattering() string kernelName = "SubsurfaceScattering"; m_SubsurfaceScatteringCS = runtimeShaders.subsurfaceScatteringCS; m_SubsurfaceScatteringKernel = m_SubsurfaceScatteringCS.FindKernel(kernelName); + m_PackDiffusionProfileKernel = m_SubsurfaceScatteringCS.FindKernel("PackDiffusionProfile"); m_SubsurfaceScatteringDownsampleCS = runtimeShaders.subsurfaceScatteringDownsampleCS; m_SubsurfaceScatteringDownsampleKernel = m_SubsurfaceScatteringDownsampleCS.FindKernel("Downsample"); @@ -57,6 +60,7 @@ void InitializeSubsurfaceScattering() m_SSSDisabledTransmissionTintsAndFresnel0 = new Vector4[DiffusionProfileConstants.DIFFUSION_PROFILE_COUNT]; m_SSSWorldScalesAndFilterRadiiAndThicknessRemaps = new Vector4[DiffusionProfileConstants.DIFFUSION_PROFILE_COUNT]; m_SSSDualLobeAndDiffusePower = new Vector4[DiffusionProfileConstants.DIFFUSION_PROFILE_COUNT]; + m_SSSBorderAttenuationColor = new Vector4[DiffusionProfileConstants.DIFFUSION_PROFILE_COUNT]; m_SSSDiffusionProfileHashes = new uint[DiffusionProfileConstants.DIFFUSION_PROFILE_COUNT]; m_SSSDiffusionProfileUpdate = new int[DiffusionProfileConstants.DIFFUSION_PROFILE_COUNT]; m_SSSSetDiffusionProfiles = new DiffusionProfileSettings[DiffusionProfileConstants.DIFFUSION_PROFILE_COUNT]; @@ -109,6 +113,7 @@ void SetDiffusionProfileAtIndex(DiffusionProfileSettings settings, int index) m_SSSDisabledTransmissionTintsAndFresnel0[index] = settings.disabledTransmissionTintAndFresnel0; m_SSSWorldScalesAndFilterRadiiAndThicknessRemaps[index] = settings.worldScaleAndFilterRadiusAndThicknessRemap; m_SSSDualLobeAndDiffusePower[index] = settings.dualLobeAndDiffusePower; + m_SSSBorderAttenuationColor[index] = settings.borderAttenuationColor; m_SSSDiffusionProfileHashes[index] = settings.profile.hash; // Erase previous value (This need to be done here individually as in the SSS editor we edit individual component) @@ -141,6 +146,7 @@ unsafe void UpdateShaderVariablesGlobalSubsurface(ref ShaderVariablesGlobal cb, cb._TransmissionTintsAndFresnel0[i * 4 + c] = hdCamera.frameSettings.IsEnabled(FrameSettingsField.Transmission) ? m_SSSTransmissionTintsAndFresnel0[i][c] : m_SSSDisabledTransmissionTintsAndFresnel0[i][c]; cb._WorldScalesAndFilterRadiiAndThicknessRemaps[i * 4 + c] = m_SSSWorldScalesAndFilterRadiiAndThicknessRemaps[i][c]; cb._DualLobeAndDiffusePower[i * 4 + c] = m_SSSDualLobeAndDiffusePower[i][c]; + cb._BorderAttenuationColor[i * 4 + c] = m_SSSBorderAttenuationColor[i][c]; } cb._DiffusionProfileHashTable[i * 4] = m_SSSDiffusionProfileHashes[i]; @@ -194,6 +200,7 @@ class SubsurfaceScaterringPassData public ComputeShader subsurfaceScatteringCS; public ComputeShader subsurfaceScatteringDownsampleCS; public int subsurfaceScatteringCSKernel; + public int packDiffusionProfileKernel; public int subsurfaceScatteringDownsampleCSKernel; public int sampleBudget; public int downsampleSteps; @@ -203,6 +210,8 @@ class SubsurfaceScaterringPassData public int numTilesX; public int numTilesY; public int numTilesZ; + public bool useOcclusion; + public Vector2 viewportSize; public TextureHandle colorBuffer; public TextureHandle diffuseBuffer; @@ -211,6 +220,7 @@ class SubsurfaceScaterringPassData public TextureHandle cameraFilteringBuffer; public TextureHandle downsampleBuffer; public TextureHandle sssBuffer; + public TextureHandle diffusionProfileIndex; public BufferHandle coarseStencilBuffer; } @@ -223,10 +233,14 @@ TextureHandle RenderSubsurfaceScatteringScreenSpace(RenderGraph renderGraph, HDC using (var builder = renderGraph.AddRenderPass("Subsurface Scattering", out var passData, ProfilingSampler.Get(HDProfileId.SubsurfaceScattering))) { + passData.useOcclusion = currentAsset.currentPlatformRenderPipelineSettings.subsurfaceScatteringAttenuation; + CoreUtils.SetKeyword(m_SubsurfaceScatteringCS, "ENABLE_MSAA", hdCamera.msaaEnabled); + CoreUtils.SetKeyword(m_SubsurfaceScatteringCS, "USE_SSS_OCCLUSION", passData.useOcclusion); passData.subsurfaceScatteringCS = m_SubsurfaceScatteringCS; passData.subsurfaceScatteringCSKernel = m_SubsurfaceScatteringKernel; + passData.packDiffusionProfileKernel = m_PackDiffusionProfileKernel; passData.subsurfaceScatteringDownsampleCS = m_SubsurfaceScatteringDownsampleCS; passData.subsurfaceScatteringDownsampleCSKernel = m_SubsurfaceScatteringDownsampleKernel; passData.needTemporaryBuffer = NeedTemporarySubsurfaceBuffer() || hdCamera.msaaEnabled; @@ -245,6 +259,18 @@ TextureHandle RenderSubsurfaceScatteringScreenSpace(RenderGraph renderGraph, HDC passData.sssBuffer = builder.ReadTexture(lightingBuffers.sssBuffer); passData.coarseStencilBuffer = builder.ReadBuffer(prepassOutput.coarseStencilBuffer); + if (passData.useOcclusion) + { + passData.diffusionProfileIndex = builder.CreateTransientTexture(new TextureDesc(new Vector2(0.5f, 1f), true, true) + { + colorFormat = GraphicsFormat.R8_UInt, + enableRandomWrite = true, + clearBuffer = false, + name = "Packed Diffusion Profile Index", + }); + passData.viewportSize = hdCamera.screenSize; + } + if (passData.downsampleSteps > 0) { float scale = 1.0f / (1u << passData.downsampleSteps); @@ -253,7 +279,6 @@ TextureHandle RenderSubsurfaceScatteringScreenSpace(RenderGraph renderGraph, HDC { format = GraphicsFormat.B10G11R11_UFloatPack32, enableRandomWrite = true, clearBuffer = true, clearColor = Color.clear, name = "SSSDownsampled" }); } - if (passData.needTemporaryBuffer) { passData.cameraFilteringBuffer = builder.CreateTransientTexture( @@ -298,6 +323,22 @@ TextureHandle RenderSubsurfaceScatteringScreenSpace(RenderGraph renderGraph, HDC ctx.cmd.SetComputeBufferParam(data.subsurfaceScatteringCS, data.subsurfaceScatteringCSKernel, HDShaderIDs._CoarseStencilBuffer, data.coarseStencilBuffer); + // When occlusion is enabled, we pack the 2 diffusion profile indices into a single 8bit texel to improve the bandwidth when fetching the buffer. + // We couldn't pack this data into the lighting buffer because of the MSAA resolve and the precision loss. + if (data.useOcclusion) + { + ctx.cmd.SetComputeTextureParam(data.subsurfaceScatteringCS, data.packDiffusionProfileKernel, HDShaderIDs._DiffusionProfileIndexTexture, data.diffusionProfileIndex); + ctx.cmd.SetComputeTextureParam(data.subsurfaceScatteringCS, data.packDiffusionProfileKernel, HDShaderIDs._SSSBufferTexture, data.sssBuffer); + int xGroupCount = HDUtils.DivRoundUp(Mathf.CeilToInt(data.viewportSize.x / 2.0f), 8); + ctx.cmd.DispatchCompute(data.subsurfaceScatteringCS, data.packDiffusionProfileKernel, xGroupCount, HDUtils.DivRoundUp((int)data.viewportSize.y, 8), data.numTilesZ); + + ctx.cmd.SetComputeTextureParam(data.subsurfaceScatteringCS, data.subsurfaceScatteringCSKernel, HDShaderIDs._DiffusionProfileIndexTexture, data.diffusionProfileIndex); + } + else + { + ctx.cmd.SetComputeTextureParam(data.subsurfaceScatteringCS, data.subsurfaceScatteringCSKernel, HDShaderIDs._DiffusionProfileIndexTexture, TextureXR.GetBlackTexture()); + } + if (data.needTemporaryBuffer) { ctx.cmd.SetComputeTextureParam(data.subsurfaceScatteringCS, data.subsurfaceScatteringCSKernel, HDShaderIDs._CameraFilteringBuffer, data.cameraFilteringBuffer); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs index c381bdf61e6..4af62aaf16d 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs @@ -442,6 +442,7 @@ static class HDShaderIDs public static readonly int _VolumetricMaterialFalloffMode = Shader.PropertyToID("_VolumetricMaterialFalloffMode"); public static readonly int _SSSBufferTexture = Shader.PropertyToID("_SSSBufferTexture"); + public static readonly int _DiffusionProfileIndexTexture = Shader.PropertyToID("_DiffusionProfileIndexTexture"); public static readonly int _NormalBufferTexture = Shader.PropertyToID("_NormalBufferTexture"); public static readonly int _NormalBufferRW = Shader.PropertyToID("_NormalBufferRW"); public static readonly int _RaytracePrepassBufferTexture = Shader.PropertyToID("_RaytracePrepassBufferTexture"); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPass.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPass.cs index 8ad47ce0fe0..0c183738df1 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPass.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPass.cs @@ -179,6 +179,7 @@ class ExecutePassData public CullingResults cullingResult; public CullingResults cameraCullingResult; public HDCamera hdCamera; + public ShaderVariablesGlobal shaderVariablesGlobal; } RenderTargets ReadRenderTargets(in RenderGraphBuilder builder, in RenderTargets targets) @@ -225,6 +226,7 @@ virtual internal void ExecuteInternal(RenderGraph renderGraph, HDCamera hdCamera passData.cullingResult = cullingResult; passData.cameraCullingResult = cameraCullingResult; passData.hdCamera = hdCamera; + passData.shaderVariablesGlobal = HDRenderPipeline.currentPipeline.GetShaderVariablesGlobalCB(); this.currentRenderTarget = ReadRenderTargets(builder, targets); @@ -275,7 +277,7 @@ virtual internal void ExecuteInternal(RenderGraph renderGraph, HDCamera hdCamera customPass.currentRenderTarget.customColorBuffer, customPass.currentRenderTarget.customDepthBuffer, ctx.renderGraphPool.GetTempMaterialPropertyBlock(), - customPass.injectionPoint + customPass.injectionPoint, data.shaderVariablesGlobal ); customPass.isExecuting = true; diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassContext.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassContext.cs index 108654238cd..9199c662614 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassContext.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassContext.cs @@ -68,6 +68,10 @@ public struct CustomPassContext public readonly MaterialPropertyBlock propertyBlock; internal readonly CustomPassInjectionPoint injectionPoint; + // This represent the state of HDRP globals at the point of recording the custom passes. + // Using GetShaderVariablesGlobals() from HDRP inside the execute of the custom pass would give invalid result + // because the execute of custom passes is called during the render graph execution, after the recording of all passes. + internal readonly ShaderVariablesGlobal currentGlobalState; internal CustomPassContext( ScriptableRenderContext renderContext, CommandBuffer cmd, @@ -77,7 +81,7 @@ internal CustomPassContext( RTHandle cameraNormalBuffer, RTHandle cameraMotionVectorsBuffer, Lazy customColorBuffer, Lazy customDepthBuffer, MaterialPropertyBlock propertyBlock, - CustomPassInjectionPoint injectionPoint) + CustomPassInjectionPoint injectionPoint, ShaderVariablesGlobal currentGlobalState) { this.renderContext = renderContext; this.cmd = cmd; @@ -92,6 +96,7 @@ internal CustomPassContext( this.customDepthBuffer = customDepthBuffer; this.propertyBlock = propertyBlock; this.injectionPoint = injectionPoint; + this.currentGlobalState = currentGlobalState; } } } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassUtils.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassUtils.cs index 82cbf4b4526..49df296133d 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassUtils.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassUtils.cs @@ -561,7 +561,7 @@ public static void RenderFromCamera(in CustomPassContext ctx, ShaderTagId[] shad using (new ProfilingScope(ctx.cmd, renderFromCameraSampler)) { DrawRenderers(ctx, shaderTags, layerMask, renderQueueFilter, overrideMaterial, overrideMaterialIndex, overrideRenderState); - + if (GetRenderQueueRangeFromRenderQueueType(renderQueueFilter).Contains((int)RenderQueue.Transparent)) { int mode = 0; @@ -788,7 +788,8 @@ public struct OverrideCameraRendering : IDisposable HDCamera overrideHDCamera; float originalAspect; - static Stack overrideCameraStack = new Stack(); + static Stack overrideCameraStack = new(); + static Stack overrideGlobalVariablesStack = new(); /// /// Overrides the current camera, changing all the matrices and view parameters for the new one. @@ -878,12 +879,13 @@ void Init(CustomPassContext ctx, Camera overrideCamera, float overrideAspectRati overrideHDCamera.Update(overrideHDCamera.frameSettings, hdrp, XRSystem.emptyPass, allocateHistoryBuffers: false); // Reset the reference size as it could have been changed by the override camera ctx.hdCamera.SetReferenceSize(); - var globalCB = hdrp.GetShaderVariablesGlobalCB(); + var globalCB = ctx.currentGlobalState; overrideHDCamera.UpdateShaderVariablesGlobalCB(ref globalCB); ConstantBuffer.PushGlobal(ctx.cmd, globalCB, HDShaderIDs._ShaderVariablesGlobal); overrideCameraStack.Push(overrideHDCamera); + overrideGlobalVariablesStack.Push(globalCB); } static bool IsContextValid(CustomPassContext ctx, Camera overrideCamera) @@ -909,22 +911,23 @@ void IDisposable.Dispose() overrideCamera.aspect = originalAspect; // Set back the settings of the previous camera - var globalCB = HDRenderPipeline.currentPipeline.GetShaderVariablesGlobalCB(); overrideCameraStack.Pop(); if (overrideCameraStack.Count > 0) { var previousHDCamera = overrideCameraStack.Peek(); previousHDCamera.SetReferenceSize(); - previousHDCamera.UpdateShaderVariablesGlobalCB(ref globalCB); } else // If we don't have any nested override camera, then we go back to the original one. { // Reset the reference size as it could have been changed by the override camera ctx.hdCamera.SetReferenceSize(); - ctx.hdCamera.UpdateShaderVariablesGlobalCB(ref globalCB); } - ConstantBuffer.PushGlobal(ctx.cmd, globalCB, HDShaderIDs._ShaderVariablesGlobal); + overrideGlobalVariablesStack.Pop(); + if (overrideGlobalVariablesStack.Count > 0) + ConstantBuffer.PushGlobal(ctx.cmd, overrideGlobalVariablesStack.Peek(), HDShaderIDs._ShaderVariablesGlobal); + else + ConstantBuffer.PushGlobal(ctx.cmd, ctx.currentGlobalState, HDShaderIDs._ShaderVariablesGlobal); } } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/RenderPipelineSettings.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/RenderPipelineSettings.cs index 7cb3549a287..c4b3cd52cba 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/RenderPipelineSettings.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/RenderPipelineSettings.cs @@ -103,6 +103,7 @@ internal static RenderPipelineSettings NewDefault() supportShadowMask = true, supportSSAO = true, supportSubsurfaceScattering = true, + subsurfaceScatteringAttenuation = true, sssSampleBudget = new IntScalableSetting(new[] { (int)DefaultSssSampleBudgetForQualityLevel.Low, (int)DefaultSssSampleBudgetForQualityLevel.Medium, (int)DefaultSssSampleBudgetForQualityLevel.High }, ScalableSettingSchemaId.With3Levels), @@ -249,6 +250,8 @@ public ReflectionProbeResolutionScalableSetting(CubeReflectionResolution[] value // [ShaderKeywordFilter.RemoveIf(true, keywordNames: "OUTPUT_SPLIT_LIGHTING")] #endif public bool supportSubsurfaceScattering; + /// Enable SubSurface-Scattering occlusion computation. Enabling this makes the SSS slightly more expensive but add great details to occluded zones with SSS materials. + public bool subsurfaceScatteringAttenuation; /// Sample budget for the Subsurface Scattering algorithm. public IntScalableSetting sssSampleBudget; /// Downsample input texture for the Subsurface Scattering algorithm. diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/WorldLightManager.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/WorldLightManager.cs index 9186de26cfe..33934362745 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/WorldLightManager.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/WorldLightManager.cs @@ -154,12 +154,9 @@ internal void ResizeLightDataGraphicsBuffer(int numLights) m_LightDataGPUArray = new GraphicsBuffer(GraphicsBuffer.Target.Structured, numLightsGpu, System.Runtime.InteropServices.Marshal.SizeOf(typeof(LightData))); } - internal const int k_MaxPlanarReflectionsOnScreen = 16; - internal const int k_MaxCubeReflectionsOnScreen = 64; - internal unsafe void SetPlanarReflectionDataRT(int index, ref Matrix4x4 vp, ref Vector4 scaleOffset) { - Debug.Assert(index < k_MaxPlanarReflectionsOnScreen); + Debug.Assert(index < HDRenderPipeline.k_MaxPlanarReflectionsOnScreen); for (int j = 0; j < 16; ++j) m_EnvLightReflectionDataRT._PlanarCaptureVPWL[index * 16 + j] = vp[j]; @@ -170,7 +167,7 @@ internal unsafe void SetPlanarReflectionDataRT(int index, ref Matrix4x4 vp, ref internal unsafe void SetCubeReflectionDataRT(int index, ref Vector4 scaleOffset) { - Debug.Assert(index < k_MaxCubeReflectionsOnScreen); + Debug.Assert(index < HDRenderPipeline.k_MaxCubeReflectionsOnScreen); for (int j = 0; j < 4; ++j) m_EnvLightReflectionDataRT._CubeScaleOffsetWL[index * 4 + j] = scaleOffset[j]; @@ -354,16 +351,16 @@ public static void CollectWorldLights(in HDCamera hdCamera, in WorldLightsSettin // this to ensure that we don't process more lights than before if ((flagFunc(hdCamera, hdLight, light) & 0xfffffffe) == 0) continue; - + // TODO-WL: Directional lights if (hdLight.legacyLight.type == LightType.Directional) continue; - + // Compute the camera relative position Vector3 lightPositionRWS = hdLight.gameObject.transform.position; if (ShaderConfig.s_CameraRelativeRendering != 0) lightPositionRWS -= camPosWS; - + var lightType = hdLight.legacyLight.type; float lightRange = light.range; bool isAreaLight = lightType.IsArea(); @@ -401,10 +398,10 @@ public static void CollectWorldLights(in HDCamera hdCamera, in WorldLightsSettin // Let's now compute an AABB that matches the previously defined OOBB Bounds lightBounds = new Bounds(); OOBBToAABBBounds(oobbCenter, extents, hdLight.gameObject.transform.up, hdLight.gameObject.transform.right, hdLight.gameObject.transform.forward, ref lightBounds); - + if (!bounds.Intersects(lightBounds)) continue; - + visibleLight.bounds = lightBounds; } @@ -679,7 +676,7 @@ public static void BuildWorldLightVolumes(in HDCamera hdCamera, in HDRenderPipel lightVolume.position = visibleLight.bounds.center; lightVolume.lightType = isAreaLight ? 1u : 0u; lightVolume.shape = isAreaLight || isBoxLight ? 1u : 0u; - + worldLightsVolumes.bounds.Encapsulate(visibleLight.bounds); realIndex++; } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariablesGlobal.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariablesGlobal.cs index 4477ece5b4c..0efb213d50f 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariablesGlobal.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariablesGlobal.cs @@ -258,6 +258,8 @@ unsafe struct ShaderVariablesGlobal public fixed float _WorldScalesAndFilterRadiiAndThicknessRemaps[DiffusionProfileConstants.DIFFUSION_PROFILE_COUNT * 4]; // X = meters per world unit, Y = filter radius (in mm), Z = remap start, W = end - start [HLSLArray(DiffusionProfileConstants.DIFFUSION_PROFILE_COUNT, typeof(Vector4))] public fixed float _DualLobeAndDiffusePower[DiffusionProfileConstants.DIFFUSION_PROFILE_COUNT * 4]; // RGB = dual lobe, A = diffuse power + [HLSLArray(DiffusionProfileConstants.DIFFUSION_PROFILE_COUNT, typeof(Vector4))] + public fixed float _BorderAttenuationColor[DiffusionProfileConstants.DIFFUSION_PROFILE_COUNT * 4]; // RGB = dual lobe, A = diffuse power // Because of constant buffer limitation, arrays can only hold 4 components elements (otherwise we get alignment issues) // We could pack the 16 values inside 4 uint4 but then the generated code is inefficient and generates a lots of swizzle operations instead of a single load. // That's why we have 16 uint and only use the first component of each element. diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariablesGlobal.cs.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariablesGlobal.cs.hlsl index e598df55b1e..dad5dfaa792 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariablesGlobal.cs.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariablesGlobal.cs.hlsl @@ -152,6 +152,7 @@ GLOBAL_CBUFFER_START(ShaderVariablesGlobal, b0) float4 _TransmissionTintsAndFresnel0[16]; float4 _WorldScalesAndFilterRadiiAndThicknessRemaps[16]; float4 _DualLobeAndDiffusePower[16]; + float4 _BorderAttenuationColor[16]; uint4 _DiffusionProfileHashTable[16]; uint _EnableSubsurfaceScattering; uint _TexturingModeFlags; 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 3a711f5c921..1b00ab03e71 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 @@ -562,7 +562,7 @@ public override void RenderSky(BuiltinSkyParameters builtinParams, bool renderFo cameraPosPS -= (upAltitude.w - 1.0f) * (Vector3)upAltitude.xyz; bool simpleEarthMode = pbrSky.type.value == PhysicallyBasedSkyModel.EarthSimple; - bool customMaterial = pbrSky.renderingMode.value == PhysicallyBasedSky.RenderingMode.Material && pbrSky.material.value != null; + bool customMaterial = pbrSky.renderingMode.value == PhysicallyBasedSky.RenderingMode.Material && pbrSky.material.value != null && pbrSky.material.overrideState; var material = customMaterial ? pbrSky.material.value : m_PbrSkyMaterial; // Common material properties diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/VFXGraph/Shaders/VFXLit.hlsl b/Packages/com.unity.render-pipelines.high-definition/Runtime/VFXGraph/Shaders/VFXLit.hlsl index 899d9b455b2..6a0b8b93bff 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/VFXGraph/Shaders/VFXLit.hlsl +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/VFXGraph/Shaders/VFXLit.hlsl @@ -12,7 +12,7 @@ #endif #if defined(VFX_MATERIAL_TYPE_SIX_WAY_SMOKE) && (SHADERPASS == SHADERPASS_FORWARD) -//Do nothing. In Six-way lighting forward pass, these includes are required earlier, defined in VFXVertexProbeSampling.template +//Do nothing. In Six-way lighting forward pass, these includes are required earlier, defined in VFXSixWayIncludes.template #else #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Material.hlsl" diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/Shaders/WaterExclusion.shader b/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/Shaders/WaterExclusion.shader index a826a90cc16..1e72406e005 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/Shaders/WaterExclusion.shader +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Water/Shaders/WaterExclusion.shader @@ -26,6 +26,7 @@ Shader "Hidden/HDRP/WaterExclusion" HLSLPROGRAM #pragma target 4.5 #pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch + #pragma multi_compile _ DOTS_INSTANCING_ON // #pragma enable_d3d11_debug_symbols diff --git a/Packages/com.unity.render-pipelines.high-definition/Samples~/WaterSamples/Scripts/MeshBaker.cs b/Packages/com.unity.render-pipelines.high-definition/Samples~/WaterSamples/Scripts/MeshBaker.cs index 2cc953d196b..b9fed33f313 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Samples~/WaterSamples/Scripts/MeshBaker.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Samples~/WaterSamples/Scripts/MeshBaker.cs @@ -1,8 +1,10 @@ using System.Collections; using System.Collections.Generic; using UnityEngine; -using UnityEditor; using System.IO; +#if UNITY_EDITOR +using UnityEditor; +#endif public class MeshBaker : MonoBehaviour { @@ -188,6 +190,7 @@ void OnDrawGizmos() } } +#if UNITY_EDITOR [CustomEditor(typeof(MeshBaker))] public class MeshBakerEditor : Editor { @@ -206,3 +209,5 @@ public override void OnInspectorGUI() } } } + +#endif diff --git a/Packages/com.unity.render-pipelines.high-definition/Samples~/WaterSamples/Scripts/MoveWave.cs b/Packages/com.unity.render-pipelines.high-definition/Samples~/WaterSamples/Scripts/MoveWave.cs index c4faae2fabc..e7850183707 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Samples~/WaterSamples/Scripts/MoveWave.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Samples~/WaterSamples/Scripts/MoveWave.cs @@ -2,8 +2,10 @@ using System.Collections.Generic; using UnityEngine; using UnityEngine.VFX; -using UnityEditor; using UnityEngine.Rendering.HighDefinition; +#if UNITY_EDITOR +using UnityEditor; +#endif [ExecuteInEditMode] public class MoveWave : MonoBehaviour @@ -58,6 +60,7 @@ public float GetState() } } +#if UNITY_EDITOR [CustomEditor(typeof(MoveWave))] public class MoveWaveEditor : Editor { @@ -74,3 +77,5 @@ public override void OnInspectorGUI() } } +#endif + diff --git a/Packages/com.unity.render-pipelines.high-definition/Tests/Editor/HDAnalyticsTests_Defaults.txt b/Packages/com.unity.render-pipelines.high-definition/Tests/Editor/HDAnalyticsTests_Defaults.txt index dc9a14034b4..5a424c8cc43 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Tests/Editor/HDAnalyticsTests_Defaults.txt +++ b/Packages/com.unity.render-pipelines.high-definition/Tests/Editor/HDAnalyticsTests_Defaults.txt @@ -4,6 +4,7 @@ {"supportSSAO":"True"}, {"supportSSGI":"False"}, {"supportSubsurfaceScattering":"True"}, +{"subsurfaceScatteringAttenuation":"True"}, {"sssSampleBudget.m_Values":"[20,40,80]"}, {"sssSampleBudget.m_SchemaId.m_Id":"With3Levels"}, {"sssDownsampleSteps.m_Values":"[0,0,0]"}, diff --git a/Packages/com.unity.render-pipelines.universal/Editor/Decal/DecalProjectorEditor.Skin.cs b/Packages/com.unity.render-pipelines.universal/Editor/Decal/DecalProjectorEditor.Skin.cs index da10211d51e..2294730d57b 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/Decal/DecalProjectorEditor.Skin.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/Decal/DecalProjectorEditor.Skin.cs @@ -21,7 +21,9 @@ partial class DecalProjectorEditor static readonly GUIContent k_UVBiasContent = EditorGUIUtility.TrTextContent("Offset", "Sets the offset for the decal Material. Moves the decal along its UV axes."); static readonly GUIContent k_OpacityContent = EditorGUIUtility.TrTextContent("Opacity", "Controls the transparency of the decal."); static readonly GUIContent k_Offset = EditorGUIUtility.TrTextContent("Pivot", "Controls the position of the pivot point of the decal."); + static readonly GUIContent k_NewMaterialButtonText = EditorGUIUtility.TrTextContent("New", "Creates a new decal Material asset template."); + static readonly string k_NewDecalMaterialText = "New Decal"; static readonly string k_BaseSceneEditingToolText = "Decal Scene Editing Mode: "; static readonly string k_EditShapeWithoutPreservingUVName = k_BaseSceneEditingToolText + "Scale"; static readonly string k_EditShapePreservingUVName = k_BaseSceneEditingToolText + "Crop"; diff --git a/Packages/com.unity.render-pipelines.universal/Editor/Decal/DecalProjectorEditor.cs b/Packages/com.unity.render-pipelines.universal/Editor/Decal/DecalProjectorEditor.cs index 09b57f54482..cf7b308e277 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/Decal/DecalProjectorEditor.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/Decal/DecalProjectorEditor.cs @@ -4,6 +4,7 @@ using UnityEditor.ShortcutManagement; using UnityEditorInternal; using UnityEngine; +using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; using static UnityEditorInternal.EditMode; @@ -626,7 +627,7 @@ public override void OnInspectorGUI() EditorGUILayout.Space(); EditorGUI.BeginChangeCheck(); - EditorGUILayout.PropertyField(m_MaterialProperty, k_MaterialContent); + MaterialFieldWithButton(m_MaterialProperty, k_MaterialContent); materialChanged = EditorGUI.EndChangeCheck(); EditorUtils.DrawRenderingLayerMask(m_RenderingLayerMask, k_RenderingLayerMaskContent); @@ -729,6 +730,30 @@ public override void OnInspectorGUI() } } + internal void MaterialFieldWithButton(SerializedProperty prop, GUIContent label) + { + const int k_NewFieldWidth = 70; + + var rect = EditorGUILayout.GetControlRect(); + rect.xMax -= k_NewFieldWidth + 2; + + EditorGUI.PropertyField(rect, prop, label); + + var newFieldRect = rect; + newFieldRect.x = rect.xMax + 2; + newFieldRect.width = k_NewFieldWidth; + + if (GUI.Button(newFieldRect, k_NewMaterialButtonText)) + { + string materialName = k_NewDecalMaterialText + ".mat"; + var materialIcon = AssetPreview.GetMiniTypeThumbnail(typeof(Material)); + var action = ScriptableObject.CreateInstance(); + action.decalProjector = target as DecalProjector; + ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, action, materialName, materialIcon, null); + } + + } + [Shortcut("URP/Decal: Handle changing size stretching UV", typeof(SceneView), KeyCode.Keypad1, ShortcutModifiers.Action)] static void EnterEditModeWithoutPreservingUV(ShortcutArguments args) { @@ -796,4 +821,17 @@ static void ExitEditMode(ShortcutArguments args) QuitEditMode(); } } + + class DoCreateDecalDefaultMaterial : ProjectWindowCallback.EndNameEditAction + { + public DecalProjector decalProjector; + public override void Action(int instanceId, string pathName, string resourceFile) + { + var shader = DecalProjector.defaultMaterial.shader; + var material = new Material(shader); + AssetDatabase.CreateAsset(material, pathName); + ProjectWindowUtil.ShowCreatedAsset(material); + decalProjector.material = material; + } + } } diff --git a/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/ParticleMeshesLit/PassDepthOrMV.template b/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/ParticleMeshesLit/PassDepthOrMV.template index 1e4094316dd..055317597b5 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/ParticleMeshesLit/PassDepthOrMV.template +++ b/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/ParticleMeshesLit/PassDepthOrMV.template @@ -21,7 +21,7 @@ #endif struct ps_input -{ +{ float4 pos : SV_POSITION; #if USE_FLIPBOOK_INTERPOLATION float4 uv : TEXCOORD0; @@ -30,7 +30,7 @@ struct ps_input float3 uv : TEXCOORD0; #else float2 uv : TEXCOORD0; - #endif + #endif #endif #if VFX_SHADERGRAPH_HAS_UV1 float4 uv1 : COLOR2; @@ -72,7 +72,7 @@ struct ps_input #endif ${VFXAdditionalInterpolantsDeclaration} - + UNITY_VERTEX_OUTPUT_STEREO VFX_VERTEX_OUTPUT_INSTANCE_INDEX }; @@ -107,4 +107,4 @@ ${VFXURPLitFillVaryings} ${VFXEnd} ${VFXInclude("Shaders/ParticleMeshes/Pass.template")} -${VFXPassDepthCommonFragmentURPLit} +${VFXIncludeRP("Templates/VFXPassDepthCommonFragmentLit.template")} diff --git a/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/ParticleMeshesLit/PassForward.template b/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/ParticleMeshesLit/PassForward.template index 03ef2bd77a0..2e54ba4721f 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/ParticleMeshesLit/PassForward.template +++ b/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/ParticleMeshesLit/PassForward.template @@ -10,8 +10,8 @@ Pass ${VFXPassForwardLitAdditionalPragma} ${VFXURPForwardDefines} - ${VFXIncludeRP("VFXLitVaryings.template")} ${VFXIncludeRP("VFXVertexProbeSampling.template"),VFX_MATERIAL_TYPE_SIX_WAY_SMOKE} + ${VFXIncludeRP("VFXLitVaryings.template")} struct ps_input { diff --git a/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/ParticlePlanarPrimitivesLit/PassDepthOrMV.template b/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/ParticlePlanarPrimitivesLit/PassDepthOrMV.template index 8c5b057804a..66e4b931b66 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/ParticlePlanarPrimitivesLit/PassDepthOrMV.template +++ b/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/ParticlePlanarPrimitivesLit/PassDepthOrMV.template @@ -31,7 +31,7 @@ struct ps_input #if USE_FLIPBOOK_ARRAY_LAYOUT float3 uv : TEXCOORD0; #else - float2 uv : TEXCOORD0; + float2 uv : TEXCOORD0; #endif #endif #if USE_ALPHA_TEST || USE_FLIPBOOK_INTERPOLATION || VFX_USE_ALPHA_CURRENT @@ -41,13 +41,13 @@ struct ps_input // w: smoothness VFX_OPTIONAL_INTERPOLATION float4 builtInInterpolants : TEXCOORD1; #endif - + #if USE_FLIPBOOK_MOTIONVECTORS // x: motion vector scale u // y: motion vector scale v VFX_OPTIONAL_INTERPOLATION float2 builtInInterpolants2 : TEXCOORD2; #endif - + #if NEEDS_NORMAL float4 normal : TEXCOORD3; // normal scale is stored in w #endif @@ -64,7 +64,7 @@ struct ps_input #if VFX_PASSDEPTH == VFX_PASSDEPTH_MOTION_VECTOR VFX_DECLARE_MOTION_VECTORS_STORAGE(7,8) #endif - + ${VFXAdditionalInterpolantsDeclaration} UNITY_VERTEX_OUTPUT_STEREO @@ -105,4 +105,4 @@ ${VFXURPLitFillVaryings} ${VFXEnd} ${VFXInclude("Shaders/ParticlePlanarPrimitives/Pass.template")} -${VFXPassDepthCommonFragmentURPLit} +${VFXIncludeRP("Templates/VFXPassDepthCommonFragmentLit.template")} diff --git a/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/ParticlePlanarPrimitivesLit/PassForward.template b/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/ParticlePlanarPrimitivesLit/PassForward.template index 964622ecadd..c1d75991b31 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/ParticlePlanarPrimitivesLit/PassForward.template +++ b/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/ParticlePlanarPrimitivesLit/PassForward.template @@ -10,8 +10,8 @@ Pass ${VFXPassForwardLitAdditionalPragma} ${VFXURPForwardDefines} - ${VFXIncludeRP("VFXLitVaryings.template")} ${VFXIncludeRP("VFXVertexProbeSampling.template"),VFX_MATERIAL_TYPE_SIX_WAY_SMOKE} + ${VFXIncludeRP("VFXLitVaryings.template")} struct ps_input { diff --git a/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/VFXPassDepthCommonFragmentLit.template b/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/VFXPassDepthCommonFragmentLit.template new file mode 100644 index 00000000000..8c9fcca1e1d --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/VFXPassDepthCommonFragmentLit.template @@ -0,0 +1,101 @@ +#if VFX_PASSDEPTH == VFX_PASSDEPTH_MOTION_VECTOR +${VFXPassVelocityDefine} +#elif VFX_PASSDEPTH == VFX_PASSDEPTH_SHADOW +${VFXPassShadowDefine} +#else +${VFXPassDepthDefine} +#endif +${VFXIncludeRP("VFXLit.template")} + +#if defined(WRITE_NORMAL_BUFFER) +${SHADERGRAPH_PIXEL_CODE_DEPTHNORMALS} +#else +${SHADERGRAPH_PIXEL_CODE_DEPTHONLY} +#endif + +#if VFX_PASSDEPTH == VFX_PASSDEPTH_SELECTION +int _ObjectId; +int _PassValue; +#elif VFX_PASSDEPTH == VFX_PASSDEPTH_PICKING +float4 _SelectionID; +#endif + +#pragma fragment frag +void frag(ps_input i +#if USE_DOUBLE_SIDED + , bool frontFace : SV_IsFrontFace +#endif +#if VFX_PASSDEPTH == VFX_PASSDEPTH_MOTION_VECTOR + , out float4 outMotionVector : SV_Target0 +#elif VFX_PASSDEPTH == VFX_PASSDEPTH_ACTUAL + #if defined(WRITE_NORMAL_BUFFER) + , out float4 outNormalBuffer : SV_Target0 + , out float4 outDepthColor : SV_Target1 + #else + , out float4 outDepthColor : SV_Target0 + #endif +#elif VFX_PASSDEPTH == VFX_PASSDEPTH_SELECTION || VFX_PASSDEPTH == VFX_PASSDEPTH_PICKING + , out float4 outColor : SV_Target0 +#endif +) +{ + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); + VFXTransformPSInputs(i); + ${VFXComputeNormalWS} + + #ifdef VFX_SHADERGRAPH + ${VFXAdditionalInterpolantsPreparation} + + #if defined(WRITE_NORMAL_BUFFER) + ${SHADERGRAPH_PIXEL_CALL_DEPTHNORMALS} + #else + ${SHADERGRAPH_PIXEL_CALL_DEPTHONLY} + #endif + + float alpha = OUTSG.${SHADERGRAPH_PARAM_ALPHA}; + #else + + float alpha = VFXGetFragmentColor(i).a; + #if URP_USE_BASE_COLOR_MAP_ALPHA + alpha *= VFXGetTextureColor(VFX_SAMPLER(baseColorMap),i).a; + #endif + + #if VFX_MATERIAL_TYPE_SIX_WAY_SMOKE + #ifndef VFX_VARYING_NORMAL + const VFXUVData uvData = GetUVData(i); + #endif + alpha *= SampleTexture(VFX_SAMPLER(positiveAxesLightmap),uvData).a; + #if defined(VFX_VARYING_ALPHA_REMAP) + alpha = SampleCurve(i.VFX_VARYING_ALPHA_REMAP, alpha); + #endif + #endif + #endif + + VFXClipFragmentColor(alpha,i); + + #if defined(WRITE_NORMAL_BUFFER) + #ifdef VFX_SHADERGRAPH + #if HAS_SHADERGRAPH_PARAM_NORMALTS + float3 n = OUTSG.${SHADERGRAPH_PARAM_NORMALTS}; + normalWS = mul(n,tbn); + #endif + #endif + VFXComputePixelOutputToNormalBuffer(i, normalWS, GetUVData(i), outNormalBuffer); + #endif + + #if VFX_PASSDEPTH == VFX_PASSDEPTH_MOTION_VECTOR + ${VFXComputeOutputMotionVector} + outMotionVector = encodedMotionVector; + #elif VFX_PASSDEPTH == VFX_PASSDEPTH_SELECTION + // We use depth prepass for scene selection in the editor, this code allow to output the outline correctly + outColor = float4(_ObjectId, _PassValue, 1.0, 1.0); + #elif VFX_PASSDEPTH == VFX_PASSDEPTH_PICKING + outColor = _SelectionID; + #elif VFX_PASSDEPTH == VFX_PASSDEPTH_ACTUAL + outDepthColor = float4(i.VFX_VARYING_POSCS.z, 0,0,0); + #elif VFX_PASSDEPTH == VFX_PASSDEPTH_SHADOW + //void + #else + #error VFX_PASSDEPTH undefined + #endif +} diff --git a/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/VFXPassDepthCommonFragmentLit.template.meta b/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/VFXPassDepthCommonFragmentLit.template.meta new file mode 100644 index 00000000000..3c0a5d4f7d4 --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/VFXPassDepthCommonFragmentLit.template.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5e151e0faedc4a8ea681032f3bd79061 +timeCreated: 1720611629 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/VFXPasses.template b/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/VFXPasses.template index 1ec30694f28..0410d1f7640 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/VFXPasses.template +++ b/Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/VFXPasses.template @@ -56,122 +56,6 @@ ${VFXBegin:VFXPassGBufferAdditionalPragma} #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RenderingLayers.hlsl" ${VFXEnd} -${VFXBegin:VFXShaderGraphFunctionsInclude} -#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/Color.hlsl" -#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlsl" -#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" -#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl" -#include_with_pragmas "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRenderingKeywords.hlsl" -#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRendering.hlsl" -${VFXEnd} - - -${VFXBegin:VFXPassDepthCommonFragmentURPLit} -#if VFX_PASSDEPTH == VFX_PASSDEPTH_MOTION_VECTOR -${VFXPassVelocityDefine} -#elif VFX_PASSDEPTH == VFX_PASSDEPTH_SHADOW -${VFXPassShadowDefine} -#else -${VFXPassDepthDefine} -#endif -${VFXIncludeRP("VFXLit.template")} - -#if defined(WRITE_NORMAL_BUFFER) -${SHADERGRAPH_PIXEL_CODE_DEPTHNORMALS} -#else -${SHADERGRAPH_PIXEL_CODE_DEPTHONLY} -#endif - -#if VFX_PASSDEPTH == VFX_PASSDEPTH_SELECTION -int _ObjectId; -int _PassValue; -#elif VFX_PASSDEPTH == VFX_PASSDEPTH_PICKING -float4 _SelectionID; -#endif - -#pragma fragment frag -void frag(ps_input i -#if USE_DOUBLE_SIDED - , bool frontFace : SV_IsFrontFace -#endif -#if VFX_PASSDEPTH == VFX_PASSDEPTH_MOTION_VECTOR - , out float4 outMotionVector : SV_Target0 -#elif VFX_PASSDEPTH == VFX_PASSDEPTH_ACTUAL - #if defined(WRITE_NORMAL_BUFFER) - , out float4 outNormalBuffer : SV_Target0 - , out float4 outDepthColor : SV_Target1 - #else - , out float4 outDepthColor : SV_Target0 - #endif -#elif VFX_PASSDEPTH == VFX_PASSDEPTH_SELECTION || VFX_PASSDEPTH == VFX_PASSDEPTH_PICKING - , out float4 outColor : SV_Target0 -#endif -) -{ - UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); - VFXTransformPSInputs(i); - ${VFXComputeNormalWS} - - #ifdef VFX_SHADERGRAPH - ${VFXAdditionalInterpolantsPreparation} - - #if defined(WRITE_NORMAL_BUFFER) - ${SHADERGRAPH_PIXEL_CALL_DEPTHNORMALS} - #else - ${SHADERGRAPH_PIXEL_CALL_DEPTHONLY} - #endif - - float alpha = OUTSG.${SHADERGRAPH_PARAM_ALPHA}; - #else - - float alpha = VFXGetFragmentColor(i).a; - #if URP_USE_BASE_COLOR_MAP_ALPHA - alpha *= VFXGetTextureColor(VFX_SAMPLER(baseColorMap),i).a; - #endif - - #if VFX_MATERIAL_TYPE_SIX_WAY_SMOKE - #ifndef VFX_VARYING_NORMAL - const VFXUVData uvData = GetUVData(i); - #endif - alpha *= SampleTexture(VFX_SAMPLER(positiveAxesLightmap),uvData).a; - #if defined(VFX_VARYING_ALPHA_REMAP) - alpha = SampleCurve(i.VFX_VARYING_ALPHA_REMAP, alpha); - #endif - #endif - #endif - - VFXClipFragmentColor(alpha,i); - - #if defined(WRITE_NORMAL_BUFFER) - #ifdef VFX_SHADERGRAPH - #if HAS_SHADERGRAPH_PARAM_NORMALTS - float3 n = OUTSG.${SHADERGRAPH_PARAM_NORMALTS}; - normalWS = mul(n,tbn); - #endif - #endif - VFXComputePixelOutputToNormalBuffer(i, normalWS, GetUVData(i), outNormalBuffer); - #endif - - #if VFX_PASSDEPTH == VFX_PASSDEPTH_MOTION_VECTOR - ${VFXComputeOutputMotionVector} - outMotionVector = encodedMotionVector; - #elif VFX_PASSDEPTH == VFX_PASSDEPTH_SELECTION - // We use depth prepass for scene selection in the editor, this code allow to output the outline correctly - outColor = float4(_ObjectId, _PassValue, 1.0, 1.0); - #elif VFX_PASSDEPTH == VFX_PASSDEPTH_PICKING - outColor = _SelectionID; - #elif VFX_PASSDEPTH == VFX_PASSDEPTH_ACTUAL - outDepthColor = float4(i.VFX_VARYING_POSCS.z, 0,0,0); - #elif VFX_PASSDEPTH == VFX_PASSDEPTH_SHADOW - //void - #else - #error VFX_PASSDEPTH undefined - #endif -} -${VFXEnd} - ${VFXBegin:VFXUnlitDebugDisplay} #if defined(DEBUG_DISPLAY) InputData inputData; diff --git a/Packages/com.unity.render-pipelines.universal/Editor/Volume/DefaultVolumeProfile.asset.meta b/Packages/com.unity.render-pipelines.universal/Editor/Volume/DefaultVolumeProfile.asset.meta index 53b314adfa7..2b7243deeee 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/Volume/DefaultVolumeProfile.asset.meta +++ b/Packages/com.unity.render-pipelines.universal/Editor/Volume/DefaultVolumeProfile.asset.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: ab09877e2e707104187f6f83e2f62510 +guid: eda47df5b85f4f249abf7abd73db2cb2 NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Render2DLightingPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Render2DLightingPass.cs index 05664a160a9..c47a23d25d1 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Render2DLightingPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Passes/Render2DLightingPass.cs @@ -240,7 +240,7 @@ private int DrawLayerBatches( CoreUtils.SetRenderTarget(cmd, colorAttachmentHandle, RenderBufferLoadAction.Load, initialStoreAction, depthAttachmentHandle, RenderBufferLoadAction.Load, initialStoreAction, - ClearFlag.None, Color.clear); + GetCameraClearFlag(renderingData.cameraData), Color.clear); for (var i = startIndex; i < startIndex + batchesDrawn; i++) { @@ -415,7 +415,7 @@ public override void Execute(ScriptableRenderContext context, ref RenderingData CoreUtils.SetRenderTarget(cmd, colorAttachmentHandle, RenderBufferLoadAction.Load, storeAction, depthAttachmentHandle, RenderBufferLoadAction.Load, storeAction, - ClearFlag.None, Color.clear); + GetCameraClearFlag(renderingData.cameraData), Color.clear); cmd.SetGlobalColor(k_RendererColorID, Color.white); @@ -457,6 +457,16 @@ public override void Execute(ScriptableRenderContext context, ref RenderingData RenderingUtils.DrawRendererListObjectsWithError(CommandBufferHelpers.GetRasterCommandBuffer(renderingData.commandBuffer), ref objectsWithErrorRendererList); } + ClearFlag GetCameraClearFlag(CameraData cameraData) + { + if (Application.platform != RuntimePlatform.OSXEditor && + (cameraData.camera.clearFlags == CameraClearFlags.Skybox || + cameraData.camera.clearFlags == CameraClearFlags.Nothing)) + return ClearFlag.Color; + + return ClearFlag.None; + } + Renderer2DData IRenderPass2D.rendererData { get { return m_Renderer2DData; } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Renderer2D.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Renderer2D.cs index 64d6698adde..21f8a8de8a1 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Renderer2D.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Renderer2D.cs @@ -6,7 +6,7 @@ namespace UnityEngine.Rendering.Universal { internal sealed partial class Renderer2D : ScriptableRenderer { - #if UNITY_SWITCH || UNITY_EMBEDDED_LINUX || UNITY_QNX + #if UNITY_SWITCH || UNITY_EMBEDDED_LINUX || UNITY_QNX || UNITY_ANDROID const GraphicsFormat k_DepthStencilFormat = GraphicsFormat.D24_UNorm_S8_UInt; #else const GraphicsFormat k_DepthStencilFormat = GraphicsFormat.D32_SFloat_S8_UInt; 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 d0a7d8adfc3..ef441086035 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 @@ -359,6 +359,9 @@ void CreateResources(RenderGraph renderGraph) m_CreateColorTexture = baseRenderer.m_CreateColorTexture; m_CreateDepthTexture = baseRenderer.m_CreateDepthTexture; + + commonResourceData.activeColorID = m_CreateColorTexture ? ActiveID.Camera : ActiveID.BackBuffer; + commonResourceData.activeDepthID = m_CreateDepthTexture ? ActiveID.Camera : ActiveID.BackBuffer; } ImportResourceSummary importSummary = GetImportResourceSummary(renderGraph, cameraData); diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/FrameData/UniversalCameraData.cs b/Packages/com.unity.render-pipelines.universal/Runtime/FrameData/UniversalCameraData.cs index 6e50635426a..6099d4b9d6c 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/FrameData/UniversalCameraData.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/FrameData/UniversalCameraData.cs @@ -442,12 +442,28 @@ public bool IsRenderTargetProjectionMatrixFlipped(RTHandle color, RTHandle depth return targetTexture != null || IsHandleYFlipped(color ?? depth); } + /// + /// Returns true if temporal anti-aliasing has been requested + /// Use IsTemporalAAEnabled() to ensure that TAA is active at runtime + /// + /// True if TAA is requested + internal bool IsTemporalAARequested() + { + return antialiasing == AntialiasingMode.TemporalAntiAliasing; + } + + /// + /// Returns true if the pipeline and the given camera are configured to render with temporal anti-aliasing post processing enabled + /// + /// Once selected, TAA necessitates some pre-requisites from the pipeline to run, mostly from the camera itself. + /// + /// True if TAA is enabled internal bool IsTemporalAAEnabled() { UniversalAdditionalCameraData additionalCameraData; camera.TryGetComponent(out additionalCameraData); - return (antialiasing == AntialiasingMode.TemporalAntiAliasing) // Enabled + return IsTemporalAARequested() // Requested && postProcessEnabled // Postprocessing Enabled && (taaHistory != null) // Initialized && (cameraTargetDescriptor.msaaSamples == 1) // No MSAA @@ -457,17 +473,27 @@ internal bool IsTemporalAAEnabled() } /// - /// Returns true if the pipeline is configured to render with the STP upscaler + /// Returns true if the STP upscaler has been requested + /// Use IsSTPEnabled() to ensure that STP upscaler is active at runtime, it necessitates TAA pre-processing + /// + /// True if STP is requested + internal bool IsSTPRequested() + { + return (imageScalingMode == ImageScalingMode.Upscaling) && (upscalingFilter == ImageUpscalingFilter.STP); + } + + /// + /// Returns true if the pipeline and the given camera are configured to render with the STP upscaler /// /// When STP runs, it relies on much of the existing TAA infrastructure provided by URP's native TAA. Due to this, URP forces the anti-aliasing mode to - /// TAA when STP is enabled to ensure that most TAA logic remains active. A side effect of this behavior is that STP inherits all of the same configuration + /// TAA when STP is requested to ensure that most TAA logic remains active. A side effect of this behavior is that STP inherits all of the same configuration /// restrictions as TAA and effectively cannot run if IsTemporalAAEnabled() returns false. The post processing pass logic that executes STP handles this /// situation and STP should behave identically to TAA in cases where TAA support requirements aren't met at runtime. /// /// True if STP is enabled internal bool IsSTPEnabled() { - return (imageScalingMode == ImageScalingMode.Upscaling) && (upscalingFilter == ImageUpscalingFilter.STP); + return IsSTPRequested() && IsTemporalAAEnabled(); } /// 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 e2ea0124db6..8f2b5f0861d 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/AdditionalLightsShadowCasterPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/AdditionalLightsShadowCasterPass.cs @@ -10,57 +10,80 @@ namespace UnityEngine.Rendering.Universal.Internal /// public partial class AdditionalLightsShadowCasterPass : ScriptableRenderPass { - private static class AdditionalShadowsConstantBuffer - { - public static int _AdditionalLightsWorldToShadow; - public static int _AdditionalShadowParams; - public static int _AdditionalShadowOffset0; - public static int _AdditionalShadowOffset1; - public static int _AdditionalShadowFadeParams; - public static int _AdditionalShadowmapSize; - } - - /// - /// x is used in RenderAdditionalShadowMapAtlas to skip shadow map rendering for non-shadow-casting lights. - /// w is perLightFirstShadowSliceIndex, used in Lighting shader to find if Additional light casts shadows. - /// - readonly static Vector4 c_DefaultShadowParams = new Vector4(0, 0, 0, -1); - - static int m_AdditionalLightsWorldToShadow_SSBO; - static int m_AdditionalShadowParams_SSBO; - bool m_UseStructuredBuffer; - - const int k_ShadowmapBufferBits = 16; - private int m_AdditionalLightsShadowmapID; + // Internal internal RTHandle m_AdditionalLightsShadowmapHandle; + internal static Vector4[] s_EmptyAdditionalLightIndexToShadowParams = null; + // Private + private int renderTargetWidth; + private int renderTargetHeight; private bool m_CreateEmptyShadowmap; - private bool m_EmptyShadowmapNeedsClear = false; + private bool m_EmptyShadowmapNeedsClear; + private bool m_IssuedMessageAboutShadowSlicesTooMany; + private bool m_IssuedMessageAboutShadowMapsRescale; + private bool m_IssuedMessageAboutShadowMapsTooBig; + private bool m_IssuedMessageAboutRemovedShadowSlices; + private static bool m_IssuedMessageAboutPointLightHardShadowResolutionTooSmall; + private static bool m_IssuedMessageAboutPointLightSoftShadowResolutionTooSmall; + private readonly bool m_UseStructuredBuffer; + private float m_MaxShadowDistanceSq; + private float m_CascadeBorder; + private PassData m_PassData; private RTHandle m_EmptyAdditionalLightShadowmapTexture; + private bool[] m_VisibleLightIndexToIsCastingShadows; // maps a "global" visible light index (index to lightData.visibleLights) to a shadow casting state (Is the light casting shadows or not?) + private short[] m_VisibleLightIndexToAdditionalLightIndex; // maps a "global" visible light index (index to lightData.visibleLights) to an "additional light index" (index to arrays _AdditionalLightsPosition, _AdditionalShadowParams, ...), or -1 if it is not an additional light (i.e if it is the main light) + private short[] m_AdditionalLightIndexToVisibleLightIndex; // maps additional light index (index to arrays _AdditionalLightsPosition, _AdditionalShadowParams, ...) to its "global" visible light index (index to lightData.visibleLights) + private Vector4[] m_AdditionalLightIndexToShadowParams; // per-additional-light shadow info passed to the lighting shader (x: shadowStrength, y: softShadows, z: light type, w: perLightFirstShadowSliceIndex) + private List m_GlobalShadowSliceIndexToPerLightShadowSliceIndex = new(); // For each shadow slice, store its "per-light shadow slice index" in the punctual light that casts it (can be up to 5 for point lights) + private List m_ShadowSliceToAdditionalLightIndex = new (); // For each shadow slice, store the "additional light indices" of the punctual light that casts it + private Matrix4x4[] m_AdditionalLightShadowSliceIndexTo_WorldShadowMatrix; // per-shadow-slice info passed to the lighting shader + private ShadowSliceData[] m_AdditionalLightsShadowSlices; + private Dictionary m_ShadowRequestsHashes = new(); // used to keep track of changes in the shadow requests and shadow atlas configuration (per camera) + private ProfilingSampler m_ProfilingSetupSampler = new ProfilingSampler("Setup Additional Shadows"); + private RenderTextureDescriptor m_AdditionalLightShadowDescriptor; + + // Constants and Statics + private const int k_ShadowmapBufferBits = 16; private const int k_EmptyShadowMapDimensions = 1; private const string k_AdditionalLightShadowMapTextureName = "_AdditionalLightsShadowmapTexture"; private const string k_EmptyAdditionalLightShadowMapTextureName = "_EmptyAdditionalLightShadowmapTexture"; - internal static Vector4[] s_EmptyAdditionalLightIndexToShadowParams = null; - - float m_MaxShadowDistanceSq; - float m_CascadeBorder; - - ShadowSliceData[] m_AdditionalLightsShadowSlices = null; - - bool[] m_VisibleLightIndexToIsCastingShadows = null; // maps a "global" visible light index (index to lightData.visibleLights) to a shadow casting state (Is the light casting shadows or not?) - short[] m_VisibleLightIndexToAdditionalLightIndex = null; // maps a "global" visible light index (index to lightData.visibleLights) to an "additional light index" (index to arrays _AdditionalLightsPosition, _AdditionalShadowParams, ...), or -1 if it is not an additional light (i.e if it is the main light) - short[] m_AdditionalLightIndexToVisibleLightIndex = null; // maps additional light index (index to arrays _AdditionalLightsPosition, _AdditionalShadowParams, ...) to its "global" visible light index (index to lightData.visibleLights) - Vector4[] m_AdditionalLightIndexToShadowParams = null; // per-additional-light shadow info passed to the lighting shader (x: shadowStrength, y: softShadows, z: light type, w: perLightFirstShadowSliceIndex) - Matrix4x4[] m_AdditionalLightShadowSliceIndexTo_WorldShadowMatrix = null; // per-shadow-slice info passed to the lighting shader - List m_ShadowSliceToAdditionalLightIndex = new (); // For each shadow slice, store the "additional light indices" of the punctual light that casts it - List m_GlobalShadowSliceIndexToPerLightShadowSliceIndex = new(); // For each shadow slice, store its "per-light shadow slice index" in the punctual light that casts it (can be up to 5 for point lights) + // x is used in RenderAdditionalShadowMapAtlas to skip shadow map rendering for non-shadow-casting lights. + // w is perLightFirstShadowSliceIndex, used in Lighting shader to find if Additional light casts shadows. + readonly static Vector4 c_DefaultShadowParams = new Vector4(0, 0, 0, -1); + // Magic numbers used to identify light type when rendering shadow receiver. + // Keep in sync with AdditionalLightRealtimeShadow code in com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl + private const float LightTypeIdentifierInShadowParams_Spot = 0; + private const float LightTypeIdentifierInShadowParams_Point = 1; - int renderTargetWidth; - int renderTargetHeight; - private RenderTextureDescriptor m_AdditionalLightShadowDescriptor; + // Classes + private static class AdditionalShadowsConstantBuffer + { + public static int _AdditionalLightsWorldToShadow = Shader.PropertyToID("_AdditionalLightsWorldToShadow"); + public static int _AdditionalShadowParams = Shader.PropertyToID("_AdditionalShadowParams"); + public static int _AdditionalShadowOffset0 = Shader.PropertyToID("_AdditionalShadowOffset0"); + public static int _AdditionalShadowOffset1 = Shader.PropertyToID("_AdditionalShadowOffset1"); + public static int _AdditionalShadowFadeParams = Shader.PropertyToID("_AdditionalShadowFadeParams"); + public static int _AdditionalShadowmapSize = Shader.PropertyToID("_AdditionalShadowmapSize"); + public static int _AdditionalLightsShadowmapID = Shader.PropertyToID(k_AdditionalLightShadowMapTextureName); + public static int _AdditionalLightsWorldToShadow_SSBO = Shader.PropertyToID("_AdditionalLightsWorldToShadow_SSBO"); + public static int _AdditionalShadowParams_SSBO = Shader.PropertyToID("_AdditionalShadowParams_SSBO"); + } - ProfilingSampler m_ProfilingSetupSampler = new ProfilingSampler("Setup Additional Shadows"); - private PassData m_PassData; + private class PassData + { + internal int shadowmapID; + internal bool emptyShadowmap; + internal bool useStructuredBuffer; + internal bool stripShadowsOffVariants; + internal Matrix4x4 viewMatrix; + internal Vector2Int allocatedShadowAtlasSize; + internal TextureHandle shadowmapTexture; + internal RendererList[] shadowRendererLists = new RendererList[ShaderOptions.k_MaxVisibleLightCountDesktop]; + internal RendererListHandle[] shadowRendererListsHdl = new RendererListHandle[ShaderOptions.k_MaxVisibleLightCountDesktop]; + internal UniversalLightData lightData; + internal UniversalShadowData shadowData; + internal AdditionalLightsShadowCasterPass pass; + } /// /// Creates a new AdditionalLightsShadowCasterPass instance. @@ -73,17 +96,6 @@ public AdditionalLightsShadowCasterPass(RenderPassEvent evt) renderPassEvent = evt; m_PassData = new PassData(); - AdditionalShadowsConstantBuffer._AdditionalLightsWorldToShadow = Shader.PropertyToID("_AdditionalLightsWorldToShadow"); - AdditionalShadowsConstantBuffer._AdditionalShadowParams = Shader.PropertyToID("_AdditionalShadowParams"); - AdditionalShadowsConstantBuffer._AdditionalShadowOffset0 = Shader.PropertyToID("_AdditionalShadowOffset0"); - AdditionalShadowsConstantBuffer._AdditionalShadowOffset1 = Shader.PropertyToID("_AdditionalShadowOffset1"); - AdditionalShadowsConstantBuffer._AdditionalShadowFadeParams = Shader.PropertyToID("_AdditionalShadowFadeParams"); - AdditionalShadowsConstantBuffer._AdditionalShadowmapSize = Shader.PropertyToID("_AdditionalShadowmapSize"); - m_AdditionalLightsShadowmapID = Shader.PropertyToID(k_AdditionalLightShadowMapTextureName); - - m_AdditionalLightsWorldToShadow_SSBO = Shader.PropertyToID("_AdditionalLightsWorldToShadow_SSBO"); - m_AdditionalShadowParams_SSBO = Shader.PropertyToID("_AdditionalShadowParams_SSBO"); - m_UseStructuredBuffer = RenderingUtils.useStructuredBuffer; // Preallocated a fixed size. CommandBuffer.SetGlobal* does allow this data to grow. @@ -104,11 +116,9 @@ public AdditionalLightsShadowCasterPass(RenderPassEvent evt) for (int i = 0; i < s_EmptyAdditionalLightIndexToShadowParams.Length; i++) s_EmptyAdditionalLightIndexToShadowParams[i] = c_DefaultShadowParams; + // Uniform buffers are faster on some platforms, but they have stricter size limitations if (!m_UseStructuredBuffer) - { - // Uniform buffers are faster on some platforms, but they have stricter size limitations m_AdditionalLightShadowSliceIndexTo_WorldShadowMatrix = new Matrix4x4[maxVisibleAdditionalLights]; - } m_EmptyShadowmapNeedsClear = true; } @@ -122,12 +132,6 @@ public void Dispose() m_EmptyAdditionalLightShadowmapTexture?.Release(); } - // Magic numbers used to identify light type when rendering shadow receiver. - // Keep in sync with AdditionalLightRealtimeShadow code in com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl - private const float LightTypeIdentifierInShadowParams_Spot = 0; - private const float LightTypeIdentifierInShadowParams_Point = 1; - - // Returns the guard angle that must be added to a frustum angle covering a projection map of resolution sliceResolutionInTexels, // in order to also cover a guard band of size guardBandSizeInTexels around the projection map. // Formula illustrated in https://i.ibb.co/wpW5Mnf/Calc-Guard-Angle.png @@ -152,7 +156,6 @@ internal static float CalcGuardAngle(float frustumAngleInDegrees, float guardBan return guardAngleInDegree; } - // Returns the guard angle that must be added to a point light shadow face frustum angle // in order to avoid shadows missing at the boundaries between cube faces. internal static float GetPointLightShadowFrustumFovBiasInDegrees(int shadowSliceResolution, bool shadowFiltering) @@ -166,7 +169,6 @@ internal static float GetPointLightShadowFrustumFovBiasInDegrees(int shadowSlice return fudgeFactor * CalcGuardAngle(90, shadowFiltering ? 5 : 1, shadowSliceResolution); #endif - float fovBias = 4.00f; // Empirical value found to remove gaps between point light shadow faces in test scenes. @@ -229,16 +231,7 @@ internal static float GetPointLightShadowFrustumFovBiasInDegrees(int shadowSlice return fovBias; } - private bool m_IssuedMessageAboutShadowSlicesTooMany = false; - private bool m_IssuedMessageAboutShadowMapsRescale = false; - private bool m_IssuedMessageAboutShadowMapsTooBig = false; - private bool m_IssuedMessageAboutRemovedShadowSlices = false; - private static bool m_IssuedMessageAboutPointLightHardShadowResolutionTooSmall = false; - private static bool m_IssuedMessageAboutPointLightSoftShadowResolutionTooSmall = false; - - Dictionary m_ShadowRequestsHashes = new Dictionary(); // used to keep track of changes in the shadow requests and shadow atlas configuration (per camera) - - ulong ResolutionLog2ForHash(int resolution) + private ulong ResolutionLog2ForHash(int resolution) { switch (resolution) { @@ -250,7 +243,7 @@ ulong ResolutionLog2ForHash(int resolution) return 08; } - ulong ComputeShadowRequestHash(UniversalLightData lightData, UniversalShadowData shadowData) + private ulong ComputeShadowRequestHash(UniversalLightData lightData, UniversalShadowData shadowData) { ulong numberOfShadowedPointLights = 0; ulong numberOfSoftShadowedLights = 0; @@ -605,7 +598,7 @@ private void UpdateTextureDescriptorIfNeeded() } } - bool SetupForEmptyRendering(bool stripShadowsOffVariants, UniversalShadowData shadowData) + private bool SetupForEmptyRendering(bool stripShadowsOffVariants, UniversalShadowData shadowData) { if (!stripShadowsOffVariants) return false; @@ -636,12 +629,6 @@ public override void Configure(CommandBuffer cmd, RenderTextureDescriptor camera if (!m_EmptyShadowmapNeedsClear) { - // UUM-63146 - 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 - // Resetting of target would clean up the color attachment buffers and depth attachment buffers, which inturn is preventing the leak in the said platform. This is likely a symptomatic fix, but is solving the problem for now. - - if (Application.platform == RuntimePlatform.Android && PlatformAutoDetect.isRunningOnPowerVRGPU) - ResetTarget(); - return; } @@ -668,7 +655,7 @@ public override void Execute(ScriptableRenderContext context, ref RenderingData if (m_CreateEmptyShadowmap) { SetEmptyAdditionalShadowmapAtlas(CommandBufferHelpers.GetRasterCommandBuffer(renderingData.commandBuffer)); - universalRenderingData.commandBuffer.SetGlobalTexture(m_AdditionalLightsShadowmapID, m_EmptyAdditionalLightShadowmapTexture); + universalRenderingData.commandBuffer.SetGlobalTexture(AdditionalShadowsConstantBuffer._AdditionalLightsShadowmapID, m_EmptyAdditionalLightShadowmapTexture); return; } @@ -682,7 +669,7 @@ public override void Execute(ScriptableRenderContext context, ref RenderingData m_PassData.allocatedShadowAtlasSize = m_AdditionalLightsShadowmapHandle.referenceSize; InitRendererLists(ref universalRenderingData.cullResults, ref m_PassData, context, default(RenderGraph), false); RenderAdditionalShadowmapAtlas(CommandBufferHelpers.GetRasterCommandBuffer(universalRenderingData.commandBuffer), ref m_PassData, false); - universalRenderingData.commandBuffer.SetGlobalTexture(m_AdditionalLightsShadowmapID, m_AdditionalLightsShadowmapHandle.nameID); + universalRenderingData.commandBuffer.SetGlobalTexture(AdditionalShadowsConstantBuffer._AdditionalLightsShadowmapID, m_AdditionalLightsShadowmapHandle.nameID); } /// @@ -698,13 +685,13 @@ public int GetShadowLightIndexFromLightIndex(int visibleLightIndex) return m_VisibleLightIndexToAdditionalLightIndex[visibleLightIndex]; } - void Clear() + private void Clear() { m_ShadowSliceToAdditionalLightIndex.Clear(); m_GlobalShadowSliceIndexToPerLightShadowSliceIndex.Clear(); } - void SetEmptyAdditionalShadowmapAtlas(RasterCommandBuffer cmd) + private void SetEmptyAdditionalShadowmapAtlas(RasterCommandBuffer cmd) { cmd.EnableKeyword(ShaderGlobalKeywords.AdditionalLightShadows); SetEmptyAdditionalLightShadowParams(cmd, m_AdditionalLightIndexToShadowParams); @@ -716,7 +703,7 @@ internal static void SetEmptyAdditionalLightShadowParams(RasterCommandBuffer cmd { ComputeBuffer shadowParamsBuffer = ShaderData.instance.GetAdditionalLightShadowParamsStructuredBuffer(lightIndexToShadowParams.Length); shadowParamsBuffer.SetData(lightIndexToShadowParams); - cmd.SetGlobalBuffer(m_AdditionalShadowParams_SSBO, shadowParamsBuffer); + cmd.SetGlobalBuffer(AdditionalShadowsConstantBuffer._AdditionalShadowParams_SSBO, shadowParamsBuffer); } else { @@ -724,7 +711,7 @@ internal static void SetEmptyAdditionalLightShadowParams(RasterCommandBuffer cmd } } - void RenderAdditionalShadowmapAtlas(RasterCommandBuffer cmd, ref PassData data, bool useRenderGraph) + private void RenderAdditionalShadowmapAtlas(RasterCommandBuffer cmd, ref PassData data, bool useRenderGraph) { NativeArray visibleLights = data.lightData.visibleLights; @@ -802,19 +789,19 @@ void RenderAdditionalShadowmapAtlas(RasterCommandBuffer cmd, ref PassData data, } // Set constant buffer data that will be used during the lighting/shadowing pass - void SetupAdditionalLightsShadowReceiverConstants(RasterCommandBuffer cmd, Vector2Int allocatedShadowAtlasSize, bool useStructuredBuffer, bool softShadows) + private void SetupAdditionalLightsShadowReceiverConstants(RasterCommandBuffer cmd, Vector2Int allocatedShadowAtlasSize, bool useStructuredBuffer, bool softShadows) { if (useStructuredBuffer) { // per-light data var shadowParamsBuffer = ShaderData.instance.GetAdditionalLightShadowParamsStructuredBuffer(m_AdditionalLightIndexToShadowParams.Length); shadowParamsBuffer.SetData(m_AdditionalLightIndexToShadowParams); - cmd.SetGlobalBuffer(m_AdditionalShadowParams_SSBO, shadowParamsBuffer); + cmd.SetGlobalBuffer(AdditionalShadowsConstantBuffer._AdditionalShadowParams_SSBO, shadowParamsBuffer); // per-shadow-slice data var shadowSliceMatricesBuffer = ShaderData.instance.GetAdditionalLightShadowSliceMatricesStructuredBuffer(m_AdditionalLightShadowSliceIndexTo_WorldShadowMatrix.Length); shadowSliceMatricesBuffer.SetData(m_AdditionalLightShadowSliceIndexTo_WorldShadowMatrix); - cmd.SetGlobalBuffer(m_AdditionalLightsWorldToShadow_SSBO, shadowSliceMatricesBuffer); + cmd.SetGlobalBuffer(AdditionalShadowsConstantBuffer._AdditionalLightsWorldToShadow_SSBO, shadowSliceMatricesBuffer); } else { @@ -842,26 +829,6 @@ void SetupAdditionalLightsShadowReceiverConstants(RasterCommandBuffer cmd, Vecto } } - private class PassData - { - internal UniversalLightData lightData; - internal UniversalShadowData shadowData; - internal Matrix4x4 viewMatrix; - internal bool stripShadowsOffVariants; - - internal AdditionalLightsShadowCasterPass pass; - - internal TextureHandle shadowmapTexture; - internal int shadowmapID; - internal bool useStructuredBuffer; - internal Vector2Int allocatedShadowAtlasSize; - - internal bool emptyShadowmap; - - internal RendererListHandle[] shadowRendererListsHdl = new RendererListHandle[ShaderOptions.k_MaxVisibleLightCountDesktop]; - internal RendererList[] shadowRendererLists = new RendererList[ShaderOptions.k_MaxVisibleLightCountDesktop]; - } - private void InitPassData(ref PassData passData, UniversalCameraData cameraData, UniversalLightData lightData, UniversalShadowData shadowData) { passData.pass = this; @@ -872,11 +839,11 @@ private void InitPassData(ref PassData passData, UniversalCameraData cameraData, passData.stripShadowsOffVariants = cameraData.renderer.stripShadowsOffVariants; passData.emptyShadowmap = m_CreateEmptyShadowmap; - passData.shadowmapID = m_AdditionalLightsShadowmapID; + passData.shadowmapID = AdditionalShadowsConstantBuffer._AdditionalLightsShadowmapID; passData.useStructuredBuffer = m_UseStructuredBuffer; } - void InitEmptyPassData(ref PassData passData, UniversalCameraData cameraData, UniversalLightData lightData, UniversalShadowData shadowData) + private void InitEmptyPassData(ref PassData passData, UniversalCameraData cameraData, UniversalLightData lightData, UniversalShadowData shadowData) { passData.pass = this; @@ -885,7 +852,7 @@ void InitEmptyPassData(ref PassData passData, UniversalCameraData cameraData, Un passData.stripShadowsOffVariants = cameraData.renderer.stripShadowsOffVariants; passData.emptyShadowmap = m_CreateEmptyShadowmap; - passData.shadowmapID = m_AdditionalLightsShadowmapID; + passData.shadowmapID = AdditionalShadowsConstantBuffer._AdditionalLightsShadowmapID; } private void InitRendererLists(ref CullingResults cullResults, ref PassData passData, ScriptableRenderContext context, RenderGraph renderGraph, bool useRenderGraph) 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 1ff4cb64c77..0ad302b9652 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/MainLightShadowCasterPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/MainLightShadowCasterPass.cs @@ -35,7 +35,7 @@ public class MainLightShadowCasterPass : ScriptableRenderPass private const int k_ShadowmapBufferBits = 16; private const string k_MainLightShadowMapTextureName = "_MainLightShadowmapTexture"; private const string k_EmptyMainLightShadowMapTextureName = "_EmptyMainLightShadowmapTexture"; - private static readonly Vector4 s_EmptyShadowParams = new (1, 0, 1, 0); + private static readonly Vector4 s_EmptyShadowParams = new (0f, 0f, 1f, 0f); private static readonly Vector4 s_EmptyShadowmapSize = new (k_EmptyShadowMapDimensions, 1f / k_EmptyShadowMapDimensions, k_EmptyShadowMapDimensions, k_EmptyShadowMapDimensions); // Classes @@ -54,6 +54,22 @@ private static class MainLightShadowConstantBuffer public static readonly int _MainLightShadowmapID = Shader.PropertyToID(k_MainLightShadowMapTextureName); } + private class PassData + { + internal UniversalRenderingData renderingData; + internal UniversalCameraData cameraData; + internal UniversalLightData lightData; + internal UniversalShadowData shadowData; + + internal MainLightShadowCasterPass pass; + + internal TextureHandle shadowmapTexture; + internal bool emptyShadowmap; + + internal RendererListHandle[] shadowRendererListsHandle = new RendererListHandle[k_MaxCascades]; + internal RendererList[] shadowRendererLists = new RendererList[k_MaxCascades]; + } + /// /// Creates a new MainLightShadowCasterPass instance. /// @@ -201,14 +217,7 @@ public override void Configure(CommandBuffer cmd, RenderTextureDescriptor camera m_EmptyShadowmapNeedsClear = true; if (!m_EmptyShadowmapNeedsClear) - { - // UUM-63146 - 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 - // Resetting of target would clean up the color attachment buffers and depth attachment buffers, which inturn is preventing the leak in the said platform. This is likely a symptomatic fix, but is solving the problem for now. - if (Application.platform == RuntimePlatform.Android && PlatformAutoDetect.isRunningOnPowerVRGPU) - ResetTarget(); - return; - } ConfigureTarget(m_EmptyMainLightShadowmapTexture); m_EmptyShadowmapNeedsClear = false; @@ -375,22 +384,6 @@ void SetupMainLightShadowReceiverConstants(RasterCommandBuffer cmd, ref VisibleL } } - private class PassData - { - internal UniversalRenderingData renderingData; - internal UniversalCameraData cameraData; - internal UniversalLightData lightData; - internal UniversalShadowData shadowData; - - internal MainLightShadowCasterPass pass; - - internal TextureHandle shadowmapTexture; - internal bool emptyShadowmap; - - internal RendererListHandle[] shadowRendererListsHandle = new RendererListHandle[k_MaxCascades]; - internal RendererList[] shadowRendererLists = new RendererList[k_MaxCascades]; - } - private void InitPassData( ref PassData passData, UniversalRenderingData renderingData, 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 c0469c81572..0d61eeb7bd9 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPass.cs @@ -463,7 +463,7 @@ void Render(CommandBuffer cmd, ref RenderingData renderingData) // disable useTemporalAA if another feature is disabled) then we need to put it in CameraData::IsTemporalAAEnabled() as opposed // to tweaking the value here. bool useTemporalAA = cameraData.IsTemporalAAEnabled(); - if (cameraData.antialiasing == AntialiasingMode.TemporalAntiAliasing && !useTemporalAA) + if (cameraData.IsTemporalAARequested() && !useTemporalAA) TemporalAA.ValidateAndWarn(cameraData); int amountOfPassesRemaining = (useStopNan ? 1 : 0) + (useSubPixeMorpAA ? 1 : 0) + (useDepthOfField ? 1 : 0) + (useLensFlare ? 1 : 0) + (useTemporalAA ? 1 : 0) + (useMotionBlur ? 1 : 0) + (usePaniniProjection ? 1 : 0); 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 6e083d54b17..48282b7dbf9 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPassRenderGraph.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPassRenderGraph.cs @@ -1996,12 +1996,15 @@ public void RenderPostProcessingRenderGraph(RenderGraph renderGraph, ContextCont // disable useTemporalAA if another feature is disabled) then we need to put it in CameraData::IsTemporalAAEnabled() as opposed // to tweaking the value here. bool useTemporalAA = cameraData.IsTemporalAAEnabled(); - if (cameraData.antialiasing == AntialiasingMode.TemporalAntiAliasing && !useTemporalAA) - TemporalAA.ValidateAndWarn(cameraData); - // STP is only supported when TAA is enabled and all of its runtime requirements are met. - // See the comments for IsSTPEnabled() for more information. - bool useSTP = useTemporalAA && cameraData.IsSTPEnabled(); + // STP is only enabled when TAA is enabled and all of its runtime requirements are met. + // Using IsSTPRequested() vs IsSTPEnabled() for perf reason here, as we already know TAA status + bool isSTPRequested = cameraData.IsSTPRequested(); + bool useSTP = useTemporalAA && isSTPRequested; + + // Warn users if TAA and STP are disabled despite being requested + if (!useTemporalAA && cameraData.IsTemporalAARequested()) + TemporalAA.ValidateAndWarn(cameraData, isSTPRequested); using (var builder = renderGraph.AddRasterRenderPass("Setup PostFX passes", out var passData, ProfilingSampler.Get(URPProfileId.RG_SetupPostFX))) diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/TransparentSettingsPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/TransparentSettingsPass.cs index 85cfa3182e0..6a96fc30918 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/TransparentSettingsPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/TransparentSettingsPass.cs @@ -37,11 +37,11 @@ public override void Execute(ScriptableRenderContext context, ref RenderingData } public static void ExecutePass(RasterCommandBuffer cmd, bool shouldReceiveShadows) - { + { // This pass is only used when transparent objects should not // receive shadows using the setting on the URP Renderer. MainLightShadowCasterPass.SetEmptyMainLightShadowParams(cmd); - AdditionalLightsShadowCasterPass.SetEmptyAdditionalLightShadowParams(cmd, AdditionalLightsShadowCasterPass.s_EmptyAdditionalLightIndexToShadowParams); + AdditionalLightsShadowCasterPass.SetEmptyAdditionalLightShadowParams(cmd, AdditionalLightsShadowCasterPass.s_EmptyAdditionalLightIndexToShadowParams); } } } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/RTHandleUtils.cs b/Packages/com.unity.render-pipelines.universal/Runtime/RTHandleUtils.cs index ce87321a59d..10785882b1b 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/RTHandleUtils.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/RTHandleUtils.cs @@ -26,7 +26,7 @@ internal class RTHandleResourcePool protected static int s_StaleResourceMaxCapacity = 32; /// - /// Controls the resource pool's max stale resource capacity. + /// Controls the resource pool's max stale resource capacity. /// Increasing the capacity may have a negative impact on the memory usage. /// Increasing the capacity may reduce the runtime RTHandle realloc cost in multi view/multi camera setup. /// Setting capacity will purge the current pool. It is recommended to setup the capacity upfront and not changing it during the runtime. @@ -83,7 +83,7 @@ internal bool TryGetResource(in TextureDesc texDesc, out RTHandle resource, bool return false; } - // Release all resources in pool. + // Release all resources in pool. internal void Cleanup() { foreach (var kvp in m_ResourcePool) @@ -198,6 +198,7 @@ internal static TextureDesc CreateTextureDesc(RenderTextureDescriptor desc, rgDesc.memoryless = RenderTextureMemoryless.None; rgDesc.vrUsage = VRTextureUsage.None; rgDesc.name = name; + rgDesc.enableShadingRate = desc.enableShadingRate; return rgDesc; } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/RenderingUtils.cs b/Packages/com.unity.render-pipelines.universal/Runtime/RenderingUtils.cs index 3d2ec7a4d9d..4fb15c0c4f5 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/RenderingUtils.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/RenderingUtils.cs @@ -5,6 +5,7 @@ using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering.RenderGraphModule; using System.Diagnostics; +using System.Runtime.CompilerServices; namespace UnityEngine.Rendering.Universal { @@ -125,7 +126,17 @@ static Material errorMaterial /// Projection matrix to be set. /// Set this to true if you also need to set inverse camera matrices. public static void SetViewAndProjectionMatrices(CommandBuffer cmd, Matrix4x4 viewMatrix, Matrix4x4 projectionMatrix, bool setInverseMatrices) { SetViewAndProjectionMatrices(CommandBufferHelpers.GetRasterCommandBuffer(cmd), viewMatrix, projectionMatrix, setInverseMatrices); } - internal static void SetViewAndProjectionMatrices(RasterCommandBuffer cmd, Matrix4x4 viewMatrix, Matrix4x4 projectionMatrix, bool setInverseMatrices) + + /// + /// Set view and projection matrices. + /// This function will set UNITY_MATRIX_V, UNITY_MATRIX_P, UNITY_MATRIX_VP to given view and projection matrices. + /// If setInverseMatrices is set to true this function will also set UNITY_MATRIX_I_V and UNITY_MATRIX_I_VP. + /// + /// RasterCommandBuffer to submit data to GPU. + /// View matrix to be set. + /// Projection matrix to be set. + /// Set this to true if you also need to set inverse camera matrices. + public static void SetViewAndProjectionMatrices(RasterCommandBuffer cmd, Matrix4x4 viewMatrix, Matrix4x4 projectionMatrix, bool setInverseMatrices) { Matrix4x4 viewAndProjectionMatrix = projectionMatrix * viewMatrix; cmd.SetGlobalMatrix(ShaderPropertyId.viewMatrix, viewMatrix); @@ -426,8 +437,8 @@ public static bool SupportsRenderTextureFormat(RenderTextureFormat format) [Obsolete("Use SystemInfo.IsFormatSupported instead.", false)] public static bool SupportsGraphicsFormat(GraphicsFormat format, FormatUsage usage) { - GraphicsFormatUsage graphicsFormatUsage = (GraphicsFormatUsage)(1 << (int)usage); - return SystemInfo.IsFormatSupported(format, graphicsFormatUsage); + GraphicsFormatUsage graphicsFormatUsage = (GraphicsFormatUsage)(1 << (int)usage); + return SystemInfo.IsFormatSupported(format, graphicsFormatUsage); } /// @@ -592,11 +603,6 @@ internal static bool MultisampleDepthResolveSupported() /// /// RTHandle to check (can be null) /// Descriptor for the RTHandle to match - /// Filtering mode of the RTHandle. - /// Addressing mode of the RTHandle. - /// Anisotropic filtering level. - /// Bias applied to mipmaps during filtering. - /// Name of the RTHandle. /// Check if the RTHandle has auto scaling enabled if not, check the widths and heights /// internal static bool RTHandleNeedsReAlloc( @@ -610,18 +616,25 @@ internal static bool RTHandleNeedsReAlloc( return true; if (!scaled && (handle.rt.width != descriptor.width || handle.rt.height != descriptor.height)) return true; + if (handle.rt.enableShadingRate && handle.rt.graphicsFormat != descriptor.colorFormat) + return true; var rtHandleFormat = (handle.rt.descriptor.depthStencilFormat != GraphicsFormat.None) ? handle.rt.descriptor.depthStencilFormat : handle.rt.descriptor.graphicsFormat; + var isShadowMap = handle.rt.descriptor.shadowSamplingMode != ShadowSamplingMode.None; return rtHandleFormat != descriptor.format || handle.rt.descriptor.dimension != descriptor.dimension || + handle.rt.descriptor.volumeDepth != descriptor.slices || handle.rt.descriptor.enableRandomWrite != descriptor.enableRandomWrite || + handle.rt.descriptor.enableShadingRate != descriptor.enableShadingRate || handle.rt.descriptor.useMipMap != descriptor.useMipMap || handle.rt.descriptor.autoGenerateMips != descriptor.autoGenerateMips || + isShadowMap != descriptor.isShadowMap || (MSAASamples)handle.rt.descriptor.msaaSamples != descriptor.msaaSamples || handle.rt.descriptor.bindMS != descriptor.bindTextureMS || handle.rt.descriptor.useDynamicScale != descriptor.useDynamicScale || + handle.rt.descriptor.useDynamicScaleExplicit != descriptor.useDynamicScaleExplicit || handle.rt.descriptor.memoryless != descriptor.memoryless || handle.rt.filterMode != descriptor.filterMode || handle.rt.wrapMode != descriptor.wrapMode || @@ -837,28 +850,7 @@ public static bool ReAllocateHandleIfNeeded( return true; } - var actualFormat = descriptor.graphicsFormat != GraphicsFormat.None ? descriptor.graphicsFormat : descriptor.depthStencilFormat; - - RTHandleAllocInfo allocInfo = new RTHandleAllocInfo(); - allocInfo.slices = descriptor.volumeDepth; - allocInfo.format = actualFormat; - allocInfo.filterMode = filterMode; - allocInfo.wrapModeU = wrapMode; - allocInfo.wrapModeV = wrapMode; - allocInfo.wrapModeW = wrapMode; - allocInfo.dimension = descriptor.dimension; - allocInfo.enableRandomWrite = descriptor.enableRandomWrite; - allocInfo.useMipMap = descriptor.useMipMap; - allocInfo.autoGenerateMips = descriptor.autoGenerateMips; - allocInfo.anisoLevel = anisoLevel; - allocInfo.mipMapBias = mipMapBias; - allocInfo.msaaSamples = (MSAASamples)descriptor.msaaSamples; - allocInfo.bindTextureMS = descriptor.bindMS; - allocInfo.useDynamicScale = descriptor.useDynamicScale; - allocInfo.memoryless = descriptor.memoryless; - allocInfo.vrUsage = descriptor.vrUsage; - allocInfo.name = name; - + var allocInfo = CreateRTHandleAllocInfo(descriptor, filterMode, wrapMode, anisoLevel, mipMapBias, name); handle = RTHandles.Alloc(descriptor.width, descriptor.height, allocInfo); return true; } @@ -902,28 +894,7 @@ public static bool ReAllocateHandleIfNeeded( return true; } - var actualFormat = descriptor.graphicsFormat != GraphicsFormat.None ? descriptor.graphicsFormat : descriptor.depthStencilFormat; - - RTHandleAllocInfo allocInfo = new RTHandleAllocInfo(); - allocInfo.slices = descriptor.volumeDepth; - allocInfo.format = actualFormat; - allocInfo.filterMode = filterMode; - allocInfo.wrapModeU = wrapMode; - allocInfo.wrapModeV = wrapMode; - allocInfo.wrapModeW = wrapMode; - allocInfo.dimension = descriptor.dimension; - allocInfo.enableRandomWrite = descriptor.enableRandomWrite; - allocInfo.useMipMap = descriptor.useMipMap; - allocInfo.autoGenerateMips = descriptor.autoGenerateMips; - allocInfo.anisoLevel = anisoLevel; - allocInfo.mipMapBias = mipMapBias; - allocInfo.msaaSamples = (MSAASamples)descriptor.msaaSamples; - allocInfo.bindTextureMS = descriptor.bindMS; - allocInfo.useDynamicScale = descriptor.useDynamicScale; - allocInfo.memoryless = descriptor.memoryless; - allocInfo.vrUsage = descriptor.vrUsage; - allocInfo.name = name; - + var allocInfo = CreateRTHandleAllocInfo(descriptor, filterMode, wrapMode, anisoLevel, mipMapBias, name); handle = RTHandles.Alloc(scaleFactor, allocInfo); return true; } @@ -967,28 +938,7 @@ public static bool ReAllocateHandleIfNeeded( return true; } - var actualFormat = descriptor.graphicsFormat != GraphicsFormat.None ? descriptor.graphicsFormat : descriptor.depthStencilFormat; - - RTHandleAllocInfo allocInfo = new RTHandleAllocInfo(); - allocInfo.slices = descriptor.volumeDepth; - allocInfo.format = actualFormat; - allocInfo.filterMode = filterMode; - allocInfo.wrapModeU = wrapMode; - allocInfo.wrapModeV = wrapMode; - allocInfo.wrapModeW = wrapMode; - allocInfo.dimension = descriptor.dimension; - allocInfo.enableRandomWrite = descriptor.enableRandomWrite; - allocInfo.useMipMap = descriptor.useMipMap; - allocInfo.autoGenerateMips = descriptor.autoGenerateMips; - allocInfo.anisoLevel = anisoLevel; - allocInfo.mipMapBias = mipMapBias; - allocInfo.msaaSamples = (MSAASamples)descriptor.msaaSamples; - allocInfo.bindTextureMS = descriptor.bindMS; - allocInfo.useDynamicScale = descriptor.useDynamicScale; - allocInfo.memoryless = descriptor.memoryless; - allocInfo.vrUsage = descriptor.vrUsage; - allocInfo.name = name; - + var allocInfo = CreateRTHandleAllocInfo(descriptor, filterMode, wrapMode, anisoLevel, mipMapBias, name); handle = RTHandles.Alloc(scaleFunc, allocInfo); return true; } @@ -1128,5 +1078,38 @@ internal static Vector4 GetFinalBlitScaleBias(RTHandle source, RTHandle destinat return scaleBias; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static RTHandleAllocInfo CreateRTHandleAllocInfo(in RenderTextureDescriptor descriptor, FilterMode filterMode, TextureWrapMode wrapMode, int anisoLevel, float mipMapBias, string name) + { + var actualFormat = descriptor.graphicsFormat != GraphicsFormat.None ? descriptor.graphicsFormat : descriptor.depthStencilFormat; + + // NOTE: this calls default(RTHandleAllocInfo) not RTHandleAllocInfo(string = "") + RTHandleAllocInfo allocInfo = new RTHandleAllocInfo(); + allocInfo.slices = descriptor.volumeDepth; + allocInfo.format = actualFormat; + allocInfo.filterMode = filterMode; + allocInfo.wrapModeU = wrapMode; + allocInfo.wrapModeV = wrapMode; + allocInfo.wrapModeW = wrapMode; + allocInfo.dimension = descriptor.dimension; + allocInfo.enableRandomWrite = descriptor.enableRandomWrite; + allocInfo.enableShadingRate = descriptor.enableShadingRate; + allocInfo.useMipMap = descriptor.useMipMap; + allocInfo.autoGenerateMips = descriptor.autoGenerateMips; + allocInfo.anisoLevel = anisoLevel; + allocInfo.mipMapBias = mipMapBias; + allocInfo.isShadowMap = descriptor.shadowSamplingMode != ShadowSamplingMode.None; + allocInfo.msaaSamples = (MSAASamples)descriptor.msaaSamples; + allocInfo.bindTextureMS = descriptor.bindMS; + allocInfo.useDynamicScale = descriptor.useDynamicScale; + allocInfo.useDynamicScaleExplicit = descriptor.useDynamicScaleExplicit; + allocInfo.memoryless = descriptor.memoryless; + allocInfo.vrUsage = descriptor.vrUsage; + allocInfo.enableShadingRate = descriptor.enableShadingRate; + allocInfo.name = name; + + return allocInfo; + } } } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/ShaderUtils.cs b/Packages/com.unity.render-pipelines.universal/Runtime/ShaderUtils.cs index f32cd66e283..17ef53262b3 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/ShaderUtils.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/ShaderUtils.cs @@ -94,6 +94,7 @@ public static class ShaderUtils "Universal Render Pipeline/Nature/SpeedTree7", "Universal Render Pipeline/Nature/SpeedTree7 Billboard", "Universal Render Pipeline/Nature/SpeedTree8_PBRLit", + "SpeedTree9_Dummy_Path", // SpeedTree9 is shadergraph-only and does not have an HLSLF version, but this entry is still required "Universal Render Pipeline/Complex Lit", }; diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/TemporalAA.cs b/Packages/com.unity.render-pipelines.universal/Runtime/TemporalAA.cs index cdbfe3fc43a..b0da32158d6 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/TemporalAA.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/TemporalAA.cs @@ -337,47 +337,47 @@ internal static RenderTextureDescriptor TemporalAADescFromCameraDesc(ref RenderT static uint s_warnCounter = 0; - internal static string ValidateAndWarn(UniversalCameraData cameraData) + internal static string ValidateAndWarn(UniversalCameraData cameraData, bool isSTPRequested = false) { - string warning = null; + string reasonWarning = null; - if(warning == null && !cameraData.postProcessEnabled) - warning = "Disabling TAA because camera has post-processing disabled."; + if(reasonWarning == null && !cameraData.postProcessEnabled) + reasonWarning = "because camera has post-processing disabled."; if (cameraData.taaHistory == null) { - warning = "Disabling TAA due to invalid persistent data."; + reasonWarning = "due to invalid persistent data."; } - if (warning == null && cameraData.cameraTargetDescriptor.msaaSamples != 1) + if (reasonWarning == null && cameraData.cameraTargetDescriptor.msaaSamples != 1) { if (cameraData.xr != null && cameraData.xr.enabled) - warning = "Disabling TAA because MSAA is on. MSAA must be disabled globally for all cameras in XR mode."; + reasonWarning = "because MSAA is on. MSAA must be disabled globally for all cameras in XR mode."; else - warning = "Disabling TAA because MSAA is on. Turn MSAA off on the camera or current URP Asset to enable TAA."; + reasonWarning = "because MSAA is on. Turn MSAA off on the camera or current URP Asset."; } - if(warning == null && cameraData.camera.TryGetComponent(out var additionalCameraData)) + if(reasonWarning == null && cameraData.camera.TryGetComponent(out var additionalCameraData)) { if (additionalCameraData.renderType == CameraRenderType.Overlay || additionalCameraData.cameraStack.Count > 0) { - warning = "Disabling TAA because camera is stacked."; + reasonWarning = "because camera is stacked."; } } - if (warning == null && cameraData.camera.allowDynamicResolution) - warning = "Disabling TAA because camera has dynamic resolution enabled. You can use a constant render scale instead."; + if (reasonWarning == null && cameraData.camera.allowDynamicResolution) + reasonWarning = "because camera has dynamic resolution enabled. You can use a constant render scale instead."; - if(warning == null && !cameraData.renderer.SupportsMotionVectors()) - warning = "Disabling TAA because the renderer does not implement motion vectors. Motion vectors are required for TAA."; + if(reasonWarning == null && !cameraData.renderer.SupportsMotionVectors()) + reasonWarning = "because the renderer does not implement motion vectors. Motion vectors are required."; const int warningThrottleFrames = 60 * 1; // 60 FPS * 1 sec if (s_warnCounter % warningThrottleFrames == 0) - Debug.LogWarning(warning); + Debug.LogWarning("Disabling TAA " + (isSTPRequested ? "and STP " : "") + reasonWarning); s_warnCounter++; - return warning; + return reasonWarning; } internal static void ExecutePass(CommandBuffer cmd, Material taaMaterial, ref CameraData cameraData, RTHandle source, RTHandle destination, RenderTexture motionVectors) diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs index cf37da04b80..810ab80a71e 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs @@ -1,6 +1,7 @@ using System; using Unity.Collections; using System.Collections.Generic; +using System.Reflection; #if UNITY_EDITOR using UnityEditor; using UnityEditor.Rendering.Universal; @@ -151,7 +152,18 @@ public static int maxVisibleAdditionalLights } } - internal static bool useDynamicBranchFogKeyword => ShaderOptions.k_UseDynamicBranchFogKeyword == 1; +#if UNITY_EDITOR + internal static bool UseDynamicBranchFogKeyword() + { + const string kMemberName = "k_UseDynamicBranchFogKeyword"; + Type type = typeof(ShaderOptions); + MemberInfo[] memberInfo = type.GetMember(kMemberName); + if (memberInfo.Length == 0) + return false; + int value = (int)((FieldInfo)memberInfo[0]).GetValue(null); + return value == 1; + } +#endif // Match with values in Input.hlsl internal static int lightsPerTile => ((maxVisibleAdditionalLights + 31) / 32) * 32; @@ -290,11 +302,16 @@ public UniversalRenderPipeline(UniversalRenderPipelineAsset asset) #pragma warning restore 618 }); } + + // Initializes only if VRS is supported. + Vrs.InitializeResources(); } /// protected override void Dispose(bool disposing) { + Vrs.DisposeResources(); + if (apvIsEnabled) { ProbeReferenceVolume.instance.Cleanup(); @@ -427,7 +444,7 @@ protected override void Render(ScriptableRenderContext renderContext, Camera[] c #endif // For XR, HDR and no camera cases, UI Overlay ownership must be enforced AdjustUIOverlayOwnership(cameraCount); - + // Bandwidth optimization with Render Graph in some circumstances SetupScreenMSAASamplesState(cameraCount); @@ -1428,12 +1445,12 @@ static void InitializeStackedCameraData(Camera baseCamera, UniversalAdditionalCa } else if ((cameraData.renderScale < 1.0f) || (!isScenePreviewOrReflectionCamera && ((cameraData.upscalingFilter == ImageUpscalingFilter.FSR) || (cameraData.upscalingFilter == ImageUpscalingFilter.STP)))) { - // When certain upscalers are enabled, we still consider 100% render scale an upscaling operation. (This behavior is only intended for game view cameras) + // When certain upscalers are requested, we still consider 100% render scale an upscaling operation. (This behavior is only intended for game view cameras) // This allows us to run the upscaling shader passes all the time since they improve visual quality even at 100% scale. cameraData.imageScalingMode = ImageScalingMode.Upscaling; - // When STP is enabled, we force temporal anti-aliasing on since it's a prerequisite. + // When STP is requested, we force temporal anti-aliasing on since it's a prerequisite. if (cameraData.upscalingFilter == ImageUpscalingFilter.STP) { cameraData.antialiasing = AntialiasingMode.TemporalAntiAliasing; @@ -1514,7 +1531,6 @@ static void InitializeAdditionalCameraData(Camera camera, UniversalAdditionalCam } cameraData.renderer = renderer; - cameraData.requiresDepthTexture |= isSceneViewCamera; cameraData.postProcessingRequiresDepthTexture = CheckPostProcessForDepth(cameraData); cameraData.resolveFinalTarget = resolveFinalTarget; @@ -1874,7 +1890,7 @@ private static void UpdateTemporalAATargets(UniversalCameraData cameraData) xrMultipassEnabled = cameraData.xr.enabled && !cameraData.xr.singlePassEnabled; #endif bool allocation; - if (cameraData.IsSTPEnabled()) + if (cameraData.IsSTPRequested()) { Debug.Assert(cameraData.stpHistory != null); @@ -1897,9 +1913,9 @@ private static void UpdateTemporalAATargets(UniversalCameraData cameraData) { cameraData.taaHistory.Reset(); // TAA GPUResources is explicitly released if the feature is turned off. We could refactor this to rely on the type request and the "gc" only. - // In the case where STP is enabled, but TAA gets disabled for various reasons, we should release the STP history resources - if (cameraData.IsSTPEnabled()) - cameraData.stpHistory.Reset(); + // In the case where STP is requested, but TAA gets disabled for various reasons so STP is disabled, we should release the STP history resources + if (cameraData.IsSTPRequested()) + cameraData.stpHistory?.Reset(); } } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs index d3c0eb53d76..076e5eef2f2 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs @@ -152,6 +152,7 @@ protected internal override bool SupportsMotionVectors() RTHandle m_ColorFrontBuffer; internal RTHandle m_ActiveCameraDepthAttachment; internal RTHandle m_CameraDepthAttachment; + internal RTHandle m_CameraDepthAttachment_D3d_11; RTHandle m_TargetColorHandle; RTHandle m_TargetDepthHandle; internal RTHandle m_DepthTexture; @@ -461,6 +462,7 @@ internal override void ReleaseRenderTargets() m_AdditionalLightsShadowCasterPass?.Dispose(); m_CameraDepthAttachment?.Release(); + m_CameraDepthAttachment_D3d_11?.Release(); m_DepthTexture?.Release(); m_NormalsTexture?.Release(); m_DecalLayersTexture?.Release(); @@ -1008,6 +1010,9 @@ public override void Setup(ScriptableRenderContext context, ref RenderingData re // Assign camera targets (color and depth) ConfigureCameraTarget(m_ActiveCameraColorAttachment, m_ActiveCameraDepthAttachment); + if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Direct3D11) + cmd.CopyTexture(m_CameraDepthAttachment, m_CameraDepthAttachment_D3d_11); + bool hasPassesAfterPostProcessing = activeRenderPassQueue.Find(x => x.renderPassEvent == RenderPassEvent.AfterRenderingPostProcessing) != null; if (mainLightShadows) @@ -1840,7 +1845,14 @@ void CreateCameraRenderTarget(ScriptableRenderContext context, ref RenderTexture depthDescriptor.graphicsFormat = GraphicsFormat.None; depthDescriptor.depthStencilFormat = cameraDepthAttachmentFormat; RenderingUtils.ReAllocateHandleIfNeeded(ref m_CameraDepthAttachment, depthDescriptor, FilterMode.Point, TextureWrapMode.Clamp, name: "_CameraDepthAttachment"); - cmd.SetGlobalTexture(m_CameraDepthAttachment.name, m_CameraDepthAttachment.nameID); + + if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Direct3D11) + { + RenderingUtils.ReAllocateHandleIfNeeded(ref m_CameraDepthAttachment_D3d_11, depthDescriptor, FilterMode.Point, TextureWrapMode.Clamp, name: "_CameraDepthAttachment_Temp"); + cmd.SetGlobalTexture(m_CameraDepthAttachment.name, m_CameraDepthAttachment_D3d_11.nameID); + } + else + cmd.SetGlobalTexture(m_CameraDepthAttachment.name, m_CameraDepthAttachment.nameID); // update the descriptor to match the depth attachment descriptor.depthStencilFormat = depthDescriptor.depthStencilFormat; @@ -1909,7 +1921,7 @@ bool RequiresIntermediateColorTexture(UniversalCameraData cameraData, ref Render if (isOffscreenRender) return requiresBlitForOffscreenCamera; - return requiresBlitForOffscreenCamera || isSceneViewCamera || isScaledRender || cameraData.isHdrEnabled || + return requiresBlitForOffscreenCamera || isScaledRender || cameraData.isHdrEnabled || !isCompatibleBackbufferTextureDimension || isCapturing || cameraData.requireSrgbConversion || renderPassInputs.requiresColorTexture || renderPassInputs.requiresColorTextureCreated; } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs index 02816c35c89..7cee7e234e0 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs @@ -245,6 +245,7 @@ public static TextureHandle CreateRenderGraphTexture(RenderGraph renderGraph, Re rgDesc.wrapMode = wrapMode; rgDesc.isShadowMap = desc.shadowSamplingMode != ShadowSamplingMode.None && desc.depthStencilFormat != GraphicsFormat.None; rgDesc.vrUsage = desc.vrUsage; + rgDesc.enableShadingRate = desc.enableShadingRate; rgDesc.useDynamicScale = desc.useDynamicScale; rgDesc.useDynamicScaleExplicit = desc.useDynamicScaleExplicit; @@ -266,6 +267,7 @@ internal static TextureHandle CreateRenderGraphTexture(RenderGraph renderGraph, rgDesc.enableRandomWrite = desc.enableRandomWrite; rgDesc.filterMode = filterMode; rgDesc.wrapMode = wrapMode; + rgDesc.enableShadingRate = desc.enableShadingRate; rgDesc.useDynamicScale = desc.useDynamicScale; rgDesc.useDynamicScaleExplicit = desc.useDynamicScaleExplicit; @@ -282,25 +284,21 @@ bool CameraHasPostProcessingWithDepth(UniversalCameraData cameraData) return ShouldApplyPostProcessing(cameraData.postProcessEnabled) && cameraData.postProcessingRequiresDepthTexture; } - void RequiresColorAndDepthAttachments(RenderGraph renderGraph, out bool createColorTexture, out bool createDepthTexture, UniversalCameraData cameraData, ref RenderPassInputSummary renderPassInputs) + bool RequiresIntermediateAttachments(UniversalCameraData cameraData, ref RenderPassInputSummary renderPassInputs) { - bool isPreviewCamera = cameraData.isPreviewCamera; bool requiresDepthPrepass = RequireDepthPrepass(cameraData, ref renderPassInputs); var requireColorTexture = HasActiveRenderFeatures() && m_IntermediateTextureMode == IntermediateTextureMode.Always; requireColorTexture |= HasPassesRequiringIntermediateTexture(); requireColorTexture |= Application.isEditor && m_Clustering; requireColorTexture |= RequiresIntermediateColorTexture(cameraData, ref renderPassInputs); - requireColorTexture &= !isPreviewCamera; var requireDepthTexture = RequireDepthTexture(cameraData, requiresDepthPrepass, ref renderPassInputs); useDepthPriming = IsDepthPrimingEnabled(cameraData); // Intermediate texture has different yflip state than backbuffer. In case we use intermediate texture, we must use both color and depth together. - bool intermediateRenderTexture = (requireColorTexture || requireDepthTexture); - createDepthTexture = intermediateRenderTexture; - createColorTexture = intermediateRenderTexture; + return (requireColorTexture || requireDepthTexture); } // Gather history render requests and manage camera history texture life-time. @@ -437,8 +435,7 @@ void CreateRenderGraphCameraRenderTargets(RenderGraph renderGraph, bool isCamera // We configure this for the first camera of the stack and overlay camera will reuse create color/depth var // to pick the correct target, as if there is an intermediate texture, overlay cam should use them if (cameraData.renderType == CameraRenderType.Base) - RequiresColorAndDepthAttachments(renderGraph, out m_CreateColorAttachment, out m_CreateDepthAttachment, cameraData, ref renderPassInputs); - + m_RequiresIntermediateAttachments = RequiresIntermediateAttachments(cameraData, ref renderPassInputs); // The final output back buffer should be cleared by the graph on first use only if we have no final blit pass. // If there is a final blit, that blit will write the buffers so on first sight an extra clear should not be problem, @@ -446,7 +443,7 @@ void CreateRenderGraphCameraRenderTargets(RenderGraph renderGraph, bool isCamera // with a Viewport Rect smaller than the full screen. So the existing backbuffer contents need to be preserved in this case. // Finally for non-base cameras the backbuffer should never be cleared. (Note that there might still be two base cameras // rendering to the same screen. See e.g. test foundation 014 that renders a minimap) - bool clearBackbufferOnFirstUse = (cameraData.renderType == CameraRenderType.Base) && !m_CreateColorAttachment; + bool clearBackbufferOnFirstUse = (cameraData.renderType == CameraRenderType.Base) && !m_RequiresIntermediateAttachments; // force the clear if we are rendering to an offscreen depth texture clearBackbufferOnFirstUse |= isCameraTargetOffscreenDepth; @@ -457,9 +454,9 @@ void CreateRenderGraphCameraRenderTargets(RenderGraph renderGraph, bool isCamera // We cannot use directly !cameraData.rendersOverlayUI but this is similar logic bool isNativeUIOverlayRenderingAfterURP = !SupportedRenderingFeatures.active.rendersUIOverlay && cameraData.resolveToScreen; bool isNativeRenderingAfterURP = UnityEngine.Rendering.Watermark.IsVisible() || isNativeUIOverlayRenderingAfterURP; - // If MSAA > 1, no extra native rendering after SRP and we target the BB directly (!m_CreateColorAttachment) + // If MSAA > 1, no extra native rendering after SRP and we target the BB directly (!m_RequiresIntermediateAttachments) // then we can discard MSAA buffers and only resolve, otherwise we must store and resolve - bool noStoreOnlyResolveBBColor = !m_CreateColorAttachment && !isNativeRenderingAfterURP && (cameraData.cameraTargetDescriptor.msaaSamples > 1); + bool noStoreOnlyResolveBBColor = !m_RequiresIntermediateAttachments && !isNativeRenderingAfterURP && (cameraData.cameraTargetDescriptor.msaaSamples > 1); ImportResourceParams importBackbufferColorParams = new ImportResourceParams(); importBackbufferColorParams.clearOnFirstUse = clearBackbufferOnFirstUse; @@ -500,7 +497,7 @@ void CreateRenderGraphCameraRenderTargets(RenderGraph renderGraph, bool isCamera { // Backbuffer is the final render target, we obtain its number of MSAA samples through Screen API // in some cases we disable multisampling for optimization purpose - int numSamples = AdjustAndGetScreenMSAASamples(renderGraph, m_CreateColorAttachment); + int numSamples = AdjustAndGetScreenMSAASamples(renderGraph, m_RequiresIntermediateAttachments); //BuiltinRenderTextureType.CameraTarget so this is either system render target or camera.targetTexture if non null //NOTE: Careful what you use here as many of the properties bake-in the camera rect so for example @@ -560,7 +557,7 @@ void CreateRenderGraphCameraRenderTargets(RenderGraph renderGraph, bool isCamera #region Intermediate Camera Target - if (m_CreateColorAttachment && !isCameraTargetOffscreenDepth) + if (m_RequiresIntermediateAttachments && !isCameraTargetOffscreenDepth) { var cameraTargetDescriptor = cameraData.cameraTargetDescriptor; cameraTargetDescriptor.useMipMap = false; @@ -604,7 +601,7 @@ void CreateRenderGraphCameraRenderTargets(RenderGraph renderGraph, bool isCamera bool depthTextureIsDepthFormat = RequireDepthPrepass(cameraData, ref renderPassInputs) && (renderingModeActual != RenderingMode.Deferred); - if (m_CreateDepthAttachment) + if (m_RequiresIntermediateAttachments) { var depthDescriptor = cameraData.cameraTargetDescriptor; depthDescriptor.useMipMap = false; @@ -627,6 +624,12 @@ void CreateRenderGraphCameraRenderTargets(RenderGraph renderGraph, bool isCamera RenderingUtils.ReAllocateHandleIfNeeded(ref m_RenderGraphCameraDepthHandle, depthDescriptor, FilterMode.Point, TextureWrapMode.Clamp, name: "_CameraDepthAttachment"); importDepthParams.discardOnLastUse = lastCameraInTheStack; + #if UNITY_EDITOR + // scene filtering will reuse "camera" depth from the normal pass for the "filter highlight" effect + if (cameraData.isSceneViewCamera && CoreUtils.IsSceneFilteringEnabled()) + importDepthParams.discardOnLastUse = false; + #endif + resourceData.cameraDepth = renderGraph.ImportTexture(m_RenderGraphCameraDepthHandle, importDepthParams); resourceData.activeDepthID = UniversalResourceData.ActiveID.Camera; @@ -843,8 +846,7 @@ public override bool supportsGPUOcclusion } } - private static bool m_CreateColorAttachment; - private static bool m_CreateDepthAttachment; + private static bool m_RequiresIntermediateAttachments; private void OnOffscreenDepthTextureRendering(RenderGraph renderGraph, ScriptableRenderContext context, UniversalResourceData resourceData, UniversalCameraData cameraData) { @@ -1089,7 +1091,6 @@ private TextureCopySchedules CalculateTextureCopySchedules(UniversalCameraData c } bool requiresColorCopyPass = cameraData.requiresOpaqueTexture || renderPassInputs.requiresColorTexture; - requiresColorCopyPass &= !cameraData.isPreviewCamera; // Schedule a color copy pass if required ColorCopySchedule color = requiresColorCopyPass ? ColorCopySchedule.AfterSkybox @@ -1632,44 +1633,37 @@ private void OnAfterRendering(RenderGraph renderGraph) debugHandler.Render(renderGraph, cameraData, debugScreenTexture, overlayUITexture, debugHandlerColorTarget); } -#if UNITY_EDITOR - bool isGizmosEnabled = UnityEditor.Handles.ShouldRenderGizmos(); - - if (cameraData.isSceneViewCamera || cameraData.isPreviewCamera || (isGizmosEnabled && cameraData.resolveFinalTarget)) + if (cameraData.resolveFinalTarget) { - TextureHandle cameraDepthTexture = resourceData.cameraDepthTexture; - m_FinalDepthCopyPass.MssaSamples = 0; - m_FinalDepthCopyPass.CopyToBackbuffer = cameraData.isGameCamera; - m_FinalDepthCopyPass.Render(renderGraph, frameData, resourceData.activeDepthTexture, cameraDepthTexture, false, "Final Depth Copy"); - } +#if UNITY_EDITOR + // If we render to an intermediate depth attachment instead of the backbuffer, we need to copy the result to the backbuffer in cases where backbuffer + // depth data is required later in the frame. + bool backbufferDepthRequired = (cameraData.isSceneViewCamera || cameraData.isPreviewCamera || UnityEditor.Handles.ShouldRenderGizmos()); + if (m_RequiresIntermediateAttachments && backbufferDepthRequired) + { + m_FinalDepthCopyPass.MssaSamples = 0; + m_FinalDepthCopyPass.CopyToBackbuffer = cameraData.isGameCamera; + m_FinalDepthCopyPass.Render(renderGraph, frameData, resourceData.backBufferDepth, resourceData.cameraDepth, false, "Final Depth Copy"); + } #endif - if (cameraData.isSceneViewCamera) - DrawRenderGraphWireOverlay(renderGraph, frameData, resourceData.backBufferColor); + if (cameraData.isSceneViewCamera) + DrawRenderGraphWireOverlay(renderGraph, frameData, resourceData.backBufferColor); - if (drawGizmos) - DrawRenderGraphGizmos(renderGraph, frameData, resourceData.backBufferColor, resourceData.activeDepthTexture, GizmoSubset.PostImageEffects); + if (drawGizmos) + DrawRenderGraphGizmos(renderGraph, frameData, resourceData.backBufferColor, resourceData.activeDepthTexture, GizmoSubset.PostImageEffects); + } } bool RequireDepthPrepass(UniversalCameraData cameraData, ref RenderPassInputSummary renderPassInputs) { - bool applyPostProcessing = ShouldApplyPostProcessing(cameraData.postProcessEnabled); // If Camera's PostProcessing is enabled and if there any enabled PostProcessing requires depth texture as shader read resource (Motion Blur/DoF) bool cameraHasPostProcessingWithDepth = CameraHasPostProcessingWithDepth(cameraData); bool forcePrepass = (m_CopyDepthMode == CopyDepthMode.ForcePrepass); bool depthPrimingEnabled = IsDepthPrimingEnabled(cameraData); -#if UNITY_EDITOR - bool isGizmosEnabled = UnityEditor.Handles.ShouldRenderGizmos(); -#else - bool isGizmosEnabled = false; -#endif - bool requiresDepthTexture = cameraData.requiresDepthTexture || renderPassInputs.requiresDepthTexture || depthPrimingEnabled; bool requiresDepthPrepass = (requiresDepthTexture || cameraHasPostProcessingWithDepth) && (!CanCopyDepth(cameraData) || forcePrepass); - requiresDepthPrepass |= cameraData.isSceneViewCamera; - requiresDepthPrepass |= isGizmosEnabled; - requiresDepthPrepass |= cameraData.isPreviewCamera; requiresDepthPrepass |= renderPassInputs.requiresDepthPrepass; requiresDepthPrepass |= renderPassInputs.requiresNormalsTexture; // This must be checked explicitly because some features inject normal requirements later in the frame requiresDepthPrepass |= depthPrimingEnabled; @@ -1686,8 +1680,8 @@ bool RequireDepthTexture(UniversalCameraData cameraData, bool requiresDepthPrepa createDepthTexture |= !cameraData.resolveFinalTarget; // Deferred renderer always need to access depth buffer. createDepthTexture |= (renderingModeActual == RenderingMode.Deferred && !useRenderPassEnabled); - // Some render cases (e.g. Material previews) have shown we need to create a depth texture when we're forcing a prepass. - createDepthTexture |= depthPrimingEnabled || cameraData.isPreviewCamera; + // An intermediate depth target is required when depth priming is enabled because we can't copy out of backbuffer depth if it's needed later + createDepthTexture |= depthPrimingEnabled; // TODO: seems like with mrt depth is not taken from first target. Investigate if this is needed createDepthTexture |= m_RenderingLayerProvidesRenderObjectPass; diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/VFXGraph/Shaders/VFXCommon.hlsl b/Packages/com.unity.render-pipelines.universal/Runtime/VFXGraph/Shaders/VFXCommon.hlsl index 5518a7de713..16dc0eaa3b0 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/VFXGraph/Shaders/VFXCommon.hlsl +++ b/Packages/com.unity.render-pipelines.universal/Runtime/VFXGraph/Shaders/VFXCommon.hlsl @@ -189,7 +189,7 @@ float4 VFXTransformFinalColor(float4 color, float4 posCS) float4 VFXApplyFog(float4 color,float4 posCS,float3 posWS) { -#if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) +#if defined(FOG_LINEAR_KEYWORD_DECLARED) if (FOG_LINEAR || FOG_EXP || FOG_EXP2) { float4 fog = (float4)0; @@ -205,23 +205,7 @@ float4 VFXApplyFog(float4 color,float4 posCS,float3 posWS) color.rgb = lerp(fog.rgb * color.a, color.rgb, fog.a); #endif } -#else // #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) -#if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2) - float4 fog = (float4)0; - fog.rgb = unity_FogColor.rgb; - - float fogFactor = ComputeFogFactor(posCS.z * posCS.w); - fog.a = ComputeFogIntensity(fogFactor); - -#if VFX_BLENDMODE_ALPHA || IS_OPAQUE_PARTICLE - color.rgb = lerp(fog.rgb, color.rgb, fog.a); -#elif VFX_BLENDMODE_ADD - color.rgb *= fog.a; -#elif VFX_BLENDMODE_PREMULTIPLY - color.rgb = lerp(fog.rgb * color.a, color.rgb, fog.a); -#endif -#endif // #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2) -#endif // #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) +#endif // #if defined(FOG_LINEAR_KEYWORD_DECLARED) return color; } diff --git a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl index 51980f231c1..e584771b1eb 100644 --- a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl +++ b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl @@ -163,7 +163,7 @@ StructuredBuffer _AdditionalLightsBuffer; StructuredBuffer _AdditionalLightsIndices; #else // GLES3 causes a performance regression in some devices when using CBUFFER. -#ifndef SHADER_API_GLES3 +#ifndef LIGHT_SHADOWS_NO_CBUFFER CBUFFER_START(AdditionalLights) #endif float4 _AdditionalLightsPosition[MAX_VISIBLE_LIGHTS]; @@ -173,7 +173,7 @@ half4 _AdditionalLightsAttenuation[MAX_VISIBLE_LIGHTS]; half4 _AdditionalLightsSpotDir[MAX_VISIBLE_LIGHTS]; half4 _AdditionalLightsOcclusionProbes[MAX_VISIBLE_LIGHTS]; float _AdditionalLightsLayerMasks[MAX_VISIBLE_LIGHTS]; // we want uint[] but Unity api does not support it. -#ifndef SHADER_API_GLES3 +#ifndef LIGHT_SHADOWS_NO_CBUFFER CBUFFER_END #endif #endif @@ -193,14 +193,14 @@ float urp_ReflProbes_Count; // 2023.3 Deprecated. This is for backwards compatibility. Remove in the future. #define samplerurp_ReflProbes_Atlas sampler_LinearClamp -#ifndef SHADER_API_GLES3 +#ifndef LIGHT_SHADOWS_NO_CBUFFER CBUFFER_START(urp_ReflectionProbeBuffer) #endif float4 urp_ReflProbes_BoxMax[MAX_REFLECTION_PROBES]; // w contains the blend distance float4 urp_ReflProbes_BoxMin[MAX_REFLECTION_PROBES]; // w contains the importance float4 urp_ReflProbes_ProbePosition[MAX_REFLECTION_PROBES]; // w is positive for box projection, |w| is max mip level float4 urp_ReflProbes_MipScaleOffset[MAX_REFLECTION_PROBES * 7]; -#ifndef SHADER_API_GLES3 +#ifndef LIGHT_SHADOWS_NO_CBUFFER CBUFFER_END #endif diff --git a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/LightCookie/LightCookieInput.hlsl b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/LightCookie/LightCookieInput.hlsl index 3d29e8b73a4..7f79825ddc5 100644 --- a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/LightCookie/LightCookieInput.hlsl +++ b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/LightCookie/LightCookieInput.hlsl @@ -13,7 +13,7 @@ SAMPLER(sampler_MainLightCookieTexture); // Buffers // GLES3 causes a performance regression in some devices when using CBUFFER. -#ifndef SHADER_API_GLES3 +#ifndef LIGHT_SHADOWS_NO_CBUFFER CBUFFER_START(LightCookies) #endif float4x4 _MainLightWorldToLight; @@ -25,7 +25,7 @@ CBUFFER_START(LightCookies) float4 _AdditionalLightsCookieAtlasUVRects[MAX_VISIBLE_LIGHTS]; // (xy: uv size, zw: uv offset) float _AdditionalLightsLightTypes[MAX_VISIBLE_LIGHTS]; #endif -#ifndef SHADER_API_GLES3 +#ifndef LIGHT_SHADOWS_NO_CBUFFER CBUFFER_END #endif diff --git a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl index d997e1cfcf6..8c0f13c9d84 100644 --- a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl +++ b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl @@ -205,27 +205,18 @@ half4 CalculateFinalColor(LightingData lightingData, half alpha) half4 CalculateFinalColor(LightingData lightingData, half3 albedo, half alpha, float fogCoord) { + half fogFactor = 0; #if defined(_FOG_FRAGMENT) - - #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) - half fogFactor = 0; + #if defined(FOG_LINEAR_KEYWORD_DECLARED) if (FOG_LINEAR || FOG_EXP || FOG_EXP2) { float viewZ = -fogCoord; float nearToFarZ = max(viewZ - _ProjectionParams.y, 0); fogFactor = ComputeFogFactorZ0ToFar(nearToFarZ); } - #else // #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) - #if (defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)) - float viewZ = -fogCoord; - float nearToFarZ = max(viewZ - _ProjectionParams.y, 0); - half fogFactor = ComputeFogFactorZ0ToFar(nearToFarZ); - #else - half fogFactor = 0; - #endif - #endif // #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) + #endif // defined(FOG_LINEAR_KEYWORD_DECLARED) #else // #if defined(_FOG_FRAGMENT) - half fogFactor = fogCoord; + fogFactor = fogCoord; #endif // #if defined(_FOG_FRAGMENT) half3 lightingColor = CalculateLightingColor(lightingData, albedo); half3 finalColor = MixFog(lightingColor, fogFactor); diff --git a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl index c64c3bd9232..616d4fd7588 100644 --- a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl +++ b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl @@ -95,7 +95,8 @@ float3 shadergraph_LWReflectionProbe(float3 viewDir, float3 normalOS, float lod) void shadergraph_LWFog(float3 positionOS, out float4 color, out float density) { color = unity_FogColor; - #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) + density = 0.0f; + #if defined(FOG_LINEAR_KEYWORD_DECLARED) if (FOG_LINEAR || FOG_EXP || FOG_EXP2) { float viewZ = -TransformWorldToView(TransformObjectToWorld(positionOS)).z; @@ -103,20 +104,7 @@ void shadergraph_LWFog(float3 positionOS, out float4 color, out float density) // ComputeFogFactorZ0ToFar returns the fog "occlusion" (0 for full fog and 1 for no fog) so this has to be inverted for density. density = 1.0f - ComputeFogIntensity(ComputeFogFactorZ0ToFar(nearZ0ToFarZ)); } - else - { - density = 0.0f; - } - #else // #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) - #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2) - float viewZ = -TransformWorldToView(TransformObjectToWorld(positionOS)).z; - float nearZ0ToFarZ = max(viewZ - _ProjectionParams.y, 0); - // ComputeFogFactorZ0ToFar returns the fog "occlusion" (0 for full fog and 1 for no fog) so this has to be inverted for density. - density = 1.0f - ComputeFogIntensity(ComputeFogFactorZ0ToFar(nearZ0ToFarZ)); - #else - density = 0.0f; - #endif - #endif // #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) + #endif // defined(FOG_LINEAR_KEYWORD_DECLARED) } // This function assumes the bitangent flip is encoded in tangentWS.w diff --git a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderVariablesFunctions.hlsl b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderVariablesFunctions.hlsl index df5ffa03d36..ecd7c6b5bd3 100644 --- a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderVariablesFunctions.hlsl +++ b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderVariablesFunctions.hlsl @@ -314,7 +314,7 @@ float3 NormalizeNormalPerPixel(float3 normalWS) real ComputeFogFactorZ0ToFar(float z) { - #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) + #if defined(FOG_LINEAR_KEYWORD_DECLARED) if (FOG_LINEAR) { // factor = (end-z)/(end-start) = z * (-1/(end-start)) + (end/(end-start)) @@ -329,21 +329,13 @@ real ComputeFogFactorZ0ToFar(float z) } else { + // This process is necessary to avoid errors in iOS graphics tests + // when using the dynamic branching of fog keywords. return real(0.0); } - #else // #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) - #if defined(FOG_LINEAR) - // factor = (end-z)/(end-start) = z * (-1/(end-start)) + (end/(end-start)) - float fogFactor = saturate(z * unity_FogParams.z + unity_FogParams.w); - return real(fogFactor); - #elif defined(FOG_EXP) || defined(FOG_EXP2) - // factor = exp(-(density*z)^2) - // -density * z computed at vertex - return real(unity_FogParams.x * z); - #else - return real(0.0); - #endif - #endif //#if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) + #else // #if defined(FOG_LINEAR_KEYWORD_DECLARED) + return real(0.0); + #endif // #if defined(FOG_LINEAR_KEYWORD_DECLARED) } real ComputeFogFactor(float zPositionCS) @@ -355,7 +347,7 @@ real ComputeFogFactor(float zPositionCS) half ComputeFogIntensity(half fogFactor) { half fogIntensity = half(0.0); - #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) + #if defined(FOG_LINEAR_KEYWORD_DECLARED) if (FOG_EXP) { // factor = exp(-density*z) @@ -372,21 +364,7 @@ half ComputeFogIntensity(half fogFactor) { fogIntensity = fogFactor; } - #else // #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) - #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2) - #if defined(FOG_EXP) - // factor = exp(-density*z) - // fogFactor = density*z compute at vertex - fogIntensity = saturate(exp2(-fogFactor)); - #elif defined(FOG_EXP2) - // factor = exp(-(density*z)^2) - // fogFactor = density*z compute at vertex - fogIntensity = saturate(exp2(-fogFactor * fogFactor)); - #elif defined(FOG_LINEAR) - fogIntensity = fogFactor; - #endif - #endif - #endif // #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) + #endif // #if defined(FOG_LINEAR_KEYWORD_DECLARED return fogIntensity; } @@ -396,7 +374,7 @@ real InitializeInputDataFog(float4 positionWS, real vertFogFactor) { real fogFactor = 0.0; #if defined(_FOG_FRAGMENT) - #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) + #if defined(FOG_LINEAR_KEYWORD_DECLARED) if (FOG_LINEAR || FOG_EXP || FOG_EXP2) { // Compiler eliminates unused math --> matrix.column_z * vec @@ -405,15 +383,7 @@ real InitializeInputDataFog(float4 positionWS, real vertFogFactor) float nearToFarZ = max(viewZ - _ProjectionParams.y, 0); fogFactor = ComputeFogFactorZ0ToFar(nearToFarZ); } - #else // #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) - #if (defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)) - // Compiler eliminates unused math --> matrix.column_z * vec - float viewZ = -(mul(UNITY_MATRIX_V, positionWS).z); - // View Z is 0 at camera pos, remap 0 to near plane. - float nearToFarZ = max(viewZ - _ProjectionParams.y, 0); - fogFactor = ComputeFogFactorZ0ToFar(nearToFarZ); - #endif - #endif // #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) + #endif // #if defined(FOG_LINEAR_KEYWORD_DECLARED) #else // #if defined(_FOG_FRAGMENT) fogFactor = vertFogFactor; #endif // #if defined(_FOG_FRAGMENT) @@ -423,7 +393,7 @@ real InitializeInputDataFog(float4 positionWS, real vertFogFactor) float ComputeFogIntensity(float fogFactor) { float fogIntensity = 0.0; - #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) + #if defined(FOG_LINEAR_KEYWORD_DECLARED) if (FOG_EXP) { // factor = exp(-density*z) @@ -440,46 +410,26 @@ float ComputeFogIntensity(float fogFactor) { fogIntensity = fogFactor; } - #else // #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) - #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2) - #if defined(FOG_EXP) - // factor = exp(-density*z) - // fogFactor = density*z compute at vertex - fogIntensity = saturate(exp2(-fogFactor)); - #elif defined(FOG_EXP2) - // factor = exp(-(density*z)^2) - // fogFactor = density*z compute at vertex - fogIntensity = saturate(exp2(-fogFactor * fogFactor)); - #elif defined(FOG_LINEAR) - fogIntensity = fogFactor; - #endif - #endif - #endif // #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) + #endif // #if defined(FOG_LINEAR_KEYWORD_DECLARED) return fogIntensity; } half3 MixFogColor(half3 fragColor, half3 fogColor, half fogFactor) { - #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) + #if defined(FOG_LINEAR_KEYWORD_DECLARED) if (FOG_LINEAR || FOG_EXP || FOG_EXP2) { half fogIntensity = ComputeFogIntensity(fogFactor); // Workaround for UUM-61728: using a manual lerp to avoid rendering artifacts on some GPUs when Vulkan is used fragColor = fragColor * fogIntensity + fogColor * (half(1.0) - fogIntensity); } - #else // #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) - #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2) - half fogIntensity = ComputeFogIntensity(fogFactor); - // Workaround for UUM-61728: using a manual lerp to avoid rendering artifacts on some GPUs when Vulkan is used - fragColor = fragColor * fogIntensity + fogColor * (half(1.0) - fogIntensity); - #endif - #endif // #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) + #endif // #if defined(FOG_LINEAR_KEYWORD_DECLARED) return fragColor; } float3 MixFogColor(float3 fragColor, float3 fogColor, float fogFactor) { - #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) + #if defined(FOG_LINEAR_KEYWORD_DECLARED) if (FOG_LINEAR || FOG_EXP || FOG_EXP2) { if (IsFogEnabled()) @@ -488,15 +438,7 @@ float3 MixFogColor(float3 fragColor, float3 fogColor, float fogFactor) fragColor = lerp(fogColor, fragColor, fogIntensity); } } - #else // #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) - #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2) - if (IsFogEnabled()) - { - float fogIntensity = ComputeFogIntensity(fogFactor); - fragColor = lerp(fogColor, fragColor, fogIntensity); - } - #endif - #endif // #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) + #endif // #if defined(FOG_LINEAR_KEYWORD_DECLARED) return fragColor; } diff --git a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl index 38cf43e4091..552b022a989 100644 --- a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl +++ b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl @@ -60,7 +60,7 @@ TEXTURE2D_SHADOW(_AdditionalLightsShadowmapTexture); SAMPLER_CMP(sampler_LinearClampCompare); // GLES3 causes a performance regression in some devices when using CBUFFER. -#ifndef SHADER_API_GLES3 +#ifndef LIGHT_SHADOWS_NO_CBUFFER CBUFFER_START(LightShadows) #endif @@ -90,12 +90,12 @@ float4 _AdditionalShadowmapSize; // (xy: 1/width and 1/height, zw: width an // blocks bigger than 8kb while others have a 64kb max uniform block size. This number ensures size of buffer // AdditionalLightShadows stays reasonable. It also avoids shader compilation errors on SHADER_API_GLES30 // devices where max number of uniforms per shader GL_MAX_FRAGMENT_UNIFORM_VECTORS is low (224) -float4 _AdditionalShadowParams[MAX_VISIBLE_LIGHTS]; // Per-light data +float4 _AdditionalShadowParams[MAX_VISIBLE_LIGHTS]; // Per-light data: (x: shadowStrength, y: softShadows, z: light type (Spot: 0, Point: 1), w: perLightFirstShadowSliceIndex) float4x4 _AdditionalLightsWorldToShadow[MAX_VISIBLE_LIGHTS]; // Per-shadow-slice-data #endif #endif -#ifndef SHADER_API_GLES3 +#ifndef LIGHT_SHADOWS_NO_CBUFFER CBUFFER_END #endif @@ -196,7 +196,7 @@ half4 GetAdditionalLightShadowParams(int lightIndex) #if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA results = _AdditionalShadowParams_SSBO[lightIndex]; #else - results = _AdditionalShadowParams[lightIndex]; + results = _AdditionalShadowParams[lightIndex]; // workaround: Avoid failing the graphics test using Terrain Shader on Android Vulkan when using dynamic branching for fog keywords. #if !SKIP_SHADOWS_LIGHT_INDEX_CHECK results.w = lightIndex < 0 ? -1 : results.w; @@ -350,15 +350,18 @@ half ComputeCascadeIndex(float3 positionWS) float4 TransformWorldToShadowCoord(float3 positionWS) { -#ifdef _MAIN_LIGHT_SHADOWS_CASCADE - half cascadeIndex = ComputeCascadeIndex(positionWS); +#if defined(_MAIN_LIGHT_SHADOWS_SCREEN) && !defined(_SURFACE_TYPE_TRANSPARENT) + float4 shadowCoord = float4(ComputeNormalizedDeviceCoordinatesWithZ(positionWS, GetWorldToHClipMatrix()), 1.0); #else - half cascadeIndex = half(0.0); + #ifdef _MAIN_LIGHT_SHADOWS_CASCADE + half cascadeIndex = ComputeCascadeIndex(positionWS); + #else + half cascadeIndex = half(0.0); + #endif + + float4 shadowCoord = float4(mul(_MainLightWorldToShadow[cascadeIndex], float4(positionWS, 1.0)).xyz, 0.0); #endif - - float4 shadowCoord = mul(_MainLightWorldToShadow[cascadeIndex], float4(positionWS, 1.0)); - - return float4(shadowCoord.xyz, 0); + return shadowCoord; } half MainLightRealtimeShadow(float4 shadowCoord) diff --git a/Packages/com.unity.render-pipelines.universal/Shaders/UnlitForwardPass.hlsl b/Packages/com.unity.render-pipelines.universal/Shaders/UnlitForwardPass.hlsl index 8181b553913..b77b18b4167 100644 --- a/Packages/com.unity.render-pipelines.universal/Shaders/UnlitForwardPass.hlsl +++ b/Packages/com.unity.render-pipelines.universal/Shaders/UnlitForwardPass.hlsl @@ -132,27 +132,19 @@ void UnlitPassFragment( finalColor.rgb *= aoFactor.directAmbientOcclusion; #endif -#if defined(_FOG_FRAGMENT) -#if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) half fogFactor = 0; +#if defined(_FOG_FRAGMENT) +#if defined(FOG_LINEAR_KEYWORD_DECLARED) if (FOG_LINEAR || FOG_EXP || FOG_EXP2) { float viewZ = -input.fogCoord; float nearToFarZ = max(viewZ - _ProjectionParams.y, 0); fogFactor = ComputeFogFactorZ0ToFar(nearToFarZ); } -#else // #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) -#if (defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)) - float viewZ = -input.fogCoord; - float nearToFarZ = max(viewZ - _ProjectionParams.y, 0); - half fogFactor = ComputeFogFactorZ0ToFar(nearToFarZ); -#else - half fogFactor = 0; -#endif -#endif // #if USE_DYNAMIC_BRANCH_FOG_KEYWORD && defined(FOG_LINEAR_KEYWORD_DECLARED) -#else - half fogFactor = input.fogCoord; -#endif +#endif // #if defined(FOG_LINEAR_KEYWORD_DECLARED) +#else // #if defined(_FOG_FRAGMENT) + fogFactor = input.fogCoord; +#endif // #if defined(_FOG_FRAGMENT) finalColor.rgb = MixFog(finalColor.rgb, fogFactor); finalColor.a = OutputAlpha(finalColor.a, IsSurfaceTypeTransparent(_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 f7af2108c80..fc5c568f359 100644 --- a/Packages/com.unity.render-pipelines.universal/Tests/Editor/EditorTests.cs +++ b/Packages/com.unity.render-pipelines.universal/Tests/Editor/EditorTests.cs @@ -179,7 +179,7 @@ public void UseDynamicBranchFogKeyword(ShaderPathID shaderPathID) string path = AssetDatabase.GUIDToAssetPath(ShaderUtils.GetShaderGUID(shaderPathID)); var shader = AssetDatabase.LoadAssetAtPath(path); var keywordIdentifiers = new string[] { "FOG_EXP", "FOG_EXP2", "FOG_LINEAR" }; - var dynamicBranchFogKeyword = UniversalRenderPipeline.useDynamicBranchFogKeyword; + var dynamicBranchFogKeyword = UniversalRenderPipeline.UseDynamicBranchFogKeyword(); foreach (var identifier in keywordIdentifiers) { diff --git a/Packages/com.unity.shadergraph/Editor/Data/Nodes/Input/Scene/FogNode.cs b/Packages/com.unity.shadergraph/Editor/Data/Nodes/Input/Scene/FogNode.cs index ad0822b8a3a..6e742854959 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Nodes/Input/Scene/FogNode.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Nodes/Input/Scene/FogNode.cs @@ -4,7 +4,7 @@ namespace UnityEditor.ShaderGraph { [Title("Input", "Scene", "Fog")] - class FogNode : CodeFunctionNode + class FogNode : CodeFunctionNode, IMayRequireTransform { public FogNode() { @@ -31,5 +31,7 @@ static string Unity_Fog( } "; } + + public NeededTransform[] RequiresTransform(ShaderStageCapability stageCapability = ShaderStageCapability.All) => new[] { NeededTransform.ObjectToWorld }; } } diff --git a/Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/ShaderLibrary/Input.hlsl b/Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/ShaderLibrary/Input.hlsl index 403b06e6d1f..a80df578bd4 100644 --- a/Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/ShaderLibrary/Input.hlsl +++ b/Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/ShaderLibrary/Input.hlsl @@ -56,7 +56,7 @@ StructuredBuffer _AdditionalLightsBuffer; StructuredBuffer _AdditionalLightsIndices; #else // GLES3 causes a performance regression in some devices when using CBUFFER. -#ifndef SHADER_API_GLES3 +#ifndef LIGHT_SHADOWS_NO_CBUFFER CBUFFER_START(AdditionalLights) #endif float4 _AdditionalLightsPosition[MAX_VISIBLE_LIGHTS]; @@ -64,7 +64,7 @@ half4 _AdditionalLightsColor[MAX_VISIBLE_LIGHTS]; half4 _AdditionalLightsAttenuation[MAX_VISIBLE_LIGHTS]; half4 _AdditionalLightsSpotDir[MAX_VISIBLE_LIGHTS]; half4 _AdditionalLightsOcclusionProbes[MAX_VISIBLE_LIGHTS]; -#ifndef SHADER_API_GLES3 +#ifndef LIGHT_SHADOWS_NO_CBUFFER CBUFFER_END #endif #endif diff --git a/Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/ShaderLibrary/Shadows.hlsl b/Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/ShaderLibrary/Shadows.hlsl index 14a5d1678d6..fd146904f3c 100644 --- a/Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/ShaderLibrary/Shadows.hlsl +++ b/Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/ShaderLibrary/Shadows.hlsl @@ -49,7 +49,7 @@ TEXTURE2D_SHADOW(_AdditionalLightsShadowmapTexture); SAMPLER_CMP(sampler_AdditionalLightsShadowmapTexture); // GLES3 causes a performance regression in some devices when using CBUFFER. -#ifndef SHADER_API_GLES3 +#ifndef LIGHT_SHADOWS_NO_CBUFFER CBUFFER_START(MainLightShadows) #endif // Last cascade is initialized with a no-op matrix. It always transforms @@ -67,7 +67,7 @@ half4 _MainLightShadowOffset2; half4 _MainLightShadowOffset3; half4 _MainLightShadowParams; // (x: shadowStrength, y: 1.0 if soft shadows, 0.0 otherwise, z: main light fade scale, w: main light fade bias) float4 _MainLightShadowmapSize; // (xy: 1/width and 1/height, zw: width and height) -#ifndef SHADER_API_GLES3 +#ifndef LIGHT_SHADOWS_NO_CBUFFER CBUFFER_END #endif @@ -98,7 +98,7 @@ float4 _AdditionalShadowmapSize; // (xy: 1/width and 1/height, zw: width an #endif // GLES3 causes a performance regression in some devices when using CBUFFER. -#ifndef SHADER_API_GLES3 +#ifndef LIGHT_SHADOWS_NO_CBUFFER CBUFFER_START(AdditionalLightShadows) #endif @@ -112,7 +112,7 @@ half4 _AdditionalShadowOffset3; half4 _AdditionalShadowFadeParams; // x: additional light fade scale, y: additional light fade bias, z: 0.0, w: 0.0) float4 _AdditionalShadowmapSize; // (xy: 1/width and 1/height, zw: width and height) -#ifndef SHADER_API_GLES3 +#ifndef LIGHT_SHADOWS_NO_CBUFFER CBUFFER_END #endif diff --git a/Packages/com.unity.visualeffectgraph/Documentation~/ComponentAPI.md b/Packages/com.unity.visualeffectgraph/Documentation~/ComponentAPI.md index 5e4d361ae06..4531a6787e9 100644 --- a/Packages/com.unity.visualeffectgraph/Documentation~/ComponentAPI.md +++ b/Packages/com.unity.visualeffectgraph/Documentation~/ComponentAPI.md @@ -179,7 +179,7 @@ If you want to manage multiple Visual Effect instances in the same Scene and wan VisualEffect visualEffect; VFXEventAttribute eventAttribute; -static readonly ExposedProperty positionAttribute = "Position" +static readonly ExposedProperty positionAttribute = "position" static readonly ExposedProperty enteredTriggerEvent = "EnteredTrigger" void Start() diff --git a/Packages/com.unity.visualeffectgraph/Documentation~/Context-OutputShaderGraphMesh.md b/Packages/com.unity.visualeffectgraph/Documentation~/Context-OutputShaderGraphMesh.md index 8f9c2694b67..f5c37286b1c 100644 --- a/Packages/com.unity.visualeffectgraph/Documentation~/Context-OutputShaderGraphMesh.md +++ b/Packages/com.unity.visualeffectgraph/Documentation~/Context-OutputShaderGraphMesh.md @@ -2,7 +2,7 @@ Menu Path : **Context > Output Particle ShaderGraph Mesh** -[!include[](Snippets/Context-OutputShaderGraph-InlineIntro.md)] +You can use custom Shader Graphs in dedicated Shader Graph Outputs. Refer to [Working with Shader Graph](sg-working-with.md) for more information about the general Shader Graph workflow. This output is similar to [Output Particle Mesh](Context-OutputParticleMesh.md). diff --git a/Packages/com.unity.visualeffectgraph/Documentation~/Properties.md b/Packages/com.unity.visualeffectgraph/Documentation~/Properties.md index 98f2aea80af..1d28bcbb211 100644 --- a/Packages/com.unity.visualeffectgraph/Documentation~/Properties.md +++ b/Packages/com.unity.visualeffectgraph/Documentation~/Properties.md @@ -45,6 +45,8 @@ Compound Property Types are made from base data types. These types describe more Expand Compound Property Types to access their components. +To access components in a script, add an underscore before the component name. For example to access the `radius` component of `MySphere`, use `MySphere_radius`. + ![](Images/PropertyCompound.png) diff --git a/Packages/com.unity.visualeffectgraph/Documentation~/System-Requirements.md b/Packages/com.unity.visualeffectgraph/Documentation~/System-Requirements.md index 87d33fedf6e..32b809aae1d 100644 --- a/Packages/com.unity.visualeffectgraph/Documentation~/System-Requirements.md +++ b/Packages/com.unity.visualeffectgraph/Documentation~/System-Requirements.md @@ -8,6 +8,7 @@ The following table shows the compatibility of the Visual Effect Graph versions | **Package version** | **Minimum Unity version** | **Maximum Unity version** | | ------------------- | ------------------------- | ------------------------- | +| 17.x | Unity 6 | Unity 6.1 | | 16.x | 2023.2 | 2023.2 | | 15.x | 2023.1 | 2023.1 | | 14.x | 2022.2 | 2022.2 | @@ -25,7 +26,7 @@ The Visual Effect Graph varies in compatibility between the High Definition Rend | **Package version** | **HDRP** | **URP** | | ------------------- | ---------- | ------------- | -| 16.x | Supported | Supported | +| 17.x | Supported | Supported | | 16.x | Supported | Supported | | 14.x | Supported | Supported | | 13.x | Supported | Supported | diff --git a/Packages/com.unity.visualeffectgraph/Documentation~/VisualEffectComponent.md b/Packages/com.unity.visualeffectgraph/Documentation~/VisualEffectComponent.md index e16a63edb69..90f848e8ac4 100644 --- a/Packages/com.unity.visualeffectgraph/Documentation~/VisualEffectComponent.md +++ b/Packages/com.unity.visualeffectgraph/Documentation~/VisualEffectComponent.md @@ -1,6 +1,6 @@ # Visual Effect (Component) -The Visual Effect Component creates an instance of a Visual Effect in the scene, based on a Visual Effect Graph Asset. It controls how the effect plays, renders and let the user customize the instance by editing [Exposed Properties](Blackboard.md#creating-properties). +The Visual Effect Component creates an instance of a Visual Effect in the scene, based on a Visual Effect Graph Asset. It controls how the effect plays, renders and let the user customize the instance by editing [Exposed Properties](Blackboard.md). ## How to create a Visual Effect diff --git a/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXCodeGenerator.cs b/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXCodeGenerator.cs index 3301eac790f..033f777e060 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXCodeGenerator.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXCodeGenerator.cs @@ -21,74 +21,20 @@ static class VFXCodeGenerator { public const uint nbThreadsPerGroup = 64u; - private static string GetIndent(string src, int index) + internal static VFXShaderWriter GenerateLoadAttribute(string matching, VFXContext context, VFXTaskCompiledData taskData) { - var indent = ""; - index--; - while (index > 0 && (src[index] == ' ' || src[index] == '\t')) - { - indent = src[index] + indent; - index--; - } - return indent; - } + var r = new VFXShaderWriter(); - //This function insure to keep padding while replacing a specific string - public static void ReplaceMultiline(StringBuilder target, string targetQuery, StringBuilder value) - { - Profiler.BeginSample("ReplaceMultiline"); - - string[] delim = { System.Environment.NewLine, "\n" }; - var valueLines = value.ToString().Split(delim, System.StringSplitOptions.None); - // For some reasons, just calling Replace(...) without any index data is orders of magnitude - // slower than searching a copy of the string to get the index first. So both codepaths do - // exactly that. - if (valueLines.Length <= 1) + VFXAttributeInfo[] attributesFromContext; + if (matching != null) { - var replacement = value.ToString(); - int startIndex = 0; - while (true) - { - var targetCopy = target.ToString(); - var index = targetCopy.IndexOf(targetQuery, startIndex, StringComparison.Ordinal); - if (index == -1) - break; - target.Replace(targetQuery, replacement, index, targetQuery.Length); - startIndex = index; - } + var regex = new Regex(matching); + attributesFromContext = context.GetData().GetAttributes().Where(o => regex.IsMatch(o.attrib.name)).ToArray(); } else { - int startIndex = 0; - while (true) - { - var targetCopy = target.ToString(); - var index = targetCopy.IndexOf(targetQuery, startIndex, StringComparison.Ordinal); - if (index == -1) - break; - var indent = GetIndent(targetCopy, index); - var currentValue = new StringBuilder(); - foreach (var line in valueLines) - { - currentValue.Append(indent + line + '\n'); - } - var currentValueString = currentValue.ToString(); - var toReplace = indent + targetQuery; - index -= indent.Length; - target.Replace(toReplace, currentValueString, index, toReplace.Length); - startIndex = index; - } + attributesFromContext = context.GetData().GetAttributes().ToArray(); } - - Profiler.EndSample(); - } - - internal static VFXShaderWriter GenerateLoadAttribute(string matching, VFXContext context, VFXTaskCompiledData taskData) - { - var r = new VFXShaderWriter(); - - var regex = new Regex(matching); - var attributesFromContext = context.GetData().GetAttributes().Where(o => regex.IsMatch(o.attrib.name)).ToArray(); var attributesSource = attributesFromContext.Where(a => context.GetData().IsSourceAttributeUsed(a.attrib, context)).ToArray(); var attributesCurrent = attributesFromContext.Where(a => context.GetData().IsCurrentAttributeUsed(a.attrib, context) || (context.contextType == VFXContextType.Init && context.GetData().IsAttributeStored(a.attrib))).ToArray(); @@ -148,7 +94,42 @@ internal static VFXShaderWriter GenerateLoadAttribute(string matching, VFXContex private const string eventListOutName = "eventListOut"; - static private VFXShaderWriter GenerateStoreAttribute(string matching, VFXContext context, uint linkedOutCount) + internal class Cache + { + private Dictionary m_SnippetsMap = new Dictionary(); + private Dictionary m_TemplateIncludeCache = new Dictionary(); + + internal void ClearSnippets() + { + m_SnippetsMap.Clear(); + } + internal bool TryAddSnippet(string key, StringBuilder value) + { + return m_SnippetsMap.TryAdd(key, value); + } + + internal void SetSnippet(string key, StringBuilder value) + { + m_SnippetsMap[key] = value; + } + + internal bool TryGetSnippet(string key, out StringBuilder value) + { + return m_SnippetsMap.TryGetValue(key, out value); + } + + internal void AddTemplateCache(string key, string value) + { + m_TemplateIncludeCache.Add(key, value); + } + + internal bool TryGetTemplateCache(string key, out string value) + { + return m_TemplateIncludeCache.TryGetValue(key, out value); + } + } + + internal static VFXShaderWriter GenerateStoreAttribute(string matching, VFXContext context, uint linkedOutCount) { var r = new VFXShaderWriter(); var regex = new Regex(matching); @@ -180,7 +161,7 @@ static private VFXShaderWriter GenerateStoreAttribute(string matching, VFXContex } return r; } - static internal VFXShaderWriter GenerateSetInstancingIndices(VFXContext context) + static internal VFXShaderWriter GenerateSetInstancingIndices() { var r = new VFXShaderWriter(); @@ -193,11 +174,11 @@ static internal VFXShaderWriter GenerateSetInstancingIndices(VFXContext context) static internal VFXShaderWriter GenerateLoadParameter(string matching, VFXNamedExpression[] namedExpressions, Dictionary expressionToName) { - var r = new VFXShaderWriter(); - var regex = new Regex(matching); - - var filteredNamedExpressions = namedExpressions.Where(o => regex.IsMatch(o.name) && - !(expressionToName.ContainsKey(o.exp) && expressionToName[o.exp] == o.name)); // if parameter already in the global scope, there's nothing to do + VFXShaderWriter r = new VFXShaderWriter(); + var filteredNamedExpressions = namedExpressions.Where(o => o.name == matching && + !(expressionToName.ContainsKey(o.exp) && expressionToName[o.exp] == o.name)).ToArray(); // if parameter already in the global scope, there's nothing to do + if (filteredNamedExpressions.Length == 0) + return r; bool needScope = false; foreach (var namedExpression in filteredNamedExpressions) @@ -234,6 +215,7 @@ public static StringBuilder Build( VFXTaskCompiledData taskData, HashSet dependencies, bool forceShadeDebugSymbols, + Cache codeGeneratorCache, out List errors) { string templatePath = null; @@ -243,7 +225,7 @@ public static StringBuilder Build( dependencies.Add(AssetDatabase.AssetPathToGUID(templatePath)); } - return Build(context, task, templatePath, compilationMode, taskData, dependencies, forceShadeDebugSymbols, out errors); + return Build(context, task, templatePath, compilationMode, taskData, dependencies, forceShadeDebugSymbols, codeGeneratorCache, out errors); } private static void GetFunctionName(VFXBlock block, out string functionName, out string comment) @@ -271,123 +253,6 @@ private static void GetFunctionName(VFXBlock block, out string functionName, out } } - static private string FormatPath(string path) - { - return Path.GetFullPath(path) - .TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) -#if !UNITY_EDITOR_LINUX - .ToLowerInvariant() -#endif - ; - } - - static IEnumerable GetUniqueMatches(string regexStr, string src) - { - var regex = new Regex(regexStr); - var matches = regex.Matches(src); - return matches.Cast().GroupBy(m => m.Groups[0].Value).Select(g => g.First()); - } - - static private StringBuilder GetFlattenedTemplateContent(string path, List includes, IEnumerable defines, HashSet dependencies) - { - var formattedPath = FormatPath(path); - - if (includes.Contains(formattedPath)) - { - var includeHierarchy = new StringBuilder(string.Format("Cyclic VFXInclude dependency detected: {0}\n", formattedPath)); - foreach (var str in Enumerable.Reverse(includes)) - includeHierarchy.Append(str + '\n'); - throw new InvalidOperationException(includeHierarchy.ToString()); - } - - includes.Add(formattedPath); - var templateContent = new StringBuilder(System.IO.File.ReadAllText(formattedPath)); - - foreach (var match in GetUniqueMatches("\\${VFXInclude(RP|)\\(\\\"(.*?)\\\"\\)(,.*)?}", templateContent.ToString())) - { - var groups = match.Groups; - var renderPipelineInclude = groups[1].Value == "RP"; - var includePath = groups[2].Value; - - - if (groups.Count > 3 && !String.IsNullOrEmpty(groups[2].Value)) - { - var allDefines = groups[3].Value.Split(new char[] { ',', ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); - var neededDefines = allDefines.Where(d => d[0] != '!'); - var forbiddenDefines = allDefines.Except(neededDefines).Select(d => d.Substring(1)); - if (!neededDefines.All(d => defines.Contains(d)) || forbiddenDefines.Any(d => defines.Contains(d))) - { - ReplaceMultiline(templateContent, groups[0].Value, new StringBuilder()); - continue; - } - } - - string absolutePath; - if (renderPipelineInclude) - absolutePath = VFXLibrary.currentSRPBinder.templatePath + "/" + includePath; - else - absolutePath = VisualEffectGraphPackageInfo.assetPackagePath + "/" + includePath; - dependencies.Add(AssetDatabase.AssetPathToGUID(absolutePath)); - - var includeBuilder = GetFlattenedTemplateContent(absolutePath, includes, defines, dependencies); - ReplaceMultiline(templateContent, groups[0].Value, includeBuilder); - } - - includes.Remove(formattedPath); - return templateContent; - } - - static private void SubstituteMacros(StringBuilder builder) - { - var definesToCode = new Dictionary(); - var source = builder.ToString(); - Regex beginRegex = new Regex("\\${VFXBegin:(.*)}"); - - int currentPos = -1; - int builderOffset = 0; - while ((currentPos = source.IndexOf("${", StringComparison.Ordinal)) != -1) - { - int endPos = source.IndexOf('}', currentPos); - if (endPos == -1) - throw new FormatException("Ill-formed VFX tag (Missing closing brace"); - - var tag = source.Substring(currentPos, endPos - currentPos + 1); - // Replace any tag found - string macro; - if (definesToCode.TryGetValue(tag, out macro)) - { - builder.Remove(currentPos + builderOffset, tag.Length); - var indentedMacro = macro.Replace("\n", "\n" + GetIndent(source, currentPos)); - builder.Insert(currentPos + builderOffset, indentedMacro); - } - else - { - const string endStr = "${VFXEnd}"; - var match = beginRegex.Match(source, currentPos, tag.Length); - if (match.Success) - { - var macroStartPos = match.Index + match.Length; - var macroEndCodePos = source.IndexOf(endStr, macroStartPos); - if (macroEndCodePos == -1) - throw new FormatException("${VFXBegin} found without ${VFXEnd}"); - - var defineStr = "${" + match.Groups[1].Value + "}"; - definesToCode[defineStr] = source.Substring(macroStartPos, macroEndCodePos - macroStartPos); - - // Remove the define in builder - builder.Remove(match.Index + builderOffset, macroEndCodePos - match.Index + endStr.Length); - } - else if (tag == endStr) - throw new FormatException("${VFXEnd} found without ${VFXBegin}"); - else // Remove undefined tag - builder.Remove(currentPos + builderOffset, tag.Length); - } - - builderOffset += currentPos; - source = builder.ToString(builderOffset, builder.Length - builderOffset); - } - } - internal static Dictionary BuildExpressionToName(VFXContext context, VFXTaskCompiledData taskData) { var expressionToName = new Dictionary(taskData.uniformMapper.expressionToCode); @@ -469,11 +334,11 @@ internal static void BuildParameterBuffer(VFXTaskCompiledData taskData, IEnumera var parameterBuffer = new VFXShaderWriter(); needsGraphValueStruct = parameterBuffer.WriteGraphValuesStruct(taskData.uniformMapper); parameterBuffer.WriteLine(); - parameterBuffer.WriteBufferTypeDeclaration(taskData.bufferUsage.Values); + parameterBuffer.WriteBufferTypeDeclaration(taskData.bufferTypeUsage.Values); parameterBuffer.WriteLine(); - parameterBuffer.WriteBuffer(taskData.uniformMapper, taskData.bufferUsage); + parameterBuffer.WriteBuffer(taskData.uniformMapper, taskData.bufferTypeUsage); parameterBuffer.WriteLine(); - parameterBuffer.WriteTexture(taskData.uniformMapper, filteredOutTextures); + parameterBuffer.WriteTexture(taskData.uniformMapper, taskData.bufferTypeUsage, filteredOutTextures); parameterBufferContent = parameterBuffer.ToString(); } @@ -648,7 +513,7 @@ internal static void BuildLoadContextData(VFXDataParticle.GraphValuesLayout grap loadContextData = loadContextDataShaderWriter.ToString(); } - static private StringBuilder Build( + private static StringBuilder Build( VFXContext context, VFXTask task, string templatePath, @@ -656,6 +521,7 @@ static private StringBuilder Build( VFXTaskCompiledData taskData, HashSet dependencies, bool enableShaderDebugSymbols, + Cache codeGeneratorCache, out List errors) { errors = null; @@ -690,8 +556,10 @@ static private StringBuilder Build( } } - var allAdditionalDefines = context.additionalDefines.Concat(task.additionalDefines ?? Enumerable.Empty()); - var stringBuilder = GetFlattenedTemplateContent(templatePath, new List(), allAdditionalDefines, dependencies); + VFXShaderSnippets.ShaderGenerationData shaderGenerationData = new VFXShaderSnippets.ShaderGenerationData(); + codeGeneratorCache.ClearSnippets(); + + var allAdditionalDefines = context.additionalDefines.Concat(task.additionalDefines ?? Enumerable.Empty()).ToHashSet(); var allCurrentAttributes = contextData.GetAttributes().Where(a => (contextData.IsCurrentAttributeUsed(a.attrib, context)) || @@ -700,7 +568,7 @@ static private StringBuilder Build( var allSourceAttributes = contextData.GetAttributes().Where(a => (contextData.IsSourceAttributeUsed(a.attrib, context))); var globalDeclaration = new VFXShaderWriter(); - globalDeclaration.WriteBufferTypeDeclaration(taskData.bufferUsage.Values); + globalDeclaration.WriteBufferTypeDeclaration(taskData.bufferTypeUsage.Values); globalDeclaration.WriteLine(); var particleData = (contextData as VFXDataParticle); var systemUniformMapper = particleData.systemUniformMapper; @@ -708,9 +576,9 @@ static private StringBuilder Build( var needsGraphValueStruct = globalDeclaration.WriteGraphValuesStruct(taskData.uniformMapper); globalDeclaration.WriteLine(); - globalDeclaration.WriteBuffer(taskData.uniformMapper, taskData.bufferUsage); + globalDeclaration.WriteBuffer(taskData.uniformMapper, taskData.bufferTypeUsage); globalDeclaration.WriteLine(); - globalDeclaration.WriteTexture(taskData.uniformMapper); + globalDeclaration.WriteTexture(taskData.uniformMapper, taskData.bufferTypeUsage); globalDeclaration.WriteAttributeStruct(allCurrentAttributes.Select(a => a.attrib), "VFXAttributes"); globalDeclaration.WriteLine(); globalDeclaration.WriteAttributeStruct(allSourceAttributes.Select(a => a.attrib), "VFXSourceAttributes"); @@ -719,7 +587,12 @@ static private StringBuilder Build( globalDeclaration.WriteEventBuffers(eventListOutName, taskData.linkedEventOut.Length); var expressionToName = BuildExpressionToName(context, taskData); - BuildContextBlocks(context, taskData, expressionToName, out var blockFunction, out var blockCallFunction, out var blockIncludes, out var blockDefines); + shaderGenerationData.m_ExpressionToName = BuildExpressionToName(context, taskData); + BuildContextBlocks(context, taskData, expressionToName, + out var blockFunction, + out var blockCallFunction, + out var blockIncludes, + out var blockDefines); //< Final composition var globalIncludeContent = new VFXShaderWriter(); @@ -727,7 +600,6 @@ static private StringBuilder Build( if (enableShaderDebugSymbols) { globalIncludeContent.WriteLine("#pragma enable_d3d11_debug_symbols"); - globalIncludeContent.WriteLine(); } globalIncludeContent.WriteLine("#define NB_THREADS_PER_GROUP " + nbThreadsPerGroup); @@ -752,13 +624,7 @@ static private StringBuilder Build( // We consider that tasks are always generating a compute shader. bool generateComputes = task.shaderType == VFXTaskShaderType.ComputeShader; - var renderTemplatePipePath = VFXLibrary.currentSRPBinder.templatePath; var renderRuntimePipePath = VFXLibrary.currentSRPBinder.runtimePath; - if (!generateComputes && !string.IsNullOrEmpty(renderTemplatePipePath)) - { - string renderPipePasses = renderTemplatePipePath + "/VFXPasses.template"; - globalIncludeContent.Write(GetFlattenedTemplateContent(renderPipePasses, new List(), allAdditionalDefines, dependencies)); - } if (contextData is ISpaceable) { @@ -781,90 +647,66 @@ static private StringBuilder Build( { perPassIncludeContent.WriteLine("#include \"Packages/com.unity.visualeffectgraph/Shaders/VFXCommonOutput.hlsl\""); } + globalIncludeContent.Write(blockDefines.builder.ToString()); perPassIncludeContent.Write(blockIncludes.builder.ToString()); - ReplaceMultiline(stringBuilder, "${VFXGlobalInclude}", globalIncludeContent.builder); - ReplaceMultiline(stringBuilder, "${VFXGlobalDeclaration}", globalDeclaration.builder); - ReplaceMultiline(stringBuilder, "${VFXPerPassInclude}", perPassIncludeContent.builder); - ReplaceMultiline(stringBuilder, "${VFXGeneratedBlockFunction}", blockFunction.builder); - ReplaceMultiline(stringBuilder, "${VFXProcessBlocks}", blockCallFunction.builder); + codeGeneratorCache.TryAddSnippet("${VFXGlobalInclude}",globalIncludeContent.builder); + codeGeneratorCache.TryAddSnippet("${VFXGlobalDeclaration}", globalDeclaration.builder); + codeGeneratorCache.TryAddSnippet("${VFXPerPassInclude}", perPassIncludeContent.builder); + codeGeneratorCache.TryAddSnippet("${VFXGeneratedBlockFunction}", blockFunction.builder); + codeGeneratorCache.TryAddSnippet("${VFXProcessBlocks}", blockCallFunction.builder); VFXShaderWriter fillGraphValueStruct = new VFXShaderWriter(); fillGraphValueStruct.GenerateFillGraphValuesStruct(taskData.uniformMapper, particleData.graphValuesLayout); - ReplaceMultiline(stringBuilder, "${VFXLoadGraphValues}", fillGraphValueStruct.builder); + codeGeneratorCache.TryAddSnippet("${VFXLoadGraphValues}", fillGraphValueStruct.builder); VFXShaderWriter loadContextData = new VFXShaderWriter(); loadContextData.GenerateLoadContextData(particleData.graphValuesLayout); - ReplaceMultiline(stringBuilder, "${VFXLoadContextData}", loadContextData.builder); - - var mainParameters = taskData.gpuMapper.CollectExpression(-1).ToArray(); - foreach (var match in GetUniqueMatches("\\${VFXLoadParameter:{(.*?)}}", stringBuilder.ToString())) - { - var str = match.Groups[0].Value; - var pattern = match.Groups[1].Value; - var loadParameters = GenerateLoadParameter(pattern, mainParameters, expressionToName); - ReplaceMultiline(stringBuilder, str, loadParameters.builder); - } + codeGeneratorCache.TryAddSnippet("${VFXLoadContextData}", loadContextData.builder); + shaderGenerationData.m_MainParameters = taskData.gpuMapper.CollectExpression(-1).ToArray(); // Old SG integration - VFXOldShaderGraphHelpers.ReplaceShaderGraphTag(stringBuilder, context, mainParameters, expressionToName); + VFXOldShaderGraphHelpers.ReplaceShaderGraphTag(context, shaderGenerationData.m_MainParameters, expressionToName, codeGeneratorCache); //< Load Attribute - if (stringBuilder.ToString().Contains("${VFXLoadAttributes}")) - { - var loadAttributes = GenerateLoadAttribute(".*", context, taskData); - ReplaceMultiline(stringBuilder, "${VFXLoadAttributes}", loadAttributes.builder); - } - - foreach (var match in GetUniqueMatches("\\${VFXLoadAttributes:{(.*?)}}", stringBuilder.ToString())) - { - var str = match.Groups[0].Value; - var pattern = match.Groups[1].Value; - var loadAttributes = GenerateLoadAttribute(pattern, context, taskData); - ReplaceMultiline(stringBuilder, str, loadAttributes.builder); - } + var loadAttributes = GenerateLoadAttribute(null, context, taskData); + codeGeneratorCache.TryAddSnippet("${VFXLoadAttributes}", loadAttributes.builder); //< Store Attribute - if (stringBuilder.ToString().Contains("${VFXStoreAttributes}")) - { - var storeAttribute = GenerateStoreAttribute(".*", context, (uint)taskData.linkedEventOut.Length); - ReplaceMultiline(stringBuilder, "${VFXStoreAttributes}", storeAttribute.builder); - } - - foreach (var match in GetUniqueMatches("\\${VFXStoreAttributes:{(.*?)}}", stringBuilder.ToString())) - { - var str = match.Groups[0].Value; - var pattern = match.Groups[1].Value; - var storeAttributes = GenerateStoreAttribute(pattern, context, (uint)taskData.linkedEventOut.Length); - ReplaceMultiline(stringBuilder, str, storeAttributes.builder); - } + var storeAttribute = GenerateStoreAttribute(".*", context, (uint)taskData.linkedEventOut.Length); + codeGeneratorCache.TryAddSnippet("${VFXStoreAttributes}", storeAttribute.builder); //< Detect needed pragma require var useCubeArray = taskData.uniformMapper.textures.Any(o => o.valueType == VFXValueType.TextureCubeArray); var pragmaRequire = useCubeArray ? new StringBuilder("#pragma require cubearray") : new StringBuilder(); - ReplaceMultiline(stringBuilder, "${VFXPragmaRequire}", pragmaRequire); + codeGeneratorCache.TryAddSnippet("${VFXPragmaRequire}", pragmaRequire); + if (VFXLibrary.currentSRPBinder != null) { var allowedRenderers = new StringBuilder("#pragma only_renderers "); allowedRenderers.Append(String.Join(" ", VFXLibrary.currentSRPBinder.GetSupportedGraphicDevices().Select(d => DeviceTypeToShaderString(d)))); - ReplaceMultiline(stringBuilder, "${VFXPragmaOnlyRenderers}", allowedRenderers); + codeGeneratorCache.TryAddSnippet("${VFXPragmaOnlyRenderers}", allowedRenderers); } - foreach (var addionalReplacement in context.additionalReplacements) - { - ReplaceMultiline(stringBuilder, addionalReplacement.Key, addionalReplacement.Value.builder); - } + foreach (var additionalReplacement in context.additionalReplacements) + codeGeneratorCache.TryAddSnippet(additionalReplacement.Key, additionalReplacement.Value.builder); + + shaderGenerationData.m_Context = context; + shaderGenerationData.m_TaskData = taskData; + shaderGenerationData.m_Defines = allAdditionalDefines; + shaderGenerationData.m_Dependencies = dependencies; + shaderGenerationData.m_CodeGeneratorCache = codeGeneratorCache; + shaderGenerationData.m_HumanReadable = true; - // Replace defines - SubstituteMacros(stringBuilder); + StringBuilder shaderStringSb = VFXShaderSnippets.GenerateShaderCode(templatePath, shaderGenerationData); if (VFXViewPreference.advancedLogs) - Debug.LogFormat("GENERATED_OUTPUT_FILE_FOR : {0}\n{1}", context.ToString(), stringBuilder.ToString()); + Debug.LogFormat("GENERATED_OUTPUT_FILE_FOR : {0}\n{1}", context.ToString(), shaderStringSb.ToString()); context.EndCompilation(); Profiler.EndSample(); - return stringBuilder; + return shaderStringSb; } static string DeviceTypeToShaderString(GraphicsDeviceType deviceType) => deviceType switch @@ -1031,7 +873,8 @@ private static void BuildBlock(VFXTaskCompiledData taskData, VFXShaderWriter blo blockCallFunction.WriteCallFunction(methodName, parameters, taskData.gpuMapper, - expressionToNameLocal); + expressionToNameLocal, + taskData.bufferTypeUsage); if (indexEventCount != -1) { diff --git a/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXExpressionGraph.cs b/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXExpressionGraph.cs index a7b0ac657a1..99ee206dbbc 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXExpressionGraph.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXExpressionGraph.cs @@ -289,14 +289,14 @@ private VFXExpressionMapper BuildMapper(VFXContext context, Dictionary GlobalEventAttributes => m_GlobalEventAttributes; - public ReadOnlyDictionary GetBufferTypeUsage(VFXContext context) + public ReadOnlyDictionary GetBufferUsage(VFXContext context) { if (m_BufferTypeUsagePerContext.TryGetValue(context, out var bufferTypeUsage)) { - return new ReadOnlyDictionary(bufferTypeUsage); + return new ReadOnlyDictionary(bufferTypeUsage); } - return new ReadOnlyDictionary(new Dictionary()); + return new ReadOnlyDictionary(new Dictionary()); } public IHLSLCodeHolder[] GetCustomHLSLExpressions(VFXContext context) @@ -309,7 +309,7 @@ public IHLSLCodeHolder[] GetCustomHLSLExpressions(VFXContext context) } private Dictionary> m_CustomHLSLExpressionsPerContext = new(); - private Dictionary> m_BufferTypeUsagePerContext = new(); + private Dictionary> m_BufferTypeUsagePerContext = new(); private HashSet m_Expressions = new HashSet(); private Dictionary m_CPUExpressionsToReduced = new Dictionary(); private Dictionary m_GPUExpressionsToReduced = new Dictionary(); diff --git a/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXGraphCompiledData.cs b/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXGraphCompiledData.cs index 1206be92de6..8b52a47c0f9 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXGraphCompiledData.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXGraphCompiledData.cs @@ -66,7 +66,7 @@ struct VFXTaskCompiledData public VFXUniformMapper uniformMapper; public VFXSGInputs SGInputs; public List instancingSplitValues; - public ReadOnlyDictionary bufferUsage; + public ReadOnlyDictionary bufferTypeUsage; public VFXMapping[] parameters; public (VFXSlot slot, VFXData data)[] linkedEventOut; public IHLSLCodeHolder[] hlslCodeHolders; @@ -826,6 +826,7 @@ private void GenerateShaders(List outGeneratedCodeData, VFXEx Profiler.BeginSample("VFXEditor.GenerateShaders"); try { + var codeGeneratorCache = new VFXCodeGenerator.Cache(); var errorMessage = new StringBuilder(); foreach (var context in contexts) { @@ -842,11 +843,11 @@ private void GenerateShaders(List outGeneratedCodeData, VFXEx var contextData = compiledData.taskToCompiledData[task]; contextData.gpuMapper = gpuMapper; contextData.uniformMapper = uniformMapper; - contextData.bufferUsage = graph.GetBufferTypeUsage(context); + contextData.bufferTypeUsage = graph.GetBufferUsage(context); if (task.doesGenerateShader) { - var generatedContent = VFXCodeGenerator.Build(context, task, compilationMode, contextData, dependencies, enableShaderDebugSymbols, out var errors); + var generatedContent = VFXCodeGenerator.Build(context, task, compilationMode, contextData, dependencies, enableShaderDebugSymbols, codeGeneratorCache, out var errors); if (generatedContent != null && generatedContent.Length > 0) { contextData.indexInShaderSource = outGeneratedCodeData.Count; diff --git a/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXShaderSnippets.cs b/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXShaderSnippets.cs new file mode 100644 index 00000000000..acfb379cd8f --- /dev/null +++ b/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXShaderSnippets.cs @@ -0,0 +1,373 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace UnityEditor.VFX +{ + internal class VFXShaderSnippets + { + internal static StringBuilder GenerateShaderCode(string templatePath, ShaderGenerationData shaderGenerationData) + { + VFXSnippetNodeInclude rootNode = new VFXSnippetNodeInclude(templatePath, shaderGenerationData, ""); + StringBuilder shaderStringSb = new StringBuilder(); + rootNode.CollectChildren(); + rootNode.AppendContent(shaderStringSb); + return shaderStringSb; + } + + //This function insure to keep padding while replacing a specific string + private static string GetIndent(string src, int index) + { + int indentLength = 0; + index--; + while (index > 0 && (src[index] == ' ' || src[index] == '\t')) + { + index--; + indentLength++; + } + + if (indentLength > 0) + return src.Substring(index + 1, indentLength); + return string.Empty; + } + + private static string FormatPath(string path) + { + return Path.GetFullPath(path) + .TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) +#if !UNITY_EDITOR_LINUX + .ToLowerInvariant() +#endif + ; + } + + internal class ShaderGenerationData + { + internal Dictionary m_ExpressionToName; + internal VFXNamedExpression[] m_MainParameters; + internal VFXContext m_Context; + internal VFXTaskCompiledData m_TaskData; + internal HashSet m_Defines; + internal HashSet m_Dependencies; + internal VFXCodeGenerator.Cache m_CodeGeneratorCache; + internal bool m_HumanReadable; + } + + internal class VFXSnippetNode + { + private static readonly char[] kDefineSeparator = { ',', ' ', '\t' }; + private const string kVFXBeginStr = "${VFXBegin"; + private const string kVFXEndStr = "${VFXEnd"; + private const string kVFXIncludeStr = "${VFXInclude"; + private const string kVFXLoadParameterStr = "${VFXLoadParameter"; + private const string kVFXLoadAttributesStr = "${VFXLoadAttributes"; + private const string kVFXStoreAttributesStr = "${VFXStoreAttributes"; + protected const string kEndLineStr = "\n"; + + private List m_Children; + protected string m_CurrentIndent; + protected ShaderGenerationData m_ShaderGenerationData; + + public VFXSnippetNode(ShaderGenerationData shaderGenerationData, string indent) + { + this.m_ShaderGenerationData = shaderGenerationData; + this.m_CurrentIndent = indent; + } + + public virtual void AppendContent(StringBuilder sb) + { + if (m_Children != null) + { + foreach (var snippet in m_Children) + { + snippet.AppendContent(sb); + } + } + } + + //Returns endIndex + protected int CollectChildrenFromString(string templateContent, int startIndex) + { + int index; + while (true) + { + index = -1; + if (startIndex <= templateContent.Length) + index = templateContent.IndexOf("${", startIndex, StringComparison.Ordinal); + if (index == -1) + { + AddRawContent(templateContent, startIndex, templateContent.Length); + break; + } + + AddRawContent(templateContent, startIndex, index); + + ExtractSnippet(templateContent, index, out string snippetWithDecoration, out string snippetIndent); + + if (m_ShaderGenerationData.m_CodeGeneratorCache.TryGetSnippet(snippetWithDecoration, out StringBuilder snippetContent)) + { + VFXSnippetNodeLeaf snippetLeaf = new VFXSnippetNodeLeaf(snippetContent, m_ShaderGenerationData, m_CurrentIndent + snippetIndent); + AddChildNode(snippetLeaf); + startIndex = index + snippetWithDecoration.Length; + } + else if (snippetWithDecoration.StartsWith(kVFXLoadParameterStr, StringComparison.Ordinal)) + startIndex = HandleLoadParameter(templateContent, index, snippetIndent); + else if (snippetWithDecoration.StartsWith(kVFXLoadAttributesStr, StringComparison.Ordinal)) + startIndex = HandleLoadAttribute(templateContent, index, snippetIndent); + else if (snippetWithDecoration.StartsWith(kVFXStoreAttributesStr, StringComparison.Ordinal)) + startIndex = HandleStoreAttribute(templateContent, index, snippetIndent); + else if (snippetWithDecoration.StartsWith(kVFXBeginStr, StringComparison.Ordinal)) + startIndex = HandleBeginTag(templateContent, snippetWithDecoration, index); + else if (snippetWithDecoration.StartsWith(kVFXEndStr, StringComparison.Ordinal)) + return index + snippetWithDecoration.Length + 1; + else if (snippetWithDecoration.StartsWith(kVFXIncludeStr, StringComparison.Ordinal)) + startIndex = + HandleTemplateInclude(templateContent, index, snippetIndent, snippetWithDecoration); + else + startIndex = index + snippetWithDecoration.Length + 1; + } + + return index; + } + private void AddChildNode(VFXSnippetNode node) + { + if (m_Children == null) + m_Children = new List(); + m_Children.Add(node); + } + + private void ExtractSnippet(string templateContent, int startIndex, out string snippetWithDecoration, out string snippetIndent) + { + int endIndex = templateContent.IndexOf("}", startIndex, StringComparison.Ordinal); + snippetWithDecoration = templateContent.Substring(startIndex, endIndex - startIndex + 1); + snippetIndent = GetIndent(templateContent, startIndex); + } + + private void AddRawContent(string templateContent, int startIndex, int index) + { + string leafContent = templateContent.Substring(startIndex, index - startIndex); + if (!string.IsNullOrEmpty(leafContent)) + { + VFXSnippetNodeLeaf leaf = new VFXSnippetNodeLeaf(leafContent, m_ShaderGenerationData, m_CurrentIndent); + AddChildNode(leaf); + } + } + private void MatchTemplateIncludePattern(string templateContent, int index, out string includePath, out string includeDefinesRaw, out bool renderPipelineInclude) + { + int includeNameBeginIndex = templateContent.IndexOf("\"", index, StringComparison.Ordinal) + 1; + int includeNameEndIndex = templateContent.IndexOf("\"", includeNameBeginIndex + 1, StringComparison.Ordinal); + includePath = + templateContent.Substring(includeNameBeginIndex, includeNameEndIndex - includeNameBeginIndex); + + renderPipelineInclude = templateContent.IndexOf("RP", index, includeNameBeginIndex - index, StringComparison.Ordinal) != -1; + + int definesBeginIndex = includeNameEndIndex + 2; + int definesEndIndex = templateContent.IndexOf("}", definesBeginIndex, StringComparison.Ordinal); + includeDefinesRaw = templateContent.Substring(definesBeginIndex, definesEndIndex - definesBeginIndex); + } + + private int HandleTemplateInclude(string templateContent, int index, string snippetIndent, string snippetWithDecoration) + { + bool AcceptInclude(string includeDefinesFused) + { + var includeDefines = includeDefinesFused.Split(kDefineSeparator, StringSplitOptions.RemoveEmptyEntries); + foreach(var define in includeDefines) + { + if (define[0] != '!') + { + if (!m_ShaderGenerationData.m_Defines.Contains(define)) + return false; + } + else if (m_ShaderGenerationData.m_Defines.Contains(define.Substring(1))) + return false; + } + + return true; + } + + MatchTemplateIncludePattern(templateContent, index, out string includePath, + out string includeDefinesRaw, out bool renderPipelineInclude); + + if(string.IsNullOrEmpty(includeDefinesRaw) || AcceptInclude(includeDefinesRaw)) + { + string absolutePath = $"{(renderPipelineInclude ? VFXLibrary.currentSRPBinder.templatePath : VisualEffectGraphPackageInfo.assetPackagePath)}/{includePath}"; + VFXSnippetNodeInclude includeSnippetNode = new VFXSnippetNodeInclude(absolutePath, m_ShaderGenerationData, m_CurrentIndent + snippetIndent); + includeSnippetNode.CollectChildren(); + AddChildNode(includeSnippetNode); + } + + var startIndex = index + snippetWithDecoration.Length; + return startIndex; + } + + private int HandleBeginTag(string templateContent, string snippetWithDecoration, int index) + { + string macroName = snippetWithDecoration.Substring(kVFXBeginStr.Length + 1, + snippetWithDecoration.Length - kVFXBeginStr.Length - 2); + int startIndex = index + snippetWithDecoration.Length; + if (templateContent[startIndex] == '\n') + startIndex += 1; + VFXSnippetNodeMacroDefinition macroDefinitionNode = + new VFXSnippetNodeMacroDefinition(macroName, m_ShaderGenerationData, ""); + startIndex = macroDefinitionNode.CollectChildrenFromString(templateContent, startIndex); + macroDefinitionNode.ExpandMacroAndStore(); + AddChildNode(macroDefinitionNode); + return startIndex; + } + + private void MatchSnippetPattern(string templateContent, int index, out string key, out string pattern) + { + int endIndex = templateContent.IndexOf("}}", index, StringComparison.Ordinal) + 2; + int patternIndex = templateContent.IndexOf(":{", index, StringComparison.Ordinal) + 2; + key = templateContent.Substring(index, endIndex - index); + pattern = templateContent.Substring(patternIndex, endIndex - patternIndex - 2); + } + + private void AddLeafNodeFromShaderWriter(string snippetIndent, VFXShaderWriter shaderWriter, string str) + { + VFXSnippetNodeLeaf snippetNodeLeaf = new VFXSnippetNodeLeaf(shaderWriter.builder, + m_ShaderGenerationData, m_CurrentIndent + snippetIndent); + AddChildNode(snippetNodeLeaf); + m_ShaderGenerationData.m_CodeGeneratorCache.TryAddSnippet(str, shaderWriter.builder); + } + + private int HandleStoreAttribute(string templateContent, int index, string snippetIndent) + { + MatchSnippetPattern(templateContent, index, out string key, out string pattern); + var storeAttribute = VFXCodeGenerator.GenerateStoreAttribute(pattern, m_ShaderGenerationData.m_Context, + (uint)m_ShaderGenerationData.m_TaskData.linkedEventOut.Length); + AddLeafNodeFromShaderWriter(snippetIndent, storeAttribute, key); + int startIndex = index + key.Length + 1; + return startIndex; + } + + private int HandleLoadAttribute(string templateContent, int index, string snippetIndent) + { + MatchSnippetPattern(templateContent, index, out string key, out string pattern); + var loadAttribute = VFXCodeGenerator.GenerateLoadAttribute(pattern, m_ShaderGenerationData.m_Context, + m_ShaderGenerationData.m_TaskData); + AddLeafNodeFromShaderWriter(snippetIndent, loadAttribute, key); + int startIndex = index + key.Length + 1; + return startIndex; + } + + private int HandleLoadParameter(string templateContent, int index, string snippetIndent) + { + MatchSnippetPattern(templateContent, index, out string key, out string pattern); + var loadParameters = VFXCodeGenerator.GenerateLoadParameter(pattern, + m_ShaderGenerationData.m_MainParameters, m_ShaderGenerationData.m_ExpressionToName); + if (string.IsNullOrEmpty(loadParameters.ToString())) + loadParameters.builder.AppendLine(); + + AddLeafNodeFromShaderWriter(snippetIndent, loadParameters, key); + int startIndex = index + key.Length; + return startIndex; + } + } + + class VFXSnippetNodeLeaf : VFXSnippetNode + { + private StringBuilder m_LeafContentSb; + private string m_LeafContentStr; + + internal VFXSnippetNodeLeaf(StringBuilder leafContentSb, ShaderGenerationData shaderGenerationData, string indent) : base(shaderGenerationData, indent) + { + //Copy to not accumulate indent + this.m_LeafContentSb = new StringBuilder(); + this.m_LeafContentSb.Append(leafContentSb); + } + + internal VFXSnippetNodeLeaf(string leafContentStr, ShaderGenerationData shaderGenerationData, string indent) : base(shaderGenerationData, indent) + { + this.m_LeafContentStr = leafContentStr; + } + + public override void AppendContent(StringBuilder sb) + { + if (m_ShaderGenerationData.m_HumanReadable && m_CurrentIndent.Length > 0) + { + if (m_LeafContentSb != null) + { + m_LeafContentSb.Replace(kEndLineStr, kEndLineStr + m_CurrentIndent); + sb.Append(m_LeafContentSb); + } + else + { + var lines = m_LeafContentStr.Split(kEndLineStr, StringSplitOptions.None); + int i = 0; + foreach (var line in lines) + { + if (i > 0) + sb.Append(kEndLineStr + m_CurrentIndent); + sb.Append(line); + i++; + } + } + } + else + { + if (m_LeafContentSb != null) + sb.Append(m_LeafContentSb); + else + sb.Append(m_LeafContentStr); + } + } + } + + internal class VFXSnippetNodeInclude : VFXSnippetNode + { + private string m_IncludePath; + + internal VFXSnippetNodeInclude(string includePath, ShaderGenerationData shaderGenerationData, string indent) : base(shaderGenerationData, indent) + { + this.m_IncludePath = includePath; + } + + public void CollectChildren() + { + if (!m_ShaderGenerationData.m_CodeGeneratorCache.TryGetTemplateCache(m_IncludePath, out var templateContent)) + { + m_ShaderGenerationData.m_Dependencies.Add(AssetDatabase.AssetPathToGUID(m_IncludePath)); + var formattedPath = FormatPath(m_IncludePath); + templateContent = File.ReadAllText(formattedPath); + m_ShaderGenerationData.m_CodeGeneratorCache.AddTemplateCache(m_IncludePath, templateContent); + } + CollectChildrenFromString(templateContent, 0); + } + } + + class VFXSnippetNodeMacroDefinition : VFXSnippetNode + { + private string m_MacroName; + private StringBuilder m_ExpandedMacro; + private bool m_Expanded; + + internal VFXSnippetNodeMacroDefinition(string macroName, ShaderGenerationData shaderGenerationData, + string indent) : base(shaderGenerationData, indent) + { + this.m_MacroName = macroName; + } + + public void ExpandMacroAndStore() + { + StringBuilder sb = new StringBuilder(); + AppendContent(sb); + m_ExpandedMacro = sb; + string snippetizedMacroName = $"${{{m_MacroName}}}"; + if (!m_ShaderGenerationData.m_CodeGeneratorCache.TryAddSnippet(snippetizedMacroName, m_ExpandedMacro)) + { + m_ShaderGenerationData.m_CodeGeneratorCache.SetSnippet(snippetizedMacroName,m_ExpandedMacro); + } + + m_Expanded = true; + } + + public override void AppendContent(StringBuilder sb) + { + if (!m_Expanded) + base.AppendContent(sb); + } + } + } +} diff --git a/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXShaderSnippets.cs.meta b/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXShaderSnippets.cs.meta new file mode 100644 index 00000000000..516c437a617 --- /dev/null +++ b/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXShaderSnippets.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7245be2bea814067bbd30db1d94c2cb4 +timeCreated: 1720614463 \ No newline at end of file diff --git a/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXShaderWriter.cs b/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXShaderWriter.cs index 11118af23a5..90dd7922db3 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXShaderWriter.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXShaderWriter.cs @@ -303,9 +303,9 @@ private void WriteBufferTypeDeclaration(Type type, HashSet alreadyGenerate } } - public void WriteBufferTypeDeclaration(IEnumerable usages) + public void WriteBufferTypeDeclaration(IEnumerable bufferTypeUsage) { - var types = usages.Select(usage => + var types = bufferTypeUsage.Select(usage => { var type = usage.actualType; if (IsBufferBuiltinType(type)) @@ -327,7 +327,7 @@ public void WriteBufferTypeDeclaration(IEnumerable usages) } } - public void WriteBuffer(VFXUniformMapper mapper, ReadOnlyDictionary usageBuffer) + public void WriteBuffer(VFXUniformMapper mapper, ReadOnlyDictionary usageBuffer) { foreach (var buffer in mapper.buffers) { @@ -346,7 +346,7 @@ public void WriteBuffer(VFXUniformMapper mapper, ReadOnlyDictionary skipNames = null) + public void WriteTexture(VFXUniformMapper mapper, ReadOnlyDictionary bufferTypeUsage, IEnumerable skipNames = null) { foreach (var texture in mapper.textures) { @@ -358,7 +358,15 @@ public void WriteTexture(VFXUniformMapper mapper, IEnumerable skipNames if (skipNames != null && skipNames.Contains(name)) continue; - WriteLineFormat("{0} {1};", VFXExpression.TypeToCode(texture.valueType), name); + if (bufferTypeUsage.TryGetValue(texture, out var usage)) + { + WriteLineFormat("{0} {1};", GetBufferDeclaration(usage), name); + } + else + { + WriteLineFormat("{0} {1};", VFXExpression.TypeToCode(texture.valueType), name); + } + if (VFXExpression.IsTexture(texture.valueType)) //Mesh doesn't require a sampler or texel helper { WriteLineFormat("SamplerState sampler{0};", name); @@ -494,20 +502,23 @@ private string AggregateParameters(List parameters) return parameters.Count == 0 ? "" : parameters.Aggregate((a, b) => a + ", " + b); } - private static string GetBufferDeclaration(BufferUsage bufferUsage) + private static string GetBufferDeclaration(BufferType bufferType) { - if (string.IsNullOrEmpty(bufferUsage.verbatimType)) - return bufferUsage.container.ToString(); + if (string.IsNullOrEmpty(bufferType.verbatimType)) + return bufferType.container.ToString(); - var verbatimType = IsBufferBuiltinType(bufferUsage.actualType) - ? VFXExpression.TypeToCode(VFXExpression.GetVFXValueTypeFromType(bufferUsage.actualType)) - : bufferUsage.verbatimType; + var verbatimType = IsBufferBuiltinType(bufferType.actualType) + ? VFXExpression.TypeToCode(VFXExpression.GetVFXValueTypeFromType(bufferType.actualType)) + : bufferType.verbatimType; - return $"{bufferUsage.container}<{verbatimType}>"; + return $"{bufferType.container}<{verbatimType}>"; } - private static string GetFunctionParameterType(VFXExpression exp, ReadOnlyDictionary usages) + private static string GetFunctionParameterType(VFXExpression exp, ReadOnlyDictionary usages) { + if (usages.TryGetValue(exp, out var usage)) + return GetBufferDeclaration(usage); + switch (exp.valueType) { case VFXValueType.Texture2D: return "VFXSampler2D"; @@ -517,15 +528,13 @@ private static string GetFunctionParameterType(VFXExpression exp, ReadOnlyDictio case VFXValueType.TextureCubeArray: return "VFXSamplerCubeArray"; case VFXValueType.CameraBuffer: return "VFXSamplerCameraBuffer"; case VFXValueType.Buffer: - if (!usages.TryGetValue(exp, out var usage)) - throw new KeyNotFoundException("Cannot find appropriate usage for " + exp); - return GetBufferDeclaration(usage); + throw new KeyNotFoundException("Cannot find appropriate usage for " + exp); default: return VFXExpression.TypeToCode(exp.valueType); } } - private static string GetFunctionParameterName(VFXExpression expression, Dictionary names) + private static string GetFunctionParameterName(VFXExpression expression, Dictionary names, ReadOnlyDictionary textureBufferUsages) { var expressionName = names[expression]; switch (expression.valueType) @@ -534,7 +543,10 @@ private static string GetFunctionParameterName(VFXExpression expression, Diction case VFXValueType.Texture2DArray: case VFXValueType.Texture3D: case VFXValueType.TextureCube: - case VFXValueType.TextureCubeArray: return string.Format("GetVFXSampler({0}, {1})", expressionName, ("sampler" + expressionName)); + case VFXValueType.TextureCubeArray: + if (textureBufferUsages.TryGetValue(expression, out var textureUsage)) + return expressionName; + return string.Format("GetVFXSampler({0}, {1})", expressionName, ("sampler" + expressionName)); case VFXValueType.CameraBuffer: return string.Format("GetVFXSampler({0}, {1})", expressionName, ("sampler" + expressionName)); default: @@ -563,7 +575,7 @@ public void WriteBlockFunction(VFXTaskCompiledData taskData, string functionName foreach (var parameter in parameters) { var inputModifier = GetInputModifier(parameter.mode); - var parameterType = GetFunctionParameterType(parameter.expression, taskData.bufferUsage); + var parameterType = GetFunctionParameterType(parameter.expression, taskData.bufferTypeUsage); parametersCode.Add(string.Format("{0}{1} {2}", inputModifier, parameterType, parameter.name)); } @@ -579,13 +591,13 @@ public void WriteBlockFunction(VFXTaskCompiledData taskData, string functionName ExitScope(); } - public void WriteCallFunction(string functionName, IEnumerable parameters, VFXExpressionMapper mapper, Dictionary variableNames) + public void WriteCallFunction(string functionName, IEnumerable parameters, VFXExpressionMapper mapper, Dictionary variableNames, ReadOnlyDictionary textureBufferUsages) { var parametersCode = new List(); foreach (var parameter in parameters) { var inputModifier = GetInputModifier(parameter.mode); - parametersCode.Add(string.Format("{1}{0}", GetFunctionParameterName(parameter.expression, variableNames), string.IsNullOrEmpty(inputModifier) ? string.Empty : string.Format(" /*{0}*/", inputModifier))); + parametersCode.Add(string.Format("{1}{0}", GetFunctionParameterName(parameter.expression, variableNames, textureBufferUsages), string.IsNullOrEmpty(inputModifier) ? string.Empty : string.Format(" /*{0}*/", inputModifier))); } WriteLineFormat("{0}({1});", functionName, AggregateParameters(parametersCode)); diff --git a/Packages/com.unity.visualeffectgraph/Editor/Data/VFXDataParticle.cs b/Packages/com.unity.visualeffectgraph/Editor/Data/VFXDataParticle.cs index 917f9d5da45..63ced2a7906 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/Data/VFXDataParticle.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/Data/VFXDataParticle.cs @@ -11,7 +11,7 @@ namespace UnityEditor.VFX { interface ILayoutProvider { - void GenerateAttributeLayout(uint capacity, Dictionary storedAttribute); + void GenerateAttributeLayout(uint capacity, Dictionary storedAttribute, bool splitBuckets); string GetCodeOffset(VFXAttribute attrib, uint capacity, string index, string instanceIndex); uint GetBufferSize(uint capacity); @@ -32,8 +32,14 @@ public AttributeLayout(int bucket, int offset) } } - // return size - private int GenerateBucketLayout(List attributes, int bucketId) + private void AddBucket(int capacity, int bucketId, int currentOffset) + { + int bucketOffset = bucketId == 0 ? 0 : m_BucketOffsets[bucketId - 1] + capacity * m_BucketSizes[bucketId - 1]; + m_BucketOffsets.Add((bucketOffset + 3) & ~3); // align on dword; + m_BucketSizes.Add(currentOffset); + } + + private void AddAttributeBuckets(List attributes, int capacity, ref int bucketId, bool splitBuckets) { var sortedAttrib = attributes.OrderByDescending(a => VFXValue.TypeToSize(a.type)); @@ -48,52 +54,55 @@ private int GenerateBucketLayout(List attributes, int bucketId) } int currentOffset = 0; - int minAlignment = 0; foreach (var block in attribBlocks) { + if (splitBuckets) + currentOffset = 0; + foreach (var attrib in block) { int size = VFXValue.TypeToSize(attrib.type); - int alignment = size > 2 ? 4 : size; - minAlignment = Math.Max(alignment, minAlignment); - // align offset - currentOffset = (currentOffset + alignment - 1) & ~(alignment - 1); m_AttributeLayout.Add(attrib, new AttributeLayout(bucketId, currentOffset)); currentOffset += size; } + if (splitBuckets) + { + AddBucket(capacity, bucketId, currentOffset); + bucketId++; + } + } + if (!splitBuckets) + { + AddBucket(capacity, bucketId, currentOffset); + bucketId++; } - - return (currentOffset + minAlignment - 1) & ~(minAlignment - 1); } - public void GenerateAttributeLayout(uint capacity, Dictionary storedAttribute) + public void GenerateAttributeLayout(uint capacity, Dictionary storedAttribute, bool splitBuckets = true) { m_BucketSizes.Clear(); m_AttributeLayout.Clear(); m_BucketOffsets.Clear(); - var attributeBuckets = new Dictionary>(); + var attributeGroups = new Dictionary>(); foreach (var kvp in storedAttribute) { List attributes; - if (!attributeBuckets.ContainsKey(kvp.Value)) + if (!attributeGroups.ContainsKey(kvp.Value)) { attributes = new List(); - attributeBuckets[kvp.Value] = attributes; + attributeGroups[kvp.Value] = attributes; } else - attributes = attributeBuckets[kvp.Value]; + attributes = attributeGroups[kvp.Value]; attributes.Add(kvp.Key); } int bucketId = 0; - foreach (var bucket in attributeBuckets) + foreach (var group in attributeGroups) { - int bucketOffset = bucketId == 0 ? 0 : m_BucketOffsets[bucketId - 1] + (int)capacity * m_BucketSizes[bucketId - 1]; - m_BucketOffsets.Add((bucketOffset + 3) & ~3); // align on dword; - m_BucketSizes.Add(GenerateBucketLayout(bucket.Value, bucketId)); - ++bucketId; + AddAttributeBuckets(group.Value, (int)capacity, ref bucketId, splitBuckets); } // Debug log @@ -485,7 +494,7 @@ public override void GenerateAttributeLayout(Dictionary o, _ => (int)VFXAttributeMode.ReadSource); - m_layoutAttributeSource.GenerateAttributeLayout(m_SourceCount, readSourceAttribute); + m_layoutAttributeSource.GenerateAttributeLayout(m_SourceCount, readSourceAttribute, false); m_ownAttributeSourceBuffer = true; } } diff --git a/Packages/com.unity.visualeffectgraph/Editor/Expressions/VFXExpressionContext.cs b/Packages/com.unity.visualeffectgraph/Editor/Expressions/VFXExpressionContext.cs index 0a9f2d59a31..6b6e6eb16aa 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/Expressions/VFXExpressionContext.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/Expressions/VFXExpressionContext.cs @@ -181,7 +181,7 @@ private void CollectPerContextData() m_GraphicsBufferTypeUsagePerContext.Add(context, usages); } - var usage = expressionBufferWithTypeCollection.Key.usage; + var usage = expressionBufferWithTypeCollection.Key.Type; var buffer = expressionBufferWithTypeCollection.Key.parents[0]; if (!usages.TryAdd(buffer, usage) && usages[buffer] != usage) { @@ -321,7 +321,7 @@ private VFXExpression PatchVFXExpression(VFXExpression input, VFXExpression targ } } - if (input.valueType == VFXValueType.Buffer && input is VFXExpressionBufferWithType bufferWithType) + if (input is VFXExpressionBufferWithType bufferWithType) { input = input.parents[0]; //Explicitly skip NoOp expression } @@ -426,14 +426,13 @@ public HashSet BuildAllReduced() } public IEnumerable RegisteredExpressions => m_EndExpressions.Keys; - - public Dictionary> GraphicsBufferTypeUsagePerContext => m_GraphicsBufferTypeUsagePerContext; + public Dictionary> GraphicsBufferTypeUsagePerContext => m_GraphicsBufferTypeUsagePerContext; public Dictionary> hlslCodeHoldersPerContext => m_HLSLCollectionPerContext; - private Dictionary m_ReducedCache = new (); + private Dictionary m_ReducedCache = new(); private Dictionary> m_EndExpressions = new (); - private Dictionary> m_GraphicsBufferTypeUsagePerContext = new (); + private Dictionary> m_GraphicsBufferTypeUsagePerContext = new (); private IEnumerable m_GlobalEventAttribute; private VFXExpressionContextOption m_ReductionOptions; diff --git a/Packages/com.unity.visualeffectgraph/Editor/Expressions/VFXExpressionHLSL.cs b/Packages/com.unity.visualeffectgraph/Editor/Expressions/VFXExpressionHLSL.cs index 1ad158e746b..9014df2a813 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/Expressions/VFXExpressionHLSL.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/Expressions/VFXExpressionHLSL.cs @@ -11,29 +11,42 @@ class VFXExpressionHLSL : VFXExpression, IHLSLCodeHolder string m_FunctionName; VFXValueType m_ValueType; string m_HlslCode; - List m_TextureParentExpressionIndex; + int[] m_TextureSamplerParentExpressionIndex; string[] m_Includes; public VFXExpressionHLSL() : this(string.Empty, string.Empty, VFXValueType.None, new [] { VFXValue.Default }, Array.Empty()) { } - public VFXExpressionHLSL(string functionName, string hlslCode, VFXValueType returnType, VFXExpression[] parents, string[] includes) : base(Flags.InvalidOnCPU, parents) + public VFXExpressionHLSL(string functionName, string hlslCode, System.Type returnType, VFXExpression[] parents, string[] includes) : this(functionName, hlslCode, GetVFXValueTypeFromType(returnType), parents, includes) { - this.m_TextureParentExpressionIndex = new List(); - this.m_FunctionName = functionName; - this.m_ValueType = returnType; - this.m_HlslCode = hlslCode; - this.m_Includes = includes; } - public VFXExpressionHLSL(string functionName, string hlslCode, System.Type returnType, VFXExpression[] parents, string[] includes) : base(Flags.InvalidOnCPU, parents) + public VFXExpressionHLSL(string functionName, string hlslCode, VFXValueType returnType, VFXExpression[] parents, string[] includes) : base(Flags.InvalidOnCPU, parents) { - this.m_TextureParentExpressionIndex = new List(); this.m_FunctionName = functionName; - this.m_ValueType = GetVFXValueTypeFromType(returnType); + this.m_ValueType = returnType; this.m_HlslCode = hlslCode; this.m_Includes = includes; + + List samplerExpression = null; + for (int i = 0; i < parents.Length; i++) + { + if (parents[i] is not VFXExpressionBufferWithType && IsTexture(parents[i].valueType)) + { + samplerExpression ??= new List(); + samplerExpression.Add(i); + } + } + + if (samplerExpression != null) + { + this.m_TextureSamplerParentExpressionIndex = samplerExpression.ToArray(); + } + else + { + this.m_TextureSamplerParentExpressionIndex = Array.Empty(); + } } public override VFXValueType valueType => m_ValueType; @@ -84,27 +97,18 @@ protected override int GetInnerHashCode() protected override VFXExpression Reduce(VFXExpression[] reducedParents) { - m_TextureParentExpressionIndex.Clear(); - for (int i = 0; i < reducedParents.Length; i++) - { - if (IsTexture(reducedParents[i].valueType)) - { - m_TextureParentExpressionIndex.Add(i); - } - } - var newExpression = (VFXExpressionHLSL)base.Reduce(reducedParents); newExpression.m_FunctionName = m_FunctionName; newExpression.m_ValueType = m_ValueType; newExpression.m_HlslCode = m_HlslCode; - newExpression.m_TextureParentExpressionIndex = new List(m_TextureParentExpressionIndex); + newExpression.m_TextureSamplerParentExpressionIndex = (int[])m_TextureSamplerParentExpressionIndex.Clone(); newExpression.m_Includes = (string[])m_Includes.Clone(); return newExpression; } public sealed override string GetCodeString(string[] parentsExpressions) { - foreach (var index in m_TextureParentExpressionIndex) + foreach (var index in m_TextureSamplerParentExpressionIndex) { var expression = parentsExpressions[index]; parentsExpressions[index] = $"VFX_SAMPLER({expression})"; diff --git a/Packages/com.unity.visualeffectgraph/Editor/Expressions/VFXExpressionTextureValues.cs b/Packages/com.unity.visualeffectgraph/Editor/Expressions/VFXExpressionTextureValues.cs index 1192714ebcd..40f80751e51 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/Expressions/VFXExpressionTextureValues.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/Expressions/VFXExpressionTextureValues.cs @@ -152,7 +152,7 @@ public sealed override VFXValue CopyExpression(Mode mode) } } - struct BufferUsage : IEquatable + struct BufferType : IEquatable { public enum Container { @@ -163,9 +163,22 @@ public enum Container Buffer, RWBuffer, AppendStructuredBuffer, - ConsumeStructuredBuffer - - //Can be extended to integrate RWTexture2D here + ConsumeStructuredBuffer, + + Texture1D, + Texture2D, + Texture3D, + TextureCube, + Texture1DArray, + Texture2DArray, + TextureCubeArray, + RWTexture1D, + RWTexture2D, + RWTexture3D, + RWTextureCube, + RWTexture1DArray, + RWTexture2DArray, + RWTextureCubeArray, } public Container container { get; private set; } @@ -173,21 +186,21 @@ public enum Container public string verbatimType { get; private set; } public bool valid => actualType != null; - public BufferUsage(Container container, string verbatimType, Type actualType) + public BufferType(Container container, string verbatimType, Type actualType) { this.container = container; this.actualType = actualType; this.verbatimType = verbatimType; } - public bool Equals(BufferUsage other) + public bool Equals(BufferType other) { return container == other.container && actualType == other.actualType && verbatimType == other.verbatimType; } public override bool Equals(object obj) { - return obj is BufferUsage other && Equals(other); + return obj is BufferType other && Equals(other); } public override int GetHashCode() @@ -195,20 +208,20 @@ public override int GetHashCode() return HashCode.Combine(container, actualType, verbatimType); } - public static bool operator ==(BufferUsage lhs, BufferUsage rhs) => lhs.Equals(rhs); - public static bool operator !=(BufferUsage lhs, BufferUsage rhs) => !(lhs == rhs); + public static bool operator ==(BufferType lhs, BufferType rhs) => lhs.Equals(rhs); + public static bool operator !=(BufferType lhs, BufferType rhs) => !(lhs == rhs); } #pragma warning disable 0659 sealed class VFXExpressionBufferWithType : VFXExpression { - public VFXExpressionBufferWithType() : this(new BufferUsage(), VFXValue.Default) + public VFXExpressionBufferWithType() : this(new BufferType(), VFXValue.Default) { } - public VFXExpressionBufferWithType(BufferUsage usage, VFXExpression graphicsBuffer) : base(Flags.None, new[] { graphicsBuffer }) + public VFXExpressionBufferWithType(BufferType type, VFXExpression buffer) : base(Flags.None, new[] { buffer }) { - this.usage = usage; + this.Type = type; } public override VFXExpressionOperation operation => VFXExpressionOperation.None; @@ -218,7 +231,7 @@ public VFXExpressionBufferWithType(BufferUsage usage, VFXExpression graphicsBuff protected override VFXExpression Reduce(VFXExpression[] reducedParents) { var reduced = (VFXExpressionBufferWithType)base.Reduce(reducedParents); - reduced.usage = usage; + reduced.Type = Type; return reduced; } @@ -230,7 +243,7 @@ protected override VFXExpression Evaluate(VFXExpression[] constParents) protected override int GetInnerHashCode() { - return HashCode.Combine(base.GetInnerHashCode(), usage.GetHashCode()); + return HashCode.Combine(base.GetInnerHashCode(), Type.GetHashCode()); } public override bool Equals(object obj) @@ -242,10 +255,10 @@ public override bool Equals(object obj) if (other == null) return false; - return other.usage == usage; + return other.Type == Type; } - public BufferUsage usage { get; private set; } + public BufferType Type { get; private set; } } #pragma warning restore 0659 } diff --git a/Packages/com.unity.visualeffectgraph/Editor/FilterPopup/VFXBlockProvider.cs b/Packages/com.unity.visualeffectgraph/Editor/FilterPopup/VFXBlockProvider.cs index cd6cad2decd..f353d2f21c1 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/FilterPopup/VFXBlockProvider.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/FilterPopup/VFXBlockProvider.cs @@ -54,10 +54,15 @@ public override IEnumerable GetDescriptors() new[] { new KeyValuePair(nameof(SetAttribute.attribute), customAttribute.name) }), null); } + var selfPath = m_ContextController.model is VFXBlockSubgraphContext ? AssetDatabase.GetAssetPath(m_ContextController.model) : string.Empty; + foreach (var item in SubGraphCache.GetItems(typeof(VisualEffectSubgraphBlock))) { - if (((SubGraphCache.AdditionalBlockInfo)item.additionalInfos).compatibleType.HasFlag(m_ContextController.model.contextType) - && ((SubGraphCache.AdditionalBlockInfo)item.additionalInfos).compatibleData.HasFlag(m_ContextController.model.ownedType)) + if (!string.IsNullOrEmpty(selfPath) && selfPath == item.path) // don't include self + continue; + + var blockInfo = (SubGraphCache.AdditionalBlockInfo)item.additionalInfos; + if (m_ContextController.model.Accept(blockInfo.compatibleType, blockInfo.compatibleData)) { var variant = new SubgraphVariant( item.name, diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Blackboard/VFXBlackboard.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Blackboard/VFXBlackboard.cs index c8da0903e86..6314210ce5c 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Blackboard/VFXBlackboard.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Blackboard/VFXBlackboard.cs @@ -430,8 +430,10 @@ private DragVisualMode OnHandleDrop(HandleDragAndDropArgs arg) var parentItem = m_Treeview.GetItemDataForId(arg.parentId); if (arg.parentId < 0 || parentItem is PropertyCategory { isRoot: true } and not OutputCategory) { + var parentItemData = m_ParametersController.Find(x => x.id == arg.parentId); + var rootPropertiesCount = parentItemData.children.Count(x => x.data is PropertyItem); fieldId.Add(category.id); - controller.MoveCategory(category.title, childIndex); + controller.MoveCategory(category.title, childIndex - rootPropertiesCount); } } } @@ -547,6 +549,10 @@ private DragVisualMode OnDragAndDropUpdate(HandleDragAndDropArgs arg) { return DragVisualMode.Move; } + else if (arg.dropPosition == DragAndDropPosition.BetweenItems && parentItem is PropertyCategory && m_Treeview.selectedItem is PropertyItem) + { + return DragVisualMode.Move; + } return DragVisualMode.Rejected; } diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Elements/Controllers/VFXParameterController.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Elements/Controllers/VFXParameterController.cs index 3b8a60b5e95..52f94a45eee 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Elements/Controllers/VFXParameterController.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Elements/Controllers/VFXParameterController.cs @@ -159,15 +159,15 @@ public object value } set { + object rootValue = m_Parameter.value; object val = m_Parameter.value; - List objectStack = new List(); foreach (var fieldInfo in m_FieldInfos.Take(m_FieldInfos.Length - 1)) { - objectStack.Add(fieldInfo.GetValue(val)); + val = fieldInfo.GetValue(val); + objectStack.Add(val); } - object targetValue = value; for (int i = objectStack.Count - 1; i >= 0; --i) { @@ -175,9 +175,8 @@ public object value targetValue = objectStack[i]; } - m_FieldInfos[0].SetValue(val, targetValue); - - m_Parameter.value = val; + m_FieldInfos[0].SetValue(rootValue, targetValue); + m_Parameter.value = rootValue; } } } @@ -498,6 +497,7 @@ public IPropertyRMProvider GetMemberController(string memberPath) } } + members.Reverse(); foreach (var member in members) { subParameterController = subParameterController.children.FirstOrDefault(t => t.name == member); @@ -562,7 +562,7 @@ public void SetMemberValue(string memberPath, object value) } } - public static string MakeNameUnique(string name, HashSet allNames, bool allowSpace = true) + public static string MakeNameUnique(string name, HashSet allNames, bool allowSpace = true, List rejectedCandidateNames = null) { if (string.IsNullOrEmpty(name)) { @@ -575,7 +575,7 @@ public static string MakeNameUnique(string name, HashSet allNames, bool } string candidateMainPart = null; int cpt = 0; - while (allNames.Contains(candidateName)) + while (allNames.Contains(candidateName, StringComparer.OrdinalIgnoreCase)) { if (candidateMainPart == null) { @@ -601,6 +601,7 @@ public static string MakeNameUnique(string name, HashSet allNames, bool candidateName = allowSpace ? $"{candidateMainPart} {cpt}" : $"{candidateMainPart}_{cpt}"; + rejectedCandidateNames?.Add(candidateName); } return candidateName; diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Elements/VFXContextUI.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Elements/VFXContextUI.cs index 9f6b72a194f..1898c81bf7d 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Elements/VFXContextUI.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Elements/VFXContextUI.cs @@ -118,8 +118,9 @@ protected override void SelfChange() } m_HeaderIcon.image = GetIconForVFXType(controller.model.inputType); - m_HeaderIcon.visible = m_HeaderIcon.image != null; m_HeaderIcon.SendToBack(); // Actually move it as first child so it's before the title label + if (m_HeaderIcon.image == null) + m_HeaderIcon.AddToClassList("Empty"); var subTitle = controller.subtitle; m_Subtitle.text = controller.subtitle; @@ -457,8 +458,11 @@ private void OnDragUpdated(DragUpdatedEvent evt) if (references.Any() && (!controller.viewController.model.isSubgraph || !references.Any(t => t.GetResource().GetOrCreateGraph().subgraphDependencies.Contains(controller.viewController.model.subgraph) || t.GetResource() == controller.viewController.model))) { - var compatibleReferences = references - .Where(x => x != null && x.GetResource().GetOrCreateGraph().children.OfType().First().compatibleContextType.HasFlag(controller.model.contextType)); + var compatibleReferences = references.Where(x => + { + var subgraphBlock = x?.GetResource()?.GetOrCreateGraph()?.children.OfType().First(); + return subgraphBlock != null ? controller.model.Accept(subgraphBlock.compatibleContextType, subgraphBlock.ownedType) : false; + }); if (compatibleReferences.Any()) { @@ -529,8 +533,12 @@ void OnDragPerform(DragPerformEvent evt) foreach (var reference in references) { var graph = reference != null ? reference.GetResource().GetOrCreateGraph() : null; - if (graph != null && graph.children.OfType().First().compatibleContextType.HasFlag(controller.model.contextType)) + if (graph != null) { + var subgraphContext = graph.children.OfType().First(); + if (!controller.model.Accept(subgraphContext.compatibleContextType, subgraphContext.ownedType)) + continue; + DragAndDrop.AcceptDrag(); if (view.HasCustomAttributeConflicts(graph.attributesManager.GetCustomAttributes())) { diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Elements/VFXNodeUI.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Elements/VFXNodeUI.cs index cb07b17adea..f37fe2c98e5 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Elements/VFXNodeUI.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Elements/VFXNodeUI.cs @@ -463,6 +463,10 @@ private void GetPreferredWidths(ref float labelWidth, ref float controlWidth) { foreach (var port in GetPorts(true, false).OfType()) { + // Skip because it's not visible + if (!port.connected && !expanded) + continue; + float portLabelWidth = port.GetPreferredLabelWidth(); float portControlWidth = port.GetPreferredControlWidth(); @@ -515,7 +519,9 @@ public void GetWidths(out float labelWidth, out float controlWidth) var settingsLabelWidth = 0f; var inputsLabelWidth = 0f; controlWidth = 50f; - GetPreferredSettingsWidths(ref settingsLabelWidth, ref controlWidth); + // Settings are only visible when node is expanded + if (expanded) + GetPreferredSettingsWidths(ref settingsLabelWidth, ref controlWidth); GetPreferredWidths(ref inputsLabelWidth, ref controlWidth); labelWidth = Mathf.Max(settingsLabelWidth, inputsLabelWidth); if (labelWidth > 0) @@ -524,12 +530,9 @@ public void GetWidths(out float labelWidth, out float controlWidth) protected virtual void RefreshLayout() { - if (expanded) - { - GetWidths(out var labelWidth, out var controlWidth); - ApplySettingsWidths(labelWidth); - ApplyWidths(labelWidth, controlWidth); - } + GetWidths(out var labelWidth, out var controlWidth); + ApplySettingsWidths(labelWidth); + ApplyWidths(labelWidth, controlWidth); } } } diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphView/VFXComponentBoard.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphView/VFXComponentBoard.cs index 4842b75048b..91995775635 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphView/VFXComponentBoard.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphView/VFXComponentBoard.cs @@ -338,7 +338,7 @@ void DeleteBoundsRecorder() void UpdateBoundsRecorder() { - if (controller != null && m_AttachedComponent != null && m_View.controller.graph != null) + if (controller != null && m_AttachedComponent != null && m_View.controller?.graph != null) { bool wasRecording = false; if (m_BoundsRecorder != null) diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphView/VFXViewWindow.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphView/VFXViewWindow.cs index d50b8e853d7..ddf3bd94f08 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphView/VFXViewWindow.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphView/VFXViewWindow.cs @@ -354,7 +354,7 @@ void Update() if (graphView == null && m_DisplayedResource == null) return; - VFXViewController controller = graphView.controller; + VFXViewController controller = graphView?.controller; var filename = "No Asset"; if (controller != null) { diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Views/Properties/ObjectPropertyRM.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Views/Properties/ObjectPropertyRM.cs index 8095a1f5ff5..d53e65e7fe5 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Views/Properties/ObjectPropertyRM.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Views/Properties/ObjectPropertyRM.cs @@ -59,7 +59,7 @@ public override void SetValue(object obj) private void OnValueChanged(ChangeEvent evt) { var newValueType = evt.newValue != null ? evt.newValue.GetType() : null; - if (newValueType != null && newValueType != m_Provider.portType && (newValueType != typeof(RenderTexture) || m_Provider.portType == typeof(CubemapArray))) + if (newValueType != null && newValueType != m_Provider.portType && (!typeof(RenderTexture).IsAssignableFrom(newValueType) || m_Provider.portType == typeof(CubemapArray))) { m_ObjectField.SetValueWithoutNotify(evt.previousValue); } diff --git a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Views/VFXHelpDropdownButton.cs b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Views/VFXHelpDropdownButton.cs index 70db4d9000a..997f300714d 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/GraphView/Views/VFXHelpDropdownButton.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/GraphView/Views/VFXHelpDropdownButton.cs @@ -10,18 +10,15 @@ namespace UnityEditor.VFX.UI { class VFXHelpDropdownButton : DropDownButtonBase { - const string k_PackageName = "com.unity.visualeffectgraph"; const string k_AdditionalSamples = "VisualEffectGraph Additions"; const string k_AdditionalHelpers = "OutputEvent Helpers"; + const string k_LearningSamples = "Learning Templates"; const string k_ManualUrl = @"https://docs.unity3d.com/Packages/com.unity.visualeffectgraph@{0}/index.html"; const string k_ForumUrl = @"https://forum.unity.com/forums/visual-effect-graph.428/"; const string k_SpaceShipUrl = @"https://github.com/Unity-Technologies/SpaceshipDemo"; const string k_SamplesUrl = @"https://github.com/Unity-Technologies/VisualEffectGraph-Samples"; const string k_VfxGraphUrl = @"https://unity.com/visual-effect-graph"; - readonly Button m_installSamplesButton; - readonly Button m_installHelpersButton; - string m_ManualUrlWithVersion; ListRequest m_PackageManagerRequest; @@ -35,11 +32,14 @@ public VFXHelpDropdownButton(VFXView vfxView) EditorResources.iconsPath + "_Help.png", true) { - m_installSamplesButton = m_PopupContent.Q
    Shadow Matte Indicates whether or not the Shader receives shadows. Shadow matte only supports shadow maps. It does not support Screen Space Shadows, Ray-Traced Shadows, or Contact Shadows.Indicates whether the shader receives shadows. Shadow matte only supports shadow maps. +It doesn't support screen-space shadows, ray-traced Shadows, or contact shadows.
    +Enable **Shadow Matte** if you add a custom Node that samples shadow maps, otherwise shadows might not render correctly. +