From 7d52e49dae51c7e20aff5002348420a057d7263b Mon Sep 17 00:00:00 2001 From: skhiat Date: Tue, 21 Apr 2020 11:25:36 +0200 Subject: [PATCH 1/8] IES Importe & Generate 2D/Cube/Equirectangular Textues --- .../Editor/Lighting/IESEngine.cs | 413 ++++++++++++++ .../Editor/Lighting/IESEngine.cs.meta | 11 + .../Editor/Lighting/IESImporter.cs | 137 +++++ .../Editor/Lighting/IESImporter.cs.meta | 11 + .../Editor/Lighting/IESImporterEditor.cs | 197 +++++++ .../Editor/Lighting/IESImporterEditor.cs.meta | 11 + .../Editor/Lighting/IESReader.cs | 526 ++++++++++++++++++ .../Editor/Lighting/IESReader.cs.meta | 11 + .../Editor/AssetProcessors/HDIESImporter.cs | 30 + .../AssetProcessors/HDIESImporter.cs.meta | 11 + .../AssetProcessors/HDIESImporterEditor.cs | 119 ++++ .../HDIESImporterEditor.cs.meta | 11 + 12 files changed, 1488 insertions(+) create mode 100644 com.unity.render-pipelines.core/Editor/Lighting/IESEngine.cs create mode 100644 com.unity.render-pipelines.core/Editor/Lighting/IESEngine.cs.meta create mode 100644 com.unity.render-pipelines.core/Editor/Lighting/IESImporter.cs create mode 100644 com.unity.render-pipelines.core/Editor/Lighting/IESImporter.cs.meta create mode 100644 com.unity.render-pipelines.core/Editor/Lighting/IESImporterEditor.cs create mode 100644 com.unity.render-pipelines.core/Editor/Lighting/IESImporterEditor.cs.meta create mode 100644 com.unity.render-pipelines.core/Editor/Lighting/IESReader.cs create mode 100644 com.unity.render-pipelines.core/Editor/Lighting/IESReader.cs.meta create mode 100644 com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporter.cs create mode 100644 com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporter.cs.meta create mode 100644 com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporterEditor.cs create mode 100644 com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporterEditor.cs.meta 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..5bd51adae6a --- /dev/null +++ b/com.unity.render-pipelines.core/Editor/Lighting/IESEngine.cs @@ -0,0 +1,413 @@ +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 + + public class IESEngine + { + const float k_HalfPi = 0.5f * Mathf.PI; + const float k_TwoPi = 2.0f * Mathf.PI; + + // k_MinTextureSize should be 32, but using a larger value to minimize Unity's issue with cubemap cookies made from low-resolution latitude-longitude images. + // When used, such a cubemap cookie North-South axis is visually tilted compared to its point light Y axis. + // In other words, when the light Y rotation is modified, the cookie highlights and shadows wriggles on the floor and walls. + const int k_MinTextureSize = 256; // power of two >= 32 + const int k_MaxTextureSize = 2048; // power of two <= 2048 + + const int k_CylindricalTextureHeight = 256; // for 180 latitudinal degrees + const int k_CylindricalTextureWidth = 2 * k_CylindricalTextureHeight; // for 360 longitudinal degrees + + IESReader m_IesReader = new IESReader(); + + public string FileFormatVersion { get => m_IesReader.FileFormatVersion; } + + TextureImporterType m_TextureGenerationType = TextureImporterType.Cookie; + public TextureImporterType TextureGenerationType + { + set { m_TextureGenerationType = value; } + } + + 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; + } + + public string GetKeywordValue(string keyword) + { + return m_IesReader.GetKeywordValue(keyword); + } + + 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"; + } + } + + public (float, string) GetMaximumIntensity() + { + if (m_IesReader.TotalLumens == -1f) // absolute photometry + { + return (m_IesReader.MaxCandelas, "Candelas"); + } + else + { + return (m_IesReader.TotalLumens, "Lumens"); + } + } + + public (string, Texture) GenerateCubeCookie(TextureImporterCompression compression) + { + int width = Mathf.NextPowerOfTwo(Mathf.Clamp(m_IesReader.GetMinHorizontalSampleCount(), k_MinTextureSize, k_MaxTextureSize)); // for 360 longitudinal degrees + int height = Mathf.NextPowerOfTwo(Mathf.Clamp(m_IesReader.GetMinVerticalSampleCount(), k_MinTextureSize, k_MaxTextureSize)); // for 180 latitudinal degrees + + 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 + 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); + } + + public (string, Texture) GenerateCylindricalTexture(TextureImporterCompression compression) + { + int width = k_CylindricalTextureWidth; // for 360 longitudinal degrees + int height = k_CylindricalTextureHeight; // for 180 latitudinal degrees + + 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..a050105cdde --- /dev/null +++ b/com.unity.render-pipelines.core/Editor/Lighting/IESImporter.cs @@ -0,0 +1,137 @@ +using System.IO; +using UnityEditor; +using UnityEditor.Experimental.AssetImporters; +using UnityEngine; + +namespace UnityEditor.Rendering +{ + public enum IESLightType + { + Point, + Spot, + } + + public abstract class IESImporter : ScriptedImporter + { + public string FileFormatVersion; + public string IesPhotometricType; + public float IesMaximumIntensity; + public string IesMaximumIntensityUnit; + + // IES luminaire product information. + public string Manufacturer; // IES keyword MANUFAC + public string LuminaireCatalogNumber; // IES keyword LUMCAT + public string LuminaireDescription; // IES keyword LUMINAIRE + public string LampCatalogNumber; // IES keyword LAMPCAT + public string LampDescription; // IES keyword LAMP + + public IESLightType PrefabLightType = IESLightType.Point; + + [Range(1f, 179f)] + public float SpotAngle = 120f; + [Range(32, 2048)] + public int SpotCookieSize = 512; + public bool ApplyLightAttenuation = true; + public bool UseIesMaximumIntensity = true; + + public TextureImporterCompression CookieCompression = TextureImporterCompression.Uncompressed; + + [Range(-180f, 180f)] + public float LightAimAxisRotation = -90f; + + public abstract void SetupIesEngineForRenderPipeline(IESEngine engine); + public abstract void SetupRenderPipelinePrefabLight(IESEngine engine, Light light); + + public override void OnImportAsset(AssetImportContext ctx) + { + var engine = new IESEngine(); + + SetupIesEngineForRenderPipeline(engine); + + Texture cookieTextureCube = null; + Texture cookieTexture2D = null; + Texture cylindricalTexture = null; + + string iesFilePath = Path.Combine(Path.GetDirectoryName(Application.dataPath), ctx.assetPath); + + string errorMessage = engine.ReadFile(iesFilePath); + + if (string.IsNullOrEmpty(errorMessage)) + { + FileFormatVersion = engine.FileFormatVersion; + IesPhotometricType = engine.GetPhotometricType(); + Manufacturer = engine.GetKeywordValue("MANUFAC"); + LuminaireCatalogNumber = engine.GetKeywordValue("LUMCAT"); + LuminaireDescription = engine.GetKeywordValue("LUMINAIRE"); + LampCatalogNumber = engine.GetKeywordValue("LAMPCAT"); + LampDescription = engine.GetKeywordValue("LAMP"); + + (IesMaximumIntensity, IesMaximumIntensityUnit) = engine.GetMaximumIntensity(); + + string warningMessage; + + + (warningMessage, cookieTextureCube) = engine.GenerateCubeCookie(CookieCompression); + + if (!string.IsNullOrEmpty(warningMessage)) + { + ctx.LogImportWarning($"Cannot properly generate IES Cube texture: {warningMessage}"); + } + + (warningMessage, cookieTexture2D) = engine.Generate2DCookie(CookieCompression, SpotAngle, SpotCookieSize, ApplyLightAttenuation); + + if (!string.IsNullOrEmpty(warningMessage)) + { + ctx.LogImportWarning($"Cannot properly generate IES 2D texture: {warningMessage}"); + } + + (warningMessage, cylindricalTexture) = engine.GenerateCylindricalTexture(CookieCompression); + + if (!string.IsNullOrEmpty(warningMessage)) + { + ctx.LogImportWarning($"Cannot properly generate IES latitude-longitude texture: {warningMessage}"); + } + } + else + { + ctx.LogImportError($"Cannot read IES file '{iesFilePath}': {errorMessage}"); + } + + string iesFileName = Path.GetFileNameWithoutExtension(ctx.assetPath); + + var lightObject = new GameObject(iesFileName); + + lightObject.transform.localEulerAngles = new Vector3(90f, 0f, LightAimAxisRotation); + + Light light = lightObject.AddComponent(); + light.type = (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 = SpotAngle; + light.cookie = (PrefabLightType == IESLightType.Point) ? cookieTextureCube : cookieTexture2D; + + SetupRenderPipelinePrefabLight(engine, light); + + // The light object will be automatically converted into a prefab. + ctx.AddObjectToAsset(iesFileName, lightObject); + ctx.SetMainObject(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); + } + + if (cylindricalTexture != null) + { + cylindricalTexture.name = iesFileName + "-Cylindrical-IES"; + ctx.AddObjectToAsset(cylindricalTexture.name, cylindricalTexture); + } + } + } +} 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..0e3b704e72d --- /dev/null +++ b/com.unity.render-pipelines.core/Editor/Lighting/IESImporterEditor.cs @@ -0,0 +1,197 @@ +using System.Reflection; +using UnityEditor; +using UnityEditor.Experimental.AssetImporters; +using UnityEngine; +using UnityEngine.Rendering; + +namespace UnityEditor.Rendering +{ + public abstract class IESImporterEditor : ScriptedImporterEditor + { + 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_SpotCookieSizeProp; + 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; + + public override void OnEnable() + { + base.OnEnable(); + + m_WordWrapStyle.wordWrap = true; + + m_FileFormatVersionProp = serializedObject.FindProperty("FileFormatVersion"); + m_IesPhotometricTypeProp = serializedObject.FindProperty("IesPhotometricType"); + m_IesMaximumIntensityProp = serializedObject.FindProperty("IesMaximumIntensity"); + m_IesMaximumIntensityUnitProp = serializedObject.FindProperty("IesMaximumIntensityUnit"); + + m_ManufacturerProp = serializedObject.FindProperty("Manufacturer"); + m_LuminaireCatalogNumberProp = serializedObject.FindProperty("LuminaireCatalogNumber"); + m_LuminaireDescriptionProp = serializedObject.FindProperty("LuminaireDescription"); + m_LampCatalogNumberProp = serializedObject.FindProperty("LampCatalogNumber"); + m_LampDescriptionProp = serializedObject.FindProperty("LampDescription"); + + m_PrefabLightTypeProp = serializedObject.FindProperty("PrefabLightType"); + m_SpotAngleProp = serializedObject.FindProperty("SpotAngle"); + m_SpotCookieSizeProp = serializedObject.FindProperty("SpotCookieSize"); + m_ApplyLightAttenuationProp = serializedObject.FindProperty("ApplyLightAttenuation"); + m_UseIesMaximumIntensityProp = serializedObject.FindProperty("UseIesMaximumIntensity"); + m_CookieCompressionProp = serializedObject.FindProperty("CookieCompression"); + m_LightAimAxisRotationProp = serializedObject.FindProperty("LightAimAxisRotation"); + } + + public override void OnInspectorGUI() + { + 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_SpotCookieSizeProp, new GUIContent("Cookie Size")); + EditorGUILayout.PropertyField(m_ApplyLightAttenuationProp); + + EditorGUILayout.PropertyField(m_CookieCompressionProp); + + LayoutRenderPipelineUseIesMaximumIntensity(); + + using (new EditorGUILayout.HorizontalScope()) + { + EditorGUILayout.PropertyField(m_LightAimAxisRotationProp, new GUIContent("Aim Axis Rotation")); + + if (GUILayout.Button("Reset", GUILayout.Width(44))) + { + m_LightAimAxisRotationProp.floatValue = -90f; + } + } + } + + serializedObject.ApplyModifiedProperties(); + + ApplyRevertGUI(); + } + + protected override void Apply() + { + base.Apply(); + + if (m_PreviewRenderUtility != null) + { + m_PreviewRenderUtility.Cleanup(); + m_PreviewRenderUtility = null; + } + } + + public override bool HasPreviewGUI() + { + 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; + } + + public abstract void LayoutRenderPipelineUseIesMaximumIntensity(); + public abstract void SetupRenderPipelinePreviewCamera(Camera camera); + public abstract void SetupRenderPipelinePreviewLight(Light light); + public abstract void SetupRenderPipelinePreviewWallRenderer(MeshRenderer wallRenderer); + public abstract void SetupRenderPipelinePreviewFloorRenderer(MeshRenderer floorRenderer); + public abstract void SetupRenderPipelinePreviewLightIntensity(Light light); + + void OnDestroy() + { + 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/IESReader.cs b/com.unity.render-pipelines.core/Editor/Lighting/IESReader.cs new file mode 100644 index 00000000000..3eeada9fea8 --- /dev/null +++ b/com.unity.render-pipelines.core/Editor/Lighting/IESReader.cs @@ -0,0 +1,526 @@ +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text.RegularExpressions; +using UnityEngine; + +namespace UnityEditor.Rendering +{ + public class IESReader + { + string m_FileFormatVersion; + public string FileFormatVersion + { + get { return m_FileFormatVersion; } + } + + float m_TotalLumens; + public float TotalLumens + { + get { return m_TotalLumens; } + } + + float m_MaxCandelas; + public float MaxCandelas + { + get { return m_MaxCandelas; } + } + + int m_PhotometricType; + 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/ + public string ReadFile(string iesFilePath) + { + // Uncomment the next line to enable the generation of a log file. + // using (var logWriter = File.CreateText(iesFilePath.Replace(".ies", ".log"))) + + using (var iesReader = File.OpenText(iesFilePath)) + { + // Uncomment the next line when the generation of a log file is enabled. + // logWriter.AutoFlush = true; + + 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; + + // The next line is an example of log writing when the generation of a log file is enabled. + // logWriter.WriteLine($"{iesDataTokens.Length} IES data tokens"); + + 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; + } + + public string GetKeywordValue(string keyword) + { + return m_KeywordDictionary.ContainsKey(keyword) ? m_KeywordDictionary[keyword] : string.Empty; + } + + public 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 + } + } + + public 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 + } + } + + public float ComputeVerticalAnglePosition(float angle) + { + return ComputeAnglePosition(angle, m_VerticalAngles); + } + + public float ComputeTypeAorBHorizontalAnglePosition(float angle) // angle in range [-180..+180] degrees + { + return ComputeAnglePosition(((m_FirstHorizontalAngle == 0f) ? Mathf.Abs(angle) : angle), m_HorizontalAngles); + } + + public 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); + } + + 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; + } + + public 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); + } + + 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.high-definition/Editor/AssetProcessors/HDIESImporter.cs b/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporter.cs new file mode 100644 index 00000000000..008963eb1e6 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporter.cs @@ -0,0 +1,30 @@ +using UnityEditor; +using UnityEngine; +using UnityEngine.Rendering.HighDefinition; +using UnityEngine.Rendering; +using UnityEditor.Experimental.AssetImporters; + +namespace UnityEditor.Rendering.HighDefinition +{ + [ScriptedImporter(1, "ies")] + public class HDIESImporter : UnityEditor.Rendering.IESImporter + { + public override void SetupIesEngineForRenderPipeline(IESEngine engine) + { + engine.TextureGenerationType = TextureImporterType.Default; + } + + public override void SetupRenderPipelinePrefabLight(IESEngine engine, Light light) + { + HDLightTypeAndShape hdLightTypeAndShape = (light.type == LightType.Point) ? HDLightTypeAndShape.Point : HDLightTypeAndShape.ConeSpot; + + HDAdditionalLightData hdLight = GameObjectExtension.AddHDLight(light.gameObject, hdLightTypeAndShape); + + if (UseIesMaximumIntensity) + { + LightUnit lightUnit = (IesMaximumIntensityUnit == "Lumens") ? LightUnit.Lumen : LightUnit.Candela; + hdLight.SetIntensity(IesMaximumIntensity, lightUnit); + } + } + } +} 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..bd4da6322c7 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporterEditor.cs @@ -0,0 +1,119 @@ +using System.Reflection; +using UnityEditor; +using UnityEngine; +using UnityEngine.Rendering.HighDefinition; +using UnityEngine.Rendering; + +namespace UnityEditor.Rendering.HighDefinition +{ + [CustomEditor(typeof(IESImporter))] + public class HDIESImporterEditor : UnityEditor.Rendering.IESImporterEditor + { + public override void LayoutRenderPipelineUseIesMaximumIntensity() + { + // 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")); + } + + public override 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); + } + + public override 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; + } + + public override void SetupRenderPipelinePreviewWallRenderer(MeshRenderer wallRenderer) + { + wallRenderer.material = AssetDatabase.LoadAssetAtPath("Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDMaterial.mat"); + } + + public override void SetupRenderPipelinePreviewFloorRenderer(MeshRenderer floorRenderer) + { + floorRenderer.material = AssetDatabase.LoadAssetAtPath("Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDMaterial.mat"); + } + + public override void SetupRenderPipelinePreviewLightIntensity(Light light) + { + // Before enabling this feature, more experimentation is needed with the addition of a Volume in the PreviewRenderUtility scene. + + // HDAdditionalLightData hdLight = light.GetComponent(); + // + // if (m_UseIesMaximumIntensityProp.boolValue) + // { + // LightUnit lightUnit = (m_IesMaximumIntensityUnitProp.stringValue == "Lumens") ? LightUnit.Lumen : LightUnit.Candela; + // hdLight.SetIntensity(m_IesMaximumIntensityProp.floatValue, lightUnit); + // } + // else + // { + // hdLight.SetIntensity(20000f, LightUnit.Lumen); + // } + } + + public override GUIContent GetPreviewTitle() + { + return new GUIContent("IES Luminaire Profile"); + } + + public override void OnPreviewGUI(Rect r, GUIStyle background) + { + if (Event.current.type == EventType.Repaint) + { + Texture cookieTexture = null; + Texture previewTexture = null; + + foreach (var subAsset in AssetDatabase.LoadAllAssetRepresentationsAtPath((target as IESImporter).assetPath)) + { + if (subAsset.name.EndsWith("-Cookie")) + { + 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_PreviewRenderUtility.lights[0].cookie = cookieTexture; + + 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); + } + } + } + } +} 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: From fc4e388bd20dd88af709d003aba9d51624b73aab Mon Sep 17 00:00:00 2001 From: skhiat Date: Wed, 22 Apr 2020 18:02:51 +0200 Subject: [PATCH 2/8] Enable PreviewGUI for IES Light, Split Core & HDRP --- .../Editor/Lighting/IESEngine.cs | 1 + .../Editor/Lighting/IESImporter.cs | 67 +++---- .../Editor/Lighting/IESImporterEditor.cs | 189 +++++++++++++----- .../Editor/Lighting/IESReader.cs | 1 + .../Editor/AssetProcessors/HDIESImporter.cs | 26 ++- .../AssetProcessors/HDIESImporterEditor.cs | 116 ++++++----- 6 files changed, 261 insertions(+), 139 deletions(-) diff --git a/com.unity.render-pipelines.core/Editor/Lighting/IESEngine.cs b/com.unity.render-pipelines.core/Editor/Lighting/IESEngine.cs index 5bd51adae6a..794d916cb37 100644 --- a/com.unity.render-pipelines.core/Editor/Lighting/IESEngine.cs +++ b/com.unity.render-pipelines.core/Editor/Lighting/IESEngine.cs @@ -10,6 +10,7 @@ namespace UnityEditor.Rendering // 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 + [System.Serializable] public class IESEngine { const float k_HalfPi = 0.5f * Mathf.PI; diff --git a/com.unity.render-pipelines.core/Editor/Lighting/IESImporter.cs b/com.unity.render-pipelines.core/Editor/Lighting/IESImporter.cs index a050105cdde..83dc8a7f3dd 100644 --- a/com.unity.render-pipelines.core/Editor/Lighting/IESImporter.cs +++ b/com.unity.render-pipelines.core/Editor/Lighting/IESImporter.cs @@ -11,12 +11,13 @@ public enum IESLightType Spot, } - public abstract class IESImporter : ScriptedImporter + [System.Serializable] + public class IESMetaData { public string FileFormatVersion; - public string IesPhotometricType; - public float IesMaximumIntensity; - public string IesMaximumIntensityUnit; + public string IESPhotometricType; + public float IESMaximumIntensity; + public string IESMaximumIntensityUnit; // IES luminaire product information. public string Manufacturer; // IES keyword MANUFAC @@ -32,61 +33,58 @@ public abstract class IESImporter : ScriptedImporter [Range(32, 2048)] public int SpotCookieSize = 512; public bool ApplyLightAttenuation = true; - public bool UseIesMaximumIntensity = true; + public bool UseIESMaximumIntensity = true; public TextureImporterCompression CookieCompression = TextureImporterCompression.Uncompressed; [Range(-180f, 180f)] public float LightAimAxisRotation = -90f; + } - public abstract void SetupIesEngineForRenderPipeline(IESEngine engine); - public abstract void SetupRenderPipelinePrefabLight(IESEngine engine, Light light); - - public override void OnImportAsset(AssetImportContext ctx) - { - var engine = new IESEngine(); + [System.Serializable] + public class IESImporter + { + public IESEngine engine = new IESEngine(); + public IESMetaData iesMetaData = new IESMetaData(); - SetupIesEngineForRenderPipeline(engine); + public delegate void SetupRenderPipelinePrefabLight(IESEngine engine, Light light); + public void CommonOnImportAsset(AssetImportContext ctx, SetupRenderPipelinePrefabLight setupRenderPipelinePrefabLight) + { Texture cookieTextureCube = null; Texture cookieTexture2D = null; Texture cylindricalTexture = null; - string iesFilePath = Path.Combine(Path.GetDirectoryName(Application.dataPath), ctx.assetPath); - + string iesFilePath = Path.Combine(Path.GetDirectoryName(Application.dataPath), ctx.assetPath); string errorMessage = engine.ReadFile(iesFilePath); if (string.IsNullOrEmpty(errorMessage)) { - FileFormatVersion = engine.FileFormatVersion; - IesPhotometricType = engine.GetPhotometricType(); - Manufacturer = engine.GetKeywordValue("MANUFAC"); - LuminaireCatalogNumber = engine.GetKeywordValue("LUMCAT"); - LuminaireDescription = engine.GetKeywordValue("LUMINAIRE"); - LampCatalogNumber = engine.GetKeywordValue("LAMPCAT"); - LampDescription = engine.GetKeywordValue("LAMP"); + 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"); - (IesMaximumIntensity, IesMaximumIntensityUnit) = engine.GetMaximumIntensity(); + (iesMetaData.IESMaximumIntensity, iesMetaData.IESMaximumIntensityUnit) = engine.GetMaximumIntensity(); string warningMessage; - - (warningMessage, cookieTextureCube) = engine.GenerateCubeCookie(CookieCompression); - + (warningMessage, cookieTextureCube) = engine.GenerateCubeCookie(iesMetaData.CookieCompression); if (!string.IsNullOrEmpty(warningMessage)) { ctx.LogImportWarning($"Cannot properly generate IES Cube texture: {warningMessage}"); } - (warningMessage, cookieTexture2D) = engine.Generate2DCookie(CookieCompression, SpotAngle, SpotCookieSize, ApplyLightAttenuation); - + (warningMessage, cookieTexture2D) = engine.Generate2DCookie(iesMetaData.CookieCompression, iesMetaData.SpotAngle, iesMetaData.SpotCookieSize, iesMetaData.ApplyLightAttenuation); if (!string.IsNullOrEmpty(warningMessage)) { ctx.LogImportWarning($"Cannot properly generate IES 2D texture: {warningMessage}"); } - (warningMessage, cylindricalTexture) = engine.GenerateCylindricalTexture(CookieCompression); - + (warningMessage, cylindricalTexture) = engine.GenerateCylindricalTexture(iesMetaData.CookieCompression); if (!string.IsNullOrEmpty(warningMessage)) { ctx.LogImportWarning($"Cannot properly generate IES latitude-longitude texture: {warningMessage}"); @@ -101,16 +99,16 @@ public override void OnImportAsset(AssetImportContext ctx) var lightObject = new GameObject(iesFileName); - lightObject.transform.localEulerAngles = new Vector3(90f, 0f, LightAimAxisRotation); + lightObject.transform.localEulerAngles = new Vector3(90f, 0f, iesMetaData.LightAimAxisRotation); Light light = lightObject.AddComponent(); - light.type = (PrefabLightType == IESLightType.Point) ? LightType.Point : LightType.Spot; + 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 = SpotAngle; - light.cookie = (PrefabLightType == IESLightType.Point) ? cookieTextureCube : cookieTexture2D; + light.spotAngle = iesMetaData.SpotAngle; + light.cookie = (iesMetaData.PrefabLightType == IESLightType.Point) ? cookieTextureCube : cookieTexture2D; - SetupRenderPipelinePrefabLight(engine, light); + setupRenderPipelinePrefabLight(engine, light); // The light object will be automatically converted into a prefab. ctx.AddObjectToAsset(iesFileName, lightObject); @@ -126,7 +124,6 @@ public override void OnImportAsset(AssetImportContext ctx) cookieTexture2D.name = iesFileName + "-2D-IES"; ctx.AddObjectToAsset(cookieTexture2D.name, cookieTexture2D); } - if (cylindricalTexture != null) { cylindricalTexture.name = iesFileName + "-Cylindrical-IES"; diff --git a/com.unity.render-pipelines.core/Editor/Lighting/IESImporterEditor.cs b/com.unity.render-pipelines.core/Editor/Lighting/IESImporterEditor.cs index 0e3b704e72d..39f8f702fac 100644 --- a/com.unity.render-pipelines.core/Editor/Lighting/IESImporterEditor.cs +++ b/com.unity.render-pipelines.core/Editor/Lighting/IESImporterEditor.cs @@ -6,14 +6,14 @@ namespace UnityEditor.Rendering { - public abstract class IESImporterEditor : ScriptedImporterEditor + public class IESImporterEditor { GUIStyle m_WordWrapStyle = new GUIStyle(); SerializedProperty m_FileFormatVersionProp; - SerializedProperty m_IesPhotometricTypeProp; - SerializedProperty m_IesMaximumIntensityProp; - SerializedProperty m_IesMaximumIntensityUnitProp; + SerializedProperty m_IESPhotometricTypeProp; + SerializedProperty m_IESMaximumIntensityProp; + SerializedProperty m_IESMaximumIntensityUnitProp; SerializedProperty m_ManufacturerProp; SerializedProperty m_LuminaireCatalogNumberProp; @@ -25,8 +25,11 @@ public abstract class IESImporterEditor : ScriptedImporterEditor SerializedProperty m_SpotAngleProp; SerializedProperty m_SpotCookieSizeProp; SerializedProperty m_ApplyLightAttenuationProp; - SerializedProperty m_UseIesMaximumIntensityProp; + SerializedProperty m_UseIESMaximumIntensityProp; SerializedProperty m_CookieCompressionProp; + + //IESMetaData iesMetaData; + protected SerializedProperty m_LightAimAxisRotationProp; bool m_ShowLuminaireProductInformation = true; @@ -34,43 +37,48 @@ public abstract class IESImporterEditor : ScriptedImporterEditor protected PreviewRenderUtility m_PreviewRenderUtility = null; - public override void OnEnable() - { - base.OnEnable(); + public delegate void LayoutRenderPipelineUseIesMaximumIntensity(); + public delegate void SetupRenderPipelinePreviewCamera(Camera camera); + public delegate void SetupRenderPipelinePreviewLight(Light light); + public delegate void SetupRenderPipelinePreviewWallRenderer(MeshRenderer wallRenderer); + public delegate void SetupRenderPipelinePreviewFloorRenderer(MeshRenderer floorRenderer); + public delegate void SetupRenderPipelinePreviewLightIntensity(Light light); + public void CommonOnEnable(SerializedProperty serializedObject) + { m_WordWrapStyle.wordWrap = true; - m_FileFormatVersionProp = serializedObject.FindProperty("FileFormatVersion"); - m_IesPhotometricTypeProp = serializedObject.FindProperty("IesPhotometricType"); - m_IesMaximumIntensityProp = serializedObject.FindProperty("IesMaximumIntensity"); - m_IesMaximumIntensityUnitProp = serializedObject.FindProperty("IesMaximumIntensityUnit"); - - m_ManufacturerProp = serializedObject.FindProperty("Manufacturer"); - m_LuminaireCatalogNumberProp = serializedObject.FindProperty("LuminaireCatalogNumber"); - m_LuminaireDescriptionProp = serializedObject.FindProperty("LuminaireDescription"); - m_LampCatalogNumberProp = serializedObject.FindProperty("LampCatalogNumber"); - m_LampDescriptionProp = serializedObject.FindProperty("LampDescription"); - - m_PrefabLightTypeProp = serializedObject.FindProperty("PrefabLightType"); - m_SpotAngleProp = serializedObject.FindProperty("SpotAngle"); - m_SpotCookieSizeProp = serializedObject.FindProperty("SpotCookieSize"); - m_ApplyLightAttenuationProp = serializedObject.FindProperty("ApplyLightAttenuation"); - m_UseIesMaximumIntensityProp = serializedObject.FindProperty("UseIesMaximumIntensity"); - m_CookieCompressionProp = serializedObject.FindProperty("CookieCompression"); - m_LightAimAxisRotationProp = serializedObject.FindProperty("LightAimAxisRotation"); + 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_SpotCookieSizeProp = serializedObject.FindPropertyRelative("SpotCookieSize"); + m_ApplyLightAttenuationProp = serializedObject.FindPropertyRelative("ApplyLightAttenuation"); + m_UseIESMaximumIntensityProp = serializedObject.FindPropertyRelative("UseIESMaximumIntensity"); + m_CookieCompressionProp = serializedObject.FindPropertyRelative("CookieCompression"); + m_LightAimAxisRotationProp = serializedObject.FindPropertyRelative("LightAimAxisRotation"); } - public override void OnInspectorGUI() + public void CommonOnInspectorGUI(ScriptedImporterEditor scriptedImporter, LayoutRenderPipelineUseIesMaximumIntensity layoutRenderPipelineUseIesMaximumIntensity) { - serializedObject.Update(); + 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}"); + 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_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); @@ -82,12 +90,12 @@ public override void OnInspectorGUI() EditorGUILayout.PropertyField(m_PrefabLightTypeProp, new GUIContent("Light Type")); EditorGUILayout.PropertyField(m_SpotAngleProp); - EditorGUILayout.PropertyField(m_SpotCookieSizeProp, new GUIContent("Cookie Size")); + EditorGUILayout.PropertyField(m_SpotCookieSizeProp, new GUIContent("IES Size")); EditorGUILayout.PropertyField(m_ApplyLightAttenuationProp); EditorGUILayout.PropertyField(m_CookieCompressionProp); - LayoutRenderPipelineUseIesMaximumIntensity(); + layoutRenderPipelineUseIesMaximumIntensity(); using (new EditorGUILayout.HorizontalScope()) { @@ -100,15 +108,49 @@ public override void OnInspectorGUI() } } - serializedObject.ApplyModifiedProperties(); + scriptedImporter.serializedObject.ApplyModifiedProperties(); + + 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_SpotCookieSizeProp, new GUIContent("IES Size")); + EditorGUILayout.PropertyField(m_ApplyLightAttenuationProp); + + EditorGUILayout.PropertyField(m_CookieCompressionProp); + + layoutRenderPipelineUseIesMaximumIntensity(); + + using (new EditorGUILayout.HorizontalScope()) + { + EditorGUILayout.PropertyField(m_LightAimAxisRotationProp, new GUIContent("Aim Axis Rotation")); - ApplyRevertGUI(); + if (GUILayout.Button("Reset", GUILayout.Width(44))) + { + m_LightAimAxisRotationProp.floatValue = -90f; + } + } + } + + scriptedImporter.serializedObject.ApplyModifiedProperties(); } - protected override void Apply() + public void CommonApply() { - base.Apply(); - if (m_PreviewRenderUtility != null) { m_PreviewRenderUtility.Cleanup(); @@ -116,7 +158,10 @@ protected override void Apply() } } - public override bool HasPreviewGUI() + public bool CommonHasPreviewGUI(SetupRenderPipelinePreviewCamera setupRenderPipelinePreviewCamera, + SetupRenderPipelinePreviewLight setupRenderPipelinePreviewLight, + SetupRenderPipelinePreviewWallRenderer setupRenderPipelinePreviewWallRenderer, + SetupRenderPipelinePreviewFloorRenderer setupRenderPipelinePreviewFloorRenderer) { if (m_PreviewRenderUtility == null) { @@ -130,7 +175,7 @@ public override bool HasPreviewGUI() 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); + 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; @@ -140,7 +185,7 @@ public override bool HasPreviewGUI() 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]); + setupRenderPipelinePreviewLight(m_PreviewRenderUtility.lights[0]); m_PreviewRenderUtility.lights[1].intensity = 0f; @@ -155,7 +200,7 @@ public override bool HasPreviewGUI() previewWallRenderer.reflectionProbeUsage = ReflectionProbeUsage.Off; previewWallRenderer.material = AssetDatabase.GetBuiltinExtraResource("Default-Material.mat"); - SetupRenderPipelinePreviewWallRenderer(previewWallRenderer); + setupRenderPipelinePreviewWallRenderer(previewWallRenderer); m_PreviewRenderUtility.AddSingleGO(previewWall); @@ -170,7 +215,7 @@ public override bool HasPreviewGUI() previewFloorRenderer.reflectionProbeUsage = ReflectionProbeUsage.Off; previewFloorRenderer.material = AssetDatabase.GetBuiltinExtraResource("Default-Diffuse.mat"); - SetupRenderPipelinePreviewFloorRenderer(previewFloorRenderer); + setupRenderPipelinePreviewFloorRenderer(previewFloorRenderer); m_PreviewRenderUtility.AddSingleGO(previewFloor); } @@ -178,14 +223,58 @@ public override bool HasPreviewGUI() return true; } - public abstract void LayoutRenderPipelineUseIesMaximumIntensity(); - public abstract void SetupRenderPipelinePreviewCamera(Camera camera); - public abstract void SetupRenderPipelinePreviewLight(Light light); - public abstract void SetupRenderPipelinePreviewWallRenderer(MeshRenderer wallRenderer); - public abstract void SetupRenderPipelinePreviewFloorRenderer(MeshRenderer floorRenderer); - public abstract void SetupRenderPipelinePreviewLightIntensity(Light light); + public GUIContent CommonGetPreviewTitle() + { + return new GUIContent("IES Luminaire Profile"); + } + + public void CommonOnPreviewGUI(Rect r, GUIStyle background, ScriptedImporter target, + SetupRenderPipelinePreviewLightIntensity setupRenderPipelinePreviewLightIntensity) + { + if (Event.current.type == EventType.Repaint) + { + Texture cookieTexture = null; + Texture previewTexture = null; + + foreach (var subAsset in AssetDatabase.LoadAllAssetRepresentationsAtPath(target.assetPath)) + { + if (subAsset.name.EndsWith("-Cube-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_PreviewRenderUtility.lights[0].cookie = cookieTexture; + + 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); + } + } + } - void OnDestroy() + public void CommonOnDisable() { if (m_PreviewRenderUtility != null) { diff --git a/com.unity.render-pipelines.core/Editor/Lighting/IESReader.cs b/com.unity.render-pipelines.core/Editor/Lighting/IESReader.cs index 3eeada9fea8..061623f1694 100644 --- a/com.unity.render-pipelines.core/Editor/Lighting/IESReader.cs +++ b/com.unity.render-pipelines.core/Editor/Lighting/IESReader.cs @@ -6,6 +6,7 @@ namespace UnityEditor.Rendering { + [System.Serializable] public class IESReader { string m_FileFormatVersion; diff --git a/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporter.cs b/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporter.cs index 008963eb1e6..78bbffbb0d5 100644 --- a/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporter.cs +++ b/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporter.cs @@ -7,24 +7,32 @@ namespace UnityEditor.Rendering.HighDefinition { [ScriptedImporter(1, "ies")] - public class HDIESImporter : UnityEditor.Rendering.IESImporter + public partial class HDIESImporter : ScriptedImporter { - public override void SetupIesEngineForRenderPipeline(IESEngine engine) - { - engine.TextureGenerationType = TextureImporterType.Default; - } + public UnityEditor.Rendering.IESImporter commonIESImporter = new UnityEditor.Rendering.IESImporter(); - public override void SetupRenderPipelinePrefabLight(IESEngine engine, Light light) + internal void SetupRenderPipelinePrefabLight(IESEngine engine, Light light) { HDLightTypeAndShape hdLightTypeAndShape = (light.type == LightType.Point) ? HDLightTypeAndShape.Point : HDLightTypeAndShape.ConeSpot; HDAdditionalLightData hdLight = GameObjectExtension.AddHDLight(light.gameObject, hdLightTypeAndShape); - if (UseIesMaximumIntensity) + if (commonIESImporter.iesMetaData.UseIESMaximumIntensity) { - LightUnit lightUnit = (IesMaximumIntensityUnit == "Lumens") ? LightUnit.Lumen : LightUnit.Candela; - hdLight.SetIntensity(IesMaximumIntensity, lightUnit); + LightUnit lightUnit = (commonIESImporter.iesMetaData.IESMaximumIntensityUnit == "Lumens") ? LightUnit.Lumen : LightUnit.Candela; + hdLight.SetIntensity(commonIESImporter.iesMetaData.IESMaximumIntensity, lightUnit); } } + + public override void OnImportAsset(AssetImportContext ctx) + { + commonIESImporter.engine.TextureGenerationType = TextureImporterType.Default; + + commonIESImporter.CommonOnImportAsset(ctx, + delegate (IESEngine engine, Light light) + { + SetupRenderPipelinePrefabLight(engine, light); + } ); + } } } diff --git a/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporterEditor.cs b/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporterEditor.cs index bd4da6322c7..bcbf3226156 100644 --- a/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporterEditor.cs +++ b/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporterEditor.cs @@ -3,20 +3,23 @@ using UnityEngine; using UnityEngine.Rendering.HighDefinition; using UnityEngine.Rendering; +using UnityEditor.Experimental.AssetImporters; namespace UnityEditor.Rendering.HighDefinition { - [CustomEditor(typeof(IESImporter))] - public class HDIESImporterEditor : UnityEditor.Rendering.IESImporterEditor + [CustomEditor(typeof(HDIESImporter))] + public partial class HDIESImporterEditor : ScriptedImporterEditor { - public override void LayoutRenderPipelineUseIesMaximumIntensity() + public UnityEditor.Rendering.IESImporterEditor iesImporterEditor = new UnityEditor.Rendering.IESImporterEditor(); + + internal void LayoutRenderPipelineUseIesMaximumIntensity() { // 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")); + // EditorGUILayout.PropertyField(m_UseIESMaximumIntensityProp, new GUIContent("Use IES Maximum Intensity")); } - public override void SetupRenderPipelinePreviewCamera(Camera camera) + internal void SetupRenderPipelinePreviewCamera(Camera camera) { HDAdditionalCameraData hdCamera = camera.gameObject.AddComponent(); @@ -26,7 +29,7 @@ public override void SetupRenderPipelinePreviewCamera(Camera camera) hdCamera.GetType().GetProperty("isEditorCameraPreview", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(hdCamera, true, null); } - public override void SetupRenderPipelinePreviewLight(Light light) + internal void SetupRenderPipelinePreviewLight(Light light) { HDLightTypeAndShape hdLightTypeAndShape = (light.type == LightType.Point) ? HDLightTypeAndShape.Point : HDLightTypeAndShape.ConeSpot; @@ -39,17 +42,17 @@ public override void SetupRenderPipelinePreviewLight(Light light) hdLight.affectsVolumetric = false; } - public override void SetupRenderPipelinePreviewWallRenderer(MeshRenderer wallRenderer) + internal void SetupRenderPipelinePreviewWallRenderer(MeshRenderer wallRenderer) { wallRenderer.material = AssetDatabase.LoadAssetAtPath("Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDMaterial.mat"); } - public override void SetupRenderPipelinePreviewFloorRenderer(MeshRenderer floorRenderer) + internal void SetupRenderPipelinePreviewFloorRenderer(MeshRenderer floorRenderer) { floorRenderer.material = AssetDatabase.LoadAssetAtPath("Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/Material/DefaultHDMaterial.mat"); } - public override void SetupRenderPipelinePreviewLightIntensity(Light light) + internal void SetupRenderPipelinePreviewLightIntensity(Light light) { // Before enabling this feature, more experimentation is needed with the addition of a Volume in the PreviewRenderUtility scene. @@ -66,54 +69,77 @@ public override void SetupRenderPipelinePreviewLightIntensity(Light light) // } } - public override GUIContent GetPreviewTitle() + public override void OnEnable() { - return new GUIContent("IES Luminaire Profile"); + base.OnEnable(); + + var entryPoint0 = new PropertyFetcher(serializedObject); + SerializedProperty entryPoint1 = entryPoint0.Find(x => x.commonIESImporter); + Debug.Log("001"); + SerializedProperty entryPoint = entryPoint1.FindPropertyRelative("iesMetaData"); + + iesImporterEditor.CommonOnEnable(entryPoint); } - public override void OnPreviewGUI(Rect r, GUIStyle background) + public override void OnInspectorGUI() { - if (Event.current.type == EventType.Repaint) - { - Texture cookieTexture = null; - Texture previewTexture = null; - - foreach (var subAsset in AssetDatabase.LoadAllAssetRepresentationsAtPath((target as IESImporter).assetPath)) + iesImporterEditor.CommonOnInspectorGUI(this as ScriptedImporterEditor, + delegate () { - if (subAsset.name.EndsWith("-Cookie")) - { - cookieTexture = subAsset as Texture; - break; - } - } + LayoutRenderPipelineUseIesMaximumIntensity(); + }); - if (cookieTexture != null) - { - m_PreviewRenderUtility.lights[0].transform.localEulerAngles = new Vector3(90f, 0f, m_LightAimAxisRotationProp.floatValue); - SetupRenderPipelinePreviewLightIntensity(m_PreviewRenderUtility.lights[0]); - m_PreviewRenderUtility.lights[0].cookie = cookieTexture; + base.ApplyRevertGUI(); + } - m_PreviewRenderUtility.BeginPreview(r, background); + protected override void Apply() + { + base.Apply(); - bool fog = RenderSettings.fog; - Unsupported.SetRenderSettingsUseFogNoDirty(false); + iesImporterEditor.CommonApply(); + } - m_PreviewRenderUtility.camera.Render(); + 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); + } + ); + } + + public override GUIContent GetPreviewTitle() + { + return iesImporterEditor.CommonGetPreviewTitle(); + } - Unsupported.SetRenderSettingsUseFogNoDirty(fog); + public override void OnPreviewGUI(Rect r, GUIStyle background) + { + iesImporterEditor.CommonOnPreviewGUI(r, background, target as HDIESImporter, + delegate (Light light) + { + SetupRenderPipelinePreviewLightIntensity(light); + }); + } - previewTexture = m_PreviewRenderUtility.EndPreview(); - } + public override void OnDisable() + { + base.OnDisable(); - if (previewTexture == null) - { - GUI.DrawTexture(r, Texture2D.blackTexture, ScaleMode.StretchToFill, false); - } - else - { - GUI.DrawTexture(r, previewTexture, ScaleMode.ScaleToFit, false); - } - } + iesImporterEditor.CommonOnDisable(); } } } From db96816c303f4f20da51953cc5c91e343b3c696e Mon Sep 17 00:00:00 2001 From: skhiat Date: Fri, 24 Apr 2020 02:03:44 +0200 Subject: [PATCH 3/8] IES Point sampling enable Octahedral --- .../Editor/Lighting/IESImporterEditor.cs | 75 ++---- .../ShaderLibrary/Common.hlsl | 14 +- .../ShaderLibrary/Macros.hlsl | 14 +- .../Documentation~/Light-Component.md | 3 +- .../RenderPipeline/HDRenderPipelineUI.cs | 20 -- .../SerializedGlobalLightLoopSettings.cs | 4 +- .../CoreResources/ProjectCubeTo2D.compute | 237 ++++++++++++++++++ .../ProjectCubeTo2D.compute.meta | 9 + .../Runtime/Core/Textures/RTHandlesDeleter.cs | 61 +++++ .../Core/Textures/RTHandlesDeleter.cs.meta | 11 + .../Runtime/Debug/DebugDisplay.cs | 12 - .../Runtime/Debug/LightingDebug.cs | 4 +- .../Runtime/Lighting/LightCookieManager.cs | 103 ++++++-- .../Runtime/Lighting/LightDefinition.cs | 16 +- .../Runtime/Lighting/LightDefinition.cs.hlsl | 8 +- .../Runtime/Lighting/LightEvaluation.hlsl | 12 +- .../Lighting/LightLoop/CookieSampling.hlsl | 8 +- .../LightLoop/GlobalLightLoopSettings.cs | 4 - .../Runtime/Lighting/LightLoop/LightLoop.cs | 25 +- .../Runtime/Lighting/LightLoop/LightLoop.hlsl | 1 - .../LightLoop/ShaderVariablesLightLoop.hlsl | 3 - .../RenderPipeline/HDRenderPipeline.cs | 16 +- .../RenderPipeline/HDStringConstants.cs | 4 +- .../Shaders/Shadows/RaytracingShadow.raytrace | 10 +- .../RenderPipeline/RenderPipelineResources.cs | 5 +- .../Utility/PowerOfTwoTextureAtlas.cs | 22 +- .../RenderPipeline/Utility/Texture2DAtlas.cs | 5 +- 27 files changed, 535 insertions(+), 171 deletions(-) create mode 100644 com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/ProjectCubeTo2D.compute create mode 100644 com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/ProjectCubeTo2D.compute.meta create mode 100644 com.unity.render-pipelines.high-definition/Runtime/Core/Textures/RTHandlesDeleter.cs create mode 100644 com.unity.render-pipelines.high-definition/Runtime/Core/Textures/RTHandlesDeleter.cs.meta diff --git a/com.unity.render-pipelines.core/Editor/Lighting/IESImporterEditor.cs b/com.unity.render-pipelines.core/Editor/Lighting/IESImporterEditor.cs index 39f8f702fac..dc272743d68 100644 --- a/com.unity.render-pipelines.core/Editor/Lighting/IESImporterEditor.cs +++ b/com.unity.render-pipelines.core/Editor/Lighting/IESImporterEditor.cs @@ -109,44 +109,6 @@ public void CommonOnInspectorGUI(ScriptedImporterEditor scriptedImporter, Layout } scriptedImporter.serializedObject.ApplyModifiedProperties(); - - 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_SpotCookieSizeProp, new GUIContent("IES Size")); - EditorGUILayout.PropertyField(m_ApplyLightAttenuationProp); - - EditorGUILayout.PropertyField(m_CookieCompressionProp); - - layoutRenderPipelineUseIesMaximumIntensity(); - - 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(); } public void CommonApply() @@ -167,13 +129,13 @@ public bool CommonHasPreviewGUI(SetupRenderPipelinePreviewCamera setupRen { m_PreviewRenderUtility = new PreviewRenderUtility(); - m_PreviewRenderUtility.ambientColor = Color.black; + 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); + 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); @@ -187,7 +149,7 @@ public bool CommonHasPreviewGUI(SetupRenderPipelinePreviewCamera setupRen setupRenderPipelinePreviewLight(m_PreviewRenderUtility.lights[0]); - m_PreviewRenderUtility.lights[1].intensity = 0f; + m_PreviewRenderUtility.lights[1].intensity = 0f; GameObject previewWall = GameObject.CreatePrimitive(PrimitiveType.Plane); previewWall.name = "IESPreviewWall"; @@ -236,12 +198,26 @@ public void CommonOnPreviewGUI(Rect r, GUIStyle background, ScriptedImporter tar Texture cookieTexture = null; Texture previewTexture = null; - foreach (var subAsset in AssetDatabase.LoadAllAssetRepresentationsAtPath(target.assetPath)) + 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 { - if (subAsset.name.EndsWith("-Cube-IES")) + foreach (var subAsset in AssetDatabase.LoadAllAssetRepresentationsAtPath(target.assetPath)) { - cookieTexture = subAsset as Texture; - break; + if (subAsset.name.EndsWith("-2D-IES")) + { + cookieTexture = subAsset as Texture; + break; + } } } @@ -250,6 +226,7 @@ public void CommonOnPreviewGUI(Rect r, GUIStyle background, ScriptedImporter tar m_PreviewRenderUtility.lights[0].transform.localEulerAngles = new Vector3(90f, 0f, m_LightAimAxisRotationProp.floatValue); setupRenderPipelinePreviewLightIntensity(m_PreviewRenderUtility.lights[0]); 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); diff --git a/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl index 3f179827f91..179d300b991 100644 --- a/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl +++ b/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl @@ -552,7 +552,7 @@ TEMPLATE_2_REAL(PositivePow, base, power, return pow(abs(base), power)) // -As a replacement for pow(0,y) where y >= 1, the result of SafePositivePow(x,y) should be close enough to 0. // -For cases where we substitute for pow(0,y) where 0 < y < 1, SafePositivePow(x,y) will quickly reach 1 as y -> 0, while // normally pow(0,y) would give 0 instead of 1 for all 0 < y. -// eg: if we #define FLT_EPS 5.960464478e-8 (for fp32), +// eg: if we #define FLT_EPS 5.960464478e-8 (for fp32), // SafePositivePow(0, 0.1) = 0.1894646 // SafePositivePow(0, 0.01) = 0.8467453 // SafePositivePow(0, 0.001) = 0.9835021 @@ -1171,6 +1171,18 @@ real SphericalDot(real cosTheta1, real phi1, real cosTheta2, real phi2) return SinFromCos(cosTheta1) * SinFromCos(cosTheta2) * cos(phi1 - phi2) + cosTheta1 * cosTheta2; } +// C++ Standard: (y, x), Mathematica: (x, y) +real FastATan2(real x, real y) +{ + if (x > real(0.0)) + return FastATanPos(SafeDiv(y, sqrt(x*x + y*y) + x)); + else if (x <= real(0.0) && abs(y) <= 1e-5f) + return FastATanPos(SafeDiv(sqrt(x*x + y*y) - x, y)); + else + return PI; + // Theory: if x == 0 && y == 0 then NaN/UNDEFINED +} + // Generates a triangle in homogeneous clip space, s.t. // v0 = (-1, -1, 1), v1 = (3, -1, 1), v2 = (-1, 3, 1). float2 GetFullScreenTriangleTexCoord(uint vertexID) diff --git a/com.unity.render-pipelines.core/ShaderLibrary/Macros.hlsl b/com.unity.render-pipelines.core/ShaderLibrary/Macros.hlsl index f8f478a163e..198e5f4726e 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) @@ -49,13 +51,13 @@ #define GENERATE_INT_FLOAT_1_ARG(FunctionName, Parameter1, FunctionBody) \ float FunctionName(float Parameter1) { FunctionBody; } \ - int FunctionName(int Parameter1) { FunctionBody; } + int FunctionName(int Parameter1) { FunctionBody; } #else #define GENERATE_INT_FLOAT_1_ARG(FunctionName, Parameter1, FunctionBody) \ float FunctionName(float Parameter1) { FunctionBody; } \ uint FunctionName(uint Parameter1) { FunctionBody; } \ - int FunctionName(int Parameter1) { FunctionBody; } + int FunctionName(int Parameter1) { FunctionBody; } #endif @@ -227,11 +229,11 @@ #define GET_TEXELSIZE_NAME(name) (name##_TexelSize) #if UNITY_REVERSED_Z -# define COMPARE_DEVICE_DEPTH_CLOSER(shadowMapDepth, zDevice) (shadowMapDepth > zDevice) -# define COMPARE_DEVICE_DEPTH_CLOSEREQUAL(shadowMapDepth, zDevice) (shadowMapDepth >= zDevice) +# define COMPARE_DEVICE_DEPTH_CLOSER(shadowMapDepth, zDevice) (shadowMapDepth > zDevice) +# define COMPARE_DEVICE_DEPTH_CLOSEREQUAL(shadowMapDepth, zDevice) (shadowMapDepth >= zDevice) #else -# define COMPARE_DEVICE_DEPTH_CLOSER(shadowMapDepth, zDevice) (shadowMapDepth < zDevice) -# define COMPARE_DEVICE_DEPTH_CLOSEREQUAL(shadowMapDepth, zDevice) (shadowMapDepth <= zDevice) +# define COMPARE_DEVICE_DEPTH_CLOSER(shadowMapDepth, zDevice) (shadowMapDepth < zDevice) +# define COMPARE_DEVICE_DEPTH_CLOSEREQUAL(shadowMapDepth, zDevice) (shadowMapDepth <= zDevice) #endif #endif // UNITY_MACROS_INCLUDED 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 ea857ebb349..60b019d218d 100644 --- a/com.unity.render-pipelines.high-definition/Documentation~/Light-Component.md +++ b/com.unity.render-pipelines.high-definition/Documentation~/Light-Component.md @@ -145,7 +145,8 @@ 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** | SK-TODO | | **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. | 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 0d118994ec2..2dd98d88304 100644 --- a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs +++ b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/HDRenderPipelineUI.cs @@ -239,26 +239,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/Core/CoreResources/ProjectCubeTo2D.compute b/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/ProjectCubeTo2D.compute new file mode 100644 index 00000000000..7fffc5cdca5 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/ProjectCubeTo2D.compute @@ -0,0 +1,237 @@ +#pragma only_renderers d3d11 playstation xboxone vulkan metal switch + +#pragma kernel CSMainEquirectangular EQUIRECTANGULAR KerMain=CSMainEquirectangular +#pragma kernel CSMainFastOctahedral FAST_OCTAHEDRAL KerMain=CSMainFastOctahedral +#pragma kernel CSMainOctahedralConformalQuincuncial CONFORMAL_OCTAHEDRAL_QUINCUNCIAL KerMain=CSMainOctahedralConformalQuincuncial + +//#pragma multi_compile EQUIRECTANGULAR FAST_OCTAHEDRAL CONFORMAL_OCTAHEDRAL_QUINCUNCIAL + +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl" +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Sampling/Sampling.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" + +TextureCube _InputTexture; +RWTexture2D _OutputTexture; + +SAMPLER(sampler_InputTexture); + +float4 _SrcScaleBias; + +#if !defined(EQUIRECTANGULAR) && !defined(FAST_OCTAHEDRAL) && !defined(CONFORMAL_OCTAHEDRAL_QUINCUNCIAL) + #error Projection not defined {EQUIRECTANGULAR, FAST_OCTAHEDRAL, CONFORMAL_OCTAHEDRAL_QUINCUNCIAL} +#endif + +float3 SphericalTexCoordinateToDirection(float2 uvValue) +{ + float theta = ( 1.0f - uvValue.x )*TWO_PI; + float phi = ( uvValue.y - 0.5f )*PI; + + float csTh, siTh, csPh, siPh; + sincos(theta, siTh, csTh); + sincos(phi, siPh, csPh); + + // theta is 0 at negative Z (backwards). Coordinate frame is (-Z,X) meaning negative Z is primary axis and X is secondary axis. + return float3(siTh*csPh, siPh, -csTh*csPh); +} + +float2 Corner(float u, float v) +{ + if (u*v >= 0.0f && u >= 0.0f) + return float2( 1.0f - v, 1.0f - u); + else if (u < 0.0f && v <= 0.0f) + return float2(-1.0f - v, -1.0f - u); + else if (u < 0.0f && v > 0.0f) + return float2(-1.0f + v, 1.0f + u); + else + return float2( 1.0f + v, -1.0f + u); +} + +float2 CornerBack(float u, float v) +{ + if (abs(u) + abs(v) >= 1.0f) + return float2(u, v); + else + return Corner(u, v); +} + +#define EllipticIntegralParam (1.0f/2.0f) +#define EllipticK (1.8540746773013717f) +#define EllipticPeriodicParam (0.8472130847939793f) // pi/(2*EllipticK) +#define EllipticPeriodicParamD (1.6944261695879586f) // pi/EllipticK +#define JacobiDNParam (0.1465811135832811f) // Estimated on Mathematica + +// EllipticF[x, 1/2] +float EllipticFHalfApprox(float x) +{ +#if 0 + // Rough + return 1.1808787030571934f*x; +#else + // Better + return 1.1802869761094772f*x - 0.10157022944264996f*sin(1.9983809090670122f*x); +#endif +} +float SNApprox(float x) +{ + return sin(EllipticPeriodicParam*x); +} +float CNApprox(float x) +{ + return cos(EllipticPeriodicParam*x); +} +float DNApprox(float x) +{ + return EllipticPeriodicParam + JacobiDNParam*cos(EllipticPeriodicParamD*x); +} + +float2 CNNApprox(float2 Z) +{ + float zRe = Z.x; + float zIm = Z.y; + + float reCN = CNApprox(zRe); + float imCN = CNApprox(zIm); + + float reSN = SNApprox(zRe); + float imSN = SNApprox(zIm); + + float reDN = DNApprox(zRe); + float imDN = DNApprox(zIm); + + float t = 1.0f - reDN*reDN * imSN*imSN; + + return float2( + reCN*imCN/t, + (-reSN*reDN*imSN*imDN)/t + ); +} + +float2 SquareToDiskConformalApprox(float2 XY) +{ + float zRe = XY.x*0.5f - XY.y*0.5f; + float zIm = XY.x*0.5f + XY.y*0.5f; + + float2 r = CNNApprox(EllipticK*float2(1.0f - zRe, -zIm)); + + return INV_SQRT2*float2(r.x + r.y, r.y - r.x); +} + +real XXFastATan2(real x, real y) +{ + if (x > real(0.0)) + return /*FastATanPos*/FastATan(SafeDiv(y, sqrt(x * x + y * y) + x)); + //else if (x <= real(0.0) && abs(y) <= 1e-5f) + else if (x < real(0.0) && abs(y) <= 1e-5f) + return /*FastATanPos*/FastATan(SafeDiv(sqrt(x * x + y * y) - x, y)); + else + return PI; + // Theory: if x == 0 && y == 0 then NaN/UNDEFINED +} + +float2 StereographicInverse(float x, float y) +{ + float r = sqrt(max(x*x + y*y, 0.0f)); + float Phi = //XXFastATan2(x, y);// + atan2(y, x); + float lat = HALF_PI - 2.0f*atan(r); + float lon = Phi + HALF_PI; + // (* if Center South + // lat=-lat; + // *) + return float2(lat, lon); +} + +// Input [-1, 1] +float3 GetConformalQuincuncialDirection(float2 XY) +{ + /* + float2 uuvv = CornerBack(XY.x, XY.y); + float2 S = float2(uuvv.x - uuvv.y, uuvv.x + uuvv.y); + + float2 C = SquareToDiskConformalApprox(S); + float2 sph = BreusingHarmonicMeanInverse(C.x, C.y); + + if (abs(XY.x) + abs(XY.y) > 0.0f) + sph.x += HALF_PI; + else + sph.x -= HALF_PI; + */ + bool isCenter = (abs(XY.x) + abs(XY.y) <= 1.0f); + float2 v; + if (!isCenter) + { + if (XY.x*XY.y >= 0.0f) + { + // I or III + if (XY.x >= 0.0f) + v = float2(-XY.y + 1.0f, -XY.x + 1.0); + else + v = float2(-XY.y - 1.0f, -XY.x - 1.0); + } + else + { + // II or IV + if (XY.x < 0.0f) + v = float2(XY.y - 1.0f, XY.x + 1.0); + else + v = float2(XY.y + 1.0f, XY.x - 1.0); + } + } + else + { + v = XY; + } + float2 S = float2(v.x - v.y, v.x + v.y); + float2 xy = SquareToDiskConformalApprox(S); + float2 sph = StereographicInverse(xy.x, xy.y); + + if (!isCenter) + sph.x *= -1.0f; + sph.y -= PI_DIV_FOUR; + if (sph.y < -PI) + sph.y += TWO_PI; + //if (!isCenter) + // sph.y *= -1.0f; + //sph.x -= PI_DIV_FOUR; + //if (sph.x < -PI) + // sph.x += TWO_PI; + + //sph.y += PI_DIV_FOUR; + + //sph.x += 4.0f*HALF_PI; + //sph.y += 5.0*PI_DIV_FOUR; + + float csTh, siTh, csPh, siPh; + sincos(sph.x, siTh, csTh); + sincos(sph.y, siPh, csPh); + + //.xzy + return float3(siTh*csPh, siPh, -csTh*csPh); + //return float3(csTh*csPh, siTh*csPh, siPh); + //{Cos[\[Phi]] Sin[\[Theta]], Sin[\[Theta]] Sin[\[Phi]], Cos[\[Theta]]} + //return float3(csPh*siTh, siTh*siPh, csTh); +} + +[numthreads(8, 8, 1)] +void KerMain(uint3 dispatchThreadId : SV_DispatchThreadID) +{ + uint2 pixCoord = dispatchThreadId.xy; + float2 uv = float2(pixCoord.xy)*_SrcScaleBias.xx + _SrcScaleBias.zz; + + float4 output; + + float3 dir; +#if defined(EQUIRECTANGULAR) + dir = SphericalTexCoordinateToDirection(uv); +#elif defined(FAST_OCTAHEDRAL) + dir = UnpackNormalOctQuadEncode(2.0f*uv - 1.0f); +#else //defined(CONFORMAL_OCTAHEDRAL_QUINCUNCIAL) + dir = GetConformalQuincuncialDirection(2.0f*uv - 1.0f); +#endif + + output.rgb = SAMPLE_TEXTURECUBE_LOD(_InputTexture, s_linear_clamp_sampler, dir, 0).rgb; + output.w = 1.0f; + + _OutputTexture[pixCoord] = output; +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/ProjectCubeTo2D.compute.meta b/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/ProjectCubeTo2D.compute.meta new file mode 100644 index 00000000000..3fd261691c9 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/ProjectCubeTo2D.compute.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 1fb2e2c168c77d247b7c566c5f66363c +ComputeShaderImporter: + externalObjects: {} + currentAPIMask: 262148 + preprocessorOverride: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/RTHandlesDeleter.cs b/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/RTHandlesDeleter.cs new file mode 100644 index 00000000000..44559ead09a --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/RTHandlesDeleter.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; + +namespace UnityEngine.Rendering +{ + /// + /// RTHandlesDeleter to schedule a release of a RTHandle in N frame ('lifetime') + /// + internal static class RTHandlesDeleter + { + internal class RTHandleDesc + { + public int lifetime = 3; + public RTHandle rtHandle = null; + } + + internal static List m_RTHandleDescs = new List(); + + /// + /// Schedule a release of a RTHandle in 'lifetime' frames + /// + /// Considered rtHandle. + /// lifetime remaining of this rtHandle (unit: frame), default: 3 frames. + public static void ScheduleRelease(RTHandle rtHandle, int lifetime = 3) + { + if (rtHandle != null && lifetime > 0) + { + RTHandleDesc desc = new RTHandleDesc(); + desc.lifetime = lifetime; + desc.rtHandle = rtHandle; + m_RTHandleDescs.Add(desc); + } + else + { + rtHandle?.Release(); + } + } + + /// + /// Schedule a release of a RTHandle in 'lifetime' frames + /// + public static void Update() + { + foreach (RTHandleDesc desc in m_RTHandleDescs) + { + --desc.lifetime; + } + + // Release 'too old' RTHandle + for (int i = m_RTHandleDescs.Count - 1; i >= 0; i--) + { + var cur = m_RTHandleDescs[i]; + if (cur.lifetime <= 0) + { + cur.rtHandle.Release(); + m_RTHandleDescs.Remove(cur); + } + } + } + } +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/RTHandlesDeleter.cs.meta b/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/RTHandlesDeleter.cs.meta new file mode 100644 index 00000000000..7e44c69e166 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Core/Textures/RTHandlesDeleter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c497d1063912cbb419eb6d5a0552ced4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: 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 501cebc9b34..725681c7510 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs @@ -1098,18 +1098,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 2ca520cafff..9a91afbd840 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs @@ -298,8 +298,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/LightCookieManager.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightCookieManager.cs index c113acf19eb..e8569a7ead1 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightCookieManager.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightCookieManager.cs @@ -30,14 +30,19 @@ class LightCookieManager readonly Material m_CubeToPanoMaterial; + readonly ComputeShader m_ProjectCubeTo2D; + readonly int m_KernalEquirectangular; + readonly int m_KernalFastOctahedral; + readonly int m_KernalOctahedralConformalQuincuncial; + 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,7 +63,13 @@ 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; + m_ProjectCubeTo2D = hdResources.shaders.projectCubeTo2DCS; + + // SKCode + m_KernalEquirectangular = m_ProjectCubeTo2D.FindKernel("CSMainEquirectangular"); + m_KernalFastOctahedral = m_ProjectCubeTo2D.FindKernel("CSMainFastOctahedral"); + m_KernalOctahedralConformalQuincuncial = m_ProjectCubeTo2D.FindKernel("CSMainOctahedralConformalQuincuncial"); + int cookieAtlasSize = (int)gLightLoopSettings.cookieAtlasSize; cookieFormat = (GraphicsFormat)gLightLoopSettings.cookieFormat; cookieAtlasLastValidMip = gLightLoopSettings.cookieAtlasLastValidMip; @@ -70,18 +81,11 @@ public LightCookieManager(HDRenderPipelineAsset hdAsset, int maxCacheSize) 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; @@ -108,11 +112,6 @@ 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) @@ -231,7 +230,7 @@ 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) + if (!m_CookieAtlas.IsCached(out var scaleBias, cookie.GetInstanceID()) && !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.NeedsUpdate(cookie, false)) @@ -271,17 +270,81 @@ 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(cookie.GetInstanceID(), 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($"Cube 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.NeedsUpdate(cookie, false)) + { + Vector4 sourceScaleOffset = new Vector4(projectionSize/(float)atlasTexture.rt.width, projectionSize/(float)atlasTexture.rt.height, 0, 0); + + RTHandle projected = RTHandles.Alloc( + projectionSize, + projectionSize, + colorFormat: cookieFormat, + enableRandomWrite: true); + { + int usedKernel; + + //usedKernel = m_KernalEquirectangular; + usedKernel = m_KernalFastOctahedral; + //usedKernel = m_KernalOctahedralConformalQuincuncial; + + float invSize = 1.0f/((float)projectionSize); + + cmd.SetComputeTextureParam(m_ProjectCubeTo2D, usedKernel, HDShaderIDs._InputTexture, cookie); + cmd.SetComputeTextureParam(m_ProjectCubeTo2D, usedKernel, HDShaderIDs._OutputTexture, projected); + cmd.SetComputeFloatParams (m_ProjectCubeTo2D, HDShaderIDs._SrcScaleBias, + invSize, invSize, 0.5f*invSize, 0.5f*invSize); + + const int groupSizeX = 8; + const int groupSizeY = 8; + int threadGroupX = (projectionSize + (groupSizeX - 1))/groupSizeX; + int threadGroupY = (projectionSize + (groupSizeY - 1))/groupSizeY; + + cmd.DispatchCompute(m_ProjectCubeTo2D, usedKernel, threadGroupX, threadGroupY, 1); + } + // Generate the mips + Texture filteredProjected = FilterAreaLightTexture(cmd, projected); + m_CookieAtlas.BlitTexture(cmd, scaleBias, filteredProjected, sourceScaleOffset, blitMips: true, overrideInstanceID: cookie.GetInstanceID()); + + RTHandlesDeleter.ScheduleRelease(projected); + } + + 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..61286fe269f 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightDefinition.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightDefinition.cs @@ -57,6 +57,20 @@ public enum CookieMode Repeat, } + /// + /// IES Mode + /// + [GenerateHLSL] + public enum IESMode + { + /// Square Equirectangular Projection. + Equirectangular, + /// Fast Octahedral Projection. + FastOctahedral, + /// Conformal Octahedral Quincuncial Projection. + ConformalOctahedralQuincuncial, + } + // These structures share between C# and hlsl need to be align on float4, so we pad them. [GenerateHLSL(PackingRules.Exact, false)] struct DirectionalLightData @@ -142,7 +156,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..02a81966d5e 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 @@ -29,6 +29,13 @@ #define COOKIEMODE_CLAMP (1) #define COOKIEMODE_REPEAT (2) +// +// UnityEngine.Rendering.HighDefinition.IESMode: static fields +// +#define IESMODE_EQUIRECTANGULAR (0) +#define IESMODE_OCTAHEDRAL (1) +#define IESMODE_CONFORMAL_OCTAHEDRAL_QUINCUNCIAL (2) + // // UnityEngine.Rendering.HighDefinition.EnvShapeType: static fields // @@ -105,7 +112,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..ee235ee810d 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightEvaluation.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightEvaluation.hlsl @@ -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 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..8c158f7b488 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,8 @@ 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); + return SampleCookie2D(saturate(params*0.5f + 0.5f), 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 a81ef06827e..b952cecc56f 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 @@ -1257,7 +1257,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); @@ -1467,7 +1466,6 @@ 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; @@ -1481,8 +1479,8 @@ internal void GetLightData(CommandBuffer cmd, HDCamera hdCamera, HDShadowSetting lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.Fetch2DCookie(cmd, lightComponent.cookie); break; case HDLightType.Point: - lightData.cookieMode = CookieMode.Clamp; - lightData.cookieIndex = m_TextureCaches.lightCookieManager.FetchCubeCookie(cmd, lightComponent.cookie); + lightData.cookieMode = CookieMode.Repeat; + lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchCubeCookie(cmd, lightComponent.cookie); break; } } @@ -2718,6 +2716,9 @@ internal void ReserveCookieAtlasTexture(HDAdditionalLightData hdLightData, Light m_TextureCaches.lightCookieManager.ReserveSpace(hdLightData.surfaceTexture); m_TextureCaches.lightCookieManager.ReserveSpace(light?.cookie); break; + case HDLightType.Point: + m_TextureCaches.lightCookieManager.ReserveSpaceCube(light?.cookie ?? CoreUtils.whiteCubeTexture); + break; case HDLightType.Spot: // Projectors lights must always have a cookie texture. m_TextureCaches.lightCookieManager.ReserveSpace(light?.cookie ?? Texture2D.whiteTexture); @@ -3463,7 +3464,7 @@ void PushLightDataGlobalParams(CommandBuffer cmd) } cmd.SetGlobalTexture(HDShaderIDs._CookieAtlas, m_TextureCaches.lightCookieManager.atlasTexture); - cmd.SetGlobalTexture(HDShaderIDs._CookieCubeTextures, m_TextureCaches.lightCookieManager.cubeCache); + //cmd.SetGlobalTexture(HDShaderIDs._CookieCubeTextures, m_TextureCaches.lightCookieManager.cubeCache); cmd.SetGlobalTexture(HDShaderIDs._EnvCubemapTextures, m_TextureCaches.reflectionProbeCache.GetTexCache()); cmd.SetGlobalTexture(HDShaderIDs._Env2DTextures, m_TextureCaches.reflectionPlanarProbeCache.GetTexCache()); @@ -4036,20 +4037,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 c9b3f261ab0..fca18f531c2 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 @@ -442,7 +442,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 4298ff62652..c1c14db35d8 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/RenderPipeline/HDRenderPipeline.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs index 42cef9ae8be..b30fec0217b 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -249,7 +249,6 @@ internal int GetDecalAtlasMipCount() } internal int GetCookieAtlasMipCount() => (int)Mathf.Log((int)currentPlatformRenderPipelineSettings.lightLoopSettings.cookieAtlasSize, 2); - internal int GetCookieCubeArraySize() => currentPlatformRenderPipelineSettings.lightLoopSettings.cubeCookieTexArraySize; internal int GetPlanarReflectionProbeMipCount() { @@ -1781,6 +1780,17 @@ ref _cullingResults using (new ProfilingScope(null, ProfilingSampler.Get(HDProfileId.HDRenderPipelineAllRenderRequest))) { + // Ideally once each frame + { + var cmd = CommandBufferPool.Get(""); + // Release a RTHandle when their lifetime counter scheduled became 0 + RTHandlesDeleter.Update(); + + renderContext.ExecuteCommandBuffer(cmd); + CommandBufferPool.Release(cmd); + renderContext.Submit(); + } + // Execute render request graph, in reverse order for (int i = renderRequestIndicesToRender.Count - 1; i >= 0; --i) { @@ -3183,7 +3193,7 @@ void RenderDBuffer(HDCamera hdCamera, CommandBuffer cmd, ScriptableRenderContext { // We still bind black textures to make sure that something is bound (can be a problem on some platforms) m_DbufferManager.BindBlackTextures(cmd); - + // Bind buffer to make sure that something is bound . cmd.SetGlobalBuffer(HDShaderIDs._DecalPropertyMaskBufferSRV, m_DbufferManager.propertyMaskBuffer); @@ -4402,7 +4412,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/HDStringConstants.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs index f221e32003a..fb2b74b261d 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs @@ -121,7 +121,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"); @@ -343,7 +343,7 @@ static class HDShaderIDs public static readonly int _InputCubemap = Shader.PropertyToID("_InputCubemap"); public static readonly int _Mipmap = Shader.PropertyToID("_Mipmap"); - public static readonly int _ApplyExposure = Shader.PropertyToID("_ApplyExposure"); + public static readonly int _ApplyExposure = Shader.PropertyToID("_ApplyExposure"); public static readonly int _DiffusionProfileHash = Shader.PropertyToID("_DiffusionProfileHash"); public static readonly int _MaxRadius = Shader.PropertyToID("_MaxRadius"); 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..3ba80b230a1 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,10 @@ 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 cookieIndex = 0; 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 +233,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 +697,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 1adb07ae3df..f6602e8d696 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs @@ -88,7 +88,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")] @@ -165,6 +164,8 @@ public sealed class ShaderResources public Shader filterAreaLightCookiesPS; [Reload("Runtime/Core/CoreResources/ClearUIntTextureArray.compute")] public ComputeShader clearUIntTextureCS; + [Reload("Runtime/Core/CoreResources/ProjectCubeTo2D.compute")] + public ComputeShader projectCubeTo2DCS; // XR [Reload("Runtime/ShaderLibrary/XRMirrorView.shader")] @@ -375,7 +376,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/PowerOfTwoTextureAtlas.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Utility/PowerOfTwoTextureAtlas.cs index 73e30eb238d..c505630a9c5 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); @@ -79,7 +79,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 +98,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 +115,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 10de009345b..e658a152daa 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 @@ -289,7 +289,10 @@ 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); + => IsCached(out scaleOffset, texture.GetInstanceID()); + + public bool IsCached(out Vector4 scaleOffset, int id) + => m_AllocationCache.TryGetValue(id, out scaleOffset); public virtual bool NeedsUpdate(Texture texture, bool needMips = false) { From e03a6ae6317f1846d004e0bb60288211005a4630 Mon Sep 17 00:00:00 2001 From: skhiat Date: Fri, 24 Apr 2020 02:05:33 +0200 Subject: [PATCH 4/8] missing file --- .../Runtime/Lighting/LightDefinition.cs.hlsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 02a81966d5e..749bf0357d7 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 @@ -33,7 +33,7 @@ // UnityEngine.Rendering.HighDefinition.IESMode: static fields // #define IESMODE_EQUIRECTANGULAR (0) -#define IESMODE_OCTAHEDRAL (1) +#define IESMODE_FAST_OCTAHEDRAL (1) #define IESMODE_CONFORMAL_OCTAHEDRAL_QUINCUNCIAL (2) // From be7d37dbae165337849bf858d3dc3c2e6724cc65 Mon Sep 17 00:00:00 2001 From: skhiat Date: Fri, 24 Apr 2020 11:24:01 +0200 Subject: [PATCH 5/8] spaces --- .../Runtime/Utilities/CoreUtils.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/com.unity.render-pipelines.core/Runtime/Utilities/CoreUtils.cs b/com.unity.render-pipelines.core/Runtime/Utilities/CoreUtils.cs index 19818aec801..ba1f6590c48 100644 --- a/com.unity.render-pipelines.core/Runtime/Utilities/CoreUtils.cs +++ b/com.unity.render-pipelines.core/Runtime/Utilities/CoreUtils.cs @@ -579,7 +579,7 @@ public static void SetViewport(CommandBuffer cmd, RTHandle target) /// Generated names bassed on the provided parameters. public static string GetRenderTargetAutoName(int width, int height, int depth, RenderTextureFormat format, string name, bool mips = false, bool enableMSAA = false, MSAASamples msaaSamples = MSAASamples.None) => GetRenderTargetAutoName(width, height, depth, format.ToString(), name, mips, enableMSAA, msaaSamples); - + /// /// Generate a name based on render texture parameters. /// @@ -1062,7 +1062,7 @@ public static bool AreAnimatedMaterialsEnabled(Camera camera) #if UNITY_2020_2_OR_NEWER if (sv.camera == camera && sv.sceneViewState.alwaysRefreshEnabled) #else - if (sv.camera == camera && sv.sceneViewState.materialUpdateEnabled) + if (sv.camera == camera && sv.sceneViewState.materialUpdateEnabled) #endif { animateMaterials = true; From dedecd29130fe52bba7a103c5c8ce5bb062f9998 Mon Sep 17 00:00:00 2001 From: skhiat Date: Fri, 24 Apr 2020 15:30:05 +0200 Subject: [PATCH 6/8] for test --- .../Editor/Lighting/IESImporter.cs | 2 +- .../Runtime/Lighting/LightCookieManager.cs | 1 - .../Runtime/Lighting/LightEvaluation.hlsl | 26 ++++++++++++++++--- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/com.unity.render-pipelines.core/Editor/Lighting/IESImporter.cs b/com.unity.render-pipelines.core/Editor/Lighting/IESImporter.cs index 83dc8a7f3dd..23a6f342831 100644 --- a/com.unity.render-pipelines.core/Editor/Lighting/IESImporter.cs +++ b/com.unity.render-pipelines.core/Editor/Lighting/IESImporter.cs @@ -31,7 +31,7 @@ public class IESMetaData [Range(1f, 179f)] public float SpotAngle = 120f; [Range(32, 2048)] - public int SpotCookieSize = 512; + public int SpotCookieSize = 128; public bool ApplyLightAttenuation = true; public bool UseIESMaximumIntensity = true; 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 e8569a7ead1..55b3a5fe842 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightCookieManager.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightCookieManager.cs @@ -65,7 +65,6 @@ public LightCookieManager(HDRenderPipelineAsset hdAsset, int maxCacheSize) m_ProjectCubeTo2D = hdResources.shaders.projectCubeTo2DCS; - // SKCode m_KernalEquirectangular = m_ProjectCubeTo2D.FindKernel("CSMainEquirectangular"); m_KernalFastOctahedral = m_ProjectCubeTo2D.FindKernel("CSMainFastOctahedral"); m_KernalOctahedralConformalQuincuncial = m_ProjectCubeTo2D.FindKernel("CSMainOctahedralConformalQuincuncial"); 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 ee235ee810d..8f50400d0bb 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightEvaluation.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightEvaluation.hlsl @@ -324,22 +324,42 @@ float4 EvaluateCookie_Punctual(LightLoopContext lightLoopContext, LightData ligh } else { +#if 0 // Perform orthographic or perspective projection. float perspectiveZ = (lightType != GPULIGHTTYPE_PROJECTOR_BOX) ? positionLS.z : 1.0; - float2 positionCS = positionLS.xy / perspectiveZ; + float2 positionCS = positionLS.xy/perspectiveZ; float z = positionLS.z; float r = light.range; // 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; + bool isInBounds = Max3(abs(positionCS.x), abs(positionCS.y), abs(z - 0.5*r) - 0.5*r + 1) <= light.boxLightSafeExtent; + const float bound = (1.0f/light.angleScale); // Remap the texture coordinates from [-1, 1]^2 to [0, 1]^2. - float2 positionNDC = positionCS * 0.5 + 0.5; + float2 positionNDC = clamp(positionCS, -bound.xx, bound.xx)*0.5 + 0.5; // Manually clamp to border (black). cookie.rgb = SampleCookie2D(positionNDC, light.cookieScaleOffset); cookie.a = isInBounds ? 1.0 : 0.0; +#else + // Perform orthographic or perspective projection. + float perspectiveZ = (lightType != GPULIGHTTYPE_PROJECTOR_BOX) ? positionLS.z : 1.0; + float2 positionCS = positionLS.xy/perspectiveZ; + + float z = positionLS.z; + float r = light.range; + + // 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; + + // Remap the texture coordinates from [-1, 1]^2 to [0, 1]^2. + float2 positionNDC = positionCS*0.5 + 0.5; + + // Manually clamp to border (black). + cookie.rgb = SampleCookie2D(positionNDC, light.cookieScaleOffset); + cookie.a = isInBounds ? 1.0 : 0.0; +#endif } #else From 90accfcb1ab317e56b103dd7aa2f674db358a14d Mon Sep 17 00:00:00 2001 From: skhiat Date: Mon, 27 Apr 2020 12:35:50 +0200 Subject: [PATCH 7/8] Cut of push Yamato generation --- .../Editor/Lighting/IESImporter.cs | 6 +- .../Editor/Lighting/IESImporterEditor.cs | 13 +- .../Editor/AssetProcessors/HDIESImporter.cs | 7 +- .../AssetProcessors/HDIESImporterEditor.cs | 50 +-- .../Editor/Lighting/HDLightUI.Skin.cs | 3 +- .../Editor/Lighting/HDLightUI.cs | 14 +- .../Editor/Lighting/SerializedHDLight.cs | 12 +- .../Core/CoreResources/GPUArithmetic.compute | 128 ++++++++ .../CoreResources/GPUArithmetic.compute.meta | 9 + .../Core/CoreResources/GPUArithmetic.cs | 307 ++++++++++++++++++ .../Core/CoreResources/GPUArithmetic.cs.meta | 11 + .../CoreResources/ProjectCubeTo2D.compute | 14 +- .../Lighting/Light/HDAdditionalLightData.cs | 84 ++++- .../Runtime/Lighting/LightCookieManager.cs | 169 ++++++++-- .../Runtime/Lighting/LightDefinition.cs | 1 + .../Runtime/Lighting/LightDefinition.cs.hlsl | 1 + .../Runtime/Lighting/LightEvaluation.hlsl | 9 +- .../Runtime/Lighting/LightLoop/LightLoop.cs | 60 +++- 18 files changed, 799 insertions(+), 99 deletions(-) create mode 100644 com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/GPUArithmetic.compute create mode 100644 com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/GPUArithmetic.compute.meta create mode 100644 com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/GPUArithmetic.cs create mode 100644 com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/GPUArithmetic.cs.meta diff --git a/com.unity.render-pipelines.core/Editor/Lighting/IESImporter.cs b/com.unity.render-pipelines.core/Editor/Lighting/IESImporter.cs index 23a6f342831..143113c792c 100644 --- a/com.unity.render-pipelines.core/Editor/Lighting/IESImporter.cs +++ b/com.unity.render-pipelines.core/Editor/Lighting/IESImporter.cs @@ -47,7 +47,7 @@ public class IESImporter public IESEngine engine = new IESEngine(); public IESMetaData iesMetaData = new IESMetaData(); - public delegate void SetupRenderPipelinePrefabLight(IESEngine engine, Light light); + public delegate void SetupRenderPipelinePrefabLight(IESEngine engine, Light light, Texture ies); public void CommonOnImportAsset(AssetImportContext ctx, SetupRenderPipelinePrefabLight setupRenderPipelinePrefabLight) { @@ -106,9 +106,9 @@ public void CommonOnImportAsset(AssetImportContext ctx, SetupRenderPipelinePrefa light.intensity = 1f; // would need a better intensity value formula light.range = 10f; // would need a better range value formula light.spotAngle = iesMetaData.SpotAngle; - light.cookie = (iesMetaData.PrefabLightType == IESLightType.Point) ? cookieTextureCube : cookieTexture2D; + //light.cookie = (iesMetaData.PrefabLightType == IESLightType.Point) ? cookieTextureCube : cookieTexture2D; - setupRenderPipelinePrefabLight(engine, light); + setupRenderPipelinePrefabLight(engine, light, (iesMetaData.PrefabLightType == IESLightType.Point) ? cookieTextureCube : cookieTexture2D); // The light object will be automatically converted into a prefab. ctx.AddObjectToAsset(iesFileName, lightObject); diff --git a/com.unity.render-pipelines.core/Editor/Lighting/IESImporterEditor.cs b/com.unity.render-pipelines.core/Editor/Lighting/IESImporterEditor.cs index dc272743d68..b52c06767ec 100644 --- a/com.unity.render-pipelines.core/Editor/Lighting/IESImporterEditor.cs +++ b/com.unity.render-pipelines.core/Editor/Lighting/IESImporterEditor.cs @@ -28,8 +28,6 @@ public class IESImporterEditor SerializedProperty m_UseIESMaximumIntensityProp; SerializedProperty m_CookieCompressionProp; - //IESMetaData iesMetaData; - protected SerializedProperty m_LightAimAxisRotationProp; bool m_ShowLuminaireProductInformation = true; @@ -42,7 +40,7 @@ public class IESImporterEditor public delegate void SetupRenderPipelinePreviewLight(Light light); public delegate void SetupRenderPipelinePreviewWallRenderer(MeshRenderer wallRenderer); public delegate void SetupRenderPipelinePreviewFloorRenderer(MeshRenderer floorRenderer); - public delegate void SetupRenderPipelinePreviewLightIntensity(Light light); + public delegate void SetupRenderPipelinePreviewLightIntensity(Light light, SerializedProperty useIESMaximumIntensityProp, SerializedProperty iesMaximumIntensityUnitProp, SerializedProperty iesMaximumIntensityProp); public void CommonOnEnable(SerializedProperty serializedObject) { @@ -68,7 +66,7 @@ public void CommonOnEnable(SerializedProperty serializedObject) m_LightAimAxisRotationProp = serializedObject.FindPropertyRelative("LightAimAxisRotation"); } - public void CommonOnInspectorGUI(ScriptedImporterEditor scriptedImporter, LayoutRenderPipelineUseIesMaximumIntensity layoutRenderPipelineUseIesMaximumIntensity) + public void CommonOnInspectorGUI(ScriptedImporterEditor scriptedImporter) { scriptedImporter.serializedObject.Update(); @@ -95,7 +93,10 @@ public void CommonOnInspectorGUI(ScriptedImporterEditor scriptedImporter, Layout EditorGUILayout.PropertyField(m_CookieCompressionProp); - layoutRenderPipelineUseIesMaximumIntensity(); + //layoutRenderPipelineUseIesMaximumIntensity(SerializedProperty useIESMaximumIntensityProp); + + // 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()) { @@ -224,7 +225,7 @@ public void CommonOnPreviewGUI(Rect r, GUIStyle background, ScriptedImporter tar if (cookieTexture != null) { m_PreviewRenderUtility.lights[0].transform.localEulerAngles = new Vector3(90f, 0f, m_LightAimAxisRotationProp.floatValue); - setupRenderPipelinePreviewLightIntensity(m_PreviewRenderUtility.lights[0]); + 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; diff --git a/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporter.cs b/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporter.cs index 78bbffbb0d5..0007b671811 100644 --- a/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporter.cs +++ b/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporter.cs @@ -11,7 +11,7 @@ public partial class HDIESImporter : ScriptedImporter { public UnityEditor.Rendering.IESImporter commonIESImporter = new UnityEditor.Rendering.IESImporter(); - internal void SetupRenderPipelinePrefabLight(IESEngine engine, Light light) + internal void SetupRenderPipelinePrefabLight(IESEngine engine, Light light, Texture ies) { HDLightTypeAndShape hdLightTypeAndShape = (light.type == LightType.Point) ? HDLightTypeAndShape.Point : HDLightTypeAndShape.ConeSpot; @@ -21,6 +21,7 @@ internal void SetupRenderPipelinePrefabLight(IESEngine engine, Light light) { LightUnit lightUnit = (commonIESImporter.iesMetaData.IESMaximumIntensityUnit == "Lumens") ? LightUnit.Lumen : LightUnit.Candela; hdLight.SetIntensity(commonIESImporter.iesMetaData.IESMaximumIntensity, lightUnit); + hdLight.SetIES(ies); } } @@ -29,9 +30,9 @@ public override void OnImportAsset(AssetImportContext ctx) commonIESImporter.engine.TextureGenerationType = TextureImporterType.Default; commonIESImporter.CommonOnImportAsset(ctx, - delegate (IESEngine engine, Light light) + delegate (IESEngine engine, Light light, Texture ies) { - SetupRenderPipelinePrefabLight(engine, light); + SetupRenderPipelinePrefabLight(engine, light, ies); } ); } } diff --git a/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporterEditor.cs b/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporterEditor.cs index bcbf3226156..4244a096d72 100644 --- a/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporterEditor.cs +++ b/com.unity.render-pipelines.high-definition/Editor/AssetProcessors/HDIESImporterEditor.cs @@ -12,12 +12,12 @@ public partial class HDIESImporterEditor : ScriptedImporterEditor { public UnityEditor.Rendering.IESImporterEditor iesImporterEditor = new UnityEditor.Rendering.IESImporterEditor(); - internal void LayoutRenderPipelineUseIesMaximumIntensity() - { - // 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")); - } + //internal void LayoutRenderPipelineUseIesMaximumIntensity(SerializedProperty useIESMaximumIntensityProp) + //{ + // // Before enabling this feature, more experimentation is needed with the addition of a Volume in the PreviewRenderUtility scene. + // + // EditorGUILayout.PropertyField(useIESMaximumIntensityProp, new GUIContent("Use IES Maximum Intensity")); + //} internal void SetupRenderPipelinePreviewCamera(Camera camera) { @@ -52,21 +52,21 @@ 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) + internal void SetupRenderPipelinePreviewLightIntensity(Light light, SerializedProperty useIESMaximumIntensityProp, SerializedProperty iesMaximumIntensityUnitProp, SerializedProperty iesMaximumIntensityProp) { // Before enabling this feature, more experimentation is needed with the addition of a Volume in the PreviewRenderUtility scene. - // HDAdditionalLightData hdLight = light.GetComponent(); - // - // if (m_UseIesMaximumIntensityProp.boolValue) - // { - // LightUnit lightUnit = (m_IesMaximumIntensityUnitProp.stringValue == "Lumens") ? LightUnit.Lumen : LightUnit.Candela; - // hdLight.SetIntensity(m_IesMaximumIntensityProp.floatValue, lightUnit); - // } - // else - // { - // hdLight.SetIntensity(20000f, LightUnit.Lumen); - // } + 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); + } } public override void OnEnable() @@ -83,11 +83,11 @@ public override void OnEnable() public override void OnInspectorGUI() { - iesImporterEditor.CommonOnInspectorGUI(this as ScriptedImporterEditor, - delegate () - { - LayoutRenderPipelineUseIesMaximumIntensity(); - }); + iesImporterEditor.CommonOnInspectorGUI(this as ScriptedImporterEditor);//, + //delegate () + //{ + // LayoutRenderPipelineUseIesMaximumIntensity(); + //}); base.ApplyRevertGUI(); } @@ -129,9 +129,9 @@ public override GUIContent GetPreviewTitle() public override void OnPreviewGUI(Rect r, GUIStyle background) { iesImporterEditor.CommonOnPreviewGUI(r, background, target as HDIESImporter, - delegate (Light light) + delegate (Light light, SerializedProperty useIESMaximumIntensityProp, SerializedProperty iesMaximumIntensityUnitProp, SerializedProperty iesMaximumIntensityProp) { - SetupRenderPipelinePreviewLightIntensity(light); + SetupRenderPipelinePreviewLightIntensity(light, useIESMaximumIntensityProp, iesMaximumIntensityUnitProp, iesMaximumIntensityProp); }); } 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 8ae052f9be6..d2e4fd78928 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", "IES Texture (Point: Cube, Spot: Texture2D)."); 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 f50088760ca..319d4f11ee7 100644 --- a/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightUI.cs +++ b/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightUI.cs @@ -622,7 +622,7 @@ static void DrawLightIntensityGUILayout(SerializedHDLight serialized, Editor own } EditorGUI.EndProperty(); EditorGUI.EndProperty(); - + EditorGUI.PropertyField(valueRect, serialized.intensity, s_Styles.empty); DrawLightIntensityUnitPopup(unitRect, serialized, owner); @@ -726,10 +726,20 @@ 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) + { + EditorGUILayout.PropertyField(serialized.ies, s_Styles.iesTexture); + } + + if (serialized.type == HDLightType.Spot && serialized.ies.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 5b04f3949e6..ee31e669b1c 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; @@ -38,7 +39,8 @@ 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 ies; public SerializedProperty areaLightShadowCone; public SerializedProperty useCustomSpotLightShadowCone; public SerializedProperty customSpotLightShadowCone; @@ -90,7 +92,7 @@ internal class SerializedHDLight public SerializedProperty penumbraTint; public SerializedProperty shadowUpdateMode; public SerializedScalableSettingValue shadowResolution; - + // Bias control public SerializedProperty slopeBias; public SerializedProperty normalBias; @@ -256,10 +258,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, @@ -288,6 +290,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"); @@ -311,6 +314,7 @@ public SerializedHDLight(HDAdditionalLightData[] lightDatas, LightEditor.Setting minFilterSize = o.Find("m_MinFilterSize"); scaleForSoftness = o.Find("m_SoftnessScale"); areaLightCookie = o.Find("m_AreaLightCookie"); + ies = o.Find("m_IES"); areaLightShadowCone = o.Find("m_AreaLightShadowCone"); useCustomSpotLightShadowCone = o.Find("m_UseCustomSpotLightShadowCone"); customSpotLightShadowCone = o.Find("m_CustomSpotLightShadowCone"); diff --git a/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/GPUArithmetic.compute b/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/GPUArithmetic.compute new file mode 100644 index 00000000000..b7d8d937356 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/GPUArithmetic.compute @@ -0,0 +1,128 @@ +#pragma only_renderers d3d11 ps4 xboxone vulkan metal switch + +#pragma kernel CSMainAdd Add KerName=CSMainAdd +#pragma kernel CSMainSub Sub KerName=CSMainSub +#pragma kernel CSMainMult Mult KerName=CSMainMult +#pragma kernel CSMainDiv Div KerName=CSMainDiv +#pragma kernel CSMainMAD MAD KerName=CSMainMAD +#pragma kernel CSMainMAD_RG MAD_RG KerName=CSMainMAD_RG +#pragma kernel CSMainMean Mean KerName=CSMainMean +#pragma kernel CSMainSelfAdd READ_WRITE Add KerName=CSMainSelfAdd +#pragma kernel CSMainSelfSub READ_WRITE Sub KerName=CSMainSelfSub +#pragma kernel CSMainSelfMult READ_WRITE Mult KerName=CSMainSelfMult +#pragma kernel CSMainSelfDiv READ_WRITE Div KerName=CSMainSelfDiv +#pragma kernel CSMainSelfMAD READ_WRITE MAD KerName=CSMainSelfMAD +#pragma kernel CSMainSelfMAD_RG READ_WRITE MAD_RG KerName=CSMainSelfMAD_RG +#pragma kernel CSMainSelfMean READ_WRITE Mean KerName=CSMainSelfMean + +#pragma kernel CSMainAddFull Full Add KerName=CSMainAddFull +#pragma kernel CSMainSubFull Full Sub KerName=CSMainSubFull +#pragma kernel CSMainMultFull Full Mult KerName=CSMainMultFull +#pragma kernel CSMainDivFull Full Div KerName=CSMainDivFull +#pragma kernel CSMainMADFull Full MAD KerName=CSMainMADFull +#pragma kernel CSMainMAD_RGFull Full MAD_RG KerName=CSMainMAD_RGFull +#pragma kernel CSMainMeanFull Full Mean KerName=CSMainMeanFull + +#pragma kernel CSMainAddVal Val Add KerName=CSMainAddVal +#pragma kernel CSMainSubVal Val Sub KerName=CSMainSubVal +#pragma kernel CSMainMultVal Val Mult KerName=CSMainMultVal +#pragma kernel CSMainDivVal Val Div KerName=CSMainDivVal +#pragma kernel CSMainMADVal Val MAD KerName=CSMainMADVal +#pragma kernel CSMainMAD_RGVal Val MAD_RG KerName=CSMainMAD_RGVal +#pragma kernel CSMainMeanVal Val Mean KerName=CSMainMeanVal +#pragma kernel CSMainSelfAddVal Val READ_WRITE Add KerName=CSMainSelfAddVal +#pragma kernel CSMainSelfSubVal Val READ_WRITE Sub KerName=CSMainSelfSubVal +#pragma kernel CSMainSelfMultVal Val READ_WRITE Mult KerName=CSMainSelfMultVal +#pragma kernel CSMainSelfDivVal Val READ_WRITE Div KerName=CSMainSelfDivVal +#pragma kernel CSMainSelfMADVal Val READ_WRITE MAD KerName=CSMainSelfMADVal +#pragma kernel CSMainSelfMAD_RGVal Val READ_WRITE MAD_RG KerName=CSMainSelfMAD_RGVal +#pragma kernel CSMainSelfMeanVal Val READ_WRITE Mean KerName=CSMainSelfMeanVal + +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Macros.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariablesFunctions.hlsl" + +#ifdef Val + float4 _InputVal; +#elif !defined(Full) +Texture2D _InputVal; +#endif + +#ifdef READ_WRITE + RWTexture2D _Output; + #define _Input _Output +#else + Texture2D _Input; + RWTexture2D _Output; +#endif + +#ifdef Full + float4 _ScaleBias; +SAMPLER(sampler_Input); +#endif + +uint4 _Sizes; // xy: InputSize; zw: OutputSize + +[numthreads(8, 8, 1)] +void KerName(uint3 id : SV_DispatchThreadID) +{ + if (all(id.xy < _Sizes.xy)) + { +#ifdef Full + float4 v = _Output[id.xy]; +#else + float4 v = _Input[id.xy]; +#endif + +#ifdef Val + #if defined(MAD) + float4 param0 = _InputVal.r; + float4 param1 = _InputVal.g; + #elif defined(MAD_RG) + float4 param = float4(_InputVal.r, _InputVal.g, 0.0f, 0.0f); + #else + float4 param = _InputVal; + #endif +#elif defined(Full) + float2 uv = float2(id.xy)*_ScaleBias.xy + _ScaleBias.zw; + + #if defined(MAD) // . + float4 param0 = SAMPLE_TEXTURECUBE_LOD(_Input, sampler_Input, uv, 0); + float4 param1 = param0; + #elif defined(MAD_RG) + float2 rg = SAMPLE_TEXTURECUBE_LOD(_Input, sampler_Input, uv, 0).xy; + float4 param = float4(rg.r, rg.g, 0.0f, 0.0f); + #else + float4 param = SAMPLE_TEXTURECUBE_LOD(_Input, sampler_Input, uv, 0); + #endif +#else + #if defined(MAD) + float4 param0 = _InputVal[uint2(0, 0)]; + float4 param1 = _InputVal[uint2(1, 0)]; + #elif defined(MAD_RG) + float4 param = float4(_InputVal[uint2(0, 0)].r, _InputVal[uint2(0, 0)].g, 0.0f, 0.0f); + #else + float4 param = _InputVal[uint2(0, 0)]; + #endif +#endif + +#ifdef Add + _Output[id.xy] = v + param; +#elif defined(Sub) + _Output[id.xy] = v - param; +#elif defined(Mult) + _Output[id.xy] = v*param; +#elif defined(Div) + float4 a = param; + _Output[id.xy] = sign(a)*v/max(abs(a), 1e-4f); +#elif defined(MAD) + _Output[id.xy] = v*param0 + param1; +#elif defined(MAD_RG) + _Output[id.xy] = v*param.r + param.g; +#elif defined(Mean) + float mean = dot(v.xyz, float3((1.0f/3.0f).xxx)); + _Output[id.xy] = mean.xxxx; +#endif + } +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/GPUArithmetic.compute.meta b/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/GPUArithmetic.compute.meta new file mode 100644 index 00000000000..9376ff53dc4 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/GPUArithmetic.compute.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: dbea2d2cf969e91428a7d1383c9d5a09 +ComputeShaderImporter: + externalObjects: {} + currentAPIMask: 262148 + preprocessorOverride: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/GPUArithmetic.cs b/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/GPUArithmetic.cs new file mode 100644 index 00000000000..f064fd58339 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/GPUArithmetic.cs @@ -0,0 +1,307 @@ +using UnityEngine.Experimental.Rendering; +using UnityEngine.Rendering.HighDefinition; + +namespace UnityEngine.Rendering.HighDefinition +{ + public class GPUArithmetic + { + /// + /// Allowed operation for GPUArithmetic + /// + public enum Operation + { + /// + /// Addition + /// + Add, + /// + /// Multiply + /// + Mult, + /// + /// Divide + /// + Div, + /// + /// RGB Mean + /// + Mean, + /// + /// MAD: Multiply and Addition (a*x + b) + /// + MAD, + /// + /// MAD_RB: Multiply and Addition (with each needed informations are stored on red & green channels: in.r*x + in.b) + /// + MAD_RG + } + + /// + /// Compute operation, full size (output = input OP output) + /// + /// Output (Internally supported: +=, *=, /= ...) + /// Input (Internally supported: +=, *=, /= ...) + /// Command Buffer (can be null for immediate context) + /// Supported {Add: output = input + param, Mult: output = input*param, Div: output = input/param, Mean: output = dot(input, float3(1.0f/3.0f).xxx), MAD: output = param[0]*input + param[1], MAD_RG: output = param[0].x*input + param[0].y} + static public void ComputeOperation(RTHandle output, RTHandle input, CommandBuffer cmd, Operation operation) + { + Debug.Assert(input != null); + Debug.Assert(output != null); + //Debug.Assert(output.rt.width == input.rt.width && output.rt.height == input.rt.height); + + int width = output.rt.width; + int height = output.rt.height; + + var hdrp = HDRenderPipeline.defaultAsset; + ComputeShader gpuArithmeticCS = hdrp.renderPipelineResources.shaders.gpuArithmeticCS; + + string addon = ""; + switch (operation) + { + case Operation.Add: + addon = "AddFull"; + break; + case Operation.Mult: + addon = "MultFull"; + break; + case Operation.Div: + addon = "DivFull"; + break; + case Operation.Mean: + addon = "MeanFull"; + break; + case Operation.MAD: + addon = "MADFull"; + break; + case Operation.MAD_RG: + addon = "MAD_RGFull"; + break; + } + + int numTilesX = (width + (8 - 1))/8; + int numTilesY = (height + (8 - 1))/8; + + int outWidth = output.rt.width; + int outHeight = output.rt.height; + + int kernel = gpuArithmeticCS.FindKernel("CSMain" + addon); + if (cmd != null) + { + cmd.SetComputeTextureParam(gpuArithmeticCS, kernel, HDShaderIDs._Output, output); + cmd.SetComputeTextureParam(gpuArithmeticCS, kernel, HDShaderIDs._Input, input); + cmd.SetComputeIntParams (gpuArithmeticCS, HDShaderIDs._Sizes, + output.rt.width, output.rt.height, output.rt.width, output.rt.height); + cmd.SetComputeFloatParams (gpuArithmeticCS, HDShaderIDs._ScaleBias, + 1.0f/((float)outWidth), 1.0f/((float)outHeight), 0.5f/((float)outWidth), 0.5f/((float)outHeight)); + cmd.DispatchCompute(gpuArithmeticCS, kernel, numTilesX, numTilesY, 1); + } + else + { + gpuArithmeticCS.SetTexture(kernel, HDShaderIDs._Output, output); + gpuArithmeticCS.SetTexture(kernel, HDShaderIDs._Input, input); + gpuArithmeticCS.SetInts (HDShaderIDs._Sizes, + output.rt.width, output.rt.height, output.rt.width, output.rt.height); + cmd.SetComputeFloatParams (gpuArithmeticCS, HDShaderIDs._ScaleBias, + 1.0f/((float)outWidth), 1.0f/((float)outHeight), 0.5f/((float)outWidth), 0.5f/((float)outHeight)); + gpuArithmeticCS.Dispatch (kernel, numTilesX, numTilesY, 1); + } + } + + /// + /// Compute operation, output = (output OP paramRT) or (output OP input) + /// + /// Output (Internally supported: +=, *=, /= ...) + /// Input (Internally supported: +=, *=, /= ...) + /// Parameters for add, mult, ... {paramsRT[uint2(0, 0)], paramsRT[uint2(1, 0)]}, or paramsRT[uint2(0, 0)].xy + /// Command Buffer (can be null for immediate context) + /// Supported {Add: output = input + param, Mult: output = input*param, Div: output = input/param, Mean: output = dot(input, float3(1.0f/3.0f).xxx), MAD: output = param[0]*input + param[1], MAD_RG: output = param[0].x*input + param[0].y} + static public void ComputeOperation(RTHandle output, RTHandle input, RTHandle paramsRT, CommandBuffer cmd, Operation operation) + { + Debug.Assert(input != null); + Debug.Assert(output != null); + Debug.Assert(operation == Operation.Mean || paramsRT != null); + Debug.Assert(output.rt.width == input.rt.width && output.rt.height == input.rt.height); + + string addon = ""; + bool self = false; + if (input == output) + { + self = true; + addon += "Self"; + } + + int width = input.rt.width; + int height = input.rt.height; + + var hdrp = HDRenderPipeline.defaultAsset; + ComputeShader arithmeticCS = hdrp.renderPipelineResources.shaders.gpuArithmeticCS; + + switch(operation) + { + case Operation.Add: + addon += "Add"; + break; + case Operation.Mult: + addon += "Mult"; + break; + case Operation.Div: + addon += "Div"; + break; + case Operation.Mean: + addon += "Mean"; + break; + case Operation.MAD: + addon += "MAD"; + break; + case Operation.MAD_RG: + addon += "MAD_RG"; + break; + } + + int numTilesX = (width + (8 - 1))/8; + int numTilesY = (height + (8 - 1))/8; + + int kernel = arithmeticCS.FindKernel("CSMain" + addon); + if (cmd != null) + { + if (self) + { + cmd.SetComputeTextureParam(arithmeticCS, kernel, HDShaderIDs._Output, input); + if (paramsRT != null) + cmd.SetComputeTextureParam(arithmeticCS, kernel, HDShaderIDs._InputVal, paramsRT); + cmd.SetComputeIntParams (arithmeticCS, HDShaderIDs._Sizes, + input.rt.width, input.rt.height, input.rt.width, input.rt.height); + cmd.DispatchCompute(arithmeticCS, kernel, numTilesX, numTilesY, 1); + } + else + { + cmd.SetComputeTextureParam(arithmeticCS, kernel, HDShaderIDs._Output, output); + cmd.SetComputeTextureParam(arithmeticCS, kernel, HDShaderIDs._Input, input); + if (paramsRT != null) + cmd.SetComputeTextureParam(arithmeticCS, kernel, HDShaderIDs._InputVal, paramsRT); + cmd.SetComputeIntParams (arithmeticCS, HDShaderIDs._Sizes, + input.rt.width, input.rt.height, input.rt.width, input.rt.height); + cmd.DispatchCompute(arithmeticCS, kernel, numTilesX, numTilesY, 1); + } + } + else + { + if (self) + { + arithmeticCS.SetTexture(kernel, HDShaderIDs._Output, input); + if (paramsRT != null) + arithmeticCS.SetTexture(kernel, HDShaderIDs._InputVal, paramsRT); + arithmeticCS.SetInts (HDShaderIDs._Sizes, + input.rt.width, input.rt.height, input.rt.width, input.rt.height); + arithmeticCS.Dispatch (kernel, numTilesX, numTilesY, 1); + } + else + { + arithmeticCS.SetTexture(kernel, HDShaderIDs._Output, output); + arithmeticCS.SetTexture(kernel, HDShaderIDs._Input, input); + if (paramsRT != null) + arithmeticCS.SetTexture(kernel, HDShaderIDs._InputVal, paramsRT); + arithmeticCS.SetInts (HDShaderIDs._Sizes, + input.rt.width, input.rt.height, input.rt.width, input.rt.height); + arithmeticCS.Dispatch (kernel, numTilesX, numTilesY, 1); + } + } + } + + /// + /// Compute operation, output = (output OP param) or (output OP input) + /// + /// Output (Internally supported: +=, *=, /= ...) + /// Input (Internally supported: +=, *=, /= ...) + /// Parameters for add, mult, ... {paramsRT[uint2(0, 0)], paramsRT[uint2(1, 0)]}, or paramsRT[uint2(0, 0)].xy + /// Command Buffer (can be null for immediate context) + /// Supported {Add: output = input + param, Mult: output = input*param, Div: output = input/param, Mean: output = dot(input, float3(1.0f/3.0f).xxx), MAD: output = param[0]*input + param[1], MAD_RG: output = param[0].x*input + param[0].y} + static public void ComputeOperation(RTHandle output, RTHandle input, Vector4 param, CommandBuffer cmd, Operation operation) + { + Debug.Assert(input != null); + Debug.Assert(output != null); + Debug.Assert(output.rt.width == input.rt.width && output.rt.height == input.rt.height); + + string addon = ""; + bool self = false; + if (input == output) + { + self = true; + addon += "Self"; + } + + int width = input.rt.width; + int height = input.rt.height; + + var hdrp = HDRenderPipeline.defaultAsset; + ComputeShader arithmeticsCS = hdrp.renderPipelineResources.shaders.gpuArithmeticCS; + + switch(operation) + { + case Operation.Add: + addon += "AddVal"; + break; + case Operation.Mult: + addon += "MultVal"; + break; + case Operation.Div: + addon += "DivVal"; + break; + case Operation.Mean: + addon += "MeanVal"; + break; + case Operation.MAD: + addon += "MADVal"; + break; + case Operation.MAD_RG: + addon += "MAD_RGVal"; + break; + } + + int numTilesX = (width + (8 - 1))/8; + int numTilesY = (height + (8 - 1))/8; + + int kernel = arithmeticsCS.FindKernel("CSMain" + addon); + if (cmd != null) + { + if (self) + { + cmd.SetComputeTextureParam(arithmeticsCS, kernel, HDShaderIDs._Output, input); + cmd.SetComputeVectorParam (arithmeticsCS, HDShaderIDs._InputVal, param); + cmd.SetComputeIntParams (arithmeticsCS, HDShaderIDs._Sizes, + input.rt.width, input.rt.height, input.rt.width, input.rt.height); + cmd.DispatchCompute(arithmeticsCS, kernel, numTilesX, numTilesY, 1); + } + else + { + cmd.SetComputeTextureParam(arithmeticsCS, kernel, HDShaderIDs._Output, output); + cmd.SetComputeTextureParam(arithmeticsCS, kernel, HDShaderIDs._Input, input); + cmd.SetComputeVectorParam (arithmeticsCS, HDShaderIDs._InputVal, param); + cmd.SetComputeIntParams (arithmeticsCS, HDShaderIDs._Sizes, + input.rt.width, input.rt.height, input.rt.width, input.rt.height); + cmd.DispatchCompute(arithmeticsCS, kernel, numTilesX, numTilesY, 1); + } + } + else + { + if (self) + { + arithmeticsCS.SetTexture(kernel, HDShaderIDs._Output, input); + arithmeticsCS.SetVector ( HDShaderIDs._InputVal, param); + arithmeticsCS.SetInts ( HDShaderIDs._Sizes, + input.rt.width, input.rt.height, input.rt.width, input.rt.height); + arithmeticsCS.Dispatch (kernel, numTilesX, numTilesY, 1); + } + else + { + arithmeticsCS.SetTexture(kernel, HDShaderIDs._Output, output); + arithmeticsCS.SetTexture(kernel, HDShaderIDs._Input, input); + arithmeticsCS.SetVector ( HDShaderIDs._InputVal, param); + arithmeticsCS.SetInts ( HDShaderIDs._Sizes, + input.rt.width, input.rt.height, input.rt.width, input.rt.height); + arithmeticsCS.Dispatch (kernel, numTilesX, numTilesY, 1); + } + } + } + } +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/GPUArithmetic.cs.meta b/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/GPUArithmetic.cs.meta new file mode 100644 index 00000000000..f910e689ab2 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/GPUArithmetic.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7de11acf41a576142a7b02a736e514a3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/ProjectCubeTo2D.compute b/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/ProjectCubeTo2D.compute index 7fffc5cdca5..9f34765a419 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/ProjectCubeTo2D.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/Core/CoreResources/ProjectCubeTo2D.compute @@ -11,12 +11,12 @@ #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Sampling/Sampling.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" -TextureCube _InputTexture; -RWTexture2D _OutputTexture; +TextureCube _Input; +RWTexture2D _Output; -SAMPLER(sampler_InputTexture); +SAMPLER(sampler_Input); -float4 _SrcScaleBias; +float4 _ScaleBias; #if !defined(EQUIRECTANGULAR) && !defined(FAST_OCTAHEDRAL) && !defined(CONFORMAL_OCTAHEDRAL_QUINCUNCIAL) #error Projection not defined {EQUIRECTANGULAR, FAST_OCTAHEDRAL, CONFORMAL_OCTAHEDRAL_QUINCUNCIAL} @@ -217,7 +217,7 @@ float3 GetConformalQuincuncialDirection(float2 XY) void KerMain(uint3 dispatchThreadId : SV_DispatchThreadID) { uint2 pixCoord = dispatchThreadId.xy; - float2 uv = float2(pixCoord.xy)*_SrcScaleBias.xx + _SrcScaleBias.zz; + float2 uv = float2(pixCoord.xy)*_ScaleBias.xx + _ScaleBias.zz; float4 output; @@ -230,8 +230,8 @@ void KerMain(uint3 dispatchThreadId : SV_DispatchThreadID) dir = GetConformalQuincuncialDirection(2.0f*uv - 1.0f); #endif - output.rgb = SAMPLE_TEXTURECUBE_LOD(_InputTexture, s_linear_clamp_sampler, dir, 0).rgb; + output.rgb = SAMPLE_TEXTURECUBE_LOD(_Input, sampler_Input, dir, 0).rgb; output.w = 1.0f; - _OutputTexture[pixCoord] = output; + _Output[pixCoord] = output; } 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 f35359935df..8b5e0a3eba7 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 @@ -195,11 +195,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 { @@ -544,6 +568,24 @@ public Texture areaLightCookie } } + // Optional IES (Cubemap for PointLight, 2D Square texture for Spot) + [SerializeField, FormerlySerializedAs("ies")] + Texture m_IES = null; + /// + /// Get/Set IES texture for Point & Spot. + /// + public Texture IES + { + get => m_IES; + set + { + if (m_IES == value) + return; + + SetIES(value); + } + } + [Range(k_MinAreaLightShadowCone, k_MaxAreaLightShadowCone)] [SerializeField, FormerlySerializedAs("areaLightShadowCone")] float m_AreaLightShadowCone = 120.0f; @@ -1371,7 +1413,7 @@ public float barnDoorLength } /// - /// True if the light affects volumetric fog, false otherwise + /// True if the light affects volumetric fog, false otherwise /// public bool affectsVolumetric { @@ -1520,7 +1562,7 @@ void DestroyChildEmissiveMeshViewer() CoreUtils.Destroy(m_ChildEmissiveMeshViewer); m_ChildEmissiveMeshViewer = null; } - + [SerializeField] ShadowCastingMode m_AreaLightEmissiveMeshShadowCastingMode = ShadowCastingMode.Off; [SerializeField] @@ -1559,7 +1601,7 @@ public MotionVectorGenerationMode areaLightEmissiveMeshMotionVectorGenerationMod } } } - + private void DisableCachedShadowSlot() { if (WillRenderShadowMap() && !ShadowIsUpdatedEveryFrame()) @@ -2177,7 +2219,7 @@ void LateUpdate() timelineWorkaround.oldLightColorTemperature = legacyLight.colorTemperature; } } - + void OnDidApplyAnimationProperties() { UpdateAllLightValues(fromTimeLine: true); @@ -2391,7 +2433,7 @@ void UpdateLightIntensity() legacyLight.SetLightDirty(); // Should be apply only to parameter that's affect GI, but make the code cleaner #endif } - + void Awake() { Migrate(); @@ -2730,6 +2772,36 @@ public void SetCookie(Texture cookie, Vector2 directionalLightCookieSize) /// Cookie texture, must be 2D for Directional, Spot and Area light and Cubemap for Point lights public void SetCookie(Texture cookie) => SetCookie(cookie, Vector2.zero); + /// + /// Set light IES. Note that the texture must have a power of two size. + /// + /// IES texture, must be 2D for Spot, and Cubemap for Point lights + public void SetIES(Texture ies) + { + HDLightType lightType = type; + if (lightType == HDLightType.Point) + { + if (ies.dimension != TextureDimension.Cube) + { + Debug.LogError("Texture dimension " + ies.dimension + " is not supported for point lights."); + return; + } + + m_IES = ies; + } + // Only 2D IES are supported for Spot lights + else if (lightType == HDLightType.Spot) + { + if (ies.dimension != TextureDimension.Tex2D) + { + Debug.LogError("Texture dimension " + ies.dimension + " is not supported for Spot lights."); + return; + } + + m_IES = ies; + } + } + /// /// Set the spot light angle and inner spot percent. We don't use Light.innerSpotAngle. /// 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 55b3a5fe842..c67db6019f0 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightCookieManager.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightCookieManager.cs @@ -28,8 +28,6 @@ class LightCookieManager readonly Material m_MaterialFilterAreaLights; MaterialPropertyBlock m_MPBFilterAreaLights = new MaterialPropertyBlock(); - readonly Material m_CubeToPanoMaterial; - readonly ComputeShader m_ProjectCubeTo2D; readonly int m_KernalEquirectangular; readonly int m_KernalFastOctahedral; @@ -78,8 +76,6 @@ public LightCookieManager(HDRenderPipelineAsset hdAsset, int maxCacheSize) m_CookieAtlas = new PowerOfTwoTextureAtlas(cookieAtlasSize, gLightLoopSettings.cookieAtlasLastValidMip, cookieFormat, name: "Cookie Atlas (Punctual Lights)", useMipMap: true); - m_CubeToPanoMaterial = CoreUtils.CreateEngineMaterial(hdResources.shaders.cubeToPanoPS); - m_CookieCubeResolution = (int)gLightLoopSettings.pointCookieSize; } @@ -93,7 +89,6 @@ public void NewFrame() public void Release() { CoreUtils.Destroy(m_MaterialFilterAreaLights); - CoreUtils.Destroy(m_CubeToPanoMaterial); if(m_TempRenderTexture0 != null) { @@ -224,6 +219,50 @@ 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.Min(cookie.width, ies.height); + + if (width < k_MinCookieSize || height < k_MinCookieSize) + return Vector4.zero; + + if (!m_CookieAtlas.IsCached(out var scaleBias, cookie.GetInstanceID().GetHashCode() + 23*ies.GetInstanceID().GetHashCode()) && !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.NeedsUpdate(cookie, ies, false)) + { + RTHandle multiplied = RTHandles.Alloc( width, height, + colorFormat: cookieFormat, + enableRandomWrite: true); + RTHandle tex0; + RTHandle tex1; + if (cookie.width*cookie.height > ies.width*ies.height) + { + tex0 = RTHandles.Alloc(cookie); + tex1 = RTHandles.Alloc(ies); + } + else + { + tex0 = RTHandles.Alloc(ies); + tex1 = RTHandles.Alloc(cookie); + } + //GPUArithmetic.ComputeOperation(multiplied, multiplied, new Vector4(0, 0, 0, 0), cmd, GPUArithmetic.Operation.Add); + cmd.SetRenderTarget(multiplied); + cmd.ClearRenderTarget(false, true, Color.black); + GPUArithmetic.ComputeOperation(multiplied, tex0, cmd, GPUArithmetic.Operation.Add); + GPUArithmetic.ComputeOperation(multiplied, tex1, cmd, GPUArithmetic.Operation.Mult); + + m_CookieAtlas.BlitTexture(cmd, scaleBias, multiplied, new Vector4(1, 1, 0, 0), blitMips: false, overrideInstanceID: cookie.GetInstanceID().GetHashCode() + ies.GetInstanceID().GetHashCode()); + + RTHandlesDeleter.ScheduleRelease(tex0); + RTHandlesDeleter.ScheduleRelease(tex1); + RTHandlesDeleter.ScheduleRelease(multiplied); + } + + return scaleBias; + } + public Vector4 Fetch2DCookie(CommandBuffer cmd, Texture cookie) { if (cookie.width < k_MinCookieSize || cookie.height < k_MinCookieSize) @@ -257,6 +296,21 @@ public Vector4 FetchAreaCookie(CommandBuffer cmd, Texture cookie) 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(cookieA.GetInstanceID().GetHashCode() + 23*cookieB.GetInstanceID().GetHashCode(), width, height)) + m_2DCookieAtlasNeedsLayouting = true; + } + public void ReserveSpace(Texture cookie) { if (cookie == null) @@ -285,6 +339,53 @@ public void ReserveSpaceCube(Texture cookie) 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(cookieA.GetInstanceID().GetHashCode() + 23*cookieB.GetInstanceID().GetHashCode(), projectionSize, projectionSize)) + m_2DCookieAtlasNeedsLayouting = true; + } + + private RTHandle ProjectCubeTo2D(CommandBuffer cmd, Texture cookie, int projectionSize) + { + RTHandle projected = RTHandles.Alloc( + projectionSize, + projectionSize, + colorFormat: cookieFormat, + enableRandomWrite: true); + int usedKernel; + + //usedKernel = m_KernalEquirectangular; + usedKernel = m_KernalFastOctahedral; + //usedKernel = m_KernalOctahedralConformalQuincuncial; + + + float invSize = 1.0f/((float)projectionSize); + + cmd.SetComputeTextureParam(m_ProjectCubeTo2D, usedKernel, HDShaderIDs._Input, cookie); + cmd.SetComputeTextureParam(m_ProjectCubeTo2D, usedKernel, HDShaderIDs._Output, projected); + cmd.SetComputeFloatParams (m_ProjectCubeTo2D, HDShaderIDs._ScaleBias, + invSize, invSize, 0.5f*invSize, 0.5f*invSize); + + const int groupSizeX = 8; + const int groupSizeY = 8; + int threadGroupX = (projectionSize + (groupSizeX - 1))/groupSizeX; + int threadGroupY = (projectionSize + (groupSizeY - 1))/groupSizeY; + + cmd.DispatchCompute(m_ProjectCubeTo2D, usedKernel, threadGroupX, threadGroupY, 1); + + return projected; + } + public Vector4 FetchCubeCookie(CommandBuffer cmd, Texture cookie) { Debug.Assert(cookie != null); @@ -301,37 +402,47 @@ public Vector4 FetchCubeCookie(CommandBuffer cmd, Texture cookie) { Vector4 sourceScaleOffset = new Vector4(projectionSize/(float)atlasTexture.rt.width, projectionSize/(float)atlasTexture.rt.height, 0, 0); - RTHandle projected = RTHandles.Alloc( - projectionSize, - projectionSize, - colorFormat: cookieFormat, - enableRandomWrite: true); - { - int usedKernel; + RTHandle projectedCookie = ProjectCubeTo2D(cmd, cookie, projectionSize); + + // Generate the mips + Texture filteredProjected = FilterAreaLightTexture(cmd, projectedCookie); + m_CookieAtlas.BlitTexture(cmd, scaleBias, filteredProjected, sourceScaleOffset, blitMips: true, overrideInstanceID: cookie.GetInstanceID()); + + RTHandlesDeleter.ScheduleRelease(projectedCookie); + } + + 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; - //usedKernel = m_KernalEquirectangular; - usedKernel = m_KernalFastOctahedral; - //usedKernel = m_KernalOctahedralConformalQuincuncial; + if (!m_CookieAtlas.IsCached(out var scaleBias, cookie, ies) && !m_NoMoreSpace) + Debug.LogError($"Cube cookie texture {cookie} can't be fetched without having reserved. You can try to increase the cookie atlas resolution in the HDRP settings."); - float invSize = 1.0f/((float)projectionSize); + if (m_CookieAtlas.NeedsUpdate(cookie, ies, true)) + { + Vector4 sourceScaleOffset = new Vector4(projectionSize/(float)atlasTexture.rt.width, projectionSize/(float)atlasTexture.rt.height, 0, 0); - cmd.SetComputeTextureParam(m_ProjectCubeTo2D, usedKernel, HDShaderIDs._InputTexture, cookie); - cmd.SetComputeTextureParam(m_ProjectCubeTo2D, usedKernel, HDShaderIDs._OutputTexture, projected); - cmd.SetComputeFloatParams (m_ProjectCubeTo2D, HDShaderIDs._SrcScaleBias, - invSize, invSize, 0.5f*invSize, 0.5f*invSize); + RTHandle projectedCookie = ProjectCubeTo2D(cmd, cookie, projectionSize); + RTHandle projectedIES = ProjectCubeTo2D(cmd, ies, projectionSize); - const int groupSizeX = 8; - const int groupSizeY = 8; - int threadGroupX = (projectionSize + (groupSizeX - 1))/groupSizeX; - int threadGroupY = (projectionSize + (groupSizeY - 1))/groupSizeY; + GPUArithmetic.ComputeOperation(projectedCookie, projectedIES, cmd, GPUArithmetic.Operation.Mult); - cmd.DispatchCompute(m_ProjectCubeTo2D, usedKernel, threadGroupX, threadGroupY, 1); - } // Generate the mips - Texture filteredProjected = FilterAreaLightTexture(cmd, projected); - m_CookieAtlas.BlitTexture(cmd, scaleBias, filteredProjected, sourceScaleOffset, blitMips: true, overrideInstanceID: cookie.GetInstanceID()); + Texture filteredProjected = FilterAreaLightTexture(cmd, projectedCookie); + m_CookieAtlas.BlitTexture(cmd, scaleBias, filteredProjected, sourceScaleOffset, blitMips: true, overrideInstanceID: cookie.GetInstanceID().GetHashCode() + ies.GetInstanceID().GetHashCode()); - RTHandlesDeleter.ScheduleRelease(projected); + RTHandlesDeleter.ScheduleRelease(projectedCookie, 64); + RTHandlesDeleter.ScheduleRelease(projectedIES, 64); } return scaleBias; 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 61286fe269f..46f5c5c05f0 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightDefinition.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightDefinition.cs @@ -141,6 +141,7 @@ struct LightData public float angleScale; // Spot light [SurfaceDataAttributes(precision = FieldPrecision.Real)] public float angleOffset; // Spot light + public float iesCut; // Spot light public Vector3 forward; public GPULightType lightType; // TODO: move this up? 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 749bf0357d7..866005dacd9 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 @@ -103,6 +103,7 @@ struct LightData float volumetricLightDimmer; real angleScale; real angleOffset; + float iesCut; float3 forward; int lightType; float3 right; 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 8f50400d0bb..d97d108448b 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightEvaluation.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightEvaluation.hlsl @@ -324,7 +324,7 @@ float4 EvaluateCookie_Punctual(LightLoopContext lightLoopContext, LightData ligh } else { -#if 0 +#if 1 // Perform orthographic or perspective projection. float perspectiveZ = (lightType != GPULIGHTTYPE_PROJECTOR_BOX) ? positionLS.z : 1.0; float2 positionCS = positionLS.xy/perspectiveZ; @@ -334,10 +334,13 @@ 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; + isInBounds = isInBounds & dot(positionCS, positionCS) <= light.iesCut*light.iesCut; - const float bound = (1.0f/light.angleScale); + //const float bound = light.iesCut; + //(1.0f/light.angleScale); // Remap the texture coordinates from [-1, 1]^2 to [0, 1]^2. - float2 positionNDC = clamp(positionCS, -bound.xx, bound.xx)*0.5 + 0.5; + //float2 positionNDC = clamp(positionCS, -bound.xx, bound.xx)*0.5 + 0.5; + float2 positionNDC = positionCS*0.5 + 0.5; // Manually clamp to border (black). cookie.rgb = SampleCookie2D(positionNDC, light.cookieScaleOffset); 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 a9fd7fc6651..15aa1d5fb2d 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 @@ -1324,7 +1324,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; @@ -1434,8 +1434,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; @@ -1470,17 +1471,40 @@ internal void GetLightData(CommandBuffer cmd, HDCamera hdCamera, HDShadowSetting lightData.screenSpaceShadowIndex = (int)LightDefinitions.s_InvalidScreenSpaceShadow; lightData.isRayTracedContactShadow = 0.0f; - if (lightComponent != null && lightComponent.cookie != null) + if (lightComponent != null)// && additionalLightData != null/*(lightComponent.cookie != null || additionalLightData.IES != 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); + //if (additionalLightData?.IES != null || lightComponent?.cookie != null) + //{ + //if (lightComponent != null) + lightData.cookieMode = (lightComponent.cookie?.wrapMode == TextureWrapMode.Repeat) ? CookieMode.Repeat : CookieMode.Clamp; + //else + // lightData.cookieMode = CookieMode.Clamp; + if (additionalLightData.IES != null && lightComponent.cookie != null && additionalLightData.IES != lightComponent.cookie) + lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.Fetch2DCookie(cmd, lightComponent.cookie, additionalLightData.IES); + else if (lightComponent.cookie != null) + lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.Fetch2DCookie(cmd, lightComponent.cookie); + else if (additionalLightData.IES != null) + lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.Fetch2DCookie(cmd, additionalLightData.IES); + else + lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.Fetch2DCookie(cmd, Texture2D.whiteTexture); + //} + //else + // lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.Fetch2DCookie(cmd, Texture2D.whiteTexture); break; case HDLightType.Point: - lightData.cookieMode = CookieMode.Repeat; - lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchCubeCookie(cmd, lightComponent.cookie); + if (additionalLightData.IES != null || lightComponent.cookie != null) + { + lightData.cookieMode = CookieMode.Repeat; + if (additionalLightData.IES != null && lightComponent.cookie != null && additionalLightData.IES != lightComponent.cookie) + lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchCubeCookie(cmd, lightComponent.cookie, additionalLightData.IES); + else if (lightComponent.cookie != null) + lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchCubeCookie(cmd, lightComponent.cookie); + else if (additionalLightData.IES != null) + lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchCubeCookie(cmd, additionalLightData.IES); + } break; } } @@ -2717,12 +2741,28 @@ internal void ReserveCookieAtlasTexture(HDAdditionalLightData hdLightData, Light m_TextureCaches.lightCookieManager.ReserveSpace(light?.cookie); break; case HDLightType.Point: - m_TextureCaches.lightCookieManager.ReserveSpaceCube(light?.cookie ?? CoreUtils.whiteCubeTexture); + if (light.cookie != null && hdLightData.IES != null && light.cookie != hdLightData.IES) + m_TextureCaches.lightCookieManager.ReserveSpaceCube(light.cookie, hdLightData.IES); + else if (light?.cookie != null) + m_TextureCaches.lightCookieManager.ReserveSpaceCube(light.cookie); + else if (hdLightData?.IES != null) + m_TextureCaches.lightCookieManager.ReserveSpaceCube(hdLightData.IES); 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 (hdLightData.spotLightShape != SpotLightShape.Cone)// && (light?.cookie != null || hdLightData?.IES != null)) + { + if (light.cookie != null && hdLightData.IES != null && light.cookie != hdLightData.IES) + m_TextureCaches.lightCookieManager.ReserveSpace(light.cookie, hdLightData.IES); + else if (light?.cookie != null) + m_TextureCaches.lightCookieManager.ReserveSpace(light.cookie); + else if (hdLightData?.IES != null) + m_TextureCaches.lightCookieManager.ReserveSpace(hdLightData.IES); + else + m_TextureCaches.lightCookieManager.ReserveSpace(Texture2D.whiteTexture); + } + //else + // m_TextureCaches.lightCookieManager.ReserveSpace(Texture2D.whiteTexture); break; case HDLightType.Area: // Only rectnagles can have cookies From d3728bdd287b5f01074be486e67c8f67a43a0a0e Mon Sep 17 00:00:00 2001 From: skhiat Date: Mon, 27 Apr 2020 12:40:57 +0200 Subject: [PATCH 8/8] Wrong merge: Missing file --- .../Runtime/RenderPipeline/RenderPipelineResources.cs | 2 ++ 1 file changed, 2 insertions(+) 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 f6602e8d696..efaf92744ef 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs @@ -166,6 +166,8 @@ public sealed class ShaderResources public ComputeShader clearUIntTextureCS; [Reload("Runtime/Core/CoreResources/ProjectCubeTo2D.compute")] public ComputeShader projectCubeTo2DCS; + [Reload("Runtime/Core/CoreResources/GPUArithmetic.compute")] + public ComputeShader gpuArithmeticCS; // XR [Reload("Runtime/ShaderLibrary/XRMirrorView.shader")]