From 5437ef82d2fc24ac2fc505f98aea196aa13d4e28 Mon Sep 17 00:00:00 2001 From: Justin Schwartz Date: Wed, 11 Feb 2026 12:12:15 +0000 Subject: [PATCH 01/92] Optimized VolumetricLightingFiltering --- .../VolumetricLightingFiltering.compute | 80 +++++++++++-------- 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/VolumetricLightingFiltering.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/VolumetricLightingFiltering.compute index 468e2e781a3..a1ae3df1ecc 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/VolumetricLightingFiltering.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/VolumetricLightingFiltering.compute @@ -29,52 +29,65 @@ RW_TEXTURE3D(float4, _VBufferLightingFiltered); RW_TEXTURE3D(float4, _VBufferLighting); #endif -#define GAUSSIAN_SIGMA 1.0 -#define GROUP_SIZE_1D_XY 8 -#define GROUP_SIZE_1D_Z 1 +#define GAUSSIAN_SIGMA 1.0 +#define GROUP_SIZE_1D_XY 8 +#define GROUP_SIZE_1D_Z 1 +#define NR_THREADS (GROUP_SIZE_1D_XY * GROUP_SIZE_1D_XY * GROUP_SIZE_1D_Z) -#define FILTER_SIZE_1D (GROUP_SIZE_1D_XY + 2) // With a 8x8 group, we have a 10x10 working area -#define LDS_SIZE FILTER_SIZE_1D * FILTER_SIZE_1D +// Some platforms benefit from not using the split cache +#define USE_SPLIT_CACHE (!defined(SHADER_API_SWITCH) && !defined(SHADER_API_SWITCH2)) + +#define FILTER_SIZE_1D (GROUP_SIZE_1D_XY + 2) // With a 8x8 group, we have a 10x10 working area +#define LDS_SIZE FILTER_SIZE_1D * FILTER_SIZE_1D + +#define DIV_ROUND_UP(N, D) (((N) + ((D) - 1)) / (D)) // No division by 0 checks // TODO: May use 1 uint for 2 pixels +#if USE_SPLIT_CACHE groupshared float gs_cacheR[LDS_SIZE]; groupshared float gs_cacheG[LDS_SIZE]; groupshared float gs_cacheB[LDS_SIZE]; groupshared float gs_cacheA[LDS_SIZE]; +#else +groupshared float4 gs_cache[LDS_SIZE]; +#endif // USE_SPLIT_CACHE float4 GetSample(uint index) { float4 outVal; +#if USE_SPLIT_CACHE outVal.r = gs_cacheR[index]; outVal.g = gs_cacheG[index]; outVal.b = gs_cacheB[index]; outVal.a = gs_cacheA[index]; - +#else + outVal = gs_cache[index]; +#endif // USE_SPLIT_CACHE return outVal; } -void PrefetchData(uint groupIndex, uint2 groupOrigin, uint sliceIndex) +void PrefetchData(uint sampleID, uint2 groupOrigin, uint sliceIndex) { - int2 originXY = groupOrigin - int2(1, 1); + int2 originXY = int2(groupOrigin) - 1; - for (int i = 0; i < 2; ++i) - { - uint sampleID = i + (groupIndex * 2); - int offsetX = sampleID % FILTER_SIZE_1D; - int offsetY = sampleID / FILTER_SIZE_1D; + int offsetX = sampleID % FILTER_SIZE_1D; + int offsetY = sampleID / FILTER_SIZE_1D; - int3 sampleCoord = int3(clamp(originXY.x + offsetX, 0, _VBufferViewportSize.x - 1), - clamp(originXY.y + offsetY, 0, _VBufferViewportSize.y - 1), - sliceIndex); + uint3 sampleCoord = uint3(clamp(originXY.x + offsetX, 0, max(0, _VBufferViewportSize.x - 1)), + clamp(originXY.y + offsetY, 0, max(0, _VBufferViewportSize.y - 1)), + sliceIndex); - float4 sampleVal = _VBufferLighting[sampleCoord]; + float4 sampleVal = _VBufferLighting[sampleCoord]; - int LDSIndex = offsetX + offsetY * FILTER_SIZE_1D; - gs_cacheR[LDSIndex] = sampleVal.r; - gs_cacheG[LDSIndex] = sampleVal.g; - gs_cacheB[LDSIndex] = sampleVal.b; - gs_cacheA[LDSIndex] = sampleVal.a; - } + uint LDSIndex = offsetX + offsetY * FILTER_SIZE_1D; +#if USE_SPLIT_CACHE + gs_cacheR[LDSIndex] = sampleVal.r; + gs_cacheG[LDSIndex] = sampleVal.g; + gs_cacheB[LDSIndex] = sampleVal.b; + gs_cacheA[LDSIndex] = sampleVal.a; +#else + gs_cache[LDSIndex] = sampleVal; +#endif // USE_SPLIT_CACHE } void WriteOutput(uint3 voxelCoord, float4 value) @@ -94,9 +107,9 @@ float Gaussian(float radius, float sigma) [numthreads(GROUP_SIZE_1D_XY, GROUP_SIZE_1D_XY, GROUP_SIZE_1D_Z)] void FilterVolumetricLighting(uint3 dispatchThreadId : SV_DispatchThreadID, - int groupIndex : SV_GroupIndex, - uint2 groupId : SV_GroupID, - uint2 groupThreadId : SV_GroupThreadID) + uint groupIndex : SV_GroupIndex, + uint2 groupId : SV_GroupID, + uint2 groupThreadId : SV_GroupThreadID) { // Compute the coordinate that this thread needs to process uint2 currentCoord = groupId * GROUP_SIZE_1D_XY + groupThreadId; @@ -105,10 +118,11 @@ void FilterVolumetricLighting(uint3 dispatchThreadId : SV_DispatchThreadID, // Compute the output voxel coordinate uint3 voxelCoord = uint3(currentCoord, currentSlice); - if (groupIndex < 50) + // Preload data + UNITY_UNROLLX(DIV_ROUND_UP(LDS_SIZE, NR_THREADS)) + for (uint i = groupIndex; i < LDS_SIZE; i += NR_THREADS) { - // Load 2 values per thread. - PrefetchData(groupIndex, groupId * GROUP_SIZE_1D_XY, voxelCoord.z); + PrefetchData(i, groupId * GROUP_SIZE_1D_XY, voxelCoord.z); } // Make sure all values are loaded in LDS by now. @@ -120,15 +134,14 @@ void FilterVolumetricLighting(uint3 dispatchThreadId : SV_DispatchThreadID, const int radius = 1; + UNITY_UNROLL for (int idx = -radius; idx <= radius; ++idx) { + UNITY_UNROLL for (int idx2 = -radius; idx2 <= radius; ++idx2) { - // Compute the next tapping coordinate - const int3 tapCoord = int3(voxelCoord.x, voxelCoord.y, voxelCoord.z) + int3(idx2, idx, 0); - // Tap from LDS - int2 tapAddress = (groupThreadId + 1) + int2(idx2, idx); + int2 tapAddress = (int2(groupThreadId) + 1) + int2(idx2, idx); uint ldsTapAddress = uint(tapAddress.x) % FILTER_SIZE_1D + tapAddress.y * FILTER_SIZE_1D; float4 currentValue = GetSample(ldsTapAddress); @@ -139,7 +152,6 @@ void FilterVolumetricLighting(uint3 dispatchThreadId : SV_DispatchThreadID, value += currentValue * weight; sumW += weight; } - } WriteOutput(voxelCoord, value / sumW); From 28feb98d35b0aedc08fd0b95520f372fd52c0df3 Mon Sep 17 00:00:00 2001 From: Tomek Paszek Date: Wed, 11 Feb 2026 12:12:18 +0000 Subject: [PATCH 02/92] UTR: Test report edge-case fix --- .../Assets/CommonAssets/Scripts/ShaderGraphGraphicsTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/SRPTests/Projects/ShaderGraph/Assets/CommonAssets/Scripts/ShaderGraphGraphicsTests.cs b/Tests/SRPTests/Projects/ShaderGraph/Assets/CommonAssets/Scripts/ShaderGraphGraphicsTests.cs index 3493d456f57..6d0fe08d4df 100644 --- a/Tests/SRPTests/Projects/ShaderGraph/Assets/CommonAssets/Scripts/ShaderGraphGraphicsTests.cs +++ b/Tests/SRPTests/Projects/ShaderGraph/Assets/CommonAssets/Scripts/ShaderGraphGraphicsTests.cs @@ -9,6 +9,7 @@ public class ShaderGraphGraphicsTests { [IgnoreGraphicsTest("InputNodes|SamplerStateTests|UVNodes", "GLES3 renders these tests incorrectly (FB: 1354427)", runtimePlatforms: new RuntimePlatform[] { RuntimePlatform.Android }, graphicsDeviceTypes: new GraphicsDeviceType[] { GraphicsDeviceType.OpenGLES3 })] + [IgnoreGraphicsTest("InputNodes", "UUM-134140", runtimePlatforms: new RuntimePlatform[] { RuntimePlatform.WindowsEditor }, graphicsDeviceTypes: new GraphicsDeviceType[] { GraphicsDeviceType.Direct3D12 })] [IgnoreGraphicsTest("InstanceIDWithKeywords", "Platform Independent", graphicsDeviceTypes: new GraphicsDeviceType[] { GraphicsDeviceType.OpenGLES3 })] [IgnoreGraphicsTest("InstanceIDWithKeywords", "Platform Independent", graphicsDeviceTypes: new GraphicsDeviceType[] { GraphicsDeviceType.PlayStation4 })] [IgnoreGraphicsTest("InstanceIDWithKeywords", "Platform Independent", graphicsDeviceTypes: new GraphicsDeviceType[] { GraphicsDeviceType.XboxOne })] From acfbda7aec9bd2f1e23d609f353021a84965448e Mon Sep 17 00:00:00 2001 From: Marc Templin Date: Wed, 11 Feb 2026 12:12:18 +0000 Subject: [PATCH 03/92] Change "SRP XR" team to "Graphics XR" in buginfo --- .../com.unity.render-pipelines.core/Runtime/Utilities/.buginfo | 2 +- Packages/com.unity.render-pipelines.core/Runtime/XR/.buginfo | 2 +- Packages/com.unity.render-pipelines.core/Tests/Runtime/.buginfo | 2 +- .../Runtime/RenderPipeline/XR/.buginfo | 2 +- .../com.unity.render-pipelines.universal/Runtime/XR/.buginfo | 2 +- Tests/SRPTests/Packages/com.unity.testing.xr/.buginfo | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Utilities/.buginfo b/Packages/com.unity.render-pipelines.core/Runtime/Utilities/.buginfo index 0f536f6e290..5ff71313356 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Utilities/.buginfo +++ b/Packages/com.unity.render-pipelines.core/Runtime/Utilities/.buginfo @@ -15,7 +15,7 @@ xr: when: path: - ^.*XRUtils?.*$ - area: SRP XR + area: Graphics XR camera: when: diff --git a/Packages/com.unity.render-pipelines.core/Runtime/XR/.buginfo b/Packages/com.unity.render-pipelines.core/Runtime/XR/.buginfo index 701b4cbc25d..f6d9eecbd20 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/XR/.buginfo +++ b/Packages/com.unity.render-pipelines.core/Runtime/XR/.buginfo @@ -1 +1 @@ -area: SRP XR +area: Graphics XR diff --git a/Packages/com.unity.render-pipelines.core/Tests/Runtime/.buginfo b/Packages/com.unity.render-pipelines.core/Tests/Runtime/.buginfo index c0979152f33..c8ea5a54281 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Runtime/.buginfo +++ b/Packages/com.unity.render-pipelines.core/Tests/Runtime/.buginfo @@ -17,4 +17,4 @@ xr: when: path: - ^.*XRSubsystem.*$ - area: SRP XR + area: Graphics XR diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/XR/.buginfo b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/XR/.buginfo index 701b4cbc25d..f6d9eecbd20 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/XR/.buginfo +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/XR/.buginfo @@ -1 +1 @@ -area: SRP XR +area: Graphics XR diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/XR/.buginfo b/Packages/com.unity.render-pipelines.universal/Runtime/XR/.buginfo index 701b4cbc25d..f6d9eecbd20 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/XR/.buginfo +++ b/Packages/com.unity.render-pipelines.universal/Runtime/XR/.buginfo @@ -1 +1 @@ -area: SRP XR +area: Graphics XR diff --git a/Tests/SRPTests/Packages/com.unity.testing.xr/.buginfo b/Tests/SRPTests/Packages/com.unity.testing.xr/.buginfo index 701b4cbc25d..f6d9eecbd20 100644 --- a/Tests/SRPTests/Packages/com.unity.testing.xr/.buginfo +++ b/Tests/SRPTests/Packages/com.unity.testing.xr/.buginfo @@ -1 +1 @@ -area: SRP XR +area: Graphics XR From d27f1ff755939cb97cf19b267e5b423a20f2e8b1 Mon Sep 17 00:00:00 2001 From: Elvis Alistar Date: Wed, 11 Feb 2026 12:12:19 +0000 Subject: [PATCH 04/92] Disable unstable UnderWater tests --- .../Assets/GraphicTests/Tests/HDRP_Graphics_Tests.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Tests/SRPTests/Projects/HDRP_Tests/Assets/GraphicTests/Tests/HDRP_Graphics_Tests.cs b/Tests/SRPTests/Projects/HDRP_Tests/Assets/GraphicTests/Tests/HDRP_Graphics_Tests.cs index c6296701411..51e711a9f96 100644 --- a/Tests/SRPTests/Projects/HDRP_Tests/Assets/GraphicTests/Tests/HDRP_Graphics_Tests.cs +++ b/Tests/SRPTests/Projects/HDRP_Tests/Assets/GraphicTests/Tests/HDRP_Graphics_Tests.cs @@ -313,6 +313,11 @@ public void SetUpContext() "Diverges in the wave-modifier edges.", graphicsDeviceTypes: new[] { GraphicsDeviceType.Metal } )] + [IgnoreGraphicsTest( + "9921_UnderWater$", + "Unstable - see https://jira.unity3d.com/browse/UUM-134223", + runtimePlatforms: new[] { RuntimePlatform.WindowsEditor } + )] [IgnoreGraphicsTest( "9922_WaterPrefab$", "Minor divergence across the waves' crests.", From 56ebca0250b112e062f6da7852c4c67c3c9f2ebf Mon Sep 17 00:00:00 2001 From: Angela Dematte Date: Wed, 11 Feb 2026 20:29:22 +0000 Subject: [PATCH 05/92] Increase timeout value for Materials test --- .../Assets/GraphicTests/HDRP_EditModeTests/PreviewTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/SRPTests/Projects/HDRP_Tests/Assets/GraphicTests/HDRP_EditModeTests/PreviewTests.cs b/Tests/SRPTests/Projects/HDRP_Tests/Assets/GraphicTests/HDRP_EditModeTests/PreviewTests.cs index 410df310541..94cbe89ecaf 100644 --- a/Tests/SRPTests/Projects/HDRP_Tests/Assets/GraphicTests/HDRP_EditModeTests/PreviewTests.cs +++ b/Tests/SRPTests/Projects/HDRP_Tests/Assets/GraphicTests/HDRP_EditModeTests/PreviewTests.cs @@ -153,6 +153,7 @@ Mesh CreateUniqueMiniMesh() [UnityTest] + [Timeout(360000)] public IEnumerator AssetPreviewIsCorrect() { EditorSceneManager.OpenScene("Assets/GraphicTests/Scenes/1x_Materials/1101_Unlit.unity"); // Ensure the opened scene doesn't have any error. From ebaa8f3e69fd594a31a3f594c36a1be8d7759761 Mon Sep 17 00:00:00 2001 From: Elvis Alistar Date: Thu, 12 Feb 2026 09:49:37 +0000 Subject: [PATCH 06/92] Disable unstable WaterPrefab test --- .../Assets/GraphicTests/Tests/HDRP_Graphics_Tests.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Tests/SRPTests/Projects/HDRP_Tests/Assets/GraphicTests/Tests/HDRP_Graphics_Tests.cs b/Tests/SRPTests/Projects/HDRP_Tests/Assets/GraphicTests/Tests/HDRP_Graphics_Tests.cs index 51e711a9f96..03a3b2b013b 100644 --- a/Tests/SRPTests/Projects/HDRP_Tests/Assets/GraphicTests/Tests/HDRP_Graphics_Tests.cs +++ b/Tests/SRPTests/Projects/HDRP_Tests/Assets/GraphicTests/Tests/HDRP_Graphics_Tests.cs @@ -314,7 +314,17 @@ public void SetUpContext() graphicsDeviceTypes: new[] { GraphicsDeviceType.Metal } )] [IgnoreGraphicsTest( - "9921_UnderWater$", + "9921_UnderWater", + "Unstable - see https://jira.unity3d.com/browse/UUM-134223", + runtimePlatforms: new[] { RuntimePlatform.WindowsEditor } + )] + [IgnoreGraphicsTest( + "9921_UnderWater_Back", + "Unstable - see https://jira.unity3d.com/browse/UUM-134223", + runtimePlatforms: new[] { RuntimePlatform.WindowsEditor } + )] + [IgnoreGraphicsTest( + "9922_WaterPrefab", "Unstable - see https://jira.unity3d.com/browse/UUM-134223", runtimePlatforms: new[] { RuntimePlatform.WindowsEditor } )] From 851f3a5852e12420259f1f6d2644a7a14b91b2e0 Mon Sep 17 00:00:00 2001 From: Kenny Tan Date: Thu, 12 Feb 2026 11:28:07 +0000 Subject: [PATCH 07/92] [D2D-7864][6000.5][2D] RenderSprite and RenderSpriteInstanced api --- .../Includes/SpriteNormalPass.hlsl | 2 + .../Shaders/2D/Sprite-Lit-Default.shader | 3 + .../Assets/Scenes/032_RenderSprite.meta | 8 + .../Assets/Scenes/032_RenderSprite.unity | 587 ++++++++ .../Assets/Scenes/032_RenderSprite.unity.meta | 7 + .../032_RenderSprite/Glow Rock Normal Map.png | Bin 0 -> 29461 bytes .../Glow Rock Normal Map.png.meta | 143 ++ .../Scenes/032_RenderSprite/Glow Rock.png | Bin 0 -> 43158 bytes .../032_RenderSprite/Glow Rock.png.meta | 197 +++ .../032_RenderSprite/RenderSpriteDrawer.cs | 82 ++ .../RenderSpriteDrawer.cs.meta | 2 + .../RenderSpriteInstancedLit.mat | 50 + .../RenderSpriteInstancedLit.mat.meta | 8 + .../RenderSprite_Shadergraph.shadergraph | 1212 +++++++++++++++++ .../RenderSprite_Shadergraph.shadergraph.meta | 18 + .../RenderSprite_Shadergraph_Material.mat | 65 + ...RenderSprite_Shadergraph_Material.mat.meta | 8 + .../Scenes/032_RenderSprite_DrawDynamic.unity | 600 ++++++++ .../032_RenderSprite_DrawDynamic.unity.meta | 7 + .../Scenes/032_RenderSprite_SpriteMask.unity | 680 +++++++++ .../032_RenderSprite_SpriteMask.unity.meta | 7 + 21 files changed, 3686 insertions(+) create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite.unity create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite.unity.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/Glow Rock Normal Map.png create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/Glow Rock Normal Map.png.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/Glow Rock.png create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/Glow Rock.png.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSpriteDrawer.cs create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSpriteDrawer.cs.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSpriteInstancedLit.mat create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSpriteInstancedLit.mat.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSprite_Shadergraph.shadergraph create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSprite_Shadergraph.shadergraph.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSprite_Shadergraph_Material.mat create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSprite_Shadergraph_Material.mat.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite_DrawDynamic.unity create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite_DrawDynamic.unity.meta create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite_SpriteMask.unity create mode 100644 Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite_SpriteMask.unity.meta diff --git a/Packages/com.unity.render-pipelines.universal/Editor/2D/ShaderGraph/Includes/SpriteNormalPass.hlsl b/Packages/com.unity.render-pipelines.universal/Editor/2D/ShaderGraph/Includes/SpriteNormalPass.hlsl index dc7e96bf0c3..4be61625120 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/2D/ShaderGraph/Includes/SpriteNormalPass.hlsl +++ b/Packages/com.unity.render-pipelines.universal/Editor/2D/ShaderGraph/Includes/SpriteNormalPass.hlsl @@ -19,6 +19,8 @@ half4 frag(PackedVaryings packedInput) : SV_TARGET UNITY_SETUP_INSTANCE_ID(unpacked); UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(unpacked); + SetUpSpriteInstanceProperties(); + SurfaceDescription surfaceDescription = BuildSurfaceDescription(unpacked); #ifdef UNIVERSAL_USELEGACYSPRITEBLOCKS diff --git a/Packages/com.unity.render-pipelines.universal/Shaders/2D/Sprite-Lit-Default.shader b/Packages/com.unity.render-pipelines.universal/Shaders/2D/Sprite-Lit-Default.shader index 26449110ef0..f4b0e8284e5 100644 --- a/Packages/com.unity.render-pipelines.universal/Shaders/2D/Sprite-Lit-Default.shader +++ b/Packages/com.unity.render-pipelines.universal/Shaders/2D/Sprite-Lit-Default.shader @@ -126,6 +126,9 @@ Shader "Universal Render Pipeline/2D/Sprite-Lit-Default" half4 NormalsRenderingFragment(Varyings input) : SV_Target { + // Setup instancing for SpriteFlip is used in NormalsRenderingShared + SetUpSpriteInstanceProperties(); + return CommonNormalsFragment(input, input.color); } ENDHLSL diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite.meta new file mode 100644 index 00000000000..76e9b247d17 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 83f96c78311d63c46959e83b4c28b1c0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite.unity b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite.unity new file mode 100644 index 00000000000..1cbfb9681dd --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite.unity @@ -0,0 +1,587 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 10 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 2 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 1 + m_PVRFilteringGaussRadiusAO: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &552063972 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 552063974} + - component: {fileID: 552063973} + m_Layer: 0 + m_Name: RenderSpriteInstancedDrawer Shadergraph + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &552063973 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 552063972} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 17b893b44cf284b409275a57996e9e60, type: 3} + m_Name: + m_EditorClassIdentifier: Universal2DGraphicsTests::RenderParamsInstancedDrawer + drawSprite: {fileID: 21300000, guid: 803bd3331724e514cbb16c45ce27b1c5, type: 3} + drawMaterial: {fileID: 2100000, guid: 4da613ca97d323a4da07bb58873d2ee5, type: 2} + gridCount: 3 + offset: 3 + useInstancing: 1 + maskInteraction: 0 +--- !u!4 &552063974 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 552063972} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 2.2, y: -2, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1034731507 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1034731510} + - component: {fileID: 1034731509} + - component: {fileID: 1034731508} + - component: {fileID: 1034731511} + - component: {fileID: 1034731512} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1034731508 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1034731507} + m_Enabled: 1 +--- !u!20 &1034731509 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1034731507} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 1} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 1 + orthographic size: 9 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1034731510 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1034731507} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1034731511 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1034731507} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalCameraData + m_RenderShadows: 1 + m_RequiresDepthTextureOption: 2 + m_RequiresOpaqueTextureOption: 2 + m_CameraType: 0 + m_Cameras: [] + m_RendererIndex: -1 + m_VolumeLayerMask: + serializedVersion: 2 + m_Bits: 1 + m_VolumeTrigger: {fileID: 0} + m_VolumeFrameworkUpdateModeOption: 2 + m_RenderPostProcessing: 0 + m_Antialiasing: 0 + m_AntialiasingQuality: 2 + m_StopNaN: 0 + m_Dithering: 0 + m_ClearDepth: 1 + m_AllowXRRendering: 1 + m_AllowHDROutput: 1 + m_UseScreenCoordOverride: 0 + m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0} + m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0} + m_RequiresDepthTexture: 0 + m_RequiresColorTexture: 0 + m_TaaSettings: + m_Quality: 3 + m_FrameInfluence: 0.1 + m_JitterScale: 1 + m_MipBias: 0 + m_VarianceClampScale: 0.9 + m_ContrastAdaptiveSharpening: 0 + m_Version: 2 +--- !u!114 &1034731512 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1034731507} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 73231aa468d81ea49bc3d914080de185, type: 3} + m_Name: + m_EditorClassIdentifier: UniversalGraphicsTests::UniversalGraphicsTestSettings + ImageComparisonSettings: + TargetWidth: 512 + TargetHeight: 512 + TargetMSAASamples: 1 + PerPixelCorrectnessThreshold: 0.001 + PerPixelGammaThreshold: 0.003921569 + PerPixelAlphaThreshold: 0.003921569 + RMSEThreshold: 0 + AverageCorrectnessThreshold: 0.005 + IncorrectPixelsThreshold: 0.0000038146973 + UseHDR: 0 + UseBackBuffer: 0 + ImageResolution: 0 + ActiveImageTests: 1 + ActivePixelTests: 7 + WaitFrames: 15 + XRCompatible: 0 + gpuDrivenCompatible: 0 + CheckMemoryAllocation: 1 + renderBackendCompatibility: 2 + SetBackBufferResolution: 0 +--- !u!1 &1218736712 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1218736714} + - component: {fileID: 1218736713} + m_Layer: 0 + m_Name: RenderSpriteInstancedDrawer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1218736713 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1218736712} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 17b893b44cf284b409275a57996e9e60, type: 3} + m_Name: + m_EditorClassIdentifier: Universal2DGraphicsTests::RenderParamsInstancedDrawer + drawSprite: {fileID: 21300000, guid: 803bd3331724e514cbb16c45ce27b1c5, type: 3} + drawMaterial: {fileID: 2100000, guid: 3f5575fc185028542a3f30b3b4b1911a, type: 2} + gridCount: 3 + offset: 3 + useInstancing: 1 + maskInteraction: 0 +--- !u!4 &1218736714 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1218736712} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 2.2, y: 2, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1481681362 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1481681364} + - component: {fileID: 1481681363} + m_Layer: 0 + m_Name: RenderSpriteDrawer Shadergraph + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1481681363 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1481681362} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 17b893b44cf284b409275a57996e9e60, type: 3} + m_Name: + m_EditorClassIdentifier: Universal2DGraphicsTests::RenderParamsInstancedDrawer + drawSprite: {fileID: -6091329584399971573, guid: 734039631e6f77248b04a79e9dded059, + type: 3} + drawMaterial: {fileID: 2100000, guid: 4da613ca97d323a4da07bb58873d2ee5, type: 2} + gridCount: 3 + offset: 3 + useInstancing: 0 + maskInteraction: 0 +--- !u!4 &1481681364 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1481681362} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -2.2, y: -2, z: 0} + m_LocalScale: {x: 0.4, y: 0.4, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1655946128 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1655946130} + - component: {fileID: 1655946129} + m_Layer: 0 + m_Name: RenderSpriteDrawer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1655946129 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1655946128} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 17b893b44cf284b409275a57996e9e60, type: 3} + m_Name: + m_EditorClassIdentifier: Universal2DGraphicsTests::RenderParamsInstancedDrawer + drawSprite: {fileID: 21300000, guid: 86ce912717672b8429c58e6960c12e25, type: 3} + drawMaterial: {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2} + gridCount: 3 + offset: 3 + useInstancing: 0 + maskInteraction: 0 +--- !u!4 &1655946130 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1655946128} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -2.2, y: 2, z: 0} + m_LocalScale: {x: 2, y: 2, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1852367347 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1852367348} + - component: {fileID: 1852367349} + m_Layer: 0 + m_Name: Spot Light 2D + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1852367348 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1852367347} + serializedVersion: 2 + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 2, y: 2, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1852367349 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1852367347} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 073797afb82c5a1438f328866b10b3f0, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.2D.Runtime::UnityEngine.Rendering.Universal.Light2D + m_ComponentVersion: 2 + m_LightType: 3 + m_BlendStyleIndex: 0 + m_FalloffIntensity: 0.5 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 1 + m_LightVolumeIntensity: 1 + m_LightVolumeEnabled: 0 + m_ApplyToSortingLayers: eb0feddf00000000e980ef06 + m_LightCookieSprite: {fileID: 0} + m_DeprecatedPointLightCookieSprite: {fileID: 0} + m_LightOrder: 0 + m_AlphaBlendOnOverlap: 0 + m_OverlapOperation: 0 + m_NormalMapDistance: 3 + m_NormalMapQuality: 1 + m_UseNormalMap: 0 + m_ShadowsEnabled: 1 + m_ShadowIntensity: 0.75 + m_ShadowSoftness: 0.3 + m_ShadowSoftnessFalloffIntensity: 0.5 + m_ShadowVolumeIntensityEnabled: 0 + m_ShadowVolumeIntensity: 0.75 + m_LocalBounds: + m_Center: {x: 0, y: -0.00000011920929, z: 0} + m_Extent: {x: 0.9985302, y: 0.99853027, z: 0} + m_PointLightInnerAngle: 360 + m_PointLightOuterAngle: 360 + m_PointLightInnerRadius: 10 + m_PointLightOuterRadius: 12 + m_ShapeLightParametricSides: 5 + m_ShapeLightParametricAngleOffset: 0 + m_ShapeLightParametricRadius: 1 + m_ShapeLightFalloffSize: 0.5 + m_ShapeLightFalloffOffset: {x: 0, y: 0} + m_ShapePath: + - {x: -0.5, y: -0.5, z: 0} + - {x: 0.5, y: -0.5, z: 0} + - {x: 0.5, y: 0.5, z: 0} + - {x: -0.5, y: 0.5, z: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 1034731510} + - {fileID: 1852367348} + - {fileID: 1655946130} + - {fileID: 1218736714} + - {fileID: 1481681364} + - {fileID: 552063974} diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite.unity.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite.unity.meta new file mode 100644 index 00000000000..67a1046aba9 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d89649a3a172da7419f8f0e2f7858052 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/Glow Rock Normal Map.png b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/Glow Rock Normal Map.png new file mode 100644 index 0000000000000000000000000000000000000000..f759e4162436e58d9d5dd70983f4c82d3512fee3 GIT binary patch literal 29461 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 literal 0 HcmV?d00001 diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/Glow Rock Normal Map.png.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/Glow Rock Normal Map.png.meta new file mode 100644 index 00000000000..db8dd66ce17 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/Glow Rock Normal Map.png.meta @@ -0,0 +1,143 @@ +fileFormatVersion: 2 +guid: 51de18ea48a82a44886b78ffd4f4efe5 +TextureImporter: + internalIDToNameTable: + - first: + 213: -5321421104639177684 + second: Glow Rock Normal Map_0 + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 2 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 1 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: Glow Rock Normal Map_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 249 + height: 213 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: c2c07bd03b38626b0800000000000000 + internalID: -5321421104639177684 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + Glow Rock Normal Map_0: -5321421104639177684 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/Glow Rock.png b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/Glow Rock.png new file mode 100644 index 0000000000000000000000000000000000000000..d55a07ccc97370fef294095d634116162dd71cb4 GIT binary patch literal 43158 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

S2{AXhx4*J85!BB{i)C?A}Q43=;DB->L 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 literal 0 HcmV?d00001 diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/Glow Rock.png.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/Glow Rock.png.meta new file mode 100644 index 00000000000..14e34a9ab89 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/Glow Rock.png.meta @@ -0,0 +1,197 @@ +fileFormatVersion: 2 +guid: 803bd3331724e514cbb16c45ce27b1c5 +TextureImporter: + internalIDToNameTable: + - first: + 213: -8004898147434844477 + second: Glow Rock_0 + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: GameCoreXboxOne + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: CloudRendering + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Switch + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: GameCoreScarlett + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: Glow Rock_0 + rect: + serializedVersion: 2 + x: 22 + y: 22 + width: 207 + height: 175 + alignment: 0 + pivot: {x: 0.5, y: 0.5} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 3cea6f2fb83e8e090800000000000000 + internalID: -8004898147434844477 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 1537655665 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: + - texture: {fileID: 2800000, guid: 51de18ea48a82a44886b78ffd4f4efe5, type: 3} + name: _NormalMap + spriteCustomMetadata: + entries: [] + nameFileIdTable: + Glow Rock_0: -8004898147434844477 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSpriteDrawer.cs b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSpriteDrawer.cs new file mode 100644 index 00000000000..08958b8871a --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSpriteDrawer.cs @@ -0,0 +1,82 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Rendering; + +public class RenderParamsInstancedDrawer : MonoBehaviour +{ + public Sprite drawSprite; + public Material drawMaterial; + public int gridCount; + public float offset; + public bool useInstancing; + public SpriteMaskInteraction maskInteraction; + public string sortingLayerName = "Default"; + public int sortingOrder = 0; + + private int instanceCount; + MyInstanceData[] instanceData; + + struct MyInstanceData + { + public Matrix4x4 objectToWorld; + public Color spriteColor; + //public uint renderingLayerMask; + }; + + private void Start() + { + Random.InitState(1001); + + instanceCount = gridCount * gridCount; + + instanceData = new MyInstanceData[instanceCount]; + + var startOffset = gridCount / 2 * offset; + if (gridCount % 2 == 0) + startOffset -= offset / 2; + + var startPos = new Vector3(transform.position.x - startOffset, transform.position.y - startOffset, 0f); + + // Prepare some random transforms for our instances + for (int y = 0; y < gridCount; y++) + { + for (int x = 0; x < gridCount; x++) + { + var pos = new Vector3(startPos.x + x * offset, startPos.y + y * offset, 0f); + instanceData[y * gridCount + x].objectToWorld = Matrix4x4.TRS(pos + transform.position, transform.rotation, transform.localScale); + instanceData[y * gridCount + x].spriteColor = new Color(Random.Range(0, 1f), Random.Range(0, 1f), Random.Range(0, 1f), 1); + } + } + + RenderPipelineManager.beginContextRendering += OnBeginContextRendering; + } + + private void OnDestroy() + { + RenderPipelineManager.beginContextRendering -= OnBeginContextRendering; + } + + void OnBeginContextRendering(ScriptableRenderContext context, List cameras) + { + if (instanceData != null && instanceData.Length != 0) + { + RenderParams rp = new RenderParams(drawMaterial); + rp.sortingLayerID = SortingLayer.NameToID(sortingLayerName); + rp.sortingOrder = sortingOrder; + + if (useInstancing) + { + SpriteParams sp = new SpriteParams(drawSprite, Color.white, maskInteraction); + Graphics.RenderSpriteInstanced(rp, sp, 0, instanceData); + } + else + { + for (int i = 0; i < instanceData.Length; i++) + { + SpriteParams sp = new SpriteParams(drawSprite, instanceData[i].spriteColor, maskInteraction); + Graphics.RenderSprite(rp, sp, 0, instanceData[i].objectToWorld); + } + } + } + } +} diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSpriteDrawer.cs.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSpriteDrawer.cs.meta new file mode 100644 index 00000000000..d84020b6df0 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSpriteDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 17b893b44cf284b409275a57996e9e60 \ No newline at end of file diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSpriteInstancedLit.mat b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSpriteInstancedLit.mat new file mode 100644 index 00000000000..0134b710245 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSpriteInstancedLit.mat @@ -0,0 +1,50 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: RenderSpriteInstancedLit + m_Shader: {fileID: 4800000, guid: e260cfa7296ee7642b167f1eb5be5023, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 1 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _AlphaTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MaskTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _NormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _EnableExternalAlpha: 0 + - _ZWrite: 0 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _RendererColor: {r: 1, g: 1, b: 1, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSpriteInstancedLit.mat.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSpriteInstancedLit.mat.meta new file mode 100644 index 00000000000..73d876d062a --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSpriteInstancedLit.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3f5575fc185028542a3f30b3b4b1911a +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSprite_Shadergraph.shadergraph b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSprite_Shadergraph.shadergraph new file mode 100644 index 00000000000..8ceff73e556 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSprite_Shadergraph.shadergraph @@ -0,0 +1,1212 @@ +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.GraphData", + "m_ObjectId": "586930851e494e80887579d9c75172e1", + "m_Properties": [ + { + "m_Id": "31b4b452a3354da0b678a0720ced1d9e" + }, + { + "m_Id": "0755bf70e97540488b2a795beb57be87" + } + ], + "m_Keywords": [], + "m_Dropdowns": [], + "m_CategoryData": [ + { + "m_Id": "723a0f4478534bde9e762e8c0d59ab52" + } + ], + "m_Nodes": [ + { + "m_Id": "feecc8e9555240c595e65a546b8a0800" + }, + { + "m_Id": "f5940013eb90412eb8cf7c6a498139d8" + }, + { + "m_Id": "5d6ceca8af0d43e3b879322c2a0584ee" + }, + { + "m_Id": "0aa389cd937c42ab9a4b6b3057058183" + }, + { + "m_Id": "d83c2ccdc3694a71810d18c2e3b78385" + }, + { + "m_Id": "f9ae43f35dcf4825a0cf87c8e9059929" + }, + { + "m_Id": "241010d6733441e8a2fb7f0389aae4f1" + }, + { + "m_Id": "6d32ab1b2adc4edb9502ffac2e5a8b08" + }, + { + "m_Id": "d9af055288d1461d92f6330305bf50ee" + }, + { + "m_Id": "e8ae4105a3954825991ec11bf4cadfe3" + }, + { + "m_Id": "5e8ea239b3154b16a8d688a481ad4d4f" + } + ], + "m_GroupDatas": [], + "m_StickyNoteDatas": [], + "m_Edges": [ + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "5e8ea239b3154b16a8d688a481ad4d4f" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "f9ae43f35dcf4825a0cf87c8e9059929" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "6d32ab1b2adc4edb9502ffac2e5a8b08" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "d9af055288d1461d92f6330305bf50ee" + }, + "m_SlotId": 1 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "d9af055288d1461d92f6330305bf50ee" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "0aa389cd937c42ab9a4b6b3057058183" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "d9af055288d1461d92f6330305bf50ee" + }, + "m_SlotId": 7 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "241010d6733441e8a2fb7f0389aae4f1" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "e8ae4105a3954825991ec11bf4cadfe3" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "5e8ea239b3154b16a8d688a481ad4d4f" + }, + "m_SlotId": 1 + } + } + ], + "m_VertexContext": { + "m_Position": { + "x": 0.0, + "y": 0.0 + }, + "m_Blocks": [ + { + "m_Id": "feecc8e9555240c595e65a546b8a0800" + }, + { + "m_Id": "f5940013eb90412eb8cf7c6a498139d8" + }, + { + "m_Id": "5d6ceca8af0d43e3b879322c2a0584ee" + } + ] + }, + "m_FragmentContext": { + "m_Position": { + "x": 0.0, + "y": 200.0 + }, + "m_Blocks": [ + { + "m_Id": "0aa389cd937c42ab9a4b6b3057058183" + }, + { + "m_Id": "d83c2ccdc3694a71810d18c2e3b78385" + }, + { + "m_Id": "f9ae43f35dcf4825a0cf87c8e9059929" + }, + { + "m_Id": "241010d6733441e8a2fb7f0389aae4f1" + } + ] + }, + "m_PreviewData": { + "serializedMesh": { + "m_SerializedMesh": "{\"mesh\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "preventRotation": false + }, + "m_Path": "Shader Graphs", + "m_GraphPrecision": 1, + "m_PreviewMode": 2, + "m_OutputNode": { + "m_Id": "" + }, + "m_SubDatas": [], + "m_ActiveTargets": [ + { + "m_Id": "579c7870d0c842e08e5fd6fbb9ceed39" + } + ] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.UVMaterialSlot", + "m_ObjectId": "00cfa14ec3254a0e95ef789efd89941c", + "m_Id": 2, + "m_DisplayName": "UV", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "UV", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0 + }, + "m_Labels": [], + "m_Channel": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Internal.Texture2DShaderProperty", + "m_ObjectId": "0755bf70e97540488b2a795beb57be87", + "m_Guid": { + "m_GuidSerialized": "6c95e45b-f4a0-47e6-b523-5d3fd5e0734c" + }, + "promotedFromAssetID": "", + "promotedFromCategoryName": "", + "promotedOrdering": -1, + "m_Name": "NormalMap", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "NormalMap", + "m_DefaultReferenceName": "_NormalMap", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_PerRendererData": false, + "m_customAttributes": [], + "m_Value": { + "m_SerializedTexture": "", + "m_Guid": "" + }, + "isMainTexture": false, + "useTilingAndOffset": false, + "useTexelSize": true, + "m_Modifiable": true, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.UVMaterialSlot", + "m_ObjectId": "081abc247df543c898d83950be03d2d6", + "m_Id": 2, + "m_DisplayName": "UV", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "UV", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0 + }, + "m_Labels": [], + "m_Channel": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "0aa389cd937c42ab9a4b6b3057058183", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.BaseColor", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "6edf48bfe9284ba6b86d424a024e3c83" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.BaseColor" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "0bbc7c2f9e8942d8b727746b3e5876e5", + "m_Id": 4, + "m_DisplayName": "R", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "R", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [], + "m_LiteralMode": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "0c49eb39e07541b39d6e61a2b06247b8", + "m_Id": 0, + "m_DisplayName": "Alpha", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Alpha", + "m_StageCapability": 2, + "m_Value": 1.0, + "m_DefaultValue": 1.0, + "m_Labels": [], + "m_LiteralMode": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.NormalMaterialSlot", + "m_ObjectId": "10d2cb876bfc4f6dba9b60411a027a9b", + "m_Id": 0, + "m_DisplayName": "Normal (Tangent Space)", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "NormalTS", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 3 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SamplerStateMaterialSlot", + "m_ObjectId": "1d570de16eed4abd8b51b3a899f20684", + "m_Id": 3, + "m_DisplayName": "Sampler", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Sampler", + "m_StageCapability": 3, + "m_BareResource": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "241010d6733441e8a2fb7f0389aae4f1", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Alpha", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "0c49eb39e07541b39d6e61a2b06247b8" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Alpha" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "26d7cc7afd16455fad82b24619c2764a", + "m_Id": 5, + "m_DisplayName": "G", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "G", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [], + "m_LiteralMode": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PositionMaterialSlot", + "m_ObjectId": "2920c8f1f1fd4d329be139c96269964f", + "m_Id": 0, + "m_DisplayName": "Position", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Position", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Internal.Texture2DShaderProperty", + "m_ObjectId": "31b4b452a3354da0b678a0720ced1d9e", + "m_Guid": { + "m_GuidSerialized": "7a1f1fdc-5622-4aa7-9954-46dfc502412a" + }, + "promotedFromAssetID": "", + "promotedFromCategoryName": "", + "promotedOrdering": -1, + "m_Name": "MainTex", + "m_DefaultRefNameVersion": 1, + "m_RefNameGeneratedByDisplayName": "MainTex", + "m_DefaultReferenceName": "_MainTex", + "m_OverrideReferenceName": "", + "m_GeneratePropertyBlock": true, + "m_UseCustomSlotLabel": false, + "m_CustomSlotLabel": "", + "m_DismissedVersion": 0, + "m_Precision": 0, + "overrideHLSLDeclaration": false, + "hlslDeclarationOverride": 0, + "m_Hidden": false, + "m_PerRendererData": false, + "m_customAttributes": [], + "m_Value": { + "m_SerializedTexture": "", + "m_Guid": "" + }, + "isMainTexture": false, + "useTilingAndOffset": false, + "useTexelSize": true, + "m_Modifiable": true, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DMaterialSlot", + "m_ObjectId": "31daaf37794f40d08bb33ffa152ed984", + "m_Id": 0, + "m_DisplayName": "MainTex", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_BareResource": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.NormalMaterialSlot", + "m_ObjectId": "378feb07efd44359a2e175febf48ddd6", + "m_Id": 0, + "m_DisplayName": "Normal", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Normal", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SamplerStateMaterialSlot", + "m_ObjectId": "3f7d582ae2084a0999d49d7ae0b122d7", + "m_Id": 3, + "m_DisplayName": "Sampler", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Sampler", + "m_StageCapability": 3, + "m_BareResource": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "4f41777719d14f3b9cfa4922dfd1494f", + "m_Id": 7, + "m_DisplayName": "A", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "A", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [], + "m_LiteralMode": false +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.Rendering.Universal.ShaderGraph.UniversalTarget", + "m_ObjectId": "579c7870d0c842e08e5fd6fbb9ceed39", + "m_Datas": [], + "m_ActiveSubTarget": { + "m_Id": "5e4acd61ba9849118ee0367c76c7e2ce" + }, + "m_AllowMaterialOverride": false, + "m_SurfaceType": 0, + "m_ZTestMode": 4, + "m_ZWriteControl": 0, + "m_AlphaMode": 0, + "m_RenderFace": 2, + "m_AlphaClip": false, + "m_CastShadows": true, + "m_ReceiveShadows": true, + "m_DisableTint": false, + "m_Sort3DAs2DCompatible": false, + "m_AdditionalMotionVectorMode": 0, + "m_AlembicMotionVectors": false, + "m_SupportsLODCrossFade": false, + "m_CustomEditorGUI": "", + "m_SupportVFX": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "5d6ceca8af0d43e3b879322c2a0584ee", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Tangent", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "9954d90c90164d6f9d5119035be9fcb9" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Tangent" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.Rendering.Universal.ShaderGraph.UniversalSpriteLitSubTarget", + "m_ObjectId": "5e4acd61ba9849118ee0367c76c7e2ce" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SampleTexture2DNode", + "m_ObjectId": "5e8ea239b3154b16a8d688a481ad4d4f", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Sample Texture 2D", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -451.0, + "y": 373.0, + "width": 207.99998474121095, + "height": 433.00006103515627 + } + }, + "m_Slots": [ + { + "m_Id": "be17cd2e181b43cab80526cc8d539d6e" + }, + { + "m_Id": "0bbc7c2f9e8942d8b727746b3e5876e5" + }, + { + "m_Id": "26d7cc7afd16455fad82b24619c2764a" + }, + { + "m_Id": "b94c9c40108b4d1e8afe38e1fe521430" + }, + { + "m_Id": "f78731e30b73424b858be8203db56ac4" + }, + { + "m_Id": "972d64b95569436fa7c800575c83e15f" + }, + { + "m_Id": "00cfa14ec3254a0e95ef789efd89941c" + }, + { + "m_Id": "1d570de16eed4abd8b51b3a899f20684" + } + ], + "synonyms": [ + "tex2d" + ], + "m_Precision": 0, + "m_PreviewExpanded": false, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_TextureType": 1, + "m_NormalMapSpace": 0, + "m_EnableGlobalMipBias": true, + "m_MipSamplingMode": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "6d32ab1b2adc4edb9502ffac2e5a8b08", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -659.0, + "y": 71.0, + "width": 127.0, + "height": 34.0 + } + }, + "m_Slots": [ + { + "m_Id": "31daaf37794f40d08bb33ffa152ed984" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "31b4b452a3354da0b678a0720ced1d9e" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot", + "m_ObjectId": "6edf48bfe9284ba6b86d424a024e3c83", + "m_Id": 0, + "m_DisplayName": "Base Color", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "BaseColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.5, + "y": 0.5, + "z": 0.5 + }, + "m_DefaultValue": { + "x": 0.5, + "y": 0.5, + "z": 0.5 + }, + "m_Labels": [], + "m_ColorMode": 0, + "m_DefaultColor": { + "r": 0.5, + "g": 0.5, + "b": 0.5, + "a": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.CategoryData", + "m_ObjectId": "723a0f4478534bde9e762e8c0d59ab52", + "m_Name": "", + "m_ChildObjectList": [ + { + "m_Id": "31b4b452a3354da0b678a0720ced1d9e" + }, + { + "m_Id": "0755bf70e97540488b2a795beb57be87" + } + ] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DInputMaterialSlot", + "m_ObjectId": "7c05e0a9f04940c48385e1e3f4946007", + "m_Id": 1, + "m_DisplayName": "Texture", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Texture", + "m_StageCapability": 3, + "m_BareResource": false, + "m_Texture": { + "m_SerializedTexture": "", + "m_Guid": "" + }, + "m_DefaultType": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "86dc3df31103449ab4af8c29e1d49eb6", + "m_Id": 5, + "m_DisplayName": "G", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "G", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [], + "m_LiteralMode": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DInputMaterialSlot", + "m_ObjectId": "972d64b95569436fa7c800575c83e15f", + "m_Id": 1, + "m_DisplayName": "Texture", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Texture", + "m_StageCapability": 3, + "m_BareResource": false, + "m_Texture": { + "m_SerializedTexture": "", + "m_Guid": "" + }, + "m_DefaultType": 3 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "98d5d919f459462eb9bc59c8823575ad", + "m_Id": 6, + "m_DisplayName": "B", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "B", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [], + "m_LiteralMode": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.TangentMaterialSlot", + "m_ObjectId": "9954d90c90164d6f9d5119035be9fcb9", + "m_Id": 0, + "m_DisplayName": "Tangent", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "Tangent", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "b94c9c40108b4d1e8afe38e1fe521430", + "m_Id": 6, + "m_DisplayName": "B", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "B", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [], + "m_LiteralMode": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "be17cd2e181b43cab80526cc8d539d6e", + "m_Id": 0, + "m_DisplayName": "RGBA", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "RGBA", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBAMaterialSlot", + "m_ObjectId": "ce468a8661384b5b8cdeb773fe46f3e0", + "m_Id": 0, + "m_DisplayName": "Sprite Mask", + "m_SlotType": 0, + "m_Hidden": false, + "m_ShaderOutputName": "SpriteMask", + "m_StageCapability": 2, + "m_Value": { + "x": 1.0, + "y": 1.0, + "z": 1.0, + "w": 1.0 + }, + "m_DefaultValue": { + "x": 1.0, + "y": 1.0, + "z": 1.0, + "w": 1.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Texture2DMaterialSlot", + "m_ObjectId": "d6c012bd4311471696eea58d794276ec", + "m_Id": 0, + "m_DisplayName": "NormalMap", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "Out", + "m_StageCapability": 3, + "m_BareResource": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "d83c2ccdc3694a71810d18c2e3b78385", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.SpriteMask", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "ce468a8661384b5b8cdeb773fe46f3e0" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.SpriteMask" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.SampleTexture2DNode", + "m_ObjectId": "d9af055288d1461d92f6330305bf50ee", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Sample Texture 2D", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -470.0, + "y": 83.0, + "width": 208.0, + "height": 433.0 + } + }, + "m_Slots": [ + { + "m_Id": "fd59ece0eb124b21ae398577dd0fda05" + }, + { + "m_Id": "e776cae96d8b4f93902c8965b9780d5c" + }, + { + "m_Id": "86dc3df31103449ab4af8c29e1d49eb6" + }, + { + "m_Id": "98d5d919f459462eb9bc59c8823575ad" + }, + { + "m_Id": "4f41777719d14f3b9cfa4922dfd1494f" + }, + { + "m_Id": "7c05e0a9f04940c48385e1e3f4946007" + }, + { + "m_Id": "081abc247df543c898d83950be03d2d6" + }, + { + "m_Id": "3f7d582ae2084a0999d49d7ae0b122d7" + } + ], + "synonyms": [ + "tex2d" + ], + "m_Precision": 0, + "m_PreviewExpanded": false, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_TextureType": 0, + "m_NormalMapSpace": 0, + "m_EnableGlobalMipBias": true, + "m_MipSamplingMode": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "e776cae96d8b4f93902c8965b9780d5c", + "m_Id": 4, + "m_DisplayName": "R", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "R", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [], + "m_LiteralMode": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PropertyNode", + "m_ObjectId": "e8ae4105a3954825991ec11bf4cadfe3", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Property", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -644.0, + "y": 378.0000305175781, + "width": 144.0, + "height": 33.999969482421878 + } + }, + "m_Slots": [ + { + "m_Id": "d6c012bd4311471696eea58d794276ec" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_Property": { + "m_Id": "0755bf70e97540488b2a795beb57be87" + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "f5940013eb90412eb8cf7c6a498139d8", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Normal", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "378feb07efd44359a2e175febf48ddd6" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Normal" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "f78731e30b73424b858be8203db56ac4", + "m_Id": 7, + "m_DisplayName": "A", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "A", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [], + "m_LiteralMode": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "f9ae43f35dcf4825a0cf87c8e9059929", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.NormalTS", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "10d2cb876bfc4f6dba9b60411a027a9b" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.NormalTS" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot", + "m_ObjectId": "fd59ece0eb124b21ae398577dd0fda05", + "m_Id": 0, + "m_DisplayName": "RGBA", + "m_SlotType": 1, + "m_Hidden": false, + "m_ShaderOutputName": "RGBA", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "feecc8e9555240c595e65a546b8a0800", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Position", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "2920c8f1f1fd4d329be139c96269964f" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Position" +} + diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSprite_Shadergraph.shadergraph.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSprite_Shadergraph.shadergraph.meta new file mode 100644 index 00000000000..6290599989f --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSprite_Shadergraph.shadergraph.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 95c87530794c26d438c683b1dbd7c05c +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3} + useAsTemplate: 0 + exposeTemplateAsShader: 0 + template: + name: + category: + description: + icon: {instanceID: 0} + thumbnail: {instanceID: 0} diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSprite_Shadergraph_Material.mat b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSprite_Shadergraph_Material.mat new file mode 100644 index 00000000000..e1a47092f28 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSprite_Shadergraph_Material.mat @@ -0,0 +1,65 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-7105236373623228706 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion + version: 10 +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: RenderSprite_Shadergraph_Material + m_Shader: {fileID: -6465566751694194690, guid: 95c87530794c26d438c683b1dbd7c05c, + type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 1 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _NormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: [] + m_Colors: + - White: {r: 1, g: 1, b: 1, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSprite_Shadergraph_Material.mat.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSprite_Shadergraph_Material.mat.meta new file mode 100644 index 00000000000..b323b8fcb50 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite/RenderSprite_Shadergraph_Material.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4da613ca97d323a4da07bb58873d2ee5 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite_DrawDynamic.unity b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite_DrawDynamic.unity new file mode 100644 index 00000000000..650a0b0a31c --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite_DrawDynamic.unity @@ -0,0 +1,600 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 10 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 2 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 1 + m_PVRFilteringGaussRadiusAO: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &552063972 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 552063974} + - component: {fileID: 552063973} + m_Layer: 0 + m_Name: RenderSpriteInstancedDrawer Shadergraph + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &552063973 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 552063972} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 17b893b44cf284b409275a57996e9e60, type: 3} + m_Name: + m_EditorClassIdentifier: Universal2DGraphicsTests::RenderParamsInstancedDrawer + drawSprite: {fileID: 21300000, guid: 803bd3331724e514cbb16c45ce27b1c5, type: 3} + drawMaterial: {fileID: 2100000, guid: 4da613ca97d323a4da07bb58873d2ee5, type: 2} + gridCount: 3 + offset: 3 + useInstancing: 1 + maskInteraction: 0 +--- !u!4 &552063974 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 552063972} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 2.2, y: -2, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1034731507 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1034731510} + - component: {fileID: 1034731509} + - component: {fileID: 1034731508} + - component: {fileID: 1034731511} + - component: {fileID: 1034731512} + - component: {fileID: 1034731513} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1034731508 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1034731507} + m_Enabled: 1 +--- !u!20 &1034731509 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1034731507} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 1} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 1 + orthographic size: 9 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1034731510 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1034731507} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1034731511 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1034731507} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalCameraData + m_RenderShadows: 1 + m_RequiresDepthTextureOption: 2 + m_RequiresOpaqueTextureOption: 2 + m_CameraType: 0 + m_Cameras: [] + m_RendererIndex: -1 + m_VolumeLayerMask: + serializedVersion: 2 + m_Bits: 1 + m_VolumeTrigger: {fileID: 0} + m_VolumeFrameworkUpdateModeOption: 2 + m_RenderPostProcessing: 0 + m_Antialiasing: 0 + m_AntialiasingQuality: 2 + m_StopNaN: 0 + m_Dithering: 0 + m_ClearDepth: 1 + m_AllowXRRendering: 1 + m_AllowHDROutput: 1 + m_UseScreenCoordOverride: 0 + m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0} + m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0} + m_RequiresDepthTexture: 0 + m_RequiresColorTexture: 0 + m_TaaSettings: + m_Quality: 3 + m_FrameInfluence: 0.1 + m_JitterScale: 1 + m_MipBias: 0 + m_VarianceClampScale: 0.9 + m_ContrastAdaptiveSharpening: 0 + m_Version: 2 +--- !u!114 &1034731512 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1034731507} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8c967615a7994bc49a3a77f079e6a859, type: 3} + m_Name: + m_EditorClassIdentifier: Universal2DGraphicsTests::DisableSRPBatching +--- !u!114 &1034731513 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1034731507} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 73231aa468d81ea49bc3d914080de185, type: 3} + m_Name: + m_EditorClassIdentifier: UniversalGraphicsTests::UniversalGraphicsTestSettings + ImageComparisonSettings: + TargetWidth: 512 + TargetHeight: 512 + TargetMSAASamples: 1 + PerPixelCorrectnessThreshold: 0.001 + PerPixelGammaThreshold: 0.003921569 + PerPixelAlphaThreshold: 0.003921569 + RMSEThreshold: 0 + AverageCorrectnessThreshold: 0.005 + IncorrectPixelsThreshold: 0.0000038146973 + UseHDR: 0 + UseBackBuffer: 0 + ImageResolution: 0 + ActiveImageTests: 1 + ActivePixelTests: 7 + WaitFrames: 0 + XRCompatible: 0 + gpuDrivenCompatible: 0 + CheckMemoryAllocation: 1 + renderBackendCompatibility: 2 + SetBackBufferResolution: 0 +--- !u!1 &1218736712 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1218736714} + - component: {fileID: 1218736713} + m_Layer: 0 + m_Name: RenderSpriteInstancedDrawer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1218736713 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1218736712} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 17b893b44cf284b409275a57996e9e60, type: 3} + m_Name: + m_EditorClassIdentifier: Universal2DGraphicsTests::RenderParamsInstancedDrawer + drawSprite: {fileID: 21300000, guid: 803bd3331724e514cbb16c45ce27b1c5, type: 3} + drawMaterial: {fileID: 2100000, guid: 3f5575fc185028542a3f30b3b4b1911a, type: 2} + gridCount: 3 + offset: 3 + useInstancing: 1 + maskInteraction: 0 +--- !u!4 &1218736714 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1218736712} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 2.2, y: 2, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1481681362 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1481681364} + - component: {fileID: 1481681363} + m_Layer: 0 + m_Name: RenderSpriteDrawer Shadergraph + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1481681363 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1481681362} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 17b893b44cf284b409275a57996e9e60, type: 3} + m_Name: + m_EditorClassIdentifier: Universal2DGraphicsTests::RenderParamsInstancedDrawer + drawSprite: {fileID: -6091329584399971573, guid: 734039631e6f77248b04a79e9dded059, + type: 3} + drawMaterial: {fileID: 2100000, guid: 4da613ca97d323a4da07bb58873d2ee5, type: 2} + gridCount: 3 + offset: 3 + useInstancing: 0 + maskInteraction: 0 +--- !u!4 &1481681364 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1481681362} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -2.2, y: -2, z: 0} + m_LocalScale: {x: 0.4, y: 0.4, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1655946128 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1655946130} + - component: {fileID: 1655946129} + m_Layer: 0 + m_Name: RenderSpriteDrawer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1655946129 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1655946128} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 17b893b44cf284b409275a57996e9e60, type: 3} + m_Name: + m_EditorClassIdentifier: Universal2DGraphicsTests::RenderParamsInstancedDrawer + drawSprite: {fileID: 21300000, guid: 86ce912717672b8429c58e6960c12e25, type: 3} + drawMaterial: {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2} + gridCount: 3 + offset: 3 + useInstancing: 0 + maskInteraction: 0 +--- !u!4 &1655946130 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1655946128} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -2.2, y: 2, z: 0} + m_LocalScale: {x: 2, y: 2, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1852367347 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1852367348} + - component: {fileID: 1852367349} + m_Layer: 0 + m_Name: Spot Light 2D + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1852367348 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1852367347} + serializedVersion: 2 + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 2, y: 2, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1852367349 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1852367347} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 073797afb82c5a1438f328866b10b3f0, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.2D.Runtime::UnityEngine.Rendering.Universal.Light2D + m_ComponentVersion: 2 + m_LightType: 3 + m_BlendStyleIndex: 0 + m_FalloffIntensity: 0.5 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 1 + m_LightVolumeIntensity: 1 + m_LightVolumeEnabled: 0 + m_ApplyToSortingLayers: eb0feddf00000000e980ef06 + m_LightCookieSprite: {fileID: 0} + m_DeprecatedPointLightCookieSprite: {fileID: 0} + m_LightOrder: 0 + m_AlphaBlendOnOverlap: 0 + m_OverlapOperation: 0 + m_NormalMapDistance: 3 + m_NormalMapQuality: 1 + m_UseNormalMap: 0 + m_ShadowsEnabled: 1 + m_ShadowIntensity: 0.75 + m_ShadowSoftness: 0.3 + m_ShadowSoftnessFalloffIntensity: 0.5 + m_ShadowVolumeIntensityEnabled: 0 + m_ShadowVolumeIntensity: 0.75 + m_LocalBounds: + m_Center: {x: 0, y: -0.00000011920929, z: 0} + m_Extent: {x: 0.9985302, y: 0.99853027, z: 0} + m_PointLightInnerAngle: 360 + m_PointLightOuterAngle: 360 + m_PointLightInnerRadius: 10 + m_PointLightOuterRadius: 12 + m_ShapeLightParametricSides: 5 + m_ShapeLightParametricAngleOffset: 0 + m_ShapeLightParametricRadius: 1 + m_ShapeLightFalloffSize: 0.5 + m_ShapeLightFalloffOffset: {x: 0, y: 0} + m_ShapePath: + - {x: -0.5, y: -0.5, z: 0} + - {x: 0.5, y: -0.5, z: 0} + - {x: 0.5, y: 0.5, z: 0} + - {x: -0.5, y: 0.5, z: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 1034731510} + - {fileID: 1852367348} + - {fileID: 1655946130} + - {fileID: 1218736714} + - {fileID: 1481681364} + - {fileID: 552063974} diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite_DrawDynamic.unity.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite_DrawDynamic.unity.meta new file mode 100644 index 00000000000..f333563f3d3 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite_DrawDynamic.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9311c67be8fad8b4b89aee01d6e06141 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite_SpriteMask.unity b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite_SpriteMask.unity new file mode 100644 index 00000000000..25b95bf1e55 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite_SpriteMask.unity @@ -0,0 +1,680 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 10 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 2 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 1 + m_PVRFilteringGaussRadiusAO: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &552063972 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 552063974} + - component: {fileID: 552063973} + m_Layer: 0 + m_Name: RenderSpriteInstancedDrawer Shadergraph + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &552063973 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 552063972} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 17b893b44cf284b409275a57996e9e60, type: 3} + m_Name: + m_EditorClassIdentifier: Universal2DGraphicsTests::RenderParamsInstancedDrawer + drawSprite: {fileID: 21300000, guid: 803bd3331724e514cbb16c45ce27b1c5, type: 3} + drawMaterial: {fileID: 2100000, guid: 4da613ca97d323a4da07bb58873d2ee5, type: 2} + gridCount: 3 + offset: 3 + useInstancing: 1 + maskInteraction: 2 +--- !u!4 &552063974 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 552063972} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 2.2, y: -2, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1034731507 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1034731510} + - component: {fileID: 1034731509} + - component: {fileID: 1034731508} + - component: {fileID: 1034731511} + - component: {fileID: 1034731512} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1034731508 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1034731507} + m_Enabled: 1 +--- !u!20 &1034731509 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1034731507} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 1} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 1 + orthographic size: 9 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1034731510 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1034731507} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1034731511 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1034731507} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalCameraData + m_RenderShadows: 1 + m_RequiresDepthTextureOption: 2 + m_RequiresOpaqueTextureOption: 2 + m_CameraType: 0 + m_Cameras: [] + m_RendererIndex: -1 + m_VolumeLayerMask: + serializedVersion: 2 + m_Bits: 1 + m_VolumeTrigger: {fileID: 0} + m_VolumeFrameworkUpdateModeOption: 2 + m_RenderPostProcessing: 0 + m_Antialiasing: 0 + m_AntialiasingQuality: 2 + m_StopNaN: 0 + m_Dithering: 0 + m_ClearDepth: 1 + m_AllowXRRendering: 1 + m_AllowHDROutput: 1 + m_UseScreenCoordOverride: 0 + m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0} + m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0} + m_RequiresDepthTexture: 0 + m_RequiresColorTexture: 0 + m_TaaSettings: + m_Quality: 3 + m_FrameInfluence: 0.1 + m_JitterScale: 1 + m_MipBias: 0 + m_VarianceClampScale: 0.9 + m_ContrastAdaptiveSharpening: 0 + m_Version: 2 +--- !u!114 &1034731512 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1034731507} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 73231aa468d81ea49bc3d914080de185, type: 3} + m_Name: + m_EditorClassIdentifier: UniversalGraphicsTests::UniversalGraphicsTestSettings + ImageComparisonSettings: + TargetWidth: 512 + TargetHeight: 512 + TargetMSAASamples: 1 + PerPixelCorrectnessThreshold: 0.001 + PerPixelGammaThreshold: 0.003921569 + PerPixelAlphaThreshold: 0.003921569 + RMSEThreshold: 0 + AverageCorrectnessThreshold: 0.005 + IncorrectPixelsThreshold: 0.0000038146973 + UseHDR: 0 + UseBackBuffer: 0 + ImageResolution: 0 + ActiveImageTests: 1 + ActivePixelTests: 7 + WaitFrames: 0 + XRCompatible: 0 + gpuDrivenCompatible: 0 + CheckMemoryAllocation: 1 + renderBackendCompatibility: 2 + SetBackBufferResolution: 0 +--- !u!1 &1129056342 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1129056344} + - component: {fileID: 1129056343} + m_Layer: 0 + m_Name: Sprite Mask + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!331 &1129056343 +SpriteMask: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1129056342} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 0 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 15d0c3709176029428a0da2f8cecf0b5, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_MaskInteraction: 0 + m_Sprite: {fileID: 8177471321811730583, guid: 87aaca0a643d54397ba969dab4fc8875, + type: 3} + m_MaskAlphaCutoff: 0.2 + m_FrontSortingLayerID: 0 + m_BackSortingLayerID: 0 + m_FrontSortingLayer: 0 + m_BackSortingLayer: 0 + m_FrontSortingOrder: 0 + m_BackSortingOrder: 0 + m_IsCustomRangeActive: 0 + m_SpriteSortPoint: 0 + m_MaskSource: 0 +--- !u!4 &1129056344 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1129056342} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 15, y: 15, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1218736712 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1218736714} + - component: {fileID: 1218736713} + m_Layer: 0 + m_Name: RenderSpriteInstancedDrawer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1218736713 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1218736712} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 17b893b44cf284b409275a57996e9e60, type: 3} + m_Name: + m_EditorClassIdentifier: Universal2DGraphicsTests::RenderParamsInstancedDrawer + drawSprite: {fileID: 21300000, guid: 803bd3331724e514cbb16c45ce27b1c5, type: 3} + drawMaterial: {fileID: 2100000, guid: 3f5575fc185028542a3f30b3b4b1911a, type: 2} + gridCount: 3 + offset: 3 + useInstancing: 1 + maskInteraction: 2 +--- !u!4 &1218736714 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1218736712} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 2.2, y: 2, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1481681362 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1481681364} + - component: {fileID: 1481681363} + m_Layer: 0 + m_Name: RenderSpriteDrawer Shadergraph + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1481681363 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1481681362} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 17b893b44cf284b409275a57996e9e60, type: 3} + m_Name: + m_EditorClassIdentifier: Universal2DGraphicsTests::RenderParamsInstancedDrawer + drawSprite: {fileID: -6091329584399971573, guid: 734039631e6f77248b04a79e9dded059, + type: 3} + drawMaterial: {fileID: 2100000, guid: 4da613ca97d323a4da07bb58873d2ee5, type: 2} + gridCount: 3 + offset: 3 + useInstancing: 0 + maskInteraction: 2 +--- !u!4 &1481681364 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1481681362} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -2.2, y: -2, z: 0} + m_LocalScale: {x: 0.4, y: 0.4, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1655946128 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1655946130} + - component: {fileID: 1655946129} + m_Layer: 0 + m_Name: RenderSpriteDrawer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1655946129 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1655946128} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 17b893b44cf284b409275a57996e9e60, type: 3} + m_Name: + m_EditorClassIdentifier: Universal2DGraphicsTests::RenderParamsInstancedDrawer + drawSprite: {fileID: 21300000, guid: 86ce912717672b8429c58e6960c12e25, type: 3} + drawMaterial: {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2} + gridCount: 3 + offset: 3 + useInstancing: 0 + maskInteraction: 2 +--- !u!4 &1655946130 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1655946128} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -2.2, y: 2, z: 0} + m_LocalScale: {x: 2, y: 2, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1852367347 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1852367348} + - component: {fileID: 1852367349} + m_Layer: 0 + m_Name: Spot Light 2D + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1852367348 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1852367347} + serializedVersion: 2 + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 2, y: 2, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1852367349 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1852367347} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 073797afb82c5a1438f328866b10b3f0, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.2D.Runtime::UnityEngine.Rendering.Universal.Light2D + m_ComponentVersion: 2 + m_LightType: 3 + m_BlendStyleIndex: 0 + m_FalloffIntensity: 0.5 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 1 + m_LightVolumeIntensity: 1 + m_LightVolumeEnabled: 0 + m_ApplyToSortingLayers: eb0feddf00000000e980ef06 + m_LightCookieSprite: {fileID: 0} + m_DeprecatedPointLightCookieSprite: {fileID: 0} + m_LightOrder: 0 + m_AlphaBlendOnOverlap: 0 + m_OverlapOperation: 0 + m_NormalMapDistance: 3 + m_NormalMapQuality: 1 + m_UseNormalMap: 0 + m_ShadowsEnabled: 1 + m_ShadowIntensity: 0.75 + m_ShadowSoftness: 0.3 + m_ShadowSoftnessFalloffIntensity: 0.5 + m_ShadowVolumeIntensityEnabled: 0 + m_ShadowVolumeIntensity: 0.75 + m_LocalBounds: + m_Center: {x: 0, y: -0.00000011920929, z: 0} + m_Extent: {x: 0.9985302, y: 0.99853027, z: 0} + m_PointLightInnerAngle: 360 + m_PointLightOuterAngle: 360 + m_PointLightInnerRadius: 10 + m_PointLightOuterRadius: 12 + m_ShapeLightParametricSides: 5 + m_ShapeLightParametricAngleOffset: 0 + m_ShapeLightParametricRadius: 1 + m_ShapeLightFalloffSize: 0.5 + m_ShapeLightFalloffOffset: {x: 0, y: 0} + m_ShapePath: + - {x: -0.5, y: -0.5, z: 0} + - {x: 0.5, y: -0.5, z: 0} + - {x: 0.5, y: 0.5, z: 0} + - {x: -0.5, y: 0.5, z: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 1034731510} + - {fileID: 1852367348} + - {fileID: 1655946130} + - {fileID: 1218736714} + - {fileID: 1481681364} + - {fileID: 552063974} + - {fileID: 1129056344} diff --git a/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite_SpriteMask.unity.meta b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite_SpriteMask.unity.meta new file mode 100644 index 00000000000..87a7d1d6a15 --- /dev/null +++ b/Tests/SRPTests/Projects/UniversalGraphicsTest_2D/Assets/Scenes/032_RenderSprite_SpriteMask.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0acd9f4dc21cc474c9a2063c3113dee9 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 7f90955ac960c6aadb2279b68e7ef928aefae332 Mon Sep 17 00:00:00 2001 From: Steen Lund Date: Fri, 13 Feb 2026 09:48:09 +0000 Subject: [PATCH 08/92] Serialization/roslyn analyze serializable --- .../Tools/Converter/ConverterItemState.cs | 1 + .../Editor-PrivateShared/Tools/Converter/ConverterState.cs | 2 +- .../com.unity.render-pipelines.core/Editor/FilterWindow.cs | 1 + .../Editor/RenderGraph/RenderGraphTestsCore.cs | 2 +- .../Runtime/Volume/VolumeParameter.cs | 1 + .../Editor/AssetProcessors/HDIESImporterEditor.cs | 2 +- .../Editor/Lighting/HDLightEditor.cs | 2 +- .../Runtime/Compositor/CompositionLayer.cs | 4 ++-- .../Runtime/Debug/DebugDisplay.cs | 4 ++-- .../RenderPipeline/LineRendering/Core/LineRendering.Data.cs | 4 ++-- .../Runtime/2D/Shadows/ShadowProvider/ShadowShape2D.cs | 1 + .../com.unity.shaderanalysis/Editor/API/ShaderBuildReport.cs | 1 - .../Editor/Data/Graphs/SerializableVirtualTexture.cs | 1 - .../Editor/Data/Graphs/ShaderGraphRequirements.cs | 2 +- .../com.unity.shadergraph/Editor/Data/Graphs/ShaderInput.cs | 1 + .../Editor/Models/Contexts/Implementations/VFXBasicUpdate.cs | 3 ++- .../Editor/Utilities/EventTester/VFXEventTesterWindow.cs | 4 ---- .../Runtime/Utilities/EventBinding/VFXEventBinderBase.cs | 1 - .../Assets/AllTests/Editor/Tests/VFXAttributeTests.cs | 2 +- 19 files changed, 19 insertions(+), 20 deletions(-) diff --git a/Packages/com.unity.render-pipelines.core/Editor-PrivateShared/Tools/Converter/ConverterItemState.cs b/Packages/com.unity.render-pipelines.core/Editor-PrivateShared/Tools/Converter/ConverterItemState.cs index 20ccab79b56..dcd5e8b30a9 100644 --- a/Packages/com.unity.render-pipelines.core/Editor-PrivateShared/Tools/Converter/ConverterItemState.cs +++ b/Packages/com.unity.render-pipelines.core/Editor-PrivateShared/Tools/Converter/ConverterItemState.cs @@ -22,6 +22,7 @@ public bool isSelected } } public IRenderPipelineConverterItem item; + [NonSerialized] public (Status Status, string Message) conversionResult = (Status.Pending, string.Empty); internal bool hasConverted => conversionResult.Status != Status.Pending; diff --git a/Packages/com.unity.render-pipelines.core/Editor-PrivateShared/Tools/Converter/ConverterState.cs b/Packages/com.unity.render-pipelines.core/Editor-PrivateShared/Tools/Converter/ConverterState.cs index ef31c5175ae..baa1a17c9c4 100644 --- a/Packages/com.unity.render-pipelines.core/Editor-PrivateShared/Tools/Converter/ConverterState.cs +++ b/Packages/com.unity.render-pipelines.core/Editor-PrivateShared/Tools/Converter/ConverterState.cs @@ -31,7 +31,7 @@ class ConverterState public IRenderPipelineConverter converter; public DisplayFilter currentFilter = DisplayFilter.All; - public IList> filteredItems = new List>(); + public IList> filteredItems {get; private set; } = new List>(); private int CountItemWithFlag(Status status) { diff --git a/Packages/com.unity.render-pipelines.core/Editor/FilterWindow.cs b/Packages/com.unity.render-pipelines.core/Editor/FilterWindow.cs index 7264c443c39..4c63caa3fc8 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/FilterWindow.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/FilterWindow.cs @@ -53,6 +53,7 @@ public interface IProvider /// An element from the filtered list or tree. /// /// + [Serializable] public class Element : IComparable { ///

diff --git a/Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphTestsCore.cs b/Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphTestsCore.cs index 67b9c6cf544..1314ca0e791 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphTestsCore.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphTestsCore.cs @@ -35,7 +35,7 @@ internal class RenderGraphTestPipelineAsset : RenderPipelineAsset recordRenderGraphBody; - public RenderGraph renderGraph; + public RenderGraph renderGraph { get; private set; } public RenderTextureUVOriginStrategy renderTextureUVOriginStrategy; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeParameter.cs b/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeParameter.cs index 51a2e0110ab..b67e674c5b7 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeParameter.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeParameter.cs @@ -27,6 +27,7 @@ namespace UnityEngine.Rendering /// /// /// + [Serializable] public abstract class VolumeParameter : ICloneable { #if UNITY_EDITOR || DEVELOPMENT_BUILD diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporterEditor.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporterEditor.cs index ad63777a84e..70c3261f4c4 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporterEditor.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporterEditor.cs @@ -16,7 +16,7 @@ public partial class HDIESImporterEditor : ScriptedImporterEditor /// /// IES Importer Editor, common to Core and HDRP /// - public UnityEditor.Rendering.IESImporterEditor iesImporterEditor = new UnityEditor.Rendering.IESImporterEditor(); + public UnityEditor.Rendering.IESImporterEditor iesImporterEditor { get; set; } = new UnityEditor.Rendering.IESImporterEditor(); internal void SetupRenderPipelinePreviewCamera(Camera camera) { diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightEditor.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightEditor.cs index 517a2e41035..b6e901ee890 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightEditor.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightEditor.cs @@ -13,7 +13,7 @@ namespace UnityEditor.Rendering.HighDefinition [SupportedOnRenderPipeline(typeof(HDRenderPipelineAsset))] sealed partial class HDLightEditor : LightEditor { - public SerializedHDLight m_SerializedHDLight; + public SerializedHDLight m_SerializedHDLight { get; set; } HDAdditionalLightData[] m_AdditionalLightDatas; 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 5e2e61e2809..156a1dd7d87 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 @@ -86,7 +86,7 @@ public enum ResolutionScale // AOVs [SerializeField] MaterialSharedProperty m_AOVBitmask = 0; - [SerializeField] Dictionary m_AOVMap; + Dictionary m_AOVMap; List m_AOVHandles; @@ -96,7 +96,7 @@ public enum ResolutionScale [SerializeField] RenderTexture m_RenderTarget; - [SerializeField] RTHandle m_AOVTmpRTHandle; + RTHandle m_AOVTmpRTHandle; public bool clearsBackGround { 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 b1442f1052a..b93f9e8f5b9 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 @@ -329,7 +329,7 @@ public partial class DebugData public DecalsDebugSettings decalsDebugSettings; /// Current transparency debug settings. - public TransparencyDebugSettings transparencyDebugSettings = new TransparencyDebugSettings(); + public TransparencyDebugSettings transparencyDebugSettings { get; set; }= new TransparencyDebugSettings(); /// Index of screen space shadow to display. public uint screenSpaceShadowIndex = 0; /// Max quad cost for quad overdraw display. @@ -2114,7 +2114,7 @@ void UnregisterRenderingDebug() internal void RegisterDebug() { InitializeDebugEnums(); - + RegisterMaterialDebug(); RegisterLightingDebug(); RegisterRenderingDebug(); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/LineRendering/Core/LineRendering.Data.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/LineRendering/Core/LineRendering.Data.cs index 0342391c6d0..c8787570393 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/LineRendering/Core/LineRendering.Data.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/LineRendering/Core/LineRendering.Data.cs @@ -103,7 +103,7 @@ public struct RendererData /// Offscreen shading pass index. public int offscreenShadingPass; /// Handle to the line topology's index buffer resource. - public BufferHandle indexBuffer; + public BufferHandle indexBuffer { get; set; } /// Distance to camera for sorting purposes. public float distanceToCamera; /// The number of lines in the mesh. @@ -111,7 +111,7 @@ public struct RendererData /// The number of segments-per-line. public int segmentsPerLine; /// Handle to a buffer for computing level of detail. - public BufferHandle lodBuffer; + public BufferHandle lodBuffer { get; set; } /// Level of detail mode. public RendererLODMode lodMode; /// Percentage of strands to render. diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowProvider/ShadowShape2D.cs b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowProvider/ShadowShape2D.cs index 80396a410cf..acd18889cc0 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowProvider/ShadowShape2D.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/2D/Shadows/ShadowProvider/ShadowShape2D.cs @@ -8,6 +8,7 @@ namespace UnityEngine.Rendering.Universal /// /// Class ShadowShape2D stores outline geometry for use with a shadow caster. /// + [Serializable] public abstract class ShadowShape2D { /// diff --git a/Packages/com.unity.shaderanalysis/Editor/API/ShaderBuildReport.cs b/Packages/com.unity.shaderanalysis/Editor/API/ShaderBuildReport.cs index b94c61cd6bb..53866fdb5f4 100644 --- a/Packages/com.unity.shaderanalysis/Editor/API/ShaderBuildReport.cs +++ b/Packages/com.unity.shaderanalysis/Editor/API/ShaderBuildReport.cs @@ -315,7 +315,6 @@ public static ProgramPerformanceMetrics Diff(ProgramPerformanceMetrics l, Progra [SerializeField] List m_PerformanceUnit = new List(); - [SerializeField] Dictionary m_SkippedPasses = new Dictionary(); Dictionary> m_ProgramCompileUnits = new Dictionary>(); diff --git a/Packages/com.unity.shadergraph/Editor/Data/Graphs/SerializableVirtualTexture.cs b/Packages/com.unity.shadergraph/Editor/Data/Graphs/SerializableVirtualTexture.cs index 5fa9638e0d4..272ed482874 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Graphs/SerializableVirtualTexture.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Graphs/SerializableVirtualTexture.cs @@ -18,7 +18,6 @@ internal class SerializableVirtualTextureLayer public string layerRefName; public SerializableTexture layerTexture; public LayerTextureType layerTextureType; - [SerializeField] private Guid guid; public SerializableVirtualTextureLayer(string name, string refName, SerializableTexture texture) diff --git a/Packages/com.unity.shadergraph/Editor/Data/Graphs/ShaderGraphRequirements.cs b/Packages/com.unity.shadergraph/Editor/Data/Graphs/ShaderGraphRequirements.cs index b9ef355121d..2bb1efa905b 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Graphs/ShaderGraphRequirements.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Graphs/ShaderGraphRequirements.cs @@ -8,7 +8,7 @@ namespace UnityEditor.ShaderGraph.Internal [Serializable] public struct ShaderGraphRequirements { - [SerializeField] List m_RequiresTransforms; + List m_RequiresTransforms; [SerializeField] NeededCoordinateSpace m_RequiresNormal; [SerializeField] NeededCoordinateSpace m_RequiresBitangent; [SerializeField] NeededCoordinateSpace m_RequiresTangent; diff --git a/Packages/com.unity.shadergraph/Editor/Data/Graphs/ShaderInput.cs b/Packages/com.unity.shadergraph/Editor/Data/Graphs/ShaderInput.cs index 943815a1cc0..affbc22ee40 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Graphs/ShaderInput.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Graphs/ShaderInput.cs @@ -8,6 +8,7 @@ namespace UnityEditor.ShaderGraph.Internal { + [Serializable] public abstract class ShaderInput : JsonObject { [SerializeField] diff --git a/Packages/com.unity.visualeffectgraph/Editor/Models/Contexts/Implementations/VFXBasicUpdate.cs b/Packages/com.unity.visualeffectgraph/Editor/Models/Contexts/Implementations/VFXBasicUpdate.cs index 80812b460ef..e7b9702dbfa 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/Models/Contexts/Implementations/VFXBasicUpdate.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/Models/Contexts/Implementations/VFXBasicUpdate.cs @@ -274,7 +274,8 @@ public override IEnumerable additionalMappings } } - public IEnumerable rayTracingDefines = null; + public IEnumerable rayTracingDefines { get; set; } = null; + public override IEnumerable additionalDefines { get diff --git a/Packages/com.unity.visualeffectgraph/Editor/Utilities/EventTester/VFXEventTesterWindow.cs b/Packages/com.unity.visualeffectgraph/Editor/Utilities/EventTester/VFXEventTesterWindow.cs index 2f548b0c9d5..9b73f6b71de 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/Utilities/EventTester/VFXEventTesterWindow.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/Utilities/EventTester/VFXEventTesterWindow.cs @@ -53,9 +53,7 @@ private void OnSelectionChanged() static bool s_Visible; - [SerializeField] static string m_CustomEvent = "CustomEvent"; - [SerializeField] static List m_Attributes; static VisualEffect[] m_Effects; @@ -145,7 +143,6 @@ static void AddColor(object name) m_Attributes.Add(new EventAttribute(name as string, EventAttributeType.Color, Color.white)); } - [System.Serializable] enum EventAttributeType { Float = 0, @@ -155,7 +152,6 @@ enum EventAttributeType Bool = 4 } - [System.Serializable] class EventAttribute { public string name; diff --git a/Packages/com.unity.visualeffectgraph/Runtime/Utilities/EventBinding/VFXEventBinderBase.cs b/Packages/com.unity.visualeffectgraph/Runtime/Utilities/EventBinding/VFXEventBinderBase.cs index 7b66966e914..c9af4d7e9f9 100644 --- a/Packages/com.unity.visualeffectgraph/Runtime/Utilities/EventBinding/VFXEventBinderBase.cs +++ b/Packages/com.unity.visualeffectgraph/Runtime/Utilities/EventBinding/VFXEventBinderBase.cs @@ -10,7 +10,6 @@ abstract class VFXEventBinderBase : MonoBehaviour protected VisualEffect target; public string EventName = "Event"; - [SerializeField, HideInInspector] protected VFXEventAttribute eventAttribute; protected virtual void OnEnable() diff --git a/Tests/SRPTests/Projects/VisualEffectGraph_HDRP/Assets/AllTests/Editor/Tests/VFXAttributeTests.cs b/Tests/SRPTests/Projects/VisualEffectGraph_HDRP/Assets/AllTests/Editor/Tests/VFXAttributeTests.cs index 2cb2f6bdc91..14fdaff7ee8 100644 --- a/Tests/SRPTests/Projects/VisualEffectGraph_HDRP/Assets/AllTests/Editor/Tests/VFXAttributeTests.cs +++ b/Tests/SRPTests/Projects/VisualEffectGraph_HDRP/Assets/AllTests/Editor/Tests/VFXAttributeTests.cs @@ -30,7 +30,7 @@ public override IEnumerable attributes get { return attributeInfos; } } - public List attributeInfos = new List(); + public List attributeInfos { get; } = new List(); } private class ContextTestInit : ContextTest From 34c5e9de5803c51931a18ec857091431391e1605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Carr=C3=A8re?= Date: Fri, 13 Feb 2026 13:31:45 +0000 Subject: [PATCH 09/92] docg-8422: Remove deprecated link --- .../Documentation~/getting-started-in-hdrp.md | 1 - 1 file changed, 1 deletion(-) diff --git a/Packages/com.unity.render-pipelines.high-definition/Documentation~/getting-started-in-hdrp.md b/Packages/com.unity.render-pipelines.high-definition/Documentation~/getting-started-in-hdrp.md index 036be6fb1f3..c026620fec1 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Documentation~/getting-started-in-hdrp.md +++ b/Packages/com.unity.render-pipelines.high-definition/Documentation~/getting-started-in-hdrp.md @@ -10,4 +10,3 @@ Set up a project to use the High Definition Render Pipeline (HDRP), and use Volu ## Additional resources - [HDRP overview](HDRP-Features.md) -- [Achieving High Fidelity Graphics for Games with HDRP](https://resources.unity.com/unitenow/onlinesessions/achieving-high-fidelity-graphics-for-games-with-hdrp) From c30450619ef1128c4b767dc3025e9df629be4c85 Mon Sep 17 00:00:00 2001 From: Ludovic Theobald Date: Fri, 13 Feb 2026 13:31:46 +0000 Subject: [PATCH 10/92] [VFX] Fix and reenable DistortionTest and HDRP_VolumetricOutput --- .../Assets/Tests/HDRP_VisualEffectsGraph_GraphicsTests.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Tests/SRPTests/Projects/VisualEffectGraph_HDRP/Assets/Tests/HDRP_VisualEffectsGraph_GraphicsTests.cs b/Tests/SRPTests/Projects/VisualEffectGraph_HDRP/Assets/Tests/HDRP_VisualEffectsGraph_GraphicsTests.cs index 191bb2e18e9..63246f066e9 100644 --- a/Tests/SRPTests/Projects/VisualEffectGraph_HDRP/Assets/Tests/HDRP_VisualEffectsGraph_GraphicsTests.cs +++ b/Tests/SRPTests/Projects/VisualEffectGraph_HDRP/Assets/Tests/HDRP_VisualEffectsGraph_GraphicsTests.cs @@ -30,8 +30,6 @@ public class VFXGraphicsTests [IgnoreGraphicsTest("39_SmokeLighting_APV", "Too many bindings when using APVs", runtimePlatforms: new RuntimePlatform[] { RuntimePlatform.Switch })] [IgnoreGraphicsTest("102_ShadergraphShadow", "See UUM-96202", runtimePlatforms: new RuntimePlatform[] { RuntimePlatform.Switch })] [IgnoreGraphicsTest("015_FixedTime", "See UUM-109089", runtimePlatforms: new RuntimePlatform[] { RuntimePlatform.Switch })] - [IgnoreGraphicsTest("DistortionTest", "Unstable: https://jira.unity3d.com/browse/UUM-134091")] - [IgnoreGraphicsTest("HDRP_VolumetricOutput", "Unstable: https://jira.unity3d.com/browse/UUM-134091")] [IgnoreGraphicsTest("Repro_SampleGradient_Branch_Instancing", "Compute shader ([Repro_SampleGradient_Branch_Instancing] [Minimal] Update Particles): Property (Repro_SampleGradient_Branch_Instancing_Buffer) at kernel index (0) is not set")] [IgnoreGraphicsTest("Empty", "No reference images provided")] [IgnoreGraphicsTest("Empty_With_Camera", "No reference images provided")] From 329ea693cf6288149946000e9396d8c5ac3fd558 Mon Sep 17 00:00:00 2001 From: Elvis Alistar Date: Fri, 13 Feb 2026 13:31:47 +0000 Subject: [PATCH 11/92] Disable unstable TestCPULODCrossfade test --- .../Tests/Editor/GPUDriven/GPUDrivenRenderingTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/GPUDriven/GPUDrivenRenderingTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/GPUDriven/GPUDrivenRenderingTests.cs index ce4acbc4464..8a46a30d4f7 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Editor/GPUDriven/GPUDrivenRenderingTests.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/GPUDriven/GPUDrivenRenderingTests.cs @@ -522,6 +522,7 @@ public void TestCPULODSelection() } [Test, ConditionalIgnore("IgnoreGfxAPI", "Graphics API Not Supported.")] + [Ignore("Unstable - see https://jira.unity3d.com/browse/UUM-134437")] public void TestCPULODCrossfade() { if (Coverage.enabled) @@ -672,6 +673,7 @@ public void TestCPULODCrossfade() } [Test, ConditionalIgnore("IgnoreGfxAPI", "Graphics API Not Supported.")] + [Ignore("Unstable - see https://jira.unity3d.com/browse/UUM-134437")] public void TestGpuDrivenSmallMeshCulling() { if (Coverage.enabled) From 6724a472c3ce50eceb1eb57c8b5129e485341d07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Chapelain?= Date: Fri, 13 Feb 2026 23:52:37 +0000 Subject: [PATCH 12/92] [HDRP] Fix flickering regression in volumetric clouds with alpha clipped geometry --- .../VolumetricClouds/VolumetricClouds.compute | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricClouds/VolumetricClouds.compute b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricClouds/VolumetricClouds.compute index 80b8c9e3e49..9e44c083f7c 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricClouds/VolumetricClouds.compute +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricClouds/VolumetricClouds.compute @@ -96,22 +96,41 @@ void REPROJECT_CLOUDS(uint3 dispatchThreadId : SV_DispatchThreadID, float validityFactor = 1.0; #ifdef WITH_REJECTION + + bool currentIsSky = currentSceneDepth == UNITY_RAW_FAR_CLIP_VALUE; + float4 lightingMin = float4(FLT_MAX, FLT_MAX, FLT_MAX, 1.0); float4 lightingMax = float4(0, 0, 0, 0.0); - for (int y = -1; y <= 1; ++y) + + int skySampleCount = 0; + if(currentIsSky) { - for (int x = -1; x <= 1; ++x) + for (int y = -1; y <= 1; ++y) { - CloudReprojectionData data = GetCloudReprojectionDataSample(threadCoord, int2(x, y)); - if ((data.pixelDepth == UNITY_RAW_FAR_CLIP_VALUE) == (currentSceneDepth == UNITY_RAW_FAR_CLIP_VALUE)) + for (int x = -1; x <= 1; ++x) { - lightingMin = min(lightingMin, data.cloudLighting); - lightingMax = max(lightingMax, data.cloudLighting); + CloudReprojectionData data = GetCloudReprojectionDataSample(threadCoord, int2(x, y)); + bool sampleIsSky = data.pixelDepth == UNITY_RAW_FAR_CLIP_VALUE; + + if (sampleIsSky) + { + lightingMin = min(lightingMin, data.cloudLighting); + lightingMax = max(lightingMax, data.cloudLighting); + skySampleCount++; + } } } + + // Only apply clamping if we have enough sky samples (at least 5 out of 9) + if (skySampleCount >= 5) + { + // Modulate validity factor based on sky sample ratio, the more samples are sky, the more ghosting reduction + float skyRatio = skySampleCount / 9.0; + previousColor = ClipCloudsToRegion(previousColor, lightingMin, lightingMax, skyRatio); + validityFactor *= skyRatio; + } } - previousColor = ClipCloudsToRegion(previousColor, lightingMin, lightingMax, validityFactor); #endif if (validTracing) From b1370506214376afe3617ab539a43fd9db890c3e Mon Sep 17 00:00:00 2001 From: Layla Arab Date: Fri, 13 Feb 2026 23:52:37 +0000 Subject: [PATCH 13/92] Add RP-Core and HDRP-specific selectors for LightingSearch --- .../Lighting/LightingSearchSelectors.cs | 460 ++++++++++ .../Lighting/LightingSearchSelectors.cs.meta | 3 + .../StyleSheets/LightingSearchSelectors.uss | 48 + .../LightingSearchSelectors.uss.meta | 11 + .../CoreLightingSearchSelectorsTests.cs | 349 ++++++++ .../CoreLightingSearchSelectorsTests.cs.meta | 2 + .../Lighting/HDLightingSearchSelectors.cs | 833 ++++++++++++++++++ .../HDLightingSearchSelectors.cs.meta | 3 + .../Editor/StyleSheets.meta | 8 + .../StyleSheets/HDLightingSearchSelectors.uss | 6 + .../HDLightingSearchSelectors.uss.meta | 11 + .../Editor/HDLightingSearchSelectorsTests.cs | 714 +++++++++++++++ .../HDLightingSearchSelectorsTests.cs.meta | 2 + 13 files changed, 2450 insertions(+) create mode 100644 Packages/com.unity.render-pipelines.core/Editor/Lighting/LightingSearchSelectors.cs create mode 100644 Packages/com.unity.render-pipelines.core/Editor/Lighting/LightingSearchSelectors.cs.meta create mode 100644 Packages/com.unity.render-pipelines.core/Editor/StyleSheets/LightingSearchSelectors.uss create mode 100644 Packages/com.unity.render-pipelines.core/Editor/StyleSheets/LightingSearchSelectors.uss.meta create mode 100644 Packages/com.unity.render-pipelines.core/Tests/Editor/CoreLightingSearchSelectorsTests.cs create mode 100644 Packages/com.unity.render-pipelines.core/Tests/Editor/CoreLightingSearchSelectorsTests.cs.meta create mode 100644 Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightingSearchSelectors.cs create mode 100644 Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightingSearchSelectors.cs.meta create mode 100644 Packages/com.unity.render-pipelines.high-definition/Editor/StyleSheets.meta create mode 100644 Packages/com.unity.render-pipelines.high-definition/Editor/StyleSheets/HDLightingSearchSelectors.uss create mode 100644 Packages/com.unity.render-pipelines.high-definition/Editor/StyleSheets/HDLightingSearchSelectors.uss.meta create mode 100644 Packages/com.unity.render-pipelines.high-definition/Tests/Editor/HDLightingSearchSelectorsTests.cs create mode 100644 Packages/com.unity.render-pipelines.high-definition/Tests/Editor/HDLightingSearchSelectorsTests.cs.meta diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/LightingSearchSelectors.cs b/Packages/com.unity.render-pipelines.core/Editor/Lighting/LightingSearchSelectors.cs new file mode 100644 index 00000000000..bff90e1c5fd --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/LightingSearchSelectors.cs @@ -0,0 +1,460 @@ +using System; +using UnityEditor.Search; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.UIElements; + +namespace UnityEditor.Lighting +{ + static class CoreLightingSearchSelectors + { + internal const string k_SceneProvider = "scene"; + internal const string k_BakingSetPath = "BakingSets/"; + internal const string k_VolumePath = "Volume/"; + internal const string k_LightPath = "Light/"; + internal const string k_LightShapePath = k_LightPath + "Shape"; + internal const string k_BakingModePath = k_BakingSetPath + "BakingMode"; + internal const string k_SkyOcclusionBakingSamplesPath = k_BakingSetPath + "SkyOcclusionBakingSamples"; + internal const string k_VolumeModePath = k_VolumePath + "Mode"; + internal const string k_VolumeProfilePath = k_VolumePath + "Profile"; + + const string k_StyleSheetPath = "StyleSheets/LightingSearchSelectors.uss"; + const int k_DefaultSearchSelectorPriority = 99; + const int k_MinBakingSamples = 1; + const int k_MaxBakingSamples = 8192; + static StyleSheet s_StyleSheet; + + static StyleSheet LoadStyleSheet() + { + if (s_StyleSheet == null) + { + s_StyleSheet = EditorGUIUtility.Load(k_StyleSheetPath) as StyleSheet; + } + return s_StyleSheet; + } + + [SearchSelector(k_VolumeModePath, provider: k_SceneProvider, priority: k_DefaultSearchSelectorPriority)] + static object VolumeModeSearchSelector(SearchSelectorArgs args) + { + var go = args.current.ToObject(); + if (go == null) + return null; + + return LightingSearchDataAccessors.GetVolumeMode(go); + } + + [SearchSelector(k_VolumeProfilePath, provider: k_SceneProvider, priority: k_DefaultSearchSelectorPriority)] + static object VolumeProfileSearchSelector(SearchSelectorArgs args) + { + var go = args.current.ToObject(); + if (go == null) + return null; + + return LightingSearchDataAccessors.GetVolumeProfile(go); + } + + [SearchColumnProvider(k_BakingModePath)] + public static void BakingModeSearchColumnProvider(SearchColumn column) + { + column.getter = args => + { + var bakingSet = args.item.ToObject() as ProbeVolumeBakingSet; + if (bakingSet == null) + return null; + + return LightingSearchDataAccessors.GetBakingMode(bakingSet); + }; + column.setter = args => + { + if (args.value is not string) + return; + + var bakingSet = args.item.ToObject() as ProbeVolumeBakingSet; + if (bakingSet == null) + return; + + LightingSearchDataAccessors.SetBakingMode(bakingSet, (string)args.value); + }; + column.cellCreator = _ => + { + var dropdown = new DropdownField + { + choices = new System.Collections.Generic.List { "Baking Set", "Single Scene" } + }; + return dropdown; + }; + column.binder = (args, ve) => + { + var bakingSet = args.item.ToObject() as ProbeVolumeBakingSet; + if (bakingSet == null) + { + ve.visible = false; + return; + } + + var dropdown = (DropdownField)ve; + var mode = (string)args.value; + + ve.visible = true; + dropdown.SetValueWithoutNotify(mode); + }; + } + + [SearchColumnProvider(k_SkyOcclusionBakingSamplesPath)] + public static void SkyOcclusionBakingSamplesSearchColumnProvider(SearchColumn column) + { + static int SamplesToSliderValue(int samples) + { + int value = k_MinBakingSamples; + while (value < samples && value < k_MaxBakingSamples) + { + value *= 2; + } + return value; + } + + column.getter = args => + { + var bakingSet = args.item.ToObject() as ProbeVolumeBakingSet; + if (bakingSet == null) + return null; + + return LightingSearchDataAccessors.GetSkyOcclusionBakingSamples(bakingSet); + }; + column.setter = args => + { + if (args.value is not int) + return; + + var bakingSet = args.item.ToObject() as ProbeVolumeBakingSet; + if (bakingSet == null) + return; + + int samples = (int)args.value; + int roundedSamplesValue = SamplesToSliderValue(samples); + + LightingSearchDataAccessors.SetSkyOcclusionBakingSamples(bakingSet, roundedSamplesValue); + }; + column.cellCreator = _ => + { + var container = new VisualElement(); + container.AddToClassList("core-lighting-search-baking-samples"); + + var slider = new SliderInt(k_MinBakingSamples, k_MaxBakingSamples); + slider.AddToClassList("core-lighting-search-baking-samples__slider"); + + var integerField = new IntegerField(); + integerField.AddToClassList("core-lighting-search-baking-samples__text-field"); + + container.Add(slider); + container.Add(integerField); + + var styleSheet = LoadStyleSheet(); + if (styleSheet != null) + container.styleSheets.Add(styleSheet); + + return container; + }; + column.binder = (args, ve) => + { + var bakingSet = args.item.ToObject() as ProbeVolumeBakingSet; + if (bakingSet == null) + { + ve.visible = false; + return; + } + + var samples = (int)args.value; + + ve.visible = true; + var slider = ve.Q(); + var textField = ve.Q(); + + slider.SetValueWithoutNotify(samples); + textField.SetValueWithoutNotify(samples); + }; + } + + [SearchColumnProvider(k_VolumeModePath)] + public static void VolumeModeSearchColumnProvider(SearchColumn column) + { + column.getter = args => + { + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null) + return null; + + return LightingSearchDataAccessors.GetVolumeMode(go); + }; + column.setter = args => + { + if (args.value is not string) + return; + + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null) + return; + + LightingSearchDataAccessors.SetVolumeMode(go, (string)args.value); + }; + column.cellCreator = _ => + { + var dropdown = new DropdownField + { + choices = new System.Collections.Generic.List { "Global", "Local" } + }; + return dropdown; + }; + column.binder = (args, ve) => + { + var go = args.item.ToObject(); + if (go == null || !go.TryGetComponent(out _)) + { + ve.visible = false; + return; + } + + var dropdown = (DropdownField)ve; + var mode = (string)args.value; + + ve.visible = true; + dropdown.SetValueWithoutNotify(mode); + }; + } + + [SearchColumnProvider(k_VolumeProfilePath)] + public static void VolumeProfileSearchColumnProvider(SearchColumn column) + { + column.getter = args => + { + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null) + return null; + + return LightingSearchDataAccessors.GetVolumeProfile(go); + }; + column.setter = args => + { + if (args.value is not VolumeProfile) + return; + + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null) + return; + + LightingSearchDataAccessors.SetVolumeProfile(go, (VolumeProfile)args.value); + }; + column.cellCreator = _ => + { + var field = new UnityEditor.UIElements.ObjectField { objectType = typeof(VolumeProfile) }; + field.AddToClassList("core-lighting-search-volume-profile"); + + var styleSheet = LoadStyleSheet(); + if (styleSheet != null) + field.styleSheets.Add(styleSheet); + + return field; + }; + column.binder = (args, ve) => + { + var go = args.item.ToObject(); + if (go == null || !go.TryGetComponent(out _)) + { + ve.visible = false; + return; + } + + var objectField = (UnityEditor.UIElements.ObjectField)ve; + var profile = args.value as VolumeProfile; + + ve.visible = true; + objectField.SetValueWithoutNotify(profile); + }; + } + + [SearchColumnProvider(k_LightShapePath)] + internal static void LightShapeSearchColumnProvider(SearchColumn column) + { + column.getter = args => + { + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null) + return null; + + if (!go.TryGetComponent(out var light)) + return null; + + return LightingSearchDataAccessors.GetLightShape(go); + }; + column.setter = args => + { + if (args.value == null || !args.value.GetType().IsEnum) + return; + + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null) + return; + + LightingSearchDataAccessors.SetLightShape(go, (LightType)args.value); + }; + column.cellCreator = _ => new LightShapeField(); + column.binder = (args, ve) => + { + var field = (LightShapeField)ve; + if (args.value is LightType lightType) + { + if (IsLightShapeApplicable(lightType)) + { + field.visible = true; + field.SetValueWithoutNotify(lightType); + } + else + { + field.visible = false; + } + } + else + { + field.visible = false; + } + }; + } + + static class LightingSearchDataAccessors + { + internal static string GetBakingMode(ProbeVolumeBakingSet bakingSet) + { + return bakingSet.singleSceneMode ? "Single Scene" : "Baking Set"; + } + + internal static void SetBakingMode(ProbeVolumeBakingSet bakingSet, string mode) + { + bakingSet.singleSceneMode = (mode == "Single Scene"); + } + + internal static int GetSkyOcclusionBakingSamples(ProbeVolumeBakingSet bakingSet) + { + return bakingSet.skyOcclusionBakingSamples; + } + + internal static void SetSkyOcclusionBakingSamples(ProbeVolumeBakingSet bakingSet, int samples) + { + bakingSet.skyOcclusionBakingSamples = samples; + } + + internal static string GetVolumeMode(GameObject go) + { + if (!go.TryGetComponent(out var volume)) + return null; + + return volume.isGlobal ? "Global" : "Local"; + } + + internal static void SetVolumeMode(GameObject go, string mode) + { + if (!go.TryGetComponent(out var volume)) + return; + + volume.isGlobal = (mode == "Global"); + } + + internal static VolumeProfile GetVolumeProfile(GameObject go) + { + if (!go.TryGetComponent(out var volume)) + return null; + + return volume.HasInstantiatedProfile() ? volume.profile : volume.sharedProfile; + } + + internal static void SetVolumeProfile(GameObject go, VolumeProfile profile) + { + if (!go.TryGetComponent(out var volume)) + return; + + volume.sharedProfile = profile; + } + + internal static LightType? GetLightShape(GameObject go) + { + if (!go.TryGetComponent(out var light)) + return null; + + return light.type; + } + + internal static void SetLightShape(GameObject go, LightType value) + { + if (!go.TryGetComponent(out var light)) + return; + + if (IsLightShapeApplicable(value)) + { + light.type = value; + } + } + } + + internal static bool IsLightShapeApplicable(LightType lightType) + { + return IsAreaLight(lightType); + } + + static bool IsAreaLight(LightType lightType) + { + return lightType is LightType.Rectangle or LightType.Disc or LightType.Tube; + } + + enum AreaLightShape + { + Rectangle = LightType.Rectangle, + Disc = LightType.Disc, + Tube = LightType.Tube + } + + class LightShapeField : EnumField + { + LightType m_Value; + + public new LightType value + { + get => m_Value; + set + { + if (m_Value != value) + { + m_Value = value; + UpdateEnumField(); + } + } + } + + public LightShapeField() : base(AreaLightShape.Rectangle) + { + m_Value = LightType.Rectangle; + + AddToClassList("core-lighting-search-light-shape"); + + var styleSheet = LoadStyleSheet(); + if (styleSheet != null) + styleSheets.Add(styleSheet); + } + + public void SetValueWithoutNotify(LightType newValue) + { + if (m_Value == newValue) + return; + + m_Value = newValue; + UpdateEnumField(); + } + + void UpdateEnumField() + { + if (IsAreaLight(m_Value)) + { + Init((AreaLightShape)m_Value, false); + } + } + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/LightingSearchSelectors.cs.meta b/Packages/com.unity.render-pipelines.core/Editor/Lighting/LightingSearchSelectors.cs.meta new file mode 100644 index 00000000000..428ebc7f4d4 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/LightingSearchSelectors.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: dedbe1894d884f119869df1b2fbf35fc +timeCreated: 1764173616 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/LightingSearchSelectors.uss b/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/LightingSearchSelectors.uss new file mode 100644 index 00000000000..662472ba953 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/LightingSearchSelectors.uss @@ -0,0 +1,48 @@ +/* Core RP Lighting Search Selectors Styles */ + +/* Light Shape Field */ +.core-lighting-search-light-shape { + flex-grow: 1; +} + +/* Override Subdivision Levels Field */ +.core-lighting-search-subdivision-levels { + flex-direction: row; + align-items: center; + height: 20px; +} + +.core-lighting-search-subdivision-levels__toggle { + margin-right: 5px; + width: 20px; +} + +.core-lighting-search-subdivision-levels__min-field { + flex-grow: 1; + margin-right: 2px; +} + +.core-lighting-search-subdivision-levels__max-field { + flex-grow: 1; +} + +/* Sky Occlusion Baking Samples Field */ +.core-lighting-search-baking-samples { + flex-direction: row; + align-items: center; + height: 20px; +} + +.core-lighting-search-baking-samples__slider { + flex-grow: 1; + margin-right: 5px; +} + +.core-lighting-search-baking-samples__text-field { + min-width: 50px; +} + +/* Volume Profile Field */ +.core-lighting-search-volume-profile { + flex-grow: 1; +} diff --git a/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/LightingSearchSelectors.uss.meta b/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/LightingSearchSelectors.uss.meta new file mode 100644 index 00000000000..4b986b53d41 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/StyleSheets/LightingSearchSelectors.uss.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 86bb22b0f58049838f9c49469f6b82e7 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/CoreLightingSearchSelectorsTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/CoreLightingSearchSelectorsTests.cs new file mode 100644 index 00000000000..3f2879ac27a --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/CoreLightingSearchSelectorsTests.cs @@ -0,0 +1,349 @@ +using NUnit.Framework; +using UnityEditor.Lighting; +using UnityEditor.Search; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.UIElements; + +namespace UnityEditor.Rendering.Tests +{ + [TestFixture] + class CoreLightingSearchSelectorsTests + { + GameObject m_TestGameObject; + Volume m_Volume; + ProbeVolumeBakingSet m_BakingSet; + + [SetUp] + public void Setup() + { + m_TestGameObject = new GameObject("TestCoreLightingObject"); + m_Volume = m_TestGameObject.AddComponent(); + m_BakingSet = ScriptableObject.CreateInstance(); + } + + [TearDown] + public void TearDown() + { + if (m_TestGameObject != null) + { + Object.DestroyImmediate(m_TestGameObject); + } + + if (m_BakingSet != null) + { + Object.DestroyImmediate(m_BakingSet); + } + } + + #region Baking Set Tests + + [Test] + public void BakingMode_Column_CellCreator_CreatesValidElement() + { + var column = new SearchColumn("test", "test", "test"); + CoreLightingSearchSelectors.BakingModeSearchColumnProvider(column); + + var element = column.cellCreator(column); + Assert.IsNotNull(element, "Cell creator should return a valid element"); + Assert.IsInstanceOf(element, "Should create a DropdownField"); + + var dropdown = (UnityEngine.UIElements.DropdownField)element; + Assert.AreEqual(2, dropdown.choices.Count, "Dropdown should have 2 choices"); + Assert.Contains("Baking Set", dropdown.choices); + Assert.Contains("Single Scene", dropdown.choices); + } + + [Test] + public void SkyOcclusionBakingSamples_Column_CellCreator_CreatesValidElement() + { + var column = new SearchColumn("test", "test", "test"); + CoreLightingSearchSelectors.SkyOcclusionBakingSamplesSearchColumnProvider(column); + + var element = column.cellCreator(column); + Assert.IsNotNull(element, "Cell creator should return a valid element"); + Assert.IsInstanceOf(element, "Should create a VisualElement"); + + var container = (UnityEngine.UIElements.VisualElement)element; + var slider = container.Q(); + var intField = container.Q(); + Assert.IsNotNull(slider, "Container should have a SliderInt"); + Assert.IsNotNull(intField, "Container should have an IntegerField"); + } + + #endregion + + #region Volume Tests + + [Test] + public void VolumeMode_Column_SetterAndGetter_WorkCorrectly() + { + m_Volume.isGlobal = true; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + CoreLightingSearchSelectors.VolumeModeSearchColumnProvider(column); + + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + var getterResult = column.getter(searchColumnEventArgs); + Assert.IsNotNull(getterResult, "Getter should return a value"); + Assert.AreEqual("Global", getterResult, "Getter should return 'Global'"); + + var setterArgs = new SearchColumnEventArgs(searchItem, context, column); + setterArgs.value = "Local"; + column.setter(setterArgs); + Assert.IsFalse(m_Volume.isGlobal, "Volume should be local after setting"); + + setterArgs.value = "Global"; + column.setter(setterArgs); + Assert.IsTrue(m_Volume.isGlobal, "Volume should be global after setting"); + } + + [Test] + public void VolumeMode_Column_CellCreator_CreatesValidElement() + { + var column = new SearchColumn("test", "test", "test"); + CoreLightingSearchSelectors.VolumeModeSearchColumnProvider(column); + + var element = column.cellCreator(column); + Assert.IsNotNull(element, "Cell creator should return a valid element"); + Assert.IsInstanceOf(element, "Should create a DropdownField"); + + var dropdown = (UnityEngine.UIElements.DropdownField)element; + Assert.AreEqual(2, dropdown.choices.Count, "Dropdown should have 2 choices"); + Assert.Contains("Global", dropdown.choices); + Assert.Contains("Local", dropdown.choices); + } + + [Test] + public void VolumeProfile_Column_SetterAndGetter_WorkCorrectly() + { + var testProfile = ScriptableObject.CreateInstance(); + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + CoreLightingSearchSelectors.VolumeProfileSearchColumnProvider(column); + + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + + var setterArgs = new SearchColumnEventArgs(searchItem, context, column); + setterArgs.value = testProfile; + column.setter(setterArgs); + + var getterResult = column.getter(searchColumnEventArgs); + Assert.IsNotNull(getterResult, "Getter should return a value"); + Assert.AreEqual(testProfile, getterResult, "Getter should return the VolumeProfile that was set"); + + Object.DestroyImmediate(testProfile); + } + + [Test] + public void VolumeProfile_Column_CellCreator_CreatesValidElement() + { + var column = new SearchColumn("test", "test", "test"); + CoreLightingSearchSelectors.VolumeProfileSearchColumnProvider(column); + + var element = column.cellCreator(column); + Assert.IsNotNull(element, "Cell creator should return a valid element"); + Assert.IsInstanceOf(element, "Should create an ObjectField"); + + var objectField = (UnityEditor.UIElements.ObjectField)element; + Assert.AreEqual(typeof(VolumeProfile), objectField.objectType, "ObjectField should be configured for VolumeProfile type"); + Assert.IsTrue(objectField.ClassListContains("core-lighting-search-volume-profile"), "Should have USS class applied"); + } + + #endregion + + #region Light Shape Tests + + [Test] + public void LightShape_Column_Getter_ReturnsValue() + { + var light = m_TestGameObject.AddComponent(); + light.type = LightType.Rectangle; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", CoreLightingSearchSelectors.k_LightShapePath, "scene"); + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + CoreLightingSearchSelectors.LightShapeSearchColumnProvider(column); + var getterResult = column.getter(searchColumnEventArgs); + Assert.IsNotNull(getterResult, "Getter should return a value"); + Assert.AreEqual(LightType.Rectangle, getterResult, "Getter should return Rectangle"); + } + + [Test] + public void LightShape_Column_Getter_WithoutLight_ReturnsNull() + { + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", CoreLightingSearchSelectors.k_LightShapePath, "scene"); + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + CoreLightingSearchSelectors.LightShapeSearchColumnProvider(column); + var getterResult = column.getter(searchColumnEventArgs); + Assert.IsNull(getterResult, "Getter should return null for GameObject without Light component"); + } + + [Test] + public void LightShape_Column_Setter_UpdatesAreaLightValue() + { + var light = m_TestGameObject.AddComponent(); + light.type = LightType.Point; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", CoreLightingSearchSelectors.k_LightShapePath, "scene"); + CoreLightingSearchSelectors.LightShapeSearchColumnProvider(column); + + var setterArgs = new SearchColumnEventArgs(searchItem, context, column); + setterArgs.value = LightType.Rectangle; + column.setter(setterArgs); + Assert.AreEqual(LightType.Rectangle, light.type, "Light should have type Rectangle after setting"); + } + + [Test] + public void LightShape_Column_Setter_RejectsNonApplicableLightTypes() + { + var light = m_TestGameObject.AddComponent(); + light.type = LightType.Rectangle; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", CoreLightingSearchSelectors.k_LightShapePath, "scene"); + CoreLightingSearchSelectors.LightShapeSearchColumnProvider(column); + + var setterArgs = new SearchColumnEventArgs(searchItem, context, column); + setterArgs.value = LightType.Spot; + column.setter(setterArgs); + Assert.AreEqual(LightType.Rectangle, light.type, "Light type should not change when setting non-applicable type"); + } + + [Test] + public void LightShape_Column_CellCreator_CreatesValidElement() + { + var column = new SearchColumn("test", CoreLightingSearchSelectors.k_LightShapePath, "test"); + CoreLightingSearchSelectors.LightShapeSearchColumnProvider(column); + + var element = column.cellCreator(column); + Assert.IsNotNull(element, "Cell creator should return a valid element"); + Assert.IsInstanceOf(element, "Should create a VisualElement"); + } + + [Test] + public void LightShape_Column_Binder_HandlesApplicableLightTypes() + { + var light = m_TestGameObject.AddComponent(); + light.type = LightType.Rectangle; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", CoreLightingSearchSelectors.k_LightShapePath, "scene"); + CoreLightingSearchSelectors.LightShapeSearchColumnProvider(column); + + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + var getterResult = column.getter(searchColumnEventArgs); + + var element = column.cellCreator(column); + var binderArgs = new SearchColumnEventArgs(searchItem, context, column) { value = getterResult }; + Assert.DoesNotThrow(() => column.binder(binderArgs, element), "Binder should not throw for applicable light types"); + } + + [Test] + public void LightShape_Column_Binder_HidesNonApplicableLightTypes() + { + var light = m_TestGameObject.AddComponent(); + light.type = LightType.Spot; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", CoreLightingSearchSelectors.k_LightShapePath, "scene"); + CoreLightingSearchSelectors.LightShapeSearchColumnProvider(column); + + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + var getterResult = column.getter(searchColumnEventArgs); + + var element = column.cellCreator(column); + var binderArgs = new SearchColumnEventArgs(searchItem, context, column) { value = getterResult }; + column.binder(binderArgs, element); + + Assert.IsFalse(element.visible, "Element should be hidden for non-applicable light types (Spot)"); + } + + #endregion + + #region Integration Tests + + [Test] + public void AllCoreColumns_HaveValidConfiguration() + { + var columnTypes = new[] + { + CoreLightingSearchSelectors.k_BakingModePath, + CoreLightingSearchSelectors.k_SkyOcclusionBakingSamplesPath, + CoreLightingSearchSelectors.k_VolumeModePath, + CoreLightingSearchSelectors.k_VolumeProfilePath, + CoreLightingSearchSelectors.k_LightShapePath + }; + + foreach (var columnType in columnTypes) + { + var column = new SearchColumn("test", columnType, "test"); + + Assert.DoesNotThrow(() => + { + switch (columnType) + { + case "BakingSets/BakingMode": + CoreLightingSearchSelectors.BakingModeSearchColumnProvider(column); + break; + case "BakingSets/SkyOcclusionBakingSamples": + CoreLightingSearchSelectors.SkyOcclusionBakingSamplesSearchColumnProvider(column); + break; + case "Volume/Mode": + CoreLightingSearchSelectors.VolumeModeSearchColumnProvider(column); + break; + case "Volume/Profile": + CoreLightingSearchSelectors.VolumeProfileSearchColumnProvider(column); + break; + case "Light/Shape": + CoreLightingSearchSelectors.LightShapeSearchColumnProvider(column); + break; + } + }, $"Column initialization for {columnType} should not throw"); + + Assert.IsNotNull(column.getter, $"Column {columnType} should have a getter"); + Assert.IsNotNull(column.setter, $"Column {columnType} should have a setter"); + Assert.IsNotNull(column.cellCreator, $"Column {columnType} should have a cell creator"); + Assert.IsNotNull(column.binder, $"Column {columnType} should have a binder"); + } + } + + #endregion + } +} diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/CoreLightingSearchSelectorsTests.cs.meta b/Packages/com.unity.render-pipelines.core/Tests/Editor/CoreLightingSearchSelectorsTests.cs.meta new file mode 100644 index 00000000000..2f0d7173bf6 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/CoreLightingSearchSelectorsTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 31fbdf2532dda4bee96be95759cd3e19 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightingSearchSelectors.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightingSearchSelectors.cs new file mode 100644 index 00000000000..a34bd747095 --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightingSearchSelectors.cs @@ -0,0 +1,833 @@ +using System; +using UnityEditor.Search; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.UIElements; +using UnityEngine.Rendering.HighDefinition; + +namespace UnityEditor.Rendering.HighDefinition +{ + static class HDLightingSearchSelectors + { + internal const string k_SceneProvider = "scene"; + internal const string k_LightPath = "Light/"; + internal const string k_LightShapePath = k_LightPath + "Shape"; + internal const string k_LightIntensityPath = k_LightPath + "Intensity"; + internal const string k_LightIntensityUnitPath = k_LightPath + "IntensityUnit"; + internal const string k_ContactShadowsPath = k_LightPath + "ContactShadows"; + internal const string k_ShadowResolutionPath = k_LightPath + "ShadowResolution"; + internal const string k_ReflectionProbePath = "ReflectionProbe/"; + internal const string k_ReflectionProbeResolutionPath = k_ReflectionProbePath + "Resolution"; + internal const string k_MeshRendererPath = "Renderer/MeshRenderer/"; + internal const string k_RayTracingModeFilter = "RayTracingMode"; + internal const string k_RayTracingModePath = k_MeshRendererPath + "RayTracingMode"; + + const string k_StyleSheetPath = "StyleSheets/HDLightingSearchSelectors.uss"; + const float k_FlexGrowDefault = 1f; + const float k_ImguiContainerHeight = 20f; + const float k_RectLeftWidthRatio = 0.3f; + const float k_RectRightWidthRatio = 0.7f; + const float k_ToggleWidth = 18f; + static StyleSheet s_StyleSheet; + + static StyleSheet LoadStyleSheet() + { + if (s_StyleSheet == null) + { + s_StyleSheet = EditorGUIUtility.Load(k_StyleSheetPath) as StyleSheet; + } + return s_StyleSheet; + } + + internal enum DirectionalLightUnit + { + Lux = LightUnit.Lux, + } + + internal enum AreaLightUnit + { + Lumen = LightUnit.Lumen, + Nits = LightUnit.Nits, + Ev100 = LightUnit.Ev100, + } + + internal enum PunctualLightUnit + { + Lumen = LightUnit.Lumen, + Candela = LightUnit.Candela, + Lux = LightUnit.Lux, + Ev100 = LightUnit.Ev100 + } + + internal enum ShadowResolutionOption + { + Low, + Medium, + High, + Custom + } + + [SearchColumnProvider(k_LightIntensityPath)] + public static void LightIntensitySearchColumnProvider(SearchColumn column) + { + column.getter = args => + { + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null || !go.TryGetComponent(out var light)) + return null; + + return HDLightingSearchDataAccessors.GetLightIntensity(go); + }; + column.setter = args => + { + if (args.value is not float intensity) + return; + + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null) + return; + + HDLightingSearchDataAccessors.SetLightIntensity(go, intensity); + }; + column.cellCreator = _ => + { + var field = new FloatField { label = "\u2022" }; + field.style.flexGrow = k_FlexGrowDefault; + field.labelElement.style.minWidth = StyleKeyword.Auto; + field.labelElement.style.marginRight = 5; + field.labelElement.style.paddingRight = 0; + field.labelElement.style.marginTop = -1; + + var dragger = new FieldMouseDragger(field); + dragger.SetDragZone(field.labelElement); + + var textInput = field.Q("unity-text-input"); + if (textInput != null) + textInput.style.unityTextAlign = TextAnchor.MiddleRight; + + return field; + }; + column.binder = (args, ve) => + { + var field = (FloatField)ve; + var go = args.item.data as GameObject ?? args.item.ToObject(); + + if (go == null || !go.TryGetComponent(out _)) + { + field.visible = false; + return; + } + + field.visible = true; + + if (args.value is float intensity) + { + field.SetValueWithoutNotify(intensity); + } + }; + } + + [SearchColumnProvider(k_LightIntensityUnitPath)] + public static void LightIntensityUnitSearchColumnProvider(SearchColumn column) + { + column.getter = args => + { + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null) + return null; + + return HDLightingSearchDataAccessors.GetLightIntensityUnit(go); + }; + column.setter = args => + { + if (args.value == null || !args.value.GetType().IsEnum) + return; + + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null) + return; + + HDLightingSearchDataAccessors.SetLightIntensityUnit(go, (LightUnit)args.value); + }; + column.cellCreator = _ => new EnumField() { style = { flexGrow = k_FlexGrowDefault } }; + column.binder = (args, ve) => + { + var field = (EnumField)ve; + var go = args.item.data as GameObject ?? args.item.ToObject(); + + if (go == null || !go.TryGetComponent(out var light)) + { + field.visible = false; + return; + } + + field.visible = true; + + if (args.value is LightUnit lightUnit) + { + LightType lightType = light.type; + LightUnit validUnit = LightUnitUtils.IsLightUnitSupported(lightType, lightUnit) + ? lightUnit + : LightUnitUtils.GetNativeLightUnit(lightType); + + if (lightType == LightType.Directional) + { + field.Init(DirectionalLightUnit.Lux); + field.SetValueWithoutNotify((DirectionalLightUnit)validUnit); + } + else if (lightType == LightType.Rectangle || lightType == LightType.Disc || lightType == LightType.Tube) + { + field.Init(AreaLightUnit.Lumen); + field.SetValueWithoutNotify((AreaLightUnit)validUnit); + } + else + { + field.Init(PunctualLightUnit.Lumen); + field.SetValueWithoutNotify((PunctualLightUnit)validUnit); + } + } + }; + } + + [SearchSelector(k_RayTracingModePath, provider: k_SceneProvider, priority: 99)] + static object RayTracingModeSearchSelector(SearchSelectorArgs args) + { + var go = args.current.ToObject(); + if (go == null) + return null; + + return HDLightingSearchDataAccessors.GetRayTracingMode(go); + } + + [SearchColumnProvider(k_RayTracingModePath)] + public static void RayTracingModeSearchColumnProvider(SearchColumn column) + { + column.getter = args => + { + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null) + return null; + + if (!go.TryGetComponent(out var meshRenderer)) + return null; + + return HDLightingSearchDataAccessors.GetRayTracingMode(go); + }; + column.setter = args => + { + if (args.value == null || !args.value.GetType().IsEnum) + return; + + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null) + return; + + HDLightingSearchDataAccessors.SetRayTracingMode(go, (UnityEngine.Experimental.Rendering.RayTracingMode)args.value); + }; + column.cellCreator = _ => new EnumField(null, UnityEngine.Experimental.Rendering.RayTracingMode.Off) { style = { flexGrow = k_FlexGrowDefault } }; + column.binder = (args, ve) => + { + var field = (EnumField)ve; + if (args.value != null) + { + field.visible = true; + field.SetValueWithoutNotify((UnityEngine.Experimental.Rendering.RayTracingMode)args.value); + } + else + { + field.visible = false; + } + }; + } + + [SearchColumnProvider(k_ReflectionProbeResolutionPath)] + public static void ReflectionProbeResolutionSearchColumnProvider(SearchColumn column) + { + column.getter = args => + { + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null || !go.TryGetComponent(out _)) + return null; + + return HDLightingSearchDataAccessors.GetReflectionProbeResolution(go); + }; + + column.setter = args => + { + if (args.value is not HDLightingSearchDataAccessors.ReflectionProbeResolutionData data) + return; + + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null) + return; + + HDLightingSearchDataAccessors.SetReflectionProbeResolution(go, data); + }; + + column.cellCreator = _ => CreateImguiContainer(); + column.binder = (args, ve) => + { + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null || !go.TryGetComponent(out var hdProbe)) + { + ve.visible = false; + return; + } + + var reflectionProbeResolutionData = (HDLightingSearchDataAccessors.ReflectionProbeResolutionData)args.value; + + var imguiContainer = ve.Q(); + switch (hdProbe.type) + { + case ProbeSettings.ProbeType.ReflectionProbe: + imguiContainer.onGUIHandler = () => + { + var rect = EditorGUILayout.GetControlRect(false, k_ImguiContainerHeight); + var leftRect = new Rect(rect.x, rect.y, rect.width * k_RectLeftWidthRatio, rect.height); + var rightRect = new Rect(rect.x + rect.width * k_RectLeftWidthRatio, rect.y, rect.width * k_RectRightWidthRatio, rect.height); + + GUILayout.BeginHorizontal("box", GUILayout.ExpandWidth(true)); + + EditorGUI.BeginChangeCheck(); + var (level, useOverride) = SerializedScalableSettingValueUI.LevelFieldGUI(leftRect, GUIContent.none, ScalableSettingSchema.GetSchemaOrNull(ScalableSettingSchemaId.With3Levels), reflectionProbeResolutionData.level, reflectionProbeResolutionData.useOverride); + + Enum overrideLevel; + if (reflectionProbeResolutionData.useOverride) + { + overrideLevel = EditorGUI.EnumPopup(rightRect, reflectionProbeResolutionData.overrideLevel); + } + else + { + using (new EditorGUI.DisabledScope(true)) + { + overrideLevel = EditorGUI.EnumFlagsField(rightRect, reflectionProbeResolutionData.overrideLevel); + } + } + if(EditorGUI.EndChangeCheck()) + { + reflectionProbeResolutionData.level = level; + reflectionProbeResolutionData.useOverride = useOverride; + reflectionProbeResolutionData.overrideLevel = (CubeReflectionResolution)overrideLevel; + column.setter?.Invoke(new SearchColumnEventArgs(args.item, args.context, column) { value = reflectionProbeResolutionData }); + } + + GUILayout.EndHorizontal(); + }; + break; + case ProbeSettings.ProbeType.PlanarProbe: + default: + imguiContainer.onGUIHandler = () => + { + var rect = EditorGUILayout.GetControlRect(false, k_ImguiContainerHeight); + var leftRect = new Rect(rect.x, rect.y, rect.width * k_RectLeftWidthRatio, rect.height); + var rightRect = new Rect(rect.x + rect.width * k_RectLeftWidthRatio, rect.y, rect.width * k_RectRightWidthRatio, rect.height); + + GUILayout.BeginHorizontal("box", GUILayout.ExpandWidth(true)); + + EditorGUI.BeginChangeCheck(); + var (level, useOverride) = SerializedScalableSettingValueUI.LevelFieldGUI(leftRect, GUIContent.none, ScalableSettingSchema.GetSchemaOrNull(ScalableSettingSchemaId.With3Levels), reflectionProbeResolutionData.level, reflectionProbeResolutionData.useOverride); + + Enum overrideLevel; + if (reflectionProbeResolutionData.useOverride) + { + overrideLevel = EditorGUI.EnumPopup(rightRect, reflectionProbeResolutionData.overrideLevel); + } + else + { + using (new EditorGUI.DisabledScope(true)) + { + overrideLevel = EditorGUI.EnumFlagsField(rightRect, reflectionProbeResolutionData.overrideLevel); + } + } + if (EditorGUI.EndChangeCheck()) + { + reflectionProbeResolutionData.level = level; + reflectionProbeResolutionData.useOverride = useOverride; + reflectionProbeResolutionData.overrideLevel = (CubeReflectionResolution)overrideLevel; + column.setter?.Invoke(new SearchColumnEventArgs(args.item, args.context, column) { value = reflectionProbeResolutionData }); + } + + GUILayout.EndHorizontal(); + }; + break; + } + }; + } + + [SearchColumnProvider(k_ContactShadowsPath)] + public static void ContactShadowsSearchColumnProvider(SearchColumn column) + { + column.getter = args => + { + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null || !go.TryGetComponent(out _)) + return null; + + return HDLightingSearchDataAccessors.GetContactShadowsData(go); + }; + + column.setter = args => + { + if (args.value is not HDLightingSearchDataAccessors.ContactShadowsData data) + return; + + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null) + return; + + HDLightingSearchDataAccessors.SetContactShadowsData(go, data); + }; + + column.cellCreator = _ => CreateImguiContainer(); + column.binder = (args, ve) => + { + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null || !go.TryGetComponent(out _)) + { + ve.visible = false; + return; + } + + ve.visible = true; + var contactShadowsData = (HDLightingSearchDataAccessors.ContactShadowsData)args.value; + var imguiContainer = ve.Q(); + imguiContainer.onGUIHandler = () => + { + var rect = EditorGUILayout.GetControlRect(false, k_ImguiContainerHeight); + var leftRect = new Rect(rect.x, rect.y, rect.width - k_ToggleWidth - 4f, rect.height); + var rightRect = new Rect(rect.xMax - k_ToggleWidth, rect.y, k_ToggleWidth, rect.height); + + EditorGUI.BeginChangeCheck(); + var (level, useOverride) = SerializedScalableSettingValueUI.LevelFieldGUI( + leftRect, + GUIContent.none, + ScalableSettingSchema.GetSchemaOrNull(ScalableSettingSchemaId.With3Levels), + contactShadowsData.level, + contactShadowsData.useOverride); + + contactShadowsData.level = level; + contactShadowsData.useOverride = useOverride; + + if (contactShadowsData.useOverride) + { + contactShadowsData.overrideValue = EditorGUI.Toggle(rightRect, contactShadowsData.overrideValue); + } + else + { + var hdrp = HDRenderPipeline.currentAsset; + var defaultValue = HDAdditionalLightData.ScalableSettings.UseContactShadow(hdrp); + using (new EditorGUI.DisabledScope(true)) + { + contactShadowsData.overrideValue = EditorGUI.Toggle(rightRect, defaultValue[contactShadowsData.level]); + } + } + + if (EditorGUI.EndChangeCheck()) + { + column.setter?.Invoke(new SearchColumnEventArgs(args.item, args.context, column) { value = contactShadowsData }); + } + }; + }; + } + + [SearchColumnProvider(k_ShadowResolutionPath)] + public static void ShadowResolutionSearchColumnProvider(SearchColumn column) + { + column.getter = args => + { + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null || !go.TryGetComponent(out _)) + return null; + + return HDLightingSearchDataAccessors.GetShadowResolutionData(go); + }; + + column.setter = args => + { + if (args.value is not HDLightingSearchDataAccessors.ShadowResolutionData data) + return; + + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null) + return; + + HDLightingSearchDataAccessors.SetShadowResolutionData(go, data); + }; + + column.cellCreator = _ => CreateImguiContainer(); + column.binder = (args, ve) => + { + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null || !go.TryGetComponent(out _)) + { + ve.visible = false; + return; + } + + ve.visible = true; + var shadowResolutionData = (HDLightingSearchDataAccessors.ShadowResolutionData)args.value; + var imguiContainer = ve.Q(); + imguiContainer.onGUIHandler = () => + { + var rect = EditorGUILayout.GetControlRect(false, 20); + var currentOption = shadowResolutionData.useOverride + ? ShadowResolutionOption.Custom + : shadowResolutionData.level switch + { + <= 0 => ShadowResolutionOption.Low, + 1 => ShadowResolutionOption.Medium, + _ => ShadowResolutionOption.High + }; + + EditorGUI.BeginChangeCheck(); + var newOption = (ShadowResolutionOption)EditorGUI.EnumPopup(rect, currentOption); + if (EditorGUI.EndChangeCheck()) + { + if (newOption == ShadowResolutionOption.Custom) + { + shadowResolutionData.useOverride = true; + } + else + { + shadowResolutionData.useOverride = false; + shadowResolutionData.level = (int)newOption; + } + + column.setter?.Invoke(new SearchColumnEventArgs(args.item, args.context, column) { value = shadowResolutionData }); + } + }; + }; + } + + [SearchColumnProvider(k_LightShapePath)] + public static void LightShapeSearchColumnProvider(SearchColumn column) + { + column.getter = args => + { + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null) + return null; + + if (!go.TryGetComponent(out var light)) + return null; + + return HDLightingSearchDataAccessors.GetLightShape(go); + }; + column.setter = args => + { + if (args.value == null || !args.value.GetType().IsEnum) + return; + + var go = args.item.data as GameObject ?? args.item.ToObject(); + if (go == null) + return; + + HDLightingSearchDataAccessors.SetLightShape(go, (LightType)args.value); + }; + column.cellCreator = _ => new HDLightShapeField(); + column.binder = (args, ve) => + { + var field = (HDLightShapeField)ve; + if (args.value is LightType lightType) + { + if (HDLightingSearchDataAccessors.IsLightShapeApplicable(lightType)) + { + field.visible = true; + field.SetValueWithoutNotify(lightType); + } + else + { + field.visible = false; + } + } + else + { + field.visible = false; + } + }; + } + + static VisualElement CreateImguiContainer() + { + var visualElement = new VisualElement() { style = { height = k_ImguiContainerHeight } }; + visualElement.Add(new IMGUIContainer() { style = { height = k_ImguiContainerHeight } }); + return visualElement; + } + + static class HDLightingSearchDataAccessors + { + internal struct ReflectionProbeResolutionData + { + public int level; + public bool useOverride; + public CubeReflectionResolution overrideLevel; + } + + internal struct ContactShadowsData + { + public int level; + public bool useOverride; + public bool overrideValue; + } + + internal struct ShadowResolutionData + { + public int level; + public bool useOverride; + } + + internal static float GetLightIntensity(GameObject go) + { + if (!go.TryGetComponent(out var light)) + return 0f; + + LightType lightType = light.type; + LightUnit nativeUnit = LightUnitUtils.GetNativeLightUnit(lightType); + LightUnit lightUnit = light.lightUnit; + float nativeIntensity = light.intensity; + + lightUnit = LightUnitUtils.IsLightUnitSupported(lightType, lightUnit) ? lightUnit : nativeUnit; + + return LightUnitUtils.ConvertIntensity(light, nativeIntensity, nativeUnit, lightUnit); + } + + internal static void SetLightIntensity(GameObject go, float intensity) + { + if (!go.TryGetComponent(out var light)) + return; + + LightType lightType = light.type; + LightUnit nativeUnit = LightUnitUtils.GetNativeLightUnit(lightType); + LightUnit lightUnit = light.lightUnit; + + if (!LightUnitUtils.IsLightUnitSupported(lightType, lightUnit)) + return; + + light.intensity = LightUnitUtils.ConvertIntensity(light, intensity, lightUnit, nativeUnit); + } + + internal static LightUnit GetLightIntensityUnit(GameObject go) + { + if (!go.TryGetComponent(out var light)) + return LightUnit.Lumen; + + return light.lightUnit; + } + + internal static void SetLightIntensityUnit(GameObject go, LightUnit unit) + { + if (!go.TryGetComponent(out var light)) + return; + + if (!LightUnitUtils.IsLightUnitSupported(light.type, unit)) + return; + + light.lightUnit = unit; + + // Mark the light component as dirty so Unity's change detection system + // notifies all views (including Search) that this object changed. + // This triggers the intensity column to rebind and show the converted value. + EditorUtility.SetDirty(light); + } + + internal static ReflectionProbeResolutionData GetReflectionProbeResolution(GameObject go) + { + var reflectionProbeResolutionData = new ReflectionProbeResolutionData(); + + if (!go.TryGetComponent(out var hdProbe)) + return reflectionProbeResolutionData; + + switch (hdProbe.type) + { + case ProbeSettings.ProbeType.ReflectionProbe: + reflectionProbeResolutionData.useOverride = hdProbe.settingsRaw.cubeResolution.useOverride; + reflectionProbeResolutionData.level = hdProbe.settingsRaw.cubeResolution.level; + reflectionProbeResolutionData.overrideLevel = hdProbe.settingsRaw.cubeResolution.@override; + break; + case ProbeSettings.ProbeType.PlanarProbe: + default: + reflectionProbeResolutionData.useOverride = hdProbe.settingsRaw.resolutionScalable.useOverride; + reflectionProbeResolutionData.level = hdProbe.settingsRaw.resolutionScalable.level; + reflectionProbeResolutionData.overrideLevel = (CubeReflectionResolution)hdProbe.settingsRaw.resolutionScalable.@override; + break; + } + + return reflectionProbeResolutionData; + } + + internal static ContactShadowsData GetContactShadowsData(GameObject go) + { + var contactShadowsData = new ContactShadowsData(); + if (!go.TryGetComponent(out var lightData)) + return contactShadowsData; + + contactShadowsData.level = lightData.useContactShadow.level; + contactShadowsData.useOverride = lightData.useContactShadow.useOverride; + contactShadowsData.overrideValue = lightData.useContactShadow.@override; + return contactShadowsData; + } + + internal static ShadowResolutionData GetShadowResolutionData(GameObject go) + { + var shadowResolutionData = new ShadowResolutionData(); + if (!go.TryGetComponent(out var lightData)) + return shadowResolutionData; + + shadowResolutionData.level = lightData.shadowResolution.level; + shadowResolutionData.useOverride = lightData.shadowResolution.useOverride; + return shadowResolutionData; + } + + internal static void SetReflectionProbeResolution(GameObject go, ReflectionProbeResolutionData reflectionProbeResolutionData) + { + if (!go.TryGetComponent(out var hdProbe)) + return; + + switch (hdProbe.type) + { + case ProbeSettings.ProbeType.ReflectionProbe: + hdProbe.settingsRaw.cubeResolution.useOverride = reflectionProbeResolutionData.useOverride; + hdProbe.settingsRaw.cubeResolution.level = reflectionProbeResolutionData.level; + hdProbe.settingsRaw.cubeResolution.@override = reflectionProbeResolutionData.overrideLevel; + break; + case ProbeSettings.ProbeType.PlanarProbe: + default: + hdProbe.settingsRaw.resolutionScalable.useOverride = reflectionProbeResolutionData.useOverride; + hdProbe.settingsRaw.resolutionScalable.level = reflectionProbeResolutionData.level; + hdProbe.settingsRaw.resolutionScalable.@override = (PlanarReflectionAtlasResolution)reflectionProbeResolutionData.overrideLevel; + break; + } + } + + internal static void SetContactShadowsData(GameObject go, ContactShadowsData contactShadowsData) + { + if (!go.TryGetComponent(out var lightData)) + return; + + lightData.useContactShadow.level = contactShadowsData.level; + lightData.useContactShadow.useOverride = contactShadowsData.useOverride; + lightData.useContactShadow.@override = contactShadowsData.overrideValue; + } + + internal static void SetShadowResolutionData(GameObject go, ShadowResolutionData shadowResolutionData) + { + if (!go.TryGetComponent(out var lightData)) + return; + + lightData.shadowResolution.level = shadowResolutionData.level; + lightData.shadowResolution.useOverride = shadowResolutionData.useOverride; + lightData.RefreshCachedShadow(); + } + + internal static UnityEngine.Experimental.Rendering.RayTracingMode GetRayTracingMode(GameObject go) + { + if (!go.TryGetComponent(out var meshRenderer)) + return UnityEngine.Experimental.Rendering.RayTracingMode.Off; + + return meshRenderer.rayTracingMode; + } + + internal static void SetRayTracingMode(GameObject go, UnityEngine.Experimental.Rendering.RayTracingMode value) + { + if (!go.TryGetComponent(out var meshRenderer)) + return; + + meshRenderer.rayTracingMode = value; + } + + internal static LightType? GetLightShape(GameObject go) + { + if (!go.TryGetComponent(out var light)) + return null; + + return light.type; + } + + internal static void SetLightShape(GameObject go, LightType value) + { + if (!go.TryGetComponent(out var light)) + return; + + if (IsLightShapeApplicable(value)) + { + light.type = value; + + if (!LightUnitUtils.IsLightUnitSupported(value, light.lightUnit)) + { + light.lightUnit = LightUnitUtils.GetNativeLightUnit(value); + } + + // Mark the light component as dirty so the intensity and unit columns refresh + // when the light type changes. + EditorUtility.SetDirty(light); + } + } + + internal static bool IsLightShapeApplicable(LightType lightType) + { + return IsAreaLight(lightType) || IsSpotLight(lightType); + } + + internal static bool IsSpotLight(LightType lightType) + { + return lightType is LightType.Spot or LightType.Pyramid or LightType.Box; + } + + internal static bool IsAreaLight(LightType lightType) + { + return lightType is LightType.Rectangle or LightType.Disc or LightType.Tube; + } + } + + enum SpotLightShape + { + Cone = LightType.Spot, + Pyramid = LightType.Pyramid, + Box = LightType.Box + } + + enum AreaLightShape + { + Rectangle = LightType.Rectangle, + Disc = LightType.Disc, + Tube = LightType.Tube + } + + class HDLightShapeField : EnumField + { + LightType m_Value; + + public HDLightShapeField() : base(SpotLightShape.Cone) + { + m_Value = LightType.Spot; + + AddToClassList("hdrp-lighting-search-light-shape"); + + var styleSheet = LoadStyleSheet(); + if (styleSheet != null) + styleSheets.Add(styleSheet); + } + + public void SetValueWithoutNotify(LightType newValue) + { + if (m_Value == newValue) + return; + + m_Value = newValue; + UpdateEnumField(); + } + + void UpdateEnumField() + { + if (HDLightingSearchDataAccessors.IsSpotLight(m_Value)) + { + Init((SpotLightShape)m_Value); + } + else + { + Init((AreaLightShape)m_Value); + } + } + } + } +} diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightingSearchSelectors.cs.meta b/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightingSearchSelectors.cs.meta new file mode 100644 index 00000000000..41c913f92d3 --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightingSearchSelectors.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 450652a0de85411fa5ea383806643b3a +timeCreated: 1755625717 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/StyleSheets.meta b/Packages/com.unity.render-pipelines.high-definition/Editor/StyleSheets.meta new file mode 100644 index 00000000000..397c61fa216 --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/StyleSheets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2a4796d5720e5413993abf7d017f508e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/StyleSheets/HDLightingSearchSelectors.uss b/Packages/com.unity.render-pipelines.high-definition/Editor/StyleSheets/HDLightingSearchSelectors.uss new file mode 100644 index 00000000000..0cb0ba07cd4 --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/StyleSheets/HDLightingSearchSelectors.uss @@ -0,0 +1,6 @@ +/* HDRP Lighting Search Selectors Styles */ + +/* Light Shape Field */ +.hdrp-lighting-search-light-shape { + flex-grow: 1; +} diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/StyleSheets/HDLightingSearchSelectors.uss.meta b/Packages/com.unity.render-pipelines.high-definition/Editor/StyleSheets/HDLightingSearchSelectors.uss.meta new file mode 100644 index 00000000000..2302e7583d3 --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/StyleSheets/HDLightingSearchSelectors.uss.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a5ab35ca444c4f199f594959243c84c5 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 diff --git a/Packages/com.unity.render-pipelines.high-definition/Tests/Editor/HDLightingSearchSelectorsTests.cs b/Packages/com.unity.render-pipelines.high-definition/Tests/Editor/HDLightingSearchSelectorsTests.cs new file mode 100644 index 00000000000..cb98126adc7 --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Tests/Editor/HDLightingSearchSelectorsTests.cs @@ -0,0 +1,714 @@ +using NUnit.Framework; +using UnityEditor; +using UnityEditor.Rendering.HighDefinition; +using UnityEditor.Search; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.Rendering.HighDefinition; +using UnityEngine.UIElements; + +namespace UnityEditor.Rendering.HighDefinition.Tests +{ + [TestFixture] + class HDLightingSearchSelectorsTests + { + GameObject m_TestGameObject; + Light m_Light; + MeshRenderer m_MeshRenderer; + HDAdditionalLightData m_HDLightData; + + [SetUp] + public void Setup() + { + m_TestGameObject = new GameObject("TestHDLightingObject"); + m_Light = m_TestGameObject.AddComponent(); + m_Light.type = LightType.Point; + m_HDLightData = m_TestGameObject.AddComponent(); + var meshFilter = m_TestGameObject.AddComponent(); + meshFilter.mesh = Resources.GetBuiltinResource("Quad.fbx"); + m_MeshRenderer = m_TestGameObject.AddComponent(); + m_MeshRenderer.material = new Material(Shader.Find("Standard")); + } + + [TearDown] + public void TearDown() + { + if (m_TestGameObject != null) + { + Object.DestroyImmediate(m_TestGameObject); + } + } + + #region Light Intensity Tests + + [Test] + public void LightIntensity_Column_SetterAndGetter_WorkCorrectly() + { + m_Light.type = LightType.Point; + m_Light.lightUnit = LightUnit.Lumen; + m_Light.intensity = LightUnitUtils.ConvertIntensity(m_Light, 1000f, LightUnit.Lumen, LightUnit.Candela); + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + HDLightingSearchSelectors.LightIntensitySearchColumnProvider(column); + + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + var getterResult = column.getter(searchColumnEventArgs); + Assert.IsNotNull(getterResult, "Getter should return a value"); + Assert.IsInstanceOf(getterResult, "Getter should return a float"); + + float intensity = (float)getterResult; + Assert.AreEqual(1000f, intensity, 0.01f, "Getter should return intensity in UI unit (Lumen)"); + + var setterArgs = new SearchColumnEventArgs(searchItem, context, column); + setterArgs.value = 2000f; + column.setter(setterArgs); + + float expectedNativeIntensity = LightUnitUtils.ConvertIntensity(m_Light, 2000f, LightUnit.Lumen, LightUnit.Candela); + Assert.AreEqual(expectedNativeIntensity, m_Light.intensity, 0.01f, "Light intensity should be updated in native unit"); + } + + [Test] + public void LightIntensity_Column_HandlesUnitConversion_Directional() + { + m_Light.type = LightType.Directional; + m_Light.lightUnit = LightUnit.Lux; + m_Light.intensity = 100f; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + HDLightingSearchSelectors.LightIntensitySearchColumnProvider(column); + + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + var getterResult = column.getter(searchColumnEventArgs); + Assert.IsInstanceOf(getterResult, "Getter should return a float"); + + float intensity = (float)getterResult; + Assert.AreEqual(100f, intensity, 0.01f, "Directional light intensity should match (Lux is native unit)"); + } + + [Test] + public void LightIntensity_Column_HandlesUnitConversion_Area() + { + m_Light.type = LightType.Rectangle; + m_Light.areaSize = new Vector2(1f, 1f); + m_Light.lightUnit = LightUnit.Lumen; + float nativeIntensity = LightUnitUtils.ConvertIntensity(m_Light, 500f, LightUnit.Lumen, LightUnit.Nits); + m_Light.intensity = nativeIntensity; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + HDLightingSearchSelectors.LightIntensitySearchColumnProvider(column); + + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + var getterResult = column.getter(searchColumnEventArgs); + Assert.IsInstanceOf(getterResult, "Getter should return a float"); + + float intensity = (float)getterResult; + Assert.AreEqual(500f, intensity, 0.01f, "Area light intensity should be converted to Lumen for UI"); + } + + [Test] + public void LightIntensity_Column_UnitChangeConvertsDisplay() + { + m_Light.type = LightType.Point; + m_Light.lightUnit = LightUnit.Lumen; + m_Light.intensity = LightUnitUtils.ConvertIntensity(m_Light, 1000f, LightUnit.Lumen, LightUnit.Candela); + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + HDLightingSearchSelectors.LightIntensitySearchColumnProvider(column); + + var args = new SearchColumnEventArgs(searchItem, context, column); + var initialData = column.getter(args); + Assert.IsInstanceOf(initialData, "Getter should return a float"); + + float initialIntensity = (float)initialData; + Assert.AreEqual(1000f, initialIntensity, 0.01f, "Initial intensity should be 1000 Lumen"); + + m_Light.lightUnit = LightUnit.Candela; + + var updatedData = column.getter(args); + Assert.IsInstanceOf(updatedData, "Getter should return a float"); + + float updatedIntensity = (float)updatedData; + Assert.AreEqual(m_Light.intensity, updatedIntensity, 0.01f, "Intensity should now be displayed in native unit (Candela)"); + } + + #endregion + + #region Light Intensity Unit Tests + + [Test] + public void LightIntensityUnit_Column_SetterAndGetter_WorkCorrectly() + { + m_Light.lightUnit = LightUnit.Lumen; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + HDLightingSearchSelectors.LightIntensityUnitSearchColumnProvider(column); + + var getterResult = column.getter(new SearchColumnEventArgs(searchItem, context, column)); + Assert.AreEqual(LightUnit.Lumen, getterResult, "Getter should return the light unit"); + + var setterArgs = new SearchColumnEventArgs(searchItem, context, column); + setterArgs.value = LightUnit.Lux; + column.setter(setterArgs); + + Assert.AreEqual(LightUnit.Lux, m_Light.lightUnit, "Setter should update light unit"); + } + + [Test] + public void LightIntensityUnit_Column_CellCreator_CreatesValidElement() + { + var column = new SearchColumn("test", "test", "test"); + HDLightingSearchSelectors.LightIntensityUnitSearchColumnProvider(column); + + var element = column.cellCreator(column); + Assert.IsNotNull(element, "Cell creator should return a valid element"); + Assert.IsInstanceOf(element, "Should create an EnumField"); + } + + [Test] + public void LightIntensityUnit_Column_HandlesInvalidSetter() + { + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + HDLightingSearchSelectors.LightIntensityUnitSearchColumnProvider(column); + + var initialUnit = m_Light.lightUnit; + + var setterArgs = new SearchColumnEventArgs(searchItem, context, column); + setterArgs.value = null; + column.setter(setterArgs); + + Assert.AreEqual(initialUnit, m_Light.lightUnit, "Light unit should not change when setting null"); + + setterArgs.value = "invalid"; + column.setter(setterArgs); + Assert.AreEqual(initialUnit, m_Light.lightUnit, "Light unit should not change when setting invalid value"); + } + + [Test] + public void LightIntensityUnit_Column_Binder_HandlesDiscLight() + { + m_Light.type = LightType.Disc; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + HDLightingSearchSelectors.LightIntensityUnitSearchColumnProvider(column); + + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + var getterResult = column.getter(searchColumnEventArgs); + + var element = column.cellCreator(column); + var binderArgs = new SearchColumnEventArgs(searchItem, context, column) { value = getterResult }; + Assert.DoesNotThrow(() => column.binder(binderArgs, element), "Binder should not throw for Disc lights"); + + var enumField = (EnumField)element; + Assert.IsTrue(enumField.visible, "EnumField should be visible for Disc lights"); + } + + [Test] + public void LightIntensityUnit_Column_Binder_HandlesTubeLight() + { + m_Light.type = LightType.Tube; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + HDLightingSearchSelectors.LightIntensityUnitSearchColumnProvider(column); + + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + var getterResult = column.getter(searchColumnEventArgs); + + var element = column.cellCreator(column); + var binderArgs = new SearchColumnEventArgs(searchItem, context, column) { value = getterResult }; + Assert.DoesNotThrow(() => column.binder(binderArgs, element), "Binder should not throw for Tube lights"); + + var enumField = (EnumField)element; + Assert.IsTrue(enumField.visible, "EnumField should be visible for Tube lights"); + } + + [Test] + public void LightIntensityUnit_Column_Binder_HandlesRectangleLight() + { + m_Light.type = LightType.Rectangle; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + HDLightingSearchSelectors.LightIntensityUnitSearchColumnProvider(column); + + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + var getterResult = column.getter(searchColumnEventArgs); + + var element = column.cellCreator(column); + var binderArgs = new SearchColumnEventArgs(searchItem, context, column) { value = getterResult }; + Assert.DoesNotThrow(() => column.binder(binderArgs, element), "Binder should not throw for Rectangle lights"); + + var enumField = (EnumField)element; + Assert.IsTrue(enumField.visible, "EnumField should be visible for Rectangle lights"); + } + + [Test] + public void LightIntensityUnit_Column_Binder_HandlesDirectionalLight() + { + m_Light.type = LightType.Directional; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + HDLightingSearchSelectors.LightIntensityUnitSearchColumnProvider(column); + + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + var getterResult = column.getter(searchColumnEventArgs); + + var element = column.cellCreator(column); + var binderArgs = new SearchColumnEventArgs(searchItem, context, column) { value = getterResult }; + Assert.DoesNotThrow(() => column.binder(binderArgs, element), "Binder should not throw for Directional lights"); + + var enumField = (EnumField)element; + Assert.IsTrue(enumField.visible, "EnumField should be visible for Directional lights"); + } + + [Test] + public void LightIntensityUnit_Column_Binder_HandlesPunctualLights() + { + var punctualTypes = new[] { LightType.Point, LightType.Spot }; + + foreach (var lightType in punctualTypes) + { + m_Light.type = lightType; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + HDLightingSearchSelectors.LightIntensityUnitSearchColumnProvider(column); + + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + var getterResult = column.getter(searchColumnEventArgs); + + var element = column.cellCreator(column); + var binderArgs = new SearchColumnEventArgs(searchItem, context, column) { value = getterResult }; + Assert.DoesNotThrow(() => column.binder(binderArgs, element), $"Binder should not throw for {lightType} lights"); + + var enumField = (EnumField)element; + Assert.IsTrue(enumField.visible, $"EnumField should be visible for {lightType} lights"); + } + } + + #endregion + + #region Light Shape Tests + + [Test] + public void LightShape_Column_Configuration_IsValid() + { + m_Light.type = LightType.Rectangle; + + var column = new SearchColumn("test", HDLightingSearchSelectors.k_LightShapePath, "scene"); + HDLightingSearchSelectors.LightShapeSearchColumnProvider(column); + + Assert.IsNotNull(column.getter, "Column should have a getter"); + Assert.IsNotNull(column.setter, "Column should have a setter"); + Assert.IsNotNull(column.cellCreator, "Column should have a cell creator"); + Assert.IsNotNull(column.binder, "Column should have a binder"); + } + + #endregion + + #region Contact Shadows Tests + + [Test] + public void ContactShadows_Column_Getter_ReturnsContactShadowsData() + { + m_HDLightData.useContactShadow.useOverride = true; + m_HDLightData.useContactShadow.@override = true; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + HDLightingSearchSelectors.ContactShadowsSearchColumnProvider(column); + + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + var getterResult = column.getter(searchColumnEventArgs); + Assert.IsNotNull(getterResult, "Getter should return a value"); + Assert.IsTrue(getterResult.GetType().Name.Contains("ContactShadowsData"), "Getter should return ContactShadowsData"); + } + + #endregion + + #region Ray Tracing Mode Tests + + [Test] + public void RayTracingMode_Column_SetterAndGetter_WorkCorrectly() + { + m_MeshRenderer.rayTracingMode = UnityEngine.Experimental.Rendering.RayTracingMode.Static; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + HDLightingSearchSelectors.RayTracingModeSearchColumnProvider(column); + + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + var getterResult = column.getter(searchColumnEventArgs); + Assert.IsNotNull(getterResult, "Getter should return a value"); + Assert.AreEqual(UnityEngine.Experimental.Rendering.RayTracingMode.Static, getterResult, "Getter should return Static"); + + var setterArgs = new SearchColumnEventArgs(searchItem, context, column); + setterArgs.value = UnityEngine.Experimental.Rendering.RayTracingMode.Off; + column.setter(setterArgs); + Assert.AreEqual(UnityEngine.Experimental.Rendering.RayTracingMode.Off, m_MeshRenderer.rayTracingMode, "RayTracingMode should be Off after setting"); + } + + [Test] + public void RayTracingMode_Column_CellCreator_CreatesValidElement() + { + var column = new SearchColumn("test", "test", "test"); + HDLightingSearchSelectors.RayTracingModeSearchColumnProvider(column); + + var element = column.cellCreator(column); + Assert.IsNotNull(element, "Cell creator should return a valid element"); + Assert.IsInstanceOf(element, "Should create an EnumField"); + } + + #endregion + + #region Reflection Probe Resolution Tests + + [Test] + public void ReflectionProbeResolution_Column_Getter_WithHDProbe_ReturnsResolutionData() + { + m_TestGameObject.AddComponent(); + m_TestGameObject.AddComponent(); + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", HDLightingSearchSelectors.k_ReflectionProbeResolutionPath, "scene"); + HDLightingSearchSelectors.ReflectionProbeResolutionSearchColumnProvider(column); + + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + var getterResult = column.getter(searchColumnEventArgs); + + Assert.IsNotNull(getterResult, "Getter should return a value"); + Assert.IsTrue(getterResult.GetType().Name.Contains("ReflectionProbeResolutionData"), "Getter should return ReflectionProbeResolutionData"); + } + + [Test] + public void ReflectionProbeResolution_Column_Getter_WithoutHDProbe_ReturnsNull() + { + var testObj = new GameObject("TestReflectionProbeOnly"); + try + { + testObj.AddComponent(); + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{testObj.GetEntityId().ToString()}"); + searchItem.data = testObj; + + var column = new SearchColumn("test", HDLightingSearchSelectors.k_ReflectionProbeResolutionPath, "scene"); + HDLightingSearchSelectors.ReflectionProbeResolutionSearchColumnProvider(column); + + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + var getterResult = column.getter(searchColumnEventArgs); + + Assert.IsNull(getterResult, "Getter should return null without HDProbe component"); + } + finally + { + Object.DestroyImmediate(testObj); + } + } + + #endregion + + #region Shadow Resolution Tests + + [Test] + public void ShadowResolution_Column_Getter_ReturnsShadowResolutionData() + { + m_HDLightData.shadowResolution.useOverride = true; + m_HDLightData.shadowResolution.level = 2; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + HDLightingSearchSelectors.ShadowResolutionSearchColumnProvider(column); + + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + var getterResult = column.getter(searchColumnEventArgs); + Assert.IsNotNull(getterResult, "Getter should return a value"); + Assert.IsTrue(getterResult.GetType().Name.Contains("ShadowResolutionData"), "Getter should return ShadowResolutionData"); + } + + #endregion + + #region Light Shape Tests + + [Test] + public void LightShape_Column_Getter_ReturnsValue() + { + m_Light.type = LightType.Spot; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + HDLightingSearchSelectors.LightShapeSearchColumnProvider(column); + + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + var getterResult = column.getter(searchColumnEventArgs); + Assert.IsNotNull(getterResult, "Getter should return a value"); + } + + [Test] + public void LightShape_Column_Getter_WithoutLight_ReturnsNull() + { + var testObj = new GameObject("TestNoLight"); + try + { + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{testObj.GetEntityId().ToString()}"); + searchItem.data = testObj; + + var column = new SearchColumn("test", "test", "scene"); + HDLightingSearchSelectors.LightShapeSearchColumnProvider(column); + + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + var getterResult = column.getter(searchColumnEventArgs); + Assert.IsNull(getterResult, "Getter should return null for GameObject without Light component"); + } + finally + { + Object.DestroyImmediate(testObj); + } + } + + [Test] + public void LightShape_Column_Setter_UpdatesSpotLightValue() + { + m_Light.type = LightType.Point; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + HDLightingSearchSelectors.LightShapeSearchColumnProvider(column); + + var setterArgs = new SearchColumnEventArgs(searchItem, context, column); + setterArgs.value = LightType.Spot; + column.setter(setterArgs); + + Assert.AreEqual(LightType.Spot, m_Light.type, "Light should have type Spot after setting"); + } + + [Test] + public void LightShape_Column_Setter_UpdatesAreaLightValue() + { + m_Light.type = LightType.Point; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + HDLightingSearchSelectors.LightShapeSearchColumnProvider(column); + + var setterArgs = new SearchColumnEventArgs(searchItem, context, column); + setterArgs.value = LightType.Rectangle; + column.setter(setterArgs); + Assert.AreEqual(LightType.Rectangle, m_Light.type, "Light should have type Rectangle after setting"); + } + + [Test] + public void LightShape_Column_Setter_RejectsNonApplicableLightTypes() + { + m_Light.type = LightType.Spot; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + HDLightingSearchSelectors.LightShapeSearchColumnProvider(column); + + var setterArgs = new SearchColumnEventArgs(searchItem, context, column); + setterArgs.value = LightType.Point; + column.setter(setterArgs); + Assert.AreEqual(LightType.Spot, m_Light.type, "Light type should not change when setting non-applicable type"); + } + + [Test] + public void LightShape_Column_CellCreator_CreatesValidElement() + { + var column = new SearchColumn("test", "test", "test"); + HDLightingSearchSelectors.LightShapeSearchColumnProvider(column); + + var element = column.cellCreator(column); + Assert.IsNotNull(element, "Cell creator should return a valid element"); + Assert.IsInstanceOf(element, "Should create a VisualElement"); + } + + [Test] + public void LightShape_Column_Binder_HandlesSpotLights() + { + m_Light.type = LightType.Spot; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + HDLightingSearchSelectors.LightShapeSearchColumnProvider(column); + + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + var getterResult = column.getter(searchColumnEventArgs); + + var element = column.cellCreator(column); + var binderArgs = new SearchColumnEventArgs(searchItem, context, column) { value = getterResult }; + Assert.DoesNotThrow(() => column.binder(binderArgs, element), "Binder should not throw for spot lights"); + } + + [Test] + public void LightShape_Column_Binder_HandlesAreaLights() + { + m_Light.type = LightType.Rectangle; + + var sceneProvider = UnityEditor.Search.SearchService.GetProvider("scene"); + var context = UnityEditor.Search.SearchService.CreateContext("scene"); + var searchItem = sceneProvider.CreateItem(context, $"scene:{m_TestGameObject.GetEntityId().ToString()}"); + searchItem.data = m_TestGameObject; + + var column = new SearchColumn("test", "test", "scene"); + HDLightingSearchSelectors.LightShapeSearchColumnProvider(column); + + var searchColumnEventArgs = new SearchColumnEventArgs(searchItem, context, column); + var getterResult = column.getter(searchColumnEventArgs); + + var element = column.cellCreator(column); + var binderArgs = new SearchColumnEventArgs(searchItem, context, column) { value = getterResult }; + Assert.DoesNotThrow(() => column.binder(binderArgs, element), "Binder should not throw for area lights"); + } + + #endregion + + #region Integration Tests + + [Test] + public void AllHDRPColumns_HaveValidConfiguration() + { + var columnTypes = new[] + { + HDLightingSearchSelectors.k_LightIntensityPath, + HDLightingSearchSelectors.k_LightIntensityUnitPath, + HDLightingSearchSelectors.k_ContactShadowsPath, + HDLightingSearchSelectors.k_RayTracingModePath, + HDLightingSearchSelectors.k_ReflectionProbeResolutionPath, + HDLightingSearchSelectors.k_ShadowResolutionPath, + HDLightingSearchSelectors.k_LightShapePath + }; + + foreach (var columnType in columnTypes) + { + var column = new SearchColumn("test", columnType, "test"); + + Assert.DoesNotThrow(() => + { + switch (columnType) + { + case "Light/Intensity": + HDLightingSearchSelectors.LightIntensitySearchColumnProvider(column); + break; + case "Light/IntensityUnit": + HDLightingSearchSelectors.LightIntensityUnitSearchColumnProvider(column); + break; + case "Light/ContactShadows": + HDLightingSearchSelectors.ContactShadowsSearchColumnProvider(column); + break; + case "Renderer/MeshRenderer/RayTracingMode": + HDLightingSearchSelectors.RayTracingModeSearchColumnProvider(column); + break; + case "ReflectionProbe/Resolution": + HDLightingSearchSelectors.ReflectionProbeResolutionSearchColumnProvider(column); + break; + case "Light/ShadowResolution": + HDLightingSearchSelectors.ShadowResolutionSearchColumnProvider(column); + break; + case "Light/Shape": + HDLightingSearchSelectors.LightShapeSearchColumnProvider(column); + break; + } + }, $"Column initialization for {columnType} should not throw"); + + Assert.IsNotNull(column.getter, $"Column {columnType} should have a getter"); + Assert.IsNotNull(column.cellCreator, $"Column {columnType} should have a cell creator"); + Assert.IsNotNull(column.binder, $"Column {columnType} should have a binder"); + Assert.IsNotNull(column.setter, $"Column {columnType} should have a setter"); + } + } + + #endregion + } +} diff --git a/Packages/com.unity.render-pipelines.high-definition/Tests/Editor/HDLightingSearchSelectorsTests.cs.meta b/Packages/com.unity.render-pipelines.high-definition/Tests/Editor/HDLightingSearchSelectorsTests.cs.meta new file mode 100644 index 00000000000..b2479647fc5 --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Tests/Editor/HDLightingSearchSelectorsTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 503a929537e5247999f0a8f5743d1905 \ No newline at end of file From 4147bba89dbfa01bce1eccc43aed0effc79daaf4 Mon Sep 17 00:00:00 2001 From: Esmeralda Salamone Date: Sat, 14 Feb 2026 15:46:27 +0000 Subject: [PATCH 14/92] [ShaderGraph] Shader Reflection Integration --- .../Documentation~/filter.yml | 3 + .../Data/Graphs/ColorRGBMaterialSlot.cs | 2 + .../Editor/Data/Graphs/MaterialSlot.cs | 7 + .../Data/Graphs/Vector1MaterialEnumSlot.cs | 25 +- .../Data/Graphs/Vector1MaterialIntegerSlot.cs | 19 +- .../Data/Graphs/Vector1MaterialRangeSlot.cs | 18 + .../Data/Implementation/IHasDependencies.cs | 8 + .../Editor/Data/Nodes/SlotValue.cs | 5 +- .../Data/Nodes/Utility/CustomFunctionNode.cs | 2 +- .../Editor/Data/Nodes/Utility/SubGraphNode.cs | 1 + .../Editor/Data/Util/SlotValueTypeUtil.cs | 7 +- .../Editor/Drawing/MaterialGraphEditWindow.cs | 19 +- .../Editor/Drawing/PreviewManager.cs | 2 +- .../Editor/Drawing/SearchWindowProvider.cs | 27 +- .../Editor/Drawing/Views/MaterialGraphView.cs | 11 + .../Editor/Drawing/Views/MaterialNodeView.cs | 26 +- .../Views/Slots/ColorRGBSlotControlView.cs | 9 +- .../Generation/Enumerations/PropertyType.cs | 3 +- .../Editor/ProviderSystem.meta | 8 + .../ProviderSystem/CommonShaderObjects.cs | 61 + .../CommonShaderObjects.cs.meta | 2 + .../ProviderSystem/IDefinitionProvider.cs | 51 + .../IDefinitionProvider.cs.meta | 2 + .../Editor/ProviderSystem/Model.meta | 8 + .../Model/ExternalMaterialSlot.cs | 69 + .../Model/ExternalMaterialSlot.cs.meta | 2 + .../ProviderSystem/Model/FunctionHeader.cs | 72 + .../Model/FunctionHeader.cs.meta | 2 + .../ProviderSystem/Model/HeaderUtils.cs | 322 +++++ .../ProviderSystem/Model/HeaderUtils.cs.meta | 2 + .../ProviderSystem/Model/ParameterHeader.cs | 219 +++ .../Model/ParameterHeader.cs.meta | 2 + .../ProviderSystem/Model/ProviderNode.cs | 285 ++++ .../ProviderSystem/Model/ProviderNode.cs.meta | 2 + .../Model/ProviderNodePropertyDrawer.cs | 50 + .../Model/ProviderNodePropertyDrawer.cs.meta | 2 + .../Editor/ProviderSystem/ProviderLibrary.cs | 98 ++ .../ProviderSystem/ProviderLibrary.cs.meta | 2 + .../Editor/ProviderSystem/Reflection.meta | 8 + .../Reflection/ReflectedFunctionProvider.cs | 60 + .../ReflectedFunctionProvider.cs.meta | 2 + .../ShaderReflectionAssetPostProcessor.cs | 37 + ...ShaderReflectionAssetPostProcessor.cs.meta | 2 + .../Reflection/ShaderReflectionUtils.cs | 56 + .../Reflection/ShaderReflectionUtils.cs.meta | 2 + .../ProviderSystem/ShaderObjectUtils.cs | 58 + .../ProviderSystem/ShaderObjectUtils.cs.meta | 2 + .../Tests/Editor/ProviderTests.meta | 8 + .../ProviderTests/ReflectedFunctionTests.cs | 76 + .../ReflectedFunctionTests.cs.meta | 2 + .../Tests/Editor/ProviderTests/TestUtils.cs | 140 ++ .../Editor/ProviderTests/TestUtils.cs.meta | 2 + .../Graphs/ProviderSystem/AllHints.hlsl | 110 ++ .../Graphs/ProviderSystem/AllHints.hlsl.meta | 7 + .../ShouldCompileProperlyOnImport.shadergraph | 1247 +++++++++++++++++ ...ldCompileProperlyOnImport.shadergraph.meta | 20 + 56 files changed, 3270 insertions(+), 24 deletions(-) create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem.meta create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/CommonShaderObjects.cs create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/CommonShaderObjects.cs.meta create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/IDefinitionProvider.cs create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/IDefinitionProvider.cs.meta create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/Model.meta create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ExternalMaterialSlot.cs create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ExternalMaterialSlot.cs.meta create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/FunctionHeader.cs create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/FunctionHeader.cs.meta create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/HeaderUtils.cs create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/HeaderUtils.cs.meta create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ParameterHeader.cs create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ParameterHeader.cs.meta create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ProviderNode.cs create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ProviderNode.cs.meta create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ProviderNodePropertyDrawer.cs create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ProviderNodePropertyDrawer.cs.meta create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/ProviderLibrary.cs create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/ProviderLibrary.cs.meta create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection.meta create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ReflectedFunctionProvider.cs create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ReflectedFunctionProvider.cs.meta create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ShaderReflectionAssetPostProcessor.cs create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ShaderReflectionAssetPostProcessor.cs.meta create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ShaderReflectionUtils.cs create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ShaderReflectionUtils.cs.meta create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/ShaderObjectUtils.cs create mode 100644 Packages/com.unity.shadergraph/Editor/ProviderSystem/ShaderObjectUtils.cs.meta create mode 100644 Packages/com.unity.shadergraph/Tests/Editor/ProviderTests.meta create mode 100644 Packages/com.unity.shadergraph/Tests/Editor/ProviderTests/ReflectedFunctionTests.cs create mode 100644 Packages/com.unity.shadergraph/Tests/Editor/ProviderTests/ReflectedFunctionTests.cs.meta create mode 100644 Packages/com.unity.shadergraph/Tests/Editor/ProviderTests/TestUtils.cs create mode 100644 Packages/com.unity.shadergraph/Tests/Editor/ProviderTests/TestUtils.cs.meta create mode 100644 Tests/SRPTests/Projects/ShaderGraph/Assets/Testing/IntegrationTests/Graphs/ProviderSystem/AllHints.hlsl create mode 100644 Tests/SRPTests/Projects/ShaderGraph/Assets/Testing/IntegrationTests/Graphs/ProviderSystem/AllHints.hlsl.meta create mode 100644 Tests/SRPTests/Projects/ShaderGraph/Assets/Testing/IntegrationTests/Graphs/ProviderSystem/ShouldCompileProperlyOnImport.shadergraph create mode 100644 Tests/SRPTests/Projects/ShaderGraph/Assets/Testing/IntegrationTests/Graphs/ProviderSystem/ShouldCompileProperlyOnImport.shadergraph.meta diff --git a/Packages/com.unity.shadergraph/Documentation~/filter.yml b/Packages/com.unity.shadergraph/Documentation~/filter.yml index 3ac4bbb0de0..a5a6ad3bd4b 100644 --- a/Packages/com.unity.shadergraph/Documentation~/filter.yml +++ b/Packages/com.unity.shadergraph/Documentation~/filter.yml @@ -2,3 +2,6 @@ apiRules: - exclude: uidRegex: ^UnityEditor\.ShaderGraph\.Internal\.UVChannel$ type: Enum + - exclude: + uidRegex: ^UnityEditor\.ShaderGraph\.Internal\.PropertyType$ + type: Enum \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Editor/Data/Graphs/ColorRGBMaterialSlot.cs b/Packages/com.unity.shadergraph/Editor/Data/Graphs/ColorRGBMaterialSlot.cs index f934c613be3..dbebd598120 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Graphs/ColorRGBMaterialSlot.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Graphs/ColorRGBMaterialSlot.cs @@ -34,6 +34,8 @@ public ColorRGBMaterialSlot( m_DefaultColor = value; } + internal override bool canHideConnector => true; + public ColorMode colorMode { get { return m_ColorMode; } diff --git a/Packages/com.unity.shadergraph/Editor/Data/Graphs/MaterialSlot.cs b/Packages/com.unity.shadergraph/Editor/Data/Graphs/MaterialSlot.cs index 896f03e0d56..5de12e31da4 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Graphs/MaterialSlot.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Graphs/MaterialSlot.cs @@ -231,6 +231,8 @@ public static MaterialSlot CreateMaterialSlot( return new BooleanMaterialSlot(slotId, displayName, shaderOutputName, slotType, false, shaderStageCapability, hidden); case SlotValueType.PropertyConnectionState: return new PropertyConnectionStateMaterialSlot(slotId, displayName, shaderOutputName, slotType, shaderStageCapability, hidden); + case SlotValueType.External: + return new ProviderSystem.ExternalMaterialSlot(slotId, displayName, shaderOutputName, "ERROR_TYPE", slotType); } throw new ArgumentOutOfRangeException("type", type, null); @@ -352,6 +354,11 @@ public bool IsCompatibleWith(MaterialSlot otherSlot, out bool requiresLiteralMod res = this is IMaterialSlotSupportsLiteralMode { LiteralMode: true }; } requiresLiteralMode = !res; + + if (res && (this is ProviderSystem.INeedsExplicitCompatibilityTest || otherSlot is ProviderSystem.INeedsExplicitCompatibilityTest)) + { + res = ProviderSystem.INeedsExplicitCompatibilityTest.TestExplicitCompatibility(this, otherSlot); + } return res; } diff --git a/Packages/com.unity.shadergraph/Editor/Data/Graphs/Vector1MaterialEnumSlot.cs b/Packages/com.unity.shadergraph/Editor/Data/Graphs/Vector1MaterialEnumSlot.cs index 13912f3330c..61255e09051 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Graphs/Vector1MaterialEnumSlot.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Graphs/Vector1MaterialEnumSlot.cs @@ -20,6 +20,23 @@ class Vector1MaterialEnumSlot : Vector1MaterialSlot internal Vector1MaterialEnumSlot() { } + public Vector1MaterialEnumSlot( + int slotId, + string displayName, + string shaderOutputName, + SlotType slotType, + IEnumerable options, + float value, // should match a value in the options. + ShaderStageCapability stageCapability = ShaderStageCapability.All, + bool hidden = false) + : base(slotId, displayName, shaderOutputName, slotType, value, stageCapability: stageCapability, hidden: hidden) + { + this.options = new(options); + this.values = new(); + for (int i = 0; i < this.options.Count; ++i) + values.Add(i); + } + internal Vector1MaterialEnumSlot(int slotId, Vector1ShaderProperty fromProperty) : base(slotId, fromProperty) { @@ -50,9 +67,13 @@ public EnumSlotControlView(Vector1MaterialEnumSlot slot) { m_Slot = slot; + int idx = m_Slot.values.FindIndex(e => e == (int)slot.value); + if (idx < 0 || idx >= slot.options.Count) + idx = 0; + var dropdownField = slot.hideConnector - ? new DropdownField(slot.RawDisplayName(), slot.options, 0) - : new DropdownField(slot.options, 0); + ? new DropdownField(slot.RawDisplayName(), slot.options, idx) + : new DropdownField(slot.options, idx); dropdownField.RegisterValueChangedCallback(OnValueChange); Add(dropdownField); diff --git a/Packages/com.unity.shadergraph/Editor/Data/Graphs/Vector1MaterialIntegerSlot.cs b/Packages/com.unity.shadergraph/Editor/Data/Graphs/Vector1MaterialIntegerSlot.cs index 974031ad947..90e5d8c191c 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Graphs/Vector1MaterialIntegerSlot.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Graphs/Vector1MaterialIntegerSlot.cs @@ -15,6 +15,23 @@ internal Vector1MaterialIntegerSlot() { } internal Vector1MaterialIntegerSlot(int slotId, Vector1ShaderProperty property) : base(slotId, property) { } + [SerializeField] + bool m_unsigned = false; + + public Vector1MaterialIntegerSlot( + int slotId, + string displayName, + string shaderOutputName, + SlotType slotType, + float value, + ShaderStageCapability stageCapability = ShaderStageCapability.All, + bool hidden = false, + bool unsigned = false) + : base(slotId, displayName, shaderOutputName, slotType, value, stageCapability: stageCapability, hidden: hidden) + { + m_unsigned = unsigned; + } + public override VisualElement InstantiateControl() { return new IntegerSlotControlView(this); @@ -47,7 +64,7 @@ void OnValueChange(ChangeEvent evt) if (evt.newValue != m_Slot.value) { m_Slot.owner.owner.owner.RegisterCompleteObjectUndo("Integer Change"); - m_Slot.value = evt.newValue; + m_Slot.value = m_Slot.m_unsigned ? (uint)evt.newValue : (int)evt.newValue; m_Slot.owner.Dirty(ModificationScope.Node); } } diff --git a/Packages/com.unity.shadergraph/Editor/Data/Graphs/Vector1MaterialRangeSlot.cs b/Packages/com.unity.shadergraph/Editor/Data/Graphs/Vector1MaterialRangeSlot.cs index e6dd500c8e3..239128f4d1f 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Graphs/Vector1MaterialRangeSlot.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Graphs/Vector1MaterialRangeSlot.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using UnityEditor.Graphing; using UnityEditor.ShaderGraph.Internal; using UnityEngine; @@ -20,6 +21,21 @@ class Vector1MaterialRangeSlot : Vector1MaterialSlot internal Vector1MaterialRangeSlot() { } + public Vector1MaterialRangeSlot( + int slotId, + string displayName, + string shaderOutputName, + SlotType slotType, + float value, + Vector2 range, + ShaderStageCapability stageCapability = ShaderStageCapability.All, + bool hidden = false) + : base(slotId, displayName, shaderOutputName, slotType, value, stageCapability: stageCapability, hidden: hidden) + { + this.m_sliderRange = range; + } + + internal Vector1MaterialRangeSlot(int slotId, Vector1ShaderProperty fromProperty) : base(slotId, fromProperty) { @@ -56,6 +72,8 @@ public SliderSlotControlView(Vector1MaterialRangeSlot slot) ? new Slider(m_Slot.RawDisplayName(), m_Slot.m_sliderRange.x, m_Slot.m_sliderRange.y) : new Slider(m_Slot.m_sliderRange.x, m_Slot.m_sliderRange.y); + sliderField.value = slot.value; + sliderField.RegisterValueChangedCallback(OnValueChange); diff --git a/Packages/com.unity.shadergraph/Editor/Data/Implementation/IHasDependencies.cs b/Packages/com.unity.shadergraph/Editor/Data/Implementation/IHasDependencies.cs index fd13982ff73..c1f2c014c0f 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Implementation/IHasDependencies.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Implementation/IHasDependencies.cs @@ -6,4 +6,12 @@ interface IHasDependencies { void GetSourceAssetDependencies(AssetCollection assetCollection); } + + interface IHasAssetDependencies + { + // Returns true if the implementing object needed to reload. + // This allows the owning model to escalate whether the node + // should be updated or not. + bool Reload(HashSet changedAssetGuids); + } } diff --git a/Packages/com.unity.shadergraph/Editor/Data/Nodes/SlotValue.cs b/Packages/com.unity.shadergraph/Editor/Data/Nodes/SlotValue.cs index 5a1d31e6ae3..4df345424cb 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Nodes/SlotValue.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Nodes/SlotValue.cs @@ -26,6 +26,7 @@ enum SlotValueType Boolean, VirtualTexture, PropertyConnectionState, + External } enum ConcreteSlotValueType @@ -45,7 +46,8 @@ enum ConcreteSlotValueType Vector1, Boolean, VirtualTexture, - PropertyConnectionState + PropertyConnectionState, + External } // This enum must match ConcreteSlotValueType enum and is used to give friendly name in the enum popup used for custom function @@ -221,6 +223,7 @@ public static bool AreCompatible(SlotValueType inputType, ConcreteSlotValueType {ConcreteSlotValueType.SamplerState, new List() {SlotValueType.SamplerState}}, {ConcreteSlotValueType.Gradient, new List() {SlotValueType.Gradient}}, {ConcreteSlotValueType.VirtualTexture, new List() {SlotValueType.VirtualTexture}}, + {ConcreteSlotValueType.External, new List() {SlotValueType.External}}, }; } diff --git a/Packages/com.unity.shadergraph/Editor/Data/Nodes/Utility/CustomFunctionNode.cs b/Packages/com.unity.shadergraph/Editor/Data/Nodes/Utility/CustomFunctionNode.cs index 5b1d223cffa..77236515a48 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Nodes/Utility/CustomFunctionNode.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Nodes/Utility/CustomFunctionNode.cs @@ -13,7 +13,7 @@ namespace UnityEditor.ShaderGraph { [HasDependencies(typeof(MinimalCustomFunctionNode))] [Title("Utility", "Custom Function")] - class CustomFunctionNode : AbstractMaterialNode, IGeneratesBodyCode, IGeneratesFunction, IMayRequireTransform + class CustomFunctionNode : AbstractMaterialNode, IGeneratesBodyCode, IGeneratesFunction, IMayRequireTransform, IHasAssetDependencies { // 0 original version // 1 differentiate between struct-based UnityTexture2D and bare Texture2D resources (for all texture and samplerstate resources) diff --git a/Packages/com.unity.shadergraph/Editor/Data/Nodes/Utility/SubGraphNode.cs b/Packages/com.unity.shadergraph/Editor/Data/Nodes/Utility/SubGraphNode.cs index 7c4f7623d5d..28f5e7f0055 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Nodes/Utility/SubGraphNode.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Nodes/Utility/SubGraphNode.cs @@ -14,6 +14,7 @@ class SubGraphNode : AbstractMaterialNode , IGeneratesBodyCode , IOnAssetEnabled , IGeneratesFunction + , IHasAssetDependencies , IMayRequireNormal , IMayRequireTangent , IMayRequireBitangent diff --git a/Packages/com.unity.shadergraph/Editor/Data/Util/SlotValueTypeUtil.cs b/Packages/com.unity.shadergraph/Editor/Data/Util/SlotValueTypeUtil.cs index 1d27e68472d..f33e9ba6c22 100644 --- a/Packages/com.unity.shadergraph/Editor/Data/Util/SlotValueTypeUtil.cs +++ b/Packages/com.unity.shadergraph/Editor/Data/Util/SlotValueTypeUtil.cs @@ -42,6 +42,8 @@ public static SlotValueType ToSlotValueType(this ConcreteSlotValueType concreteV return SlotValueType.VirtualTexture; case ConcreteSlotValueType.PropertyConnectionState: return SlotValueType.PropertyConnectionState; + case ConcreteSlotValueType.External: + return SlotValueType.External; default: throw new ArgumentOutOfRangeException(); } @@ -124,6 +126,8 @@ public static PropertyType ToPropertyType(this ConcreteSlotValueType concreteVal return PropertyType.VirtualTexture; case ConcreteSlotValueType.PropertyConnectionState: return PropertyType.PropertyConnectionState; + case ConcreteSlotValueType.External: + return PropertyType.External; default: throw new ArgumentOutOfRangeException(); } @@ -196,7 +200,8 @@ public static string ToClassName(this ConcreteSlotValueType type) "typeFloat1", "typeBoolean", "typeVirtualTexture", - "typePropertyConnectionState" + "typePropertyConnectionState", + "typeExternal" }; } } diff --git a/Packages/com.unity.shadergraph/Editor/Drawing/MaterialGraphEditWindow.cs b/Packages/com.unity.shadergraph/Editor/Drawing/MaterialGraphEditWindow.cs index e94e9860915..f1c641c2a53 100644 --- a/Packages/com.unity.shadergraph/Editor/Drawing/MaterialGraphEditWindow.cs +++ b/Packages/com.unity.shadergraph/Editor/Drawing/MaterialGraphEditWindow.cs @@ -323,12 +323,14 @@ void Update() } } - var subGraphNodes = graphObject.graph.GetNodes(); - foreach (var subGraphNode in subGraphNodes) + var nodesWithDependencies = graphObject.graph.GetNodes(); + foreach (var node in nodesWithDependencies) { - var reloaded = subGraphNode.Reload(m_ChangedFileDependencyGUIDs); + var reloaded = node.Reload(m_ChangedFileDependencyGUIDs); reloadedSomething |= reloaded; } + + var subGraphNodes = graphObject.graph.GetNodes(); if (subGraphNodes.Count() > 0) { // Keywords always need to be updated to test against variant limit @@ -339,11 +341,6 @@ void Update() UpdateDropdownEntries(); materialGraph.OnDropdownChanged(); } - foreach (var customFunctionNode in graphObject.graph.GetNodes()) - { - var reloaded = customFunctionNode.Reload(m_ChangedFileDependencyGUIDs); - reloadedSomething |= reloaded; - } // reloading files may change serialization if (reloadedSomething) @@ -404,6 +401,12 @@ public void ReloadSubGraphsOnNextUpdate(List changedFileGUIDs) } } + public void NotifyDependencyUpdated(IEnumerable guids) + { + foreach (var guid in guids) + m_ChangedFileDependencyGUIDs.Add(guid.ToString()); + } + void UpdateDropdownEntries() { var subGraphNodes = graphObject.graph.GetNodes(); diff --git a/Packages/com.unity.shadergraph/Editor/Drawing/PreviewManager.cs b/Packages/com.unity.shadergraph/Editor/Drawing/PreviewManager.cs index 5528667d9c6..19780d548b0 100644 --- a/Packages/com.unity.shadergraph/Editor/Drawing/PreviewManager.cs +++ b/Packages/com.unity.shadergraph/Editor/Drawing/PreviewManager.cs @@ -933,7 +933,7 @@ void KickOffShaderCompilations() Assert.IsNotNull(node); Assert.IsFalse(node is BlockNode); - if (node.hasPreview && node.previewExpanded && !m_PreviewsCompiling.Contains(preview)) + if (node.hasPreview && node.previewExpanded && !m_PreviewsCompiling.Contains(preview) && MaterialNodeView.IsPreviewable(node)) { previewsToCompile.Add(preview); } diff --git a/Packages/com.unity.shadergraph/Editor/Drawing/SearchWindowProvider.cs b/Packages/com.unity.shadergraph/Editor/Drawing/SearchWindowProvider.cs index 91edeaed698..540742824f1 100644 --- a/Packages/com.unity.shadergraph/Editor/Drawing/SearchWindowProvider.cs +++ b/Packages/com.unity.shadergraph/Editor/Drawing/SearchWindowProvider.cs @@ -1,17 +1,16 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using UnityEditor.Graphing; using UnityEditor.Graphing.Util; using UnityEngine; -using UnityEditor.UIElements; using UnityEditor.Experimental.GraphView; using UnityEngine.UIElements; using UnityEditor.Searcher; using UnityEngine.Profiling; using UnityEngine.Pool; using Object = UnityEngine.Object; +using UnityEditor.ShaderGraph.ProviderSystem; namespace UnityEditor.ShaderGraph.Drawing { @@ -205,6 +204,26 @@ public void GenerateNodeEntries() } Profiler.EndSample(); + Profiler.BeginSample("SearchWindowProvider.GenerateNodeEntries.IterateProviders"); + HashSet providerCollisions = new(); + foreach (var provider in ProviderLibrary.Instance.AllProvidersByType()) + { + var node = new ProviderNode(); + node.InitializeFromProvider(provider); + var header = node.Header; + + string rawTitle = $"{header.category}/{header.uniqueName}"; + + int orderFound = 0; + while (providerCollisions.Contains(rawTitle)) + rawTitle += $", ({++orderFound})"; + + providerCollisions.Add(rawTitle); + + var title = new List(rawTitle.Split('/')); + AddEntries(node, title.ToArray(), nodeEntries); + } + Profiler.EndSample(); Profiler.BeginSample("SearchWindowProvider.GenerateNodeEntries.IterateGraphInputs"); foreach (var property in m_Graph.properties) @@ -455,6 +474,10 @@ public AbstractMaterialNode CopyNodeForGraph(AbstractMaterialNode oldNode) { newNode.ChangeVersion(oldNode.sgVersion); } + if (newNode is ProviderNode providerNode) + { + providerNode.InitializeFromProvider(((ProviderNode)oldNode).Provider); + } if (newNode is SubGraphNode subgraphNode) { subgraphNode.asset = ((SubGraphNode)oldNode).asset; diff --git a/Packages/com.unity.shadergraph/Editor/Drawing/Views/MaterialGraphView.cs b/Packages/com.unity.shadergraph/Editor/Drawing/Views/MaterialGraphView.cs index 1175f117473..579163b921c 100644 --- a/Packages/com.unity.shadergraph/Editor/Drawing/Views/MaterialGraphView.cs +++ b/Packages/com.unity.shadergraph/Editor/Drawing/Views/MaterialGraphView.cs @@ -337,6 +337,17 @@ public override void BuildContextualMenu(ContextualMenuPopulateEvent evt) evt.menu.AppendSeparator(); evt.menu.AppendAction("Open Sub Graph", OpenSubGraph, (a) => DropdownMenuAction.Status.Normal); } + if (selection.OfType().Count() == 1 && selection.OfType().First().node is ProviderSystem.ProviderNode providerNode && providerNode.isValid) + { + evt.menu.AppendSeparator(); + + void PingSource(DropdownMenuAction action) + { + var asset = AssetDatabase.LoadAssetByGUID(providerNode.Provider.AssetID); + EditorGUIUtility.PingObject(asset); + } + evt.menu.AppendAction("Show Source in Project", PingSource, (a) => DropdownMenuAction.Status.Normal); + } } evt.menu.AppendSeparator(); if (evt.target is StickyNote) diff --git a/Packages/com.unity.shadergraph/Editor/Drawing/Views/MaterialNodeView.cs b/Packages/com.unity.shadergraph/Editor/Drawing/Views/MaterialNodeView.cs index 731a2941a75..aeaabeed12c 100644 --- a/Packages/com.unity.shadergraph/Editor/Drawing/Views/MaterialNodeView.cs +++ b/Packages/com.unity.shadergraph/Editor/Drawing/Views/MaterialNodeView.cs @@ -6,13 +6,10 @@ using UnityEditor.Graphing; using UnityEditor.Graphing.Util; using UnityEditor.ShaderGraph.Drawing.Controls; -using UnityEngine.Rendering; using UnityEditor.Experimental.GraphView; using UnityEditor.Rendering; using UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers; -using UnityEditor.ShaderGraph.Internal; using UnityEngine.UIElements; -using UnityEditor.UIElements; using Node = UnityEditor.Experimental.GraphView.Node; namespace UnityEditor.ShaderGraph.Drawing @@ -73,7 +70,7 @@ public void Initialize(AbstractMaterialNode inNode, PreviewManager previewManage foreach (IControlAttribute attribute in propertyInfo.GetCustomAttributes(typeof(IControlAttribute), false)) m_ControlItems.Add(attribute.InstantiateControl(node, propertyInfo)); } - if (m_ControlItems.childCount > 0 || inNode is SubGraphNode) + if (m_ControlItems.childCount > 0 || inNode is SubGraphNode || inNode is ProviderSystem.ProviderNode) contents.Add(controlsContainer); // Add dropdowns container @@ -153,6 +150,10 @@ public void Initialize(AbstractMaterialNode inNode, PreviewManager previewManage RegisterCallback(OnSubGraphDoubleClick); m_UnregisterAll += () => { UnregisterCallback(OnSubGraphDoubleClick); }; break; + case ProviderSystem.ProviderNode: + RegisterCallback(OnProviderDoubleClick); + m_UnregisterAll += () => { UnregisterCallback(OnProviderDoubleClick); }; + break; } m_TitleContainer = this.Q("title"); @@ -340,6 +341,21 @@ void OnSubGraphDoubleClick(MouseDownEvent evt) } } + void OnProviderDoubleClick(MouseDownEvent evt) + { + if (evt.clickCount == 2 && evt.button == 0) + { + var providerNode = node as ProviderSystem.ProviderNode; + if (providerNode.Provider.IsValid && providerNode.Provider.AssetID != default) + { + var path = AssetDatabase.GUIDToAssetPath(providerNode.Provider.AssetID); + GraphUtil.OpenFile(path); + } + // Stop the double click event from starting a drag action on the node + evt.StopImmediatePropagation(); + } + } + public Node gvNode => this; [Inspectable("Node", null)] @@ -485,7 +501,7 @@ public bool CanToggleNodeExpanded() return !(node is BlockNode) && m_CollapseButton.enabledInHierarchy; } - static bool IsPreviewable(AbstractMaterialNode node) + internal static bool IsPreviewable(AbstractMaterialNode node) { // only the first output slot is considered. foreach (var slot in node.GetOutputSlots()) diff --git a/Packages/com.unity.shadergraph/Editor/Drawing/Views/Slots/ColorRGBSlotControlView.cs b/Packages/com.unity.shadergraph/Editor/Drawing/Views/Slots/ColorRGBSlotControlView.cs index f47522c2ee7..e34f7e02567 100644 --- a/Packages/com.unity.shadergraph/Editor/Drawing/Views/Slots/ColorRGBSlotControlView.cs +++ b/Packages/com.unity.shadergraph/Editor/Drawing/Views/Slots/ColorRGBSlotControlView.cs @@ -13,7 +13,10 @@ class ColorRGBSlotControlView : VisualElement public ColorRGBSlotControlView(ColorRGBMaterialSlot slot) { - styleSheets.Add(Resources.Load("Styles/Controls/ColorRGBSlotControlView")); + if (!slot.hideConnector) + styleSheets.Add(Resources.Load("Styles/Controls/ColorRGBSlotControlView")); + else styleSheets.Add(Resources.Load("Styles/Controls/ColorControlView")); + m_Slot = slot; var colorField = new ColorField { @@ -22,6 +25,10 @@ public ColorRGBSlotControlView(ColorRGBMaterialSlot slot) showAlpha = false, hdr = (slot.colorMode == ColorMode.HDR) }; + + if (slot.hideConnector) + colorField.label = slot.RawDisplayName(); + colorField.RegisterValueChangedCallback(OnValueChanged); Add(colorField); } diff --git a/Packages/com.unity.shadergraph/Editor/Generation/Enumerations/PropertyType.cs b/Packages/com.unity.shadergraph/Editor/Generation/Enumerations/PropertyType.cs index 023dc664de8..e09fd2dcc30 100644 --- a/Packages/com.unity.shadergraph/Editor/Generation/Enumerations/PropertyType.cs +++ b/Packages/com.unity.shadergraph/Editor/Generation/Enumerations/PropertyType.cs @@ -19,6 +19,7 @@ public enum PropertyType Matrix4, SamplerState, VirtualTexture, - PropertyConnectionState + PropertyConnectionState, + External } } diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem.meta b/Packages/com.unity.shadergraph/Editor/ProviderSystem.meta new file mode 100644 index 00000000000..a0fcb5ee341 --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a732a096a67254fb5a6d30afa8148e42 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/CommonShaderObjects.cs b/Packages/com.unity.shadergraph/Editor/ProviderSystem/CommonShaderObjects.cs new file mode 100644 index 00000000000..a5bc838e3cf --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/CommonShaderObjects.cs @@ -0,0 +1,61 @@ + +using System.Collections.Immutable; +using System.Collections.Generic; + +namespace UnityEditor.ShaderGraph.ProviderSystem +{ + internal struct ShaderType : IShaderType + { + public bool IsValid { get; private set; } + public string Name { get; private set; } + internal ShaderType(string name) + { + IsValid = true; + Name = name; + } + } + + internal struct ShaderField : IShaderField + { + public bool IsValid { get; private set; } + public string Name { get; private set; } + public bool IsInput { get; private set; } + public bool IsOutput { get; private set; } + public IShaderType ShaderType { get; private set; } + public IReadOnlyDictionary Hints { get; private set; } + + + internal ShaderField(string name, bool isInput, bool isOutput, IShaderType shaderType, IReadOnlyDictionary hints) + { + IsValid = true; + Name = name; + IsInput = isInput; + IsOutput = isOutput; + ShaderType = shaderType; + Hints = hints ?? ImmutableDictionary.Empty; + } + } + + internal struct ShaderFunction : IShaderFunction + { + public bool IsValid { get; private set; } + public string Name { get; private set; } + public IShaderType ReturnType { get; private set; } + public string FunctionBody { get; private set; } + public IEnumerable Namespace { get; private set; } + public IEnumerable Parameters { get; private set; } + public IReadOnlyDictionary Hints { get; private set; } + + internal ShaderFunction(string name, IEnumerable namespaces, IEnumerable parameters, IShaderType returnType, string functionBody, IReadOnlyDictionary hints) + { + IsValid = true; + Name = name; + ReturnType = returnType; + FunctionBody = functionBody; + + Parameters = parameters ?? ImmutableArray.Empty; + Namespace = namespaces ?? ImmutableArray.Empty; + Hints = hints ?? ImmutableDictionary.Empty; + } + } +} diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/CommonShaderObjects.cs.meta b/Packages/com.unity.shadergraph/Editor/ProviderSystem/CommonShaderObjects.cs.meta new file mode 100644 index 00000000000..32e5ef34f63 --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/CommonShaderObjects.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 6c992aa7356b6d242ad431b5ab535c19 \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/IDefinitionProvider.cs b/Packages/com.unity.shadergraph/Editor/ProviderSystem/IDefinitionProvider.cs new file mode 100644 index 00000000000..9f00175938d --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/IDefinitionProvider.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using UnityEngine; + +namespace UnityEditor.ShaderGraph.ProviderSystem +{ + // Data needed to represent a valid shader object and supplemental information + // on how this object might be presented in different contexts. + // Shader Object itself is Context and Domain agnostic. + internal interface IShaderObject + { + bool IsValid { get; } + string Name { get; } + IEnumerable Namespace => ImmutableArray.Empty; + IReadOnlyDictionary Hints => ImmutableDictionary.Empty; + } + + internal interface IShaderType : IShaderObject { } + + internal interface IShaderField : IShaderObject + { + bool IsInput { get; } + bool IsOutput { get; } + IShaderType ShaderType { get; } + } + + internal interface IShaderFunction : IShaderObject + { + IShaderType ReturnType { get; } + string FunctionBody { get; } + IEnumerable Parameters { get; } + } + + // Abstracts how or where an IShaderObject may be defined, + // allowing for various Domains to use IShaderObjects in a + // context free manner. + internal interface IProvider + { + string ProviderKey { get; } + GUID AssetID { get; } + bool IsValid { get; } + void Reload(); + IProvider Clone(); + } + + internal interface IProvider : IProvider where T : IShaderObject + { + T Definition { get; } + bool IProvider.IsValid => Definition?.IsValid ?? false; + } +} diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/IDefinitionProvider.cs.meta b/Packages/com.unity.shadergraph/Editor/ProviderSystem/IDefinitionProvider.cs.meta new file mode 100644 index 00000000000..bb94e110337 --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/IDefinitionProvider.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8fdab7687958d874e92d2679b0b758da \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model.meta b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model.meta new file mode 100644 index 00000000000..749fb2a7a12 --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ea92addb84cbc48fdb625329928f7b2c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ExternalMaterialSlot.cs b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ExternalMaterialSlot.cs new file mode 100644 index 00000000000..1633a20f8eb --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ExternalMaterialSlot.cs @@ -0,0 +1,69 @@ +using System; +using UnityEngine; +using UnityEditor.Graphing; + +namespace UnityEditor.ShaderGraph.ProviderSystem +{ + interface INeedsExplicitCompatibilityTest + { + bool HasExplicitCompatibility(MaterialSlot other); + + static bool TestExplicitCompatibility(MaterialSlot a, MaterialSlot b) + { + return a is INeedsExplicitCompatibilityTest atester + && b is INeedsExplicitCompatibilityTest btester + && atester.HasExplicitCompatibility(b) + && btester.HasExplicitCompatibility(a); + } + } + + [Serializable] + internal class ExternalMaterialSlot : MaterialSlot, INeedsExplicitCompatibilityTest + { + public string TypeName => m_typeName; + + [SerializeField] + string m_typeName; + + [SerializeField] + string m_rawDefaultValueString; + + public override bool isDefaultValue => throw new System.NotImplementedException(); + + public override SlotValueType valueType => SlotValueType.External; + + public override ConcreteSlotValueType concreteValueType => ConcreteSlotValueType.External; + + public ExternalMaterialSlot() : base() + { + + } + + public ExternalMaterialSlot( + int slotId, + string displayName, + string shaderOutputName, + string typeName, + SlotType slotType, + string rawDefaultValue = null, + ShaderStageCapability stageCapability = ShaderStageCapability.All, + bool hidden = false) + : base(slotId, displayName, shaderOutputName, slotType, stageCapability, hidden) + { + m_typeName = typeName; + m_rawDefaultValueString = rawDefaultValue ?? "0"; + } + + public override void AddDefaultProperty(PropertyCollector properties, GenerationMode generationMode) { } + + public override void CopyValuesFrom(MaterialSlot foundSlot) { } + + public override string GetDefaultValue(GenerationMode generationMode) + { + return $"({TypeName})({m_rawDefaultValueString})"; + } + + public bool HasExplicitCompatibility(MaterialSlot other) + => other is ExternalMaterialSlot externalSlot && externalSlot.TypeName == this.TypeName; + } +} diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ExternalMaterialSlot.cs.meta b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ExternalMaterialSlot.cs.meta new file mode 100644 index 00000000000..d5f341888d2 --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ExternalMaterialSlot.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7372d18840093464cb19d9432af6b71f \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/FunctionHeader.cs b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/FunctionHeader.cs new file mode 100644 index 00000000000..2666b81bdc5 --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/FunctionHeader.cs @@ -0,0 +1,72 @@ + +namespace UnityEditor.ShaderGraph.ProviderSystem +{ + // A "Header" object is an abstraction layer that interprets domain/context-free + // information from a ShaderObject (in this case a function) and translates it into + // domain specific information-- in this case, the Shader Graph tooling and conventions. + internal struct FunctionHeader + { + readonly internal bool isValid; + + readonly internal string referenceName; + readonly internal string displayName; + readonly internal string uniqueName; + readonly internal string tooltip; + + readonly internal IShaderType returnType; + internal bool hasReturnType => returnType.Name != "void"; + readonly internal string returnDisplayName; + + readonly internal string category; + + readonly internal string[] searchTerms; + + internal FunctionHeader(IProvider provider) + { + referenceName = null; + returnType = null; + displayName = null; + category = null; + searchTerms = null; + returnDisplayName = null; + uniqueName = null; + tooltip = null; + + isValid = provider != null && provider.Definition != null; + + if (!isValid) + return; + + var func = provider.Definition; + var path = AssetDatabase.GUIDToAssetPath(provider.AssetID); + + referenceName = func.Name; + returnType = func.ReturnType; + + if (!func.Hints.TryGetValue(Hints.Common.kDisplayName, out displayName)) + displayName = ObjectNames.NicifyVariableName(referenceName); + + if (!func.Hints.TryGetValue(Hints.Func.kSearchName, out uniqueName)) + uniqueName = ShaderObjectUtils.QualifySignature(func, false, true); + + if (func.Hints.TryGetValue(Hints.Func.kCategory, out category)) { } + else if (func.Namespace != null) + { + category = "Reflected by Namespace"; + foreach (var name in func.Namespace) + category += $"/{name}"; + } + else + { + category = $"Reflected by Path/{path}"; + } + + if (func.Hints.TryGetValue(Hints.Func.kSearchName, out var terms)) + searchTerms = HeaderUtils.LazyTokenString(terms); + else searchTerms = new[] { referenceName }; + + if (!func.Hints.TryGetValue(Hints.Func.kReturnDisplayName, out returnDisplayName)) + returnDisplayName = "Out"; + } + } +} diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/FunctionHeader.cs.meta b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/FunctionHeader.cs.meta new file mode 100644 index 00000000000..6546dea4fda --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/FunctionHeader.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a49239ad21003d64db1f49d00da3f871 \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/HeaderUtils.cs b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/HeaderUtils.cs new file mode 100644 index 00000000000..61d8e620104 --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/HeaderUtils.cs @@ -0,0 +1,322 @@ +using UnityEngine; +using UnityEditor.Graphing; +using System.Collections.Generic; + +namespace UnityEditor.ShaderGraph.ProviderSystem +{ + internal static class Hints + { + internal static class Common + { + internal const string kDisplayName = "sg:DisplayName"; + + // Not yet implemented. + internal const string kTooltip = "sg:Tooltip"; // SG doesn't have tooltips + } + internal static class Func + { + internal const string kProviderKey = "sg:ProviderKey"; + + internal const string kReturnDisplayName = "sg:ReturnDisplayName"; + + internal const string kSearchTerms = "sg:SearchTerms"; + internal const string kSearchName = "sg:SearchName"; + internal const string kCategory = "sg:SearchCategory"; + + // Not yet implemented. + internal const string kGroupKey = "sg:GroupKey"; + internal const string kReturnTooltip = "sg:ReturnTooltip"; + internal const string kDocumentationLink = "sg:HelpURL"; + + // ProviderKey associated hints, Not yet implemented. + internal const string kDeprecated = "sg:Deprecated"; + internal const string kObsolete = "sg:Obsolete"; + internal const string kVersion = "sg:Version"; + } + + internal static class Param + { + internal const string kStatic = "sg:Static"; + internal const string kLocal = "sg:Local"; + internal const string kLiteral = "sg:Literal"; + internal const string kColor = "sg:Color"; + internal const string kRange = "sg:Range"; + internal const string kDropdown = "sg:Dropdown"; + internal const string kDefault = "sg:Default"; + + // Not yet implemented. + internal const string kSetting = "sg:Setting"; + internal const string kLinkage = "sg:Linkage"; + internal const string kPrecision = "sg:Precision"; + internal const string kDynamic = "sg:Dynamic"; + internal const string kReferable = "sg:Referable"; + internal const string kExternal = "sg:External"; + + // Hard coded referables, not yet implemented. + internal const string kUV = "sg:ref:UV"; + internal const string kPosition = "sg:ref:Position"; + internal const string kNormal = "sg:ref:Normal"; + internal const string kBitangent = "sg:ref:Bitangent"; + internal const string kTangent = "sg:ref:Tangent"; + internal const string kViewDirection = "sg:ref:ViewDirection"; + internal const string kScreenPosition = "sg:ref:ScreenPosition"; + internal const string kVertexColor = "sg:VertexColor"; + } + } + + internal static class HeaderUtils + { + internal static string ToShaderType(this MaterialSlot slot) + { + if (slot is ExternalMaterialSlot eslot) + return eslot.TypeName; + + return slot.concreteValueType.ToShaderString(); + } + + internal static bool IsNumeric(string typeName) + { + return TryParseTypeInfo(typeName, out _, out _, out _, out _, out _, out _, out _); + } + + internal static bool TryParseTypeInfo( + string type, + out string prim, + out bool isScalar, + out bool isVector, + out bool isMatrix, + out int rows, + out int cols, + out int length) + { + prim = null; + isScalar = false; + isVector = false; + isMatrix = false; + rows = -1; + cols = -1; + length = -1; + + // TODO: Array support isn't established yet, if we support multidim this wouldn't work. + if (type.Contains('[')) + return false; + + + if (type.StartsWith("uint")) prim = "uint"; + if (type.StartsWith("int")) prim = "int"; + if (type.StartsWith("bool")) prim = "bool"; + if (type.StartsWith("half")) prim = "half"; + if (type.StartsWith("float")) prim = "float"; + + if (prim == null) + return false; + + if (type == prim) + return isScalar = true; + + var remainder = type.Substring(prim.Length); + + if (remainder.Length == 1) + { + return isVector = int.TryParse(remainder, out rows) && rows >= 1 && rows <= 4; + } + if (remainder.Length == 3) + { + return isMatrix + = int.TryParse(remainder.Substring(0, 1), out rows) && rows >= 1 && rows <= 4 + && int.TryParse(remainder.Substring(2, 1), out cols) && cols >= 1 && cols <= 4; + } + return false; + } + + internal static bool TryCast(string shaderType, float[] values, out T value, T fallback = default) + { + try + { + return Cast(shaderType, values, out value, fallback); + } + catch + { + value = default; + return false; + } + } + + private static bool Cast(string shaderType, float[] values, out T value, T fallback = default) + { + object obj = default; + value = fallback; + + if (values == null || values.Length == 0) + return false; + + float[] v = new float[16]; + for (int i = 0; i < values.Length; ++i) + v[i] = values[i]; + + if (!TryParseTypeInfo(shaderType, out string prim, out bool isScalar, out bool isVector, out bool isMatrix, out int rows, out int cols, out int length)) + return false; + + if (isScalar || isVector && rows == 1 || isMatrix && rows == 1 && cols == 1) + { + var fv = v[0]; + + switch (prim) + { + case "bool": obj = fv != 0; break; + case "uint": obj = fv; break; + case "int": obj = fv; break; + case "float": + case "half": obj = fv; break; + default: return false; + } + } + if (isVector) + { + switch (rows) + { + case 2: obj = new Vector2(v[0], v[1]); break; + case 3: obj = new Vector3(v[0], v[1], v[2]); break; + case 4: obj = new Vector4(v[0], v[1], v[2], v[3]); break; + default: return false; + } + + } + if (isMatrix) + { + Matrix4x4 m = new(); + for (int i = 0; i < cols * rows; ++i) + { + // TODO: Validate with GTK + m[i % rows + rows * (i / rows)] = v[i]; + } + } + + value = (T)obj; + return true; + } + + internal static MaterialSlot MakeSlotFromParameter(ParameterHeader header, int slotId, SlotType dir) + { + MaterialSlot slot; + + if (header.isDropdown) + { + HeaderUtils.TryCast(header.typeName, header.defaultValue, out var asIdx, 0.0f); + slot = new Vector1MaterialEnumSlot(slotId, header.displayName, header.referenceName, dir, header.options, asIdx); + } + else if (header.isSlider) + { + HeaderUtils.TryCast(header.typeName, header.defaultValue, out var asRng, 0); + slot = new Vector1MaterialRangeSlot(slotId, header.displayName, header.referenceName, dir, asRng, new Vector2(header.sliderMin, header.sliderMax)); + } + else switch (header.typeName) + { + case "uint1": + case "uint": + HeaderUtils.TryCast(header.typeName, header.defaultValue, out var asUint, 0u); + slot = new Vector1MaterialIntegerSlot(slotId, header.displayName, header.referenceName, dir, asUint, unsigned: true); break; + case "int1": + case "int": + HeaderUtils.TryCast(header.typeName, header.defaultValue, out var asInt, 0); + slot = new Vector1MaterialIntegerSlot(slotId, header.displayName, header.referenceName, dir, asInt); break; + case "half": + case "half1": + case "float1": + case "float": + HeaderUtils.TryCast(header.typeName, header.defaultValue, out var asFloat, 0.0f); + slot = new Vector1MaterialSlot(slotId, header.displayName, header.referenceName, dir, asFloat); break; + case "bool1": + case "bool": + HeaderUtils.TryCast(header.typeName, header.defaultValue, out var asBool, false); + slot = new BooleanMaterialSlot(slotId, header.displayName, header.referenceName, dir, asBool); break; + case "half2": + case "float2": + HeaderUtils.TryCast(header.typeName, header.defaultValue, out var asV2, Vector2.zero); + slot = new Vector2MaterialSlot(slotId, header.displayName, header.referenceName, dir, asV2); break; + case "half3": + case "float3": + HeaderUtils.TryCast(header.typeName, header.defaultValue, out var asV3, Vector3.zero); + slot = !header.isColor + ? new Vector3MaterialSlot(slotId, header.displayName, header.referenceName, dir, asV3) + : new ColorRGBMaterialSlot(slotId, header.displayName, header.referenceName, dir, new Vector4(asV3.x, asV3.y, asV3.z, 1), Internal.ColorMode.Default); + break; + case "half4": + case "float4": + HeaderUtils.TryCast(header.typeName, header.defaultValue, out var asV4, header.isColor ? new Vector4(0, 0, 0, 1) : Vector4.zero); + + slot = header.isColor + ? new ColorRGBAMaterialSlot(slotId, header.displayName, header.referenceName, dir, asV4) + : new Vector4MaterialSlot(slotId, header.displayName, header.referenceName, dir, asV4); + + break; + case "half2x2": + case "float2x2": slot = new Matrix2MaterialSlot(slotId, header.displayName, header.referenceName, dir); break; + case "half3x3": + case "float3x3": slot = new Matrix3MaterialSlot(slotId, header.displayName, header.referenceName, dir); break; + case "half4x4": + case "float4x4": slot = new Matrix4MaterialSlot(slotId, header.displayName, header.referenceName, dir); break; + + case "SamplerState": + case "UnitySamplerState": slot = new SamplerStateMaterialSlot(slotId, header.displayName, header.referenceName, dir); break; + case "Texture2D": + case "UnityTexture2D": + slot = dir == SlotType.Input + ? new Texture2DInputMaterialSlot(slotId, header.displayName, header.referenceName) + : new Texture2DMaterialSlot(slotId, header.displayName, header.referenceName, dir); + break; + case "Texture2DArray": + case "UnityTexture2DArray": + slot = dir == SlotType.Input + ? new Texture2DArrayInputMaterialSlot(slotId, header.displayName, header.referenceName) + : new Texture2DArrayMaterialSlot(slotId, header.displayName, header.referenceName, dir); break; + case "TextureCube": + case "UnityTextureCube": + slot = dir == SlotType.Input + ? new CubemapInputMaterialSlot(slotId, header.displayName, header.referenceName) + : new CubemapMaterialSlot(slotId, header.displayName, header.referenceName, dir); break; + case "Texture3D": + case "UnityTexture3D": + slot = dir == SlotType.Input + ? new Texture3DInputMaterialSlot(slotId, header.displayName, header.referenceName) + : new Texture3DMaterialSlot(slotId, header.displayName, header.referenceName, dir); break; + default: + slot = new ExternalMaterialSlot(slotId, header.displayName, header.referenceName, header.externalQualifiedTypeName, dir, header.defaultString); + break; + } + + slot.hideConnector = header.isStatic && header.isInput; + slot.hidden = header.isLocal; + slot.bareResource = header.isBareResource; + return slot; + } + + internal static float[] LazyTokenFloat(string arg) + { + var tokens = LazyTokenize(arg); + List asfloat = new(); + + foreach (var token in tokens) + if (float.TryParse(token, out float r)) + asfloat.Add(r); + + return asfloat.ToArray(); + } + + internal static string[] LazyTokenString(string arg) + { + List tokens = new(LazyTokenize(arg)); + return tokens.ToArray(); + } + + private static IEnumerable LazyTokenize(string arg) + { + foreach (var e in arg.Split(',')) + { + var result = e.Trim(); + if (!string.IsNullOrWhiteSpace(result)) + yield return e.Trim(); + } + } + } +} diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/HeaderUtils.cs.meta b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/HeaderUtils.cs.meta new file mode 100644 index 00000000000..832c0d858df --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/HeaderUtils.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 03da3bc1b8aa9064ea9e97a5eec5f074 \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ParameterHeader.cs b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ParameterHeader.cs new file mode 100644 index 00000000000..430eb31fa7a --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ParameterHeader.cs @@ -0,0 +1,219 @@ + +using System.Collections.Generic; +using System.Text; + +namespace UnityEditor.ShaderGraph.ProviderSystem +{ + internal struct ParameterHeader + { + readonly internal bool isValid; + + readonly internal string referenceName; + readonly internal IShaderType shaderType; + readonly internal string typeName => shaderType.Name; + + readonly internal string displayName; + readonly internal string tooltip; + + readonly internal bool isInput; + readonly internal bool isOutput; + + readonly internal bool isColor; + + readonly internal bool isStatic; + readonly internal bool isLocal; + + readonly internal bool isDropdown; + readonly internal string[] options; + + readonly internal bool isSlider; + readonly internal float sliderMin; + readonly internal float sliderMax; + + readonly internal float[] defaultValue; + readonly internal string defaultString; + + readonly internal string externalQualifiedTypeName; + + readonly internal bool isNumeric; + readonly internal bool isTexture; + readonly internal bool isSampler; + readonly internal bool isStruct; + readonly internal bool isReference; + readonly internal bool isLiteral; + + readonly internal string referable; + + readonly internal bool isBareResource; + + readonly internal string knownIssue; + + private ParameterHeader(int a) + { + referenceName = null; + displayName = null; + shaderType = null; + tooltip = null; + isOutput = true; + isInput = false; + isColor = false; + defaultValue = null; + isStatic = false; + isDropdown = false; + options = null; + isSlider = false; + sliderMin = 0; + sliderMax = 1; + isBareResource = false; + isLocal = false; + isReference = false; + isLiteral = false; + isTexture = false; + isSampler = false; + isNumeric = false; + isStruct = false; + referable = null; + defaultString = null; + knownIssue = null; + externalQualifiedTypeName = null; + + isValid = false; + } + + // this is for return types. + internal ParameterHeader(string referenceName, IShaderType shaderType, string tooltip = null) : this(0) + { + if (string.IsNullOrWhiteSpace(referenceName) || string.IsNullOrWhiteSpace(shaderType.Name)) + { + isValid = false; + return; + } + + this.shaderType = shaderType; + this.referenceName = referenceName; + this.displayName = referenceName; + this.tooltip = tooltip; + + string typeTest = shaderType.Name.ToLowerInvariant(); + + isNumeric = HeaderUtils.TryParseTypeInfo(typeName, out _, out _, out _, out _, out _, out _, out _); + isSampler = typeTest.Contains("sampler"); + isTexture = typeTest.Contains("texture"); + isBareResource = !typeTest.Contains("unity") && (isSampler || isTexture); // special handling case. + isStruct = !isTexture && !isSampler && !isNumeric; + isValid = true; + } + + internal ParameterHeader(IShaderField param, IShaderFunction owner) : this(param?.Name, param?.ShaderType) + { + if (!isValid || param == null) + return; + + isOutput = isInput = false; + isInput = param.IsInput; + isOutput = param.IsOutput; + + if (!param.Hints.TryGetValue(Hints.Common.kDisplayName, out displayName)) + displayName = ObjectNames.NicifyVariableName(referenceName); + + HeaderUtils.TryParseTypeInfo(typeName, out string prim, out bool isScalar, out bool isVector, out bool isMatrix, out int rows, out int cols, out _); + List editorHintsUsed = new(); + + + isLiteral = param.Hints.TryGetValue(Hints.Param.kLiteral, out _); // TODO: Only relevant for int, float, half, uint + + if (param.Hints.TryGetValue(Hints.Param.kExternal, out externalQualifiedTypeName)) + externalQualifiedTypeName += $"::{typeName}"; + else externalQualifiedTypeName = typeName; + + if (param.Hints.TryGetValue(Hints.Param.kColor, out _)) + { + editorHintsUsed.Add(Hints.Param.kColor); + if (rows != 3 && rows != 4 && !isVector) + { + knownIssue = $"'Color' hint on '{referenceName}' is not supported for '{typeName}'."; + } + else isColor = true; + } + + if (param.Hints.TryGetValue(Hints.Param.kStatic, out _)) + { + if (isOutput) + { + knownIssue = $"'Static' hint on '{referenceName}' is not supported for 'out' parameters."; + } + else if (!isScalar && !isColor) + { + knownIssue = $"'Static' hint on '{referenceName}' is not supported for '{typeName}'."; + } + else isStatic = true; + } + + if (param.Hints.TryGetValue(Hints.Param.kLocal, out _)) + { + editorHintsUsed.Add(Hints.Param.kLocal); + if (isStatic) // All Access Modifier style hints would conflict with each other, but we currently only have Local and Static + { + knownIssue = $"'Local' hint on '{referenceName}' conflicts with found 'Static' hint."; + } + else isLocal = true; + } + + if (param.Hints.TryGetValue(Hints.Param.kDropdown, out var dropdownString)) + { + editorHintsUsed.Add(Hints.Param.kDropdown); + options = HeaderUtils.LazyTokenString(dropdownString); + if (!isScalar || prim == "bool") + { + knownIssue = $"'Dropdown' hint on '{referenceName}' is not supported for '{typeName}'."; + } + else if (options.Length == 0) + { + knownIssue = $"'Dropdown' hint on '{referenceName}' has no options."; + } + else isDropdown = true; + } + + if (param.Hints.TryGetValue(Hints.Param.kRange, out var rangeValues)) + { + editorHintsUsed.Add(Hints.Param.kRange); + var values = HeaderUtils.LazyTokenFloat(rangeValues); + + if (!isScalar || prim == "bool") + { + knownIssue = $"'Range' hint on '{referenceName}' is not supported for '{typeName}'."; + } + else if (values.Length != 2 || values[0] == values[1]) + { + knownIssue = $"'Range' hint on '{referenceName}' expects two arguments of different values."; + } + else + { + sliderMin = values[0] < values[1] ? values[0] : values[1]; + sliderMax = values[0] > values[1] ? values[0] : values[1]; + isSlider = true; + } + } + + if (param.Hints.TryGetValue(Hints.Param.kDefault, out defaultString)) + { + defaultValue = HeaderUtils.LazyTokenFloat(defaultString); + } + + if(editorHintsUsed.Count > 1) + { + StringBuilder sb = new(); + bool first = true; + foreach(var hintName in editorHintsUsed) + { + if (!first) + sb.Append(", "); + first = false; + sb.Append($"{hintName}"); + } + + knownIssue = $"Found multiple conflicting editor hints on '{referenceName}': '{sb.ToString()}'."; + } + } + } +} diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ParameterHeader.cs.meta b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ParameterHeader.cs.meta new file mode 100644 index 00000000000..1b207f7b1b7 --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ParameterHeader.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: df1b66f5ce54910438e02c0d87921c4f \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ProviderNode.cs b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ProviderNode.cs new file mode 100644 index 00000000000..9ad3cb6512d --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ProviderNode.cs @@ -0,0 +1,285 @@ +using UnityEngine; +using System.Collections.Generic; +using UnityEditor.Graphing; +using System; + +namespace UnityEditor.ShaderGraph.ProviderSystem +{ + // A Base Node serving as the entry point for Provider based function definitions. + // This Model object can work with any sort of function provider, interpret the function definition, + // and generate a valid model representation of that object. This abstracts the need for node definitions + // to be aware of how the model functions. + [HasDependencies(typeof(MinimalProviderNode))] + internal class ProviderNode : AbstractMaterialNode, IHasAssetDependencies, IGeneratesBodyCode, IGeneratesFunction + { + [Serializable] + internal class MinimalProviderNode : IHasDependencies + { + [SerializeReference] + IProvider m_provider; + + public void GetSourceAssetDependencies(AssetCollection assetCollection) + { + if (m_provider?.AssetID != default) + assetCollection.AddAssetDependency(m_provider.AssetID, + AssetCollection.Flags.SourceDependency + | AssetCollection.Flags.ArtifactDependency + | AssetCollection.Flags.IncludeInExportPackage); + } + } + + [SerializeReference] + IProvider m_provider; + + internal FunctionHeader Header { get; private set; } + + internal IProvider Provider => m_provider; + + const int kReservedOutputSlot = 0; + + public override bool hasPreview => true; + + public override bool canSetPrecision => false; + + internal override bool ExposeToSearcher => false; + + public ProviderNode() + { + name = "Provider Based Node"; + } + + internal void InitializeFromProvider(IProvider provider) + { + this.m_provider = (IProvider)provider.Clone(); + UpdateModel(); + } + + public override void UpdateNodeAfterDeserialization() + { + base.UpdateNodeAfterDeserialization(); + UpdateModel(); + } + + public override void Concretize() + { + UpdateModel(); + base.Concretize(); + } + + public bool Reload(HashSet changedAssetGuids) + { + if (changedAssetGuids.Contains(Provider.AssetID.ToString())) + { + Provider?.Reload(); + UpdateModel(); + owner.ClearErrorsForNode(this); + ValidateNode(); + Dirty(ModificationScope.Topological); + Dirty(ModificationScope.Graph); + return true; + } + return false; + } + + internal void UpdateModel() + { + if (Provider == null || Provider.Definition == null) + return; + + Header = new FunctionHeader(Provider); + var header = Header; + this.name = header.displayName; + this.synonyms = header.searchTerms; + var parameters = Provider.Definition.Parameters; + + List previousSlots = new(); + GetSlots(previousSlots); + + Dictionary oldSlotMap = new(); + HashSet usedSlotIds = new(); + + // build a map of parameter names to old slot ids (tuple is to support inout params). + foreach (var oldSlot in previousSlots) + { + if (!oldSlotMap.TryGetValue(oldSlot.shaderOutputName, out var idTuple)) + idTuple = (-1, -1); + + if (oldSlot.isInputSlot) idTuple.inputId = oldSlot.id; + if (oldSlot.isOutputSlot) idTuple.outputId = oldSlot.id; + + oldSlotMap[oldSlot.shaderOutputName] = idTuple; + } + + List paramHeaders = new(); + List desiredSlotOrder = new(); + + // return type is a special case, because it has no parameter but still needs a slot + // we reserve the 0 slotId for this and always make sure it's added first/at the top. + if (header.hasReturnType) + { + var returnParam = new ParameterHeader(header.returnDisplayName, header.returnType, header.tooltip); + usedSlotIds.Add(kReservedOutputSlot); + desiredSlotOrder.Add(kReservedOutputSlot); + AddSlotFromParameter(returnParam, kReservedOutputSlot, SlotType.Output); + } + + // build the header data for our parameters and mark which slot ids are being reused. + foreach(var param in parameters) + { + paramHeaders.Add(new ParameterHeader(param, Provider.Definition)); + if (oldSlotMap.TryGetValue(param.Name, out var idTuple)) + { + if (idTuple.inputId > -1) usedSlotIds.Add(idTuple.inputId); + if (idTuple.outputId > -1) usedSlotIds.Add(idTuple.outputId); + } + } + + // walk through our header data and build the actual slots. + int nextSlot = kReservedOutputSlot; + foreach (var paramHeader in paramHeaders) + { + if (!oldSlotMap.TryGetValue(paramHeader.referenceName, out var idTuple)) + idTuple = (-1, -1); + + void DoSlot(int slotId, SlotType dir) + { + if (slotId == -1) + { + while (usedSlotIds.Contains(++nextSlot)); + usedSlotIds.Add(nextSlot); + slotId = nextSlot; + } + AddSlotFromParameter(paramHeader, slotId, dir); + desiredSlotOrder.Add(slotId); + } + + if (paramHeader.isInput) + DoSlot(idTuple.inputId, SlotType.Input); + if (paramHeader.isOutput) + DoSlot(idTuple.outputId, SlotType.Output); + } + RemoveSlotsNameNotMatching(usedSlotIds, true); + SetSlotOrder(desiredSlotOrder); + } + + void AddSlotFromParameter(ParameterHeader header, int slotId, SlotType dir) + { + var slot = HeaderUtils.MakeSlotFromParameter(header, slotId, dir); + if (slot != null) + AddSlot(slot); + } + + public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode) + { + if (this.Provider == null || this.Provider.Definition == null) + return; + + using (var slots = PooledList.Get()) + { + GetSlots(slots); + Dictionary paramSlotMap = new(); + MaterialSlot returnSlot = null; + + // for various reasons, slots won't match one-to-one with parameters; + // we'll need to make sure slots are matched to parameters in the order expected + // while also accounting for inout duplicity. + foreach (var slot in slots) + { + if (slot.id == kReservedOutputSlot) + returnSlot = slot; + else + { + paramSlotMap.TryGetValue(slot.shaderOutputName, out var tup); + if (slot.isInputSlot) tup.input = slot; + if (slot.isOutputSlot) tup.output = slot; + paramSlotMap[slot.shaderOutputName] = tup; + } + } + + ShaderStringBuilder call = new(); // for the callsite. + ShaderStringBuilder args = new(); // for building up the argument list. + + // The return result is an output slot, but will instead get initialized by the function call. + if (returnSlot != null) + { + call.Append($"{HeaderUtils.ToShaderType(returnSlot)} {GetVariableNameForSlot(returnSlot.id)} = "); + } + + bool first = true; + foreach (var param in Provider.Definition.Parameters) + { + var inputSlot = paramSlotMap[param.Name].input; + var outputSlot = paramSlotMap[param.Name].output; + + var typeString = outputSlot != null ? HeaderUtils.ToShaderType(outputSlot) : HeaderUtils.ToShaderType(inputSlot); + + var variableName = outputSlot != null ? GetVariableNameForSlot(outputSlot.id) : null; + var valueString = inputSlot != null ? GetSlotValue(inputSlot.id, generationMode) : null; + + if (inputSlot != null && inputSlot.bareResource) // Texture/Sampler slots are normally 'Unity' wrapper structures + valueString += inputSlot is SamplerStateMaterialSlot ? ".samplerstate" : ".tex"; + + var argument = valueString; // assume it's an input, in which case the arg will be the upstream value/connection. + + if (outputSlot != null) + { + // inout and out define a variable to be used as the argument. + // but only inout gets initialized by the value. + argument = variableName; + sb.AddLine($"{typeString} {variableName}{(inputSlot != null ? $" = {valueString}" : "")};"); + } + + if (!first) + args.Append(", "); + first = false; + + args.Append(argument); + } + + foreach (var name in Provider.Definition.Namespace) + call.Append($"{name}::"); + call.Append(Provider.Definition.Name); + call.Append("("); + call.Append(args.ToString()); + call.Append(");"); + + + sb.AddLine(call.ToString()); + } + } + + public void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode) + { + var includePath = AssetDatabase.GUIDToAssetPath(Provider.AssetID); + registry.RequiresIncludePath(includePath, false); + } + + public override void ValidateNode() + { + base.ValidateNode(); + if (Provider == null) + { + owner.AddSetupError(this.objectId, "Node is in an invalid state and cannot recover."); + return; + } + else if (Provider.AssetID != default && (Provider.Definition == null || !Provider.Definition.IsValid)) + { + var path = AssetDatabase.GUIDToAssetPath(Provider.AssetID); + owner.AddSetupError(this.objectId, $"Data for '{Provider.ProviderKey}' expected in '{path}'."); + return; + } + else + { + foreach(var param in Provider.Definition.Parameters) + { + var header = new ParameterHeader(param, Provider.Definition); + if (!string.IsNullOrWhiteSpace(header.knownIssue)) + { + owner.AddValidationError(this.objectId, header.knownIssue, Rendering.ShaderCompilerMessageSeverity.Warning); + break; // We can only show one error badge at a time. + } + } + } + } + } +} diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ProviderNode.cs.meta b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ProviderNode.cs.meta new file mode 100644 index 00000000000..14dcf978ff8 --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ProviderNode.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5f258658ff6f1c842b38d746f69fa370 \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ProviderNodePropertyDrawer.cs b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ProviderNodePropertyDrawer.cs new file mode 100644 index 00000000000..b53c31bb6f8 --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ProviderNodePropertyDrawer.cs @@ -0,0 +1,50 @@ +using System; +using UnityEngine.UIElements; +using UnityEditor.ShaderGraph.ProviderSystem; + + +namespace UnityEditor.ShaderGraph.Drawing.Inspector.PropertyDrawers +{ + [SGPropertyDrawer(typeof(ProviderNode))] + class ProviderNodeNodePropertyDrawer : AbstractMaterialNodePropertyDrawer + { + private ProviderNode node; + + internal override void AddCustomNodeProperties(VisualElement parentElement, AbstractMaterialNode nodeBase, Action setNodesAsDirtyCallback, Action updateNodeViewsCallback) + { + node = nodeBase as ProviderNode; + var provider = node.Provider; + var definition = node.Provider.Definition; + string sourcePath = AssetDatabase.GUIDToAssetPath(node.Provider.AssetID); + + string providerKey = provider.ProviderKey; + string qualifiedSignature = ShaderObjectUtils.QualifySignature(node.Provider.Definition, true, true); + bool hasProviderKey = definition?.Hints?.ContainsKey(Hints.Func.kProviderKey) ?? false; + bool isAnAsset = provider?.AssetID != default; + + + if (provider == null) + { + parentElement.Add(new HelpBoxRow("Provider node is in an invalid and irrecoverable state.", MessageType.Error)); + } + + if (!isAnAsset) + return; + + else if (!provider.IsValid) + { + parentElement.Add(new HelpBoxRow($"Could not find '{providerKey}' in '{sourcePath}'.", MessageType.Error)); + } + else if (!hasProviderKey) + { + parentElement.Add(new HelpBoxRow($"'{providerKey}' in '{sourcePath}' does not have a 'ProviderKey' hint. If the namespace, name, or parameter list changes- this node instance will become invalidated.", MessageType.Warning)); + } + else + { + parentElement.Add(new HelpBoxRow($"Provider Key '{providerKey}' for \n" + + $"Function Signature '{qualifiedSignature}' found in \n" + + $"File Path '{sourcePath}'.", MessageType.Info)); + } + } + } +} diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ProviderNodePropertyDrawer.cs.meta b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ProviderNodePropertyDrawer.cs.meta new file mode 100644 index 00000000000..376cc39adc1 --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Model/ProviderNodePropertyDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 46fe9e42c0090d24391ef04f22ea4514 \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/ProviderLibrary.cs b/Packages/com.unity.shadergraph/Editor/ProviderSystem/ProviderLibrary.cs new file mode 100644 index 00000000000..9442a43ce58 --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/ProviderLibrary.cs @@ -0,0 +1,98 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace UnityEditor.ShaderGraph.ProviderSystem +{ + internal class ProviderLibrary + { + static ProviderLibrary s_instance; + internal static ProviderLibrary Instance + { + get + { + if (s_instance is null) + { + s_instance = new(); + s_instance.PopulateFromFiles(); + } + return s_instance; + } + } + + Dictionary providers = new(); + Dictionary> lookup = new(); + + internal IEnumerable AllProviders() => providers.Values; + + internal IEnumerable> AllProvidersByType() where T : IShaderObject + { + foreach(var provider in providers.Values) + { + if (provider is IProvider typedProvider) + yield return typedProvider; + } + } + + internal void Clear(GUID assetID) + { + if (!lookup.TryGetValue(assetID, out var providerNames)) + return; + + foreach (var providerName in providerNames) + providers.Remove(providerName); + + lookup.Remove(assetID); + } + + internal bool TryAdd(IProvider provider) + { + if (!providers.TryAdd(provider.ProviderKey, provider)) + return false; + + if (!lookup.TryAdd(provider.AssetID, new() { provider.ProviderKey })) + lookup[provider.AssetID].Add(provider.ProviderKey); + + return true; + } + + internal bool TryFind(string name, out IProvider provider) + => providers.TryGetValue(name, out provider); + + internal void PopulateFromFiles() + { + var results = AssetDatabase.FindAssetGUIDs("t: ShaderInclude"); + + foreach (var result in results) + { + AnalyzeFile(result); + } + } + + internal bool AnalyzeFile(GUID assetID) + { + Clear(assetID); + + var shaderInclude = AssetDatabase.LoadAssetByGUID(assetID); + if (shaderInclude == null) + return false; + + var reflection = shaderInclude.Reflection; + if (reflection == null) + return false; + + foreach (var func in reflection.ReflectedFunctions) + { + var candidateProvider = new ReflectedFunctionProvider(assetID, func); + if (!TryAdd(candidateProvider)) + { + TryFind(candidateProvider.ProviderKey, out var provider); + + string path = AssetDatabase.GUIDToAssetPath(assetID); + string foundPath = AssetDatabase.GUIDToAssetPath(provider.AssetID); + Debug.LogError($"Attempted to register '{candidateProvider.ProviderKey}' found in '{path}', but was already registered from '{foundPath}'.", shaderInclude); + } + } + return true; + } + } +} diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/ProviderLibrary.cs.meta b/Packages/com.unity.shadergraph/Editor/ProviderSystem/ProviderLibrary.cs.meta new file mode 100644 index 00000000000..b9123d1a21e --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/ProviderLibrary.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 41ba38f685080e84082aa51986c2c973 \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection.meta b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection.meta new file mode 100644 index 00000000000..a1ce12a7002 --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 93caa1d2f03b541cd96c60c1fa44b1ba +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ReflectedFunctionProvider.cs b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ReflectedFunctionProvider.cs new file mode 100644 index 00000000000..ba3a806499a --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ReflectedFunctionProvider.cs @@ -0,0 +1,60 @@ + +using System; +using UnityEditor.ShaderApiReflection; +using UnityEngine; + +namespace UnityEditor.ShaderGraph.ProviderSystem +{ + [Serializable] + internal class ReflectedFunctionProvider : IProvider + { + public string ProviderKey => m_providerKey; + public GUID AssetID => m_sourceAssetId; + public IShaderFunction Definition + { + get + { + if (m_definition == null || !m_definition.IsValid) + Reload(); + return m_definition; + } + } + + [SerializeField] + string m_providerKey; + + [SerializeField] + GUID m_sourceAssetId; + + [NonSerialized] + IShaderFunction m_definition; + + internal ReflectedFunctionProvider(GUID assetId, IShaderFunction definition) + { + m_sourceAssetId = assetId; + m_definition = definition; + + if (definition.IsValid) + { + m_providerKey = ShaderObjectUtils.EvaluateProviderKey(definition); + } + } + + internal ReflectedFunctionProvider(GUID assetId, ReflectedFunction function) + : this(assetId, ShaderReflectionUtils.ToShaderFunction(function)) + { + } + + // Should be called during hot reload + public void Reload() + { + if (ShaderReflectionUtils.TryResolve(m_providerKey, m_sourceAssetId, out var function)) + m_definition = ShaderReflectionUtils.ToShaderFunction(function); + else m_definition = null; + } + + public IProvider Clone() + => new ReflectedFunctionProvider(this.AssetID, this.Definition); + + } +} diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ReflectedFunctionProvider.cs.meta b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ReflectedFunctionProvider.cs.meta new file mode 100644 index 00000000000..51e22478b3d --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ReflectedFunctionProvider.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 038ab7ce009192243b6d1d84f54a250b \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ShaderReflectionAssetPostProcessor.cs b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ShaderReflectionAssetPostProcessor.cs new file mode 100644 index 00000000000..31b54e27dd8 --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ShaderReflectionAssetPostProcessor.cs @@ -0,0 +1,37 @@ +using UnityEngine; +using UnityEditor.ShaderApiReflection; +using System.Collections.Generic; +using UnityEditor.ShaderGraph.Drawing; + +namespace UnityEditor.ShaderGraph.ProviderSystem +{ + internal class ShaderReflectionAssetPostProcessor : AssetPostprocessor + { + static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths, bool didDomainReload) + { + List modifiedFiles = new(); + foreach (string path in importedAssets) + { + var assetID = AssetDatabase.GUIDFromAssetPath(path); + if (ProviderLibrary.Instance.AnalyzeFile(assetID)) + { + modifiedFiles.Add(assetID); + } + } + + if (modifiedFiles.Count > 0) + NotifyAll(modifiedFiles); + } + + internal static void NotifyAll(IEnumerable modifiedFiles) + { + var editors = Resources.FindObjectsOfTypeAll(); + foreach(var editor in editors) + { + editor.NotifyDependencyUpdated(modifiedFiles); + } + } + + + } +} diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ShaderReflectionAssetPostProcessor.cs.meta b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ShaderReflectionAssetPostProcessor.cs.meta new file mode 100644 index 00000000000..50ddd490a45 --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ShaderReflectionAssetPostProcessor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 74b504aa51af0344f97e1591851f6256 \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ShaderReflectionUtils.cs b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ShaderReflectionUtils.cs new file mode 100644 index 00000000000..b3352e9f647 --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ShaderReflectionUtils.cs @@ -0,0 +1,56 @@ + +using System.Collections.Generic; +using System.Text; +using UnityEditor.ShaderApiReflection; +using UnityEngine; + +namespace UnityEditor.ShaderGraph.ProviderSystem +{ + internal static class ShaderReflectionUtils + { + internal static bool TryResolve(string providerKey, GUID assetId, out ReflectedFunction function) + { + var source = AssetDatabase.LoadAssetByGUID(assetId)?.Reflection; + + function = default; + if (source == null) + return false; + + foreach (var func in source.ReflectedFunctions) + { + var otherProviderKey = ShaderObjectUtils.EvaluateProviderKey(ToShaderFunction(func)); + if (providerKey == otherProviderKey) + { + function = func; + return true; + } + } + + return false; + } + + internal static IShaderType ToShaderType(string typeName) + { + return new ShaderType(typeName); + } + + internal static IShaderField ToShaderField(ReflectedParameter refParam) + { + var type = ToShaderType(refParam.TypeName); + bool isInput = refParam.DirectionFlags == ReflectedParameter.Direction.In || refParam.DirectionFlags == ReflectedParameter.Direction.InOut; + bool isOutput = refParam.DirectionFlags == ReflectedParameter.Direction.Out || refParam.DirectionFlags == ReflectedParameter.Direction.InOut; + return new ShaderField(refParam.Name, isInput, isOutput, type, refParam.Hints); + } + + internal static IShaderFunction ToShaderFunction(ReflectedFunction refFunc) + { + var returnType = ToShaderType(refFunc.ReturnTypeName); + List fields = new(); + foreach (var param in refFunc.Parameters) + { + fields.Add(ToShaderField(param)); + } + return new ShaderFunction(refFunc.Name, refFunc.EnclosingNamespace, fields, returnType, refFunc.BodyText, refFunc.Hints); + } + } +} diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ShaderReflectionUtils.cs.meta b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ShaderReflectionUtils.cs.meta new file mode 100644 index 00000000000..4218a3c23e9 --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/Reflection/ShaderReflectionUtils.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 606cfb4ddecb1c7488927f55fd68944d \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/ShaderObjectUtils.cs b/Packages/com.unity.shadergraph/Editor/ProviderSystem/ShaderObjectUtils.cs new file mode 100644 index 00000000000..33346272907 --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/ShaderObjectUtils.cs @@ -0,0 +1,58 @@ + +using System.Text; + +namespace UnityEditor.ShaderGraph.ProviderSystem +{ + internal static class ShaderObjectUtils + { + internal static string QualifyName(IShaderObject obj, string separator = "::", bool includeName = true) + { + if (obj == null || !obj.IsValid) + return null; + + StringBuilder builder = new(); + + if (obj.Namespace != null) + foreach (var name in obj.Namespace) + builder.Append($"{name}{separator}"); + + builder.Append(obj.Name); + return builder.ToString(); + } + + internal static string QualifySignature(IShaderFunction obj, bool includeNamespace = true, bool forDisplay = false) + { + if (obj == null || !obj.IsValid) + return null; + + StringBuilder builder = new(); + builder.Append(includeNamespace ? QualifyName(obj) : obj.Name); + builder.Append(forDisplay ? " (" : "("); + + bool first = true; + if (obj.Parameters != null) + { + foreach (var param in obj.Parameters) + { + if (!first) builder.Append(forDisplay ? ", " : ","); + first = false; + builder.Append(QualifyName(param.ShaderType)); + } + } + builder.Append(")"); + + return builder.ToString(); + } + + internal static string EvaluateProviderKey(IShaderFunction obj, string fromHint = Hints.Func.kProviderKey) + { + string result = null; + if (obj?.IsValid ?? false) + { + if (obj.Hints == null || !obj.Hints.TryGetValue(fromHint, out result)) + result = QualifySignature(obj); + } + return result; + } + } +} diff --git a/Packages/com.unity.shadergraph/Editor/ProviderSystem/ShaderObjectUtils.cs.meta b/Packages/com.unity.shadergraph/Editor/ProviderSystem/ShaderObjectUtils.cs.meta new file mode 100644 index 00000000000..7c7e3b238e3 --- /dev/null +++ b/Packages/com.unity.shadergraph/Editor/ProviderSystem/ShaderObjectUtils.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3567c810dd85b9b4a9c617ae8e5310e4 \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Tests/Editor/ProviderTests.meta b/Packages/com.unity.shadergraph/Tests/Editor/ProviderTests.meta new file mode 100644 index 00000000000..5c86776ebb5 --- /dev/null +++ b/Packages/com.unity.shadergraph/Tests/Editor/ProviderTests.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f77105f0477b74224805849ef79e3e83 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.shadergraph/Tests/Editor/ProviderTests/ReflectedFunctionTests.cs b/Packages/com.unity.shadergraph/Tests/Editor/ProviderTests/ReflectedFunctionTests.cs new file mode 100644 index 00000000000..414373fe68f --- /dev/null +++ b/Packages/com.unity.shadergraph/Tests/Editor/ProviderTests/ReflectedFunctionTests.cs @@ -0,0 +1,76 @@ +using System.Collections.Generic; +using NUnit.Framework; + +namespace UnityEditor.ShaderGraph.ProviderSystem.Tests +{ + [TestFixture] + class ReflectedFunctionTests + { + readonly string kTestPath = "Assets/generated-ReflectionTest.hlsl"; + Dictionary lookup = new(); + + + ShaderFunction[] functionsToTest = new[] + { + new ShaderFunction("BaseCase", new[] { "Namespace1" , "Namespace2" }, null, new ShaderType("float"), "return 1;", null), + + new ShaderFunction("InAndOut", null, + new IShaderField[] { + new ShaderField("Field", true, true, new ShaderType("float3"), null), + }, + new ShaderType("void"), + "Field.xyz = float3(1,1,1);", null), + + new ShaderFunction("ProviderName", null, null, new ShaderType("float"), "return 1;", + new Dictionary() { + { Hints.Func.kProviderKey,"UniqueProviderName" }, + }), + }; + + [OneTimeSetUp] + public void Setup() + { + ShaderStringBuilder sb = new(); + foreach (var func in functionsToTest) + { + lookup.Add(ShaderObjectUtils.EvaluateProviderKey(func), func); + sb.AppendLine(TestUtils.GenerateCode(func)); + } + FileUtilities.WriteToDisk(kTestPath, sb.ToString()); + + AssetDatabase.ImportAsset(kTestPath, ImportAssetOptions.ForceSynchronousImport | ImportAssetOptions.ForceUpdate); + } + + [OneTimeTearDown] + public void Teardown() + { + AssetDatabase.DeleteAsset(kTestPath); + } + + [Test] + public void ReflectionTest() + { + int count = 0; + HashSet keysNotFound = new(lookup.Keys); + foreach(var provider in ProviderLibrary.Instance.AllProvidersByType()) + { + if (lookup.TryGetValue(provider.ProviderKey, out var actual)) + { + count++; + keysNotFound.Remove(provider.ProviderKey); + var expected = lookup[provider.ProviderKey]; + Assert.IsTrue(TestUtils.CompareFunction(actual, expected), $"Function found with key {provider.ProviderKey} does not match test case."); + TestUtils.AssertNodeSetup(provider); + } + } + if (keysNotFound.Count > 0) + { + System.Text.StringBuilder sb = new(); + foreach (var key in keysNotFound) + sb.Append($"{key}, "); + + Assert.Fail($"Expected keys could not be found: {sb.ToString()}"); + } + } + } +} diff --git a/Packages/com.unity.shadergraph/Tests/Editor/ProviderTests/ReflectedFunctionTests.cs.meta b/Packages/com.unity.shadergraph/Tests/Editor/ProviderTests/ReflectedFunctionTests.cs.meta new file mode 100644 index 00000000000..d0b7cb1ce20 --- /dev/null +++ b/Packages/com.unity.shadergraph/Tests/Editor/ProviderTests/ReflectedFunctionTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 645fc02044bcf4856950770ee6d1641e \ No newline at end of file diff --git a/Packages/com.unity.shadergraph/Tests/Editor/ProviderTests/TestUtils.cs b/Packages/com.unity.shadergraph/Tests/Editor/ProviderTests/TestUtils.cs new file mode 100644 index 00000000000..63b096286bf --- /dev/null +++ b/Packages/com.unity.shadergraph/Tests/Editor/ProviderTests/TestUtils.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; + +namespace UnityEditor.ShaderGraph.ProviderSystem.Tests +{ + internal static class TestUtils + { + internal static bool CompareSequence(IEnumerable a, IEnumerable b, Func cmp) + { + if (a == null && b == null) + return true; + else if (a == null || b == null) + return false; + + var ait = a.GetEnumerator(); + var bit = b.GetEnumerator(); + + bool av; + bool bv; + + do { + av = ait.MoveNext(); + bv = bit.MoveNext(); + if (av && bv && !cmp(ait.Current, bit.Current)) + return false; + } while (av && bv); + return av == bv; + } + + internal static bool CompareBase(IShaderObject a, IShaderObject b) + { + return a.IsValid && b.IsValid && string.Equals(a.Name, b.Name) + && CompareSequence(a.Namespace, b.Namespace, string.Equals) + && CompareSequence(a.Hints, b.Hints, (e, f) => e.Key == f.Key && e.Value == f.Value); + } + + internal static bool CompareType(IShaderType a, IShaderType b) + { + return CompareBase(a, b); + } + + internal static bool CompareField(IShaderField a, IShaderField b) + { + return a.IsInput == b.IsInput && a.IsOutput == b.IsOutput && CompareType(a.ShaderType, b.ShaderType) && CompareBase(a, b); + } + + internal static bool CompareFunction(IShaderFunction a, IShaderFunction b) + { + return CompareBase(a, b) + && CompareType(a.ReturnType, b.ReturnType) + && a.FunctionBody == b.FunctionBody + && CompareSequence(a.Parameters, b.Parameters, CompareField); + } + + private static (string typeName, string arraySpec) SplitTypeName(string typeName) + { + int i = typeName.IndexOf('['); + return i == -1 ? (typeName, "") : (typeName.Substring(0, i - 1), typeName.Substring(i)); + } + + private static string DeclareField(IShaderField a) + { + var t = SplitTypeName(a.ShaderType.Name); + return $"{t.typeName} {a.Name}{t.arraySpec}"; + } + + private static string GenerateHints(string closure, IReadOnlyDictionary hints, string name = null) + { + ShaderStringBuilder sb = new(); + + if (name != null) + sb.AppendLine($"/// <{closure} name = \"{name}\">"); + else sb.AppendLine($"/// <{closure}>"); + + foreach(var hint in hints) + sb.AppendLine($"///\t <{hint.Key}>{hint.Value}"); + + sb.AppendLine($"/// "); + return sb.ToString(); + } + + internal static string GenerateCode(IShaderFunction func) + { + ShaderStringBuilder sb = new(); + + foreach(var name in func.Namespace) + sb.Append($"namespace {name}{{"); + + sb.AppendNewLine(); + sb.IncreaseIndent(); + + sb.Append(GenerateHints("funchints", func.Hints)); + foreach (var param in func.Parameters) + sb.Append(GenerateHints("paramhints", param.Hints, param.Name)); + + sb.Append($"UNITY_EXPORT_REFLECTION {func.ReturnType.Name} {func.Name}("); + bool first = true; + foreach (var param in func.Parameters) + { + if (!first) sb.Append(", "); + sb.Append(DeclareField(param)); + } + sb.AppendLine(")"); + sb.AppendLine("{"); + sb.IncreaseIndent(); + sb.AppendLine(func.FunctionBody); + sb.DecreaseIndent(); + sb.AppendLine("}"); + sb.DecreaseIndent(); + + foreach (var name in func.Namespace) + sb.Append($"}} /*{name}*/"); + + return sb.ToString(); + } + + internal static void AssertNodeSetup(IProvider provider) + { + Assert.IsNotNull(provider); + Assert.IsTrue(provider.IsValid); + + var node = new ProviderNode(); + node.InitializeFromProvider(provider); + + List slots = new(); + node.GetSlots(slots); + + int count = 0; + + if (provider.Definition.ReturnType.Name != "void") + count++; + + foreach (var param in node.Provider.Definition.Parameters) + count += (param.IsInput ? 1 : 0) + (param.IsOutput ? 1 : 0); + + Assert.AreEqual(slots.Count, count, $"{provider.ProviderKey} has an unexpected number of slots."); + } + } +} diff --git a/Packages/com.unity.shadergraph/Tests/Editor/ProviderTests/TestUtils.cs.meta b/Packages/com.unity.shadergraph/Tests/Editor/ProviderTests/TestUtils.cs.meta new file mode 100644 index 00000000000..81f0f34edfe --- /dev/null +++ b/Packages/com.unity.shadergraph/Tests/Editor/ProviderTests/TestUtils.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: cda199a8cac8e415ebec2dca28c8df30 \ No newline at end of file diff --git a/Tests/SRPTests/Projects/ShaderGraph/Assets/Testing/IntegrationTests/Graphs/ProviderSystem/AllHints.hlsl b/Tests/SRPTests/Projects/ShaderGraph/Assets/Testing/IntegrationTests/Graphs/ProviderSystem/AllHints.hlsl new file mode 100644 index 00000000000..3a8ae21cc50 --- /dev/null +++ b/Tests/SRPTests/Projects/ShaderGraph/Assets/Testing/IntegrationTests/Graphs/ProviderSystem/AllHints.hlsl @@ -0,0 +1,110 @@ +#include "ShaderApiReflectionSupport.hlsl" + +namespace Namespace { + +struct CustomStruct +{ + float Value; +}; + +/// +/// AllHintsUniqueStableID +/// All Known Hints +/// Final Result +/// Hints/All +/// Features, Reflected, Every, Hint +/// All Hints Search Name +/// +/// +/// Custom Struct Value +/// 0.5 +/// Namespace +/// +/// +/// Color 3 +/// +/// 1,1,0 +/// +/// +/// Color 4 +/// +/// 1,1,0,1 +/// +/// +/// Static Color 3 +/// +/// +/// 1,1,0 +/// +/// +/// Static Color 4 +/// +/// +/// 1,1,0,1 +/// +/// +/// Dropdown +/// OptionA, OptionB, OptionC +/// 1 +/// +/// +/// Dropdown +/// OptionA, OptionB, OptionC +/// +/// 2 +/// +/// +/// Range +/// 0, 1 +/// 0.75 +/// +/// +/// Range +/// +/// 0, 1 +/// 0.25 +/// +/// +/// Toggle +/// +/// 1 +/// +/// +/// Integer +/// +/// 5 +/// +UNITY_EXPORT_REFLECTION float3 AllHints( + inout CustomStruct a, + float3 c3, + inout float4 c4, + float3 sc3, + float4 sc4, + inout uint d, + uint sd, + float r, + float sr, + bool sb, + int si +) +{ + return float3(a.Value, sr, sc4.r); +} + +/// +/// Namespace +/// +UNITY_EXPORT_REFLECTION void MakeCustomStruct(float a, out CustomStruct result) +{ + result.Value = a; +} + +namespace NamespaceAsCategory +{ + UNITY_EXPORT_REFLECTION float3 NamespacedFunction() + { + return float3(1,1,0); + } +} + +} // Namespace \ No newline at end of file diff --git a/Tests/SRPTests/Projects/ShaderGraph/Assets/Testing/IntegrationTests/Graphs/ProviderSystem/AllHints.hlsl.meta b/Tests/SRPTests/Projects/ShaderGraph/Assets/Testing/IntegrationTests/Graphs/ProviderSystem/AllHints.hlsl.meta new file mode 100644 index 00000000000..1b2c94109a9 --- /dev/null +++ b/Tests/SRPTests/Projects/ShaderGraph/Assets/Testing/IntegrationTests/Graphs/ProviderSystem/AllHints.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4060428cd4c114edab3647f50d95506a +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/SRPTests/Projects/ShaderGraph/Assets/Testing/IntegrationTests/Graphs/ProviderSystem/ShouldCompileProperlyOnImport.shadergraph b/Tests/SRPTests/Projects/ShaderGraph/Assets/Testing/IntegrationTests/Graphs/ProviderSystem/ShouldCompileProperlyOnImport.shadergraph new file mode 100644 index 00000000000..cf755427f6e --- /dev/null +++ b/Tests/SRPTests/Projects/ShaderGraph/Assets/Testing/IntegrationTests/Graphs/ProviderSystem/ShouldCompileProperlyOnImport.shadergraph @@ -0,0 +1,1247 @@ +{ + "m_SGVersion": 3, + "m_Type": "UnityEditor.ShaderGraph.GraphData", + "m_ObjectId": "5986f6de68144d5fb24cd905ef9caa8c", + "m_Properties": [], + "m_Keywords": [], + "m_Dropdowns": [], + "m_CategoryData": [ + { + "m_Id": "58527e023b7745bd9800e3548b857ccd" + } + ], + "m_Nodes": [ + { + "m_Id": "bf761c536bd04fbaacb943564862d899" + }, + { + "m_Id": "55c129e19a6b4204bb696f0769b957be" + }, + { + "m_Id": "6f0a51ebf1704b26874463c4a99d68bc" + }, + { + "m_Id": "5784e5f7edb64ab6a719b6f7dccea574" + }, + { + "m_Id": "de69fe023db044b588133cac8130c0a5" + }, + { + "m_Id": "793a050e313d4f05a8b27a0ed15541ce" + }, + { + "m_Id": "b3455fdb91704dd2b4d6498433e11a3f" + }, + { + "m_Id": "9bfa1c63ad7a47cca1d428fd2664b0a1" + }, + { + "m_Id": "79827555378b43b4b8a46317eabcb8b1" + }, + { + "m_Id": "abc179ee5107447ca5495532006b435e" + }, + { + "m_Id": "d715a4d08d6e4e77b8fe8c816d434bac" + } + ], + "m_GroupDatas": [], + "m_StickyNoteDatas": [], + "m_Edges": [ + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "abc179ee5107447ca5495532006b435e" + }, + "m_SlotId": 0 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "5784e5f7edb64ab6a719b6f7dccea574" + }, + "m_SlotId": 0 + } + }, + { + "m_OutputSlot": { + "m_Node": { + "m_Id": "d715a4d08d6e4e77b8fe8c816d434bac" + }, + "m_SlotId": 2 + }, + "m_InputSlot": { + "m_Node": { + "m_Id": "abc179ee5107447ca5495532006b435e" + }, + "m_SlotId": 1 + } + } + ], + "m_VertexContext": { + "m_Position": { + "x": -98.49996948242188, + "y": -535.0 + }, + "m_Blocks": [ + { + "m_Id": "bf761c536bd04fbaacb943564862d899" + }, + { + "m_Id": "55c129e19a6b4204bb696f0769b957be" + }, + { + "m_Id": "6f0a51ebf1704b26874463c4a99d68bc" + } + ] + }, + "m_FragmentContext": { + "m_Position": { + "x": -65.49999237060547, + "y": -287.49993896484377 + }, + "m_Blocks": [ + { + "m_Id": "5784e5f7edb64ab6a719b6f7dccea574" + }, + { + "m_Id": "de69fe023db044b588133cac8130c0a5" + }, + { + "m_Id": "793a050e313d4f05a8b27a0ed15541ce" + }, + { + "m_Id": "b3455fdb91704dd2b4d6498433e11a3f" + }, + { + "m_Id": "9bfa1c63ad7a47cca1d428fd2664b0a1" + }, + { + "m_Id": "79827555378b43b4b8a46317eabcb8b1" + } + ] + }, + "m_PreviewData": { + "serializedMesh": { + "m_SerializedMesh": "{\"mesh\":{\"instanceID\":0}}", + "m_Guid": "" + }, + "preventRotation": false + }, + "m_Path": "Shader Graphs", + "m_GraphPrecision": 1, + "m_PreviewMode": 2, + "m_OutputNode": { + "m_Id": "" + }, + "m_SubDatas": [], + "m_ActiveTargets": [ + { + "m_Id": "0afb71d0a00c40ce9ef24adc614b3682" + } + ] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ProviderSystem.ExternalMaterialSlot", + "m_ObjectId": "0754487883424571af380987bf510ff7", + "m_Id": 2, + "m_DisplayName": "Result", + "m_SlotType": 1, + "m_Hidden": false, + "m_HideConnector": false, + "m_ShaderOutputName": "result", + "m_StageCapability": 3, + "m_typeName": "Namespace::CustomStruct", + "m_rawDefaultValueString": "0" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BooleanMaterialSlot", + "m_ObjectId": "087d2f43197440c3b961acc319f9bd5a", + "m_Id": 13, + "m_DisplayName": "Toggle", + "m_SlotType": 0, + "m_Hidden": false, + "m_HideConnector": true, + "m_ShaderOutputName": "sb", + "m_StageCapability": 3, + "m_Value": true, + "m_DefaultValue": true +} + +{ + "m_SGVersion": 1, + "m_Type": "UnityEditor.Rendering.Universal.ShaderGraph.UniversalTarget", + "m_ObjectId": "0afb71d0a00c40ce9ef24adc614b3682", + "m_Datas": [], + "m_ActiveSubTarget": { + "m_Id": "d5d43ab2cfd24d14ac874c98f494699e" + }, + "m_AllowMaterialOverride": false, + "m_SurfaceType": 0, + "m_ZTestMode": 4, + "m_ZWriteControl": 0, + "m_AlphaMode": 0, + "m_RenderFace": 2, + "m_AlphaClip": false, + "m_CastShadows": true, + "m_ReceiveShadows": true, + "m_DisableTint": false, + "m_Sort3DAs2DCompatible": false, + "m_AdditionalMotionVectorMode": 0, + "m_AlembicMotionVectors": false, + "m_SupportsLODCrossFade": false, + "m_CustomEditorGUI": "", + "m_SupportVFX": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "1f332c5cdfb74eeda1fd9bfa573e141e", + "m_Id": 0, + "m_DisplayName": "Metallic", + "m_SlotType": 0, + "m_Hidden": false, + "m_HideConnector": false, + "m_ShaderOutputName": "Metallic", + "m_StageCapability": 2, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [], + "m_LiteralMode": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialIntegerSlot", + "m_ObjectId": "2450c748c904403996d4d20cc478b2c2", + "m_Id": 14, + "m_DisplayName": "Integer", + "m_SlotType": 0, + "m_Hidden": false, + "m_HideConnector": true, + "m_ShaderOutputName": "si", + "m_StageCapability": 3, + "m_Value": 5.0, + "m_DefaultValue": 5.0, + "m_Labels": [], + "m_LiteralMode": false, + "m_unsigned": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialEnumSlot", + "m_ObjectId": "26052c8287894b9f8382692f5497322a", + "m_Id": 8, + "m_DisplayName": "Dropdown", + "m_SlotType": 0, + "m_Hidden": false, + "m_HideConnector": false, + "m_ShaderOutputName": "d", + "m_StageCapability": 3, + "m_Value": 1.0, + "m_DefaultValue": 1.0, + "m_Labels": [], + "m_LiteralMode": false, + "options": [ + "OptionA", + "OptionB", + "OptionC" + ], + "values": [ + 0, + 1, + 2 + ] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot", + "m_ObjectId": "3486de34952c4b7c857056075f789ed1", + "m_Id": 0, + "m_DisplayName": "Base Color", + "m_SlotType": 0, + "m_Hidden": false, + "m_HideConnector": false, + "m_ShaderOutputName": "BaseColor", + "m_StageCapability": 2, + "m_Value": { + "x": 0.5, + "y": 0.5, + "z": 0.5 + }, + "m_DefaultValue": { + "x": 0.5, + "y": 0.5, + "z": 0.5 + }, + "m_Labels": [], + "m_ColorMode": 0, + "m_DefaultColor": { + "r": 0.5, + "g": 0.5, + "b": 0.5, + "a": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.TangentMaterialSlot", + "m_ObjectId": "3cf4bae4141b4566a405cf0e50c6e600", + "m_Id": 0, + "m_DisplayName": "Tangent", + "m_SlotType": 0, + "m_Hidden": false, + "m_HideConnector": false, + "m_ShaderOutputName": "Tangent", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot", + "m_ObjectId": "4552d16fd3154640b455494b60d7728a", + "m_Id": 0, + "m_DisplayName": "Emission", + "m_SlotType": 0, + "m_Hidden": false, + "m_HideConnector": false, + "m_ShaderOutputName": "Emission", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_ColorMode": 1, + "m_DefaultColor": { + "r": 0.0, + "g": 0.0, + "b": 0.0, + "a": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialEnumSlot", + "m_ObjectId": "4e7192094bdb4399accaa088b8b78eb3", + "m_Id": 9, + "m_DisplayName": "Dropdown", + "m_SlotType": 1, + "m_Hidden": false, + "m_HideConnector": false, + "m_ShaderOutputName": "d", + "m_StageCapability": 3, + "m_Value": 1.0, + "m_DefaultValue": 1.0, + "m_Labels": [], + "m_LiteralMode": false, + "options": [ + "OptionA", + "OptionB", + "OptionC" + ], + "values": [ + 0, + 1, + 2 + ] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "55c129e19a6b4204bb696f0769b957be", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Normal", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "cf0d43ee886345429f2696eed42016b9" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Normal" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "5784e5f7edb64ab6a719b6f7dccea574", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.BaseColor", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "3486de34952c4b7c857056075f789ed1" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.BaseColor" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.CategoryData", + "m_ObjectId": "58527e023b7745bd9800e3548b857ccd", + "m_Name": "", + "m_ChildObjectList": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.PositionMaterialSlot", + "m_ObjectId": "6a4122c7f131462699d33eedffc8b834", + "m_Id": 0, + "m_DisplayName": "Position", + "m_SlotType": 0, + "m_Hidden": false, + "m_HideConnector": false, + "m_ShaderOutputName": "Position", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "6f0a51ebf1704b26874463c4a99d68bc", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Tangent", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "3cf4bae4141b4566a405cf0e50c6e600" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Tangent" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.NormalMaterialSlot", + "m_ObjectId": "7296f28828ef48e8a03494f77532d2d8", + "m_Id": 0, + "m_DisplayName": "Normal (Tangent Space)", + "m_SlotType": 0, + "m_Hidden": false, + "m_HideConnector": false, + "m_ShaderOutputName": "NormalTS", + "m_StageCapability": 2, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 3 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ProviderSystem.ExternalMaterialSlot", + "m_ObjectId": "73ae370ae0c0438d8268613bee620fcd", + "m_Id": 2, + "m_DisplayName": "Custom Struct Value", + "m_SlotType": 1, + "m_Hidden": false, + "m_HideConnector": false, + "m_ShaderOutputName": "a", + "m_StageCapability": 3, + "m_typeName": "Namespace::CustomStruct", + "m_rawDefaultValueString": "0.5" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "793a050e313d4f05a8b27a0ed15541ce", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Metallic", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "1f332c5cdfb74eeda1fd9bfa573e141e" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Metallic" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "79827555378b43b4b8a46317eabcb8b1", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Occlusion", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "bf61e113654141fc9b4996ad024424e5" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Occlusion" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ProviderSystem.ExternalMaterialSlot", + "m_ObjectId": "7a42f5ac5a944351b622af4fbb230bd9", + "m_Id": 1, + "m_DisplayName": "Custom Struct Value", + "m_SlotType": 0, + "m_Hidden": false, + "m_HideConnector": false, + "m_ShaderOutputName": "a", + "m_StageCapability": 3, + "m_typeName": "Namespace::CustomStruct", + "m_rawDefaultValueString": "0.5" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialEnumSlot", + "m_ObjectId": "7c920fa72c7e4e2eafbe4cf0aaabb426", + "m_Id": 10, + "m_DisplayName": "Dropdown", + "m_SlotType": 0, + "m_Hidden": false, + "m_HideConnector": true, + "m_ShaderOutputName": "sd", + "m_StageCapability": 3, + "m_Value": 2.0, + "m_DefaultValue": 2.0, + "m_Labels": [], + "m_LiteralMode": false, + "options": [ + "OptionA", + "OptionB", + "OptionC" + ], + "values": [ + 0, + 1, + 2 + ] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot", + "m_ObjectId": "87a0f49c5732479ab274c007f0753efa", + "m_Id": 3, + "m_DisplayName": "Color 3", + "m_SlotType": 0, + "m_Hidden": false, + "m_HideConnector": false, + "m_ShaderOutputName": "c3", + "m_StageCapability": 3, + "m_Value": { + "x": 1.0, + "y": 1.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 1.0, + "y": 1.0, + "z": 0.0 + }, + "m_Labels": [], + "m_ColorMode": 0, + "m_DefaultColor": { + "r": 1.0, + "g": 1.0, + "b": 0.0, + "a": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "9aeaec8d58e742e6874131e1d39c8aa6", + "m_Id": 1, + "m_DisplayName": "A", + "m_SlotType": 0, + "m_Hidden": false, + "m_HideConnector": false, + "m_ShaderOutputName": "a", + "m_StageCapability": 3, + "m_Value": 0.0, + "m_DefaultValue": 0.0, + "m_Labels": [], + "m_LiteralMode": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "9bfa1c63ad7a47cca1d428fd2664b0a1", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Emission", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "4552d16fd3154640b455494b60d7728a" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Emission" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBAMaterialSlot", + "m_ObjectId": "a7f8847024b34a678219b3a4aa52ef1b", + "m_Id": 7, + "m_DisplayName": "Static Color 4", + "m_SlotType": 0, + "m_Hidden": false, + "m_HideConnector": true, + "m_ShaderOutputName": "sc4", + "m_StageCapability": 3, + "m_Value": { + "x": 1.0, + "y": 1.0, + "z": 0.0, + "w": 1.0 + }, + "m_DefaultValue": { + "x": 1.0, + "y": 1.0, + "z": 0.0, + "w": 1.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ProviderSystem.ProviderNode", + "m_ObjectId": "abc179ee5107447ca5495532006b435e", + "m_Group": { + "m_Id": "" + }, + "m_Name": "All Known Hints", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -489.5, + "y": -353.9999694824219, + "width": 316.0, + "height": 491.5000305175781 + } + }, + "m_Slots": [ + { + "m_Id": "d2f9a4c5e5594ca9bbb0da08fbbc2672" + }, + { + "m_Id": "7a42f5ac5a944351b622af4fbb230bd9" + }, + { + "m_Id": "73ae370ae0c0438d8268613bee620fcd" + }, + { + "m_Id": "87a0f49c5732479ab274c007f0753efa" + }, + { + "m_Id": "b562783b180f4c2e85820fc8a48c6815" + }, + { + "m_Id": "db491031d1f647e09b27504acb2d0c93" + }, + { + "m_Id": "b84dd6b7a91943b9a245b31d9dfa8789" + }, + { + "m_Id": "a7f8847024b34a678219b3a4aa52ef1b" + }, + { + "m_Id": "26052c8287894b9f8382692f5497322a" + }, + { + "m_Id": "4e7192094bdb4399accaa088b8b78eb3" + }, + { + "m_Id": "7c920fa72c7e4e2eafbe4cf0aaabb426" + }, + { + "m_Id": "adb46ec4abb54d9abdf31c4f1b4c4c0f" + }, + { + "m_Id": "ee98c1bdfb8743deae8a0719435e7e08" + }, + { + "m_Id": "087d2f43197440c3b961acc319f9bd5a" + }, + { + "m_Id": "2450c748c904403996d4d20cc478b2c2" + } + ], + "synonyms": [ + "All Hints Search Name" + ], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_provider": { + "rid": 1000 + }, + "references": { + "version": 2, + "RefIds": [ + { + "rid": 1000, + "type": { + "class": "ReflectedFunctionProvider", + "ns": "UnityEditor.ShaderGraph.ProviderSystem", + "asm": "Unity.ShaderGraph.Editor" + }, + "data": { + "m_providerKey": "AllHintsUniqueStableID", + "m_sourceAssetId": "4060428cd4c114edab3647f50d95506a" + } + } + ] + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialRangeSlot", + "m_ObjectId": "adb46ec4abb54d9abdf31c4f1b4c4c0f", + "m_Id": 11, + "m_DisplayName": "Range", + "m_SlotType": 0, + "m_Hidden": false, + "m_HideConnector": false, + "m_ShaderOutputName": "r", + "m_StageCapability": 3, + "m_Value": 0.75, + "m_DefaultValue": 0.75, + "m_Labels": [], + "m_LiteralMode": false, + "m_sliderRange": { + "x": 0.0, + "y": 1.0 + }, + "m_SliderType": 0, + "m_SliderPower": 3.0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "b3455fdb91704dd2b4d6498433e11a3f", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.Smoothness", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "cfad1bb65f9a4cb2bfa7b302f7b8a7fc" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.Smoothness" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBAMaterialSlot", + "m_ObjectId": "b562783b180f4c2e85820fc8a48c6815", + "m_Id": 4, + "m_DisplayName": "Color 4", + "m_SlotType": 0, + "m_Hidden": false, + "m_HideConnector": false, + "m_ShaderOutputName": "c4", + "m_StageCapability": 3, + "m_Value": { + "x": 1.0, + "y": 1.0, + "z": 0.0, + "w": 1.0 + }, + "m_DefaultValue": { + "x": 1.0, + "y": 1.0, + "z": 0.0, + "w": 1.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot", + "m_ObjectId": "b84dd6b7a91943b9a245b31d9dfa8789", + "m_Id": 6, + "m_DisplayName": "Static Color 3", + "m_SlotType": 0, + "m_Hidden": false, + "m_HideConnector": true, + "m_ShaderOutputName": "sc3", + "m_StageCapability": 3, + "m_Value": { + "x": 1.0, + "y": 1.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 1.0, + "y": 1.0, + "z": 0.0 + }, + "m_Labels": [], + "m_ColorMode": 0, + "m_DefaultColor": { + "r": 1.0, + "g": 1.0, + "b": 0.0, + "a": 1.0 + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "bf61e113654141fc9b4996ad024424e5", + "m_Id": 0, + "m_DisplayName": "Ambient Occlusion", + "m_SlotType": 0, + "m_Hidden": false, + "m_HideConnector": false, + "m_ShaderOutputName": "Occlusion", + "m_StageCapability": 2, + "m_Value": 1.0, + "m_DefaultValue": 1.0, + "m_Labels": [], + "m_LiteralMode": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "bf761c536bd04fbaacb943564862d899", + "m_Group": { + "m_Id": "" + }, + "m_Name": "VertexDescription.Position", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "6a4122c7f131462699d33eedffc8b834" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "VertexDescription.Position" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.NormalMaterialSlot", + "m_ObjectId": "cf0d43ee886345429f2696eed42016b9", + "m_Id": 0, + "m_DisplayName": "Normal", + "m_SlotType": 0, + "m_Hidden": false, + "m_HideConnector": false, + "m_ShaderOutputName": "Normal", + "m_StageCapability": 1, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [], + "m_Space": 0 +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot", + "m_ObjectId": "cfad1bb65f9a4cb2bfa7b302f7b8a7fc", + "m_Id": 0, + "m_DisplayName": "Smoothness", + "m_SlotType": 0, + "m_Hidden": false, + "m_HideConnector": false, + "m_ShaderOutputName": "Smoothness", + "m_StageCapability": 2, + "m_Value": 0.5, + "m_DefaultValue": 0.5, + "m_Labels": [], + "m_LiteralMode": false +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot", + "m_ObjectId": "d2f9a4c5e5594ca9bbb0da08fbbc2672", + "m_Id": 0, + "m_DisplayName": "Final Result", + "m_SlotType": 1, + "m_Hidden": false, + "m_HideConnector": false, + "m_ShaderOutputName": "Final Result", + "m_StageCapability": 3, + "m_Value": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_DefaultValue": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 2, + "m_Type": "UnityEditor.Rendering.Universal.ShaderGraph.UniversalLitSubTarget", + "m_ObjectId": "d5d43ab2cfd24d14ac874c98f494699e", + "m_WorkflowMode": 1, + "m_NormalDropOffSpace": 0, + "m_ClearCoat": false, + "m_BlendModePreserveSpecular": true +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ProviderSystem.ProviderNode", + "m_ObjectId": "d715a4d08d6e4e77b8fe8c816d434bac", + "m_Group": { + "m_Id": "" + }, + "m_Name": "Make Custom Struct", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": -742.5, + "y": -414.9999694824219, + "width": 162.0, + "height": 86.0 + } + }, + "m_Slots": [ + { + "m_Id": "9aeaec8d58e742e6874131e1d39c8aa6" + }, + { + "m_Id": "0754487883424571af380987bf510ff7" + } + ], + "synonyms": [ + "MakeCustomStruct" + ], + "m_Precision": 0, + "m_PreviewExpanded": false, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_provider": { + "rid": 1000 + }, + "references": { + "version": 2, + "RefIds": [ + { + "rid": 1000, + "type": { + "class": "ReflectedFunctionProvider", + "ns": "UnityEditor.ShaderGraph.ProviderSystem", + "asm": "Unity.ShaderGraph.Editor" + }, + "data": { + "m_providerKey": "Namespace::MakeCustomStruct(float,CustomStruct)", + "m_sourceAssetId": "4060428cd4c114edab3647f50d95506a" + } + } + ] + } +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.ColorRGBAMaterialSlot", + "m_ObjectId": "db491031d1f647e09b27504acb2d0c93", + "m_Id": 5, + "m_DisplayName": "Color 4", + "m_SlotType": 1, + "m_Hidden": false, + "m_HideConnector": false, + "m_ShaderOutputName": "c4", + "m_StageCapability": 3, + "m_Value": { + "x": 1.0, + "y": 1.0, + "z": 0.0, + "w": 1.0 + }, + "m_DefaultValue": { + "x": 1.0, + "y": 1.0, + "z": 0.0, + "w": 1.0 + }, + "m_Labels": [] +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.BlockNode", + "m_ObjectId": "de69fe023db044b588133cac8130c0a5", + "m_Group": { + "m_Id": "" + }, + "m_Name": "SurfaceDescription.NormalTS", + "m_DrawState": { + "m_Expanded": true, + "m_Position": { + "serializedVersion": "2", + "x": 0.0, + "y": 0.0, + "width": 0.0, + "height": 0.0 + } + }, + "m_Slots": [ + { + "m_Id": "7296f28828ef48e8a03494f77532d2d8" + } + ], + "synonyms": [], + "m_Precision": 0, + "m_PreviewExpanded": true, + "m_DismissedVersion": 0, + "m_PreviewMode": 0, + "m_CustomColors": { + "m_SerializableColors": [] + }, + "m_SerializedDescriptor": "SurfaceDescription.NormalTS" +} + +{ + "m_SGVersion": 0, + "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialRangeSlot", + "m_ObjectId": "ee98c1bdfb8743deae8a0719435e7e08", + "m_Id": 12, + "m_DisplayName": "Range", + "m_SlotType": 0, + "m_Hidden": false, + "m_HideConnector": true, + "m_ShaderOutputName": "sr", + "m_StageCapability": 3, + "m_Value": 0.25, + "m_DefaultValue": 0.25, + "m_Labels": [], + "m_LiteralMode": false, + "m_sliderRange": { + "x": 0.0, + "y": 1.0 + }, + "m_SliderType": 0, + "m_SliderPower": 3.0 +} + diff --git a/Tests/SRPTests/Projects/ShaderGraph/Assets/Testing/IntegrationTests/Graphs/ProviderSystem/ShouldCompileProperlyOnImport.shadergraph.meta b/Tests/SRPTests/Projects/ShaderGraph/Assets/Testing/IntegrationTests/Graphs/ProviderSystem/ShouldCompileProperlyOnImport.shadergraph.meta new file mode 100644 index 00000000000..a54c3f9ae05 --- /dev/null +++ b/Tests/SRPTests/Projects/ShaderGraph/Assets/Testing/IntegrationTests/Graphs/ProviderSystem/ShouldCompileProperlyOnImport.shadergraph.meta @@ -0,0 +1,20 @@ +fileFormatVersion: 2 +guid: 0af07439258a942f3adfa7d48e3f6b36 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3} + useAsTemplate: 0 + exposeTemplateAsShader: 0 + indexedData: {instanceID: 0} + template: + name: + category: + description: + icon: {instanceID: 0} + thumbnail: {instanceID: 0} + order: 0 From 73200719973b8dd3c2d666967f9af99803b9b065 Mon Sep 17 00:00:00 2001 From: Rasmus Roenn Nielsen Date: Sun, 15 Feb 2026 00:41:57 +0000 Subject: [PATCH 15/92] Fix typo in APV tool tip. --- .../UniversalRenderPipelineAssetUI.Skin.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Packages/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineAsset/UniversalRenderPipelineAssetUI.Skin.cs b/Packages/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineAsset/UniversalRenderPipelineAssetUI.Skin.cs index b5557ee9c28..fbb1672aac1 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineAsset/UniversalRenderPipelineAssetUI.Skin.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineAsset/UniversalRenderPipelineAssetUI.Skin.cs @@ -51,8 +51,8 @@ internal static class Styles public static readonly GUIContent lightProbeSystemContent = EditorGUIUtility.TrTextContent("Light Probe System", "What system to use for Light Probes."); public static readonly GUIContent probeVolumeMemoryBudget = EditorGUIUtility.TrTextContent("Memory Budget", "Determines the width and height of the 3D textures used to store lighting data from probes. Depth is fixed."); public static readonly GUIContent probeVolumeBlendingMemoryBudget = EditorGUIUtility.TrTextContent("Blending Memory Budget", "Determines the width and height of the 3D textures used to store light scenario blending data from probes. Depth is fixed."); - public static readonly GUIContent supportProbeVolumeGPUStreaming = EditorGUIUtility.TrTextContent("Enable GPU Streaming", "Enable steaming of Cells for Adaptive Probe Volumes."); - public static readonly GUIContent supportProbeVolumeDiskStreaming = EditorGUIUtility.TrTextContent("Enable Disk Streaming", "Enable steaming of Cells from disk for Adaptive Probe Volumes."); + public static readonly GUIContent supportProbeVolumeGPUStreaming = EditorGUIUtility.TrTextContent("Enable GPU Streaming", "Enable streaming of Cells for Adaptive Probe Volumes."); + public static readonly GUIContent supportProbeVolumeDiskStreaming = EditorGUIUtility.TrTextContent("Enable Disk Streaming", "Enable streaming of Cells from disk for Adaptive Probe Volumes."); public static readonly GUIContent supportProbeVolumeScenarios = EditorGUIUtility.TrTextContent("Enable Lighting Scenarios", "Enable Lighting Scenario Baking for Adaptive Probe Volumes."); public static readonly GUIContent supportProbeVolumeScenarioBlending = EditorGUIUtility.TrTextContent("Enable Lighting Scenario Blending", "Enable Lighting Scenario Blending for Adaptive Probe Volumes.\nNote: Lighting Scenario Blending requires Compute Shader support."); public static readonly GUIContent probeVolumeSHBands = EditorGUIUtility.TrTextContent("SH Bands", "The number of Spherical Harmonic bands used by Adaptive Probe Volumes to store lighting data. Choosing L2 provides better quality but with higher memory and runtime costs."); From ea214528e5031dfc4cc5922ab814522dffbc5ca7 Mon Sep 17 00:00:00 2001 From: Emilie Thaulow Date: Sun, 15 Feb 2026 02:08:31 +0000 Subject: [PATCH 16/92] Fix usage of deprecated API usage in com.unity.render-pipelines.high-definition --- .../Core/Textures/Texture2DAtlasDynamic.cs | 54 ++++++++++++++----- .../Reflection/ReflectionProbeTextureCache.cs | 49 ++++++++--------- 2 files changed, 63 insertions(+), 40 deletions(-) diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/Texture2DAtlasDynamic.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/Texture2DAtlasDynamic.cs index 2e3247346f1..2bb8ea8229f 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/Texture2DAtlasDynamic.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/Texture2DAtlasDynamic.cs @@ -250,7 +250,7 @@ public bool IsMergeNeeded(AtlasNodePool pool) private int m_Height; private AtlasNodePool m_Pool; private Int16 m_Root; - private Dictionary m_NodeFromID; + private Dictionary m_NodeFromID; public AtlasAllocatorDynamic(int width, int height, int capacityAllocations) { @@ -259,7 +259,7 @@ public AtlasAllocatorDynamic(int width, int height, int capacityAllocations) Debug.Assert(capacityNodes < (1 << 16), "Error: AtlasAllocatorDynamic: Attempted to allocate a capacity of " + capacityNodes + ", which is greater than our 16-bit indices can support. Please request a capacity <=" + (1 << 16)); m_Pool = new AtlasNodePool((Int16)capacityNodes); - m_NodeFromID = new Dictionary(capacityAllocations); + m_NodeFromID = new Dictionary(capacityAllocations); Int16 rootParent = -1; m_Root = m_Pool.AtlasNodeCreate(rootParent); @@ -272,7 +272,7 @@ public AtlasAllocatorDynamic(int width, int height, int capacityAllocations) // Debug.Log("Allocating atlas = " + debug); } - public bool Allocate(out Vector4 result, int key, int width, int height) + public bool Allocate(out Vector4 result, TextureId key, int width, int height) { Int16 node = m_Pool.m_Nodes[m_Root].Allocate(m_Pool, width, height); if (node >= 0) @@ -288,7 +288,7 @@ public bool Allocate(out Vector4 result, int key, int width, int height) } } - public void Release(int key) + public void Release(TextureId key) { if (m_NodeFromID.TryGetValue(key, out Int16 node)) { @@ -333,6 +333,35 @@ private void DebugStringFromNode(ref string res, Int16 n, int depthCurrent = 0, } } + + + struct TextureId : IEquatable + { + EntityId m_EntityId; + int m_TextureSize; + + public TextureId(EntityId entityId, int textureSize) + { + this.m_EntityId = entityId; + this.m_TextureSize = textureSize; + } + + public bool Equals(TextureId other) + { + return m_EntityId.Equals(other.m_EntityId) && m_TextureSize == other.m_TextureSize; + } + + public override bool Equals(object obj) + { + return obj is TextureId other && Equals(other); + } + + public override int GetHashCode() + { + return HashCode.Combine(m_EntityId, m_TextureSize); + } + } + /// /// A generic Atlas texture of 2D textures. /// An atlas texture is a texture collection that collects multiple sub-textures into a single big texture. @@ -340,13 +369,14 @@ private void DebugStringFromNode(ref string res, Int16 n, int depthCurrent = 0, /// internal class Texture2DAtlasDynamic { + private RTHandle m_AtlasTexture = null; private bool isAtlasTextureOwner = false; private int m_Width; private int m_Height; private GraphicsFormat m_Format; private AtlasAllocatorDynamic m_AtlasAllocator = null; - private Dictionary m_AllocationCache; + private Dictionary m_AllocationCache; /// /// Handle to the texture of the atlas. @@ -393,7 +423,7 @@ public Texture2DAtlasDynamic(int width, int height, int capacity, GraphicsFormat isAtlasTextureOwner = true; m_AtlasAllocator = new AtlasAllocatorDynamic(width, height, capacity); - m_AllocationCache = new Dictionary(capacity); + m_AllocationCache = new Dictionary(capacity); } /// @@ -412,7 +442,7 @@ public Texture2DAtlasDynamic(int width, int height, int capacity, RTHandle atlas isAtlasTextureOwner = false; m_AtlasAllocator = new AtlasAllocatorDynamic(width, height, capacity); - m_AllocationCache = new Dictionary(capacity); + m_AllocationCache = new Dictionary(capacity); } /// @@ -442,9 +472,7 @@ public void ResetAllocator() /// Returns True if Unity successfully adds the texture. public bool AddTexture(CommandBuffer cmd, out Vector4 scaleOffset, Texture texture) { -#pragma warning disable 618 // Todo(@daniel.andersen): Potentially use GetRawData or sometin' - int key = texture.GetEntityId(); -#pragma warning restore 618 + TextureId key = new TextureId(texture.GetEntityId(),texture.width); if (!m_AllocationCache.TryGetValue(key, out scaleOffset)) { int width = texture.width; @@ -474,7 +502,7 @@ public bool AddTexture(CommandBuffer cmd, out Vector4 scaleOffset, Texture textu /// The texture rectangle coordinates in the atlas. /// The key that identifies the texture. /// Returns True if the texture is cached. - public bool IsCached(out Vector4 scaleOffset, int key) + public bool IsCached(out Vector4 scaleOffset, TextureId key) { return m_AllocationCache.TryGetValue(key, out scaleOffset); } @@ -488,7 +516,7 @@ public bool IsCached(out Vector4 scaleOffset, int key) /// Width of the texture. /// Height of the texture. /// Returns True if Unity successfully allocates the slot. - public bool EnsureTextureSlot(out bool isUploadNeeded, out Vector4 scaleOffset, int key, int width, int height) + public bool EnsureTextureSlot(out bool isUploadNeeded, out Vector4 scaleOffset, TextureId key, int width, int height) { isUploadNeeded = false; if (m_AllocationCache.TryGetValue(key, out scaleOffset)) { return true; } @@ -507,7 +535,7 @@ public bool EnsureTextureSlot(out bool isUploadNeeded, out Vector4 scaleOffset, /// Release allocated space from the atlas. /// /// The key that identifies the texture. - public void ReleaseTextureSlot(int key) + public void ReleaseTextureSlot(TextureId key) { m_AtlasAllocator.Release(key); m_AllocationCache.Remove(key); diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Reflection/ReflectionProbeTextureCache.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Reflection/ReflectionProbeTextureCache.cs index d4ba0df255a..64df32734bb 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Reflection/ReflectionProbeTextureCache.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Reflection/ReflectionProbeTextureCache.cs @@ -29,8 +29,8 @@ class ReflectionProbeTextureCache int m_CubeFrameFetchIndex; int m_PlanarFrameFetchIndex; - Dictionary m_TextureLRUAndHash = new Dictionary(); - List<(int, uint)> m_TextureLRUSorted = new List<(int, uint)>(); + Dictionary m_TextureLRUAndHash = new Dictionary(); + List<(TextureId, uint)> m_TextureLRUSorted = new List<(TextureId, uint)>(); Material m_ConvertTextureMaterial; MaterialPropertyBlock m_ConvertTexturePropertyBlock = new MaterialPropertyBlock(); @@ -104,22 +104,17 @@ public ReflectionProbeTextureCache( m_ConvertTextureMaterial = CoreUtils.CreateEngineMaterial(renderPipeline.runtimeShaders.blitCubeTextureFacePS); } - private static int GetTextureID(HDProbe probe) + private static TextureId GetTextureID(HDProbe probe) { return GetTextureIDAndSize(probe, out int _); } - private static int GetTextureIDAndSize(HDProbe probe, out int textureSize) + private static TextureId GetTextureIDAndSize(HDProbe probe, out int textureSize) { textureSize = GetTextureSizeInAtlas(probe); + TextureId textureId = new TextureId(probe.texture.GetEntityId(), textureSize); - int textureHash = probe.texture.GetEntityId().GetHashCode(); - - // Include texture size in ID using simple hash - const int kPrime = 31; - textureHash = kPrime * textureHash + textureSize; - - return textureHash; + return textureId; } private static int GetTextureSizeInAtlas(HDProbe probe) @@ -202,16 +197,16 @@ private void LogErrorNoMoreSpaceOnce() Debug.LogError("No more space in Reflection Probe Atlas. To solve this issue, increase the size of the Reflection Probe Atlas in the HDRP settings."); } - private bool NeedsUpdate(int textureId, uint textureHash, ref Vector4 scaleOffset) + private bool NeedsUpdate(TextureId textureTextureId, uint textureHash, ref Vector4 scaleOffset) { bool needsUpdate = false; - if (!m_Atlas.IsCached(out scaleOffset, textureId)) + if (!m_Atlas.IsCached(out scaleOffset, textureTextureId)) needsUpdate = true; - else if (!m_TextureLRUAndHash.TryGetValue(textureId, out (uint, uint hash) entry) || entry.hash != textureHash) + else if (!m_TextureLRUAndHash.TryGetValue(textureTextureId, out (uint, uint hash) entry) || entry.hash != textureHash) needsUpdate = true; - m_TextureLRUAndHash[textureId] = (m_CurrentRender, textureHash); + m_TextureLRUAndHash[textureTextureId] = (m_CurrentRender, textureHash); return needsUpdate; } @@ -400,7 +395,7 @@ private void BlitTexture2D(CommandBuffer cmd, Vector4 scaleOffset, Vector4 sourc private bool RelayoutTextureAtlas() { - using (ListPool<(int textureId, Vector4 scaleOffset)>.Get(out var atlasEntries)) + using (ListPool<(TextureId textureId, Vector4 scaleOffset)>.Get(out var atlasEntries)) { atlasEntries.Capacity = m_TextureLRUAndHash.Count; @@ -448,14 +443,14 @@ private bool RelayoutTextureAtlas() } } - private bool TryAllocateTexture(int textureId, int textureSize, ref Vector4 scaleOffset) + private bool TryAllocateTexture(TextureId textureTextureId, int textureSize, ref Vector4 scaleOffset) { Assert.IsTrue(Mathf.IsPowerOfTwo(textureSize)); - Assert.IsTrue(!m_Atlas.IsCached(out _, textureId)); + Assert.IsTrue(!m_Atlas.IsCached(out _, textureTextureId)); // 1. // The first direct attempt to find space. - if (m_Atlas.EnsureTextureSlot(out _, out scaleOffset, textureId, textureSize, textureSize)) + if (m_Atlas.EnsureTextureSlot(out _, out scaleOffset, textureTextureId, textureSize, textureSize)) return true; // 2. @@ -473,7 +468,7 @@ private bool TryAllocateTexture(int textureId, int textureSize, ref Vector4 scal m_TextureLRUAndHash.Remove(textureLRU.Item1); m_TextureLRUSorted.RemoveAt(textureIndex); - if (m_Atlas.EnsureTextureSlot(out _, out scaleOffset, textureId, textureSize, textureSize)) + if (m_Atlas.EnsureTextureSlot(out _, out scaleOffset, textureTextureId, textureSize, textureSize)) return true; } else @@ -486,11 +481,11 @@ private bool TryAllocateTexture(int textureId, int textureSize, ref Vector4 scal // Try to downscale texture and find space. if (m_DecreaseResToFit) { - if (m_Atlas.EnsureTextureSlot(out _, out scaleOffset, textureId, textureSize / 2, textureSize / 2)) + if (m_Atlas.EnsureTextureSlot(out _, out scaleOffset, textureTextureId, textureSize / 2, textureSize / 2)) return true; } - m_TextureLRUAndHash.Remove(textureId); + m_TextureLRUAndHash.Remove(textureTextureId); return false; } @@ -501,7 +496,7 @@ private bool UpdateTexture(CommandBuffer cmd, HDProbe probe, ref Vector4 scaleOf { Texture texture = probe.texture; - int textureId = GetTextureIDAndSize(probe, out int textureSize); + TextureId textureId = GetTextureIDAndSize(probe, out int textureSize); if (!m_Atlas.IsCached(out scaleOffset, textureId)) { @@ -527,7 +522,7 @@ private bool UpdateTexture(CommandBuffer cmd, HDProbe probe, ref IBLFilterBSDF.P { Texture texture = probe.texture; - int textureId = GetTextureIDAndSize(probe, out int textureSize); + TextureId textureId = GetTextureIDAndSize(probe, out int textureSize); if (!m_Atlas.IsCached(out scaleOffset, textureId)) { @@ -606,7 +601,7 @@ public Vector4 FetchCubeReflectionProbe(CommandBuffer cmd, HDProbe probe, out in Vector4 scaleOffset = Vector4.zero; - int textureId = GetTextureID(probe); + TextureId textureId = GetTextureID(probe); if (NeedsUpdate(textureId, probe.GetTextureHash(), ref scaleOffset)) { @@ -627,7 +622,7 @@ public Vector4 FetchPlanarReflectionProbe(CommandBuffer cmd, HDProbe probe, ref Vector4 scaleOffset = Vector4.zero; - int textureId = GetTextureID(probe); + TextureId textureId = GetTextureID(probe); if (NeedsUpdate(textureId, probe.GetTextureHash(), ref scaleOffset)) { @@ -644,7 +639,7 @@ public void ReserveReflectionProbeSlot(HDProbe probe) Assert.IsTrue(texture.width == texture.height, "Reflection probe should be a square texture. Check the import settings of the texture, or your Texture Importer presets"); Assert.IsTrue(texture.dimension == TextureDimension.Tex2D || texture.dimension == TextureDimension.Cube, "Reflection probe should be a 2D or Cube texture. Check the import settings of the texture, or your Texture Importer presets"); - int textureId = GetTextureIDAndSize(probe, out int textureSize); + TextureId textureId = GetTextureIDAndSize(probe, out int textureSize); if (!m_Atlas.IsCached(out _, textureId)) { From 30a4aa0cfdc21c66fc7331dcc347cd101ae0d456 Mon Sep 17 00:00:00 2001 From: Tim Cannell Date: Sun, 15 Feb 2026 02:08:32 +0000 Subject: [PATCH 17/92] [content automatically redacted] touching PlatformDependent folder --- .../Assets/Tests/HDRP_VisualEffectsGraph_GraphicsTests.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Tests/SRPTests/Projects/VisualEffectGraph_HDRP/Assets/Tests/HDRP_VisualEffectsGraph_GraphicsTests.cs b/Tests/SRPTests/Projects/VisualEffectGraph_HDRP/Assets/Tests/HDRP_VisualEffectsGraph_GraphicsTests.cs index 63246f066e9..4faf68ebe36 100644 --- a/Tests/SRPTests/Projects/VisualEffectGraph_HDRP/Assets/Tests/HDRP_VisualEffectsGraph_GraphicsTests.cs +++ b/Tests/SRPTests/Projects/VisualEffectGraph_HDRP/Assets/Tests/HDRP_VisualEffectsGraph_GraphicsTests.cs @@ -30,6 +30,9 @@ public class VFXGraphicsTests [IgnoreGraphicsTest("39_SmokeLighting_APV", "Too many bindings when using APVs", runtimePlatforms: new RuntimePlatform[] { RuntimePlatform.Switch })] [IgnoreGraphicsTest("102_ShadergraphShadow", "See UUM-96202", runtimePlatforms: new RuntimePlatform[] { RuntimePlatform.Switch })] [IgnoreGraphicsTest("015_FixedTime", "See UUM-109089", runtimePlatforms: new RuntimePlatform[] { RuntimePlatform.Switch })] + [IgnoreGraphicsTest("DebugAlbedo", "Onscreen assert", runtimePlatforms: new RuntimePlatform[] { RuntimePlatform.Switch2 })] + [IgnoreGraphicsTest("36_SkinnedSDF", "Onscreen assert", runtimePlatforms: new RuntimePlatform[] { RuntimePlatform.Switch2 })] + [IgnoreGraphicsTest("015_FixedTime", "Onscreen assert", runtimePlatforms: new RuntimePlatform[] { RuntimePlatform.Switch2 })] [IgnoreGraphicsTest("Repro_SampleGradient_Branch_Instancing", "Compute shader ([Repro_SampleGradient_Branch_Instancing] [Minimal] Update Particles): Property (Repro_SampleGradient_Branch_Instancing_Buffer) at kernel index (0) is not set")] [IgnoreGraphicsTest("Empty", "No reference images provided")] [IgnoreGraphicsTest("Empty_With_Camera", "No reference images provided")] From 57ce5b61cb890f84c47c3f97e85d43ebcf9eb090 Mon Sep 17 00:00:00 2001 From: Kirill Titov Date: Mon, 16 Feb 2026 03:42:18 +0000 Subject: [PATCH 18/92] [content automatically redacted] touching PlatformDependent folder --- .../Editor-PrivateShared/Editors.meta | 3 ++ .../Editors/HaloEditor.cs | 31 +++++++++++++++++ .../Editors/HaloEditor.cs.meta | 3 ++ .../Lighting/LightProbeProxyVolumeEditor.cs | 31 +++++++++++++++++ .../LightProbeProxyVolumeEditor.cs.meta | 3 ++ .../Editor/PostProcessing/LensFlareEditor.cs | 19 +++++++++-- .../Editor/ProjectorEditor.cs | 21 ------------ .../ProbeVolume/ProbeReferenceVolume.Debug.cs | 6 ++-- .../Editor/Material/Decal/ProjectorEditor.cs | 32 ++++++++++++++++++ .../Material/Decal/ProjectorEditor.cs.meta | 3 ++ .../Editor/Decal/ProjectorEditor.cs | 33 +++++++++++++++++++ .../Editor/Decal}/ProjectorEditor.cs.meta | 0 .../Editor/Inspector/VisualEffectEditor.cs | 2 ++ 13 files changed, 160 insertions(+), 27 deletions(-) create mode 100644 Packages/com.unity.render-pipelines.core/Editor-PrivateShared/Editors.meta create mode 100644 Packages/com.unity.render-pipelines.core/Editor-PrivateShared/Editors/HaloEditor.cs create mode 100644 Packages/com.unity.render-pipelines.core/Editor-PrivateShared/Editors/HaloEditor.cs.meta create mode 100644 Packages/com.unity.render-pipelines.core/Editor/Lighting/LightProbeProxyVolumeEditor.cs create mode 100644 Packages/com.unity.render-pipelines.core/Editor/Lighting/LightProbeProxyVolumeEditor.cs.meta delete mode 100644 Packages/com.unity.render-pipelines.core/Editor/ProjectorEditor.cs create mode 100644 Packages/com.unity.render-pipelines.high-definition/Editor/Material/Decal/ProjectorEditor.cs create mode 100644 Packages/com.unity.render-pipelines.high-definition/Editor/Material/Decal/ProjectorEditor.cs.meta create mode 100644 Packages/com.unity.render-pipelines.universal/Editor/Decal/ProjectorEditor.cs rename Packages/{com.unity.render-pipelines.core/Editor => com.unity.render-pipelines.universal/Editor/Decal}/ProjectorEditor.cs.meta (100%) diff --git a/Packages/com.unity.render-pipelines.core/Editor-PrivateShared/Editors.meta b/Packages/com.unity.render-pipelines.core/Editor-PrivateShared/Editors.meta new file mode 100644 index 00000000000..297d7b6f34f --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor-PrivateShared/Editors.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c6b7cefa8aef4df7a9901f140f4c27fd +timeCreated: 1769434100 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Editor-PrivateShared/Editors/HaloEditor.cs b/Packages/com.unity.render-pipelines.core/Editor-PrivateShared/Editors/HaloEditor.cs new file mode 100644 index 00000000000..4178151cfbd --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor-PrivateShared/Editors/HaloEditor.cs @@ -0,0 +1,31 @@ +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.Rendering; + +namespace UnityEditor +{ +#pragma warning disable CS0618 // Type or member is obsolete + [CustomEditor(typeof(Halo))] + [CanEditMultipleObjects] + class HaloEditor : Editor + { + public override void OnInspectorGUI() + { + if (GraphicsSettings.isScriptableRenderPipelineEnabled) + { + const int offsetToMatchWarning = 16; + Rect buttonRect = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight); + buttonRect.x -= offsetToMatchWarning; + buttonRect.width += offsetToMatchWarning; + + if (GUI.Button(buttonRect, "Add Lens Flare (SRP) component") && serializedObject.targetObject is Halo halo) + { + halo.gameObject.AddComponent(); + EditorSceneManager.MarkSceneDirty(halo.gameObject.scene); + } + } + + DrawDefaultInspector(); + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Editor-PrivateShared/Editors/HaloEditor.cs.meta b/Packages/com.unity.render-pipelines.core/Editor-PrivateShared/Editors/HaloEditor.cs.meta new file mode 100644 index 00000000000..f0a27e4222a --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor-PrivateShared/Editors/HaloEditor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7a95ead01cb04bdeaea7c74de1f5cbc0 +timeCreated: 1769434012 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/LightProbeProxyVolumeEditor.cs b/Packages/com.unity.render-pipelines.core/Editor/Lighting/LightProbeProxyVolumeEditor.cs new file mode 100644 index 00000000000..eb20a2b98e2 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/LightProbeProxyVolumeEditor.cs @@ -0,0 +1,31 @@ +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.Rendering; + +namespace UnityEditor +{ +#pragma warning disable CS0618 // Type or member is obsolete + [CustomEditor(typeof(LightProbeProxyVolume))] + [CanEditMultipleObjects] + class LightProbeProxyVolumeEditor : Editor + { + public override void OnInspectorGUI() + { + if (GraphicsSettings.isScriptableRenderPipelineEnabled) + { + const int offsetToMatchWarning = 16; + Rect buttonRect = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight); + buttonRect.x -= offsetToMatchWarning; + buttonRect.width += offsetToMatchWarning; + + if (GUI.Button(buttonRect, "Add Adaptive Probe Volume component") && serializedObject.targetObject is LightProbeProxyVolume proxy) + { + proxy.gameObject.AddComponent(); + EditorSceneManager.MarkSceneDirty(proxy.gameObject.scene); + } + } + + DrawDefaultInspector(); + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Editor/Lighting/LightProbeProxyVolumeEditor.cs.meta b/Packages/com.unity.render-pipelines.core/Editor/Lighting/LightProbeProxyVolumeEditor.cs.meta new file mode 100644 index 00000000000..029edce9f16 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/Lighting/LightProbeProxyVolumeEditor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5b86cda6eb63450080e6726b3da61158 +timeCreated: 1769435788 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Editor/PostProcessing/LensFlareEditor.cs b/Packages/com.unity.render-pipelines.core/Editor/PostProcessing/LensFlareEditor.cs index bc452231970..b70bb48c2a8 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/PostProcessing/LensFlareEditor.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/PostProcessing/LensFlareEditor.cs @@ -1,8 +1,10 @@ +using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.Rendering; namespace UnityEditor { +#pragma warning disable CS0618 // Type or member is obsolete /// /// Editor for Lens Flare (builtin): Editor to show an error message /// @@ -16,9 +18,20 @@ class LensFlareEditor : Editor public override void OnInspectorGUI() { if (GraphicsSettings.isScriptableRenderPipelineEnabled) - EditorGUILayout.HelpBox("This component doesn't work on SRP, use Lens Flare (SRP) instead.", MessageType.Error); - else - DrawDefaultInspector(); + { + const int offsetToMatchWarning = 16; + Rect buttonRect = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight); + buttonRect.x -= offsetToMatchWarning; + buttonRect.width += offsetToMatchWarning; + + if (GUI.Button(buttonRect, "Add Lens Flare (SRP) component") && serializedObject.targetObject is LensFlare lensFlare) + { + lensFlare.gameObject.AddComponent(); + EditorSceneManager.MarkSceneDirty(lensFlare.gameObject.scene); + } + } + + DrawDefaultInspector(); } } } diff --git a/Packages/com.unity.render-pipelines.core/Editor/ProjectorEditor.cs b/Packages/com.unity.render-pipelines.core/Editor/ProjectorEditor.cs deleted file mode 100644 index 4020bd278f1..00000000000 --- a/Packages/com.unity.render-pipelines.core/Editor/ProjectorEditor.cs +++ /dev/null @@ -1,21 +0,0 @@ -using UnityEngine; -using UnityEngine.Rendering; - -namespace UnityEditor.Rendering -{ - [CustomEditor(typeof(Projector))] - [CanEditMultipleObjects] - class ProjectorEditor : Editor - { - static readonly GUIContent k_Message = - EditorGUIUtility.TrTextContent("The active render pipeline does not support the Projector component. If using HDRP or URP, use the Decal Projector component instead."); - - public override void OnInspectorGUI() - { - if (GraphicsSettings.isScriptableRenderPipelineEnabled) - EditorGUILayout.HelpBox(k_Message.text, MessageType.Warning); - else - DrawDefaultInspector(); - } - } -} diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.Debug.cs b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.Debug.cs index 7c7b09e7ee5..a7137ae055f 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.Debug.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.Debug.cs @@ -1056,7 +1056,7 @@ void DrawProbeDebug(Camera camera, Texture exposureTexture) var probeBuffer = debug.probeBuffers[i]; m_DebugMaterial.SetInt("_DebugProbeVolumeSampling", 0); m_DebugMaterial.SetBuffer("_positionNormalBuffer", probeSamplingDebugData.positionNormalBuffer); - Graphics.DrawMeshInstanced(debugMesh, 0, m_DebugMaterial, probeBuffer, probeBuffer.Length, props, ShadowCastingMode.Off, false, 0, camera, LightProbeUsage.Off, null); + Graphics.DrawMeshInstanced(debugMesh, 0, m_DebugMaterial, probeBuffer, probeBuffer.Length, props, ShadowCastingMode.Off, false, 0, camera, LightProbeUsage.Off); } if (probeVolumeDebug.drawProbeSamplingDebug) @@ -1068,7 +1068,7 @@ void DrawProbeDebug(Camera camera, Texture exposureTexture) props.SetInt("_DebugSamplingNoise", Convert.ToInt32(probeVolumeDebug.debugWithSamplingNoise)); props.SetInt("_RenderingLayerMask", (int)probeVolumeDebug.samplingRenderingLayer); m_ProbeSamplingDebugMaterial02.SetBuffer("_positionNormalBuffer", probeSamplingDebugData.positionNormalBuffer); - Graphics.DrawMeshInstanced(debugMesh, 0, m_ProbeSamplingDebugMaterial02, probeBuffer, probeBuffer.Length, props, ShadowCastingMode.Off, false, 0, camera, LightProbeUsage.Off, null); + Graphics.DrawMeshInstanced(debugMesh, 0, m_ProbeSamplingDebugMaterial02, probeBuffer, probeBuffer.Length, props, ShadowCastingMode.Off, false, 0, camera, LightProbeUsage.Off); } if (probeVolumeDebug.drawVirtualOffsetPush) @@ -1077,7 +1077,7 @@ void DrawProbeDebug(Camera camera, Texture exposureTexture) m_DebugOffsetMaterial.SetInt("_AdjustmentVolumeCount", probeVolumeDebug.isolationProbeDebug ? adjustmentVolumeCount : 0); var offsetBuffer = debug.offsetBuffers[i]; - Graphics.DrawMeshInstanced(m_DebugOffsetMesh, 0, m_DebugOffsetMaterial, offsetBuffer, offsetBuffer.Length, props, ShadowCastingMode.Off, false, 0, camera, LightProbeUsage.Off, null); + Graphics.DrawMeshInstanced(m_DebugOffsetMesh, 0, m_DebugOffsetMaterial, offsetBuffer, offsetBuffer.Length, props, ShadowCastingMode.Off, false, 0, camera, LightProbeUsage.Off); } } } diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Decal/ProjectorEditor.cs b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Decal/ProjectorEditor.cs new file mode 100644 index 00000000000..aa24136d0ea --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Decal/ProjectorEditor.cs @@ -0,0 +1,32 @@ +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.Rendering.HighDefinition; + +namespace UnityEditor.Rendering +{ +#pragma warning disable CS0618 // Type or member is obsolete + [CustomEditor(typeof(Projector))] + [CanEditMultipleObjects] + class ProjectorEditor : Editor + { + public override void OnInspectorGUI() + { + if (GraphicsSettings.currentRenderPipelineAssetType == typeof(HDRenderPipelineAsset)) + { + const int offsetToMatchWarning = 16; + Rect buttonRect = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight); + buttonRect.x -= offsetToMatchWarning; + buttonRect.width += offsetToMatchWarning; + + if (GUI.Button(buttonRect,"Add HDRP Decal Projector component") && serializedObject.targetObject is Projector lensFlare) + { + lensFlare.gameObject.AddComponent(); + EditorSceneManager.MarkSceneDirty(lensFlare.gameObject.scene); + } + } + + DrawDefaultInspector(); + } + } +} diff --git a/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Decal/ProjectorEditor.cs.meta b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Decal/ProjectorEditor.cs.meta new file mode 100644 index 00000000000..59aad5a6dfc --- /dev/null +++ b/Packages/com.unity.render-pipelines.high-definition/Editor/Material/Decal/ProjectorEditor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ad84ea7c80d949b0a2cdb9c02fc32b7f +timeCreated: 1769433756 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.universal/Editor/Decal/ProjectorEditor.cs b/Packages/com.unity.render-pipelines.universal/Editor/Decal/ProjectorEditor.cs new file mode 100644 index 00000000000..80c6c18f76c --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Editor/Decal/ProjectorEditor.cs @@ -0,0 +1,33 @@ +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.Rendering.Universal; + +namespace UnityEditor.Rendering +{ +#pragma warning disable CS0618 // Type or member is obsolete + [CustomEditor(typeof(Projector))] + [CanEditMultipleObjects] + class ProjectorEditor : Editor + { + public override void OnInspectorGUI() + { + if (GraphicsSettings.currentRenderPipelineAssetType == typeof(UniversalRenderPipelineAsset)) + { + const int offsetToMatchWarning = 16; + Rect buttonRect = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight); + buttonRect.x -= offsetToMatchWarning; + buttonRect.width += offsetToMatchWarning; + + if (GUI.Button(buttonRect,"Add URP Decal Projector component") && serializedObject.targetObject is Projector lensFlare) + { + lensFlare.gameObject.AddComponent(); + EditorSceneManager.MarkSceneDirty(lensFlare.gameObject.scene); + } + + } + + DrawDefaultInspector(); + } + } +} diff --git a/Packages/com.unity.render-pipelines.core/Editor/ProjectorEditor.cs.meta b/Packages/com.unity.render-pipelines.universal/Editor/Decal/ProjectorEditor.cs.meta similarity index 100% rename from Packages/com.unity.render-pipelines.core/Editor/ProjectorEditor.cs.meta rename to Packages/com.unity.render-pipelines.universal/Editor/Decal/ProjectorEditor.cs.meta diff --git a/Packages/com.unity.visualeffectgraph/Editor/Inspector/VisualEffectEditor.cs b/Packages/com.unity.visualeffectgraph/Editor/Inspector/VisualEffectEditor.cs index ff31ffd3590..617541e3f39 100644 --- a/Packages/com.unity.visualeffectgraph/Editor/Inspector/VisualEffectEditor.cs +++ b/Packages/com.unity.visualeffectgraph/Editor/Inspector/VisualEffectEditor.cs @@ -1403,12 +1403,14 @@ public void OnInspectorGUI() m_LightProbeUsage.intValue = (int)(LightProbeUsage)newValue; EditorGUI.EndProperty(); +#pragma warning disable CS0618 if (!m_LightProbeUsage.hasMultipleDifferentValues && m_LightProbeUsage.intValue == (int)LightProbeUsage.UseProxyVolume) { if (!LightProbeProxyVolume.isFeatureSupported || !SupportedRenderingFeatures.active.lightProbeProxyVolumes) EditorGUILayout.HelpBox(Contents.lightProbeVolumeUnsupportedNote.text, MessageType.Warning); EditorGUILayout.PropertyField(m_LightProbeVolumeOverride, Contents.lightProbeVolumeOverrideStyle); } +#pragma warning restore CS0618 } bool useReflectionProbes = m_ReflectionProbeUsage != null && !m_ReflectionProbeUsage.hasMultipleDifferentValues && (ReflectionProbeUsage)m_ReflectionProbeUsage.intValue != ReflectionProbeUsage.Off; From ef5ffabacbecb562ac9f16d096327f5f59d7193f Mon Sep 17 00:00:00 2001 From: Pema Malling Date: Mon, 16 Feb 2026 03:42:18 +0000 Subject: [PATCH 19/92] Add round robin light sampling and fix several bugs in light sampling --- .../PathTracing/BakeInputToWorldConversion.cs | 38 ++-- .../Runtime/PathTracing/BakeLightmapDriver.cs | 4 +- .../PathTracing/LightmapIntegration.cs | 25 ++- .../Runtime/PathTracing/ManyLightSampling.cs | 25 +++ .../Runtime/PathTracing/PathTracingUtil.cs | 4 +- .../Runtime/PathTracing/ProbeIntegrator.cs | 35 ++- .../PathTracing/Shaders/LightSampling.hlsl | 203 +++++++++++------- .../LightmapDirectIntegration.urtshader | 124 +++++++---- .../LightmapShadowMaskIntegration.urtshader | 5 +- .../PathTracing/Shaders/PathTracing.hlsl | 16 +- .../Shaders/PathTracingRandom.hlsl | 18 ++ .../Shaders/PathTracingSampler.hlsl | 24 +-- .../Shaders/ProbeIntegrationDirect.urtshader | 23 +- .../ProbeIntegrationOcclusion.urtshader | 6 +- .../UnityComputeProbeIntegrator.cs | 19 +- .../Runtime/PathTracing/World.cs | 12 ++ .../Runtime/Sampling/PseudoRandom.hlsl | 8 +- 17 files changed, 392 insertions(+), 197 deletions(-) diff --git a/Packages/com.unity.render-pipelines.core/Editor/PathTracing/BakeInputToWorldConversion.cs b/Packages/com.unity.render-pipelines.core/Editor/PathTracing/BakeInputToWorldConversion.cs index ff5ba7c9097..a1b25a02818 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/PathTracing/BakeInputToWorldConversion.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/PathTracing/BakeInputToWorldConversion.cs @@ -375,6 +375,22 @@ internal static Mesh TerrainDataToMesh(in TerrainData terrainData, in HeightmapD return outMesh; } + private static Bounds CalculateMeshBounds(Vector3[] vertices, Matrix4x4 localToWorldMatrix4x4, out Vector3 meshMinVertex, out Vector3 meshMaxVertex) + { + meshMinVertex = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); + meshMaxVertex = new Vector3(float.MinValue, float.MinValue, float.MinValue); + foreach (Vector3 vert in vertices) + { + // TODO: transform the bounding box instead of looping verts (https://jira.unity3d.com/browse/GFXFEAT-667) + Vector3 v = localToWorldMatrix4x4.MultiplyPoint(vert); + meshMinVertex = Vector3.Min(v, meshMinVertex); + meshMaxVertex = Vector3.Max(v, meshMaxVertex); + } + Bounds meshBounds = new Bounds(); + meshBounds.SetMinMax(meshMinVertex, meshMaxVertex); + return meshBounds; + } + internal static void ConvertInstancesAndMeshes( World world, in BakeInput bakeInput, @@ -386,8 +402,6 @@ internal static void ConvertInstancesAndMeshes( List allocatedObjects, uint renderingObjectLayer) { - sceneBounds = new Bounds(); - // Extract meshes meshes = new Mesh[bakeInput.meshData.Length + bakeInput.terrainData.Length]; int meshIndex = 0; @@ -423,6 +437,9 @@ internal static void ConvertInstancesAndMeshes( RenderedGameObjectsFilter filter = RenderedGameObjectsFilter.OnlyStatic; const bool isStatic = true; + Vector3 sceneMinVertex = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); + Vector3 sceneMaxVertex = new Vector3(float.MinValue, float.MinValue, float.MinValue); + // Extract instances List fatInstanceList = new(); for (int i = 0; i < bakeInput.instanceData.Length; i++) @@ -444,17 +461,11 @@ internal static void ConvertInstancesAndMeshes( Vector2 uvBoundsOffset = uvBoundsOffsets[globalMeshIndex]; // Calculate bounds - var bounds = new Bounds(); - foreach (Vector3 vert in mesh.vertices) - { - bounds.Encapsulate(localToWorldMatrix4x4.MultiplyPoint(vert)); // TODO: transform the bounding box instead of looping verts (https://jira.unity3d.com/browse/GFXFEAT-667) - } + Bounds meshBounds = CalculateMeshBounds(mesh.vertices, localToWorldMatrix4x4, out Vector3 meshMinVertex, out Vector3 meshMaxVertex); // Keep track of scene bounds as we go - if (i == 0) - sceneBounds = bounds; - else - sceneBounds.Encapsulate(bounds); + sceneMinVertex = Vector3.Min(sceneMinVertex, meshMinVertex); + sceneMaxVertex = Vector3.Max(sceneMaxVertex, meshMaxVertex); // Get masks uint[] subMeshMasks = new uint[mesh.subMeshCount]; @@ -477,7 +488,7 @@ internal static void ConvertInstancesAndMeshes( Materials = materials, SubMeshMasks = subMeshMasks, LocalToWorldMatrix = localToWorldMatrix4x4, - Bounds = bounds, + Bounds = meshBounds, IsStatic = isStatic, LodIdentifier = lodIdentifier, ReceiveShadows = instanceData.receiveShadows, @@ -489,6 +500,9 @@ internal static void ConvertInstancesAndMeshes( } fatInstances = fatInstanceList.ToArray(); Debug.Assert(fatInstances.Length == bakeInput.instanceData.Length); + + sceneBounds = new Bounds(); + sceneBounds.SetMinMax(sceneMinVertex, sceneMaxVertex); } internal static void PopulateWorld(InputExtraction.BakeInput input, UnityComputeWorld world, SamplingResources samplingResources, CommandBuffer cmd, bool autoEstimateLUTRange) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/BakeLightmapDriver.cs b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/BakeLightmapDriver.cs index a72ab26ebce..ed23964ed80 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/BakeLightmapDriver.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/BakeLightmapDriver.cs @@ -253,7 +253,7 @@ internal static uint AccumulateLightmapInstance( string sampleOutput = new(""); foreach (var sample in uvSampleData) sampleOutput += string.Format(System.Globalization.CultureInfo.InvariantCulture, "float2({0}, {1})\n", sample.x, sample.y); - + System.Console.WriteLine(sampleOutput); } @@ -332,6 +332,7 @@ internal static uint AccumulateLightmapInstance( instance.ReceiveShadows, lightmapBakeSettings.PushOff, lightmapBakeSettings.DirectLightingEvaluationCount, + (uint)lightmappingContext.World.PathTracingWorld.MaxLightsInAnyCell, newChunkStarted ); break; @@ -384,7 +385,6 @@ internal static uint AccumulateLightmapInstance( lightmappingContext.IntegratorContext.CompactedGBufferLength, instance.ReceiveShadows, lightmapBakeSettings.PushOff, - lightmapBakeSettings.DirectLightingEvaluationCount, newChunkStarted ); break; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/LightmapIntegration.cs b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/LightmapIntegration.cs index c08a922417e..4fe13bde428 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/LightmapIntegration.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/LightmapIntegration.cs @@ -58,6 +58,7 @@ internal static class LightmapIntegratorShaderIDs public static readonly int ExpandedSampleCountInW = Shader.PropertyToID("g_ExpandedSampleCountInW"); public static readonly int ExpandedTexelSampleWidth = Shader.PropertyToID("g_ExpandedTexelSampleWidth"); public static readonly int MaxLocalSampleCount = Shader.PropertyToID("g_MaxLocalSampleCount"); + public static readonly int LightIndexInCell = Shader.PropertyToID("g_LightIndexInCell"); public static readonly int SourceBuffer = Shader.PropertyToID("g_SourceBuffer"); public static readonly int SourceLength = Shader.PropertyToID("g_SourceLength"); public static readonly int SourceStride = Shader.PropertyToID("g_SourceStride"); @@ -153,7 +154,8 @@ public void Accumulate( GraphicsBuffer compactedGbufferLength, bool receiveShadows, float pushOff, - uint lightEvaluationsPerBounce, + uint risCandidateCount, + uint maxLightsInAnyCell, bool newChunkStarted) { bool doDirectional = expandedDirectional != null; @@ -167,7 +169,7 @@ public void Accumulate( // path tracing inputs bool preExpose = false; float environmentIntensityMultiplier = 1.0f; - Util.BindPathTracingInputs(cmd, _accumulationShader, false, lightEvaluationsPerBounce, preExpose, 0, environmentIntensityMultiplier, RenderedGameObjectsFilter.OnlyStatic, _samplingResources, _emptyTexture); + Util.BindPathTracingInputs(cmd, _accumulationShader, false, risCandidateCount, preExpose, 0, environmentIntensityMultiplier, RenderedGameObjectsFilter.OnlyStatic, _samplingResources, _emptyTexture); Util.BindWorld(cmd, _accumulationShader, world); var requiredSizeInBytes = _accumulationShader.GetTraceScratchBufferRequiredSizeInBytes((uint)expandedOutput.count, 1, 1); @@ -205,9 +207,15 @@ public void Accumulate( { _accumulationShader.SetIntParam(cmd, LightmapIntegratorShaderIDs.SampleOffset, (int)currentSampleCountPerTexel); _accumulationShader.SetIntParam(cmd, LightmapIntegratorShaderIDs.MaxLocalSampleCount, (int)sampleCountToTakePerTexel); - cmd.BeginSample("Accumulation (Expanded)"); - _accumulationShader.Dispatch(cmd, traceScratchBuffer, _accumulationDispatchBuffer); - cmd.EndSample("Accumulation (Expanded)"); + + uint loopCount = maxLightsInAnyCell; + for (int lightIndexInCell = 0; lightIndexInCell < loopCount; ++lightIndexInCell) + { + _accumulationShader.SetIntParam(cmd, LightmapIntegratorShaderIDs.LightIndexInCell, lightIndexInCell); + cmd.BeginSample("Accumulation (Expanded)"); + _accumulationShader.Dispatch(cmd, traceScratchBuffer, _accumulationDispatchBuffer); + cmd.EndSample("Accumulation (Expanded)"); + } } } @@ -293,7 +301,7 @@ public void Accumulate( GraphicsBuffer compactedTexelIndices, GraphicsBuffer compactedGbufferLength, float pushOff, - uint lightEvaluationsPerBounce, + uint risCandidateCount, bool newChunkStarted) { bool doDirectional = expandedDirectional != null; @@ -307,7 +315,7 @@ public void Accumulate( // path tracing inputs bool preExpose = false; float environmentIntensityMultiplier = 1.0f; - Util.BindPathTracingInputs(cmd, _accumulationShader, _countNEERayAsPathSegment, lightEvaluationsPerBounce, preExpose, (int)bounceCount, environmentIntensityMultiplier, RenderedGameObjectsFilter.OnlyStatic, _samplingResources, _emptyTexture); + Util.BindPathTracingInputs(cmd, _accumulationShader, _countNEERayAsPathSegment, risCandidateCount, preExpose, (int)bounceCount, environmentIntensityMultiplier, RenderedGameObjectsFilter.OnlyStatic, _samplingResources, _emptyTexture); Util.BindWorld(cmd, _accumulationShader, world); var requiredSizeInBytes = _accumulationShader.GetTraceScratchBufferRequiredSizeInBytes((uint)expandedOutput.count, 1, 1); @@ -652,7 +660,6 @@ public void Accumulate( GraphicsBuffer compactedGbufferLength, bool receiveShadows, float pushOff, - uint lightEvaluationsPerBounce, bool newChunkStarted) { int instanceWidth = instanceTexelSize.x; @@ -665,7 +672,7 @@ public void Accumulate( // path tracing inputs bool preExpose = false; float environmentIntensityMultiplier = 1.0f; - Util.BindPathTracingInputs(cmd, _accumulationShader, false, lightEvaluationsPerBounce, preExpose, 0, environmentIntensityMultiplier, RenderedGameObjectsFilter.OnlyStatic, _samplingResources, _emptyTexture); + Util.BindPathTracingInputs(cmd, _accumulationShader, false, 1, preExpose, 0, environmentIntensityMultiplier, RenderedGameObjectsFilter.OnlyStatic, _samplingResources, _emptyTexture); Util.BindWorld(cmd, _accumulationShader, world); var requiredSizeInBytes = _accumulationShader.GetTraceScratchBufferRequiredSizeInBytes((uint)expandedOutput.count, 1, 1); diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/ManyLightSampling.cs b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/ManyLightSampling.cs index bdbff7067bf..43dd4646fd5 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/ManyLightSampling.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/ManyLightSampling.cs @@ -57,6 +57,17 @@ public static Vector3Int ComputeLightGridDims(Vector3 sceneBounds, int maxLightG Debug.Assert(gridDims.x * gridDims.y * gridDims.z <= maxLightGridCellCount); return gridDims; } + + public static int ComputeMaxLightsInAnyCell(int2[] grid, Vector3Int gridDims) + { + int maxLightsInAnyCell = 0; + for (int i = 0; i < gridDims.x * gridDims.y * gridDims.z; i++) + { + int lightCount = grid[i].y; + maxLightsInAnyCell = Math.Max(maxLightsInAnyCell, lightCount); + } + return maxLightsInAnyCell; + } } @@ -67,6 +78,7 @@ internal class ConservativeLightGrid : IManyLightSampling public int MaxLightsPerCell = 64; // Only used with GridMemLayout.Dense public GridSizingStrategy LightGridSizingStrategy = GridSizingStrategy.FitToSceneBounds; public GridMemLayout GridMemLayout = GridMemLayout.Sparse; + public int MaxLightsInAnyCell => _maxLightsInAnyCell; public ConservativeLightGrid(ComputeShader shader) { @@ -168,6 +180,11 @@ public void Build(CommandBuffer cmd, World.LightState lightState, Bounds sceneBo // Build the grid cmd.SetComputeBufferParam(_shader, _buildLightGridlKernel, ShaderProperties.LightGridCellsData, _lightGridCellsDataBuffer); DispatchBuild(cmd, 1); + + GraphicsHelpers.Flush(cmd); + int2[] grid = new int2[_lightGridBuffer.count]; + _lightGridBuffer.GetData(grid); + _maxLightsInAnyCell = LightGridUtils.ComputeMaxLightsInAnyCell(grid, _lightGridDims); } public void Bind(CommandBuffer cmd, IRayTracingShader shader) @@ -226,6 +243,7 @@ void DispatchBuild(CommandBuffer cmd, int buildPass) Vector4 _cellSize; Vector4 _invCellSize; Vector3Int _lightGridDims; + int _maxLightsInAnyCell; } internal class RegirLightGrid : IManyLightSampling @@ -235,6 +253,7 @@ internal class RegirLightGrid : IManyLightSampling public int MaxLightsPerCell = 64; public int NumCandidates = -1; // -1 means we iterate over all the lights public GridSizingStrategy LightGridSizingStrategy = GridSizingStrategy.Uniform; + public int MaxLightsInAnyCell => _maxLightsInAnyCell; public RegirLightGrid(ComputeShader shader) { @@ -308,6 +327,11 @@ public void Build(CommandBuffer cmd, World.LightState lightState, Bounds sceneBo GraphicsHelpers.DivUp(_lightGridDims.x, groupDim), GraphicsHelpers.DivUp(_lightGridDims.y, groupDim), GraphicsHelpers.DivUp(_lightGridDims.z, groupDim)); + + GraphicsHelpers.Flush(cmd); + int2[] grid = new int2[_lightGridBuffer.count]; + _lightGridBuffer.GetData(grid); + _maxLightsInAnyCell = LightGridUtils.ComputeMaxLightsInAnyCell(grid, _lightGridDims); } public void Bind(CommandBuffer cmd, IRayTracingShader shader) @@ -354,5 +378,6 @@ public void Dispose() Vector4 _cellSize; Vector4 _invCellSize; Vector3Int _lightGridDims; + int _maxLightsInAnyCell; } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/PathTracingUtil.cs b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/PathTracingUtil.cs index 549ce4de580..467f1276d74 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/PathTracingUtil.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/PathTracingUtil.cs @@ -129,7 +129,7 @@ static internal void BindPathTracingInputs( CommandBuffer cmd, IRayTracingShader shader, bool countNEERayAsPathSegment, - uint lightEvaluationsPerBounce, + uint risCandidateCount, bool preExpose, int bounces, float environmentIntensityMultiplier, @@ -137,7 +137,7 @@ static internal void BindPathTracingInputs( SamplingResources samplingResources, RTHandle emptyTexture) { - shader.SetIntParam(cmd, ShaderProperties.LightEvaluations, (int)lightEvaluationsPerBounce); + shader.SetIntParam(cmd, ShaderProperties.LightEvaluations, (int)risCandidateCount); shader.SetIntParam(cmd, ShaderProperties.PathtracerAsGiPreviewMode, 0); shader.SetIntParam(cmd, ShaderProperties.CountNEERayAsPathSegment, countNEERayAsPathSegment ? 1 : 0); shader.SetIntParam(cmd, ShaderProperties.RenderedInstances, (int)renderedGameObjectsFilter); diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/ProbeIntegrator.cs b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/ProbeIntegrator.cs index 4f8b2f0b610..6c23fde3359 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/ProbeIntegrator.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/ProbeIntegrator.cs @@ -60,6 +60,7 @@ private static class ShaderProperties public static readonly int PerProbeLightIndices = Shader.PropertyToID("g_PerProbeLightIndices"); public static readonly int PerProbeLightIndicesOffset = Shader.PropertyToID("g_PerProbeLightIndicesOffset"); public static readonly int MaxLightsPerProbe = Shader.PropertyToID("g_MaxLightsPerProbe"); + public static readonly int LightIndexInCell = Shader.PropertyToID("g_LightIndexInCell"); } public ProbeIntegrator(bool countNEERayAsPathSegment) @@ -104,7 +105,9 @@ private void DispatchRadianceEstimationKernel( uint bounceCount, uint sampleOffset, uint sampleCount, - uint lightEvaluationPerEvent, + uint risCandidateCount, + uint maxLightsInAnyCell, + bool roundRobin, float environmentIntensityMultiplier, GraphicsBuffer radianceShl2, uint radianceOffset, @@ -115,7 +118,7 @@ private void DispatchRadianceEstimationKernel( // General path tracing parameters bool preExpose = false; - Util.BindPathTracingInputs(cmd, shader, _countNEERayAsPathSegment, lightEvaluationPerEvent, preExpose, (int)bounceCount, environmentIntensityMultiplier, RenderedGameObjectsFilter.OnlyStatic, _samplingResources, _emptyExposureTexture); + Util.BindPathTracingInputs(cmd, shader, _countNEERayAsPathSegment, risCandidateCount, preExpose, (int)bounceCount, environmentIntensityMultiplier, RenderedGameObjectsFilter.OnlyStatic, _samplingResources, _emptyExposureTexture); Util.BindWorld(cmd, shader, world); // Zero initialize the output buffer @@ -123,7 +126,7 @@ private void DispatchRadianceEstimationKernel( cmd.SetBufferData(radianceShl2, new float[positionCount * floatsPerSH]); DispatchProbeKernel(cmd, shader, positionOffset, positionCount, sampleOffset, sampleCount, floatsPerSH, ShaderProperties.RadianceShl2, radianceShl2, radianceOffset, expansionBuffer, reductionBuffer, - bounceCount); + bounceCount, roundRobin, maxLightsInAnyCell); } private void DispatchProbeKernel( @@ -139,7 +142,9 @@ private void DispatchProbeKernel( uint outputOffset, GraphicsBuffer expansionBuffer, GraphicsBuffer reductionBuffer, - uint bounceCount) + uint bounceCount, + bool roundRobin, + uint maxLightsInAnyCell) { // Set constant kernel parameters shader.SetBufferParam(cmd, ShaderProperties.Positions, _positionsBuffer); @@ -166,7 +171,13 @@ private void DispatchProbeKernel( // Calculate as many samples as possible given the budget uint probesToDispatch = Math.Min(maxProbesPerDispatch, positionCount - probeOffset); uint samplesToDispatch = probesToDispatch * sampleCount; - shader.Dispatch(cmd, _traceScratchBuffer, samplesToDispatch, 1, 1); + + uint loopCount = roundRobin ? maxLightsInAnyCell : 1; + for (int lightIndexInCell = 0; lightIndexInCell < loopCount; ++lightIndexInCell) + { + shader.SetIntParam(cmd, ShaderProperties.LightIndexInCell, lightIndexInCell); + shader.Dispatch(cmd, _traceScratchBuffer, samplesToDispatch, 1, 1); + } // Perform reduction of each probes samples _resourceLibrary.GatherKernel.TwoPassSegmentedReduction( @@ -201,7 +212,8 @@ internal void EstimateIndirectRadianceShl2( uint bounceCount, uint sampleOffset, uint sampleCount, - uint lightEvaluationsPerBounce, + uint risCandidateCount, + uint maxLightsInAnyCell, bool ignoreEnvironment, GraphicsBuffer radianceShl2, uint radianceOffset, @@ -209,7 +221,7 @@ internal void EstimateIndirectRadianceShl2( GraphicsBuffer reductionBuffer) { float environmentIntensityMultiplier = ignoreEnvironment ? 0.0f : 1.0f; - DispatchRadianceEstimationKernel(cmd, _resourceLibrary.IndirectShader, world, positionOffset, positionCount, bounceCount, sampleOffset, sampleCount, lightEvaluationsPerBounce, environmentIntensityMultiplier, radianceShl2, radianceOffset, expansionBuffer, reductionBuffer); + DispatchRadianceEstimationKernel(cmd, _resourceLibrary.IndirectShader, world, positionOffset, positionCount, bounceCount, sampleOffset, sampleCount, risCandidateCount, maxLightsInAnyCell, false, environmentIntensityMultiplier, radianceShl2, radianceOffset, expansionBuffer, reductionBuffer); } internal void EstimateDirectRadianceShl2( @@ -219,7 +231,8 @@ internal void EstimateDirectRadianceShl2( uint positionCount, uint sampleOffset, uint sampleCount, - uint lightEvaluationsPerBounce, + uint risCandidateCount, + uint maxLightsInAnyCell, bool ignoreEnvironment, GraphicsBuffer radianceShl2, uint radianceOffset, @@ -227,7 +240,7 @@ internal void EstimateDirectRadianceShl2( GraphicsBuffer reductionBuffer) { float environmentIntensityMultiplier = ignoreEnvironment ? 0.0f : 1.0f; - DispatchRadianceEstimationKernel(cmd, _resourceLibrary.DirectShader, world, positionOffset, positionCount, 0, sampleOffset, sampleCount, lightEvaluationsPerBounce, environmentIntensityMultiplier, radianceShl2, radianceOffset, expansionBuffer, reductionBuffer); + DispatchRadianceEstimationKernel(cmd, _resourceLibrary.DirectShader, world, positionOffset, positionCount, 0, sampleOffset, sampleCount, risCandidateCount, maxLightsInAnyCell, true, environmentIntensityMultiplier, radianceShl2, radianceOffset, expansionBuffer, reductionBuffer); } internal void EstimateValidity( @@ -250,7 +263,7 @@ internal void EstimateValidity( SamplingResources.Bind(cmd, _samplingResources); DispatchProbeKernel(cmd, validityShader, positionOffset, positionCount, sampleOffset, sampleCount, 1, ShaderProperties.Validity, validity, validityOffset, expansionBuffer, reductionBuffer, - 0); + 0, false, 0); } internal void EstimateLightOcclusion( @@ -279,7 +292,7 @@ internal void EstimateLightOcclusion( occlusionShader.SetIntParam(cmd, ShaderProperties.MaxLightsPerProbe, (int)maxLightsPerProbe); DispatchProbeKernel(cmd, occlusionShader, positionOffset, positionCount, sampleOffset, sampleCount, maxLightsPerProbe, ShaderProperties.Occlusion, occlusion, occlusionOffset, expansionBuffer, reductionBuffer, - 0); + 0, false, 0); } private void ReleaseExistingAllocations() diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/LightSampling.hlsl b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/LightSampling.hlsl index d4029fc3d18..187d790b50e 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/LightSampling.hlsl +++ b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/LightSampling.hlsl @@ -4,6 +4,7 @@ #include "PathTracingCommon.hlsl" #include "PathTracingMaterials.hlsl" #include "PathTracingLightGrid.hlsl" +#include "Packages/com.unity.render-pipelines.core/Runtime/Sampling/PseudoRandom.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Sampling/Sampling.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonLighting.hlsl" @@ -11,14 +12,9 @@ #include "Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Environment/EnvironmentImportanceSampling.hlsl" #define SOLID_ANGLE_SAMPLING -#define RESAMPLED_IMPORTANCE_SAMPLING #define TRANSMISSION_IN_SHADOW_RAYS #define USE_DISTANCE_ATTENUATION_LUT -#ifndef QRNG_METHOD_GLOBAL_SOBOL_BLUE_NOISE -// Unless we use global sobol, stratification improves light selection -#define STRATIFIED_LIGHT_PICKING -#endif TextureCube g_EnvTex; SamplerState sampler_g_EnvTex; float g_EnvIntensityMultiplier; @@ -138,12 +134,10 @@ bool CastJitteredShadowRay( float distance, uint shadowRayMask, float2 uSample, - inout uint dimsUsed, out float3 attenuation) { if (shadowRadius > 0.0f) { - dimsUsed += 1; // jitter the light direction within the shadow radius direction = CalculateJitteredLightVec(shadowRadius, uSample, lightVector); } @@ -161,12 +155,10 @@ struct SphQuad float S; }; -bool SampleRectangularLight(inout PathTracingSampler rngState, uint dimsOffset, out uint dimsUsed, float3 P, PTLight light, inout LightShapeSample lightSample) +bool SampleRectangularLight(float2 rng, float3 P, PTLight light, inout LightShapeSample lightSample) { - float2 uv = rngState.GetSample2D(dimsOffset); - float u = uv.x; - float v = uv.y; - dimsUsed = 1; + float u = rng.x; + float v = rng.y; #ifndef SOLID_ANGLE_SAMPLING // Area sampling @@ -301,12 +293,10 @@ bool SampleRectangularLight(inout PathTracingSampler rngState, uint dimsOffset, #endif } -bool SampleDiscLight(inout PathTracingSampler rngState, uint dimsOffset, out uint dimsUsed, float3 P, PTLight light, inout LightShapeSample lightSample) +bool SampleDiscLight(float2 rng, float3 P, PTLight light, inout LightShapeSample lightSample) { - float2 uv = rngState.GetSample2D(dimsOffset); - float u = uv.x; - float v = uv.y; - dimsUsed = 1; + float u = rng.x; + float v = rng.y; float2 coord = SampleDiskUniform(u, v); const float radius = light.width; @@ -353,18 +343,14 @@ float2 MapUnitSquareToUnitTriangle(float2 unitSquareCoords) return unitSquareCoords; } -bool SampleEmissiveMesh(StructuredBuffer instanceList, inout PathTracingSampler rngState, uint dimsOffset, out uint dimsUsed, float3 P, PTLight light, inout LightShapeSample lightSample) +bool SampleEmissiveMesh(StructuredBuffer instanceList, float2 rand0, float2 rand1, float3 P, PTLight light, inout LightShapeSample lightSample) { - float2 r1 = rngState.GetSample2D(dimsOffset); - float r2 = rngState.GetSample1D(dimsOffset+1); - dimsUsed = 2; - // random point in unit triangle - float2 samplePoint = MapUnitSquareToUnitTriangle(r1); + float2 samplePoint = MapUnitSquareToUnitTriangle(rand0); int instanceIndex = light.height; int numPrimitives = light.attenuation.x; - int primitiveIndex = (r2 * numPrimitives) % numPrimitives; + int primitiveIndex = (rand1.x * numPrimitives) % numPrimitives; // fetch the triangle vertices from the geometry pool @@ -456,15 +442,13 @@ bool SamplePunctualLight(float3 P, PTLight light, out LightShapeSample lightSamp return true; } -bool SampleEnvironmentLight(inout PathTracingSampler rngState, uint dimsOffset, out uint dimsUsed, float3 P, PTLight light, out LightShapeSample lightSample) +bool SampleEnvironmentLight(float2 rng, float3 P, PTLight light, out LightShapeSample lightSample) { lightSample = (LightShapeSample)0; - const float2 rand = rngState.GetSample2D(dimsOffset); - dimsUsed = 1; #ifdef UNIFORM_ENVSAMPLING // Sample the environment with a random direction. Should only be used for reference / ground truth. - lightSample.lightVector = SampleSphereUniform(rand.x, rand.y); + lightSample.lightVector = SampleSphereUniform(rng.x, rng.y); lightSample.weight = 4 * PI; #else float normalizationFactor = GetSkyPDFNormalizationFactor(_EnvironmentCdfMarginalBuffer); @@ -476,7 +460,7 @@ bool SampleEnvironmentLight(inout PathTracingSampler rngState, uint dimsOffset, return false; const float2 u = SampleSky( - rand, + rng, _EnvironmentCdfMarginalResolution, _EnvironmentCdfMarginalBuffer, _EnvironmentCdfConditionalResolution, @@ -499,26 +483,25 @@ bool SampleEnvironmentLight(inout PathTracingSampler rngState, uint dimsOffset, return true; } -bool SampleLightShape(StructuredBuffer instanceList, inout PathTracingSampler rngState, uint dimsOffset, out uint dimsUsed, float3 P, PTLight light, out LightShapeSample lightSample) +bool SampleLightShape(StructuredBuffer instanceList, float2 rand0, float2 rand1, float3 P, PTLight light, out LightShapeSample lightSample) { - dimsUsed = 0; lightSample = (LightShapeSample)0; bool result = false; if (light.type == RECTANGULAR_LIGHT) { - result = SampleRectangularLight(rngState, dimsOffset, dimsUsed, P, light, lightSample); + result = SampleRectangularLight(rand0, P, light, lightSample); } else if (light.type == DISC_LIGHT) { - result = SampleDiscLight(rngState, dimsOffset, dimsUsed, P, light, lightSample); + result = SampleDiscLight(rand0, P, light, lightSample); } else if (light.type == EMISSIVE_MESH) { - result = SampleEmissiveMesh(instanceList, rngState, dimsOffset, dimsUsed, P, light, lightSample); + result = SampleEmissiveMesh(instanceList, rand0, rand1, P, light, lightSample); } else if (light.type == ENVIRONMENT_LIGHT) { - result = SampleEnvironmentLight(rngState, dimsOffset, dimsUsed, P, light, lightSample); + result = SampleEnvironmentLight(rand0, P, light, lightSample); } else { @@ -725,7 +708,7 @@ float3 GetDiscLightEmission(PTLight light, LightShapeSample lightSample) } } -float3 GetEmissiveMeshEmission(PTLight light, LightShapeSample lightSample) +float3 GetEmissiveMeshEmission(LightShapeSample lightSample) { PTMaterial matInfo = g_MaterialList[lightSample.materialIndex]; @@ -739,6 +722,14 @@ float3 GetEmissiveMeshEmission(PTLight light, LightShapeSample lightSample) emission = matInfo.emissionColor; } + // To match the behavior of the old baker, emission should be attenuated by transmission. + // Think about a mesh with a cutout shader - the portions that are cut out should obviously not emit light. + if (matInfo.transmissionTextureIndex != -1) + { + float3 transmission = SampleAtlas(g_TransmissionTextures, sampler_g_TransmissionTextures, matInfo.transmissionTextureIndex, lightSample.uv, matInfo.transmissionScale, matInfo.transmissionOffset, false).rgb; + emission *= 1.0-transmission; + } + return emission; } @@ -791,7 +782,7 @@ float3 GetEmission(PTLight light, LightShapeSample lightSample) } else if (light.type == EMISSIVE_MESH) { - emission = GetEmissiveMeshEmission(light, lightSample); + emission = GetEmissiveMeshEmission(lightSample); } else if (light.type == ENVIRONMENT_LIGHT) { @@ -877,19 +868,32 @@ struct Reservoir } }; -uint GetNumLights(float3 origin, uint maxLightEvaluations) +uint GetNumLights(float3 origin) { if (g_LightPickingMethod == LIGHT_PICKING_METHOD_RESERVOIR_GRID || g_LightPickingMethod == LIGHT_PICKING_METHOD_LIGHT_GRID) { uint cellIndex = GetCellIndexFromPosition(origin); uint numReservoirs = g_LightGrid[cellIndex].y; - return min(numReservoirs, maxLightEvaluations); + return numReservoirs; + } + + return g_NumLights; +} + +PTLight GetLightInCell(float3 origin, uint lightIndex) +{ + if (g_LightPickingMethod == LIGHT_PICKING_METHOD_RESERVOIR_GRID || g_LightPickingMethod == LIGHT_PICKING_METHOD_LIGHT_GRID) + { + uint cellIndex = GetCellIndexFromPosition(origin); + uint firstReservoir = g_LightGrid[cellIndex].x; + ThinReservoir reservoir = g_LightGridCellsData[firstReservoir + lightIndex]; + lightIndex = reservoir.lightIndex; } - return min(maxLightEvaluations, g_NumLights); + return FetchLight(lightIndex); } -bool SampleLight(PTLight light, float3 shadowRayOrigin, float3 normal, bool isDirect, uint enabledLightsLayerMask, StructuredBuffer instanceList, uint dimsOffset, inout PathTracingSampler rngState, out ReservoirLightSample lightSample) +bool SampleLight(PTLight light, float3 shadowRayOrigin, float3 normal, bool isDirect, uint enabledLightsLayerMask, StructuredBuffer instanceList, float2 rand0, float2 rand1, out ReservoirLightSample lightSample) { lightSample = (ReservoirLightSample)0; @@ -903,8 +907,7 @@ bool SampleLight(PTLight light, float3 shadowRayOrigin, float3 normal, bool isDi LightShapeSample lightShapeSample; - uint dimsUsed = 0; - if (!SampleLightShape(instanceList, rngState, dimsOffset, dimsUsed, shadowRayOrigin, light, lightShapeSample)) + if (!SampleLightShape(instanceList, rand0, rand1, shadowRayOrigin, light, lightShapeSample)) return false; float3 emission = GetEmission(light, lightShapeSample); @@ -936,13 +939,13 @@ struct SampleLightsOptions uint numLightCandidates; }; -PTLight PickLight(float pickingSample, float3 receiverOrigin, out float lighPickingPmf) +PTLight PickLight(float pickingSample, float3 receiverOrigin, out float lightPickingPmf) { uint lightIndex; if (g_LightPickingMethod == LIGHT_PICKING_METHOD_RESERVOIR_GRID || g_LightPickingMethod == LIGHT_PICKING_METHOD_LIGHT_GRID) - PickLightFromGrid(pickingSample, receiverOrigin, lightIndex, lighPickingPmf); + PickLightFromGrid(pickingSample, receiverOrigin, lightIndex, lightPickingPmf); else - PickLightUniformly(pickingSample, lightIndex, lighPickingPmf); + PickLightUniformly(pickingSample, lightIndex, lightPickingPmf); return FetchLight(lightIndex); } @@ -952,33 +955,45 @@ bool SampleLightsRadianceRIS( float3 receiverOrigin, float3 receiverNormal, SampleLightsOptions options, inout PathTracingSampler rngState, out LightSample resLightSample) { resLightSample = (LightSample)0; + // Find how many lights we will evaluate - uint numLightCandidates = GetNumLights(receiverOrigin, options.numLightCandidates); + uint numLightCandidates = min(GetNumLights(receiverOrigin), options.numLightCandidates); - Reservoir reservoir = (Reservoir) 0; + // We want to seed the 2 RNGs below with the pixel coordinate and sample index. To avoid calculating a 3D hash, + // we just offset the sequence using the sample index. The constant added to the pixel coord is to decorrelate + // them from the main RNG used elsewhere in the path tracer, and from each other. + + // RNG for generating samples. + QRNG_TYPE sampleGenerationRng; + sampleGenerationRng.Init(rngState.pixelCoord+3141, rngState.pathIndex * numLightCandidates); + + // RNG for selecting the RIS winner. Use white instead of blue noise for this one. + QrngPcg4D winnerSelectionRng; + winnerSelectionRng.Init(rngState.pixelCoord+2718, rngState.pathIndex * numLightCandidates); + Reservoir reservoir = (Reservoir) 0; for (uint i = 0; i < numLightCandidates; ++i) { - float pickingSample = rngState.GetSample1D(RAND_DIM_LIGHT_SELECTION + RAND_SAMPLES_PER_LIGHT * i); - #ifdef STRATIFIED_LIGHT_PICKING - pickingSample = (i + pickingSample) / numLightCandidates; - #endif - - float lighPickingPmf; - PTLight light = PickLight(pickingSample, receiverOrigin, lighPickingPmf); + float pickingSample = sampleGenerationRng.GetSample(RAND_DIM_LIGHT_SELECTION).x; + float winnerSample = winnerSelectionRng.GetSample(); - uint dimsOffset = RAND_DIM_LIGHT_SELECTION + RAND_SAMPLES_PER_LIGHT * i + 1; + float lightPickingPmf; + PTLight light = PickLight(pickingSample, receiverOrigin, lightPickingPmf); ReservoirLightSample lightSample; - if (!SampleLight(light, receiverOrigin, receiverNormal, options.isDirect, options.lightsRenderingLayerMask, instanceList, dimsOffset, rngState, lightSample)) - continue; + float2 sampleRand0 = sampleGenerationRng.GetSample(RAND_DIM_LIGHT_SELECTION + 1); + float2 sampleRand1 = sampleGenerationRng.GetSample(RAND_DIM_LIGHT_SELECTION + 2); + if (SampleLight(light, receiverOrigin, receiverNormal, options.isDirect, options.lightsRenderingLayerMask, instanceList, sampleRand0, sampleRand1, lightSample)) + { + lightSample.pdf *= lightPickingPmf; - lightSample.pdf *= lighPickingPmf; + float targetFunc = Luminance(lightSample.radiance); + float risWeight = targetFunc / lightSample.pdf; // w = targetFunc / sourcePdf + reservoir.Update(lightSample, risWeight, winnerSample); + } - float r = rngState.GetSample1D(RAND_DIM_LIGHT_SELECTION + RAND_SAMPLES_PER_LIGHT * i + 3); - float targetFunc = Luminance(lightSample.radiance); - float risWeight = targetFunc / lightSample.pdf; // w = targetFunc / sourcePdf - reservoir.Update(lightSample, risWeight, r); + sampleGenerationRng.NextSample(); + winnerSelectionRng.NextSample(); } float sampleTargetFuncEval = Luminance(reservoir.bestSample.radiance); @@ -993,9 +1008,8 @@ bool SampleLightsRadianceRIS( // cast a shadow ray float3 attenuation = 1.0f; - uint dimsUsed = 0; float2 shadowSample = rngState.GetSample2D(RAND_DIM_JITTERED_SHADOW); - bool isShadowed = castShadows && options.receiveShadows && !CastJitteredShadowRay(dispatchInfo, accelStruct, bestSample.shadowRadius, lightType == DIRECTIONAL_LIGHT ? bestSample.lightDirection : bestSample.lightDirection*bestSample.distanceToLight, receiverOrigin, bestSample.lightDirection, bestSample.distanceToLight, options.shadowRayMask, shadowSample, dimsUsed, attenuation); + bool isShadowed = castShadows && options.receiveShadows && !CastJitteredShadowRay(dispatchInfo, accelStruct, bestSample.shadowRadius, lightType == DIRECTIONAL_LIGHT ? bestSample.lightDirection : bestSample.lightDirection*bestSample.distanceToLight, receiverOrigin, bestSample.lightDirection, bestSample.distanceToLight, options.shadowRayMask, shadowSample, attenuation); if (isShadowed) return false; @@ -1016,24 +1030,54 @@ bool SampleLightsRadianceMC( float3 receiverOrigin, float3 receiverNormal, SampleLightsOptions options, inout PathTracingSampler rngState, out LightSample resLightSample) { resLightSample = (LightSample)0; - // Find how many lights we will evaluate - uint numLightCandidates = GetNumLights(receiverOrigin, 1); float pickingSample = rngState.GetSample1D(RAND_DIM_LIGHT_SELECTION); - float lighPickingPmf; - PTLight light = PickLight(pickingSample, receiverOrigin, lighPickingPmf); + float lightPickingPmf; + PTLight light = PickLight(pickingSample, receiverOrigin, lightPickingPmf); + + ReservoirLightSample lightSample; + float2 sampleRand0 = rngState.GetSample2D(RAND_DIM_LIGHT_SELECTION + 1); + float2 sampleRand1 = rngState.GetSample2D(RAND_DIM_LIGHT_SELECTION + 2); + if (!SampleLight(light, receiverOrigin, receiverNormal, options.isDirect, options.lightsRenderingLayerMask, instanceList, sampleRand0, sampleRand1, lightSample)) + return false; + + lightSample.pdf *= lightPickingPmf; + + float3 attenuation = 1.0f; + float2 shadowSample = rngState.GetSample2D(RAND_DIM_JITTERED_SHADOW); + bool isShadowed = light.castsShadows && options.receiveShadows && !CastJitteredShadowRay(dispatchInfo, accelStruct, light.shadowRadius, light.type == DIRECTIONAL_LIGHT ? lightSample.lightDirection : lightSample.lightDirection*lightSample.distanceToLight, receiverOrigin, lightSample.lightDirection, lightSample.distanceToLight, options.shadowRayMask, shadowSample, attenuation); + if (isShadowed) + return false; + + resLightSample.radiance = attenuation * lightSample.radiance / lightSample.pdf; + resLightSample.direction = lightSample.lightDirection; + resLightSample.risSourcePdf = lightSample.pdf; + resLightSample.lightType = light.type; + + return true; +} + +// Sample incoming radiance from a specific light. +bool SampleLightRadiance( + UnifiedRT::DispatchInfo dispatchInfo, UnifiedRT::RayTracingAccelStruct accelStruct, StructuredBuffer instanceList, + float3 receiverOrigin, float3 receiverNormal, SampleLightsOptions options, PTLight light, inout PathTracingSampler rngState, out LightSample resLightSample) +{ + resLightSample = (LightSample)0; + + uint numLights = GetNumLights(receiverOrigin); + float lightPickingPmf = rcp(numLights); - uint dimsOffset = RAND_DIM_LIGHT_SELECTION + 1; ReservoirLightSample lightSample; - if (!SampleLight(light, receiverOrigin, receiverNormal, options.isDirect, options.lightsRenderingLayerMask, instanceList, dimsOffset, rngState, lightSample)) + float2 sampleRand0 = rngState.GetSample2D(RAND_DIM_LIGHT_SELECTION + 1); + float2 sampleRand1 = rngState.GetSample2D(RAND_DIM_LIGHT_SELECTION + 2); + if (!SampleLight(light, receiverOrigin, receiverNormal, options.isDirect, options.lightsRenderingLayerMask, instanceList, sampleRand0, sampleRand1, lightSample)) return false; - lightSample.pdf *= lighPickingPmf; + lightSample.pdf *= lightPickingPmf; float3 attenuation = 1.0f; - uint dimsUsed = 0; float2 shadowSample = rngState.GetSample2D(RAND_DIM_JITTERED_SHADOW); - bool isShadowed = light.castsShadows && options.receiveShadows && !CastJitteredShadowRay(dispatchInfo, accelStruct, light.shadowRadius, light.type == DIRECTIONAL_LIGHT ? lightSample.lightDirection : lightSample.lightDirection*lightSample.distanceToLight, receiverOrigin, lightSample.lightDirection, lightSample.distanceToLight, options.shadowRayMask, shadowSample, dimsUsed, attenuation); + bool isShadowed = light.castsShadows && options.receiveShadows && !CastJitteredShadowRay(dispatchInfo, accelStruct, light.shadowRadius, light.type == DIRECTIONAL_LIGHT ? lightSample.lightDirection : lightSample.lightDirection*lightSample.distanceToLight, receiverOrigin, lightSample.lightDirection, lightSample.distanceToLight, options.shadowRayMask, shadowSample, attenuation); if (isShadowed) return false; @@ -1045,6 +1089,7 @@ bool SampleLightsRadianceMC( return true; } +// Sample incoming radiance from a random light, picked using either RIS or raw monte carlo. bool SampleLightsRadiance( UnifiedRT::DispatchInfo dispatchInfo, UnifiedRT::RayTracingAccelStruct accelStruct, StructuredBuffer instanceList, float3 receiverOrigin, float3 receiverNormal, SampleLightsOptions options, inout PathTracingSampler rngState, out LightSample resLightSample) @@ -1090,7 +1135,6 @@ bool IsLightVisibleFromPoint( float3 worldPosition, inout PathTracingSampler rngState, uint dimsOffset, - out uint dimsUsed, PTLight light, bool receiveShadows, out float3 attenuation) @@ -1098,9 +1142,10 @@ bool IsLightVisibleFromPoint( attenuation = 1.0f; LightShapeSample lightSample; - if (!SampleLightShape(instanceList, rngState, dimsOffset, dimsUsed, worldPosition, light, lightSample)) + float2 sampleRand0 = rngState.GetSample2D(dimsOffset); + float2 sampleRand1 = rngState.GetSample2D(dimsOffset+1); + if (!SampleLightShape(instanceList, sampleRand0, sampleRand1, worldPosition, light, lightSample)) return false; - dimsOffset += dimsUsed; if (light.type != DIRECTIONAL_LIGHT && lightSample.distanceToLight >= light.range) return false; @@ -1109,8 +1154,8 @@ bool IsLightVisibleFromPoint( if (light.castsShadows && receiveShadows) { - float2 shadowSample = rngState.GetSample2D(dimsOffset); - return CastJitteredShadowRay(dispatchInfo, accelStruct, light.shadowRadius, lightSample.lightVector, worldPosition, lightSample.L, lightSample.distanceToLight, shadowRayMask, shadowSample, dimsUsed, attenuation); + float2 shadowSample = rngState.GetSample2D(dimsOffset+2); + return CastJitteredShadowRay(dispatchInfo, accelStruct, light.shadowRadius, lightSample.lightVector, worldPosition, lightSample.L, lightSample.distanceToLight, shadowRayMask, shadowSample, attenuation); } return true; } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/LightmapDirectIntegration.urtshader b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/LightmapDirectIntegration.urtshader index f5bf2d7e233..d2ecbae128f 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/LightmapDirectIntegration.urtshader +++ b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/LightmapDirectIntegration.urtshader @@ -3,14 +3,16 @@ #define UNIFIED_RT_GROUP_SIZE_Y 1 #define UNIFIED_RT_RAYGEN_FUNC AccumulateInternal -// Set to MIS, LIGHT_SAMPLING or BRDF_SAMPLING for debugging. +#define RESAMPLED_IMPORTANCE_SAMPLING #define EMISSIVE_SAMPLING MIS +#define LIGHT_SAMPLING_ROUND_ROBIN #include "PathTracing.hlsl" #include "LightmapIntegrationHelpers.hlsl" #pragma exclude_renderers switch switch2 +uint g_LightIndexInCell; int g_AccumulateDirectional; int g_SampleOffset; uint g_ReceiveShadows; @@ -18,6 +20,36 @@ float g_PushOff; RWStructuredBuffer g_ExpandedOutput; RWStructuredBuffer g_ExpandedDirectional; +// Sample a specific light directly, weight with MIS. +// Assumes 2 sampling strategies, the other being cosine weighted hemisphere sampling. +void EstimateMISWeightedIrradianceForSpecificLightUsingDirectSampling( + UnifiedRT::DispatchInfo dispatchInfo, + UnifiedRT::RayTracingAccelStruct accelStruct, + StructuredBuffer instanceList, + float3 origin, + float3 normal, + SampleLightsOptions options, + uint lightIndexInCell, + inout PathTracingSampler rngState, + inout float4 irradiance, + inout float4 directional, + out LightSample lightSample) +{ + float3 sampleRadiance = 0.f; + float3 sampleDirection = 0.f; + float sampleDensity = 0.f; + + PTLight light = GetLightInCell(origin, lightIndexInCell); + if (SampleLightRadiance(dispatchInfo, accelStruct, g_AccelStructInstanceList, origin, normal, options, light, rngState, lightSample)) + { + float sampleMISWeight = EmissiveMISWeightForLightRay(lightSample.lightType, lightSample.direction, lightSample.risSourcePdf, normal); + float3 e = sampleMISWeight * ClampedCosine(normal, lightSample.direction) * lightSample.radiance; + + irradiance.rgb += e; + directional += float4(lightSample.direction, 1.f) * Luminance(e); + } +} + // Sample every light directly, weight with MIS. // Assumes 2 sampling strategies, the other being cosine weighted hemisphere sampling. void EstimateMISWeightedIrradianceUsingDirectSampling( @@ -26,29 +58,22 @@ void EstimateMISWeightedIrradianceUsingDirectSampling( StructuredBuffer instanceList, float3 origin, float3 normal, - bool receiveShadows, + SampleLightsOptions options, inout PathTracingSampler rngState, inout float4 irradiance, - inout float4 directional) + inout float4 directional, + out LightSample lightSample) { float3 sampleRadiance = 0.f; float3 sampleDirection = 0.f; float sampleDensity = 0.f; - SampleLightsOptions options; - options.isDirect = true; - options.receiveShadows = receiveShadows; - options.shadowRayMask = ShadowRayMask(); - options.lightsRenderingLayerMask = 0xFFFFFFFF; - options.numLightCandidates = min(g_LightEvaluations, MAX_LIGHT_EVALUATIONS); - - LightSample lightSample = (LightSample)0; if (SampleLightsRadiance(dispatchInfo, accelStruct, instanceList, origin, normal, options, rngState, lightSample)) { float sampleMISWeight = EmissiveMISWeightForLightRay(lightSample.lightType, lightSample.direction, lightSample.risSourcePdf, normal); float3 e = sampleMISWeight * ClampedCosine(normal, lightSample.direction) * lightSample.radiance; - irradiance.rgb += e; + irradiance.rgb += e; directional += float4(lightSample.direction, 1.f) * Luminance(e); } } @@ -62,13 +87,13 @@ void EstimateMISWeightedIrradianceUsingCosineSampling( StructuredBuffer instanceList, float3 origin, float3 normal, - float2 rng, + inout PathTracingSampler rngState, inout float4 irradiance, inout float4 directional) { UnifiedRT::Ray ray; ray.origin = origin; - ray.direction = CosineSample(rng, normal); + ray.direction = CosineSample(rngState.GetSample2D(RAND_DIM_SURF_SCATTER), normal); ray.tMin = 0; ray.tMax = FLT_MAX; @@ -76,7 +101,6 @@ void EstimateMISWeightedIrradianceUsingCosineSampling( float lightDensity = 0.f; float3 emission = 0.f; float3 attenuation = 1.0f; - bool hitSurface = false; for (uint i = 0; i < MAX_TRANSMISSION_BOUNCES; i++) { @@ -88,28 +112,29 @@ void EstimateMISWeightedIrradianceUsingCosineSampling( geometry.FixNormals(ray.direction); MaterialProperties material = LoadMaterialProperties(instance, false, geometry.uv0, geometry.uv1); - // Transmissive material, continue ray and attenuate - if (material.isTransmissive) + // Transmissive material, either continue or terminate ray, then apply attenuation. + if (ShouldTransmitRay(rngState, material)) { attenuation *= saturate(material.transmission); ray.origin = geometry.NextTransmissionRayOrigin(); + rngState.NextBounce(); continue; } - hitSurface = true; - // Hit emissive frontface - if (!ShouldTreatAsBackface(hitResult, material) && any(material.emissive)) + else if (!ShouldTreatAsBackface(hitResult, material) && any(material.emissive)) { - lightDensity = ComputeMeshLightDensity(instanceList, geometry, hitResult.instanceID, ray.origin); + lightDensity = ComputeEmissiveTriangleDensity(instanceList, geometry, hitResult.instanceID, ray.origin); + lightDensity /= GetNumLights(ray.origin); emission = material.emissive; - break; } + break; + } + else // Hit skybox, so stop + { + GetEnvironmentLightEmissionAndDensity(ray.direction, emission, lightDensity); + lightDensity /= GetNumLights(ray.origin); + break; } - } - - if (!hitSurface) // Hit environment - { - GetEnvironmentLightEmissionAndDensity(ray.direction, emission, lightDensity); } // Tint the emissiom by the transmissive attenuation before accumulating @@ -142,24 +167,51 @@ void AccumulateInternal(UnifiedRT::DispatchInfo dispatchInfo) float3 origin = OffsetRayOrigin(worldPosition, worldFaceNormal, g_PushOff); - float4 irradiance = 0.f; - float4 directional = 0.f; + float4 irradianceDirect = 0.f, irradianceBrdf = 0.f; + float4 directionalDirect = 0.f, directionalBrdf = 0.f; PathTracingSampler rngState; rngState.Init(instanceTexelPos, sampleOffset); - #if (EMISSIVE_SAMPLING != BRDF_SAMPLING) - EstimateMISWeightedIrradianceUsingDirectSampling(dispatchInfo, accelStruct, g_AccelStructInstanceList, origin, worldNormal, g_ReceiveShadows, rngState, irradiance, directional); + SampleLightsOptions options; + options.isDirect = true; + options.receiveShadows = g_ReceiveShadows; + options.shadowRayMask = ShadowRayMask(); + options.lightsRenderingLayerMask = 0xFFFFFFFF; + options.numLightCandidates = min(g_LightEvaluations, MAX_LIGHT_EVALUATIONS); + + uint numLightsInCell = GetNumLights(origin); + // If there are no lights to sample, continuing is a waste of time. + [branch] if (numLightsInCell == 0) + { + // We still want to write 1 into the alpha channel, as it is used as an occupancy mask for post processing. + if (localSampleOffset == 0) + g_ExpandedOutput[dispatchInfo.dispatchThreadID.x] = float4(0,0,0,1); + return; + } + + // Sample a light using direct sampling, weight with MIS. + #ifdef LIGHT_SAMPLING_ROUND_ROBIN + // If we have already sampled every light in the cell, skip this sample to avoid needing to normalize per-light. + [branch] if (g_LightIndexInCell >= numLightsInCell) + return; + + LightSample lightSample; + EstimateMISWeightedIrradianceForSpecificLightUsingDirectSampling(dispatchInfo, accelStruct, g_AccelStructInstanceList, origin, worldNormal, options, g_LightIndexInCell, rngState, irradianceDirect, directionalDirect, lightSample); + #else + LightSample lightSample; + EstimateMISWeightedIrradianceUsingDirectSampling(dispatchInfo, accelStruct, g_AccelStructInstanceList, origin, worldNormal, options, rngState, irradianceDirect, directionalDirect, lightSample); #endif + // TODO: Decouple BRDF samples from direct light samples in a separate kernel (https://jira.unity3d.com/browse/GFXLIGHT-2107) + // Sample a light with BRDF sampling, weight with MIS. #if (EMISSIVE_SAMPLING != LIGHT_SAMPLING) - float2 rng = rngState.GetSample2D(RAND_DIM_SURF_SCATTER); - EstimateMISWeightedIrradianceUsingCosineSampling(dispatchInfo, accelStruct, g_AccelStructInstanceList, origin, worldNormal, rng, irradiance, directional); + EstimateMISWeightedIrradianceUsingCosineSampling(dispatchInfo, accelStruct, g_AccelStructInstanceList, origin, worldNormal, rngState, irradianceBrdf, directionalBrdf); #endif - // store new accumulated irradiance - g_ExpandedOutput[dispatchInfo.dispatchThreadID.x] += float4(irradiance.rgb, 1.0f); + // Store new accumulated irradiance + g_ExpandedOutput[dispatchInfo.dispatchThreadID.x] += float4(irradianceDirect.rgb + irradianceBrdf.rgb, 1.0f); if (g_AccumulateDirectional > 0) - g_ExpandedDirectional[dispatchInfo.dispatchThreadID.x] += directional; + g_ExpandedDirectional[dispatchInfo.dispatchThreadID.x] += directionalDirect + directionalBrdf; } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/LightmapShadowMaskIntegration.urtshader b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/LightmapShadowMaskIntegration.urtshader index afbeb64c8ea..443ac85ad60 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/LightmapShadowMaskIntegration.urtshader +++ b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/LightmapShadowMaskIntegration.urtshader @@ -41,13 +41,12 @@ void AccumulateInternal(UnifiedRT::DispatchInfo dispatchInfo) continue; if (light.type == EMISSIVE_MESH || light.type == ENVIRONMENT_LIGHT) // Shadowmask only makes sense for punctual lights continue; - uint dimsUsed = 0; float3 origin = OffsetRayOrigin(worldPosition, worldFaceNormal, g_PushOff); float3 attenuation = 1.0f; - float isVisible = IsLightVisibleFromPoint(dispatchInfo, accelStruct, g_AccelStructInstanceList, ShadowRayMask(), origin, rngState, dimsOffset, dimsUsed, light, g_ReceiveShadows, attenuation) ? dot(float3(1.0f, 1.0f, 1.0f), attenuation)/3.0f : 0.0f; - dimsOffset += dimsUsed; + float isVisible = IsLightVisibleFromPoint(dispatchInfo, accelStruct, g_AccelStructInstanceList, ShadowRayMask(), origin, rngState, dimsOffset, light, g_ReceiveShadows, attenuation) ? dot(float3(1.0f, 1.0f, 1.0f), attenuation)/3.0f : 0.0f; + dimsOffset += 3; // 2 dimensions for sampling the light, 1 dimension for jittering the shadow ray if (light.shadowMaskChannel < 0 || light.shadowMaskChannel >= 4) continue; visibility[light.shadowMaskChannel] += isVisible; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/PathTracing.hlsl b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/PathTracing.hlsl index d12f681fd20..e1765e6674e 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/PathTracing.hlsl +++ b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/PathTracing.hlsl @@ -78,16 +78,6 @@ float ComputeEmissiveTriangleDensity(StructuredBuffer i return weight; } -float ComputeMeshLightDensity(StructuredBuffer instanceList, PTHitGeom hitGeom, int instanceIndex, float3 rayOrigin) -{ - float weight = ComputeEmissiveTriangleDensity(instanceList, hitGeom, instanceIndex, rayOrigin); - - // pdf to select the light source - weight /= g_NumLights; - - return weight; -} - bool ShouldTreatAsBackface(UnifiedRT::Hit hitResult, MaterialProperties material) { // Have we hit something that is considered a backface when double sided GI is taken into account? @@ -201,7 +191,7 @@ void AddEnvironmentRadiance(inout PathIterator iterator, bool applyIndirectScale float envPdf; if (GetEnvironmentLightEmissionAndDensity(iterator.ray.direction, envRadiance, envPdf)) { - envPdf /= g_NumLights; + envPdf /= GetNumLights(iterator.ray.origin); if (applyIndirectScale) envRadiance *= g_IndirectScale; @@ -213,7 +203,9 @@ void AddEnvironmentRadiance(inout PathIterator iterator, bool applyIndirectScale // Add radiance due to a hit emissive surface. void AddEmissionRadiance(inout PathIterator iterator, UnifiedRT::RayTracingAccelStruct accelStruct, StructuredBuffer instanceList, bool applyIndirectScale) { - float lightDensity = ComputeMeshLightDensity(instanceList, iterator.hitGeo, iterator.hitResult.instanceID, iterator.ray.origin); + float lightDensity = ComputeEmissiveTriangleDensity(instanceList, iterator.hitGeo, iterator.hitResult.instanceID, iterator.ray.origin); + lightDensity /= GetNumLights(iterator.ray.origin); + float3 emission = iterator.material.emissive; if (applyIndirectScale) emission *= g_IndirectScale; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/PathTracingRandom.hlsl b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/PathTracingRandom.hlsl index b355e73ab05..7585b1370d4 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/PathTracingRandom.hlsl +++ b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/PathTracingRandom.hlsl @@ -22,6 +22,24 @@ // The number of dimensions used per bounce (depends on the number of light evaluations) #define QRNG_SAMPLES_PER_BOUNCE (RAND_DIM_LIGHT_SELECTION + RAND_SAMPLES_PER_LIGHT * MAX_LIGHT_EVALUATIONS) + +// Which RNG to use for most of our path tracing code. #define QRNG_METHOD_SOBOL #define QRNG_SOBOL_02 + +// Define an alias for the RNG type we have chosen. +#if defined(QRNG_METHOD_SOBOL) + #define QRNG_TYPE QrngSobol2D +#elif defined(QRNG_METHOD_SOBOL_BLUE_NOISE) + #define QRNG_TYPE QrngSobolBlueNoise2D +#elif defined(QRNG_METHOD_GLOBAL_SOBOL_BLUE_NOISE) + #define QRNG_TYPE QrngGlobalSobolBlueNoise2D +#elif defined(QRNG_METHOD_KRONECKER) + #define QRNG_TYPE QrngKronecker2D +#elif defined(QRNG_METHOD_RANDOM_XOR_SHIFT) + #define QRNG_TYPE QrngXorShift +#elif defined(QRNG_METHOD_RANDOM_PCG_4D) + #define QRNG_TYPE QrngPcg4D +#endif + #include "PathTracingSampler.hlsl" diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/PathTracingSampler.hlsl b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/PathTracingSampler.hlsl index 8a2f77c4bdc..c54ea82acca 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/PathTracingSampler.hlsl +++ b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/PathTracingSampler.hlsl @@ -18,28 +18,20 @@ struct PathTracingSampler { - #if defined(QRNG_METHOD_SOBOL) - QrngSobol2D generator; - #elif defined(QRNG_METHOD_SOBOL_BLUE_NOISE) - QrngSobolBlueNoise2D generator; - #elif defined(QRNG_METHOD_GLOBAL_SOBOL_BLUE_NOISE) - QrngGlobalSobolBlueNoise2D generator; - #elif defined(QRNG_METHOD_KRONECKER) - QrngKronecker2D generator; - #elif defined(QRNG_METHOD_RANDOM_XOR_SHIFT) - QrngXorShift generator; - #elif defined(QRNG_METHOD_RANDOM_PCG_4D) - QrngPcg4D generator; - #endif + QRNG_TYPE generator; + int pathIndex; int bounceIndex; + uint2 pixelCoord; - void Init(uint2 pixelCoord, uint startPathIndex, uint perPixelPathCount = 256) + void Init(uint2 startPixelCoord, uint startPathIndex, uint perPixelPathCount = 256) { #if defined(QRNG_METHOD_GLOBAL_SOBOL_BLUE_NOISE) - generator.Init(pixelCoord, startPathIndex, perPixelPathCount); + generator.Init(startPixelCoord, startPathIndex, perPixelPathCount); #else - generator.Init(pixelCoord, startPathIndex); + generator.Init(startPixelCoord, startPathIndex); #endif + pixelCoord = startPixelCoord; + pathIndex = startPathIndex; bounceIndex = 0; } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/ProbeIntegrationDirect.urtshader b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/ProbeIntegrationDirect.urtshader index af5e0fc2687..c5c83203256 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/ProbeIntegrationDirect.urtshader +++ b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/ProbeIntegrationDirect.urtshader @@ -5,9 +5,13 @@ #include "Packages/com.unity.render-pipelines.core/Runtime/UnifiedRayTracing/FetchGeometry.hlsl" +#define RESAMPLED_IMPORTANCE_SAMPLING +#define LIGHT_SAMPLING_ROUND_ROBIN + #include "PathTracing.hlsl" #include "SphericalHarmonicsUtils.hlsl" +uint g_LightIndexInCell; RWStructuredBuffer g_Positions; RWStructuredBuffer g_RadianceShl2; uint g_PositionsOffset; @@ -42,8 +46,21 @@ void IntegrateDirectRadiance(UnifiedRT::DispatchInfo dispatchInfo) options.lightsRenderingLayerMask = 0xFFFFFFFF; options.numLightCandidates = min(g_LightEvaluations, MAX_LIGHT_EVALUATIONS); + uint numLightsInCell = GetNumLights(worldPosition); + // If there are no lights to sample, continuing is a waste of time. + [branch] if (numLightsInCell == 0) + return; + LightSample lightSample = (LightSample)0; + #ifdef LIGHT_SAMPLING_ROUND_ROBIN + [branch] if (g_LightIndexInCell >= numLightsInCell) + return; + + PTLight light = GetLightInCell(worldPosition, g_LightIndexInCell); + if (SampleLightRadiance(dispatchInfo, accelStruct, g_AccelStructInstanceList, worldPosition, 0.0f, options, light, rngState, lightSample)) + #else if (SampleLightsRadiance(dispatchInfo, accelStruct, g_AccelStructInstanceList, worldPosition, 0.0f, options, rngState, lightSample)) + #endif { // Project into SH. accumulatedRadianceSH[0] += lightSample.radiance * SHL0(); @@ -58,12 +75,16 @@ void IntegrateDirectRadiance(UnifiedRT::DispatchInfo dispatchInfo) accumulatedRadianceSH[8] += lightSample.radiance * SHL22(lightSample.direction); } + #ifdef LIGHT_SAMPLING_ROUND_ROBIN + const float monteCarloNormalization = 1.0f / (float)g_SampleCount / (float)numLightsInCell; + #else const float monteCarloNormalization = 1.0f / (float)g_SampleCount; + #endif for (uint channel = 0; channel < SH_COLOR_CHANNELS; ++channel) { for (uint i = 0; i < SH_COEFFICIENTS_PER_CHANNEL; ++i) { - g_RadianceShl2[SHIndex(outProbeIdx, channel, i)] = accumulatedRadianceSH[i][channel] * monteCarloNormalization; + g_RadianceShl2[SHIndex(outProbeIdx, channel, i)] += accumulatedRadianceSH[i][channel] * monteCarloNormalization; } } } diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/ProbeIntegrationOcclusion.urtshader b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/ProbeIntegrationOcclusion.urtshader index c94cb8bedbb..9e10280c7b2 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/ProbeIntegrationOcclusion.urtshader +++ b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/Shaders/ProbeIntegrationOcclusion.urtshader @@ -30,6 +30,7 @@ void IntegrateOcclusion(UnifiedRT::DispatchInfo dispatchInfo) // Which probe in the expanded g_Occlusion buffer are we in? const uint outProbeIdx = inProbeIdx * g_SampleCount + inProbeSampleIdx; + uint dimsOffset = 0; for (uint indirectLightIndex = 0; indirectLightIndex < g_MaxLightsPerProbe; indirectLightIndex++) { // Which light in the expanded g_Occlusion buffer are we in? @@ -48,10 +49,9 @@ void IntegrateOcclusion(UnifiedRT::DispatchInfo dispatchInfo) PTLight light = FetchLight(lightIndex); if (light.type == SPOT_LIGHT || light.type == POINT_LIGHT || light.type == DIRECTIONAL_LIGHT) { - uint dimsOffset = 0; - uint dimsUsed = 0; float3 attenuation = 1.0f; - bool isVisible = IsLightVisibleFromPoint(dispatchInfo, accelStruct, g_AccelStructInstanceList, SHADOW_RAY_VIS_MASK, worldPosition, rngState, dimsOffset, dimsUsed, light, true, attenuation); + bool isVisible = IsLightVisibleFromPoint(dispatchInfo, accelStruct, g_AccelStructInstanceList, SHADOW_RAY_VIS_MASK, worldPosition, rngState, dimsOffset, light, true, attenuation); + dimsOffset += 3; // 2 dimensions for sampling the light, 1 dimension for jittering the shadow ray if (isVisible) { g_Occlusion[outOcclusionValueIdx] = 1.0f / g_SampleCount; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/UnityComputeProbeIntegrator.cs b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/UnityComputeProbeIntegrator.cs index a8c64fd083c..412ea7b72ac 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/UnityComputeProbeIntegrator.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/UnityComputeProbeIntegrator.cs @@ -15,8 +15,8 @@ internal class UnityComputeProbeIntegrator : IProbeIntegrator private readonly ProbeIntegrator _probeIntegrator; private UnityComputeWorld _world; private uint _bounceCount; - private uint _directLightingEvaluationCount; - private uint _numIndirectLightingEvaluations; + private uint _directRISCandidateCount = 4; + private uint _indirectRISCandidateCount = 1; private uint _basePositionsOffset; private static class ShaderProperties @@ -66,7 +66,8 @@ public IProbeIntegrator.Result IntegrateDirectRadiance(IDeviceContext context, i (uint)positionCount, sampleOffset, (uint)sampleCount, - _directLightingEvaluationCount, + _directRISCandidateCount, + (uint)_world.PathTracingWorld.MaxLightsInAnyCell, ignoreEnvironment, unifiedContext.GetComputeBuffer(radianceEstimateOut.Id), (uint)radianceEstimateOut.Offset, @@ -96,7 +97,8 @@ public IProbeIntegrator.Result IntegrateIndirectRadiance(IDeviceContext context, _bounceCount, sampleOffset, (uint)sampleCount, - _numIndirectLightingEvaluations, + _indirectRISCandidateCount, + (uint)_world.PathTracingWorld.MaxLightsInAnyCell, ignoreEnvironment, unifiedContext.GetComputeBuffer(radianceEstimateOut.Id), (uint)radianceEstimateOut.Offset, @@ -191,11 +193,14 @@ public IProbeIntegrator.Result IntegrateOcclusion(IDeviceContext context, int po return new IProbeIntegrator.Result(IProbeIntegrator.ResultType.Success, string.Empty); } - public void Prepare(IDeviceContext context, IWorld world, BufferSlice positions, float pushoff, int bounceCount) + public void Prepare( + IDeviceContext context, + IWorld world, + BufferSlice positions, + float pushoff, + int bounceCount) { _bounceCount = (uint)bounceCount; - _directLightingEvaluationCount = 4; - _numIndirectLightingEvaluations = 1; _world = world as UnityComputeWorld; Debug.Assert(world != null); diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/World.cs b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/World.cs index 6dca1ab0704..eb98df5979c 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/World.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/PathTracing/World.cs @@ -276,6 +276,18 @@ public LightPickingMethod lightPickingMethod public int NonMeshLightCount => _lightState.LightHandleToLightListEntry.Count; public int MeshLightCount => _lightState.MeshLights.Count; public int EnvLightCount => _lightState.HasEnvironmentLight ? 1 : 0; + public int MaxLightsInAnyCell + { + get + { + switch (_lightState.lightPickingMethod) + { + case LightPickingMethod.LightGrid: return _conservativeLightGrid.MaxLightsInAnyCell; + case LightPickingMethod.Regir: return _reservoirGrid.MaxLightsInAnyCell; + default: return LightCount; + } + } + } public List LightList => _lightState.LightList; public Dictionary LightHandleToLightListIndex => _lightState.LightHandleToLightListIndex; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Sampling/PseudoRandom.hlsl b/Packages/com.unity.render-pipelines.core/Runtime/Sampling/PseudoRandom.hlsl index a5becfdf4f8..12a1a1cacdb 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Sampling/PseudoRandom.hlsl +++ b/Packages/com.unity.render-pipelines.core/Runtime/Sampling/PseudoRandom.hlsl @@ -19,7 +19,7 @@ struct QrngXorShift state = seed; } - float PrivateGetFloat() + float GetSample() { state = XorShift32(state); return UintToFloat01(state); @@ -27,7 +27,7 @@ struct QrngXorShift float2 GetSample(uint dimension) { - return float2(PrivateGetFloat(), PrivateGetFloat()); + return float2(GetSample(), GetSample()); } void NextSample() @@ -51,7 +51,7 @@ struct QrngPcg4D state = uint4(seed, 1, startSampleIndex, 0); } - float PrivateGetFloat() + float GetSample() { state.w++; return UintToFloat01(Pcg4d(state).x); @@ -59,7 +59,7 @@ struct QrngPcg4D float2 GetSample(uint dimension) { - return float2(PrivateGetFloat(), PrivateGetFloat()); + return float2(GetSample(), GetSample()); } void NextSample() From 495eb86a2dfcc1f91f93d3e13fe75798ae18ff5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolaj=20Z=C3=B8llner?= Date: Mon, 16 Feb 2026 20:51:02 +0000 Subject: [PATCH 20/92] [Bugfix] Reflection probe rotation setting included in build --- .../Runtime/Settings/URPReflectionProbeSettings.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Settings/URPReflectionProbeSettings.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Settings/URPReflectionProbeSettings.cs index 4f16a3aa5ad..47677c29327 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Settings/URPReflectionProbeSettings.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Settings/URPReflectionProbeSettings.cs @@ -18,6 +18,7 @@ public class URPReflectionProbeSettings : IRenderPipelineGraphicsSettings [SerializeField, HideInInspector] private int version = 1; int IRenderPipelineGraphicsSettings.version => version; + bool IRenderPipelineGraphicsSettings.isAvailableInPlayerBuild => true; [SerializeField, Tooltip("Use ReflectionProbe rotation. Enabling this will improve the appearance of reflections when the ReflectionProbe isn't axis aligned, but may worsen performance on lower end platforms.")] private bool useReflectionProbeRotation = true; From 783431b81f8ab9db779b75d5965adb6391039da6 Mon Sep 17 00:00:00 2001 From: Arttu Peltonen Date: Mon, 16 Feb 2026 20:51:05 +0000 Subject: [PATCH 21/92] Keep debug menu input actions disabled until the debug UI is open --- .../Runtime/Debugging/DebugManager.Input.cs | 27 ++++++++++--------- .../Runtime/Debugging/DebugManager.UIState.cs | 9 +++++++ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugManager.Input.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugManager.Input.cs index f69c81c8836..d10ba23c3ed 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugManager.Input.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugManager.Input.cs @@ -23,24 +23,25 @@ public sealed partial class DebugManager #if USE_INPUT_SYSTEM const string k_AnyTouch = "Any Touch"; - readonly InputActionMap m_DebugActionMap = new InputActionMap("Debug Menu"); + readonly InputActionMap m_DebugMenuEnableActions = new InputActionMap("Debug Menu Enable Actions"); + readonly InputActionMap m_DebugMenuActions = new InputActionMap("Debug Menu Actions"); InputAction m_MultiplierAction; internal void EnableInputCallbacks() { - m_DebugActionMap.Enable(); + m_DebugMenuEnableActions.Enable(); } internal void DisableInputCallbacks() { - m_DebugActionMap.Disable(); + m_DebugMenuEnableActions.Disable(); } void ToggleRuntimeUI() => displayRuntimeUI = !displayRuntimeUI; void RegisterDebugInputs() { - var enableAction = m_DebugActionMap.AddAction(k_EnableDebug, type: InputActionType.Button); + var enableAction = m_DebugMenuEnableActions.AddAction(k_EnableDebug, type: InputActionType.Button); enableAction.AddCompositeBinding("ButtonWithOneModifier") .With("Modifier", "/rightStickPress") .With("Button", "/leftStickPress") @@ -48,7 +49,7 @@ void RegisterDebugInputs() .With("Button", "/backspace"); enableAction.performed += _ => ToggleRuntimeUI(); - var anyTouchAction = m_DebugActionMap.AddAction(k_AnyTouch, type: InputActionType.Button); + var anyTouchAction = m_DebugMenuEnableActions.AddAction(k_AnyTouch, type: InputActionType.Button); anyTouchAction.AddBinding("/touch2/tap"); // touch2 means "third finger" anyTouchAction.performed += ctx => { @@ -63,7 +64,7 @@ void RegisterDebugInputs() }; #if ENABLE_RENDERING_DEBUGGER_UI - var resetAction = m_DebugActionMap.AddAction(k_ResetBtn, type: InputActionType.Button); + var resetAction = m_DebugMenuActions.AddAction(k_ResetBtn, type: InputActionType.Button); resetAction.AddCompositeBinding("ButtonWithOneModifier") .With("Modifier", "/rightStickPress") .With("Button", "/b") @@ -71,26 +72,26 @@ void RegisterDebugInputs() .With("Button", "/backspace"); resetAction.performed += _ => { Reset(); }; - var next = m_DebugActionMap.AddAction(k_DebugNextBtn, type: InputActionType.Button); + var next = m_DebugMenuActions.AddAction(k_DebugNextBtn, type: InputActionType.Button); next.AddBinding("/pageDown"); next.AddBinding("/rightShoulder"); next.performed += _ => { m_RuntimeDebugWindow.SelectNextPanel(); }; - var previous = m_DebugActionMap.AddAction(k_DebugPreviousBtn, type: InputActionType.Button); + var previous = m_DebugMenuActions.AddAction(k_DebugPreviousBtn, type: InputActionType.Button); previous.AddBinding("/pageUp"); previous.AddBinding("/leftShoulder"); previous.performed += _ => { m_RuntimeDebugWindow.SelectPreviousPanel(); }; - var persistentAction = m_DebugActionMap.AddAction(k_PersistentBtn, type: InputActionType.Button); + var persistentAction = m_DebugMenuActions.AddAction(k_PersistentBtn, type: InputActionType.Button); persistentAction.AddBinding("/rightShift"); persistentAction.AddBinding("/x"); persistentAction.performed += _ => { TogglePersistent(); }; - m_MultiplierAction = m_DebugActionMap.AddAction(k_MultiplierBtn, type: InputActionType.Value); + m_MultiplierAction = m_DebugMenuActions.AddAction(k_MultiplierBtn, type: InputActionType.Value); m_MultiplierAction.AddBinding("/leftShift"); m_MultiplierAction.AddBinding("/y"); - var moveHorizontalAction = m_DebugActionMap.AddAction(k_DPadHorizontal); + var moveHorizontalAction = m_DebugMenuActions.AddAction(k_DPadHorizontal); moveHorizontalAction.AddCompositeBinding("1DAxis") .With("Positive", "/dpad/right") .With("Negative", "/dpad/left") @@ -102,11 +103,11 @@ void RegisterDebugInputs() bool increment = ctx.ReadValue() > 0.0f; if (increment) { - selectedWidget.OnIncrement(multiplierPressed); + selectedWidget?.OnIncrement(multiplierPressed); } else { - selectedWidget.OnDecrement(multiplierPressed); + selectedWidget?.OnDecrement(multiplierPressed); } }; #endif diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugManager.UIState.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugManager.UIState.cs index 1214c4385b6..cba5d156cdf 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugManager.UIState.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugManager.UIState.cs @@ -1,6 +1,9 @@ #if ENABLE_UIELEMENTS_MODULE && (UNITY_EDITOR || DEVELOPMENT_BUILD) #define ENABLE_RENDERING_DEBUGGER_UI #endif +#if ENABLE_INPUT_SYSTEM && ENABLE_INPUT_SYSTEM_PACKAGE +#define USE_INPUT_SYSTEM +#endif using System; @@ -99,6 +102,9 @@ public bool displayRuntimeUI m_RuntimeDebugWindow = go.AddComponent(); go.SetActive(true); } +#if USE_INPUT_SYSTEM + m_DebugMenuActions.Enable(); +#endif } else { @@ -107,6 +113,9 @@ public bool displayRuntimeUI CoreUtils.Destroy(m_RuntimeDebugWindow.gameObject); m_RuntimeDebugWindow = null; } +#if USE_INPUT_SYSTEM + m_DebugMenuActions.Disable(); +#endif } onDisplayRuntimeUIChanged(value); From 058e7d8af957cde522f6430a0fdf7d4ff12e400a Mon Sep 17 00:00:00 2001 From: Angela Dematte Date: Mon, 16 Feb 2026 20:51:05 +0000 Subject: [PATCH 22/92] Disable unstable Materials test --- .../Assets/Tests/HDRP_Runtime_Graphics_Tests.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Tests/SRPTests/Projects/HDRP_RuntimeTests/Assets/Tests/HDRP_Runtime_Graphics_Tests.cs b/Tests/SRPTests/Projects/HDRP_RuntimeTests/Assets/Tests/HDRP_Runtime_Graphics_Tests.cs index 91f3cfef4f0..72ce7ab476b 100644 --- a/Tests/SRPTests/Projects/HDRP_RuntimeTests/Assets/Tests/HDRP_Runtime_Graphics_Tests.cs +++ b/Tests/SRPTests/Projects/HDRP_RuntimeTests/Assets/Tests/HDRP_Runtime_Graphics_Tests.cs @@ -83,6 +83,11 @@ public void SetDefaultResolution() graphicsDeviceTypes: new GraphicsDeviceType[] { GraphicsDeviceType.Metal }, architectures: new Architecture[] { Architecture.X64 } )] + [IgnoreGraphicsTest( + "010-BRG-Simple", + "Unstable: https://jira.unity3d.com/browse/UUM-134572", + runtimePlatforms: new RuntimePlatform[] { RuntimePlatform.PS5 } + )] [IgnoreGraphicsTest( "012-SVL_Check$", "https://jira.unity3d.com/browse/UUM-70791", From 889f8099595d115b45a6966a7eb7dba856765d4a Mon Sep 17 00:00:00 2001 From: Volkan Ilbeyli Date: Tue, 17 Feb 2026 02:05:17 +0000 Subject: [PATCH 23/92] [NVUnityPlugin] DLSS 4.5: upgrade SDK to v310.5.0 --- .../deep-learning-super-sampling-in-hdrp.md | 18 ++++++++++-------- .../RenderPipeline/HDRenderPipelineUI.Skin.cs | 2 +- .../RenderPipeline/RenderPass/DLSSPass.cs | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) 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 0b4b54c3c2c..15565a39b90 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 @@ -1,6 +1,6 @@ # Deep learning super sampling (DLSS) -[NVIDIA Deep Learning Super Sampling (DLSS)](https://www.nvidia.com/en-us/geforce/technologies/dlss/) is a rendering technology that uses artificial intelligence to increase graphics performance. The High Definition Render Pipeline (HDRP) natively supports DLSS 4 Super Resolution. +[NVIDIA Deep Learning Super Sampling (DLSS)](https://www.nvidia.com/en-us/geforce/technologies/dlss/) is a rendering technology that uses artificial intelligence to increase graphics performance. The High Definition Render Pipeline (HDRP) natively supports DLSS 4.5 Super Resolution. ## Requirements and compatibility @@ -82,18 +82,20 @@ Available presets are marked as '1' in the table below. | Render Preset | Maximum Quality | Balanced | Maximum Performance | Ultra Performance | DLAA | Explanation | AI Model | |- |- |- |- |- |- |- |- | -| Preset F | | | | 1 | 1 | Provides the highest image stability. Default value for UltraPerformance. | CNN | -| Preset J | 1 | 1 | 1| | 1 | Slightly lowers ghosting but increases flickering.
NVIDIA recommends using **Preset K** instead of **Preset J**. | Transformer | -| Preset K | 1 | 1 | 1| | 1 | Provides the highest image quality. | Transformer | +| Preset F | | | | 1 | 1 | Marked for deprecation in upcoming DLSS releases. Don't use for new projects. | CNN | +| Preset J | 1 | 1 | 1| 1 | 1 | Slightly lowers ghosting but increases flickering.
NVIDIA recommends using **Preset K** instead of **Preset J**. | Transformer | +| Preset K | 1 | 1 | 1| 1 | 1 | Default preset for DLAA/Balanced/Quality modes. Requires fewer resources than Preset L. | Transformer | +| Preset L | | | | 1 | | Delivers a sharper, more stable image with less ghosting than Preset J, K, but lowers performance. Recommended for RTX 40 Series GPUs and above. | Transformer Gen 2 | +Provides about the same image quality as **Preset L**. This preset is slower than presets **J** and **K**, but faster than preset **L**. Recommended for RTX 40 Series GPUs and above. The defaults for each quality mode are: | **Quality mode** | **Default render preset** | |- |- | -| **Maximum Quality** | Preset K -| **Balanced** | Preset K -| **Maximum Performance** | Preset K -| **Ultra Performance** | Preset F +| **Maximum Quality** | Preset K | +| **Balanced** | Preset K | +| **Maximum Performance** | Preset M | +| **Ultra Performance** | Preset L | | **DLAA** | Preset K | DLSS render presets are project-specific. Presets are available only from the HDRP Asset settings. You can't override presets on a per-camera basis. 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 3b997464002..53e32897760 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 @@ -315,7 +315,7 @@ int CountBits(uint bitMask) // System.Numerics.BitOperations not available { if (preset == UnityEngine.NVIDIA.DLSSPreset.Preset_Default) { - labels[(int)quality][iWrite++] = "Default Preset"; + labels[(int)quality][iWrite++] = "Default Preset" + " - " + UnityEngine.NVIDIA.GraphicsDevice.GetDLSSPresetExplanation(preset); continue; } diff --git a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/DLSSPass.cs b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/DLSSPass.cs index 89b93bc27ab..adf939a5990 100644 --- a/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/DLSSPass.cs +++ b/Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/DLSSPass.cs @@ -183,7 +183,7 @@ private bool ShouldUseAutomaticSettings() static NVIDIA.DLSSPreset Uint2Preset(uint preset) { - if (preset >= (uint)NVIDIA.DLSSPreset.Preset_Default && preset <= (uint)NVIDIA.DLSSPreset.Preset_K) + if (preset >= (uint)NVIDIA.DLSSPreset.Preset_Default && preset <= (uint)NVIDIA.DLSSPreset.Preset_M) return (NVIDIA.DLSSPreset)preset; Debug.LogWarningFormat("Unknown DLSS Preset value {0}, using default value.", preset); return NVIDIA.DLSSPreset.Preset_Default; From ba3c75a525ac96d894c31c1a589cf62a5ddb2a68 Mon Sep 17 00:00:00 2001 From: Rose Hirigoyen Date: Tue, 17 Feb 2026 04:25:10 +0000 Subject: [PATCH 24/92] SRP-1077 Improve batchmode converter command line tool --- .../BuiltInAndURP3DTo2DMaterialUpgrader.cs | 1 + ...BuiltInToURP2DReadonlyMaterialConverter.cs | 1 + .../BuiltInToURP2DRenderSettingsConverter.cs | 1 + .../ParametricToFreeformLightUpgrader.cs | 1 + .../Editor/Converter/Converters.cs | 353 ++++++++++-------- .../Editor/Converter/Converters.cs.meta | 12 +- .../Editor/Deprecated.cs | 196 ++++++++++ .../AnimationClipConverter.cs | 1 + .../BuiltInToURP3DMaterialUpgrader.cs | 1 + ...BuiltInToURP3DReadonlyMaterialConverter.cs | 1 + .../BuiltInToURP3DRenderSettingsConverter.cs | 1 + .../Tools/Converters/PPv2/PPv2Converter.cs | 1 + .../Tools/Converters/ConvertersTests.cs | 142 ++++++- 13 files changed, 550 insertions(+), 162 deletions(-) diff --git a/Packages/com.unity.render-pipelines.universal/Editor/2D/Converter/BuiltInAndURP3DTo2DMaterialUpgrader.cs b/Packages/com.unity.render-pipelines.universal/Editor/2D/Converter/BuiltInAndURP3DTo2DMaterialUpgrader.cs index c715cffc05d..373b2a9a30f 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/2D/Converter/BuiltInAndURP3DTo2DMaterialUpgrader.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/2D/Converter/BuiltInAndURP3DTo2DMaterialUpgrader.cs @@ -8,6 +8,7 @@ namespace UnityEditor.Rendering.Universal { [Serializable] [PipelineTools] + [BatchModeConverterClassInfo("UpgradeURP2DAssets", "URPToReadonlyMaterial2D")] [ElementInfo(Name = "Convert Built-in and URP ( Universal Renderer ) Materials to Mesh2D-Lit-Default", Order = 300, Description = "This will upgrade/crossgrade all 3D materials and 3D material references for URP 2D.")] diff --git a/Packages/com.unity.render-pipelines.universal/Editor/2D/Converter/BuiltInToURP2DReadonlyMaterialConverter.cs b/Packages/com.unity.render-pipelines.universal/Editor/2D/Converter/BuiltInToURP2DReadonlyMaterialConverter.cs index 8d804a82a16..c59e9ccfe2c 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/2D/Converter/BuiltInToURP2DReadonlyMaterialConverter.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/2D/Converter/BuiltInToURP2DReadonlyMaterialConverter.cs @@ -10,6 +10,7 @@ namespace UnityEditor.Rendering.Universal { [Serializable] [PipelineConverter("Built-in", "Universal Render Pipeline (2D Renderer)")] + [BatchModeConverterClassInfo("BuiltInToURP2D", "ReadonlyMaterial2D")] [ElementInfo(Name = "Material Reference Converter", Order = 100, Description = "Converts references to Built-In readonly materials to URP (2D) readonly materials.")] diff --git a/Packages/com.unity.render-pipelines.universal/Editor/2D/Converter/BuiltInToURP2DRenderSettingsConverter.cs b/Packages/com.unity.render-pipelines.universal/Editor/2D/Converter/BuiltInToURP2DRenderSettingsConverter.cs index dc95826c388..75c33a1dd7e 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/2D/Converter/BuiltInToURP2DRenderSettingsConverter.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/2D/Converter/BuiltInToURP2DRenderSettingsConverter.cs @@ -9,6 +9,7 @@ namespace UnityEditor.Rendering.Universal { [Serializable] [PipelineConverter("Built-in", "Universal Render Pipeline (2D Renderer)")] + [BatchModeConverterClassInfo("BuiltInToURP2D", "RenderSettings2D")] [ElementInfo(Name = "Rendering Settings", Order = int.MinValue, Description = "This converter creates Universal Render Pipeline (URP) assets and corresponding Renderer assets, configuring their settings to match the equivalent settings from the Built-in Render Pipeline.")] diff --git a/Packages/com.unity.render-pipelines.universal/Editor/2D/Converter/ParametricToFreeformLightUpgrader.cs b/Packages/com.unity.render-pipelines.universal/Editor/2D/Converter/ParametricToFreeformLightUpgrader.cs index 90995d02ede..9ef67901770 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/2D/Converter/ParametricToFreeformLightUpgrader.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/2D/Converter/ParametricToFreeformLightUpgrader.cs @@ -27,6 +27,7 @@ public ParametricToFreeformLightUpgraderItem(GlobalObjectId gid, string assetPat [Serializable] [PipelineTools] + [BatchModeConverterClassInfo("UpgradeURP2DAssets", "ParametricToFreeformLight")] [ElementInfo(Name = "Parametric to Freeform Light Upgrade", Order = 100, Description = "This will upgrade all parametric lights to freeform lights.")] diff --git a/Packages/com.unity.render-pipelines.universal/Editor/Converter/Converters.cs b/Packages/com.unity.render-pipelines.universal/Editor/Converter/Converters.cs index a4c2551c2dc..220668f307e 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/Converter/Converters.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/Converter/Converters.cs @@ -4,212 +4,268 @@ using System.Text; using UnityEditor.Rendering.Converter; using UnityEngine; +using UnityEngine.Rendering; namespace UnityEditor.Rendering.Universal { - /// - /// Filter for the list of converters used in batch mode. - /// - /// - public enum ConverterFilter + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] + internal class BatchModeConverterClassInfo : Attribute { - /// - /// Use this to include converters matching the filter. - /// - Inclusive, + public string converterType { get; } + public string containerName { get; } - /// - /// Use this to exclude converters matching the filter. - /// - Exclusive + public BatchModeConverterClassInfo(string containerName, string converterType) + { + this.converterType = converterType; + this.containerName = containerName; + } } /// - /// The container to run in batch mode. + /// Class for the converter framework. /// - /// - public enum ConverterContainerId + public static partial class Converters { - /// - /// Use this for Built-in to URP converter. - /// - BuiltInToURP, + // Commands + const string k_BatchmodeCommand = "-batchmode"; + const string k_HelpCommand = "--help"; + const string k_ListCommand = "--list"; + const string k_ContainerCommand = "-container"; + const string k_TypesFilterCommand = "-typesFilter"; + const string k_InclusiveFlag = "--inclusive"; + const string k_ExclusiveFlag = "--exclusive"; + + // List all available containers + static void ListAvailableConverters() + { + // Get all converters and group them by container + var containersDict = DictionaryPool>.Get(); + foreach (var container in TypeCache.GetTypesWithAttribute()) + { + if (container.IsAbstract || container.IsInterface) + continue; - /// - /// Use this for Built-in to 2D (URP) converter. - /// - BuiltInToURP2D, + var info = container.GetCustomAttribute(); + if (!containersDict.ContainsKey(info.containerName)) + { + containersDict[info.containerName] = new List(); + } - /// - /// Use this for Built-in and 3D URP to 2D (URP) converter. - /// - BuiltInAndURPToURP2D, + containersDict[info.containerName].Add(info.converterType); + } - /// - /// Use this to upgrade 2D (URP) assets. - /// - UpgradeURP2DAssets, - } + // Organize the information + StringBuilder convertersMessage = StringBuilderPool.Get(); + foreach (var converter in containersDict) + { + convertersMessage.AppendLine($"Container: {converter.Key}"); + convertersMessage.AppendLine("Available converter types:"); + convertersMessage.AppendLine(String.Join($"\n\t- ", converter.Value)); + convertersMessage.AppendLine("\n"); + } - [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)] - internal class BatchModeConverterInfo : Attribute - { - public Type converterType { get; } - public ConverterContainerId containerName {get;} + Debug.Log($"Available containers and their converter types\n{convertersMessage}"); + } - public BatchModeConverterInfo(ConverterContainerId containerName, Type converterType) + static void LogHelp() { - this.converterType = converterType; - this.containerName = containerName; + StringBuilder helpMessage = StringBuilderPool.Get(); + + // Description + helpMessage.AppendLine("\n"); + helpMessage.AppendLine( "The batchmode converter is a tool to help you upgrade your projects from one scriptable render pipeline\n" + + "to another. Using this API can lead to incomplete or unpredictable conversion outcomes.\n" + + "For reliable results, please perform the conversion via the dedicated window: Window > Rendering > Render Pipeline Converter."); + helpMessage.AppendLine("\n"); + + // Usage + helpMessage.AppendLine($"usage: \t -projectPath {k_BatchmodeCommand} -executeMethod UnityEditor.Rendering.Universal.Converters.RunInBatchModeCmdLine\n" + + $"\t \t[{k_HelpCommand}] [{k_ListCommand}]\n" + + $"\t \t[{k_ContainerCommand} ] [{k_TypesFilterCommand} ] [{k_InclusiveFlag}|{k_ExclusiveFlag}]"); + helpMessage.AppendLine("\n"); + + // Commands + helpMessage.AppendLine("Commands"); + helpMessage.AppendLine($"\t{k_HelpCommand} \t \t Show this help and exit."); + helpMessage.AppendLine($"\t{k_ListCommand} \t \t List all available converters and exit."); + helpMessage.AppendLine("\n"); + + // Options + helpMessage.AppendLine("Options"); + helpMessage.AppendLine($"\t{k_ContainerCommand} \t \t \t The name of the container which will be batched (required)."); + helpMessage.AppendLine($"\t{k_TypesFilterCommand} \t The list of converters types that will be either included or excluded from batching. These converters need to be part of the passed in container for them to run."); + helpMessage.AppendLine($"\t{k_InclusiveFlag}|{k_ExclusiveFlag} \t \t \t Whether the list of converters specified with {k_TypesFilterCommand} will be included or excluded when batching."); + helpMessage.AppendLine("\n"); + + helpMessage.AppendLine("Notes"); + helpMessage.AppendLine($"\t Use either {k_InclusiveFlag} or {k_ExclusiveFlag}, not both."); + helpMessage.AppendLine($"\t When using {k_InclusiveFlag}, you must specify values for {k_TypesFilterCommand}."); + helpMessage.AppendLine($"\t Values for {k_TypesFilterCommand} must be provided as a space-separated list: {k_TypesFilterCommand} typeA typeB typeC"); + helpMessage.AppendLine("\nOnline documentation: https://docs.unity3d.com/6000.5/Documentation/Manual/urp/convert-assets-to-urp.html\n"); + + Debug.Log(helpMessage); } - } - /// - /// The converter to run in batch mode. - /// - /// - public enum ConverterId - { - /// - /// Use this for the material converters. - /// - [BatchModeConverterInfo(ConverterContainerId.BuiltInToURP,typeof(BuiltInToURP3DMaterialUpgrader))] - Material, + internal static void SuggestUpdatedCommand(string container, List converters, bool isInclusive) + { + var containerParameter = $" {k_ContainerCommand} {container}"; + var converterParameter = converters.Count == 0 ? "" : $" {k_TypesFilterCommand} {string.Join(" ", converters)}"; + var filterModeFlag = isInclusive ? $" {k_InclusiveFlag}" : $" {k_ExclusiveFlag}"; + Debug.Log("The method you're trying to use is deprecated. Try running the following command in the command line:\n" + + $" -projectPath {k_BatchmodeCommand} -executeMethod UnityEditor.Rendering.Universal.Converters.RunInBatchModeCmdLine{filterModeFlag}{containerParameter}{converterParameter}"); + } - /// - /// Use this for the render settings converters. - /// - [BatchModeConverterInfo(ConverterContainerId.BuiltInToURP, typeof(BuiltInToURP3DRenderSettingsConverter))] - RenderSettings, + // Return all converters we will be running + internal static List FilterConverters(string containerName, List convertedTypesFilter, bool isInclusive = false) + { + var allConverters = TypeCache.GetTypesWithAttribute(); + var filteredList = new List(allConverters.Count); - /// - /// Use this for the animation clip converters. - /// - [BatchModeConverterInfo(ConverterContainerId.BuiltInToURP, typeof(AnimationClipConverter))] - AnimationClip, + // early return + if (isInclusive && convertedTypesFilter.Count == 0) + return filteredList; // nothing included in the list - /// - /// Use this for readonly material converters. - /// - [BatchModeConverterInfo(ConverterContainerId.BuiltInToURP, typeof(BuiltInToURP3DReadonlyMaterialConverter))] - ReadonlyMaterial, + foreach (var converterType in allConverters) + { + var converterInfo = converterType.GetCustomAttribute(); + if (containerName != converterInfo.containerName) + continue; - /// - /// Use this for 2D material conversion - /// - [BatchModeConverterInfo(ConverterContainerId.BuiltInToURP2D, typeof(BuiltInToURP2DReadonlyMaterialConverter))] - ReadonlyMaterial2D, + var isTypeInFilteredList = convertedTypesFilter.Contains(converterInfo.converterType); - /// - /// Use this for 2D material conversion - /// - [BatchModeConverterInfo(ConverterContainerId.BuiltInToURP2D, typeof(BuiltInToURP2DRenderSettingsConverter))] - RenderSettings2D, + // add if inclusive and in the included list, add if exclusive and not in the excluded list + if (isInclusive == isTypeInFilteredList) + filteredList.Add(converterType); + } - /// - /// Use this for 3D URP material conversion - /// - [BatchModeConverterInfo(ConverterContainerId.UpgradeURP2DAssets, typeof(BuiltInAndURP3DTo2DMaterialUpgrader))] - URPToReadonlyMaterial2D, + return filteredList; + } -#if PPV2_EXISTS - /// - /// Use this for post processing V2 converters. - /// - [BatchModeConverterInfo(ConverterContainerId.BuiltInToURP, typeof(PPv2Converter))] - PPv2, -#endif + internal static Dictionary> ParseArgs(string[] rawArgs) + { + int batchmodeArgIndex = Array.FindIndex(rawArgs, arg => arg == k_BatchmodeCommand); + if (batchmodeArgIndex == -1) + throw new ArgumentException($"No {k_BatchmodeCommand} argument found. Exiting."); - /// - /// Use this for parametric to freeform light converters. - /// - [BatchModeConverterInfo(ConverterContainerId.UpgradeURP2DAssets, typeof(ParametricToFreeformLightUpgrader))] - ParametricToFreeformLight, - } + var parsedArgs = DictionaryPool>.Get(); + parsedArgs["Flags"] = new List(); - /// - /// Class for the converter framework. - /// - public static class Converters - { - private static void DumpAvailableConverters() - { - StringBuilder sb = new(); - foreach (var converter in TypeCache.GetTypesDerivedFrom()) + string currentKey = null; // are we collecting values for a key? + + for(int i = batchmodeArgIndex + 1; i < rawArgs.Length; i++) { - if (converter.IsAbstract || converter.IsInterface) - continue; + if (rawArgs[i].StartsWith("--")) // new flag + { + parsedArgs["Flags"].Add(rawArgs[i]); + currentKey = ""; + } + else if (rawArgs[i].StartsWith("-")) // new argument + { + parsedArgs.Add(rawArgs[i], new List()); + currentKey = rawArgs[i]; + } + else // adding to the last argument + { + if (String.IsNullOrEmpty(currentKey)) + { + throw new ArgumentException($"Unrecognized argument: {rawArgs[i]}"); + } - sb.AppendLine(converter.AssemblyQualifiedName); + parsedArgs[currentKey].Add(rawArgs[i]); + } } - Debug.Log(sb.ToString()); + return parsedArgs; } /// /// Call this method to run all the converters in a specific container in batch mode. /// /// The name of the container which will be batched. All Converters in this Container will run if prerequisites are met. - public static void RunInBatchMode(ConverterContainerId containerName) + public static void RunInBatchMode(string containerName) { - RunInBatchMode(containerName, new List() { }, ConverterFilter.Exclusive); - } - - internal static bool TryGetTypeInContainer(ConverterId value, ConverterContainerId containerName, out Type type) - { - type = null; - var memberInfo = typeof(ConverterId).GetMember(value.ToString()); - if (memberInfo.Length > 0) - { - var attr = memberInfo[0].GetCustomAttribute(); - if (attr != null) - { - if(attr.containerName == containerName) - type = attr.converterType; - } - } - return type != null; + RunInBatchMode(containerName, null, isInclusive: false); } /// /// Call this method to run a specific list of converters in a specific container in batch mode. /// /// The name of the container which will be batched. - /// The list of converters that will be either included or excluded from batching. These converters need to be part of the passed in container for them to run. - /// The enum that decide if the list of converters will be included or excluded when batching. - public static void RunInBatchMode(ConverterContainerId containerName, List converterList, ConverterFilter converterFilter) + /// The list of converters that will be either included or excluded from batching. These converters need to be part of the passed in container for them to run. + /// Whether the list of converters will be included or excluded when batching. + public static void RunInBatchMode(string containerName, List convertedTypes, bool isInclusive) { - var types = FilterConverters(containerName, converterList, converterFilter); + var types = FilterConverters(containerName, convertedTypes, isInclusive); RunInBatchMode(types); } - internal static List FilterConverters(ConverterContainerId containerName, List converterList, ConverterFilter converterFilter) + /// + /// Call this method to run a specific list of converters in a specific container in batch mode. + /// Entry point for: -executeMethod UnityEditor.Rendering.Universal.Converters.RunInBatchModeCmdLine + /// + public static void RunInBatchModeCmdLine() { - Array converters = Enum.GetValues(typeof(ConverterId)); - - List converterTypes = new(); - foreach (object value in converters) + Debug.Log("BATCH MODE COMMAND LINE\n"); + var exitCode = 0; + try { - var converterEnum = (ConverterId)value; - if (TryGetTypeInContainer(converterEnum, containerName, out var type)) + var args = ParseArgs(Environment.GetCommandLineArgs()); + // If help requested, print and exit + if (args["Flags"].Contains(k_HelpCommand)) { - bool inFilter = converterList.Contains(converterEnum); - if ((converterFilter == ConverterFilter.Inclusive) ^ !inFilter) - converterTypes.Add(type); + LogHelp(); + EditorApplication.Exit(0); + return; } - } - return converterTypes; + if (args["Flags"].Contains(k_ListCommand)) + { + ListAvailableConverters(); + EditorApplication.Exit(0); + return; + } + + // ContainerType ----- + if (!args.TryGetValue(k_ContainerCommand, out var converter)) + throw new ArgumentException($"Missing required {k_ContainerCommand} . Use {k_ListCommand} to see available converter."); + if(converter.Count != 1) + throw new ArgumentException($"Please specify only one container. Use {k_ListCommand} to see available converters."); + + // Filter + Include/Exclude ------ + var hasInclusive = args["Flags"].Contains(k_InclusiveFlag); + var hasExclusive = args["Flags"].Contains(k_ExclusiveFlag); + var hasTypesFilter = args.TryGetValue(k_TypesFilterCommand, out var filteredTypes); + + if (hasTypesFilter && hasExclusive == hasInclusive) + { + throw new ArgumentException($"When using {k_TypesFilterCommand}, please specify exactly one of {k_InclusiveFlag} or {k_ExclusiveFlag}. Use {k_HelpCommand} for usage."); + } + + if (hasInclusive && !hasTypesFilter) + throw new ArgumentException($"When using {k_InclusiveFlag} mode, please specify types to include using {k_TypesFilterCommand} otherwise nothing will be converted. " + + $"Use {k_ListCommand} to see available types."); + + RunInBatchMode(converter[0], filteredTypes, hasInclusive); + } + catch (Exception ex) + { + Debug.LogError($"ConverterCli failed: {ex.Message}\n{ex}"); + exitCode = 1; + } + finally + { + EditorApplication.Exit(exitCode); + } } - /// + /// /// Call this method to run a specific list of converters in batch mode. /// /// The list of converters to run /// False if there were errors. internal static bool RunInBatchMode(List converterTypes) { - Debug.LogWarning("Using this API can lead to incomplete or unpredictable conversion outcomes. For reliable results, please perform the conversion via the dedicated window: Window > Rendering > Render Pipeline Converter."); + Debug.LogWarning($"Using this API can lead to incomplete or unpredictable conversion outcomes. For reliable results, please perform the conversion via the dedicated window: Window > Rendering > Render Pipeline Converter."); List convertersToExecute = new(); @@ -237,7 +293,7 @@ internal static bool RunInBatchMode(List converterTypes) if (errors) { Debug.LogWarning($"Please use any of the given Converter Types."); - DumpAvailableConverters(); + ListAvailableConverters(); } BatchConverters(convertersToExecute); @@ -245,11 +301,11 @@ internal static bool RunInBatchMode(List converterTypes) return !errors; } - internal static void BatchConverters(List converters) + static void BatchConverters(List converters) { foreach (var converter in converters) { - var sb = new StringBuilder(); + var sb = StringBuilderPool.Get(); converter.Scan(OnConverterCompleteDataCollection); @@ -270,7 +326,6 @@ void OnConverterCompleteDataCollection(List items) case Status.Success: { sb.AppendLine($"- {item.name} ({status})"); - message = "Conversion successful!"; } break; } diff --git a/Packages/com.unity.render-pipelines.universal/Editor/Converter/Converters.cs.meta b/Packages/com.unity.render-pipelines.universal/Editor/Converter/Converters.cs.meta index 5713c676a85..6dafa388ff7 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/Converter/Converters.cs.meta +++ b/Packages/com.unity.render-pipelines.universal/Editor/Converter/Converters.cs.meta @@ -1,11 +1,3 @@ fileFormatVersion: 2 -guid: 3b0b271613f343246a84ba7a171df9dc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +guid: df92998552b941e79fe2ceca76b5288f +timeCreated: 1769617671 \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.universal/Editor/Deprecated.cs b/Packages/com.unity.render-pipelines.universal/Editor/Deprecated.cs index 9caa83f6f82..6addc6dd95f 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/Deprecated.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/Deprecated.cs @@ -1,4 +1,9 @@ using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using UnityEditor.Rendering.Converter; +using UnityEngine; namespace UnityEditor.Rendering.Universal { @@ -18,4 +23,195 @@ public override void OnInspectorGUI() static partial class EditorUtils { } + + /// + /// Filter for the list of converters used in batch mode. + /// + /// + [Obsolete("ConverterFilter has been deprecated.", false)] + + public enum ConverterFilter + { + /// + /// Use this to include converters matching the filter. + /// + Inclusive, + + /// + /// Use this to exclude converters matching the filter. + /// + Exclusive + } + + /// + /// The container to run in batch mode. + /// + /// + [Obsolete("ConverterContainerId has been deprecated.", false)] + public enum ConverterContainerId + { + /// + /// Use this for Built-in to URP converter. + /// + BuiltInToURP, + + /// + /// Use this for Built-in to 2D (URP) converter. + /// + BuiltInToURP2D, + + /// + /// Use this for Built-in and 3D URP to 2D (URP) converter. + /// + BuiltInAndURPToURP2D, + + /// + /// Use this to upgrade 2D (URP) assets. + /// + UpgradeURP2DAssets, + } + + [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)] + [Obsolete("BatchModeConverterInfo has been deprecated. Please use BatchModeConverterClassInfo or upgrade using UnityEditor.Rendering.Universal.Converters.RunInBatchModeCmdLine instead.", false)] + internal class BatchModeConverterInfo : Attribute + { + public Type converterType { get; } + public ConverterContainerId containerName { get; } + + public BatchModeConverterInfo(ConverterContainerId containerName, Type converterType) + { + this.converterType = converterType; + this.containerName = containerName; + } + } + + /// + /// The converter to run in batch mode. + /// + /// + [Obsolete("ConverterId has been deprecated. Please upgrade using UnityEditor.Rendering.Universal.Converters.RunInBatchModeCmdLine instead.", false)] + public enum ConverterId + { + /// + /// Use this for the material converters. + /// + [BatchModeConverterInfo(ConverterContainerId.BuiltInToURP, typeof(BuiltInToURP3DMaterialUpgrader))] + Material, + + /// + /// Use this for the render settings converters. + /// + [BatchModeConverterInfo(ConverterContainerId.BuiltInToURP, typeof(BuiltInToURP3DRenderSettingsConverter))] + RenderSettings, + + /// + /// Use this for the animation clip converters. + /// + [BatchModeConverterInfo(ConverterContainerId.BuiltInToURP, typeof(AnimationClipConverter))] + AnimationClip, + + /// + /// Use this for readonly material converters. + /// + [BatchModeConverterInfo(ConverterContainerId.BuiltInToURP, typeof(BuiltInToURP3DReadonlyMaterialConverter))] + ReadonlyMaterial, + + /// + /// Use this for 2D material conversion + /// + [BatchModeConverterInfo(ConverterContainerId.BuiltInToURP2D, + typeof(BuiltInToURP2DReadonlyMaterialConverter))] + ReadonlyMaterial2D, + + /// + /// Use this for 2D material conversion + /// + [BatchModeConverterInfo(ConverterContainerId.BuiltInToURP2D, typeof(BuiltInToURP2DRenderSettingsConverter))] + RenderSettings2D, + + /// + /// Use this for 3D URP material conversion + /// + [BatchModeConverterInfo(ConverterContainerId.UpgradeURP2DAssets, + typeof(BuiltInAndURP3DTo2DMaterialUpgrader))] + URPToReadonlyMaterial2D, + +#if PPV2_EXISTS + /// + /// Use this for post processing V2 converters. + /// + [BatchModeConverterInfo(ConverterContainerId.BuiltInToURP, typeof(PPv2Converter))] + PPv2, +#endif + + /// + /// Use this for parametric to freeform light converters. + /// + [BatchModeConverterInfo(ConverterContainerId.UpgradeURP2DAssets, typeof(ParametricToFreeformLightUpgrader))] + ParametricToFreeformLight, + } + + public static partial class Converters + { + /// + /// Call this method to run all the converters in a specific container in batch mode. + /// + /// The name of the container which will be batched. All Converters in this Container will run if prerequisites are met. + [Obsolete("RunInBatchMode(ConverterContainerId) has been deprecated. Please use RunInBatchMode(string) or upgrade using UnityEditor.Rendering.Universal.Converters.RunInBatchModeCmdLine instead.", false)] + public static void RunInBatchMode(ConverterContainerId containerName) + { + RunInBatchMode(containerName, new List() { }, ConverterFilter.Exclusive); + } + + [Obsolete("TryGetTypeInContainer has been deprecated. Please upgrade using UnityEditor.Rendering.Universal.Converters.RunInBatchModeCmdLine instead.", false)] + static bool TryGetTypeInContainer(ConverterId value, ConverterContainerId containerName, out Type type) + { + type = null; + var memberInfo = typeof(ConverterId).GetMember(value.ToString()); + if (memberInfo.Length > 0) + { + var attr = memberInfo[0].GetCustomAttribute(); + if (attr != null) + { + if(attr.containerName == containerName) + type = attr.converterType; + } + } + return type != null; + } + + /// + /// Call this method to run a specific list of converters in a specific container in batch mode. + /// + /// The name of the container which will be batched. + /// The list of converters that will be either included or excluded from batching. These converters need to be part of the passed in container for them to run. + /// The enum that decide if the list of converters will be included or excluded when batching. + [Obsolete("RunInBatchMode(ConverterContainerId, List, ConverterFilter) has been deprecated. Please use RunInBatchMode(string, List, bool) or upgrade using UnityEditor.Rendering.Universal.Converters.RunInBatchModeCmdLine instead.", false)] + public static void RunInBatchMode(ConverterContainerId containerName, List converterList, ConverterFilter converterFilter) + { + var types = FilterConverters(containerName, converterList, converterFilter); + SuggestUpdatedCommand(containerName.ToString(), converterList.ConvertAll(id => id.ToString()), converterFilter == ConverterFilter.Inclusive); + RunInBatchMode(types); + } + + [Obsolete("FilterConverters(ConverterContainerId, List, ConverterFilter) has been deprecated. Please use FilterConverters(string, List, bool) instead.", false)] + internal static List FilterConverters(ConverterContainerId containerName, List converterList, ConverterFilter converterFilter) + { + Array converters = Enum.GetValues(typeof(ConverterId)); + + List converterTypes = new(); + foreach (object value in converters) + { + var converterEnum = (ConverterId)value; + if (TryGetTypeInContainer(converterEnum, containerName, out var type)) + { + bool inFilter = converterList.Contains(converterEnum); + if ((converterFilter == ConverterFilter.Inclusive) ^ !inFilter) + converterTypes.Add(type); + } + } + + return converterTypes; + } + } } diff --git a/Packages/com.unity.render-pipelines.universal/Editor/Tools/Converters/AnimationClipConverter/AnimationClipConverter.cs b/Packages/com.unity.render-pipelines.universal/Editor/Tools/Converters/AnimationClipConverter/AnimationClipConverter.cs index ee98fc7f4a1..d2474e9b732 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/Tools/Converters/AnimationClipConverter/AnimationClipConverter.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/Tools/Converters/AnimationClipConverter/AnimationClipConverter.cs @@ -40,6 +40,7 @@ public AnimationClipConverterItem(GlobalObjectId gid, string assetPath) [Serializable] [URPHelpURL("features/rp-converter")] [PipelineConverter("Built-in", "Universal Render Pipeline (Universal Renderer)")] + [BatchModeConverterClassInfo("BuiltInToURP", "AnimationClip")] [ElementInfo(Name = "Animation Clip", Order = 110, Description = "Updates animation clips that reference material properties to work with URP shaders.\nEnsures material animations continue working after converting Materials from Built-in RP to URP.")] diff --git a/Packages/com.unity.render-pipelines.universal/Editor/Tools/Converters/BuiltInToURP3DMaterialUpgrader.cs b/Packages/com.unity.render-pipelines.universal/Editor/Tools/Converters/BuiltInToURP3DMaterialUpgrader.cs index be461dacc50..0e97e287d06 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/Tools/Converters/BuiltInToURP3DMaterialUpgrader.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/Tools/Converters/BuiltInToURP3DMaterialUpgrader.cs @@ -8,6 +8,7 @@ namespace UnityEditor.Rendering.Universal { [Serializable] [PipelineConverter("Built-in", "Universal Render Pipeline (Universal Renderer)")] + [BatchModeConverterClassInfo("BuiltInToURP", "Material")] [ElementInfo(Name = "Material Shader Converter", Order = 100, Description = "This converter scans all materials that reference Built-in shaders and upgrades them to use Universal Render Pipeline (URP) shaders.")] diff --git a/Packages/com.unity.render-pipelines.universal/Editor/Tools/Converters/BuiltInToURP3DReadonlyMaterialConverter.cs b/Packages/com.unity.render-pipelines.universal/Editor/Tools/Converters/BuiltInToURP3DReadonlyMaterialConverter.cs index 31d5adbf405..14cf7070182 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/Tools/Converters/BuiltInToURP3DReadonlyMaterialConverter.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/Tools/Converters/BuiltInToURP3DReadonlyMaterialConverter.cs @@ -10,6 +10,7 @@ namespace UnityEditor.Rendering.Universal { [Serializable] [PipelineConverter("Built-in", "Universal Render Pipeline (Universal Renderer)")] + [BatchModeConverterClassInfo("BuiltInToURP", "ReadonlyMaterial")] [ElementInfo(Name = "Material Reference Converter", Order = 100, Description = "Converts references to Built-In readonly materials to URP readonly materials.")] diff --git a/Packages/com.unity.render-pipelines.universal/Editor/Tools/Converters/BuiltInToURP3DRenderSettingsConverter.cs b/Packages/com.unity.render-pipelines.universal/Editor/Tools/Converters/BuiltInToURP3DRenderSettingsConverter.cs index e5e6a25ad3b..0991ece7369 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/Tools/Converters/BuiltInToURP3DRenderSettingsConverter.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/Tools/Converters/BuiltInToURP3DRenderSettingsConverter.cs @@ -11,6 +11,7 @@ namespace UnityEditor.Rendering.Universal [Serializable] [URPHelpURL("features/rp-converter")] [PipelineConverter("Built-in", "Universal Render Pipeline (Universal Renderer)")] + [BatchModeConverterClassInfo("BuiltInToURP", "RenderSettings")] [ElementInfo(Name = "Rendering Settings", Order = int.MinValue, Description = "This converter creates Universal Render Pipeline (URP) assets and corresponding Renderer assets, configuring their settings to match the equivalent settings from the Built-in Render Pipeline.")] diff --git a/Packages/com.unity.render-pipelines.universal/Editor/Tools/Converters/PPv2/PPv2Converter.cs b/Packages/com.unity.render-pipelines.universal/Editor/Tools/Converters/PPv2/PPv2Converter.cs index 6c859eb0ed3..094c8f94d97 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/Tools/Converters/PPv2/PPv2Converter.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/Tools/Converters/PPv2/PPv2Converter.cs @@ -21,6 +21,7 @@ namespace UnityEditor.Rendering.Universal [URPHelpURL("features/rp-converter")] [Serializable] [PipelineConverter("Built-in", "Universal Render Pipeline (Universal Renderer)")] + [BatchModeConverterClassInfo("BuiltInToURP", "PPv2")] [ElementInfo(Name = "Post-Processing Stack v2", Order = int.MaxValue, Description = "This converter creates Universal Render Pipeline (URP) assets and corresponding Renderer assets, configuring their settings to match the equivalent settings from the Built-in Render Pipeline.")] diff --git a/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/ConvertersTests.cs b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/ConvertersTests.cs index 17fa8e4ea24..c265e56398d 100644 --- a/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/ConvertersTests.cs +++ b/Packages/com.unity.render-pipelines.universal/Tests/Editor/Tools/Converters/ConvertersTests.cs @@ -64,8 +64,124 @@ public void RunInBatchMode_LogsUsageWarning() bool _ = Converters.RunInBatchMode(new List() {}); } -#pragma warning disable CS0618 // Type or member is obsolete public static IEnumerable TestCases() + { + yield return new TestCaseData( + "BuiltInToURP", + new List { "Material" }, + true, + new List { typeof(BuiltInToURP3DMaterialUpgrader) } + ).SetName("When Using Inclusive filter with Material in the correct category. The Filter only returns that converter"); + yield return new TestCaseData( + "BuiltInToURP", + new List { "ParametricToFreeformLight" }, + true, + new List() + ).SetName("When Using Inclusive filter with Light in the wrong category. The Filter returns nothing"); + + yield return new TestCaseData( + "BuiltInToURP", + new List + { + "RenderSettings", +#if PPV2_EXISTS + "PPv2" +#endif + }, + false, + new List + { + typeof(AnimationClipConverter), + typeof(BuiltInToURP3DMaterialUpgrader), + typeof(BuiltInToURP3DReadonlyMaterialConverter), + } + ).SetName("When Using Exclusive filter. The filter returns everything except the given ids"); + + yield return new TestCaseData( + "BuiltInToURP", + new List(), + true, + new List() // No converters match + ).SetName("When Using Inclusive filter with no converters. The filter returns nothing"); + + yield return new TestCaseData( + "BuiltInToURP", + new List(), + false, + new List + { +#if PPV2_EXISTS + typeof(PPv2Converter), +#endif + typeof(BuiltInToURP3DRenderSettingsConverter), + typeof(AnimationClipConverter), + typeof(BuiltInToURP3DMaterialUpgrader), + typeof(BuiltInToURP3DReadonlyMaterialConverter), + } + ).SetName("BuiltInToURP - When Using Exclusive filter with no converters. The filter returns everything"); + + yield return new TestCaseData( + "BuiltInToURP2D", + new List(), + false, + new List + { + typeof(BuiltInToURP2DRenderSettingsConverter), + typeof(BuiltInToURP2DReadonlyMaterialConverter), + } + ).SetName("BuiltInToURP2D - When Using Exclusive filter with no converters. The filter returns everything"); + + yield return new TestCaseData( + "UpgradeURP2DAssets", + new List(), + false, + new List + { + typeof(BuiltInAndURP3DTo2DMaterialUpgrader), + typeof(ParametricToFreeformLightUpgrader) + } + ).SetName("UpgradeURP2DAssets - When Using Exclusive filter with no converters. The filter returns everything"); + } + + [TestCaseSource(nameof(TestCases))] + public void FilterConverters_ShouldReturnExpectedConverters( + string containerName, + List filterList, + bool filterModeIsInclusive, + List expectedTypes) + { + var actualTypes = Converters.FilterConverters(containerName, filterList, filterModeIsInclusive); + CollectionAssert.AreEquivalent(expectedTypes, actualTypes); + } + + [Test] + public void CommandLine_ArgumentsParsedProperly() + { + // case 1 - working command + var dummyArgs = "-batchmode -executeMethod UnityEditor.Rendering.Universal.Converters.RunInBatchModeCmdLine --flagA -paramA 1 2 3 --flagB --flagC -paramB --flagD"; + var actualArgs = Converters.ParseArgs(dummyArgs.Split(' ')); + Dictionary> expectedArgs = new() + { + { "-executeMethod", new List {"UnityEditor.Rendering.Universal.Converters.RunInBatchModeCmdLine"} }, + { "-paramA", new List {"1", "2", "3"} }, + { "-paramB", new List {} }, + { "Flags", new List {"--flagA", "--flagB", "--flagC", "--flagD"} } + }; + CollectionAssert.AreEquivalent(expectedArgs, actualArgs); + + // case 2 - Error: No -batchmode flag + dummyArgs = "-executeMethod UnityEditor.Rendering.Universal.Converters.RunInBatchModeCmdLine --flagA -paramA 1 2 3"; + var exception = Assert.Throws(() => Converters.ParseArgs(dummyArgs.Split(' '))); + Assert.That(exception.Message, Is.EqualTo("No -batchmode argument found. Exiting.")); + + // case 3 - Error: Adding values without a key + dummyArgs = "-batchmode -executeMethod UnityEditor.Rendering.Universal.Converters.RunInBatchModeCmdLine --flagA wrongArgument"; + exception = Assert.Throws(() => Converters.ParseArgs(dummyArgs.Split(' '))); + Assert.That(exception.Message, Is.EqualTo("Unrecognized argument: wrongArgument")); + } + +#pragma warning disable CS0618 // Type or member is obsolete + public static IEnumerable TestCasesDeprecated() { yield return new TestCaseData( ConverterContainerId.BuiltInToURP, @@ -144,8 +260,8 @@ public static IEnumerable TestCases() ).SetName("UpgradeURP2DAssets - When Using Exclusive filter with no converters. The filter returns everything"); } - [TestCaseSource(nameof(TestCases))] - public void FilterConverters_ShouldReturnExpectedConverters( + [TestCaseSource(nameof(TestCasesDeprecated))] + public void FilterConverters_ShouldReturnExpectedConverters_DeprecatedAPI( ConverterContainerId containerId, List filterList, ConverterFilter filterMode, @@ -155,6 +271,26 @@ public void FilterConverters_ShouldReturnExpectedConverters( CollectionAssert.AreEquivalent(expectedTypes, actualTypes); } + [Test] + public void CommandLine_SuggestCorrectCommands() + { + var expectedOutputTemplate = "The method you're trying to use is deprecated. Try running the following command in the command line:\n{0}"; + + // case 1 + var containerID = ConverterContainerId.BuiltInToURP; + var filterList = new List { ConverterId.Material, ConverterId.RenderSettings }; + Converters.SuggestUpdatedCommand(containerID.ToString(), filterList.ConvertAll(id => id.ToString()), true); + var suggestedCommand = " -projectPath -batchmode -executeMethod UnityEditor.Rendering.Universal.Converters.RunInBatchModeCmdLine --inclusive -container BuiltInToURP -typesFilter Material RenderSettings"; + LogAssert.Expect(LogType.Log, String.Format(expectedOutputTemplate, suggestedCommand)); + + // case 2 + containerID = ConverterContainerId.BuiltInToURP2D; + filterList = new List { }; + Converters.SuggestUpdatedCommand(containerID.ToString(), filterList.ConvertAll(id => id.ToString()), false); + suggestedCommand = " -projectPath -batchmode -executeMethod UnityEditor.Rendering.Universal.Converters.RunInBatchModeCmdLine --exclusive -container BuiltInToURP2D"; + LogAssert.Expect(LogType.Log, String.Format(expectedOutputTemplate, suggestedCommand)); + } + #pragma warning restore CS0618 // Type or member is obsolete } From 366ddfd402ecb983c125647622d58a2382fd0019 Mon Sep 17 00:00:00 2001 From: Rose Hirigoyen Date: Tue, 17 Feb 2026 04:25:10 +0000 Subject: [PATCH 25/92] UUM-133557 Color texture is read twice in custom pass --- .../Runtime/RenderPipeline/RenderPass/CustomPass/CustomPass.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 a0a82bf4cc1..ffb4289aecb 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 @@ -227,7 +227,7 @@ RenderTargets ReadRenderTargets(in IUnsafeRenderGraphBuilder builder, in RenderT output.colorBufferRG = targets.colorBufferRG; builder.UseTexture(output.colorBufferRG, AccessFlags.ReadWrite); } - if (targets.nonMSAAColorBufferRG.IsValid()) + if (targets.nonMSAAColorBufferRG.IsValid() && targets.nonMSAAColorBufferRG != targets.colorBufferRG) { output.nonMSAAColorBufferRG = targets.nonMSAAColorBufferRG; builder.UseTexture(output.nonMSAAColorBufferRG, AccessFlags.ReadWrite); From 54f4d855b4a16980decbfbd2e744c2e1ab68ac86 Mon Sep 17 00:00:00 2001 From: Arttu Peltonen Date: Tue, 17 Feb 2026 16:41:33 +0000 Subject: [PATCH 26/92] Don't initialize debug UI on pipeline create --- .../Editor/Debugging/DebugWindow.cs | 14 +++-- .../Debugging/DebugDisplaySettingsUI.cs | 63 ++++++++++++------- .../Runtime/Debugging/DebugManager.UIState.cs | 16 ++--- .../Runtime/Debugging/RuntimeDebugWindow.cs | 2 + .../Runtime/Deprecated.cs | 2 +- .../Debugging/PanelNameAndOrderTests.cs | 1 + 6 files changed, 60 insertions(+), 38 deletions(-) diff --git a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.cs b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.cs index 9d5fc8b904e..b8800d93db2 100644 --- a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.cs +++ b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.cs @@ -163,11 +163,15 @@ static void SendWidgetValueChangedAnalytic(string queryPath, T previousValue, // Note: this won't get called if the window is opened when the editor itself is closed void OnDestroy() { - // Note: In the case where the window is maximized/unmaximized, OnEnable for the new window gets called *before* OnDestroy. - // Therefore you need to be careful with statics/globals. In this case, we only mark displayEditorUI as false if we are - // closing the only/last DebugWindow instance. - if (Resources.FindObjectsOfTypeAll(typeof(DebugWindow)).Length == 0) - DebugManager.instance.displayEditorUI = false; + EditorApplication.delayCall += () => + { + // Note: In the case where the window is maximized/unmaximized, OnEnable for the new window gets called *before* OnDestroy. + // Therefore you need to be careful with statics/globals. In this case, we only mark displayEditorUI as false if we are + // closing the only/last DebugWindow instance. The check is delayed because inside OnDestroy, the current window still exists. + var debugWindows = Resources.FindObjectsOfTypeAll(typeof(DebugWindow)); + if (debugWindows.Length == 0) + DebugManager.instance.displayEditorUI = false; + }; DebugManager.instance.onSetDirty -= MarkDirty; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettingsUI.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettingsUI.cs index f7fd9098d8e..6216867ad25 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettingsUI.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugDisplaySettingsUI.cs @@ -32,42 +32,55 @@ private void Reset() /// to be registered public void RegisterDebug(IDebugDisplaySettings settings) { - DebugManager debugManager = DebugManager.instance; - List panels = new List(); - - debugManager.RegisterData(this); - + DebugManager.instance.RegisterData(this); m_Settings = settings; - m_DisposablePanels = panels; - m_Settings.Add(new DebugDisplaySettingsRenderGraph()); - Action onExecute = (data) => + // Don't initialize the UI immediately to avoid unnecessary work at pipeline init time. Instaed, + // initialize UI when any debug UI is opened (or if the editor window is already open) + DebugManager.windowStateChanged += DebugUIOpened; + if (DebugManager.instance.isAnyDebugUIActive) + InitializeDebugUI(); + } + + void DebugUIOpened(DebugManager.UIMode uiMode, bool isOpen) + { + InitializeDebugUI(); + } + + internal void InitializeDebugUI() + { + if (m_DisposablePanels == null) { - IDebugDisplaySettingsPanelDisposable disposableSettingsPanel = data.CreatePanel(); + var panels = new List(); - DebugUI.Widget[] panelWidgets = disposableSettingsPanel.Widgets; + Action onExecute = (data) => + { + IDebugDisplaySettingsPanelDisposable disposableSettingsPanel = data.CreatePanel(); - DebugUI.Panel panel = debugManager.GetPanel( - displayName: disposableSettingsPanel.PanelName, - createIfNull: true, - groupIndex: (disposableSettingsPanel is DebugDisplaySettingsPanel debugDisplaySettingsPanel) ? debugDisplaySettingsPanel.Order : 0); -#if UNITY_EDITOR + DebugUI.Widget[] panelWidgets = disposableSettingsPanel.Widgets; - if (DocumentationUtils.TryGetHelpURL(disposableSettingsPanel.GetType(), out var documentationUrl)) - panel.documentationUrl = documentationUrl; + DebugUI.Panel panel = DebugManager.instance.GetPanel( + displayName: disposableSettingsPanel.PanelName, + createIfNull: true, + groupIndex: (disposableSettingsPanel is DebugDisplaySettingsPanel debugDisplaySettingsPanel) ? debugDisplaySettingsPanel.Order : 0); +#if UNITY_EDITOR + if (DocumentationUtils.TryGetHelpURL(disposableSettingsPanel.GetType(), out var documentationUrl)) + panel.documentationUrl = documentationUrl; #endif - ObservableList panelChildren = panel.children; + ObservableList panelChildren = panel.children; - panel.flags = disposableSettingsPanel.Flags; - panels.Add(disposableSettingsPanel); - panelChildren.Add(panelWidgets); - }; + panel.flags = disposableSettingsPanel.Flags; + panels.Add(disposableSettingsPanel); + panelChildren.Add(panelWidgets); + }; - m_Settings.ForEach(onExecute); + m_Settings.ForEach(onExecute); + m_DisposablePanels = panels; - DebugDisplaySerializer.LoadFoldoutStates(); + DebugDisplaySerializer.LoadFoldoutStates(); + } } /// @@ -96,6 +109,8 @@ public void UnregisterDebug() } debugManager.UnregisterData(this); + + DebugManager.windowStateChanged -= DebugUIOpened; } #region IDebugData diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugManager.UIState.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugManager.UIState.cs index cba5d156cdf..f0d30531a58 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugManager.UIState.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/DebugManager.UIState.cs @@ -36,8 +36,8 @@ class UIState { public UIMode mode; - [SerializeField] - private bool m_Open; + bool m_Open; + public bool open { get => m_Open; @@ -53,18 +53,18 @@ public bool open } } - private UIState editorUIState = new UIState() { mode = UIMode.EditorMode }; + readonly UIState m_EditorUIState = new UIState() { mode = UIMode.EditorMode }; /// /// Is the debug editor window open. /// public bool displayEditorUI { - get => editorUIState.open; - set => editorUIState.open = value; + get => m_EditorUIState.open; + set => m_EditorUIState.open = value; } - private bool m_EnableRuntimeUI = true; + bool m_EnableRuntimeUI = true; /// /// Controls whether runtime UI can be enabled. When this is set to false, there will be no overhead @@ -83,7 +83,7 @@ public bool enableRuntimeUI } } - private UIState runtimeUIState = new UIState() { mode = UIMode.RuntimeMode }; + readonly UIState m_RuntimeUIState = new UIState() { mode = UIMode.RuntimeMode }; /// /// Displays the runtime version of the debug window. @@ -120,7 +120,7 @@ public bool displayRuntimeUI onDisplayRuntimeUIChanged(value); - runtimeUIState.open = m_RuntimeDebugWindow != null && m_RuntimeDebugWindow.gameObject.activeInHierarchy; + m_RuntimeUIState.open = m_RuntimeDebugWindow != null && m_RuntimeDebugWindow.gameObject.activeInHierarchy; } #else get => false; diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/RuntimeDebugWindow.cs b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/RuntimeDebugWindow.cs index 3dc42d6b0c6..fd7d4c934ab 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Debugging/RuntimeDebugWindow.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Debugging/RuntimeDebugWindow.cs @@ -116,6 +116,8 @@ void OnDestroy() // Need to unregister here as well because when the UI is closed and reopened, it is a different object so the member // function will be a different object and the Unregister call in RecreateGUI does nothing. m_PanelRootElement.UnregisterCallback(ConvertNavigationMoveEvents, TrickleDown.TrickleDown); + + DebugManager.instance.displayRuntimeUI = false; } void ConvertNavigationMoveEvents(NavigationMoveEvent evt) diff --git a/Packages/com.unity.render-pipelines.core/Runtime/Deprecated.cs b/Packages/com.unity.render-pipelines.core/Runtime/Deprecated.cs index 13f35093f16..5375653abfe 100644 --- a/Packages/com.unity.render-pipelines.core/Runtime/Deprecated.cs +++ b/Packages/com.unity.render-pipelines.core/Runtime/Deprecated.cs @@ -101,7 +101,7 @@ public sealed partial class DebugManager /// /// State of the debug window. [Obsolete("Use DebugManager.instance.displayEditorUI property instead. #from(2023.1)")] - public void ToggleEditorUI(bool open) => editorUIState.open = open; + public void ToggleEditorUI(bool open) => m_EditorUIState.open = open; /// /// Get hashcode state of the Debug Window. diff --git a/Packages/com.unity.render-pipelines.core/Tests/Editor/Debugging/PanelNameAndOrderTests.cs b/Packages/com.unity.render-pipelines.core/Tests/Editor/Debugging/PanelNameAndOrderTests.cs index 09514e0ac4e..dd714946cb1 100644 --- a/Packages/com.unity.render-pipelines.core/Tests/Editor/Debugging/PanelNameAndOrderTests.cs +++ b/Packages/com.unity.render-pipelines.core/Tests/Editor/Debugging/PanelNameAndOrderTests.cs @@ -112,6 +112,7 @@ public void TestOrderAndPanelName() { var debugDisplaySettingsUI = new DebugDisplaySettingsUI(); debugDisplaySettingsUI.RegisterDebug(TestDebugDisplaySettings.Instance); + debugDisplaySettingsUI.InitializeDebugUI(); var panelTest1Index = DebugManager.instance.PanelIndex("Test 1"); Assert.IsTrue(panelTest1Index >= 0); From a042cf9d2db255a3f071307330ff5f7a4c053502 Mon Sep 17 00:00:00 2001 From: Arttu Peltonen Date: Tue, 17 Feb 2026 22:13:56 +0000 Subject: [PATCH 27/92] Search field for Rendering Debugger --- .../Debugging/DebugWindow.SearchFilter.cs | 148 +++++++++++++ .../DebugWindow.SearchFilter.cs.meta | 2 + .../Editor/Debugging/DebugWindow.cs | 3 + .../Editor/Debugging/DebugWindow.uss | 4 +- .../Editor/Debugging/DebugWindow.uxml | 1 + .../RenderGraphViewer.SidePanel.cs | 110 +--------- .../Editor/Utilities/UIElementSearchFilter.cs | 132 ++++++++++++ .../Utilities/UIElementSearchFilter.cs.meta | 2 + .../Runtime/Debugging/DebugUI.Containers.cs | 6 + .../Runtime/Debugging/DebugUI.FieldUtils.cs | 1 + .../Runtime/Debugging/DebugUI.Fields.cs | 34 ++- .../Runtime/Debugging/DebugUI.Panel.cs | 1 + .../Runtime/Debugging/DebugUI.cs | 14 ++ .../DebugPanelRenderingDebuggerTests.cs | 200 +++++++++++++++++- .../Tests/Editor/RenderGraphViewerTests.cs | 2 +- 15 files changed, 546 insertions(+), 114 deletions(-) create mode 100644 Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.SearchFilter.cs create mode 100644 Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.SearchFilter.cs.meta create mode 100644 Packages/com.unity.render-pipelines.core/Editor/Utilities/UIElementSearchFilter.cs create mode 100644 Packages/com.unity.render-pipelines.core/Editor/Utilities/UIElementSearchFilter.cs.meta diff --git a/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.SearchFilter.cs b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.SearchFilter.cs new file mode 100644 index 00000000000..598e6490a18 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Editor/Debugging/DebugWindow.SearchFilter.cs @@ -0,0 +1,148 @@ +#if ENABLE_UIELEMENTS_MODULE && (UNITY_EDITOR || DEVELOPMENT_BUILD) +#define ENABLE_RENDERING_DEBUGGER_UI +#endif + +using System; +using System.Collections.Generic; +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.UIElements; + +namespace UnityEditor.Rendering +{ + internal class WidgetSearchData + { + public List textElements; + public string aggregatedAdditionalSearchText; + + public WidgetSearchData(List textElements, string aggregatedAdditionalSearchText) + { + this.textElements = textElements; + this.aggregatedAdditionalSearchText = aggregatedAdditionalSearchText; + } + } + + sealed partial class DebugWindow + { +#if ENABLE_RENDERING_DEBUGGER_UI + readonly Dictionary m_WidgetSearchElementCache = new(); + readonly List m_PanelHeaderTextElements = new(); + UIElementSearchFilter m_SearchFilter; + + void BuildSearchCache() + { + m_WidgetSearchElementCache.Clear(); + m_PanelHeaderTextElements.Clear(); + + foreach (var panelElement in m_RightPaneElement.Children()) + { + var headerLabel = panelElement.Q