diff --git a/TestProjects/HDRP_DXR_Tests/Assets/Common/HDRenderPipelineAssetSmallCookieAtlas.asset b/TestProjects/HDRP_DXR_Tests/Assets/Common/HDRenderPipelineAssetSmallCookieAtlas.asset
index 11acc0cea20..3f1075b6dbd 100644
--- a/TestProjects/HDRP_DXR_Tests/Assets/Common/HDRenderPipelineAssetSmallCookieAtlas.asset
+++ b/TestProjects/HDRP_DXR_Tests/Assets/Common/HDRenderPipelineAssetSmallCookieAtlas.asset
@@ -12,7 +12,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 0cf1dab834d4ec34195b920ea7bbf9ec, type: 3}
m_Name: HDRenderPipelineAssetSmallCookieAtlas
m_EditorClassIdentifier:
- m_Version: 15
+ m_Version: 16
m_ObsoleteFrameSettings:
overrides: 0
enableShadow: 0
@@ -202,6 +202,7 @@ MonoBehaviour:
supportSSR: 1
supportSSRTransparent: 0
supportSSAO: 1
+ supportSSGI: 0
supportSubsurfaceScattering: 1
sssSampleBudget:
m_Values: 140000002800000050000000
@@ -241,10 +242,9 @@ MonoBehaviour:
atlasOctahedralDepthWidth: 2048
atlasOctahedralDepthHeight: 2048
lightLoopSettings:
- cookieAtlasSize: 1024
+ cookieAtlasSize: 2048
cookieFormat: 74
pointCookieSize: 128
- cubeCookieTexArraySize: 16
cookieAtlasLastValidMip: 0
cookieTexArraySize: 16
planarReflectionAtlasSize: 1024
@@ -275,6 +275,8 @@ MonoBehaviour:
shadowAtlasResolution: 4096
shadowAtlasDepthBits: 32
useDynamicViewportRescale: 1
+ cachedPunctualLightShadowAtlas: 2048
+ cachedAreaLightShadowAtlas: 1024
shadowResolutionDirectional:
m_Values: 00010000000200000004000000080000
m_SchemaId:
@@ -359,6 +361,37 @@ MonoBehaviour:
AODirectionCount: 010000000200000004000000
ContactShadowSampleCount: 060000000a00000010000000
SSRMaxRaySteps: 100000002000000040000000
+ RTAORayLength:
+ - 0.5
+ - 3
+ - 20
+ RTAOSampleCount: 010000000200000008000000
+ RTAODenoise: 010101
+ RTAODenoiserRadius:
+ - 0.25
+ - 0.5
+ - 0.65
+ RTGIRayLength:
+ - 50
+ - 50
+ - 50
+ RTGIFullResolution: 000001
+ RTGIClampValue:
+ - 0.5
+ - 0.8
+ - 1.5
+ RTGIUpScaleRadius: 040000000400000004000000
+ RTGIDenoise: 010101
+ RTGIHalfResDenoise: 010000
+ RTGIDenoiserRadius:
+ - 0.66
+ - 0.66
+ - 1
+ RTGISecondDenoise: 010101
+ RTGISecondDenoiserRadius:
+ - 0.33
+ - 0.33
+ - 0.5
allowShaderVariantStripping: 1
enableSRPBatcher: 1
shaderVariantLogLevel: 0
@@ -375,3 +408,8 @@ MonoBehaviour:
beforeTransparentCustomPostProcesses: []
beforePostProcessCustomPostProcesses: []
afterPostProcessCustomPostProcesses: []
+ virtualTexturingSettings:
+ streamingCpuCacheSizeInMegaBytes: 256
+ streamingGpuCacheSettings:
+ - format: 0
+ sizeInMegaBytes: 128
diff --git a/TestProjects/HDRP_Tests/Assets/GraphicTests/Scenes/2x_Lighting/2004_AnimatedCookie/AnimatedCookie_CRT3.asset b/TestProjects/HDRP_Tests/Assets/GraphicTests/Scenes/2x_Lighting/2004_AnimatedCookie/AnimatedCookie_CRT3.asset
index 92c19f8c8cc..6dd8715ab0f 100644
--- a/TestProjects/HDRP_Tests/Assets/GraphicTests/Scenes/2x_Lighting/2004_AnimatedCookie/AnimatedCookie_CRT3.asset
+++ b/TestProjects/HDRP_Tests/Assets/GraphicTests/Scenes/2x_Lighting/2004_AnimatedCookie/AnimatedCookie_CRT3.asset
@@ -12,9 +12,10 @@ CustomRenderTexture:
Hash: 00000000000000000000000000000000
m_ForcedFallbackFormat: 4
m_DownscaleFallback: 0
+ m_IsAlphaChannelOptional: 0
serializedVersion: 3
- m_Width: 64
- m_Height: 64
+ m_Width: 256
+ m_Height: 256
m_AntiAliasing: 1
m_MipCount: -1
m_DepthFormat: 0
diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/LinuxEditor/Vulkan/None/2004_Light_AnimatedCookie.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/LinuxEditor/Vulkan/None/2004_Light_AnimatedCookie.png
index 6778cdb7f96..e1af18cb1af 100644
--- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/LinuxEditor/Vulkan/None/2004_Light_AnimatedCookie.png
+++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/LinuxEditor/Vulkan/None/2004_Light_AnimatedCookie.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f77c423457601bdf793b25973b5be1f288cd098762d810b35463809164c08a93
-size 147352
+oid sha256:be076b5df08573b0d7b27ebb74a3f0ba802547796c4a19f319b76078142a55d3
+size 139200
diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/OSXEditor/Metal/None/2004_Light_AnimatedCookie.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/OSXEditor/Metal/None/2004_Light_AnimatedCookie.png
index 4ff441cc63a..a76f955465b 100644
--- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/OSXEditor/Metal/None/2004_Light_AnimatedCookie.png
+++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/OSXEditor/Metal/None/2004_Light_AnimatedCookie.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:dcb7d75a3a63dd0fe452f692b07c21e2b579dcbcd6166caf02585d9b881dcd58
-size 128654
+oid sha256:b6d1a8144ec4080233b188b689f7bdf6490f5168bc51422eab4cbd2f678e3bd9
+size 140381
diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2004_Light_AnimatedCookie.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2004_Light_AnimatedCookie.png
index 4ff441cc63a..c7a668196f8 100644
--- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2004_Light_AnimatedCookie.png
+++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2004_Light_AnimatedCookie.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:dcb7d75a3a63dd0fe452f692b07c21e2b579dcbcd6166caf02585d9b881dcd58
-size 128654
+oid sha256:1954dc92000bb8bdd1672467c3b4ecc59d3e9945483468e405cc1b464e62745a
+size 139196
diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2004_Light_AnimatedCookie.png.meta b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2004_Light_AnimatedCookie.png.meta
index 63e0bbc7151..7d7607779eb 100644
--- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2004_Light_AnimatedCookie.png.meta
+++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2004_Light_AnimatedCookie.png.meta
@@ -1,12 +1,12 @@
fileFormatVersion: 2
-guid: 4fb2f0be5656817498ff2dc989a5311d
+guid: 34611e41cbeaf0442b03c2709a014a20
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
- serializedVersion: 10
+ serializedVersion: 11
mipmaps:
mipMapMode: 0
- enableMipMap: 0
+ enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
@@ -20,9 +20,10 @@ TextureImporter:
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
- isReadable: 1
+ isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
+ vTOnly: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
@@ -54,17 +55,32 @@ TextureImporter:
textureType: 0
textureShape: 1
singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
+ applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
- textureCompression: 0
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/2004_Light_AnimatedCookie.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/2004_Light_AnimatedCookie.png
index d2c13b6d589..3d950209ce1 100644
--- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/2004_Light_AnimatedCookie.png
+++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/2004_Light_AnimatedCookie.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:30f785424e4e7fc14885c0208f02f7978b9a3c5ae8e4c20bca9a0b433df60a56
-size 147409
+oid sha256:de539e02d7879f309c4c865aa19509935c7ad586599c7da0e9fe283c31d5ee51
+size 139148
diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/2313_Shadow_Mask_Spotlight_Shapes.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/2313_Shadow_Mask_Spotlight_Shapes.png
index df8d13de973..b8ee90de1b5 100644
--- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/2313_Shadow_Mask_Spotlight_Shapes.png
+++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/2313_Shadow_Mask_Spotlight_Shapes.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8be30cb45821cd11408651cee8a836a038e9a13e183fd78bf91073050d87ef5a
-size 84570
+oid sha256:97ffb86a6a0fc5f461eeebe2d963f812fe61656517ca0decd0b5078cae391ab3
+size 75138
diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/2004_Light_AnimatedCookie.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/2004_Light_AnimatedCookie.png
index d3e89936cdb..fcbee48d525 100644
--- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/2004_Light_AnimatedCookie.png
+++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/2004_Light_AnimatedCookie.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:821312d5f29d57ed32db265755c9684880fa5aadafcff785826cea0f9872255f
-size 129002
+oid sha256:4dcae60e1c451d51a4cae8858be477ba475d0344979238d5c92e16392aa19d1c
+size 139201
diff --git a/com.unity.render-pipelines.core/Editor/Lighting/IESEngine.cs b/com.unity.render-pipelines.core/Editor/Lighting/IESEngine.cs
new file mode 100644
index 00000000000..5888ae75fd7
--- /dev/null
+++ b/com.unity.render-pipelines.core/Editor/Lighting/IESEngine.cs
@@ -0,0 +1,444 @@
+using System.IO;
+using Unity.Collections;
+using UnityEditor;
+using UnityEditor.Experimental.AssetImporters;
+using UnityEngine;
+
+namespace UnityEditor.Rendering
+{
+ // Photometric type coordinate system references:
+ // https://www.ies.org/product/approved-method-guide-to-goniometer-measurements-and-types-and-photometric-coordinate-systems/
+ // https://support.agi32.com/support/solutions/articles/22000209748-type-a-type-b-and-type-c-photometry
+ ///
+ /// IES class which is common for the Importers
+ ///
+
+ [System.Serializable]
+ public class IESEngine
+ {
+ const float k_HalfPi = 0.5f * Mathf.PI;
+ const float k_TwoPi = 2.0f * Mathf.PI;
+
+ internal IESReader m_iesReader = new IESReader();
+
+ internal string FileFormatVersion { get => m_iesReader.FileFormatVersion; }
+
+ internal TextureImporterType m_TextureGenerationType = TextureImporterType.Cookie;
+
+ ///
+ /// setter for the Texture generation Type
+ ///
+ public TextureImporterType TextureGenerationType
+ {
+ set { m_TextureGenerationType = value; }
+ }
+
+ ///
+ /// Method to read the IES File
+ ///
+ /// Path to the IES file in the Disk.
+ /// An error message or warning otherwise null if no error
+ public string ReadFile(string iesFilePath)
+ {
+ if (!File.Exists(iesFilePath))
+ {
+ return "IES file does not exist.";
+ }
+
+ string errorMessage;
+
+ try
+ {
+ errorMessage = m_iesReader.ReadFile(iesFilePath);
+ }
+ catch (IOException ioEx)
+ {
+ return ioEx.Message;
+ }
+
+ return errorMessage;
+ }
+
+ ///
+ /// Check a keyword
+ ///
+ /// A keyword to check if exist.
+ /// A Keyword if exist inside the internal Dictionary
+ public string GetKeywordValue(string keyword)
+ {
+ return m_iesReader.GetKeywordValue(keyword);
+ }
+
+ ///
+ /// Getter (as a string) for the Photometric Type
+ ///
+ /// The current Photometric Type
+ public string GetPhotometricType()
+ {
+ switch (m_iesReader.PhotometricType)
+ {
+ case 3: // type A
+ return "Type A";
+ case 2: // type B
+ return "Type B";
+ default: // type C
+ return "Type C";
+ }
+ }
+
+ ///
+ /// Get the CUrrent Max intensity
+ ///
+ /// A pair of the intensity follow by the used unit (candelas or lumens)
+ public (float, string) GetMaximumIntensity()
+ {
+ if (m_iesReader.TotalLumens == -1f) // absolute photometry
+ {
+ return (m_iesReader.MaxCandelas, "Candelas");
+ }
+ else
+ {
+ return (m_iesReader.TotalLumens, "Lumens");
+ }
+ }
+
+ ///
+ /// Generated a Cube texture based on the internal PhotometricType
+ ///
+ /// Compression parameter requestted.
+ /// The resquested size.
+ /// A Cubemap representing this IES
+ public (string, Texture) GenerateCubeCookie(TextureImporterCompression compression, int textureSize)
+ {
+ int width = 2 * textureSize;
+ int height = 2 * textureSize;
+
+ NativeArray colorBuffer;
+
+ switch (m_iesReader.PhotometricType)
+ {
+ case 3: // type A
+ colorBuffer = BuildTypeACylindricalTexture(width, height);
+ break;
+ case 2: // type B
+ colorBuffer = BuildTypeBCylindricalTexture(width, height);
+ break;
+ default: // type C
+ colorBuffer = BuildTypeCCylindricalTexture(width, height);
+ break;
+ }
+
+ return GenerateTexture(m_TextureGenerationType, TextureImporterShape.TextureCube, compression, width, height, colorBuffer);
+ }
+
+ // Gnomonic projection reference:
+ // http://speleotrove.com/pangazer/gnomonic_projection.html
+ ///
+ /// Generating a 2D Texture of this cookie, using a Gnomonic projection of the bottom of the IES
+ ///
+ /// Compression parameter requestted.
+ /// Cone angle used to performe the Gnomonic projection.
+ /// The resquested size.
+ /// Bool to enable or not the Light Attenuation based on the squared distance.
+ /// A Generated 2D texture doing the projection of the IES using the Gnomonic projection of the bottom half hemisphere with the given 'cone angle'
+ public (string, Texture) Generate2DCookie(TextureImporterCompression compression, float coneAngle, int textureSize, bool applyLightAttenuation)
+ {
+ NativeArray colorBuffer;
+
+ switch (m_iesReader.PhotometricType)
+ {
+ case 3: // type A
+ colorBuffer = BuildTypeAGnomonicTexture(coneAngle, textureSize, applyLightAttenuation);
+ break;
+ case 2: // type B
+ colorBuffer = BuildTypeBGnomonicTexture(coneAngle, textureSize, applyLightAttenuation);
+ break;
+ default: // type C
+ colorBuffer = BuildTypeCGnomonicTexture(coneAngle, textureSize, applyLightAttenuation);
+ break;
+ }
+
+ return GenerateTexture(m_TextureGenerationType, TextureImporterShape.Texture2D, compression, textureSize, textureSize, colorBuffer);
+ }
+
+ private (string, Texture) GenerateCylindricalTexture(TextureImporterCompression compression, int textureSize)
+ {
+ int width = 2 * textureSize;
+ int height = textureSize;
+
+ NativeArray colorBuffer;
+
+ switch (m_iesReader.PhotometricType)
+ {
+ case 3: // type A
+ colorBuffer = BuildTypeACylindricalTexture(width, height);
+ break;
+ case 2: // type B
+ colorBuffer = BuildTypeBCylindricalTexture(width, height);
+ break;
+ default: // type C
+ colorBuffer = BuildTypeCCylindricalTexture(width, height);
+ break;
+ }
+
+ return GenerateTexture(TextureImporterType.Default, TextureImporterShape.Texture2D, compression, width, height, colorBuffer);
+ }
+
+ (string, Texture) GenerateTexture(TextureImporterType type, TextureImporterShape shape, TextureImporterCompression compression, int width, int height, NativeArray colorBuffer)
+ {
+ // Default values set by the TextureGenerationSettings constructor can be found in this file on GitHub:
+ // https://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/AssetPipeline/TextureGenerator.bindings.cs
+
+ var settings = new TextureGenerationSettings(type);
+
+ SourceTextureInformation textureInfo = settings.sourceTextureInformation;
+ textureInfo.containsAlpha = true;
+ textureInfo.height = height;
+ textureInfo.width = width;
+
+ TextureImporterSettings textureImporterSettings = settings.textureImporterSettings;
+ textureImporterSettings.alphaSource = TextureImporterAlphaSource.FromInput;
+ textureImporterSettings.aniso = 0;
+ textureImporterSettings.borderMipmap = (textureImporterSettings.textureType == TextureImporterType.Cookie);
+ textureImporterSettings.filterMode = FilterMode.Bilinear;
+ textureImporterSettings.generateCubemap = TextureImporterGenerateCubemap.Cylindrical;
+ textureImporterSettings.mipmapEnabled = false;
+ textureImporterSettings.npotScale = TextureImporterNPOTScale.None;
+ textureImporterSettings.readable = true;
+ textureImporterSettings.sRGBTexture = false;
+ textureImporterSettings.textureShape = shape;
+ textureImporterSettings.wrapMode = textureImporterSettings.wrapModeU = textureImporterSettings.wrapModeV = textureImporterSettings.wrapModeW = TextureWrapMode.Clamp;
+
+ TextureImporterPlatformSettings platformSettings = settings.platformSettings;
+ platformSettings.maxTextureSize = 2048;
+ platformSettings.resizeAlgorithm = TextureResizeAlgorithm.Bilinear;
+ platformSettings.textureCompression = compression;
+
+ TextureGenerationOutput output = TextureGenerator.GenerateTexture(settings, colorBuffer);
+
+ if (output.importWarnings.Length > 0)
+ {
+ Debug.LogWarning("Cannot properly generate IES texture:\n" + string.Join("\n", output.importWarnings));
+ }
+
+ return (output.importInspectorWarnings, output.texture);
+ }
+
+ NativeArray BuildTypeACylindricalTexture(int width, int height)
+ {
+ float stepU = 360f / (width - 1);
+ float stepV = 180f / (height - 1);
+
+ var textureBuffer = new NativeArray(width * height, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
+
+ for (int y = 0; y < height; y++)
+ {
+ var slice = new NativeSlice(textureBuffer, y * width, width);
+
+ float latitude = y * stepV - 90f; // in range [-90..+90] degrees
+
+ float verticalAnglePosition = m_iesReader.ComputeVerticalAnglePosition(latitude);
+
+ for (int x = 0; x < width; x++)
+ {
+ float longitude = x * stepU - 180f; // in range [-180..+180] degrees
+
+ float horizontalAnglePosition = m_iesReader.ComputeTypeAorBHorizontalAnglePosition(longitude);
+
+ byte value = (byte)((m_iesReader.InterpolateBilinear(horizontalAnglePosition, verticalAnglePosition) / m_iesReader.MaxCandelas) * 255);
+ slice[x] = new Color32(value, value, value, value);
+ }
+ }
+
+ return textureBuffer;
+ }
+
+ NativeArray BuildTypeBCylindricalTexture(int width, int height)
+ {
+ float stepU = k_TwoPi / (width - 1);
+ float stepV = Mathf.PI / (height - 1);
+
+ var textureBuffer = new NativeArray(width * height, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
+
+ for (int y = 0; y < height; y++)
+ {
+ var slice = new NativeSlice(textureBuffer, y * width, width);
+
+ float v = y * stepV - k_HalfPi; // in range [-90..+90] degrees
+
+ float sinV = Mathf.Sin(v);
+ float cosV = Mathf.Cos(v);
+
+ for (int x = 0; x < width; x++)
+ {
+ float u = Mathf.PI - x * stepU; // in range [+180..-180] degrees
+
+ float sinU = Mathf.Sin(u);
+ float cosU = Mathf.Cos(u);
+
+ // Since a type B luminaire is turned on its side, rotate it to make its polar axis horizontal.
+ float longitude = Mathf.Atan2(sinV, cosU * cosV) * Mathf.Rad2Deg; // in range [-180..+180] degrees
+ float latitude = Mathf.Asin(-sinU * cosV) * Mathf.Rad2Deg; // in range [-90..+90] degrees
+
+ float horizontalAnglePosition = m_iesReader.ComputeTypeAorBHorizontalAnglePosition(longitude);
+ float verticalAnglePosition = m_iesReader.ComputeVerticalAnglePosition(latitude);
+
+ byte value = (byte)((m_iesReader.InterpolateBilinear(horizontalAnglePosition, verticalAnglePosition) / m_iesReader.MaxCandelas) * 255);
+ slice[x] = new Color32(value, value, value, value);
+ }
+ }
+
+ return textureBuffer;
+ }
+
+ NativeArray BuildTypeCCylindricalTexture(int width, int height)
+ {
+ float stepU = k_TwoPi / (width - 1);
+ float stepV = Mathf.PI / (height - 1);
+
+ var textureBuffer = new NativeArray(width * height, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
+
+ for (int y = 0; y < height; y++)
+ {
+ var slice = new NativeSlice(textureBuffer, y * width, width);
+
+ float v = y * stepV - k_HalfPi; // in range [-90..+90] degrees
+
+ float sinV = Mathf.Sin(v);
+ float cosV = Mathf.Cos(v);
+
+ for (int x = 0; x < width; x++)
+ {
+ float u = Mathf.PI - x * stepU; // in range [+180..-180] degrees
+
+ float sinU = Mathf.Sin(u);
+ float cosU = Mathf.Cos(u);
+
+ // Since a type C luminaire is generally aimed at nadir, orient it toward +Z at the center of the cylindrical texture.
+ float longitude = ((Mathf.Atan2(sinU * cosV, sinV) + k_TwoPi) % k_TwoPi) * Mathf.Rad2Deg; // in range [0..360] degrees
+ float latitude = (Mathf.Asin(-cosU * cosV) + k_HalfPi) * Mathf.Rad2Deg; // in range [0..180] degrees
+
+ float horizontalAnglePosition = m_iesReader.ComputeTypeCHorizontalAnglePosition(longitude);
+ float verticalAnglePosition = m_iesReader.ComputeVerticalAnglePosition(latitude);
+
+ byte value = (byte)((m_iesReader.InterpolateBilinear(horizontalAnglePosition, verticalAnglePosition) / m_iesReader.MaxCandelas) * 255);
+ slice[x] = new Color32(value, value, value, value);
+ }
+ }
+
+ return textureBuffer;
+ }
+
+ NativeArray BuildTypeAGnomonicTexture(float coneAngle, int size, bool applyLightAttenuation)
+ {
+ float limitUV = Mathf.Tan(0.5f * coneAngle * Mathf.Deg2Rad);
+ float stepUV = (2 * limitUV) / (size - 3);
+
+ var textureBuffer = new NativeArray(size * size, Allocator.Temp, NativeArrayOptions.ClearMemory);
+
+ // Leave a one-pixel black border around the texture to avoid cookie spilling.
+ for (int y = 1; y < size - 1; y++)
+ {
+ var slice = new NativeSlice(textureBuffer, y * size, size);
+
+ float v = (y - 1) * stepUV - limitUV;
+
+ for (int x = 1; x < size - 1; x++)
+ {
+ float u = (x - 1) * stepUV - limitUV;
+
+ float rayLengthSquared = u * u + v * v + 1;
+
+ float longitude = Mathf.Atan(u) * Mathf.Rad2Deg; // in range [-90..+90] degrees
+ float latitude = Mathf.Asin(v / Mathf.Sqrt(rayLengthSquared)) * Mathf.Rad2Deg; // in range [-90..+90] degrees
+
+ float horizontalAnglePosition = m_iesReader.ComputeTypeCHorizontalAnglePosition(longitude);
+ float verticalAnglePosition = m_iesReader.ComputeVerticalAnglePosition(latitude);
+
+ // Factor in the light attenuation further from the texture center.
+ float lightAttenuation = applyLightAttenuation ? rayLengthSquared : 1f;
+
+ byte value = (byte)((m_iesReader.InterpolateBilinear(horizontalAnglePosition, verticalAnglePosition) / (m_iesReader.MaxCandelas * lightAttenuation)) * 255);
+ slice[x] = new Color32(value, value, value, value);
+ }
+ }
+
+ return textureBuffer;
+ }
+
+ NativeArray BuildTypeBGnomonicTexture(float coneAngle, int size, bool applyLightAttenuation)
+ {
+ float limitUV = Mathf.Tan(0.5f * coneAngle * Mathf.Deg2Rad);
+ float stepUV = (2 * limitUV) / (size - 3);
+
+ var textureBuffer = new NativeArray(size * size, Allocator.Temp, NativeArrayOptions.ClearMemory);
+
+ // Leave a one-pixel black border around the texture to avoid cookie spilling.
+ for (int y = 1; y < size - 1; y++)
+ {
+ var slice = new NativeSlice(textureBuffer, y * size, size);
+
+ float v = (y - 1) * stepUV - limitUV;
+
+ for (int x = 1; x < size - 1; x++)
+ {
+ float u = (x - 1) * stepUV - limitUV;
+
+ float rayLengthSquared = u * u + v * v + 1;
+
+ // Since a type B luminaire is turned on its side, U and V are flipped.
+ float longitude = Mathf.Atan(v) * Mathf.Rad2Deg; // in range [-90..+90] degrees
+ float latitude = Mathf.Asin(u / Mathf.Sqrt(rayLengthSquared)) * Mathf.Rad2Deg; // in range [-90..+90] degrees
+
+ float horizontalAnglePosition = m_iesReader.ComputeTypeCHorizontalAnglePosition(longitude);
+ float verticalAnglePosition = m_iesReader.ComputeVerticalAnglePosition(latitude);
+
+ // Factor in the light attenuation further from the texture center.
+ float lightAttenuation = applyLightAttenuation ? rayLengthSquared : 1f;
+
+ byte value = (byte)((m_iesReader.InterpolateBilinear(horizontalAnglePosition, verticalAnglePosition) / (m_iesReader.MaxCandelas * lightAttenuation)) * 255);
+ slice[x] = new Color32(value, value, value, value);
+ }
+ }
+
+ return textureBuffer;
+ }
+
+ NativeArray BuildTypeCGnomonicTexture(float coneAngle, int size, bool applyLightAttenuation)
+ {
+ float limitUV = Mathf.Tan(0.5f * coneAngle * Mathf.Deg2Rad);
+ float stepUV = (2 * limitUV) / (size - 3);
+
+ var textureBuffer = new NativeArray(size * size, Allocator.Temp, NativeArrayOptions.ClearMemory);
+
+ // Leave a one-pixel black border around the texture to avoid cookie spilling.
+ for (int y = 1; y < size - 1; y++)
+ {
+ var slice = new NativeSlice(textureBuffer, y * size, size);
+
+ float v = (y - 1) * stepUV - limitUV;
+
+ for (int x = 1; x < size - 1; x++)
+ {
+ float u = (x - 1) * stepUV - limitUV;
+
+ float uvLength = Mathf.Sqrt(u * u + v * v);
+
+ float longitude = ((Mathf.Atan2(v, u) - k_HalfPi + k_TwoPi) % k_TwoPi) * Mathf.Rad2Deg; // in range [0..360] degrees
+ float latitude = Mathf.Atan(uvLength) * Mathf.Rad2Deg; // in range [0..90] degrees
+
+ float horizontalAnglePosition = m_iesReader.ComputeTypeCHorizontalAnglePosition(longitude);
+ float verticalAnglePosition = m_iesReader.ComputeVerticalAnglePosition(latitude);
+
+ // Factor in the light attenuation further from the texture center.
+ float lightAttenuation = applyLightAttenuation ? (uvLength * uvLength + 1) : 1f;
+
+ byte value = (byte)((m_iesReader.InterpolateBilinear(horizontalAnglePosition, verticalAnglePosition) / (m_iesReader.MaxCandelas * lightAttenuation)) * 255);
+ slice[x] = new Color32(value, value, value, value);
+ }
+ }
+
+ return textureBuffer;
+ }
+ }
+}
diff --git a/com.unity.render-pipelines.core/Editor/Lighting/IESEngine.cs.meta b/com.unity.render-pipelines.core/Editor/Lighting/IESEngine.cs.meta
new file mode 100644
index 00000000000..2b65feac1b8
--- /dev/null
+++ b/com.unity.render-pipelines.core/Editor/Lighting/IESEngine.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: acb96f1a980ed8a42a75ee14ffb92af1
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.render-pipelines.core/Editor/Lighting/IESImporter.cs b/com.unity.render-pipelines.core/Editor/Lighting/IESImporter.cs
new file mode 100644
index 00000000000..5fc3736ad1c
--- /dev/null
+++ b/com.unity.render-pipelines.core/Editor/Lighting/IESImporter.cs
@@ -0,0 +1,109 @@
+using System.IO;
+using UnityEditor;
+using UnityEditor.Experimental.AssetImporters;
+using UnityEngine;
+
+namespace UnityEditor.Rendering
+{
+ ///
+ /// Common class use to share code between implementation of IES Importeres
+ ///
+ [System.Serializable]
+ public class IESImporter
+ {
+ ///
+ /// IES Engine
+ ///
+ public IESEngine engine = new IESEngine();
+
+ ///
+ /// IES Meta data stored in the ies file
+ ///
+ public IESMetaData iesMetaData = new IESMetaData();
+
+ ///
+ /// Delegate prototype which will be sent by the pipeline implementation of the IES Importer
+ ///
+ public delegate void SetupRenderPipelinePrefabLight(IESEngine engine, Light light, Texture ies);
+
+ ///
+ /// Common method performing the import of the asset
+ ///
+ /// Asset importer context.
+ /// Delegate needed to perform operation which are "Render Pipeline specific" here setuping the prefab of light
+ public void CommonOnImportAsset(AssetImportContext ctx, SetupRenderPipelinePrefabLight setupRenderPipelinePrefabLight)
+ {
+ Texture cookieTextureCube = null;
+ Texture cookieTexture2D = null;
+
+ string iesFilePath = Path.Combine(Path.GetDirectoryName(Application.dataPath), ctx.assetPath);
+ string errorMessage = engine.ReadFile(iesFilePath);
+
+ if (string.IsNullOrEmpty(errorMessage))
+ {
+ iesMetaData.FileFormatVersion = engine.FileFormatVersion;
+ iesMetaData.IESPhotometricType = engine.GetPhotometricType();
+ iesMetaData.Manufacturer = engine.GetKeywordValue("MANUFAC");
+ iesMetaData.LuminaireCatalogNumber = engine.GetKeywordValue("LUMCAT");
+ iesMetaData.LuminaireDescription = engine.GetKeywordValue("LUMINAIRE");
+ iesMetaData.LampCatalogNumber = engine.GetKeywordValue("LAMPCAT");
+ iesMetaData.LampDescription = engine.GetKeywordValue("LAMP");
+
+ (iesMetaData.IESMaximumIntensity, iesMetaData.IESMaximumIntensityUnit) = engine.GetMaximumIntensity();
+
+ string warningMessage;
+
+ (warningMessage, cookieTextureCube) = engine.GenerateCubeCookie(iesMetaData.CookieCompression, (int)iesMetaData.iesSize);
+ if (!string.IsNullOrEmpty(warningMessage))
+ {
+ ctx.LogImportWarning($"Cannot properly generate IES Cube texture: {warningMessage}");
+ }
+ cookieTextureCube.IncrementUpdateCount();
+
+ (warningMessage, cookieTexture2D) = engine.Generate2DCookie(iesMetaData.CookieCompression, iesMetaData.SpotAngle, (int)iesMetaData.iesSize, iesMetaData.ApplyLightAttenuation);
+ if (!string.IsNullOrEmpty(warningMessage))
+ {
+ ctx.LogImportWarning($"Cannot properly generate IES 2D texture: {warningMessage}");
+ }
+ cookieTexture2D.IncrementUpdateCount();
+ }
+ else
+ {
+ ctx.LogImportError($"Cannot read IES file '{iesFilePath}': {errorMessage}");
+ }
+
+ string iesFileName = Path.GetFileNameWithoutExtension(ctx.assetPath);
+
+ var iesObject = ScriptableObject.CreateInstance();
+ iesObject.iesMetaData = iesMetaData;
+ var lightObject = new GameObject(iesFileName);
+
+ lightObject.transform.localEulerAngles = new Vector3(90f, 0f, iesMetaData.LightAimAxisRotation);
+
+ Light light = lightObject.AddComponent();
+ light.type = (iesMetaData.PrefabLightType == IESLightType.Point) ? LightType.Point : LightType.Spot;
+ light.intensity = 1f; // would need a better intensity value formula
+ light.range = 10f; // would need a better range value formula
+ light.spotAngle = iesMetaData.SpotAngle;
+
+ setupRenderPipelinePrefabLight(engine, light, (iesMetaData.PrefabLightType == IESLightType.Point) ? cookieTextureCube : cookieTexture2D);
+
+ ctx.AddObjectToAsset("IES", iesObject);
+ ctx.SetMainObject(iesObject);
+
+ // The light object will be automatically converted into a prefab.
+ ctx.AddObjectToAsset(iesFileName, lightObject);
+
+ if (cookieTextureCube != null)
+ {
+ cookieTextureCube.name = iesFileName + "-Cube-IES";
+ ctx.AddObjectToAsset(cookieTextureCube.name, cookieTextureCube);
+ }
+ if (cookieTexture2D != null)
+ {
+ cookieTexture2D.name = iesFileName + "-2D-IES";
+ ctx.AddObjectToAsset(cookieTexture2D.name, cookieTexture2D);
+ }
+ }
+ }
+}
diff --git a/com.unity.render-pipelines.core/Editor/Lighting/IESImporter.cs.meta b/com.unity.render-pipelines.core/Editor/Lighting/IESImporter.cs.meta
new file mode 100644
index 00000000000..2963aab1480
--- /dev/null
+++ b/com.unity.render-pipelines.core/Editor/Lighting/IESImporter.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9801397f829a1ed42984340315cbf362
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.render-pipelines.core/Editor/Lighting/IESImporterEditor.cs b/com.unity.render-pipelines.core/Editor/Lighting/IESImporterEditor.cs
new file mode 100644
index 00000000000..312ede908ec
--- /dev/null
+++ b/com.unity.render-pipelines.core/Editor/Lighting/IESImporterEditor.cs
@@ -0,0 +1,313 @@
+using System.Reflection;
+using UnityEditor;
+using UnityEditor.Experimental.AssetImporters;
+using UnityEngine;
+using UnityEngine.Rendering;
+
+namespace UnityEditor.Rendering
+{
+ ///
+ /// Common class for IES Importer Editor (currently implemented only on HDRP)
+ ///
+ public class IESImporterEditor
+ {
+ GUIStyle m_WordWrapStyle = new GUIStyle();
+
+ SerializedProperty m_FileFormatVersionProp;
+ SerializedProperty m_IESPhotometricTypeProp;
+ SerializedProperty m_IESMaximumIntensityProp;
+ SerializedProperty m_IESMaximumIntensityUnitProp;
+
+ SerializedProperty m_ManufacturerProp;
+ SerializedProperty m_LuminaireCatalogNumberProp;
+ SerializedProperty m_LuminaireDescriptionProp;
+ SerializedProperty m_LampCatalogNumberProp;
+ SerializedProperty m_LampDescriptionProp;
+
+ SerializedProperty m_PrefabLightTypeProp;
+ SerializedProperty m_SpotAngleProp;
+ SerializedProperty m_IESSizeProp;
+ SerializedProperty m_ApplyLightAttenuationProp;
+ SerializedProperty m_UseIESMaximumIntensityProp;
+ SerializedProperty m_CookieCompressionProp;
+
+ protected SerializedProperty m_LightAimAxisRotationProp;
+
+ bool m_ShowLuminaireProductInformation = true;
+ bool m_ShowLightProperties = true;
+
+ protected PreviewRenderUtility m_PreviewRenderUtility = null;
+
+ ///
+ /// Delegate prototype sent by the specialization of the IESImporterEditor per Render Pipeline
+ ///
+ public delegate void LayoutRenderPipelineUseIesMaximumIntensity();
+ ///
+ /// Delegate prototype sent by the specialization of the IESImporterEditor per Render Pipeline
+ ///
+ public delegate void SetupRenderPipelinePreviewCamera(Camera camera);
+ ///
+ /// Delegate prototype sent by the specialization of the IESImporterEditor per Render Pipeline
+ ///
+ public delegate void SetupRenderPipelinePreviewLight(Light light);
+ ///
+ /// Delegate prototype sent by the specialization of the IESImporterEditor per Render Pipeline
+ ///
+ public delegate void SetupRenderPipelinePreviewWallRenderer(MeshRenderer wallRenderer);
+ ///
+ /// Delegate prototype sent by the specialization of the IESImporterEditor per Render Pipeline
+ ///
+ public delegate void SetupRenderPipelinePreviewFloorRenderer(MeshRenderer floorRenderer);
+ ///
+ /// Delegate prototype sent by the specialization of the IESImporterEditor per Render Pipeline
+ ///
+ public delegate void SetupRenderPipelinePreviewLightIntensity(Light light, SerializedProperty useIESMaximumIntensityProp, SerializedProperty iesMaximumIntensityUnitProp, SerializedProperty iesMaximumIntensityProp);
+
+ ///
+ /// Callback called on the Implemented IESImporterEditor (currently on HDRP Only)
+ ///
+ /// Serialized object which can be linked to IESMetadata
+ public void CommonOnEnable(SerializedProperty serializedObject)
+ {
+ m_WordWrapStyle.wordWrap = true;
+
+ m_FileFormatVersionProp = serializedObject.FindPropertyRelative("FileFormatVersion");
+ m_IESPhotometricTypeProp = serializedObject.FindPropertyRelative("IESPhotometricType");
+ m_IESMaximumIntensityProp = serializedObject.FindPropertyRelative("IESMaximumIntensity");
+ m_IESMaximumIntensityUnitProp = serializedObject.FindPropertyRelative("IESMaximumIntensityUnit");
+
+ m_ManufacturerProp = serializedObject.FindPropertyRelative("Manufacturer");
+ m_LuminaireCatalogNumberProp = serializedObject.FindPropertyRelative("LuminaireCatalogNumber");
+ m_LuminaireDescriptionProp = serializedObject.FindPropertyRelative("LuminaireDescription");
+ m_LampCatalogNumberProp = serializedObject.FindPropertyRelative("LampCatalogNumber");
+ m_LampDescriptionProp = serializedObject.FindPropertyRelative("LampDescription");
+
+ m_PrefabLightTypeProp = serializedObject.FindPropertyRelative("PrefabLightType");
+ m_SpotAngleProp = serializedObject.FindPropertyRelative("SpotAngle");
+ m_IESSizeProp = serializedObject.FindPropertyRelative("iesSize");
+ m_ApplyLightAttenuationProp = serializedObject.FindPropertyRelative("ApplyLightAttenuation");
+ m_UseIESMaximumIntensityProp = serializedObject.FindPropertyRelative("UseIESMaximumIntensity");
+ m_CookieCompressionProp = serializedObject.FindPropertyRelative("CookieCompression");
+ m_LightAimAxisRotationProp = serializedObject.FindPropertyRelative("LightAimAxisRotation");
+ }
+
+ ///
+ /// Callback called on the Implemented IESImporterEditor (currently on HDRP Only)
+ ///
+ /// The current specialized scripted importer using the common code
+ public void CommonOnInspectorGUI(ScriptedImporterEditor scriptedImporter)
+ {
+ scriptedImporter.serializedObject.Update();
+
+ EditorGUILayout.LabelField("File Format Version", m_FileFormatVersionProp.stringValue);
+ EditorGUILayout.LabelField("Photometric Type", m_IESPhotometricTypeProp.stringValue);
+ EditorGUILayout.LabelField("Maximum Intensity", $"{m_IESMaximumIntensityProp.floatValue} {m_IESMaximumIntensityUnitProp.stringValue}");
+
+ if (m_ShowLuminaireProductInformation = EditorGUILayout.Foldout(m_ShowLuminaireProductInformation, "Luminaire Product Information"))
+ {
+ EditorGUILayout.LabelField(m_ManufacturerProp.displayName, m_ManufacturerProp.stringValue, m_WordWrapStyle);
+ EditorGUILayout.LabelField(m_LuminaireCatalogNumberProp.displayName, m_LuminaireCatalogNumberProp.stringValue, m_WordWrapStyle);
+ EditorGUILayout.LabelField(m_LuminaireDescriptionProp.displayName, m_LuminaireDescriptionProp.stringValue, m_WordWrapStyle);
+ EditorGUILayout.LabelField(m_LampCatalogNumberProp.displayName, m_LampCatalogNumberProp.stringValue, m_WordWrapStyle);
+ EditorGUILayout.LabelField(m_LampDescriptionProp.displayName, m_LampDescriptionProp.stringValue, m_WordWrapStyle);
+ }
+
+ if (m_ShowLightProperties = EditorGUILayout.Foldout(m_ShowLightProperties, "Light and Cookie Properties"))
+ {
+ EditorGUILayout.PropertyField(m_PrefabLightTypeProp, new GUIContent("Light Type"));
+ EditorGUILayout.PropertyField(m_SpotAngleProp);
+ EditorGUILayout.PropertyField(m_IESSizeProp, new GUIContent("IES Size"));
+ EditorGUILayout.PropertyField(m_ApplyLightAttenuationProp);
+ EditorGUILayout.PropertyField(m_CookieCompressionProp, new GUIContent("IES Compression"));
+
+ // Before enabling this feature, more experimentation is needed with the addition of a Volume in the PreviewRenderUtility scene.
+ EditorGUILayout.PropertyField(m_UseIESMaximumIntensityProp, new GUIContent("Use IES Maximum Intensity"));
+
+ using (new EditorGUILayout.HorizontalScope())
+ {
+ EditorGUILayout.PropertyField(m_LightAimAxisRotationProp, new GUIContent("Aim Axis Rotation"));
+
+ if (GUILayout.Button("Reset", GUILayout.Width(44)))
+ {
+ m_LightAimAxisRotationProp.floatValue = -90f;
+ }
+ }
+ }
+
+ scriptedImporter.serializedObject.ApplyModifiedProperties();
+ }
+
+ ///
+ /// Callback called on the Implemented IESImporterEditor (currently on HDRP Only)
+ ///
+ public void CommonApply()
+ {
+ if (m_PreviewRenderUtility != null)
+ {
+ m_PreviewRenderUtility.Cleanup();
+ m_PreviewRenderUtility = null;
+ }
+ }
+
+ ///
+ /// Callback called on the Implemented IESImporterEditor (currently on HDRP Only)
+ ///
+ /// Delegate provided by the Render pipeline to setup the Preview Camera
+ /// Delegate provided by the Render pipeline to setup the Preview Light
+ /// Delegate provided by the Render pipeline to setup the Preview Wall
+ /// Delegate provided by the Render pipeline to setup the Preview Floor
+ public bool CommonHasPreviewGUI(SetupRenderPipelinePreviewCamera setupRenderPipelinePreviewCamera,
+ SetupRenderPipelinePreviewLight setupRenderPipelinePreviewLight,
+ SetupRenderPipelinePreviewWallRenderer setupRenderPipelinePreviewWallRenderer,
+ SetupRenderPipelinePreviewFloorRenderer setupRenderPipelinePreviewFloorRenderer)
+ {
+ if (m_PreviewRenderUtility == null)
+ {
+ m_PreviewRenderUtility = new PreviewRenderUtility();
+
+ m_PreviewRenderUtility.ambientColor = Color.black;
+
+ m_PreviewRenderUtility.camera.fieldOfView = 60f;
+ m_PreviewRenderUtility.camera.nearClipPlane = 0.1f;
+ m_PreviewRenderUtility.camera.farClipPlane = 10f;
+ m_PreviewRenderUtility.camera.transform.localPosition = new Vector3(1.85f, 0.71f, 0f);
+ m_PreviewRenderUtility.camera.transform.localEulerAngles = new Vector3(15f, -90f, 0f);
+
+ setupRenderPipelinePreviewCamera(m_PreviewRenderUtility.camera);
+
+ m_PreviewRenderUtility.lights[0].type = (m_PrefabLightTypeProp.enumValueIndex == (int)IESLightType.Point) ? LightType.Point : LightType.Spot;
+ m_PreviewRenderUtility.lights[0].color = Color.white;
+ m_PreviewRenderUtility.lights[0].intensity = 1f;
+ m_PreviewRenderUtility.lights[0].range = 10f;
+ m_PreviewRenderUtility.lights[0].spotAngle = m_SpotAngleProp.floatValue;
+ m_PreviewRenderUtility.lights[0].transform.localPosition = new Vector3(0.14f, 1f, 0f);
+ m_PreviewRenderUtility.lights[0].transform.localEulerAngles = new Vector3(90f, 0f, -90f);
+
+ setupRenderPipelinePreviewLight(m_PreviewRenderUtility.lights[0]);
+
+ m_PreviewRenderUtility.lights[1].intensity = 0f;
+
+ GameObject previewWall = GameObject.CreatePrimitive(PrimitiveType.Plane);
+ previewWall.name = "IESPreviewWall";
+ previewWall.hideFlags = HideFlags.HideAndDontSave;
+ previewWall.transform.localPosition = new Vector3(0f, 4f, 0f);
+ previewWall.transform.localEulerAngles = new Vector3(0f, 0f, -90f);
+ previewWall.transform.localScale = new Vector3(1f, 1f, 10f);
+ MeshRenderer previewWallRenderer = previewWall.GetComponent();
+ previewWallRenderer.lightProbeUsage = LightProbeUsage.Off;
+ previewWallRenderer.reflectionProbeUsage = ReflectionProbeUsage.Off;
+ previewWallRenderer.material = AssetDatabase.GetBuiltinExtraResource("Default-Material.mat");
+
+ setupRenderPipelinePreviewWallRenderer(previewWallRenderer);
+
+ m_PreviewRenderUtility.AddSingleGO(previewWall);
+
+ GameObject previewFloor = GameObject.CreatePrimitive(PrimitiveType.Plane);
+ previewFloor.name = "IESPreviewFloor";
+ previewFloor.hideFlags = HideFlags.HideAndDontSave;
+ previewFloor.transform.localPosition = new Vector3(4f, 0f, 0f);
+ previewFloor.transform.localEulerAngles = new Vector3(0f, 0f, 0f);
+ previewFloor.transform.localScale = new Vector3(1f, 1f, 10f);
+ MeshRenderer previewFloorRenderer = previewFloor.GetComponent();
+ previewFloorRenderer.lightProbeUsage = LightProbeUsage.Off;
+ previewFloorRenderer.reflectionProbeUsage = ReflectionProbeUsage.Off;
+ previewFloorRenderer.material = AssetDatabase.GetBuiltinExtraResource("Default-Diffuse.mat");
+
+ setupRenderPipelinePreviewFloorRenderer(previewFloorRenderer);
+
+ m_PreviewRenderUtility.AddSingleGO(previewFloor);
+ }
+
+ return true;
+ }
+
+ ///
+ /// Callback called on the Implemented IESImporterEditor (currently on HDRP Only)
+ ///
+ /// The title of the Preview
+ public GUIContent CommonGetPreviewTitle()
+ {
+ return new GUIContent("IES Luminaire Profile");
+ }
+
+ ///
+ /// Callback called on the Implemented IESImporterEditor (currently on HDRP Only)
+ ///
+ /// Background of the Preview
+ /// Rect of the Preview
+ /// ScriptedImporter targeted
+ /// Delegate provided by the Rendering Pipeline to setup the Light Intensity
+ public void CommonOnPreviewGUI(Rect r, GUIStyle background, ScriptedImporter target,
+ SetupRenderPipelinePreviewLightIntensity setupRenderPipelinePreviewLightIntensity)
+ {
+ if (Event.current.type == EventType.Repaint)
+ {
+ Texture cookieTexture = null;
+ Texture previewTexture = null;
+
+ if (m_PrefabLightTypeProp.enumValueIndex == (int)IESLightType.Point)
+ {
+ foreach (var subAsset in AssetDatabase.LoadAllAssetRepresentationsAtPath(target.assetPath))
+ {
+ if (subAsset.name.EndsWith("-Cube-IES"))
+ {
+ cookieTexture = subAsset as Texture;
+ break;
+ }
+ }
+ }
+ else // LightType.Spot
+ {
+ foreach (var subAsset in AssetDatabase.LoadAllAssetRepresentationsAtPath(target.assetPath))
+ {
+ if (subAsset.name.EndsWith("-2D-IES"))
+ {
+ cookieTexture = subAsset as Texture;
+ break;
+ }
+ }
+ }
+
+ if (cookieTexture != null)
+ {
+ m_PreviewRenderUtility.lights[0].transform.localEulerAngles = new Vector3(90f, 0f, m_LightAimAxisRotationProp.floatValue);
+ setupRenderPipelinePreviewLightIntensity(m_PreviewRenderUtility.lights[0], m_UseIESMaximumIntensityProp, m_IESMaximumIntensityUnitProp, m_IESMaximumIntensityProp);
+ m_PreviewRenderUtility.lights[0].cookie = cookieTexture;
+ m_PreviewRenderUtility.lights[0].type = m_PrefabLightTypeProp.enumValueIndex == (int)IESLightType.Point ? LightType.Point : LightType.Spot;
+
+ m_PreviewRenderUtility.BeginPreview(r, background);
+
+ bool fog = RenderSettings.fog;
+ Unsupported.SetRenderSettingsUseFogNoDirty(false);
+
+ m_PreviewRenderUtility.camera.Render();
+
+ Unsupported.SetRenderSettingsUseFogNoDirty(fog);
+
+ previewTexture = m_PreviewRenderUtility.EndPreview();
+ }
+
+ if (previewTexture == null)
+ {
+ GUI.DrawTexture(r, Texture2D.blackTexture, ScaleMode.StretchToFill, false);
+ }
+ else
+ {
+ GUI.DrawTexture(r, previewTexture, ScaleMode.ScaleToFit, false);
+ }
+ }
+ }
+
+ ///
+ /// Callback called on the Implemented IESImporterEditor (currently on HDRP Only)
+ ///
+ public void CommonOnDisable()
+ {
+ if (m_PreviewRenderUtility != null)
+ {
+ m_PreviewRenderUtility.Cleanup();
+ m_PreviewRenderUtility = null;
+ }
+ }
+ }
+}
diff --git a/com.unity.render-pipelines.core/Editor/Lighting/IESImporterEditor.cs.meta b/com.unity.render-pipelines.core/Editor/Lighting/IESImporterEditor.cs.meta
new file mode 100644
index 00000000000..f39d479f342
--- /dev/null
+++ b/com.unity.render-pipelines.core/Editor/Lighting/IESImporterEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b913694f5cbdba14f8d9ba1e8c028276
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.render-pipelines.core/Editor/Lighting/IESObject.cs b/com.unity.render-pipelines.core/Editor/Lighting/IESObject.cs
new file mode 100644
index 00000000000..0fb941ee111
--- /dev/null
+++ b/com.unity.render-pipelines.core/Editor/Lighting/IESObject.cs
@@ -0,0 +1,171 @@
+using System.IO;
+using UnityEditor;
+using UnityEditor.Experimental.AssetImporters;
+using UnityEngine;
+
+namespace UnityEditor.Rendering
+{
+ ///
+ /// Various possible type for IES, in HDRP for Rectangular light we use spot version
+ ///
+ public enum IESLightType
+ {
+ ///
+ /// Point for the IES
+ ///
+ Point,
+ ///
+ /// Spot for IES (compatible with Area Light)
+ ///
+ Spot,
+ }
+
+ ///
+ /// Possible values for the IES Size.
+ ///
+ public enum IESResolution
+ {
+ /// Size 16
+ IESResolution16 = 16,
+ /// Size 32
+ IESResolution32 = 32,
+ /// Size 64
+ IESResolution64 = 64,
+ /// Size 128
+ IESResolution128 = 128,
+ /// Size 256
+ IESResolution256 = 256,
+ /// Size 512
+ IESResolution512 = 512,
+ /// Size 1024
+ IESResolution1024 = 1024,
+ /// Size 2048
+ IESResolution2048 = 2048,
+ /// Size 4096
+ IESResolution4096 = 4096
+ }
+
+ ///
+ /// Common class to store metadata of an IES file
+ ///
+ [System.Serializable]
+ public class IESMetaData
+ {
+ ///
+ /// Version of the IES File
+ ///
+ public string FileFormatVersion;
+ ///
+ /// Total light intensity (in Lumens) stored on the file, usage of it is optional (through the prefab subasset inside the IESObject)
+ ///
+ public string IESPhotometricType;
+ ///
+ /// IES Max Intensity depends on the various information stored on the IES file
+ ///
+ public float IESMaximumIntensity;
+ ///
+ /// Unit used to measure the IESMaximumIntensity
+ ///
+ public string IESMaximumIntensityUnit;
+
+ // IES luminaire product information.
+ ///
+ /// Manufacturer of the current IES file
+ ///
+ public string Manufacturer; // IES keyword MANUFAC
+ ///
+ /// Luninaire Catalog Number
+ ///
+ public string LuminaireCatalogNumber; // IES keyword LUMCAT
+ ///
+ /// Luminaire Description
+ ///
+ public string LuminaireDescription; // IES keyword LUMINAIRE
+ ///
+ /// Lamp Catalog Number
+ ///
+ public string LampCatalogNumber; // IES keyword LAMPCAT
+ ///
+ /// Lamp Description
+ ///
+ public string LampDescription; // IES keyword LAMP
+
+ ///
+ /// Prefab Light Type (optional to generate the texture used by the renderer)
+ ///
+ public IESLightType PrefabLightType = IESLightType.Point;
+
+ ///
+ /// Spot angle used for the Gnomonic projection of the IES. This parameter will be responsible of the pixel footprint in the 2D Texture
+ /// https://en.wikipedia.org/wiki/Gnomonic_projection
+ ///
+ [Range(1f, 179f)]
+ public float SpotAngle = 120f;
+ ///
+ /// IES Size of the texture used (same parameter for Point & Spot)
+ ///
+ public IESResolution iesSize = IESResolution.IESResolution128;
+
+ ///
+ /// Enable attenuation used for Spot recommanded to be true, particulary with large angle of "SpotAngle" (cf. Gnomonic Projection)
+ ///
+ public bool ApplyLightAttenuation = true;
+ ///
+ /// Enable max intensity for the texture generation
+ ///
+ public bool UseIESMaximumIntensity = true;
+
+ ///
+ /// Compression used to generate the texture (CompressedHQ by default (BC7))
+ ///
+ public TextureImporterCompression CookieCompression = TextureImporterCompression.CompressedHQ;
+
+ ///
+ /// Internally we use 2D projection, we have to choose one axis to project the IES propertly
+ ///
+ [Range(-180f, 180f)]
+ public float LightAimAxisRotation = -90f;
+
+ ///
+ /// Get Hash describing an unique IES
+ ///
+ /// The Hash of the IES Object
+ public override int GetHashCode()
+ {
+ int hash = base.GetHashCode();
+
+ hash = hash * 23 + FileFormatVersion.GetHashCode();
+ hash = hash * 23 + IESPhotometricType.GetHashCode();
+ hash = hash * 23 + IESMaximumIntensity.GetHashCode();
+ hash = hash * 23 + IESMaximumIntensityUnit.GetHashCode();
+
+ hash = hash * 23 + Manufacturer.GetHashCode();
+ hash = hash * 23 + LuminaireCatalogNumber.GetHashCode();
+ hash = hash * 23 + LuminaireDescription.GetHashCode();
+ hash = hash * 23 + LampCatalogNumber.GetHashCode();
+ hash = hash * 23 + LampDescription.GetHashCode();
+
+ hash = hash * 23 + PrefabLightType.GetHashCode();
+
+ hash = hash * 23 + SpotAngle.GetHashCode();
+
+ hash = hash * 23 + iesSize.GetHashCode();
+ hash = hash * 23 + ApplyLightAttenuation.GetHashCode();
+ hash = hash * 23 + UseIESMaximumIntensity.GetHashCode();
+
+ return hash;
+ }
+ }
+
+ ///
+ /// IESObject manipulated internally (in the UI)
+ ///
+ [System.Serializable]
+ public class IESObject : ScriptableObject
+ {
+ ///
+ /// Metadata of the IES file
+ ///
+ public IESMetaData iesMetaData = new IESMetaData();
+ }
+}
diff --git a/com.unity.render-pipelines.core/Editor/Lighting/IESObject.cs.meta b/com.unity.render-pipelines.core/Editor/Lighting/IESObject.cs.meta
new file mode 100644
index 00000000000..40682ff2c79
--- /dev/null
+++ b/com.unity.render-pipelines.core/Editor/Lighting/IESObject.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 901e3026412fba146ab1b63bfc229b78
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.render-pipelines.core/Editor/Lighting/IESReader.cs b/com.unity.render-pipelines.core/Editor/Lighting/IESReader.cs
new file mode 100644
index 00000000000..b1df52999ae
--- /dev/null
+++ b/com.unity.render-pipelines.core/Editor/Lighting/IESReader.cs
@@ -0,0 +1,540 @@
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Text.RegularExpressions;
+using UnityEngine;
+
+namespace UnityEditor.Rendering
+{
+ ///
+ /// Class to Parse IES File
+ ///
+ [System.Serializable]
+ public class IESReader
+ {
+ string m_FileFormatVersion;
+ ///
+ /// Version of the IES File
+ ///
+ public string FileFormatVersion
+ {
+ get { return m_FileFormatVersion; }
+ }
+
+ float m_TotalLumens;
+ ///
+ /// Total light intensity (in Lumens) stored on the file, usage of it is optional (through the prefab subasset inside the IESObject)
+ ///
+ public float TotalLumens
+ {
+ get { return m_TotalLumens; }
+ }
+
+ float m_MaxCandelas;
+ ///
+ /// Maximum of Candela in the IES File
+ ///
+ public float MaxCandelas
+ {
+ get { return m_MaxCandelas; }
+ }
+
+ int m_PhotometricType;
+ ///
+ /// Type of Photometric light in the IES file, varying per IES-Type & version
+ ///
+ public int PhotometricType
+ {
+ get { return m_PhotometricType; }
+ }
+
+ Dictionary m_KeywordDictionary = new Dictionary();
+
+ int m_VerticalAngleCount;
+ int m_HorizontalAngleCount;
+ float[] m_VerticalAngles;
+ float[] m_HorizontalAngles;
+ float[] m_CandelaValues;
+
+ float m_MinDeltaVerticalAngle;
+ float m_MinDeltaHorizontalAngle;
+ float m_FirstHorizontalAngle;
+ float m_LastHorizontalAngle;
+
+ // File format references:
+ // https://www.ies.org/product/standard-file-format-for-electronic-transfer-of-photometric-data/
+ // http://lumen.iee.put.poznan.pl/kw/iesna.txt
+ // https://seblagarde.wordpress.com/2014/11/05/ies-light-format-specification-and-reader/
+ ///
+ /// Main function to read the file
+ ///
+ /// The path to the IES File on disk.
+ /// Return the error during the import otherwise null if no error
+ public string ReadFile(string iesFilePath)
+ {
+
+ using (var iesReader = File.OpenText(iesFilePath))
+ {
+ string versionLine = iesReader.ReadLine();
+
+ if (versionLine == null)
+ {
+ return "Premature end of file (empty file).";
+ }
+
+ switch (versionLine.Trim())
+ {
+ case "IESNA91":
+ m_FileFormatVersion = "LM-63-1991";
+ break;
+ case "IESNA:LM-63-1995":
+ m_FileFormatVersion = "LM-63-1995";
+ break;
+ case "IESNA:LM-63-2002":
+ m_FileFormatVersion = "LM-63-2002";
+ break;
+ case "IES:LM-63-2019":
+ m_FileFormatVersion = "LM-63-2019";
+ break;
+ default:
+ m_FileFormatVersion = "LM-63-1986";
+ break;
+ }
+
+ var keywordRegex = new Regex(@"\s*\[(?\w+)\]\s*(?.*)", RegexOptions.Compiled);
+ var tiltRegex = new Regex(@"TILT=(?.*)", RegexOptions.Compiled);
+
+ string currentKeyword = string.Empty;
+
+ for (string keywordLine = (m_FileFormatVersion == "LM-63-1986") ? versionLine : iesReader.ReadLine(); true; keywordLine = iesReader.ReadLine())
+ {
+ if (keywordLine == null)
+ {
+ return "Premature end of file (missing TILT=NONE).";
+ }
+
+ if (string.IsNullOrWhiteSpace(keywordLine))
+ {
+ continue;
+ }
+
+ Match keywordMatch = keywordRegex.Match(keywordLine);
+
+ if (keywordMatch.Success)
+ {
+ string keyword = keywordMatch.Groups["keyword"].Value;
+ string data = keywordMatch.Groups["data"].Value.Trim();
+
+ if (keyword == currentKeyword || keyword == "MORE")
+ {
+ m_KeywordDictionary[currentKeyword] += $" {data}";
+ }
+ else
+ {
+ // Many separate occurrences of keyword OTHER will need to be handled properly once exposed in the inspector.
+ currentKeyword = keyword;
+ m_KeywordDictionary[currentKeyword] = data;
+ }
+
+ continue;
+ }
+
+ Match tiltMatch = tiltRegex.Match(keywordLine);
+
+ if (tiltMatch.Success)
+ {
+ string data = tiltMatch.Groups["data"].Value.Trim();
+
+ if (data == "NONE")
+ {
+ break;
+ }
+
+ return $"TILT format not supported: TILT={data}";
+ }
+ }
+
+ string[] iesDataTokens = Regex.Split(iesReader.ReadToEnd().Trim(), @"[\s,]+");
+ var iesDataTokenEnumerator = iesDataTokens.GetEnumerator();
+ string iesDataToken;
+
+
+ if (iesDataTokens.Length == 1 && string.IsNullOrWhiteSpace(iesDataTokens[0]))
+ {
+ return "Premature end of file (missing IES data).";
+ }
+
+ if (!iesDataTokenEnumerator.MoveNext())
+ {
+ return "Premature end of file (missing lamp count value).";
+ }
+
+ int lampCount;
+ iesDataToken = iesDataTokenEnumerator.Current.ToString();
+ if (!int.TryParse(iesDataToken, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out lampCount))
+ {
+ return $"Invalid lamp count value: {iesDataToken}";
+ }
+ if (lampCount < 1) lampCount = 1;
+
+ if (!iesDataTokenEnumerator.MoveNext())
+ {
+ return "Premature end of file (missing lumens per lamp value).";
+ }
+
+ float lumensPerLamp;
+ iesDataToken = iesDataTokenEnumerator.Current.ToString();
+ if (!float.TryParse(iesDataToken, NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out lumensPerLamp))
+ {
+ return $"Invalid lumens per lamp value: {iesDataToken}";
+ }
+ m_TotalLumens = (lumensPerLamp < 0f) ? -1f : lampCount * lumensPerLamp;
+
+ if (!iesDataTokenEnumerator.MoveNext())
+ {
+ return "Premature end of file (missing candela multiplier value).";
+ }
+
+ float candelaMultiplier;
+ iesDataToken = iesDataTokenEnumerator.Current.ToString();
+ if (!float.TryParse(iesDataToken, NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out candelaMultiplier))
+ {
+ return $"Invalid candela multiplier value: {iesDataToken}";
+ }
+ if (candelaMultiplier < 0f) candelaMultiplier = 0f;
+
+ if (!iesDataTokenEnumerator.MoveNext())
+ {
+ return "Premature end of file (missing vertical angle count value).";
+ }
+
+ iesDataToken = iesDataTokenEnumerator.Current.ToString();
+ if (!int.TryParse(iesDataToken, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out m_VerticalAngleCount))
+ {
+ return $"Invalid vertical angle count value: {iesDataToken}";
+ }
+ if (m_VerticalAngleCount < 1)
+ {
+ return $"Invalid number of vertical angles: {m_VerticalAngleCount}";
+ }
+
+ if (!iesDataTokenEnumerator.MoveNext())
+ {
+ return "Premature end of file (missing horizontal angle count value).";
+ }
+
+ iesDataToken = iesDataTokenEnumerator.Current.ToString();
+ if (!int.TryParse(iesDataToken, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out m_HorizontalAngleCount))
+ {
+ return $"Invalid horizontal angle count value: {iesDataToken}";
+ }
+ if (m_HorizontalAngleCount < 1)
+ {
+ return $"Invalid number of horizontal angles: {m_HorizontalAngleCount}";
+ }
+
+ if (!iesDataTokenEnumerator.MoveNext())
+ {
+ return "Premature end of file (missing photometric type value).";
+ }
+
+ iesDataToken = iesDataTokenEnumerator.Current.ToString();
+ if (!int.TryParse(iesDataToken, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out m_PhotometricType))
+ {
+ return $"Invalid photometric type value: {iesDataToken}";
+ }
+ if (m_PhotometricType < 1 || m_PhotometricType > 3)
+ {
+ return $"Invalid photometric type: {m_PhotometricType}";
+ }
+
+ // Skip luminous dimension unit type.
+ if (!iesDataTokenEnumerator.MoveNext())
+ {
+ return "Premature end of file (missing luminous dimension unit type value).";
+ }
+
+ // Skip luminous dimension width.
+ if (!iesDataTokenEnumerator.MoveNext())
+ {
+ return "Premature end of file (missing luminous dimension width value).";
+ }
+
+ // Skip luminous dimension length.
+ if (!iesDataTokenEnumerator.MoveNext())
+ {
+ return "Premature end of file (missing luminous dimension length value).";
+ }
+
+ // Skip luminous dimension height.
+ if (!iesDataTokenEnumerator.MoveNext())
+ {
+ return "Premature end of file (missing luminous dimension height value).";
+ }
+
+ if (!iesDataTokenEnumerator.MoveNext())
+ {
+ return "Premature end of file (missing ballast factor value).";
+ }
+
+ float ballastFactor;
+ iesDataToken = iesDataTokenEnumerator.Current.ToString();
+ if (!float.TryParse(iesDataToken, NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out ballastFactor))
+ {
+ return $"Invalid ballast factor value: {iesDataToken}";
+ }
+ if (ballastFactor < 0f) ballastFactor = 0f;
+
+ // Skip future use.
+ if (!iesDataTokenEnumerator.MoveNext())
+ {
+ return "Premature end of file (missing future use value).";
+ }
+
+ // Skip input watts.
+ if (!iesDataTokenEnumerator.MoveNext())
+ {
+ return "Premature end of file (missing input watts value).";
+ }
+
+ m_VerticalAngles = new float[m_VerticalAngleCount];
+ float previousVerticalAngle = float.MinValue;
+
+ m_MinDeltaVerticalAngle = 180f;
+
+ for (int v = 0; v < m_VerticalAngleCount; ++v)
+ {
+ if (!iesDataTokenEnumerator.MoveNext())
+ {
+ return "Premature end of file (missing vertical angle values).";
+ }
+
+ float angle;
+ iesDataToken = iesDataTokenEnumerator.Current.ToString();
+ if (!float.TryParse(iesDataToken, NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out angle))
+ {
+ return $"Invalid vertical angle value: {iesDataToken}";
+ }
+
+ if (angle <= previousVerticalAngle)
+ {
+ return $"Vertical angles are not in ascending order near: {angle}";
+ }
+
+ float deltaVerticalAngle = angle - previousVerticalAngle;
+ if (deltaVerticalAngle < m_MinDeltaVerticalAngle)
+ {
+ m_MinDeltaVerticalAngle = deltaVerticalAngle;
+ }
+
+ m_VerticalAngles[v] = previousVerticalAngle = angle;
+ }
+
+ m_HorizontalAngles = new float[m_HorizontalAngleCount];
+ float previousHorizontalAngle = float.MinValue;
+
+ m_MinDeltaHorizontalAngle = 360f;
+
+ for (int h = 0; h < m_HorizontalAngleCount; ++h)
+ {
+ if (!iesDataTokenEnumerator.MoveNext())
+ {
+ return "Premature end of file (missing horizontal angle values).";
+ }
+
+ float angle;
+ iesDataToken = iesDataTokenEnumerator.Current.ToString();
+ if (!float.TryParse(iesDataToken, NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out angle))
+ {
+ return $"Invalid horizontal angle value: {iesDataToken}";
+ }
+
+ if (angle <= previousHorizontalAngle)
+ {
+ return $"Horizontal angles are not in ascending order near: {angle}";
+ }
+
+ float deltaHorizontalAngle = angle - previousHorizontalAngle;
+ if (deltaHorizontalAngle < m_MinDeltaHorizontalAngle)
+ {
+ m_MinDeltaHorizontalAngle = deltaHorizontalAngle;
+ }
+
+ m_HorizontalAngles[h] = previousHorizontalAngle = angle;
+ }
+
+ m_FirstHorizontalAngle = m_HorizontalAngles[0];
+ m_LastHorizontalAngle = m_HorizontalAngles[m_HorizontalAngleCount - 1];
+
+ m_CandelaValues = new float[m_HorizontalAngleCount * m_VerticalAngleCount];
+ m_MaxCandelas = 0f;
+
+ for (int h = 0; h < m_HorizontalAngleCount; ++h)
+ {
+ for (int v = 0; v < m_VerticalAngleCount; ++v)
+ {
+ if (!iesDataTokenEnumerator.MoveNext())
+ {
+ return "Premature end of file (missing candela values).";
+ }
+
+ float value;
+ iesDataToken = iesDataTokenEnumerator.Current.ToString();
+ if (!float.TryParse(iesDataToken, NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out value))
+ {
+ return $"Invalid candela value: {iesDataToken}";
+ }
+ value *= candelaMultiplier * ballastFactor;
+
+ m_CandelaValues[h * m_VerticalAngleCount + v] = value;
+
+ if (value > m_MaxCandelas)
+ {
+ m_MaxCandelas = value;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ internal string GetKeywordValue(string keyword)
+ {
+ return m_KeywordDictionary.ContainsKey(keyword) ? m_KeywordDictionary[keyword] : string.Empty;
+ }
+
+ internal int GetMinVerticalSampleCount()
+ {
+ if (m_PhotometricType == 2) // type B
+ {
+ // Factor in the 90 degree rotation that will be done when building the cylindrical texture.
+ return 1 + (int)Mathf.Ceil(360 / m_MinDeltaHorizontalAngle); // 360 is 2 * 180 degrees
+ }
+ else // type A or C
+ {
+ return 1 + (int)Mathf.Ceil(360 / m_MinDeltaVerticalAngle); // 360 is 2 * 180 degrees
+ }
+ }
+
+ internal int GetMinHorizontalSampleCount()
+ {
+ switch (m_PhotometricType)
+ {
+ case 3: // type A
+ return 1 + (int)Mathf.Ceil(720 / m_MinDeltaHorizontalAngle); // 720 is 2 * 360 degrees
+ case 2: // type B
+ // Factor in the 90 degree rotation that will be done when building the cylindrical texture.
+ return 1 + (int)Mathf.Ceil(720 / m_MinDeltaVerticalAngle); // 720 is 2 * 360 degrees
+ default: // type C
+ // Factor in the 90 degree rotation that will be done when building the cylindrical texture.
+ return 1 + (int)Mathf.Ceil(720 / Mathf.Min(m_MinDeltaHorizontalAngle, m_MinDeltaVerticalAngle)); // 720 is 2 * 360 degrees
+ }
+ }
+
+ internal float ComputeVerticalAnglePosition(float angle)
+ {
+ return ComputeAnglePosition(angle, m_VerticalAngles);
+ }
+
+ internal float ComputeTypeAorBHorizontalAnglePosition(float angle) // angle in range [-180..+180] degrees
+ {
+ return ComputeAnglePosition(((m_FirstHorizontalAngle == 0f) ? Mathf.Abs(angle) : angle), m_HorizontalAngles);
+ }
+
+ internal float ComputeTypeCHorizontalAnglePosition(float angle) // angle in range [0..360] degrees
+ {
+ switch (m_LastHorizontalAngle)
+ {
+ case 0f: // the luminaire is assumed to be laterally symmetric in all planes
+ angle = 0f;
+ break;
+ case 90f: // the luminaire is assumed to be symmetric in each quadrant
+ angle = 90f - Mathf.Abs(Mathf.Abs(angle - 180f) - 90f);
+ break;
+ case 180f: // the luminaire is assumed to be symmetric about the 0 to 180 degree plane
+ angle = 180f - Mathf.Abs(angle - 180f);
+ break;
+ default: // the luminaire is assumed to exhibit no lateral symmetry
+ break;
+ }
+
+ return ComputeAnglePosition(angle, m_HorizontalAngles);
+ }
+
+ internal float ComputeAnglePosition(float value, float[] angles)
+ {
+ int start = 0;
+ int end = angles.Length - 1;
+
+ if (value < angles[start])
+ {
+ return start;
+ }
+
+ if (value > angles[end])
+ {
+ return end;
+ }
+
+ while (start < end)
+ {
+ int index = (start + end + 1) / 2;
+
+ float angle = angles[index];
+
+ if (value >= angle)
+ {
+ start = index;
+ }
+ else
+ {
+ end = index - 1;
+ }
+ }
+
+ float leftValue = angles[start];
+ float fraction = 0f;
+
+ if (start + 1 < angles.Length)
+ {
+ float rightValue = angles[start + 1];
+ float deltaValue = rightValue - leftValue;
+
+ if (deltaValue > 0.0001f)
+ {
+ fraction = (value - leftValue) / deltaValue;
+ }
+ }
+
+ return start + fraction;
+ }
+
+ internal float InterpolateBilinear(float x, float y)
+ {
+ int ix = (int)Mathf.Floor(x);
+ int iy = (int)Mathf.Floor(y);
+
+ float fractionX = x - ix;
+ float fractionY = y - iy;
+
+ float p00 = InterpolatePoint(ix + 0, iy + 0);
+ float p10 = InterpolatePoint(ix + 1, iy + 0);
+ float p01 = InterpolatePoint(ix + 0, iy + 1);
+ float p11 = InterpolatePoint(ix + 1, iy + 1);
+
+ float p0 = Mathf.Lerp(p00, p01, fractionY);
+ float p1 = Mathf.Lerp(p10, p11, fractionY);
+
+ return Mathf.Lerp(p0, p1, fractionX);
+ }
+
+ internal float InterpolatePoint(int x, int y)
+ {
+ x %= m_HorizontalAngles.Length;
+ y %= m_VerticalAngles.Length;
+
+ return m_CandelaValues[y + x * m_VerticalAngles.Length];
+ }
+ }
+}
diff --git a/com.unity.render-pipelines.core/Editor/Lighting/IESReader.cs.meta b/com.unity.render-pipelines.core/Editor/Lighting/IESReader.cs.meta
new file mode 100644
index 00000000000..ff107842b81
--- /dev/null
+++ b/com.unity.render-pipelines.core/Editor/Lighting/IESReader.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 28e75f38a2dd403448c94e1663867a24
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.render-pipelines.core/ShaderLibrary/Macros.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/Macros.hlsl
index 74a2aaed681..c318581e16b 100644
--- a/com.unity.render-pipelines.core/ShaderLibrary/Macros.hlsl
+++ b/com.unity.render-pipelines.core/ShaderLibrary/Macros.hlsl
@@ -29,6 +29,8 @@
#define HALF_PI 1.57079632679489661923
#define INV_HALF_PI 0.63661977236758134308
#define LOG2_E 1.44269504088896340736
+#define INV_SQRT2 0.70710678118654752440
+#define PI_DIV_FOUR 0.78539816339744830961
#define MILLIMETERS_PER_METER 1000
#define METERS_PER_MILLIMETER rcp(MILLIMETERS_PER_METER)
diff --git a/com.unity.render-pipelines.high-definition/CHANGELOG.md b/com.unity.render-pipelines.high-definition/CHANGELOG.md
index 456559da011..101179d5f4d 100644
--- a/com.unity.render-pipelines.high-definition/CHANGELOG.md
+++ b/com.unity.render-pipelines.high-definition/CHANGELOG.md
@@ -146,6 +146,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Added Fast Memory support for platform that support it.
- Added CPU and GPU timings for ray tracing effects.
- Added support to combine RTSSS and RTGI (1248733).
+- Added IES Profile support for Point, Spot and Rectangular-Area lights
### Fixed
- Fix when rescale probe all direction below zero (1219246)
diff --git a/com.unity.render-pipelines.high-definition/Documentation~/IES-Importer.md b/com.unity.render-pipelines.high-definition/Documentation~/IES-Importer.md
new file mode 100644
index 00000000000..a995bf1bb00
--- /dev/null
+++ b/com.unity.render-pipelines.high-definition/Documentation~/IES-Importer.md
@@ -0,0 +1,25 @@
+# IES Importer
+
+
+
+IES Importer inspector provide informations and customization options for the internally used textures.
+
+### Properties
+
+| **Property** | **Description** |
+| --------------- | ------------------------------------------------------------ |
+| **File Format Version** | The internal format of the IES File |
+| **Photometric Type** | The type of the photometric information stored on the IES File |
+| **Maximum Intensity** | The intensity used on the preface generated as the sub-asset |
+| **Manufacturer** | Metadata about the Manufacturer of the luminaire |
+| **Luminaire Catalog Number** | Metadata about the catalog number of the manufactorer of the luminaire |
+| **Luminaire Description** | Metadata about the luminaire |
+| **Lamp Catalog Number** | Metadata about the catalog number of the manufactorer of the Lamp |
+| **Lamp Description** | Metadata about the Lamp |
+| **Light Type** | Light type used for the prefab used |
+| **Spot Angle** | For a spot light a 2D texture is needed, to be able to project the IES in 2D we need an angle on the upper hemisphere for a proper projection (A [Gnomonic projection](https://en.wikipedia.org/wiki/Gnomonic_projection) is used). As we cannot have infinite precision this parameter will decide how the pixels will be distributed. | [Light Mode](https://docs.unity3d.com/Manual/LightModes.html)
+| **IES Size** | The size of the texture generated (Size of the 2D texture (for spot and Area Lights) and the size of the cubemap (for Point lights)). |
+| **Apply Light Attenuation** | For spot light, as its a projection, we need to take in account the distance to the light source to have a proper light attenuation. |
+| **IES Compression** | Compression used for the internal texture |
+| **Use IES Maximum Intensity** | Use the intensity stored in the IES File for the prefab generated as Sub-Asset. |
+| **Aim Axis Rotation** | For IES with less symmetry, this parameter will allow us to choose on which orientation we can project the IES in the texture. |
diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Images/IES-Importer1.png b/com.unity.render-pipelines.high-definition/Documentation~/Images/IES-Importer1.png
new file mode 100644
index 00000000000..ea26fc842f2
--- /dev/null
+++ b/com.unity.render-pipelines.high-definition/Documentation~/Images/IES-Importer1.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:4614e7cbf7e64ad388c81c62829de7f50eb3b05b5e82354f47f322b1c7674c4c
+size 219336
diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Light-Component.md b/com.unity.render-pipelines.high-definition/Documentation~/Light-Component.md
index a889989aa30..d970b2899a9 100644
--- a/com.unity.render-pipelines.high-definition/Documentation~/Light-Component.md
+++ b/com.unity.render-pipelines.high-definition/Documentation~/Light-Component.md
@@ -145,13 +145,15 @@ These settings define the emissive behavior of your Light. You can set the Light
| **Intensity** | The strength of the Light. Intensity is expressed in the following units:
• A Spot Light can use [Lumen](Physical-Light-Units.html#Lumen), [Candela](Physical-Light-Units.html#Candela), [Lux](Physical-Light-Units.html#Lux), and [EV100](Physical-Light-Units.html#EV).
• A Directional Light can only use **Lux**.
• A Point Light can use **Lumen**, **Candela**, **Lux**, and **EV100**.
• A Area Light can use **Lumen**, [Nits](Physical-Light-Units.html#Nits), and **EV100**.
Generally, the further the light travels from its source, the weaker it gets. The only exception to this is the **Directional Light** which has the same intensity regardless of distance. For the rest of the Light types, lower values cause light to diminish closer to the source. Higher values cause light to diminish further away from the source. |
| **Range** | The range of influence for this Light. Defines how far the emitted light reaches. This property is available for all **Light Types** except **Directional**. |
| **Indirect Multiplier** | The intensity of [indirect](https://docs.unity3d.com/Manual/LightModes-TechnicalInformation.html) light in your Scene. A value of 1 mimics realistic light behavior. A value of 0 disables indirect lighting for this Light. If both **Realtime** and **Baked** Global Illumination are disabled in Lighting Settings (menu: **Window > Rendering > Lighting Settings**), the Indirect Multiplier has no effect. |
-| **Cookie** | An RGB Texture that the Light projects. For example, to create silhouettes or patterned illumination for the Light. Texture shapes should be 2D for Spot and Directional Lights and Cube for Point Lights. Always import **Cookie** textures as the default texture type. This property is available for **Spot**, **Directional**, and **Point** Lights. |
+| **Cookie** | An RGB Texture that the Light projects. For example, to create silhouettes or patterned illumination for the Light. Texture shapes should be 2D for Spot and Directional Lights and Cube for Point Lights. Always import **Cookie** textures as the default texture type. This property is available for **Spot**, **Area** (Rectangular only), **Directional**, and **Point** Lights. |
+| **IES Profile** | An IES File that describe the light profile. If a cookie and an IES profile are setup, a linear average of them is used. (In case of an IES profile and a cookie used at the same time during light baking, only the cookie will be used). |
+| **IES cutoff angle (%)** | Cut off of the IES Profile, as a percentage of the Outer angle. During a baking of a light map this parameter is not used. |
| **Affect Diffuse** | Enable the checkbox to apply [diffuse]() lighting to this Light.
This property only appears when you enable [more options](More-Options.html) for this section. It is only available in Realtime or Mixed light **Mode**. |
| **Affect Specular** | Enable the checkbox to apply [specular](https://docs.unity3d.com/Manual/shader-NormalSpecular.html) lighting to this Light.
This property only appears when you enable [more options](More-Options.html) for this section. It is only available in Realtime or Mixed light **Mode**. |
| **Range Attenuation** | Enable the checkbox to make this Light shine uniformly across its range. This stops light from fading around the edges. This setting is useful when the range limit is not visible on screen, and you do not want the edges of your light to fade out. This property is available for all **Light Types** except **Directional**.
This property only appears when you enable [more options](More-Options.html) for this section. It is only available in Realtime or Mixed light **Mode** for **Type** Area. |
| **Fade Distance** | The distance between the Light source and the Camera at which the Light begins to fade out. Measured in meters. This property is available for all **Light Types** except **Directional**.
This property only appears when you enable [more options](More-Options.html) for this section. It is only available in Realtime or Mixed light **Mode**. |
| **Intensity Multiplier** | A multiplier that gets applied to the intensity of the Light. Does not affect the intensity value, but only gets applied during the evaluation of the lighting. You can also modify this property via [Timeline](https://docs.unity3d.com/Manual/TimelineSection.html), Scripting or [animation](https://docs.unity3d.com/Manual/animeditor-AnimatingAGameObject.html). The parameter lets you fade the Light in and out without having to store its original intensity.
This property only appears when you enable [more options](More-Options.html) for this section. It is only available in Realtime or Mixed light **Mode**. |
-| **Display Emissive Mesh** | Enable the checkbox to make Unity automatically generate a Mesh with an emissive Material using the size, colour, and intensity of this Light. Unity automatically adds the Mesh and Material to the GameObject the Light component is attached to. This property is available for **Rectangle** and **Tube** Lights.
This property only appears when you enable [more options](More-Options.html) for this section. |
+| **Display Emissive Mesh** | Enable the checkbox to make Unity automatically generate a Mesh with an emissive Material using the size, colour, and intensity of this Light. Unity automatically adds the Mesh and Material to the GameObject the Light component is attached to. This property is available for **Rectangle** and **Tube** Lights.
This property only appears when you enable [more options](More-Options.html) for this section. (In case of an IES profile and a cookie used at the same time, only the cookie will be displayed). |
#### Spot Light
diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Upgrading-from-2020.1-to-2020.2.md b/com.unity.render-pipelines.high-definition/Documentation~/Upgrading-from-2020.1-to-2020.2.md
index 725d40c3aad..e4e0480fa28 100644
--- a/com.unity.render-pipelines.high-definition/Documentation~/Upgrading-from-2020.1-to-2020.2.md
+++ b/com.unity.render-pipelines.high-definition/Documentation~/Upgrading-from-2020.1-to-2020.2.md
@@ -22,6 +22,13 @@ From Unity 2020.2, if you create a new [HDRP Asset](HDRP-Asset.md), the **MSAA W
From Unity 2020.2, if you disable the sky override used as the **Static Lighting Sky** in the **Lighting** window, the sky no longer affects the baked lighting. Previously, the sky affected the baked lighting even when it was disabled.
+From Unity 2020.2, HDRP has removed the Cubemap Array for Point [Light](Light-Component.md) cookies and now uses octahedral projection with a regular 2D-Cookie atlas. This is to allow for a single path for light cookies and IES, but it may produce visual artifacts when using a low-resolution cube-cookie. For example, projecting pixel art data.
+
+As the **Cubemap cookie atlas no longer exists**, it is possible that HDRP does not have enough space on the current 2D atlas for the cookies. If this is the case, HDRP displays an error in the Console window. To fix this, increase the size of the 2D cookie atlas. To do this:
+Select your [HDRP Asset](HDRP-Asset.md).
+In the Inspector, go to Lighting > Cookies.
+In the 2D Atlas Size drop-down, select a larger cookie resolution.
+
## Shadows
From Unity 2020.2, it is no longer necessary to change the [HDRP Config package](HDRP-Config-Package.md) to set the [shadow filtering quality](HDRP-Asset.md#FilteringQualities) for deferred rendering. Instead, you can now change the filtering quality directly on the [HDRP Asset](HDRP-Asset.md#FilteringQualities). Note if you previously had not set the shadow filtering quality to **Medium** on the HDRP Asset, the automatic project upgrade process changes the shadow quality which means you may need to manually change it back to its original value.
diff --git a/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporter.cs b/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporter.cs
new file mode 100644
index 00000000000..d887d630a8a
--- /dev/null
+++ b/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporter.cs
@@ -0,0 +1,52 @@
+using UnityEditor;
+using UnityEngine;
+using UnityEngine.Rendering.HighDefinition;
+using UnityEngine.Rendering;
+using UnityEditor.Experimental.AssetImporters;
+
+namespace UnityEditor.Rendering.HighDefinition
+{
+ ///
+ /// Class to describe an IES file
+ ///
+ [ScriptedImporter(1, "ies")]
+ public partial class HDIESImporter : ScriptedImporter
+ {
+ ///
+ /// Data of the IES importer which is common between Core and HDRP
+ ///
+ public UnityEditor.Rendering.IESImporter commonIESImporter = new UnityEditor.Rendering.IESImporter();
+
+ internal void SetupRenderPipelinePrefabLight(IESEngine engine, Light light, Texture ies)
+ {
+ HDLightTypeAndShape hdLightTypeAndShape = (light.type == LightType.Point) ? HDLightTypeAndShape.Point : HDLightTypeAndShape.ConeSpot;
+
+ HDAdditionalLightData hdLight = GameObjectExtension.AddHDLight(light.gameObject, hdLightTypeAndShape);
+
+ if (commonIESImporter.iesMetaData.UseIESMaximumIntensity)
+ {
+ LightUnit lightUnit = (commonIESImporter.iesMetaData.IESMaximumIntensityUnit == "Lumens") ? LightUnit.Lumen : LightUnit.Candela;
+ hdLight.SetIntensity(commonIESImporter.iesMetaData.IESMaximumIntensity, lightUnit);
+ if (light.type == LightType.Point)
+ hdLight.IESPoint = ies;
+ else
+ hdLight.IESSpot = ies;
+ }
+ }
+
+ ///
+ /// Callback when the Importer is done
+ ///
+ /// Asset Importer context.
+ public override void OnImportAsset(AssetImportContext ctx)
+ {
+ commonIESImporter.engine.TextureGenerationType = TextureImporterType.Default;
+
+ commonIESImporter.CommonOnImportAsset(ctx,
+ delegate (IESEngine engine, Light light, Texture ies)
+ {
+ SetupRenderPipelinePrefabLight(engine, light, ies);
+ });
+ }
+ }
+}
diff --git a/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporter.cs.meta b/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporter.cs.meta
new file mode 100644
index 00000000000..b395dde3487
--- /dev/null
+++ b/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporter.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 68f0d5657f1e2aa4e81a5f81ff7edcad
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporterEditor.cs b/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporterEditor.cs
new file mode 100644
index 00000000000..faf826b8f86
--- /dev/null
+++ b/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporterEditor.cs
@@ -0,0 +1,162 @@
+using System.Reflection;
+using UnityEditor;
+using UnityEngine;
+using UnityEngine.Rendering.HighDefinition;
+using UnityEngine.Rendering;
+using UnityEditor.Experimental.AssetImporters;
+
+namespace UnityEditor.Rendering.HighDefinition
+{
+ ///
+ /// Class describing the logic for importer an IES file an generating the IESObject associated
+ ///
+ [CustomEditor(typeof(HDIESImporter))]
+ public partial class HDIESImporterEditor : ScriptedImporterEditor
+ {
+ ///
+ /// IES Importer Editor, common to Core and HDRP
+ ///
+ public UnityEditor.Rendering.IESImporterEditor iesImporterEditor = new UnityEditor.Rendering.IESImporterEditor();
+
+ internal void SetupRenderPipelinePreviewCamera(Camera camera)
+ {
+ HDAdditionalCameraData hdCamera = camera.gameObject.AddComponent();
+
+ hdCamera.clearDepth = true;
+ hdCamera.clearColorMode = HDAdditionalCameraData.ClearColorMode.None;
+
+ hdCamera.GetType().GetProperty("isEditorCameraPreview", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(hdCamera, true, null);
+ }
+
+ internal void SetupRenderPipelinePreviewLight(Light light)
+ {
+ HDLightTypeAndShape hdLightTypeAndShape = (light.type == LightType.Point) ? HDLightTypeAndShape.Point : HDLightTypeAndShape.ConeSpot;
+
+ HDAdditionalLightData hdLight = GameObjectExtension.AddHDLight(light.gameObject, hdLightTypeAndShape);
+
+ hdLight.SetIntensity(20000f, LightUnit.Lumen);
+
+ hdLight.affectDiffuse = true;
+ hdLight.affectSpecular = false;
+ hdLight.affectsVolumetric = false;
+ }
+
+ internal void SetupRenderPipelinePreviewWallRenderer(MeshRenderer wallRenderer)
+ {
+ wallRenderer.material = AssetDatabase.LoadAssetAtPath("Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDMaterial.mat");
+ }
+
+ internal void SetupRenderPipelinePreviewFloorRenderer(MeshRenderer floorRenderer)
+ {
+ floorRenderer.material = AssetDatabase.LoadAssetAtPath("Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDMaterial.mat");
+ }
+
+ internal void SetupRenderPipelinePreviewLightIntensity(Light light, SerializedProperty useIESMaximumIntensityProp, SerializedProperty iesMaximumIntensityUnitProp, SerializedProperty iesMaximumIntensityProp)
+ {
+ HDAdditionalLightData hdLight = light.GetComponent();
+
+ if (useIESMaximumIntensityProp.boolValue)
+ {
+ LightUnit lightUnit = (iesMaximumIntensityUnitProp.stringValue == "Lumens") ? LightUnit.Lumen : LightUnit.Candela;
+ hdLight.SetIntensity(iesMaximumIntensityProp.floatValue, lightUnit);
+ }
+ else
+ {
+ hdLight.SetIntensity(20000f, LightUnit.Lumen);
+ }
+ }
+
+ ///
+ /// Call back for ScriptedImporterEditor
+ ///
+ public override void OnEnable()
+ {
+ base.OnEnable();
+
+ PropertyFetcher entryPoint0 = new PropertyFetcher(serializedObject);
+ SerializedProperty entryPoint1 = entryPoint0.Find(x => x.commonIESImporter);
+ SerializedProperty entryPoint = entryPoint1.FindPropertyRelative("iesMetaData");
+
+ iesImporterEditor.CommonOnEnable(entryPoint);
+ }
+
+ ///
+ /// Call back for ScriptedImporterEditor
+ ///
+ public override void OnInspectorGUI()
+ {
+ iesImporterEditor.CommonOnInspectorGUI(this as ScriptedImporterEditor);
+
+ base.ApplyRevertGUI();
+ }
+
+ ///
+ /// Call back for ScriptedImporterEditor
+ ///
+ protected override void Apply()
+ {
+ base.Apply();
+
+ iesImporterEditor.CommonApply();
+ }
+
+ ///
+ /// Call back for ScriptedImporterEditor
+ ///
+ /// If this importer has a preview or not
+ public override bool HasPreviewGUI()
+ {
+ return iesImporterEditor.CommonHasPreviewGUI(
+ delegate (Camera camera)
+ {
+ SetupRenderPipelinePreviewCamera(camera);
+ },
+ delegate (Light light)
+ {
+ SetupRenderPipelinePreviewLight(light);
+ },
+ delegate (MeshRenderer wallRenderer)
+ {
+ SetupRenderPipelinePreviewWallRenderer(wallRenderer);
+ },
+ delegate (MeshRenderer floorRenderer)
+ {
+ SetupRenderPipelinePreviewFloorRenderer(floorRenderer);
+ }
+ );
+ }
+
+ ///
+ /// Call back for ScriptedImporterEditor
+ ///
+ /// The title of the Preview
+ public override GUIContent GetPreviewTitle()
+ {
+ return iesImporterEditor.CommonGetPreviewTitle();
+ }
+
+ ///
+ /// Call back for ScriptedImporterEditor
+ ///
+ /// Rectangle of the preview.
+ /// Style of the background of the preview.
+ public override void OnPreviewGUI(Rect r, GUIStyle background)
+ {
+ iesImporterEditor.CommonOnPreviewGUI(r, background, target as HDIESImporter,
+ delegate (Light light, SerializedProperty useIESMaximumIntensityProp, SerializedProperty iesMaximumIntensityUnitProp, SerializedProperty iesMaximumIntensityProp)
+ {
+ SetupRenderPipelinePreviewLightIntensity(light, useIESMaximumIntensityProp, iesMaximumIntensityUnitProp, iesMaximumIntensityProp);
+ });
+ }
+
+ ///
+ /// Call back for ScriptedImporterEditor
+ ///
+ public override void OnDisable()
+ {
+ base.OnDisable();
+
+ iesImporterEditor.CommonOnDisable();
+ }
+ }
+}
diff --git a/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporterEditor.cs.meta b/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporterEditor.cs.meta
new file mode 100644
index 00000000000..b5924936b8c
--- /dev/null
+++ b/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporterEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c5d8bf4b18b15bb49a5754a5f1ffcd2d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightUI.Skin.cs b/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightUI.Skin.cs
index a1dc34876e9..22d5faaf2b7 100644
--- a/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightUI.Skin.cs
+++ b/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightUI.Skin.cs
@@ -39,12 +39,12 @@ sealed class Styles
public readonly GUIContent colorFilter = new GUIContent("Filter", "Specifies a color which tints the Light source.");
public readonly GUIContent colorTemperature = new GUIContent("Temperature", "Specifies a temperature (in Kelvin) HDRP uses to correlate a color for the Light. For reference, White is 6500K.");
public readonly GUIContent areaLightCookie = new GUIContent("Cookie", "Cookie mask currently assigned to the area light.");
+ public readonly GUIContent iesTexture = new GUIContent("IES Profile", "IES Profile (Support: Point, Spot, Rectangular-Area Lights).");
public readonly GUIContent cookieTextureTypeError = new GUIContent("HDRP does not support the Cookie Texture type, only Default is supported.", EditorGUIUtility.IconContent("console.warnicon").image);
public readonly string cookieNonPOT = "HDRP does not support non power of two cookie textures.";
public readonly string cookieTooSmall = "Min texture size for cookies is 2x2 pixels.";
public readonly string cookieBaking = "Light Baking for cookies disabled on the Project Settings.";
-
// Additional light data
public readonly GUIContent directionalIntensity = new GUIContent("Intensity (Lux)", "Illuminance of the Directional Light, at ground level, in lux.");
public readonly GUIContent punctualIntensity = new GUIContent("Intensity (Lumen)", "Luminous power of the Light in lumen.");
@@ -61,6 +61,7 @@ sealed class Styles
public readonly GUIContent lightDimmer = new GUIContent("Intensity Multiplier", "Multiplies the intensity of the Light by the given number. This is useful for modifying the intensity of multiple Lights simultaneously without needing know the intensity of each Light.");
public readonly GUIContent fadeDistance = new GUIContent("Fade Distance", "The distance at which light smoothly fades out before HDRP culls it completely. This minimizes popping.");
public readonly GUIContent spotInnerPercent = new GUIContent("Inner Angle (%)", "Controls size of the angular attenuation, in percent, of the base angle of the Spot Light's cone.");
+ public readonly GUIContent spotIESCutoffPercent = new GUIContent("IES Cutoff Angle (%)", "Cutoff the IES Light in percent, of the base angle of the Spot Light's cone.");
public readonly GUIContent spotLightShape = new GUIContent("Shape", "The shape of the Spot Light. Impacts the the cookie transformation and the Light's angular attenuation.");
public readonly GUIContent areaLightShape = new GUIContent("Shape", "The shape of the Area Light. Note that some are Realtime only and some Baked only.");
public readonly GUIContent[] areaShapeNames =
diff --git a/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightUI.cs b/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightUI.cs
index c6d08511ad1..e923e9e3198 100644
--- a/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightUI.cs
+++ b/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightUI.cs
@@ -611,7 +611,7 @@ static void DrawLightIntensityGUILayout(SerializedHDLight serialized, Editor own
}
EditorGUI.EndProperty();
EditorGUI.EndProperty();
-
+
EditorGUI.PropertyField(valueRect, serialized.intensity, s_Styles.empty);
DrawLightIntensityUnitPopup(unitRect, serialized, owner);
@@ -715,10 +715,57 @@ static void DrawEmissionContent(SerializedHDLight serialized, Editor owner)
}
else if (serialized.areaLightShape == AreaLightShape.Rectangle || serialized.areaLightShape == AreaLightShape.Disc)
{
- EditorGUILayout.ObjectField( serialized.areaLightCookie, s_Styles.areaLightCookie );
+ EditorGUILayout.ObjectField(serialized.areaLightCookie, s_Styles.areaLightCookie);
ShowCookieTextureWarnings(serialized.areaLightCookie.objectReferenceValue as Texture, serialized.settings.isCompletelyBaked || serialized.settings.isBakedOrMixed);
}
+ if (serialized.type == HDLightType.Point || serialized.type == HDLightType.Spot || (serialized.type == HDLightType.Area && serialized.areaLightShape == AreaLightShape.Rectangle))
+ {
+ EditorGUI.BeginChangeCheck();
+ UnityEngine.Object iesAsset = EditorGUILayout.ObjectField(
+ s_Styles.iesTexture,
+ serialized.type == HDLightType.Point ? serialized.iesPoint.objectReferenceValue : serialized.iesSpot.objectReferenceValue,
+ typeof(IESObject), false);
+ if (EditorGUI.EndChangeCheck())
+ {
+ SerializedProperty pointTex = serialized.iesPoint;
+ SerializedProperty spotTex = serialized.iesSpot;
+ if (iesAsset == null)
+ {
+ pointTex.objectReferenceValue = null;
+ spotTex .objectReferenceValue = null;
+ }
+ else
+ {
+ string guid;
+ long localID;
+ AssetDatabase.TryGetGUIDAndLocalFileIdentifier(iesAsset, out guid, out localID);
+ string path = AssetDatabase.GUIDToAssetPath(guid);
+ UnityEngine.Object[] textures = AssetDatabase.LoadAllAssetRepresentationsAtPath(path);
+ foreach (var subAsset in textures)
+ {
+ if (AssetDatabase.IsSubAsset(subAsset) && subAsset.name.EndsWith("-Cube-IES"))
+ {
+ pointTex.objectReferenceValue = subAsset;
+ }
+ else if (AssetDatabase.IsSubAsset(subAsset) && subAsset.name.EndsWith("-2D-IES"))
+ {
+ spotTex.objectReferenceValue = subAsset;
+ }
+ }
+ }
+ serialized.iesPoint.serializedObject.ApplyModifiedProperties();
+ serialized.iesSpot .serializedObject.ApplyModifiedProperties();
+ }
+ }
+
+ if (serialized.type == HDLightType.Spot &&
+ serialized.spotLightShape.enumValueIndex == (int)SpotLightShape.Cone &&
+ serialized.iesSpot.objectReferenceValue != null)
+ {
+ EditorGUILayout.PropertyField(serialized.spotIESCutoffPercent, s_Styles.spotIESCutoffPercent);
+ }
+
if (EditorGUI.EndChangeCheck())
{
serialized.needUpdateAreaLightEmissiveMeshComponents = true;
diff --git a/com.unity.render-pipelines.high-definition/Editor/Lighting/SerializedHDLight.cs b/com.unity.render-pipelines.high-definition/Editor/Lighting/SerializedHDLight.cs
index 10d310391e7..de2021cc109 100644
--- a/com.unity.render-pipelines.high-definition/Editor/Lighting/SerializedHDLight.cs
+++ b/com.unity.render-pipelines.high-definition/Editor/Lighting/SerializedHDLight.cs
@@ -11,6 +11,7 @@ internal class SerializedHDLight
public SerializedProperty enableSpotReflector;
public SerializedProperty luxAtDistance;
public SerializedProperty spotInnerPercent;
+ public SerializedProperty spotIESCutoffPercent;
public SerializedProperty lightDimmer;
public SerializedProperty fadeDistance;
public SerializedProperty affectDiffuse;
@@ -40,7 +41,9 @@ internal class SerializedHDLight
public SerializedProperty filterSampleCount;
public SerializedProperty minFilterSize;
public SerializedProperty scaleForSoftness;
- public SerializedProperty areaLightCookie; // We can't use default light cookies because the cookie gets reset by some safety measure on C++ side... :/
+ public SerializedProperty areaLightCookie; // We can't use default light cookies because the cookie gets reset by some safety measure on C++ side... :/
+ public SerializedProperty iesPoint;
+ public SerializedProperty iesSpot;
public SerializedProperty areaLightShadowCone;
public SerializedProperty useCustomSpotLightShadowCone;
public SerializedProperty customSpotLightShadowCone;
@@ -92,7 +95,7 @@ internal class SerializedHDLight
public SerializedProperty penumbraTint;
public SerializedProperty shadowUpdateMode;
public SerializedScalableSettingValue shadowResolution;
-
+
// Bias control
public SerializedProperty slopeBias;
public SerializedProperty normalBias;
@@ -286,10 +289,10 @@ public void UpdateAreaLightEmissiveMeshCastShadow(UnityEngine.Rendering.ShadowCa
areaLightEmissiveMeshCastShadow.intValue = (int)shadowCastingMode;
if (deportedAreaLightEmissiveMeshCastShadow != null) //only possible while editing from prefab
deportedAreaLightEmissiveMeshCastShadow.intValue = (int)shadowCastingMode;
-
+
}
}
-
+
public enum MotionVector
{
CameraMotionOnly = MotionVectorGenerationMode.Camera,
@@ -328,6 +331,7 @@ public SerializedHDLight(HDAdditionalLightData[] lightDatas, LightEditor.Setting
enableSpotReflector = o.Find("m_EnableSpotReflector");
luxAtDistance = o.Find("m_LuxAtDistance");
spotInnerPercent = o.Find("m_InnerSpotPercent");
+ spotIESCutoffPercent = o.Find("m_SpotIESCutoffPercent");
lightDimmer = o.Find("m_LightDimmer");
volumetricDimmer = o.Find("m_VolumetricDimmer");
lightUnit = o.Find("m_LightUnit");
@@ -351,6 +355,8 @@ public SerializedHDLight(HDAdditionalLightData[] lightDatas, LightEditor.Setting
minFilterSize = o.Find("m_MinFilterSize");
scaleForSoftness = o.Find("m_SoftnessScale");
areaLightCookie = o.Find("m_AreaLightCookie");
+ iesPoint = o.Find("m_IESPoint");
+ iesSpot = o.Find("m_IESSpot");
areaLightShadowCone = o.Find("m_AreaLightShadowCone");
useCustomSpotLightShadowCone = o.Find("m_UseCustomSpotLightShadowCone");
customSpotLightShadowCone = o.Find("m_CustomSpotLightShadowCone");
diff --git a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs
index 5522674d37b..d5aed268be2 100644
--- a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs
+++ b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs
@@ -234,26 +234,6 @@ static void Drawer_SectionCookies(SerializedHDRenderPipelineAsset serialized, Ed
EditorGUILayout.PropertyField(serialized.renderPipelineSettings.lightLoopSettings.cookieFormat, Styles.cookieAtlasFormatContent);
EditorGUILayout.PropertyField(serialized.renderPipelineSettings.lightLoopSettings.pointCookieSize, Styles.pointCoockieSizeContent);
EditorGUI.BeginChangeCheck();
- EditorGUILayout.DelayedIntField(serialized.renderPipelineSettings.lightLoopSettings.cubeCookieTexArraySize, Styles.pointCookieTextureArraySizeContent);
- if (EditorGUI.EndChangeCheck())
- serialized.renderPipelineSettings.lightLoopSettings.cubeCookieTexArraySize.intValue = Mathf.Clamp(serialized.renderPipelineSettings.lightLoopSettings.cubeCookieTexArraySize.intValue, 1, TextureCache.k_MaxSupported);
- if (serialized.renderPipelineSettings.lightLoopSettings.cubeCookieTexArraySize.hasMultipleDifferentValues)
- EditorGUILayout.HelpBox(Styles.multipleDifferenteValueMessage, MessageType.Info);
- else
- {
- long currentCache = TextureCacheCubemap.GetApproxCacheSizeInByte(serialized.renderPipelineSettings.lightLoopSettings.cubeCookieTexArraySize.intValue, serialized.renderPipelineSettings.lightLoopSettings.pointCookieSize.intValue, 1);
- if (currentCache > HDRenderPipeline.k_MaxCacheSize)
- {
- int reserved = TextureCacheCubemap.GetMaxCacheSizeForWeightInByte(HDRenderPipeline.k_MaxCacheSize, serialized.renderPipelineSettings.lightLoopSettings.pointCookieSize.intValue, 1);
- string message = string.Format(Styles.cacheErrorFormat, HDEditorUtils.HumanizeWeight(currentCache), reserved);
- EditorGUILayout.HelpBox(message, MessageType.Error);
- }
- else
- {
- string message = string.Format(Styles.cacheInfoFormat, HDEditorUtils.HumanizeWeight(currentCache));
- EditorGUILayout.HelpBox(message, MessageType.Info);
- }
- }
}
static void Drawer_SectionReflection(SerializedHDRenderPipelineAsset serialized, Editor owner)
diff --git a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/SerializedGlobalLightLoopSettings.cs b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/SerializedGlobalLightLoopSettings.cs
index c9f717fe145..6584196057e 100644
--- a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/SerializedGlobalLightLoopSettings.cs
+++ b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/SerializedGlobalLightLoopSettings.cs
@@ -11,7 +11,6 @@ class SerializedGlobalLightLoopSettings
public SerializedProperty cookieFormat;
public SerializedProperty cookieAtlasLastValidMip;
public SerializedProperty pointCookieSize;
- public SerializedProperty cubeCookieTexArraySize;
public SerializedProperty reflectionProbeCacheSize;
public SerializedProperty reflectionCubemapSize;
public SerializedProperty reflectionCacheCompressed;
@@ -22,7 +21,7 @@ class SerializedGlobalLightLoopSettings
public SerializedProperty supportFabricConvolution;
public SerializedProperty maxDirectionalLightsOnScreen;
public SerializedProperty maxPunctualLightsOnScreen;
- public SerializedProperty maxAreaLightsOnScreen;
+ public SerializedProperty maxAreaLightsOnScreen;
public SerializedProperty maxEnvLightsOnScreen;
public SerializedProperty maxDecalsOnScreen;
public SerializedProperty maxPlanarReflectionOnScreen;
@@ -35,7 +34,6 @@ public SerializedGlobalLightLoopSettings(SerializedProperty root)
cookieFormat = root.Find((GlobalLightLoopSettings s) => s.cookieFormat);
cookieAtlasLastValidMip = root.Find((GlobalLightLoopSettings s) => s.cookieAtlasLastValidMip);
pointCookieSize = root.Find((GlobalLightLoopSettings s) => s.pointCookieSize);
- cubeCookieTexArraySize = root.Find((GlobalLightLoopSettings s) => s.cubeCookieTexArraySize);
reflectionProbeCacheSize = root.Find((GlobalLightLoopSettings s) => s.reflectionProbeCacheSize);
reflectionCubemapSize = root.Find((GlobalLightLoopSettings s) => s.reflectionCubemapSize);
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs
index 3d9c378d267..1d4f00de3b2 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs
@@ -1229,18 +1229,6 @@ void RegisterLightingDebug()
});
}
- list.Add(new DebugUI.BoolField { displayName = "Display Point Light Cookie Array", getter = () => data.lightingDebugSettings.displayCookieCubeArray, setter = value => data.lightingDebugSettings.displayCookieCubeArray = value, onValueChanged = RefreshLightingDebug});
- if (data.lightingDebugSettings.displayCookieCubeArray)
- {
- list.Add(new DebugUI.Container
- {
- children =
- {
- new DebugUI.UIntField { displayName = "Slice Index", getter = () => data.lightingDebugSettings.cookieCubeArraySliceIndex, setter = value => data.lightingDebugSettings.cookieCubeArraySliceIndex = value, min = () => 0, max = () => (uint)(RenderPipelineManager.currentPipeline as HDRenderPipeline).GetCookieCubeArraySize() - 1},
- }
- });
- }
-
list.Add(new DebugUI.BoolField { displayName = "Display Planar Reflection Atlas", getter = () => data.lightingDebugSettings.displayPlanarReflectionProbeAtlas, setter = value => data.lightingDebugSettings.displayPlanarReflectionProbeAtlas = value, onValueChanged = RefreshLightingDebug});
if (data.lightingDebugSettings.displayPlanarReflectionProbeAtlas)
{
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs b/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs
index 02a048b822e..89d8812e501 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs
@@ -328,8 +328,8 @@ public bool IsDebugDisplayEnabled()
public bool displayCookieAtlas = false;
/// Display the light cookies cubemap array.
public bool displayCookieCubeArray = false;
- /// Index of the light cookie cubemap to display.
- public uint cookieCubeArraySliceIndex = 0;
+ /// Index of the light cubemap to display.
+ public uint cubeArraySliceIndex = 0;
/// Mip level of the cookie cubemap display.
public uint cookieAtlasMipLevel = 0;
/// Clear cookie atlas each frame.
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/GlobalIlluminationUtils.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/GlobalIlluminationUtils.cs
index 97aa015afac..a0a581772d1 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/GlobalIlluminationUtils.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/GlobalIlluminationUtils.cs
@@ -114,6 +114,12 @@ public static bool LightDataGIExtract(Light light, ref LightDataGI lightDataGI)
spot.angularFalloff = AngularFalloffType.AnalyticAndInnerAngle;
lightDataGI.Init(ref spot, ref cookie);
lightDataGI.shape1 = (float)AngularFalloffType.AnalyticAndInnerAngle;
+ if (light.cookie != null)
+ lightDataGI.cookieID = light.cookie.GetInstanceID();
+ else if (add.IESSpot != null)
+ lightDataGI.cookieID = add.IESSpot.GetInstanceID();
+ else
+ lightDataGI.cookieID = 0;
}
break;
@@ -132,6 +138,12 @@ public static bool LightDataGIExtract(Light light, ref LightDataGI lightDataGI)
pyramid.aspectRatio = add.aspectRatio;
pyramid.falloff = add.applyRangeAttenuation ? FalloffType.InverseSquared : FalloffType.InverseSquaredNoRangeAttenuation;
lightDataGI.Init(ref pyramid, ref cookie);
+ if (light.cookie != null)
+ lightDataGI.cookieID = light.cookie.GetInstanceID();
+ else if (add.IESSpot != null)
+ lightDataGI.cookieID = add.IESSpot.GetInstanceID();
+ else
+ lightDataGI.cookieID = 0;
}
break;
@@ -149,6 +161,12 @@ public static bool LightDataGIExtract(Light light, ref LightDataGI lightDataGI)
box.width = add.shapeWidth;
box.height = add.shapeHeight;
lightDataGI.Init(ref box, ref cookie);
+ if (light.cookie != null)
+ lightDataGI.cookieID = light.cookie.GetInstanceID();
+ else if (add.IESSpot != null)
+ lightDataGI.cookieID = add.IESSpot.GetInstanceID();
+ else
+ lightDataGI.cookieID = 0;
}
break;
@@ -194,7 +212,12 @@ public static bool LightDataGIExtract(Light light, ref LightDataGI lightDataGI)
// TEMP: for now, if we bake a rectangle type this will disable the light for runtime, need to speak with GI team about it!
lightDataGI.type = UnityEngine.Experimental.GlobalIllumination.LightType.Rectangle;
lightDataGI.falloff = add.applyRangeAttenuation ? FalloffType.InverseSquared : FalloffType.InverseSquaredNoRangeAttenuation;
- lightDataGI.cookieID = add.areaLightCookie ? add.areaLightCookie.GetInstanceID() : 0;
+ if (add.areaLightCookie != null)
+ lightDataGI.cookieID = add.areaLightCookie.GetInstanceID();
+ else if (add.IESSpot != null)
+ lightDataGI.cookieID = add.IESSpot.GetInstanceID();
+ else
+ lightDataGI.cookieID = 0;
break;
case AreaLightShape.Tube:
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/Light/HDAdditionalLightData.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/Light/HDAdditionalLightData.cs
index 0c8f8dec753..7577e93ad39 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/Light/HDAdditionalLightData.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/Light/HDAdditionalLightData.cs
@@ -198,11 +198,35 @@ public float innerSpotPercent
///
public float innerSpotPercent01 => innerSpotPercent / 100f;
+
+ [Range(k_MinSpotInnerPercent, k_MaxSpotInnerPercent)]
+ [SerializeField]
+ float m_SpotIESCutoffPercent = 100.0f; // To display this field in the UI this need to be public
+ ///
+ /// Get/Set the spot ies cutoff.
+ ///
+ public float spotIESCutoffPercent
+ {
+ get => m_SpotIESCutoffPercent;
+ set
+ {
+ if (m_SpotIESCutoffPercent == value)
+ return;
+
+ m_SpotIESCutoffPercent = Mathf.Clamp(value, k_MinSpotInnerPercent, k_MaxSpotInnerPercent);
+ }
+ }
+
+ ///
+ /// Get the inner spot radius between 0 and 1.
+ ///
+ public float spotIESCutoffPercent01 => spotIESCutoffPercent/100f;
+
[Range(0.0f, 16.0f)]
[SerializeField, FormerlySerializedAs("lightDimmer")]
float m_LightDimmer = 1.0f;
///
- /// Get/Set the light dimmer / multiplier, between 0 and 16.
+ /// Get/Set the light dimmer / multiplier, between 0 and 16.
///
public float lightDimmer
{
@@ -547,6 +571,56 @@ public Texture areaLightCookie
}
}
+
+ // Optional IES (Cubemap for PointLight)
+ [SerializeField]
+ internal Texture m_IESPoint;
+ // Optional IES (2D Square texture for Spot or rectangular light)
+ [SerializeField]
+ internal Texture m_IESSpot;
+
+ ///
+ /// Get/Set IES texture for Point
+ ///
+ internal Texture IESPoint
+ {
+ get => m_IESPoint;
+ set
+ {
+ if (value.dimension == TextureDimension.Cube)
+ {
+ m_IESPoint = value;
+ UpdateAllLightValues();
+ }
+ else
+ {
+ Debug.LogError("Texture dimension " + value.dimension + " is not supported for point lights.");
+ m_IESPoint = null;
+ }
+ }
+ }
+
+ ///
+ /// Get/Set IES texture for Spot or rectangular light.
+ ///
+ internal Texture IESSpot
+ {
+ get => m_IESSpot;
+ set
+ {
+ if (value.dimension == TextureDimension.Tex2D && value.width == value.height)
+ {
+ m_IESSpot = value;
+ UpdateAllLightValues();
+ }
+ else
+ {
+ Debug.LogError("Texture dimension " + value.dimension + " is not supported for spot lights or rectangular light (only square images).");
+ m_IESSpot = null;
+ }
+ }
+ }
+
[Range(k_MinAreaLightShadowCone, k_MaxAreaLightShadowCone)]
[SerializeField, FormerlySerializedAs("areaLightShadowCone")]
float m_AreaLightShadowCone = 120.0f;
@@ -1404,7 +1478,7 @@ public bool preserveCachedShadow
}
///
- /// True if the light affects volumetric fog, false otherwise
+ /// True if the light affects volumetric fog, false otherwise
///
public bool affectsVolumetric
{
@@ -1595,7 +1669,7 @@ void DestroyChildEmissiveMeshViewer()
CoreUtils.Destroy(m_ChildEmissiveMeshViewer);
m_ChildEmissiveMeshViewer = null;
}
-
+
[SerializeField]
ShadowCastingMode m_AreaLightEmissiveMeshShadowCastingMode = ShadowCastingMode.Off;
[SerializeField]
@@ -1664,7 +1738,7 @@ void OnDestroy()
void OnDisable()
{
// If it is within the cached system we need to evict it, unless user explicitly requires not to.
- if (!preserveCachedShadow && lightIdxForCachedShadows >= 0)
+ if (!preserveCachedShadow && lightIdxForCachedShadows >= 0)
{
HDShadowManager.cachedShadowManager.EvictLight(this);
}
@@ -2009,7 +2083,7 @@ internal int UpdateShadowRequest(HDCamera hdCamera, HDShadowManager manager, HDS
if(shadowIsInCachedSystem && shadowNeedsRendering)
{
// Handshake with the cached shadow manager to notify about the rendering.
- // Technically the rendering has not happened yet, but it is scheduled.
+ // Technically the rendering has not happened yet, but it is scheduled.
HDShadowManager.cachedShadowManager.MarkShadowAsRendered(cachedShadowID, shadowMapType);
}
@@ -2246,7 +2320,7 @@ void LateUpdate()
&& m_ChildEmissiveMeshViewer != null && !m_ChildEmissiveMeshViewer.Equals(null)
&& m_ChildEmissiveMeshViewer.gameObject.layer != gameObject.layer)
m_ChildEmissiveMeshViewer.gameObject.layer = gameObject.layer;
-
+
// Delayed cleanup when removing emissive mesh from timeline
if (needRefreshEmissiveMeshesFromTimeLineUpdate)
{
@@ -2306,7 +2380,7 @@ void LateUpdate()
timelineWorkaround.oldLightColorTemperature = legacyLight.colorTemperature;
}
}
-
+
void OnDidApplyAnimationProperties()
{
UpdateAllLightValues(fromTimeLine: true);
@@ -2520,7 +2594,7 @@ void UpdateLightIntensity()
legacyLight.SetLightDirty(); // Should be apply only to parameter that's affect GI, but make the code cleaner
#endif
}
-
+
void Awake()
{
Migrate();
@@ -2645,9 +2719,23 @@ internal void UpdateAreaLightEmissiveMesh(bool fromTimeLine = false)
emissiveMeshRenderer.sharedMaterial.SetColor("_EmissiveColor", value);
+ bool enableEmissiveColorMap = false;
// Set the cookie (if there is one) and raise or remove the shader feature
- emissiveMeshRenderer.sharedMaterial.SetTexture("_EmissiveColorMap", areaLightCookie);
- CoreUtils.SetKeyword(emissiveMeshRenderer.sharedMaterial, "_EMISSIVE_COLOR_MAP", areaLightCookie != null);
+ if (displayEmissiveMesh && areaLightCookie != null && areaLightCookie != Texture2D.whiteTexture)
+ {
+ emissiveMeshRenderer.sharedMaterial.SetTexture("_EmissiveColorMap", areaLightCookie);
+ enableEmissiveColorMap = true;
+ }
+ else if (displayEmissiveMesh && IESSpot != null && IESSpot != Texture2D.whiteTexture)
+ {
+ emissiveMeshRenderer.sharedMaterial.SetTexture("_EmissiveColorMap", IESSpot);
+ enableEmissiveColorMap = true;
+ }
+ else
+ {
+ emissiveMeshRenderer.sharedMaterial.SetTexture("_EmissiveColorMap", Texture2D.whiteTexture);
+ }
+ CoreUtils.SetKeyword(emissiveMeshRenderer.sharedMaterial, "_EMISSIVE_COLOR_MAP", enableEmissiveColorMap);
}
void UpdateRectangleLightBounds()
@@ -2942,7 +3030,7 @@ public void SetShadowResolutionOverride(bool useOverride)
shadowResolution.useOverride = useOverride;
RefreshCachedShadow();
}
- }
+ }
///
/// Set the near plane of the shadow.
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightCookieManager.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightCookieManager.cs
index 0ae105ff725..5832815bcf2 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightCookieManager.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightCookieManager.cs
@@ -1,3 +1,4 @@
+using System.Collections.Generic;
using UnityEngine.Experimental.Rendering;
namespace UnityEngine.Rendering.HighDefinition
@@ -19,6 +20,7 @@ class LightCookieManager
HDRenderPipelineAsset m_RenderPipelineAsset = null;
internal static readonly int s_texSource = Shader.PropertyToID("_SourceTexture");
+ internal static readonly int s_texCubeSource = Shader.PropertyToID("_SourceCubeTexture");
internal static readonly int s_sourceMipLevel = Shader.PropertyToID("_SourceMipLevel");
internal static readonly int s_sourceSize = Shader.PropertyToID("_SourceSize");
internal static readonly int s_uvLimits = Shader.PropertyToID("_UVLimits");
@@ -28,16 +30,14 @@ class LightCookieManager
readonly Material m_MaterialFilterAreaLights;
MaterialPropertyBlock m_MPBFilterAreaLights = new MaterialPropertyBlock();
- readonly Material m_CubeToPanoMaterial;
-
RenderTexture m_TempRenderTexture0 = null;
RenderTexture m_TempRenderTexture1 = null;
// Structure for cookies used by directional and spotlights
PowerOfTwoTextureAtlas m_CookieAtlas;
- // Structure for cookies used by point lights
- TextureCacheCubemap m_CubeCookieTexArray;
+ int m_CookieCubeResolution;
+
// During the light loop, when reserving space for the cookies (first part of the light loop) the atlas
// can run out of space, in this case, we set to true this flag which will trigger a re-layouting of the
// atlas (sort entries by size and insert them again).
@@ -58,27 +58,17 @@ public LightCookieManager(HDRenderPipelineAsset hdAsset, int maxCacheSize)
// Also make sure to create the engine material that is used for the filtering
m_MaterialFilterAreaLights = CoreUtils.CreateEngineMaterial(hdResources.shaders.filterAreaLightCookiesPS);
- int cookieCubeSize = gLightLoopSettings.cubeCookieTexArraySize;
int cookieAtlasSize = (int)gLightLoopSettings.cookieAtlasSize;
cookieFormat = (GraphicsFormat)gLightLoopSettings.cookieFormat;
cookieAtlasLastValidMip = gLightLoopSettings.cookieAtlasLastValidMip;
m_CookieAtlas = new PowerOfTwoTextureAtlas(cookieAtlasSize, gLightLoopSettings.cookieAtlasLastValidMip, cookieFormat, name: "Cookie Atlas (Punctual Lights)", useMipMap: true);
- m_CubeToPanoMaterial = CoreUtils.CreateEngineMaterial(hdResources.shaders.cubeToPanoPS);
-
- m_CubeCookieTexArray = new TextureCacheCubemap("Cookie");
- int cookieCubeResolution = (int)gLightLoopSettings.pointCookieSize;
- if (TextureCacheCubemap.GetApproxCacheSizeInByte(cookieCubeSize, cookieCubeResolution, 1) > HDRenderPipeline.k_MaxCacheSize)
- cookieCubeSize = TextureCacheCubemap.GetMaxCacheSizeForWeightInByte(HDRenderPipeline.k_MaxCacheSize, cookieCubeResolution, 1);
-
- // For now the cubemap cookie array format is hardcoded to R8G8B8A8 SRGB.
- m_CubeCookieTexArray.AllocTextureArray(cookieCubeSize, cookieCubeResolution, cookieFormat, true, m_CubeToPanoMaterial);
+ m_CookieCubeResolution = (int)gLightLoopSettings.pointCookieSize;
}
public void NewFrame()
{
- m_CubeCookieTexArray.NewFrame();
m_CookieAtlas.ResetRequestedTexture();
m_2DCookieAtlasNeedsLayouting = false;
m_NoMoreSpace = false;
@@ -87,7 +77,6 @@ public void NewFrame()
public void Release()
{
CoreUtils.Destroy(m_MaterialFilterAreaLights);
- CoreUtils.Destroy(m_CubeToPanoMaterial);
if(m_TempRenderTexture0 != null)
{
@@ -105,31 +94,17 @@ public void Release()
m_CookieAtlas.Release();
m_CookieAtlas = null;
}
- if (m_CubeCookieTexArray != null)
- {
- m_CubeCookieTexArray.Release();
- m_CubeCookieTexArray = null;
- }
}
- Texture FilterAreaLightTexture(CommandBuffer cmd, Texture source)
+ void ReserveTempTextureIfNeeded(CommandBuffer cmd, int mipMapCount)
{
- if (m_MaterialFilterAreaLights == null)
- {
- Debug.LogError("FilterAreaLightTexture has an invalid shader. Can't filter area light cookie.");
- return null;
- }
-
- // TODO: we don't need to allocate two temp RT, we can use the atlas as temp render texture
- // it will avoid additional copy of the whole mip chain into the atlas.
- int sourceWidth = m_CookieAtlas.AtlasTexture.rt.width;
- int sourceHeight = m_CookieAtlas.AtlasTexture.rt.height;
- int viewportWidth = source.width;
- int viewportHeight = source.height;
- int mipMapCount = 1 + Mathf.FloorToInt(Mathf.Log(Mathf.Max(source.width, source.height), 2));
-
if (m_TempRenderTexture0 == null)
{
+ // TODO: we don't need to allocate two temp RT, we can use the atlas as temp render texture
+ // it will avoid additional copy of the whole mip chain into the atlas.
+ int sourceWidth = m_CookieAtlas.AtlasTexture.rt.width;
+ int sourceHeight = m_CookieAtlas.AtlasTexture.rt.height;
+
string cacheName = m_CookieAtlas.AtlasTexture.name;
m_TempRenderTexture0 = new RenderTexture(sourceWidth, sourceHeight, 1, cookieFormat)
{
@@ -163,14 +138,41 @@ Texture FilterAreaLightTexture(CommandBuffer cmd, Texture source)
}
}
+ }
+
+ Texture FilterAreaLightTexture(CommandBuffer cmd, Texture source, int finalWidth, int finalHeight)
+ {
+ if (m_MaterialFilterAreaLights == null)
+ {
+ Debug.LogError("FilterAreaLightTexture has an invalid shader. Can't filter area light cookie.");
+ return null;
+ }
+
+ int sourceWidth = m_CookieAtlas.AtlasTexture.rt.width;
+ int sourceHeight = m_CookieAtlas.AtlasTexture.rt.height;
+ int viewportWidth = finalWidth;// source.width;
+ int viewportHeight = finalHeight;// source.height;
+ int mipMapCount = 1 + Mathf.FloorToInt(Mathf.Log(Mathf.Max(source.width, source.height), 2));
+
+ ReserveTempTextureIfNeeded(cmd, mipMapCount);
using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.AreaLightCookieConvolution)))
{
int targetWidth = sourceWidth;
int targetHeight = sourceHeight;
- // Start by copying the source texture to the array slice's mip 0
+ if (source.dimension == TextureDimension.Cube)
+ {
+ m_MPBFilterAreaLights.SetInt(s_sourceMipLevel, 0);
+ m_MPBFilterAreaLights.SetTexture(s_texCubeSource, source);
+
+ cmd.SetRenderTarget(m_TempRenderTexture0, 0);
+ cmd.SetViewport(new Rect(0, 0, viewportWidth, viewportHeight));
+ cmd.DrawProcedural(Matrix4x4.identity, m_MaterialFilterAreaLights, 3, MeshTopology.Triangles, 3, 1, m_MPBFilterAreaLights);
+ }
+ else
{
+ // Start by copying the source texture to the array slice's mip 0
m_MPBFilterAreaLights.SetInt(s_sourceMipLevel, 0);
m_MPBFilterAreaLights.SetTexture(s_texSource, source);
@@ -188,7 +190,7 @@ Texture FilterAreaLightTexture(CommandBuffer cmd, Texture source)
Vector4 uvLimits = new Vector4(0, 0, viewportWidth / (float)sourceWidth, viewportHeight / (float)sourceHeight);
viewportWidth = Mathf.Max(1, viewportWidth >> 1);
- targetWidth = Mathf.Max(1, targetWidth >> 1);
+ targetWidth = Mathf.Max(1, targetWidth >> 1);
m_MPBFilterAreaLights.SetTexture(s_texSource, m_TempRenderTexture0);
m_MPBFilterAreaLights.SetInt(s_sourceMipLevel, mipIndex - 1);
@@ -238,13 +240,33 @@ public void LayoutIfNeeded()
}
}
+ public Vector4 Fetch2DCookie(CommandBuffer cmd, Texture cookie, Texture ies)
+ {
+ int width = (int)Mathf.Max(cookie.width, ies.height);
+ int height = (int)Mathf.Max(cookie.width, ies.height);
+
+ if (width < k_MinCookieSize || height < k_MinCookieSize)
+ return Vector4.zero;
+
+ if (!m_CookieAtlas.IsCached(out var scaleBias, m_CookieAtlas.GetTextureID(cookie, ies)) && !m_NoMoreSpace)
+ Debug.LogError($"Unity cannot fetch the 2D Light cookie texture: {cookie} because it is not on the cookie atlas. To resolve this, open your HDRP Asset and increase the resolution of the cookie atlas.");
+
+ if (m_CookieAtlas.NeedsUpdate(cookie, ies, false))
+ {
+ m_CookieAtlas.BlitTexture(cmd, scaleBias, ies, new Vector4(1, 1, 0, 0), blitMips: false, overrideInstanceID: m_CookieAtlas.GetTextureID(cookie, ies));
+ m_CookieAtlas.BlitTextureMultiply(cmd, scaleBias, cookie, new Vector4(1, 1, 0, 0), blitMips: false, overrideInstanceID: m_CookieAtlas.GetTextureID(cookie, ies));
+ }
+
+ return scaleBias;
+ }
+
public Vector4 Fetch2DCookie(CommandBuffer cmd, Texture cookie)
{
if (cookie.width < k_MinCookieSize || cookie.height < k_MinCookieSize)
return Vector4.zero;
- if (!m_CookieAtlas.IsCached(out var scaleBias, cookie) && !m_NoMoreSpace)
- Debug.LogError($"2D Light cookie texture {cookie} can't be fetched without having reserved. You can try to increase the cookie atlas resolution in the HDRP settings.");
+ if (!m_CookieAtlas.IsCached(out var scaleBias, m_CookieAtlas.GetTextureID(cookie)) && !m_NoMoreSpace)
+ Debug.LogError($"Unity cannot fetch the 2D Light cookie texture: {cookie} because it is not on the cookie atlas. To resolve this, open your HDRP Asset and increase the resolution of the cookie atlas.");
if (m_CookieAtlas.NeedsUpdate(cookie, false))
m_CookieAtlas.BlitTexture(cmd, scaleBias, cookie, new Vector4(1, 1, 0, 0), blitMips: false);
@@ -260,17 +282,61 @@ public Vector4 FetchAreaCookie(CommandBuffer cmd, Texture cookie)
if (!m_CookieAtlas.IsCached(out var scaleBias, cookie) && !m_NoMoreSpace)
Debug.LogError($"Area Light cookie texture {cookie} can't be fetched without having reserved. You can try to increase the cookie atlas resolution in the HDRP settings.");
+ int currentID = m_CookieAtlas.GetTextureID(cookie);
+ //RTHandle existingTexture;
if (m_CookieAtlas.NeedsUpdate(cookie, true))
{
// Generate the mips
- Texture filteredAreaLight = FilterAreaLightTexture(cmd, cookie);
+ Texture filteredAreaLight = FilterAreaLightTexture(cmd, cookie, cookie.width, cookie.height);
Vector4 sourceScaleOffset = new Vector4(cookie.width / (float)atlasTexture.rt.width, cookie.height / (float)atlasTexture.rt.height, 0, 0);
- m_CookieAtlas.BlitTexture(cmd, scaleBias, filteredAreaLight, sourceScaleOffset, blitMips: true, overrideInstanceID: cookie.GetInstanceID());
+ m_CookieAtlas.BlitTexture(cmd, scaleBias, filteredAreaLight, sourceScaleOffset, blitMips: true, overrideInstanceID: currentID);
+ }
+
+ return scaleBias;
+ }
+
+ public Vector4 FetchAreaCookie(CommandBuffer cmd, Texture cookie, Texture ies)
+ {
+ int width = (int)Mathf.Max(cookie.width, ies.height);
+ int height = (int)Mathf.Max(cookie.width, ies.height);
+
+ if (width < k_MinCookieSize || height < k_MinCookieSize)
+ return Vector4.zero;
+
+ int projectionSize = 2*(int)Mathf.Max((float)m_CookieCubeResolution, Mathf.Max((float)cookie.width, (float)ies.width));
+
+ if (!m_CookieAtlas.IsCached(out var scaleBias, cookie, ies) && !m_NoMoreSpace)
+ Debug.LogError($"Area Light cookie texture {cookie} & {ies} can't be fetched without having reserved. You can try to increase the cookie atlas resolution in the HDRP settings.");
+
+ int currentID = m_CookieAtlas.GetTextureID(cookie, ies);
+ if (m_CookieAtlas.NeedsUpdate(cookie, ies, true))
+ {
+ Vector4 sourceScaleOffset = new Vector4(projectionSize / (float)atlasTexture.rt.width, projectionSize / (float)atlasTexture.rt.height, 0, 0);
+
+ Texture filteredProjected = FilterAreaLightTexture(cmd, cookie, projectionSize, projectionSize);
+ m_CookieAtlas.BlitOctahedralTexture(cmd, scaleBias, filteredProjected, sourceScaleOffset, blitMips: true, overrideInstanceID: m_CookieAtlas.GetTextureID(cookie, ies));
+ filteredProjected = FilterAreaLightTexture(cmd, ies, projectionSize, projectionSize);
+ m_CookieAtlas.BlitOctahedralTextureMultiply(cmd, scaleBias, filteredProjected, sourceScaleOffset, blitMips: true, overrideInstanceID: m_CookieAtlas.GetTextureID(cookie, ies));
}
return scaleBias;
}
+ public void ReserveSpace(Texture cookieA, Texture cookieB)
+ {
+ if (cookieA == null || cookieB == null)
+ return;
+
+ int width = (int)Mathf.Max(cookieA.width, cookieB.height);
+ int height = (int)Mathf.Max(cookieA.width, cookieB.height);
+
+ if (width < k_MinCookieSize || height < k_MinCookieSize)
+ return;
+
+ if (!m_CookieAtlas.ReserveSpace(m_CookieAtlas.GetTextureID(cookieA, cookieB), width, height))
+ m_2DCookieAtlasNeedsLayouting = true;
+ }
+
public void ReserveSpace(Texture cookie)
{
if (cookie == null)
@@ -283,17 +349,95 @@ public void ReserveSpace(Texture cookie)
m_2DCookieAtlasNeedsLayouting = true;
}
- public int FetchCubeCookie(CommandBuffer cmd, Texture cookie) => m_CubeCookieTexArray.FetchSlice(cmd, cookie);
+ public void ReserveSpaceCube(Texture cookie)
+ {
+ if (cookie == null)
+ return;
+
+ Debug.Assert(cookie.dimension == TextureDimension.Cube);
+
+ int projectionSize = 2*cookie.width;
+
+ if (projectionSize < k_MinCookieSize)
+ return;
+
+ if (!m_CookieAtlas.ReserveSpace(m_CookieAtlas.GetTextureID(cookie), projectionSize, projectionSize))
+ m_2DCookieAtlasNeedsLayouting = true;
+ }
+
+ public void ReserveSpaceCube(Texture cookieA, Texture cookieB)
+ {
+ if (cookieA == null && cookieB == null)
+ return;
+
+ Debug.Assert(cookieA.dimension == TextureDimension.Cube && cookieB.dimension == TextureDimension.Cube);
+
+ int projectionSize = 2*(int)Mathf.Max(cookieA.width, cookieB.width);
+
+ if (projectionSize < k_MinCookieSize)
+ return;
+
+ if (!m_CookieAtlas.ReserveSpace(m_CookieAtlas.GetTextureID(cookieA, cookieB), projectionSize, projectionSize))
+ m_2DCookieAtlasNeedsLayouting = true;
+ }
+
+ public Vector4 FetchCubeCookie(CommandBuffer cmd, Texture cookie)
+ {
+ Debug.Assert(cookie != null);
+ Debug.Assert(cookie.dimension == TextureDimension.Cube);
+
+ int projectionSize = 2*(int)Mathf.Max((float)m_CookieCubeResolution, (float)cookie.width);
+ if (projectionSize < k_MinCookieSize)
+ return Vector4.zero;
+
+ if (!m_CookieAtlas.IsCached(out var scaleBias, cookie) && !m_NoMoreSpace)
+ Debug.LogError($"Unity cannot fetch the Cube cookie texture: {cookie} because it is not on the cookie atlas. To resolve this, open your HDRP Asset and increase the resolution of the cookie atlas.");
+
+ if (m_CookieAtlas.NeedsUpdate(cookie, true))
+ {
+ Vector4 sourceScaleOffset = new Vector4(projectionSize/(float)atlasTexture.rt.width, projectionSize/(float)atlasTexture.rt.height, 0, 0);
+
+ Texture filteredProjected = FilterAreaLightTexture(cmd, cookie, projectionSize, projectionSize);
+ m_CookieAtlas.BlitOctahedralTexture(cmd, scaleBias, filteredProjected, sourceScaleOffset, blitMips: true, overrideInstanceID: m_CookieAtlas.GetTextureID(cookie));
+ }
+
+ return scaleBias;
+ }
+
+ public Vector4 FetchCubeCookie(CommandBuffer cmd, Texture cookie, Texture ies)
+ {
+ Debug.Assert(cookie != null);
+ Debug.Assert(ies != null);
+ Debug.Assert(cookie.dimension == TextureDimension.Cube);
+ Debug.Assert(ies.dimension == TextureDimension.Cube);
+
+ int projectionSize = 2*(int)Mathf.Max((float)m_CookieCubeResolution, (float)cookie.width);
+ if (projectionSize < k_MinCookieSize)
+ return Vector4.zero;
+
+ if (!m_CookieAtlas.IsCached(out var scaleBias, cookie, ies) && !m_NoMoreSpace)
+ Debug.LogError($"Unity cannot fetch the Cube cookie texture: {cookie} because it is not on the cookie atlas. To resolve this, open your HDRP Asset and increase the resolution of the cookie atlas.");
+
+ if (m_CookieAtlas.NeedsUpdate(cookie, ies, true))
+ {
+ Vector4 sourceScaleOffset = new Vector4(projectionSize/(float)atlasTexture.rt.width, projectionSize/(float)atlasTexture.rt.height, 0, 0);
+
+ Texture filteredProjected = FilterAreaLightTexture(cmd, cookie, projectionSize, projectionSize);
+ m_CookieAtlas.BlitOctahedralTexture(cmd, scaleBias, filteredProjected, sourceScaleOffset, blitMips: true, overrideInstanceID: m_CookieAtlas.GetTextureID(cookie, ies));
+ filteredProjected = FilterAreaLightTexture(cmd, ies, projectionSize, projectionSize);
+ m_CookieAtlas.BlitOctahedralTextureMultiply(cmd, scaleBias, filteredProjected, sourceScaleOffset, blitMips: true, overrideInstanceID: m_CookieAtlas.GetTextureID(cookie, ies));
+ }
+
+ return scaleBias;
+ }
public void ResetAllocator() => m_CookieAtlas.ResetAllocator();
public void ClearAtlasTexture(CommandBuffer cmd) => m_CookieAtlas.ClearTarget(cmd);
public RTHandle atlasTexture => m_CookieAtlas.AtlasTexture;
- public Texture cubeCache => m_CubeCookieTexArray.GetTexCache();
public PowerOfTwoTextureAtlas atlas => m_CookieAtlas;
- public TextureCacheCubemap cubeCookieTexArray => m_CubeCookieTexArray;
public Vector4 GetCookieAtlasSize()
{
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightDefinition.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightDefinition.cs
index 624ba0a393c..982e5bb923e 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightDefinition.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightDefinition.cs
@@ -129,6 +129,8 @@ struct LightData
public float angleOffset; // Spot light
public Vector3 forward;
+ public float iesCut; // Spot light
+
public GPULightType lightType; // TODO: move this up?
public Vector3 right; // If spot: rescaled by cot(outerHalfAngle); if projector: rescaled by (2 / shapeWidth)
@@ -142,7 +144,7 @@ struct LightData
public float rangeAttenuationBias;
public CookieMode cookieMode;
- public int cookieIndex; // Texture array index of the point and rectangle light cookies
+
public int shadowIndex; // -1 if unused (TODO: 16 bit)
public Vector4 cookieScaleOffset; // coordinates of the cookie texture in the atlas
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightDefinition.cs.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightDefinition.cs.hlsl
index 4723c0ddf02..907299c3b15 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightDefinition.cs.hlsl
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightDefinition.cs.hlsl
@@ -97,6 +97,7 @@ struct LightData
real angleScale;
real angleOffset;
float3 forward;
+ float iesCut;
int lightType;
float3 right;
real range;
@@ -105,7 +106,6 @@ struct LightData
float3 color;
float rangeAttenuationBias;
int cookieMode;
- int cookieIndex;
int shadowIndex;
float4 cookieScaleOffset;
int contactShadowMask;
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightEvaluation.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightEvaluation.hlsl
index e509922b0d0..e7269e379a1 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightEvaluation.hlsl
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightEvaluation.hlsl
@@ -26,10 +26,10 @@ float3 SampleAreaLightCookie(float4 cookieScaleOffset, float4x3 L, float3 F)
float3 hitPosition = hitDistance * normal;
hitPosition -= origin; // Relative to bottom-left corner
- // Here, right and up vectors are not necessarily orthonormal
- // We create the orthogonal vector "ortho" by projecting "up" onto the vector orthogonal to "right"
- // ortho = up - (up.right') * right'
- // Where right' = right / sqrt( dot( right, right ) ), the normalized right vector
+ // Here, right and up vectors are not necessarily orthonormal
+ // We create the orthogonal vector "ortho" by projecting "up" onto the vector orthogonal to "right"
+ // ortho = up - (up.right') * right'
+ // Where right' = right / sqrt( dot( right, right ) ), the normalized right vector
float recSqLengthRight = 1.0 / dot(right, right);
float upRightMixing = dot(up, right);
float3 ortho = up - upRightMixing * right * recSqLengthRight;
@@ -93,7 +93,7 @@ void RectangularLightApplyBarnDoor(inout LightData lightData, float3 pointPositi
// Transform the point to light source space. First position then orientation
float3 lightRelativePointPos = -(lightData.positionRWS - pointPosition);
float3 pointLS = float3(dot(lightRelativePointPos, lightData.right), dot(lightRelativePointPos, lightData.up), dot(lightRelativePointPos, lightData.forward));
-
+
// Compute the depth of the point in the pyramid space
float pointDepth = min(pointLS.z, lightData.size.z * lightData.size.w);
@@ -103,15 +103,15 @@ void RectangularLightApplyBarnDoor(inout LightData lightData, float3 pointPositi
// Compute the barn door projection
float barnDoorProjection = sinTheta * lightData.size.w * pointDepthRatio;
-
+
// Compute the sign of the point when in the local light space
float2 pointSign = sign(pointLS.xy);
// Clamp the point to the closest edge
pointLS.xy = float2(pointSign.x, pointSign.y) * max(abs(pointLS.xy), float2(halfWidth, halfHeight) + barnDoorProjection.xx);
-
+
// Compute the closest rect lignt corner, offset by the barn door size
float3 closestLightCorner = float3(pointSign.x * (halfWidth + barnDoorProjection), pointSign.y * (halfHeight + barnDoorProjection), pointDepth);
-
+
// Compute the point projection onto the edge and deduce the size that should be removed from the light dimensions
float3 pointProjection = pointLS - closestLightCorner;
// Phi being the angle between the point projection point and the forward vector of the light source
@@ -127,7 +127,7 @@ void RectangularLightApplyBarnDoor(inout LightData lightData, float3 pointPositi
bottomLeft += (projectionDistance.y - barnDoorProjection) * float2(max(0, -pointSign.y), -max(0, pointSign.y));
topRight = clamp(topRight, -halfWidth, halfWidth);
bottomLeft = clamp(bottomLeft, -halfHeight, halfHeight);
-
+
// Compute the offset that needs to be applied to the origin points to match the culling of the barn door
float2 lightCenterOffset = 0.5f * float2(topRight.x + topRight.y, bottomLeft.x + bottomLeft.y);
@@ -319,7 +319,7 @@ float4 EvaluateCookie_Punctual(LightLoopContext lightLoopContext, LightData ligh
UNITY_BRANCH if (lightType == GPULIGHTTYPE_POINT)
{
- cookie.rgb = SampleCookieCube(positionLS, light.cookieIndex);
+ cookie.rgb = SamplePointCookie(mul(lightToWorld, lightToSample), light.cookieScaleOffset);
cookie.a = 1;
}
else
@@ -333,8 +333,11 @@ float4 EvaluateCookie_Punctual(LightLoopContext lightLoopContext, LightData ligh
// Box lights have no range attenuation, so we must clip manually.
bool isInBounds = Max3(abs(positionCS.x), abs(positionCS.y), abs(z - 0.5 * r) - 0.5 * r + 1) <= light.boxLightSafeExtent;
+ if (lightType != GPULIGHTTYPE_PROJECTOR_PYRAMID && lightType != GPULIGHTTYPE_PROJECTOR_BOX)
+ {
+ isInBounds = isInBounds & dot(positionCS, positionCS) <= light.iesCut * light.iesCut;
+ }
- // Remap the texture coordinates from [-1, 1]^2 to [0, 1]^2.
float2 positionNDC = positionCS * 0.5 + 0.5;
// Manually clamp to border (black).
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/CookieSampling.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/CookieSampling.hlsl
index 6d9fbed7a5b..0a0d951d650 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/CookieSampling.hlsl
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/CookieSampling.hlsl
@@ -2,6 +2,8 @@
// Cookie sampling functions
// ----------------------------------------------------------------------------
+#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl"
+
#define COOKIE_ATLAS_SIZE _CookieAtlasData.x
#define COOKIE_ATLAS_RCP_PADDING _CookieAtlasData.y
#define COOKIE_ATLAS_LAST_VALID_MIP _CookieAtlasData.z
@@ -38,8 +40,10 @@ float3 SampleCookie2D(float2 coord, float4 scaleOffset, float lod = 0) // TODO:
}
// Used by point lights.
-float3 SampleCookieCube(float3 coord, int index)
+float3 SamplePointCookie(float3 lightToSample, float4 scaleOffset, float lod = 0)
{
- // TODO: add MIP maps to combat aliasing?
- return SAMPLE_TEXTURECUBE_ARRAY_LOD_ABSTRACT(_CookieCubeTextures, s_linear_clamp_sampler, coord, index, 0).rgb;
+ float2 params = PackNormalOctQuadEncode(lightToSample);
+ float2 uv = saturate(params*0.5f + 0.5f);
+
+ return SampleCookie2D(uv, scaleOffset, lod);
}
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/GlobalLightLoopSettings.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/GlobalLightLoopSettings.cs
index 2d17767990d..f1b66ed1403 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/GlobalLightLoopSettings.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/GlobalLightLoopSettings.cs
@@ -113,8 +113,6 @@ public struct GlobalLightLoopSettings
{
cookieAtlasSize = CookieAtlasResolution.CookieResolution2048,
cookieFormat = CookieAtlasGraphicsFormat.R11G11B10,
- pointCookieSize = CubeCookieResolution.CubeCookieResolution128,
- cubeCookieTexArraySize = 16,
cookieAtlasLastValidMip = 0,
@@ -145,8 +143,6 @@ public struct GlobalLightLoopSettings
public CookieAtlasGraphicsFormat cookieFormat;
/// Cookie atlas resolution for point lights.
public CubeCookieResolution pointCookieSize;
- /// Maximum number of cached cookies for point lights.
- public int cubeCookieTexArraySize;
/// Last valid mip for cookie atlas.
public int cookieAtlasLastValidMip;
// We keep this property for the migration code (we need to know how many cookies we could have before).
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs
index 7c03143128a..ee3e3364a06 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs
@@ -1271,7 +1271,6 @@ internal void GetDirectionalLightData(CommandBuffer cmd, HDCamera hdCamera, Visi
m_CurrentSunLightAdditionalLightData = additionalLightData;
m_CurrentSunLightDirectionalLightData = lightData;
m_CurrentShadowSortedSunLightIndex = sortedIndex;
-
}
//Value of max smoothness is derived from AngularDiameter. Formula results from eyeballing. Angular diameter of 0 results in 1 and angular diameter of 80 results in 0.
float maxSmoothness = Mathf.Clamp01(1.35f / (1.0f + Mathf.Pow(1.15f * (0.0315f * additionalLightData.angularDiameter + 0.4f),2f)) - 0.11f);
@@ -1339,7 +1338,7 @@ bool EnoughScreenSpaceShadowSlots(GPULightType gpuLightType, int screenSpaceChan
}
internal void GetLightData(CommandBuffer cmd, HDCamera hdCamera, HDShadowSettings shadowSettings, VisibleLight light, Light lightComponent,
- in ProcessedLightData processedData, int shadowIndex, BoolScalableSetting contactShadowsScalableSetting, bool isRasterization, ref Vector3 lightDimensions, ref int screenSpaceShadowIndex, ref int screenSpaceChannelSlot, ref LightData lightData)
+ in ProcessedLightData processedData, int shadowIndex, BoolScalableSetting contactShadowsScalableSetting, bool isRasterization, ref Vector3 lightDimensions, ref int screenSpaceShadowIndex, ref int screenSpaceChannelSlot, ref LightData lightData)
{
var additionalLightData = processedData.additionalLightData;
var gpuLightType = processedData.gpuLightType;
@@ -1449,8 +1448,9 @@ internal void GetLightData(CommandBuffer cmd, HDCamera hdCamera, HDShadowSetting
var cosSpotInnerHalfAngle = Mathf.Clamp(Mathf.Cos(spotAngle * 0.5f * innerConePercent * Mathf.Deg2Rad), 0.0f, 1.0f); // inner cone
var val = Mathf.Max(0.0001f, (cosSpotInnerHalfAngle - cosSpotOuterHalfAngle));
- lightData.angleScale = 1.0f / val;
+ lightData.angleScale = 1.0f / val;
lightData.angleOffset = -cosSpotOuterHalfAngle * lightData.angleScale;
+ lightData.iesCut = additionalLightData.spotIESCutoffPercent01;
// Rescale for cookies and windowing.
float cotOuterHalfAngle = cosSpotOuterHalfAngle / sinSpotOuterHalfAngle;
@@ -1462,6 +1462,7 @@ internal void GetLightData(CommandBuffer cmd, HDCamera hdCamera, HDShadowSetting
// These are the neutral values allowing GetAngleAnttenuation in shader code to return 1.0
lightData.angleScale = 0.0f;
lightData.angleOffset = 1.0f;
+ lightData.iesCut = 1.0f;
}
if (lightData.lightType != GPULightType.Directional && lightData.lightType != GPULightType.ProjectorBox)
@@ -1481,23 +1482,47 @@ internal void GetLightData(CommandBuffer cmd, HDCamera hdCamera, HDShadowSetting
lightData.volumetricLightDimmer = processedData.lightDistanceFade * (additionalLightData.volumetricDimmer);
lightData.cookieMode = CookieMode.None;
- lightData.cookieIndex = -1;
lightData.shadowIndex = -1;
lightData.screenSpaceShadowIndex = (int)LightDefinitions.s_InvalidScreenSpaceShadow;
lightData.isRayTracedContactShadow = 0.0f;
- // lightComponent.cookie can't be used for area lights
- if (lightComponent != null && lightComponent.cookie != null && lightType != HDLightType.Area)
+ if (lightComponent != null && additionalLightData != null &&
+ (
+ (lightType == HDLightType.Spot && (lightComponent.cookie != null || additionalLightData.IESPoint != null)) ||
+ ((lightType == HDLightType.Area && lightData.lightType == GPULightType.Rectangle) && (lightComponent.cookie != null || additionalLightData.IESSpot != null)) ||
+ (lightType == HDLightType.Point && (lightComponent.cookie != null || additionalLightData.IESPoint != null))
+ ))
{
switch (lightType)
{
case HDLightType.Spot:
- lightData.cookieMode = (lightComponent.cookie.wrapMode == TextureWrapMode.Repeat) ? CookieMode.Repeat : CookieMode.Clamp;
- lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.Fetch2DCookie(cmd, lightComponent.cookie);
+ lightData.cookieMode = (lightComponent.cookie?.wrapMode == TextureWrapMode.Repeat) ? CookieMode.Repeat : CookieMode.Clamp;
+ if (additionalLightData.IESSpot != null && lightComponent.cookie != null && additionalLightData.IESSpot != lightComponent.cookie)
+ lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.Fetch2DCookie(cmd, lightComponent.cookie, additionalLightData.IESSpot);
+ else if (lightComponent.cookie != null)
+ lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.Fetch2DCookie(cmd, lightComponent.cookie);
+ else if (additionalLightData.IESSpot != null)
+ lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.Fetch2DCookie(cmd, additionalLightData.IESSpot);
+ else
+ lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.Fetch2DCookie(cmd, Texture2D.whiteTexture);
break;
case HDLightType.Point:
+ lightData.cookieMode = CookieMode.Repeat;
+ if (additionalLightData.IESPoint != null && lightComponent.cookie != null && additionalLightData.IESPoint != lightComponent.cookie)
+ lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchCubeCookie(cmd, lightComponent.cookie, additionalLightData.IESPoint);
+ else if (lightComponent.cookie != null)
+ lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchCubeCookie(cmd, lightComponent.cookie);
+ else if (additionalLightData.IESPoint != null)
+ lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchCubeCookie(cmd, additionalLightData.IESPoint);
+ break;
+ case HDLightType.Area:
lightData.cookieMode = CookieMode.Clamp;
- lightData.cookieIndex = m_TextureCaches.lightCookieManager.FetchCubeCookie(cmd, lightComponent.cookie);
+ if (additionalLightData.areaLightCookie != null && additionalLightData.IESSpot != null && additionalLightData.areaLightCookie != additionalLightData.IESSpot)
+ lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchAreaCookie(cmd, additionalLightData.areaLightCookie, additionalLightData.IESSpot);
+ else if (additionalLightData.IESSpot != null)
+ lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchAreaCookie(cmd, additionalLightData.IESSpot);
+ else if (additionalLightData.areaLightCookie != null)
+ lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchAreaCookie(cmd, additionalLightData.areaLightCookie);
break;
}
}
@@ -1508,10 +1533,18 @@ internal void GetLightData(CommandBuffer cmd, HDCamera hdCamera, HDShadowSetting
lightData.cookieMode = CookieMode.Clamp;
lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.Fetch2DCookie(cmd, Texture2D.whiteTexture);
}
- else if (lightData.lightType == GPULightType.Rectangle && additionalLightData.areaLightCookie != null)
+ else if (lightData.lightType == GPULightType.Rectangle)
{
- lightData.cookieMode = CookieMode.Clamp;
- lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchAreaCookie(cmd, additionalLightData.areaLightCookie);
+ if (additionalLightData.areaLightCookie != null || additionalLightData.IESPoint != null)
+ {
+ lightData.cookieMode = CookieMode.Clamp;
+ if (additionalLightData.areaLightCookie != null && additionalLightData.IESSpot != null && additionalLightData.areaLightCookie != additionalLightData.IESSpot)
+ lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchAreaCookie(cmd, additionalLightData.areaLightCookie, additionalLightData.IESSpot);
+ else if (additionalLightData.IESSpot != null)
+ lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchAreaCookie(cmd, additionalLightData.IESSpot);
+ else if (additionalLightData.areaLightCookie != null)
+ lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchAreaCookie(cmd, additionalLightData.areaLightCookie);
+ }
}
float shadowDistanceFade = HDUtils.ComputeLinearDistanceFade(processedData.distanceToCamera, Mathf.Min(shadowSettings.maxShadowDistance.value, additionalLightData.shadowFadeDistance));
@@ -2760,15 +2793,36 @@ internal void ReserveCookieAtlasTexture(HDAdditionalLightData hdLightData, Light
m_TextureCaches.lightCookieManager.ReserveSpace(hdLightData.surfaceTexture);
m_TextureCaches.lightCookieManager.ReserveSpace(light?.cookie);
break;
+ case HDLightType.Point:
+ if (light.cookie != null && hdLightData.IESPoint != null && light.cookie != hdLightData.IESPoint)
+ m_TextureCaches.lightCookieManager.ReserveSpaceCube(light.cookie, hdLightData.IESPoint);
+ else if (light?.cookie != null)
+ m_TextureCaches.lightCookieManager.ReserveSpaceCube(light.cookie);
+ else if (hdLightData.IESPoint != null)
+ m_TextureCaches.lightCookieManager.ReserveSpaceCube(hdLightData.IESPoint);
+ break;
case HDLightType.Spot:
// Projectors lights must always have a cookie texture.
- if (hdLightData.spotLightShape != SpotLightShape.Cone || light?.cookie != null)
- m_TextureCaches.lightCookieManager.ReserveSpace(light?.cookie ?? Texture2D.whiteTexture);
+ if (light.cookie != null && hdLightData.IESSpot != null && light.cookie != hdLightData.IESSpot)
+ m_TextureCaches.lightCookieManager.ReserveSpace(light.cookie, hdLightData.IESSpot);
+ else if (light?.cookie != null)
+ m_TextureCaches.lightCookieManager.ReserveSpace(light.cookie);
+ else if (hdLightData.IESSpot != null)
+ m_TextureCaches.lightCookieManager.ReserveSpace(hdLightData.IESSpot);
+ else
+ m_TextureCaches.lightCookieManager.ReserveSpace(Texture2D.whiteTexture);
break;
case HDLightType.Area:
- // Only rectnagles can have cookies
+ // Only rectangle can have cookies
if (hdLightData.areaLightShape == AreaLightShape.Rectangle)
- m_TextureCaches.lightCookieManager.ReserveSpace(hdLightData.areaLightCookie);
+ {
+ if (hdLightData.IESSpot != null && hdLightData.areaLightCookie != null && hdLightData.IESSpot != hdLightData.areaLightCookie)
+ m_TextureCaches.lightCookieManager.ReserveSpace(hdLightData.areaLightCookie, hdLightData.IESSpot);
+ else if (hdLightData.IESSpot != null)
+ m_TextureCaches.lightCookieManager.ReserveSpace(hdLightData.IESSpot);
+ else if (hdLightData.areaLightCookie != null)
+ m_TextureCaches.lightCookieManager.ReserveSpace(hdLightData.areaLightCookie);
+ }
break;
}
}
@@ -3517,7 +3571,6 @@ void PushLightDataGlobalParams(CommandBuffer cmd)
}
cmd.SetGlobalTexture(HDShaderIDs._CookieAtlas, m_TextureCaches.lightCookieManager.atlasTexture);
- cmd.SetGlobalTexture(HDShaderIDs._CookieCubeTextures, m_TextureCaches.lightCookieManager.cubeCache);
cmd.SetGlobalTexture(HDShaderIDs._EnvCubemapTextures, m_TextureCaches.reflectionProbeCache.GetTexCache());
cmd.SetGlobalTexture(HDShaderIDs._Env2DTextures, m_TextureCaches.reflectionPlanarProbeCache.GetTexCache());
@@ -4092,20 +4145,6 @@ static void RenderLightLoopDebugOverlay(in DebugParameters debugParameters, Comm
}
}
- if (lightingDebug.displayCookieCubeArray)
- {
- using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.DisplayPointLightCookieArray)))
- {
- m_LightLoopDebugMaterialProperties.SetFloat(HDShaderIDs._ApplyExposure, 0.0f);
- m_LightLoopDebugMaterialProperties.SetTexture(HDShaderIDs._InputCubemap, parameters.cookieManager.cubeCache);
- m_LightLoopDebugMaterialProperties.SetFloat(HDShaderIDs._Mipmap, 0);
- m_LightLoopDebugMaterialProperties.SetFloat(HDShaderIDs._SliceIndex, lightingDebug.cookieCubeArraySliceIndex);
- cmd.SetViewport(new Rect(x, y, overlaySize, overlaySize));
- cmd.DrawProcedural(Matrix4x4.identity, debugParameters.debugLatlongMaterial, 0, MeshTopology.Triangles, 3, 1, m_LightLoopDebugMaterialProperties);
- HDUtils.NextOverlayCoord(ref x, ref y, overlaySize, overlaySize, hdCamera);
- }
- }
-
if (lightingDebug.clearPlanarReflectionProbeAtlas)
{
parameters.planarProbeCache.Clear(cmd);
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.hlsl
index 2c633b7d26d..d6783969846 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.hlsl
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.hlsl
@@ -444,7 +444,6 @@ void LightLoop( float3 V, PositionInputs posInput, PreLightData preLightData, BS
while (i <= last && lightData.lightType == GPULIGHTTYPE_TUBE)
{
lightData.lightType = GPULIGHTTYPE_TUBE; // Enforce constant propagation
- lightData.cookieIndex = -1; // Enforce constant propagation
lightData.cookieMode = COOKIEMODE_NONE; // Enforce constant propagation
if (IsMatchingLightLayer(lightData.lightLayers, builtinData.renderingLayers))
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/ShaderVariablesLightLoop.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/ShaderVariablesLightLoop.hlsl
index 3f45edd1510..d7ed05ef52d 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/ShaderVariablesLightLoop.hlsl
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/ShaderVariablesLightLoop.hlsl
@@ -18,9 +18,6 @@ StructuredBuffer _EnvLightDatas;
// Used by directional and spot lights
TEXTURE2D(_CookieAtlas);
-// Used by point lights
-TEXTURECUBE_ARRAY_ABSTRACT(_CookieCubeTextures);
-
// Use texture array for reflection (or LatLong 2D array for mobile)
TEXTURECUBE_ARRAY_ABSTRACT(_EnvCubemapTextures);
TEXTURE2D(_Env2DTextures);
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/LTCAreaLight/FilterAreaLightCookies.shader b/com.unity.render-pipelines.high-definition/Runtime/Material/LTCAreaLight/FilterAreaLightCookies.shader
index 849746b2c11..9e9226ac0ab 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Material/LTCAreaLight/FilterAreaLightCookies.shader
+++ b/com.unity.render-pipelines.high-definition/Runtime/Material/LTCAreaLight/FilterAreaLightCookies.shader
@@ -10,10 +10,13 @@ Shader "CoreResources/FilterAreaLightCookies"
// SRP includes
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
+ #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
// Input Data
TEXTURE2D( _SourceTexture );
+ TEXTURECUBE( _SourceCubeTexture );
+ SAMPLER( sampler_SourceCubeTexture );
uniform uint _SourceMipLevel;
uniform float4 _SourceSize;
uniform float4 _UVLimits;
@@ -57,7 +60,7 @@ Shader "CoreResources/FilterAreaLightCookies"
ZWrite Off ZTest Always Blend Off Cull Off
HLSLPROGRAM
- float4 frag(Varyings input) : SV_Target
+ float4 frag(Varyings input) : SV_Target
{
float2 UV = input.texcoord;
return SAMPLE_TEXTURE2D_LOD( _SourceTexture, s_linear_clamp_sampler, UV, _SourceMipLevel);
@@ -113,6 +116,21 @@ Shader "CoreResources/FilterAreaLightCookies"
}
ENDHLSL
}
+
+ // 3. Project Cube to Octahedral to mip 0
+ Pass
+ {
+ ZWrite Off ZTest Always Blend Off Cull Off
+
+ HLSLPROGRAM
+ float4 frag(Varyings input) : SV_Target
+ {
+ float2 UV = saturate(input.texcoord);
+ float3 dir = UnpackNormalOctQuadEncode(2.0f*UV - 1.0f);
+ return float4(SAMPLE_TEXTURECUBE_LOD(_SourceCubeTexture, sampler_SourceCubeTexture, dir, 0).rgb, 1);
+ }
+ ENDHLSL
+ }
}
Fallback Off
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs
index ee47e855809..cf2c640bb94 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs
@@ -267,7 +267,6 @@ internal int GetDecalAtlasMipCount()
}
internal int GetCookieAtlasMipCount() => (int)Mathf.Log((int)currentPlatformRenderPipelineSettings.lightLoopSettings.cookieAtlasSize, 2);
- internal int GetCookieCubeArraySize() => currentPlatformRenderPipelineSettings.lightLoopSettings.cubeCookieTexArraySize;
internal int GetPlanarReflectionProbeMipCount()
{
@@ -4945,7 +4944,7 @@ static void RenderSkyReflectionOverlay(in DebugParameters debugParameters, Comma
mpb.SetTexture(HDShaderIDs._InputCubemap, debugParameters.skyReflectionTexture);
mpb.SetFloat(HDShaderIDs._Mipmap, lightingDebug.skyReflectionMipmap);
mpb.SetFloat(HDShaderIDs._ApplyExposure, 1.0f);
- mpb.SetFloat(HDShaderIDs._SliceIndex, lightingDebug.cookieCubeArraySliceIndex);
+ mpb.SetFloat(HDShaderIDs._SliceIndex, lightingDebug.cubeArraySliceIndex);
cmd.SetViewport(new Rect(x, y, overlaySize, overlaySize));
cmd.DrawProcedural(Matrix4x4.identity, debugParameters.debugLatlongMaterial, 0, MeshTopology.Triangles, 3, 1, mpb);
HDUtils.NextOverlayCoord(ref x, ref y, overlaySize, overlaySize, debugParameters.hdCamera);
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.Migration.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.Migration.cs
index 29fa5bd1cc1..8dda8efbff8 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.Migration.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.Migration.cs
@@ -21,7 +21,8 @@ enum Version
ShadowFilteringVeryHighQualityRemoval,
SeparateColorGradingAndTonemappingFrameSettings,
ReplaceTextureArraysByAtlasForCookieAndPlanar,
- AddedAdaptiveSSS
+ AddedAdaptiveSSS,
+ RemoveCookieCubeAtlasToOctahedral2D
}
static readonly MigrationDescription k_Migration = MigrationDescription.New(
@@ -110,6 +111,20 @@ enum Version
FrameSettings.MigrateSubsurfaceParams(ref data.m_RenderingPathDefaultCameraFrameSettings, previouslyHighQuality);
FrameSettings.MigrateSubsurfaceParams(ref data.m_RenderingPathDefaultBakedOrCustomReflectionFrameSettings, previouslyHighQuality);
FrameSettings.MigrateSubsurfaceParams(ref data.m_RenderingPathDefaultRealtimeReflectionFrameSettings, previouslyHighQuality);
+ }),
+ MigrationStep.New(Version.RemoveCookieCubeAtlasToOctahedral2D, (HDRenderPipelineAsset data) =>
+ {
+ ref var lightLoopSettings = ref data.m_RenderPipelineSettings.lightLoopSettings;
+
+#pragma warning disable 618 // Type or member is obsolete
+ float cookieAtlasSize = Mathf.Sqrt((int)lightLoopSettings.cookieAtlasSize * (int)lightLoopSettings.cookieAtlasSize * lightLoopSettings.cookieTexArraySize);
+ float planarSize = Mathf.Sqrt((int)lightLoopSettings.planarReflectionAtlasSize * (int)lightLoopSettings.planarReflectionAtlasSize * lightLoopSettings.maxPlanarReflectionOnScreen);
+#pragma warning restore 618
+
+ if (cookieAtlasSize > 128f && planarSize <= 1024f)
+ {
+ Debug.LogWarning("HDRP Internally change the storage of Cube Cookie to Octahedral Projection inside the Planar Reflection Atlas. It is recommended that you increase the size of the Planar Projection Atlas if the cookies no longer fit.");
+ }
})
);
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs
index f0e646378ac..4dc572eb898 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs
@@ -125,7 +125,7 @@ static class HDShaderIDs
public static readonly int _NumTiles = Shader.PropertyToID("_NumTiles");
public static readonly int _CookieAtlas = Shader.PropertyToID("_CookieAtlas");
- public static readonly int _CookieCubeTextures = Shader.PropertyToID("_CookieCubeTextures");
+
public static readonly int _EnvCubemapTextures = Shader.PropertyToID("_EnvCubemapTextures");
public static readonly int _Env2DTextures = Shader.PropertyToID("_Env2DTextures");
public static readonly int _DirectionalLightDatas = Shader.PropertyToID("_DirectionalLightDatas");
@@ -274,7 +274,13 @@ static class HDShaderIDs
public static readonly int _DepthTextureOblique = Shader.PropertyToID("_DepthTextureOblique");
public static readonly int _DepthTextureNonOblique = Shader.PropertyToID("_DepthTextureNonOblique");
public static readonly int _CaptureCameraIVP_NO = Shader.PropertyToID("_CaptureCameraIVP_NO");
-
+
+ public static readonly int _Output = Shader.PropertyToID("_Output");
+ public static readonly int _Input = Shader.PropertyToID("_Input");
+ public static readonly int _InputVal = Shader.PropertyToID("_InputVal");
+ public static readonly int _Sizes = Shader.PropertyToID("_Sizes");
+ public static readonly int _ScaleBias = Shader.PropertyToID("_ScaleBias");
+
// MSAA shader properties
public static readonly int _ColorTextureMS = Shader.PropertyToID("_ColorTextureMS");
public static readonly int _DepthTextureMS = Shader.PropertyToID("_DepthTextureMS");
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Shadows/RaytracingShadow.raytrace b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Shadows/RaytracingShadow.raytrace
index 14590bc5fa9..fea469a6773 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Shadows/RaytracingShadow.raytrace
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Shadows/RaytracingShadow.raytrace
@@ -140,14 +140,8 @@ void RayGenAreaShadows()
LightLoopContext context;
// Given that the approximation used for LTC is completely different from what we would get from a real integration, we only rely on the not textured intensity.
// To acheive that, we set cookie index to -1 so that the evaluatebsdf_rect function to not use any cookie. We also keep track of that cookie value to restore it after the evaluation.
- int cookieIndex = lightData.cookieIndex;
- int cookieMode = lightData.cookieMode;
- lightData.cookieIndex = -1;
- lightData.cookieIndex = COOKIEMODE_NONE;
DirectLighting lighting = EvaluateBSDF_Rect(context, viewWS, posInput, preLightData, lightData, bsdfData, builtinData);
lighting.diffuse = lighting.diffuse * bsdfData.diffuseColor;
- lightData.cookieIndex = cookieIndex;
- lightData.cookieIndex = cookieMode;
// Compute the non-occluded analytic luminance value
float U = Luminance(lighting.diffuse + lighting.specular);
@@ -237,7 +231,7 @@ void RayGenAreaShadows()
// Combine the light color with the light cookie color (if any)
float3 lightColor = lightData.color;
- if (lightData.cookieIndex >= 0)
+ if (lightData.cookieMode != COOKIEMODE_NONE)
{
float cookieWidth = lightData.cookieScaleOffset.x * _CookieAtlasSize.x;
float cookieSizePOT = round(LOG2_E * log(cookieWidth));
@@ -701,4 +695,4 @@ void RayGenSemiTransparentShadowSegmentSingle()
_RaytracedShadowIntegration[COORD_TEXTURE2D_X(currentPixelCoord)] = previousValue + Luminance(rayIntersection.color) / (float)_RaytracingNumSamples;
_VelocityBuffer[COORD_TEXTURE2D_X(currentPixelCoord)] = max(rayIntersection.velocity, previousVelocityValue);
_RaytracingDistanceBufferRW[COORD_TEXTURE2D_X(currentPixelCoord)] = previousDistanceValue + rayIntersection.t / (float)_RaytracingNumSamples;
-}
\ No newline at end of file
+}
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs
index 87b1b915415..06f3e24d1ed 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs
@@ -90,7 +90,6 @@ public sealed class ShaderResources
[Reload("Runtime/Lighting/ProbeVolume/DebugDisplayProbeVolume.shader")]
public Shader debugDisplayProbeVolumePS;
-
[Reload("Runtime/Material/SubsurfaceScattering/SubsurfaceScattering.compute")]
public ComputeShader subsurfaceScatteringCS; // Disney SSS
[Reload("Runtime/Material/SubsurfaceScattering/CombineLighting.shader")]
@@ -399,7 +398,7 @@ public sealed class AssetResources
{
[Reload("Runtime/RenderPipelineResources/defaultDiffusionProfile.asset")]
public DiffusionProfileSettings defaultDiffusionProfile;
-
+
//Area Light Emissive Meshes
[Reload("Runtime/RenderPipelineResources/Mesh/Cylinder.fbx")]
public Mesh emissiveCylinderMesh;
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/HDUtils.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/HDUtils.cs
index e3cceebbc20..c93264b3dd2 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/HDUtils.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/HDUtils.cs
@@ -245,6 +245,75 @@ public static void BlitQuadWithPadding(CommandBuffer cmd, Texture source, Vector
cmd.DrawProcedural(Matrix4x4.identity, GetBlitMaterial(source.dimension), bilinear ? 5 : 4, MeshTopology.Quads, 4, 1, s_PropertyBlock);
}
+ ///
+ /// Blit a texture using a quad in the current render target, by performing an alpha blend with the existing content on the render target.
+ ///
+ /// Command buffer used for rendering.
+ /// Source texture.
+ /// Source texture size.
+ /// Scale and bias for sampling the input texture.
+ /// Scale and bias for the output texture.
+ /// Mip level to blit.
+ /// Enable bilinear filtering.
+ /// Padding in pixels.
+ public static void BlitQuadWithPaddingMultiply(CommandBuffer cmd, Texture source, Vector2 textureSize, Vector4 scaleBiasTex, Vector4 scaleBiasRT, int mipLevelTex, bool bilinear, int paddingInPixels)
+ {
+ s_PropertyBlock.SetTexture(HDShaderIDs._BlitTexture, source);
+ s_PropertyBlock.SetVector(HDShaderIDs._BlitScaleBias, scaleBiasTex);
+ s_PropertyBlock.SetVector(HDShaderIDs._BlitScaleBiasRt, scaleBiasRT);
+ s_PropertyBlock.SetFloat(HDShaderIDs._BlitMipLevel, mipLevelTex);
+ s_PropertyBlock.SetVector(HDShaderIDs._BlitTextureSize, textureSize);
+ s_PropertyBlock.SetInt(HDShaderIDs._BlitPaddingSize, paddingInPixels);
+ if (source.wrapMode == TextureWrapMode.Repeat)
+ cmd.DrawProcedural(Matrix4x4.identity, GetBlitMaterial(source.dimension), bilinear ? 12 : 11, MeshTopology.Quads, 4, 1, s_PropertyBlock);
+ else
+ cmd.DrawProcedural(Matrix4x4.identity, GetBlitMaterial(source.dimension), bilinear ? 10 : 9, MeshTopology.Quads, 4, 1, s_PropertyBlock);
+ }
+
+ ///
+ /// Blit a texture (which is a Octahedral projection) using a quad in the current render target.
+ ///
+ /// Command buffer used for rendering.
+ /// Source texture.
+ /// Source texture size.
+ /// Scale and bias for sampling the input texture.
+ /// Scale and bias for the output texture.
+ /// Mip level to blit.
+ /// Enable bilinear filtering.
+ /// Padding in pixels.
+ public static void BlitOctahedralWithPadding(CommandBuffer cmd, Texture source, Vector2 textureSize, Vector4 scaleBiasTex, Vector4 scaleBiasRT, int mipLevelTex, bool bilinear, int paddingInPixels)
+ {
+ s_PropertyBlock.SetTexture(HDShaderIDs._BlitTexture, source);
+ s_PropertyBlock.SetVector(HDShaderIDs._BlitScaleBias, scaleBiasTex);
+ s_PropertyBlock.SetVector(HDShaderIDs._BlitScaleBiasRt, scaleBiasRT);
+ s_PropertyBlock.SetFloat(HDShaderIDs._BlitMipLevel, mipLevelTex);
+ s_PropertyBlock.SetVector(HDShaderIDs._BlitTextureSize, textureSize);
+ s_PropertyBlock.SetInt(HDShaderIDs._BlitPaddingSize, paddingInPixels);
+ cmd.DrawProcedural(Matrix4x4.identity, GetBlitMaterial(source.dimension), 8, MeshTopology.Quads, 4, 1, s_PropertyBlock);
+ }
+
+ ///
+ /// Blit a texture (which is a Octahedral projection) using a quad in the current render target, by performing an alpha blend with the existing content on the render target.
+ ///
+ /// Command buffer used for rendering.
+ /// Source texture.
+ /// Source texture size.
+ /// Scale and bias for sampling the input texture.
+ /// Scale and bias for the output texture.
+ /// Mip level to blit.
+ /// Enable bilinear filtering.
+ /// Padding in pixels.
+ public static void BlitOctahedralWithPaddingMultiply(CommandBuffer cmd, Texture source, Vector2 textureSize, Vector4 scaleBiasTex, Vector4 scaleBiasRT, int mipLevelTex, bool bilinear, int paddingInPixels)
+ {
+ s_PropertyBlock.SetTexture(HDShaderIDs._BlitTexture, source);
+ s_PropertyBlock.SetVector(HDShaderIDs._BlitScaleBias, scaleBiasTex);
+ s_PropertyBlock.SetVector(HDShaderIDs._BlitScaleBiasRt, scaleBiasRT);
+ s_PropertyBlock.SetFloat(HDShaderIDs._BlitMipLevel, mipLevelTex);
+ s_PropertyBlock.SetVector(HDShaderIDs._BlitTextureSize, textureSize);
+ s_PropertyBlock.SetInt(HDShaderIDs._BlitPaddingSize, paddingInPixels);
+ cmd.DrawProcedural(Matrix4x4.identity, GetBlitMaterial(source.dimension), 13, MeshTopology.Quads, 4, 1, s_PropertyBlock);
+ }
+
///
/// Blit a RTHandle texture.
///
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/PowerOfTwoTextureAtlas.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/PowerOfTwoTextureAtlas.cs
index 73e30eb238d..4d7e0830bc5 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/PowerOfTwoTextureAtlas.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/PowerOfTwoTextureAtlas.cs
@@ -38,7 +38,7 @@ static int PreviousPowerOfTwo(int size)
size |= (size >> 16);
return size - (size >> 1);
}
-
+
void Blit2DTexturePadding(CommandBuffer cmd, Vector4 scaleOffset, Texture texture, Vector4 sourceScaleOffset, bool blitMips = true)
{
int mipCount = GetTextureMipmapCount(texture.width, texture.height);
@@ -59,6 +59,66 @@ void Blit2DTexturePadding(CommandBuffer cmd, Vector4 scaleOffset, Texture textur
}
}
+ void Blit2DTexturePaddingMultiply(CommandBuffer cmd, Vector4 scaleOffset, Texture texture, Vector4 sourceScaleOffset, bool blitMips = true)
+ {
+ int mipCount = GetTextureMipmapCount(texture.width, texture.height);
+ int pixelPadding = GetTexturePadding();
+ Vector2 textureSize = GetPowerOfTwoTextureSize(texture);
+ bool bilinear = texture.filterMode != FilterMode.Point;
+
+ if (!blitMips)
+ mipCount = 1;
+
+ using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.BlitTextureInPotAtlas)))
+ {
+ for (int mipLevel = 0; mipLevel < mipCount; mipLevel++)
+ {
+ cmd.SetRenderTarget(m_AtlasTexture, mipLevel);
+ HDUtils.BlitQuadWithPaddingMultiply(cmd, texture, textureSize, sourceScaleOffset, scaleOffset, mipLevel, bilinear, pixelPadding);
+ }
+ }
+ }
+
+ void BlitOctahedralTexturePadding(CommandBuffer cmd, Vector4 scaleOffset, Texture texture, Vector4 sourceScaleOffset, bool blitMips = true)
+ {
+ int mipCount = GetTextureMipmapCount(texture.width, texture.height);
+ int pixelPadding = GetTexturePadding();
+ Vector2 textureSize = GetPowerOfTwoTextureSize(texture);
+ bool bilinear = texture.filterMode != FilterMode.Point;
+
+ if (!blitMips)
+ mipCount = 1;
+
+ using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.BlitTextureInPotAtlas)))
+ {
+ for (int mipLevel = 0; mipLevel < mipCount; mipLevel++)
+ {
+ cmd.SetRenderTarget(m_AtlasTexture, mipLevel);
+ HDUtils.BlitOctahedralWithPadding(cmd, texture, textureSize, sourceScaleOffset, scaleOffset, mipLevel, bilinear, pixelPadding);
+ }
+ }
+ }
+
+ void BlitOctahedralTexturePaddingMultiply(CommandBuffer cmd, Vector4 scaleOffset, Texture texture, Vector4 sourceScaleOffset, bool blitMips = true)
+ {
+ int mipCount = GetTextureMipmapCount(texture.width, texture.height);
+ int pixelPadding = GetTexturePadding();
+ Vector2 textureSize = GetPowerOfTwoTextureSize(texture);
+ bool bilinear = texture.filterMode != FilterMode.Point;
+
+ if (!blitMips)
+ mipCount = 1;
+
+ using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.BlitTextureInPotAtlas)))
+ {
+ for (int mipLevel = 0; mipLevel < mipCount; mipLevel++)
+ {
+ cmd.SetRenderTarget(m_AtlasTexture, mipLevel);
+ HDUtils.BlitOctahedralWithPaddingMultiply(cmd, texture, textureSize, sourceScaleOffset, scaleOffset, mipLevel, bilinear, pixelPadding);
+ }
+ }
+ }
+
public override void BlitTexture(CommandBuffer cmd, Vector4 scaleOffset, Texture texture, Vector4 sourceScaleOffset, bool blitMips = true, int overrideInstanceID = -1)
{
// We handle ourself the 2D blit because cookies needs mipPadding for trilinear filtering
@@ -69,6 +129,36 @@ public override void BlitTexture(CommandBuffer cmd, Vector4 scaleOffset, Texture
}
}
+ public void BlitTextureMultiply(CommandBuffer cmd, Vector4 scaleOffset, Texture texture, Vector4 sourceScaleOffset, bool blitMips = true, int overrideInstanceID = -1)
+ {
+ // We handle ourself the 2D blit because cookies needs mipPadding for trilinear filtering
+ if (Is2D(texture))
+ {
+ Blit2DTexturePaddingMultiply(cmd, scaleOffset, texture, sourceScaleOffset, blitMips);
+ MarkGPUTextureValid(overrideInstanceID != -1 ? overrideInstanceID : texture.GetInstanceID(), blitMips);
+ }
+ }
+
+ public override void BlitOctahedralTexture(CommandBuffer cmd, Vector4 scaleOffset, Texture texture, Vector4 sourceScaleOffset, bool blitMips = true, int overrideInstanceID = -1)
+ {
+ // We handle ourself the 2D blit because cookies needs mipPadding for trilinear filtering
+ if (Is2D(texture))
+ {
+ BlitOctahedralTexturePadding(cmd, scaleOffset, texture, sourceScaleOffset, blitMips);
+ MarkGPUTextureValid(overrideInstanceID != -1 ? overrideInstanceID : texture.GetInstanceID(), blitMips);
+ }
+ }
+
+ public void BlitOctahedralTextureMultiply(CommandBuffer cmd, Vector4 scaleOffset, Texture texture, Vector4 sourceScaleOffset, bool blitMips = true, int overrideInstanceID = -1)
+ {
+ // We handle ourself the 2D blit because cookies needs mipPadding for trilinear filtering
+ if (Is2D(texture))
+ {
+ BlitOctahedralTexturePaddingMultiply(cmd, scaleOffset, texture, sourceScaleOffset, blitMips);
+ MarkGPUTextureValid(overrideInstanceID != -1 ? overrideInstanceID : texture.GetInstanceID(), blitMips);
+ }
+ }
+
void TextureSizeToPowerOfTwo(Texture texture, ref int width, ref int height)
{
// Change the width and height of the texture to be power of two
@@ -79,7 +169,7 @@ void TextureSizeToPowerOfTwo(Texture texture, ref int width, ref int height)
Vector2 GetPowerOfTwoTextureSize(Texture texture)
{
int width = texture.width, height = texture.height;
-
+
TextureSizeToPowerOfTwo(texture, ref width, ref height);
return new Vector2(width, height);
}
@@ -98,9 +188,9 @@ public override bool AllocateTexture(CommandBuffer cmd, ref Vector4 scaleOffset,
return base.AllocateTexture(cmd, ref scaleOffset, texture, width, height);
}
-
+
public void ResetRequestedTexture() => m_RequestedTextures.Clear();
-
+
public bool ReserveSpace(Texture texture)
{
m_RequestedTextures[texture.GetInstanceID()] = new Vector2Int(texture.width, texture.height);
@@ -115,6 +205,20 @@ public bool ReserveSpace(Texture texture)
return true;
}
+ public bool ReserveSpace(int id, int width, int height)
+ {
+ m_RequestedTextures[id] = new Vector2Int(width, height);
+
+ // new texture
+ if (!IsCached(out _, id))
+ {
+ Vector4 scaleBias = Vector4.zero;
+ if (!AllocateTextureWithoutBlit(id, width, height, ref scaleBias))
+ return false;
+ }
+ return true;
+ }
+
///
/// sort all the requested allocation from biggest to smallest and re-insert them.
/// This function does not moves the textures in the atlas, it only changes their coordinates
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/Texture2DAtlas.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/Texture2DAtlas.cs
index 64f36667ff4..9536ee4f2d7 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/Texture2DAtlas.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/Texture2DAtlas.cs
@@ -256,6 +256,13 @@ public virtual void BlitTexture(CommandBuffer cmd, Vector4 scaleOffset, Texture
Blit2DTexture(cmd, scaleOffset, texture, sourceScaleOffset, blitMips);
}
+ public virtual void BlitOctahedralTexture(CommandBuffer cmd, Vector4 scaleOffset, Texture texture, Vector4 sourceScaleOffset, bool blitMips = true, int overrideInstanceID = -1)
+ {
+ // This atlas only support 2D texture so we only blit 2D textures
+ if (Is2D(texture))
+ BlitOctahedralTexture(cmd, scaleOffset, texture, sourceScaleOffset, blitMips);
+ }
+
public virtual bool AllocateTexture(CommandBuffer cmd, ref Vector4 scaleOffset, Texture texture, int width, int height, int overrideInstanceID = -1)
{
bool allocated = AllocateTextureWithoutBlit(texture, width, height, ref scaleOffset);
@@ -263,14 +270,14 @@ public virtual bool AllocateTexture(CommandBuffer cmd, ref Vector4 scaleOffset,
if (allocated)
{
BlitTexture(cmd, scaleOffset, texture, fullScaleOffset);
- MarkGPUTextureValid(overrideInstanceID != -1 ? overrideInstanceID : texture.GetInstanceID(), true); // texture is up to date
+ MarkGPUTextureValid(overrideInstanceID != -1 ? overrideInstanceID : GetTextureID(texture), true); // texture is up to date
}
return allocated;
}
public bool AllocateTextureWithoutBlit(Texture texture, int width, int height, ref Vector4 scaleOffset)
- => AllocateTextureWithoutBlit(texture.GetInstanceID(), width, height, ref scaleOffset);
+ => AllocateTextureWithoutBlit(GetTextureID(texture), width, height, ref scaleOffset);
public virtual bool AllocateTextureWithoutBlit(int instanceId, int width, int height, ref Vector4 scaleOffset)
{
@@ -290,32 +297,54 @@ public virtual bool AllocateTextureWithoutBlit(int instanceId, int width, int he
}
}
- public bool IsCached(out Vector4 scaleOffset, Texture texture)
- => m_AllocationCache.TryGetValue(texture.GetInstanceID(), out scaleOffset);
-
protected int GetTextureHash(Texture texture)
{
int hash = texture.GetHashCode();
unchecked
{
- hash = hash * 23 + texture.graphicsFormat.GetHashCode();
- hash = hash * 23 + texture.wrapMode.GetHashCode();
- hash = hash * 23 + texture.width.GetHashCode();
- hash = hash * 23 + texture.height.GetHashCode();
- hash = hash * 23 + texture.filterMode.GetHashCode();
- hash = hash * 23 + texture.anisoLevel.GetHashCode();
- hash = hash * 23 + texture.mipmapCount.GetHashCode();
+ hash = 23*hash + texture.GetInstanceID().GetHashCode();
+ hash = 23*hash + texture.graphicsFormat.GetHashCode();
+ hash = 23*hash + texture.wrapMode.GetHashCode();
+ hash = 23*hash + texture.width.GetHashCode();
+ hash = 23*hash + texture.height.GetHashCode();
+ hash = 23*hash + texture.filterMode.GetHashCode();
+ hash = 23*hash + texture.anisoLevel.GetHashCode();
+ hash = 23*hash + texture.mipmapCount.GetHashCode();
+ hash = 23*hash + texture.updateCount.GetHashCode();
+
+ RenderTexture rt = texture as RenderTexture;
+ if (rt != null)
+ hash = 23*hash + rt.updateCount.GetHashCode();
}
return hash;
}
+ public int GetTextureID(Texture texture)
+ {
+ return GetTextureHash(texture);
+ }
+
+ public int GetTextureID(Texture textureA, Texture textureB)
+ {
+ return GetTextureHash(textureA) + 23*GetTextureHash(textureB);
+ }
+
+ public bool IsCached(out Vector4 scaleOffset, Texture textureA, Texture textureB)
+ => IsCached(out scaleOffset, GetTextureID(textureA, textureB));
+
+ public bool IsCached(out Vector4 scaleOffset, Texture texture)
+ => IsCached(out scaleOffset, GetTextureID(texture));
+
+ public bool IsCached(out Vector4 scaleOffset, int id)
+ => m_AllocationCache.TryGetValue(id, out scaleOffset);
+
public virtual bool NeedsUpdate(Texture texture, bool needMips = false)
{
RenderTexture rt = texture as RenderTexture;
- int key = texture.GetInstanceID();
- int textureHash = GetTextureHash(texture);
+ int key = GetTextureID(texture);
+ uint textureHash = (uint)key;
// Update the render texture if needed
if (rt != null)
@@ -323,19 +352,56 @@ public virtual bool NeedsUpdate(Texture texture, bool needMips = false)
uint updateCount;
if (m_IsGPUTextureUpToDate.TryGetValue(key, out updateCount))
{
- m_IsGPUTextureUpToDate[key] = rt.updateCount;
- if (rt.updateCount != updateCount)
+ m_IsGPUTextureUpToDate[key] = textureHash;
+ if (rt.updateCount != textureHash)
+ return true;
+ }
+ else
+ {
+ m_IsGPUTextureUpToDate[key] = textureHash;
+ }
+ }
+ // In case the texture settings/import settings have changed, we need to update it
+ else if (m_TextureHashes.TryGetValue(key, out int hash) && hash != textureHash)
+ {
+ m_TextureHashes[key] = key;
+ return true;
+ }
+ // For regular textures, values == 0 means that their GPU data needs to be updated (either because
+ // the atlas have been re-layouted or the texture have never been uploaded. We also check if the mips
+ // are valid for the texture if we need them
+ else if (m_IsGPUTextureUpToDate.TryGetValue(key, out var value))
+ return value == 0 || (needMips && value == 1);
+
+ return false;
+ }
+
+ public virtual bool NeedsUpdate(Texture textureA, Texture textureB, bool needMips = false)
+ {
+ RenderTexture rtA = textureA as RenderTexture;
+ RenderTexture rtB = textureB as RenderTexture;
+ int key = GetTextureID(textureA, textureB);
+ uint textureHash = (uint)key;
+
+ // Update the render texture if needed
+ if (rtA != null || rtB != null)
+ {
+ uint currentHash;
+ if (m_IsGPUTextureUpToDate.TryGetValue(key, out currentHash))
+ {
+ m_IsGPUTextureUpToDate[key] = textureHash;
+ if (textureHash != currentHash)
return true;
}
else
{
- m_IsGPUTextureUpToDate[key] = rt.updateCount;
+ m_IsGPUTextureUpToDate[key] = textureHash;
}
}
// In case the texture settings/import settings have changed, we need to update it
else if (m_TextureHashes.TryGetValue(key, out int hash) && hash != textureHash)
{
- m_TextureHashes[key] = textureHash;
+ m_TextureHashes[key] = key;
return true;
}
// For regular textures, values == 0 means that their GPU data needs to be updated (either because
@@ -367,7 +433,7 @@ public virtual bool UpdateTexture(CommandBuffer cmd, Texture oldTexture, Texture
if (updateIfNeeded && NeedsUpdate(newTexture))
{
BlitTexture(cmd, scaleOffset, newTexture, sourceScaleOffset, blitMips);
- MarkGPUTextureValid(newTexture.GetInstanceID(), blitMips); // texture is up to date
+ MarkGPUTextureValid(GetTextureID(newTexture), blitMips); // texture is up to date
}
return true;
}
diff --git a/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/Blit.shader b/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/Blit.shader
index 20b3a47ba14..f2b3d7e925f 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/Blit.shader
+++ b/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/Blit.shader
@@ -92,7 +92,7 @@ Shader "Hidden/HDRP/Blit"
{
return Frag(input, sampler_LinearClamp);
}
-
+
float4 FragBilinearRepeat(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
@@ -107,6 +107,44 @@ Shader "Hidden/HDRP/Blit"
return SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_PointRepeat, uv, _BlitMipLevel);
}
+ float4 FragOctahedralBilinearRepeat(Varyings input) : SV_Target
+ {
+ UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
+ float u = input.texcoord.x;
+ float v = input.texcoord.y;
+
+ float2 uv;
+ if (u < 0.0f)
+ {
+ if (v < 0.0f)
+ uv = float2(1.0f + u, 1.0f + v);
+ else if (v < 1.0f)
+ uv = float2(-u, 1.0f - v);
+ else
+ uv = float2(1.0f + u, v - 1.0f);
+ }
+ else if (u < 1.0f)
+ {
+ if (v < 0.0f)
+ uv = float2(1.0f - u, -v);
+ else if (v < 1.0f)
+ uv = float2(u, v);
+ else
+ uv = float2(1.0f - u, 2.0f - v);
+ }
+ else
+ {
+ if (v < 0.0f)
+ uv = float2(u - 1.0f, 1.0f + v);
+ else if (v < 1.0f)
+ uv = float2(2.0f - u, 1.0f - v);
+ else
+ uv = float2(u - 1.0f, v - 1.0f);
+ }
+
+ return SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_LinearRepeat, uv, _BlitMipLevel);
+ }
+
ENDHLSL
SubShader
@@ -156,7 +194,7 @@ Shader "Hidden/HDRP/Blit"
#pragma fragment FragBilinear
ENDHLSL
}
-
+
// 4: Nearest quad with padding
Pass
{
@@ -178,7 +216,7 @@ Shader "Hidden/HDRP/Blit"
#pragma fragment FragBilinear
ENDHLSL
}
-
+
// 6: Nearest quad with padding
Pass
{
@@ -201,6 +239,78 @@ Shader "Hidden/HDRP/Blit"
ENDHLSL
}
+ // 8: Bilinear quad with padding (for OctahedralTexture)
+ Pass
+ {
+ ZWrite Off ZTest Always Blend Off Cull Off
+
+ HLSLPROGRAM
+ #pragma vertex VertQuadPadding
+ #pragma fragment FragOctahedralBilinearRepeat
+ ENDHLSL
+ }
+
+ /// Version 4, 5, 6, 7 with Alpha Blending 0.5
+ // 9: Nearest quad with padding alpha blend (4 with alpha blend)
+ Pass
+ {
+ ZWrite Off ZTest Always Blend DstColor Zero Cull Off
+
+ HLSLPROGRAM
+ #pragma vertex VertQuadPadding
+ #pragma fragment FragNearest
+ #define WITH_ALPHA_BLEND
+ ENDHLSL
+ }
+
+ // 10: Bilinear quad with padding alpha blend (5 with alpha blend)
+ Pass
+ {
+ ZWrite Off ZTest Always Blend DstColor Zero Cull Off
+
+ HLSLPROGRAM
+ #pragma vertex VertQuadPadding
+ #pragma fragment FragBilinear
+ #define WITH_ALPHA_BLEND
+ ENDHLSL
+ }
+
+ // 11: Nearest quad with padding alpha blend (6 with alpha blend)
+ Pass
+ {
+ ZWrite Off ZTest Always Blend DstColor Zero Cull Off
+
+ HLSLPROGRAM
+ #pragma vertex VertQuadPadding
+ #pragma fragment FragNearestRepeat
+ #define WITH_ALPHA_BLEND
+ ENDHLSL
+ }
+
+ // 12: Bilinear quad with padding alpha blend (7 with alpha blend)
+ Pass
+ {
+ ZWrite Off ZTest Always Blend DstColor Zero Cull Off
+
+ HLSLPROGRAM
+ #pragma vertex VertQuadPadding
+ #pragma fragment FragBilinearRepeat
+ #define WITH_ALPHA_BLEND
+ ENDHLSL
+ }
+
+ // 13: Bilinear quad with padding alpha blend (for OctahedralTexture) (8 with alpha blend)
+ Pass
+ {
+ ZWrite Off ZTest Always Blend DstColor Zero Cull Off
+
+ HLSLPROGRAM
+ #pragma vertex VertQuadPadding
+ #pragma fragment FragOctahedralBilinearRepeat
+ #define WITH_ALPHA_BLEND
+ ENDHLSL
+ }
+
}
Fallback Off
diff --git a/com.unity.testing.hdrp/RP_Assets/HDRP_Test_Def.asset b/com.unity.testing.hdrp/RP_Assets/HDRP_Test_Def.asset
index 57fcb1b7d61..5cb6df8dc50 100644
--- a/com.unity.testing.hdrp/RP_Assets/HDRP_Test_Def.asset
+++ b/com.unity.testing.hdrp/RP_Assets/HDRP_Test_Def.asset
@@ -12,7 +12,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 0cf1dab834d4ec34195b920ea7bbf9ec, type: 3}
m_Name: HDRP_Test_Def
m_EditorClassIdentifier:
- m_Version: 15
+ m_Version: 16
m_ObsoleteFrameSettings:
overrides: 0
enableShadow: 0
@@ -202,6 +202,7 @@ MonoBehaviour:
supportSSR: 1
supportSSRTransparent: 0
supportSSAO: 1
+ supportSSGI: 0
supportSubsurfaceScattering: 1
sssSampleBudget:
m_Values: 140000002800000050000000
@@ -241,10 +242,9 @@ MonoBehaviour:
atlasOctahedralDepthWidth: 2048
atlasOctahedralDepthHeight: 2048
lightLoopSettings:
- cookieAtlasSize: 4096
+ cookieAtlasSize: 8192
cookieFormat: 74
- pointCookieSize: 512
- cubeCookieTexArraySize: 16
+ pointCookieSize: 256
cookieAtlasLastValidMip: 0
cookieTexArraySize: 1
planarReflectionAtlasSize: 2048
@@ -275,6 +275,8 @@ MonoBehaviour:
shadowAtlasResolution: 4096
shadowAtlasDepthBits: 32
useDynamicViewportRescale: 0
+ cachedPunctualLightShadowAtlas: 2048
+ cachedAreaLightShadowAtlas: 1024
shadowResolutionDirectional:
m_Values: 00010000000200000004000000000000
m_SchemaId:
@@ -359,6 +361,37 @@ MonoBehaviour:
AODirectionCount: 010000000200000004000000
ContactShadowSampleCount: 060000000a00000010000000
SSRMaxRaySteps: 100000002000000040000000
+ RTAORayLength:
+ - 0.5
+ - 3
+ - 20
+ RTAOSampleCount: 010000000200000008000000
+ RTAODenoise: 010101
+ RTAODenoiserRadius:
+ - 0.25
+ - 0.5
+ - 0.65
+ RTGIRayLength:
+ - 50
+ - 50
+ - 50
+ RTGIFullResolution: 000001
+ RTGIClampValue:
+ - 0.5
+ - 0.8
+ - 1.5
+ RTGIUpScaleRadius: 040000000400000004000000
+ RTGIDenoise: 010101
+ RTGIHalfResDenoise: 010000
+ RTGIDenoiserRadius:
+ - 0.66
+ - 0.66
+ - 1
+ RTGISecondDenoise: 010101
+ RTGISecondDenoiserRadius:
+ - 0.33
+ - 0.33
+ - 0.5
allowShaderVariantStripping: 1
enableSRPBatcher: 1
shaderVariantLogLevel: 0
@@ -390,3 +423,8 @@ MonoBehaviour:
- RedPP, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
afterPostProcessCustomPostProcesses:
- BluePP, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
+ virtualTexturingSettings:
+ streamingCpuCacheSizeInMegaBytes: 256
+ streamingGpuCacheSettings:
+ - format: 0
+ sizeInMegaBytes: 128