diff --git a/com.unity.render-pipelines.high-definition/CHANGELOG.md b/com.unity.render-pipelines.high-definition/CHANGELOG.md index 4652d9a2fef..e6d59ed0021 100644 --- a/com.unity.render-pipelines.high-definition/CHANGELOG.md +++ b/com.unity.render-pipelines.high-definition/CHANGELOG.md @@ -121,6 +121,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Added an API in HDRP to override the camera within the rendering of a frame (mainly for custom pass). - Added a function (HDRenderPipeline.ResetRTHandleReferenceSize) to reset the reference size of RTHandle systems. - Added support for AxF measurements importing into texture resources tilings. +- Added Layer parameter on Area Light to modify Layer of generated Emissive Mesh ### Fixed - Fix when rescale probe all direction below zero (1219246) 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..0e48300f445 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 @@ -81,6 +81,8 @@ sealed class Styles public readonly GUIContent displayAreaLightEmissiveMesh = new GUIContent("Display Emissive Mesh", "Generate an emissive mesh using the size, Color and Intensity of the Area Light."); public readonly GUIContent areaLightEmissiveMeshCastShadow = new GUIContent("Cast Shadows", "Specify wether the generated geometry create shadow or not when a shadow casting Light shines on it"); public readonly GUIContent areaLightEmissiveMeshMotionVector = new GUIContent("Motion Vectors", "Specify wether the generated Mesh renders 'Per Object Motion', 'Camera Motion' or 'No Motion' vectors to the Camera Motion Vector Texture."); + public readonly GUIContent areaLightEmissiveMeshSameLayer = new GUIContent("Same Layer", "If checked, use the same Layer than the Light one."); + public readonly GUIContent areaLightEmissiveMeshCustomLayer = new GUIContent("Custom Layer", "Specify on which layer the generated Mesh live."); public readonly GUIContent lightLayer = new GUIContent("Light Layer", "Specifies the current Light Layers that the Light affects. This Light illuminates corresponding Renderers with the same Light Layer flags."); public readonly GUIContent interactsWithSky = new GUIContent("Affect Physically Based Sky", "Check this option to make the light and the Physically Based sky affect one another."); 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..fe6def1919f 100644 --- a/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightUI.cs +++ b/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightUI.cs @@ -104,17 +104,6 @@ static HDLightUI() CED.FoldoutGroup(s_Styles.shapeHeader, Expandable.Shape, k_ExpandedState, DrawShapeContent), CED.Conditional((serialized, owner) => serialized.type == HDLightType.Directional && !serialized.settings.isCompletelyBaked, CED.FoldoutGroup(s_Styles.celestialBodyHeader, Expandable.CelestialBody, k_ExpandedState, DrawCelestialBodyContent)), - //CED.TernaryConditional((serialized, owner) => serialized.type == HDLightType.Directional && !serialized.settings.isCompletelyBaked, - // CED.AdvancedFoldoutGroup(s_Styles.shapeHeader, Expandable.Shape, k_ExpandedState, - // (serialized, owner) => GetAdvanced(AdvancedMode.Shape, serialized, owner), - // (serialized, owner) => SwitchAdvanced(AdvancedMode.Shape, serialized, owner), - // DrawShapeContent, - // DrawShapeAdvancedContent - // ), - // CED.FoldoutGroup(s_Styles.shapeHeader, Expandable.Shape, k_ExpandedState, - // DrawShapeContent - // ) - //), CED.AdvancedFoldoutGroup(s_Styles.emissionHeader, Expandable.Emission, k_ExpandedState, (serialized, owner) => GetAdvanced(AdvancedMode.Emission, serialized, owner), (serialized, owner) => SwitchAdvanced(AdvancedMode.Emission, serialized, owner), @@ -825,6 +814,7 @@ static void DrawEmissionAdvancedContent(SerializedHDLight serialized, Editor own { serialized.UpdateAreaLightEmissiveMeshCastShadow(newCastShadow); } + EditorGUI.showMixedValue = false; lineRect = EditorGUILayout.GetControlRect(); SerializedHDLight.MotionVector newMotionVector; @@ -838,8 +828,62 @@ static void DrawEmissionAdvancedContent(SerializedHDLight serialized, Editor own { serialized.UpdateAreaLightEmissiveMeshMotionVectorGeneration(newMotionVector); } + EditorGUI.showMixedValue = false; + EditorGUI.showMixedValue = serialized.areaLightEmissiveMeshLayer.hasMultipleDifferentValues || serialized.lightLayer.hasMultipleDifferentValues; + EditorGUI.BeginChangeCheck(); + bool toggle; + using (new SerializedHDLight.AreaLightEmissiveMeshDrawScope(lineRect, s_Styles.areaLightEmissiveMeshSameLayer, showSubArea, serialized.areaLightEmissiveMeshLayer, serialized.deportedAreaLightEmissiveMeshLayer)) + { + toggle = EditorGUILayout.Toggle(s_Styles.areaLightEmissiveMeshSameLayer, serialized.areaLightEmissiveMeshLayer.intValue == -1); + } + if (EditorGUI.EndChangeCheck()) + { + serialized.UpdateAreaLightEmissiveMeshLayer(serialized.lightLayer.intValue); + if (toggle) + serialized.areaLightEmissiveMeshLayer.intValue = -1; + } EditorGUI.showMixedValue = false; + + ++EditorGUI.indentLevel; + if (toggle || serialized.areaLightEmissiveMeshLayer.hasMultipleDifferentValues) + { + using (new EditorGUI.DisabledScope(true)) + { + lineRect = EditorGUILayout.GetControlRect(); + EditorGUI.showMixedValue = serialized.areaLightEmissiveMeshLayer.hasMultipleDifferentValues || serialized.lightLayer.hasMultipleDifferentValues; + EditorGUI.LayerField(lineRect, s_Styles.areaLightEmissiveMeshCustomLayer, serialized.lightLayer.intValue); + EditorGUI.showMixedValue = false; + } + } + else + { + EditorGUI.showMixedValue = serialized.areaLightEmissiveMeshLayer.hasMultipleDifferentValues; + lineRect = EditorGUILayout.GetControlRect(); + int layer; + EditorGUI.BeginChangeCheck(); + using (new SerializedHDLight.AreaLightEmissiveMeshDrawScope(lineRect, s_Styles.areaLightEmissiveMeshCustomLayer, showSubArea, serialized.areaLightEmissiveMeshLayer, serialized.deportedAreaLightEmissiveMeshLayer)) + { + layer = EditorGUI.LayerField(lineRect, s_Styles.areaLightEmissiveMeshCustomLayer, serialized.areaLightEmissiveMeshLayer.intValue); + } + if (EditorGUI.EndChangeCheck()) + { + serialized.UpdateAreaLightEmissiveMeshLayer(layer); + } + // or if the value of layer got changed using the layer change including child mechanism (strangely apply even if object not editable), + // discard the change: the child is not saved anyway so the value in HDAdditionalLightData is the only serialized one. + else if (!EditorGUI.showMixedValue + && serialized.deportedAreaLightEmissiveMeshLayer != null + && !serialized.deportedAreaLightEmissiveMeshLayer.Equals(null) + && serialized.areaLightEmissiveMeshLayer.intValue != serialized.deportedAreaLightEmissiveMeshLayer.intValue) + { + GUI.changed = true; //force register change to handle update and apply later + serialized.UpdateAreaLightEmissiveMeshLayer(layer); + } + EditorGUI.showMixedValue = false; + } + --EditorGUI.indentLevel; + --EditorGUI.indentLevel; } 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..10d310391e7 100644 --- a/com.unity.render-pipelines.high-definition/Editor/Lighting/SerializedHDLight.cs +++ b/com.unity.render-pipelines.high-definition/Editor/Lighting/SerializedHDLight.cs @@ -32,6 +32,8 @@ internal class SerializedHDLight public SerializedProperty deportedAreaLightEmissiveMeshCastShadow; public SerializedProperty areaLightEmissiveMeshMotionVector; public SerializedProperty deportedAreaLightEmissiveMeshMotionVector; + public SerializedProperty areaLightEmissiveMeshLayer; + public SerializedProperty deportedAreaLightEmissiveMeshLayer; public SerializedProperty renderingLayerMask; public SerializedProperty shadowNearPlane; public SerializedProperty blockerSampleCount; @@ -98,12 +100,15 @@ internal class SerializedHDLight private SerializedProperty pointLightHDType; private SerializedProperty areaLightShapeProperty; - private IEnumerable emissiveMeshes; + private GameObject[] emissiveMeshes; public bool needUpdateAreaLightEmissiveMeshComponents = false; public SerializedObject serializedObject; + public SerializedProperty lightLayer; + private SerializedObject lightGameObject; + //contain serialized property that are mainly used to draw inspector public LightEditor.Settings settings; @@ -227,25 +232,50 @@ void System.IDisposable.Dispose() } } + struct AreaLightEmissiveMeshObjectEditionScope : System.IDisposable + { + SerializedHDLight m_Serialized; + public AreaLightEmissiveMeshObjectEditionScope(SerializedHDLight serialized) + { + m_Serialized = serialized; + foreach (GameObject emissiveMesh in m_Serialized.emissiveMeshes) + { + emissiveMesh.hideFlags &= ~HideFlags.NotEditable; + } + m_Serialized.areaLightEmissiveMeshLayer.serializedObject.Update(); + } + + void System.IDisposable.Dispose() + { + m_Serialized.areaLightEmissiveMeshLayer.serializedObject.ApplyModifiedProperties(); + foreach (GameObject emissiveMesh in m_Serialized.emissiveMeshes) + { + emissiveMesh.hideFlags |= HideFlags.NotEditable; + } + m_Serialized.areaLightEmissiveMeshLayer.serializedObject.Update(); + } + } + public struct AreaLightEmissiveMeshDrawScope : System.IDisposable { - int propertyCount; - bool oldEnableState; + SerializedProperty[] m_Properties; + bool m_OldEnableState; public AreaLightEmissiveMeshDrawScope(Rect rect, GUIContent label, bool enabler, params SerializedProperty[] properties) { - propertyCount = properties.Count(p => p != null); - foreach (var property in properties) + m_Properties = properties; + foreach (var property in m_Properties) if (property != null) EditorGUI.BeginProperty(rect, label, property); - oldEnableState = GUI.enabled; + m_OldEnableState = GUI.enabled; GUI.enabled = enabler; } void System.IDisposable.Dispose() { - GUI.enabled = oldEnableState; - for (int i = 0; i < propertyCount; ++i) - EditorGUI.EndProperty(); + GUI.enabled = m_OldEnableState; + foreach (var property in m_Properties) + if (property != null) + EditorGUI.EndProperty(); } } @@ -277,6 +307,16 @@ public void UpdateAreaLightEmissiveMeshMotionVectorGeneration(MotionVector motio } } + public void UpdateAreaLightEmissiveMeshLayer(int layer) + { + using (new AreaLightEmissiveMeshObjectEditionScope(this)) + { + areaLightEmissiveMeshLayer.intValue = layer; + if (deportedAreaLightEmissiveMeshLayer != null) //only possible while editing from prefab + deportedAreaLightEmissiveMeshLayer.intValue = layer; + } + } + public SerializedHDLight(HDAdditionalLightData[] lightDatas, LightEditor.Settings settings) { serializedObject = new SerializedObject(lightDatas); @@ -374,9 +414,13 @@ public SerializedHDLight(HDAdditionalLightData[] lightDatas, LightEditor.Setting // emission mesh areaLightEmissiveMeshCastShadow = o.Find("m_AreaLightEmissiveMeshShadowCastingMode"); areaLightEmissiveMeshMotionVector = o.Find("m_AreaLightEmissiveMeshMotionVectorGenerationMode"); + areaLightEmissiveMeshLayer = o.Find("m_AreaLightEmissiveMeshLayer"); } RefreshEmissiveMeshReference(); + + lightGameObject = new SerializedObject(serializedObject.targetObjects.Select(ld => ((HDAdditionalLightData)ld).gameObject).ToArray()); + lightLayer = lightGameObject.FindProperty("m_Layer"); } void RefreshEmissiveMeshReference() @@ -388,9 +432,11 @@ void RefreshEmissiveMeshReference() SerializedObject meshRendererSerializedObject = new SerializedObject(meshRenderers.ToArray()); deportedAreaLightEmissiveMeshCastShadow = meshRendererSerializedObject.FindProperty("m_CastShadows"); deportedAreaLightEmissiveMeshMotionVector = meshRendererSerializedObject.FindProperty("m_MotionVectors"); + SerializedObject gameObjectSerializedObject = new SerializedObject(emissiveMeshes); + deportedAreaLightEmissiveMeshLayer = gameObjectSerializedObject.FindProperty("m_Layer"); } else - deportedAreaLightEmissiveMeshCastShadow = deportedAreaLightEmissiveMeshMotionVector = null; + deportedAreaLightEmissiveMeshCastShadow = deportedAreaLightEmissiveMeshMotionVector = deportedAreaLightEmissiveMeshLayer = null; } public void FetchAreaLightEmissiveMeshComponents() @@ -418,6 +464,10 @@ public void Update() serializedObject.Update(); settings.Update(); + + lightGameObject.Update(); + deportedAreaLightEmissiveMeshMotionVector?.serializedObject.Update(); + deportedAreaLightEmissiveMeshLayer?.serializedObject.Update(); } void ApplyInternal(bool withDeportedEmissiveMeshData) @@ -425,7 +475,10 @@ void ApplyInternal(bool withDeportedEmissiveMeshData) serializedObject.ApplyModifiedProperties(); settings.ApplyModifiedProperties(); if (withDeportedEmissiveMeshData) + { deportedAreaLightEmissiveMeshMotionVector?.serializedObject.ApplyModifiedProperties(); + deportedAreaLightEmissiveMeshLayer?.serializedObject.ApplyModifiedProperties(); + } } public void Apply() => ApplyInternal(withDeportedEmissiveMeshData: true); 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..1ddd8c08256 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 @@ -511,7 +511,7 @@ public bool applyRangeAttenuation /// /// If enabled, display an emissive mesh rect synchronized with the intensity and color of the light. /// - internal bool displayAreaLightEmissiveMesh + public bool displayAreaLightEmissiveMesh { get => m_DisplayAreaLightEmissiveMesh; set @@ -1492,9 +1492,53 @@ void CreateChildEmissiveMeshViewerIfNeeded() if (PrefabUtility.IsPartOfPrefabAsset(this)) return; #endif + bool here = m_ChildEmissiveMeshViewer != null && !m_ChildEmissiveMeshViewer.Equals(null); - //if not here, create it - if (m_ChildEmissiveMeshViewer == null || m_ChildEmissiveMeshViewer.Equals(null)) +#if UNITY_EDITOR + //if not parented anymore, destroy it + if (here && m_ChildEmissiveMeshViewer.transform.parent != transform) + { + if (Application.isPlaying) + Destroy(m_ChildEmissiveMeshViewer); + else + DestroyImmediate(m_ChildEmissiveMeshViewer); + m_ChildEmissiveMeshViewer = null; + m_EmissiveMeshFilter = null; + here = false; + } +#endif + + //if not here, try to find it first + if (!here) + { + foreach (Transform child in transform) + { + var test = child.GetComponents(typeof(Component)); + if (child.name == k_EmissiveMeshViewerName + && child.hideFlags == (HideFlags.NotEditable | HideFlags.DontSaveInBuild | HideFlags.DontSaveInEditor) + && child.GetComponents(typeof(MeshFilter)).Length == 1 + && child.GetComponents(typeof(MeshRenderer)).Length == 1 + && child.GetComponents(typeof(Component)).Length == 3) // Transform + MeshFilter + MeshRenderer + { + m_ChildEmissiveMeshViewer = child.gameObject; + m_ChildEmissiveMeshViewer.transform.localPosition = Vector3.zero; + m_ChildEmissiveMeshViewer.transform.localRotation = Quaternion.identity; + m_ChildEmissiveMeshViewer.transform.localScale = Vector3.one; + m_ChildEmissiveMeshViewer.layer = areaLightEmissiveMeshLayer == -1 ? gameObject.layer : areaLightEmissiveMeshLayer; + + m_EmissiveMeshFilter = m_ChildEmissiveMeshViewer.GetComponent(); + emissiveMeshRenderer = m_ChildEmissiveMeshViewer.GetComponent(); + emissiveMeshRenderer.shadowCastingMode = m_AreaLightEmissiveMeshShadowCastingMode; + emissiveMeshRenderer.motionVectorGenerationMode = m_AreaLightEmissiveMeshMotionVectorGenerationMode; + + here = true; + break; + } + } + } + + //if still not here, create it + if (!here) { m_ChildEmissiveMeshViewer = new GameObject(k_EmissiveMeshViewerName, typeof(MeshFilter), typeof(MeshRenderer)); m_ChildEmissiveMeshViewer.hideFlags = HideFlags.NotEditable | HideFlags.DontSaveInBuild | HideFlags.DontSaveInEditor; @@ -1502,6 +1546,7 @@ void CreateChildEmissiveMeshViewerIfNeeded() m_ChildEmissiveMeshViewer.transform.localPosition = Vector3.zero; m_ChildEmissiveMeshViewer.transform.localRotation = Quaternion.identity; m_ChildEmissiveMeshViewer.transform.localScale = Vector3.one; + m_ChildEmissiveMeshViewer.layer = areaLightEmissiveMeshLayer == -1 ? gameObject.layer : areaLightEmissiveMeshLayer; m_EmissiveMeshFilter = m_ChildEmissiveMeshViewer.GetComponent(); emissiveMeshRenderer = m_ChildEmissiveMeshViewer.GetComponent(); @@ -1525,6 +1570,8 @@ void DestroyChildEmissiveMeshViewer() ShadowCastingMode m_AreaLightEmissiveMeshShadowCastingMode = ShadowCastingMode.Off; [SerializeField] MotionVectorGenerationMode m_AreaLightEmissiveMeshMotionVectorGenerationMode; + [SerializeField] + int m_AreaLightEmissiveMeshLayer = -1; //Special value that means we need to grab the one in the Light for initialization (for migration purpose) /// Change the Shadow Casting Mode of the generated emissive mesh for Area Light public ShadowCastingMode areaLightEmissiveMeshShadowCastingMode @@ -1559,7 +1606,24 @@ public MotionVectorGenerationMode areaLightEmissiveMeshMotionVectorGenerationMod } } } - + + /// Change the Layer of the generated emissive mesh for Area Light + public int areaLightEmissiveMeshLayer + { + get => m_AreaLightEmissiveMeshLayer; + set + { + if (m_AreaLightEmissiveMeshLayer == value) + return; + + m_AreaLightEmissiveMeshLayer = value; + if (emissiveMeshRenderer != null && !emissiveMeshRenderer.Equals(null)) + { + emissiveMeshRenderer.gameObject.layer = m_AreaLightEmissiveMeshLayer; + } + } + } + private void DisableCachedShadowSlot() { if (WillRenderShadowMap() && !ShadowIsUpdatedEveryFrame()) @@ -2118,6 +2182,28 @@ void LateUpdate() return; #endif +#if UNITY_EDITOR + //if not parented anymore, refresh it + if (m_ChildEmissiveMeshViewer != null && !m_ChildEmissiveMeshViewer.Equals(null)) + { + if (m_ChildEmissiveMeshViewer.transform.parent != transform) + { + CreateChildEmissiveMeshViewerIfNeeded(); + UpdateAreaLightEmissiveMesh(); + } + if (m_ChildEmissiveMeshViewer.gameObject.isStatic != gameObject.isStatic) + m_ChildEmissiveMeshViewer.gameObject.isStatic = gameObject.isStatic; + if (GameObjectUtility.GetStaticEditorFlags(m_ChildEmissiveMeshViewer.gameObject) != GameObjectUtility.GetStaticEditorFlags(gameObject)) + GameObjectUtility.SetStaticEditorFlags(m_ChildEmissiveMeshViewer.gameObject, GameObjectUtility.GetStaticEditorFlags(gameObject)); + } +#endif + + //auto change layer on emissive mesh + if (areaLightEmissiveMeshLayer == -1 + && m_ChildEmissiveMeshViewer != null && !m_ChildEmissiveMeshViewer.Equals(null) + && m_ChildEmissiveMeshViewer.gameObject.layer != gameObject.layer) + m_ChildEmissiveMeshViewer.gameObject.layer = gameObject.layer; + // Delayed cleanup when removing emissive mesh from timeline if (needRefreshEmissiveMeshesFromTimeLineUpdate) {