OSDN Git Service

Added Assets for main menu
[mindgames/Mindgames_main.git] / Mindgames / Library / PackageCache / com.unity.render-pipelines.high-definition@6.9.0-preview / Runtime / Lighting / Light / HDAdditionalLightData.cs
1 using System;
2 using UnityEngine.Rendering;
3 #if UNITY_EDITOR
4 using UnityEditor;
5 using UnityEditor.Experimental.Rendering;
6 using UnityEditor.Experimental.Rendering.HDPipeline;
7 #endif
8 using UnityEngine.Serialization;
9
10 namespace UnityEngine.Experimental.Rendering.HDPipeline
11 {
12     // This enum extent the original LightType enum with new light type from HD
13     public enum LightTypeExtent
14     {
15         Punctual, // Fallback on LightShape type
16         Rectangle,
17         Tube,
18         // Sphere,
19         // Disc,
20     };
21
22     public enum SpotLightShape { Cone, Pyramid, Box };
23
24     public enum LightUnit
25     {
26         Lumen,      // lm = total power/flux emitted by the light
27         Candela,    // lm/sr = flux per steradian
28         Lux,        // lm/m² = flux per unit area
29         Luminance,  // lm/m²/sr = flux per unit area and per steradian
30         Ev100,      // ISO 100 Exposure Value (https://en.wikipedia.org/wiki/Exposure_value)
31     }
32
33     // Light layering
34     public enum LightLayerEnum
35     {
36         Nothing = 0,   // Custom name for "Nothing" option
37         LightLayerDefault = 1 << 0,
38         LightLayer1 = 1 << 1,
39         LightLayer2 = 1 << 2,
40         LightLayer3 = 1 << 3,
41         LightLayer4 = 1 << 4,
42         LightLayer5 = 1 << 5,
43         LightLayer6 = 1 << 6,
44         LightLayer7 = 1 << 7,
45         Everything = 0xFF, // Custom name for "Everything" option
46     }
47
48     // This structure contains all the old values for every recordable fields from the HD light editor
49     // so we can force timeline to record changes on other fields from the LateUpdate function (editor only)
50     struct TimelineWorkaround
51     {
52         public float oldDisplayLightIntensity;
53         public float oldLuxAtDistance;
54         public float oldSpotAngle;
55         public bool oldEnableSpotReflector;
56         public Color oldLightColor;
57         public Vector3 oldLocalScale;
58         public bool oldDisplayAreaLightEmissiveMesh;
59         public LightTypeExtent oldLightTypeExtent;
60         public float oldLightColorTemperature;
61         public Vector3 oldShape;
62         public float lightDimmer;
63     }
64
65     //@TODO: We should continuously move these values
66     // into the engine when we can see them being generally useful
67     [RequireComponent(typeof(Light))]
68     [ExecuteAlways]
69     public class HDAdditionalLightData : MonoBehaviour, ISerializationCallbackReceiver
70     {
71         // TODO: Use proper migration toolkit
72         // 3. Added ShadowNearPlane to HDRP additional light data, we don't use Light.shadowNearPlane anymore
73         // 4. Migrate HDAdditionalLightData.lightLayer to Light.renderingLayerMask
74         // 5. Added the ShadowLayer
75         private const int currentVersion = 5;
76
77         [HideInInspector, SerializeField]
78         [FormerlySerializedAs("m_Version")]
79         [System.Obsolete("version is deprecated, use m_Version instead")]
80         private float version = currentVersion;
81         [SerializeField]
82         private int m_Version = currentVersion;
83
84         // To be able to have correct default values for our lights and to also control the conversion of intensity from the light editor (so it is compatible with GI)
85         // we add intensity (for each type of light we want to manage).
86         [System.Obsolete("directionalIntensity is deprecated, use intensity and lightUnit instead")]
87         public float directionalIntensity = k_DefaultDirectionalLightIntensity;
88         [System.Obsolete("punctualIntensity is deprecated, use intensity and lightUnit instead")]
89         public float punctualIntensity = k_DefaultPunctualLightIntensity;
90         [System.Obsolete("areaIntensity is deprecated, use intensity and lightUnit instead")]
91         public float areaIntensity = k_DefaultAreaLightIntensity;
92
93         public const float k_DefaultDirectionalLightIntensity = Mathf.PI; // In lux
94         public const float k_DefaultPunctualLightIntensity = 600.0f;      // Light default to 600 lumen, i.e ~48 candela
95         public const float k_DefaultAreaLightIntensity = 200.0f;          // Light default to 200 lumen to better match point light
96
97         public float intensity
98         {
99             get { return displayLightIntensity; }
100             set { SetLightIntensity(value); }
101         }
102
103         // Only for Spotlight, should be hide for other light
104         public bool enableSpotReflector = false;
105         // Lux unity for all light except directional require a distance
106         public float luxAtDistance = 1.0f;
107
108         [Range(0.0f, 100.0f)]
109         public float m_InnerSpotPercent; // To display this field in the UI this need to be public
110
111         public float GetInnerSpotPercent01()
112         {
113             return Mathf.Clamp(m_InnerSpotPercent, 0.0f, 100.0f) / 100.0f;
114         }
115
116         [Range(0.0f, 1.0f)]
117         public float lightDimmer = 1.0f;
118
119         [Range(0.0f, 1.0f), SerializeField, FormerlySerializedAs("volumetricDimmer")]
120         private float m_VolumetricDimmer = 1.0f;
121
122         public float volumetricDimmer
123         {
124             get { return useVolumetric ? m_VolumetricDimmer : 0f; }
125             set {  m_VolumetricDimmer = value; }
126         }
127
128         // Used internally to convert any light unit input into light intensity
129         public LightUnit lightUnit = LightUnit.Lumen;
130
131         // Not used for directional lights.
132         public float fadeDistance = 10000.0f;
133
134         public bool affectDiffuse = true;
135         public bool affectSpecular = true;
136
137         // This property work only with shadow mask and allow to say we don't render any lightMapped object in the shadow map
138         public bool nonLightmappedOnly = false;
139
140         public LightTypeExtent lightTypeExtent = LightTypeExtent.Punctual;
141
142         // Only for Spotlight, should be hide for other light
143         public SpotLightShape spotLightShape { get { return m_SpotLightShape; } set { SetSpotLightShape(value); } }
144         [SerializeField, FormerlySerializedAs("spotLightShape")]
145         SpotLightShape m_SpotLightShape = SpotLightShape.Cone;
146
147         // Only for Rectangle/Line/box projector lights
148         public float shapeWidth = 0.5f;
149
150         // Only for Rectangle/box projector lights
151         public float shapeHeight = 0.5f;
152
153         // Only for pyramid projector
154         public float aspectRatio = 1.0f;
155
156         // Only for Punctual/Sphere/Disc
157         public float shapeRadius = 0.0f;
158
159         // Only for Spot/Point - use to cheaply fake specular spherical area light
160         // It is not 1 to make sure the highlight does not disappear.
161         [Range(0.0f, 1.0f)]
162         public float maxSmoothness = 0.99f;
163
164         // If true, we apply the smooth attenuation factor on the range attenuation to get 0 value, else the attenuation is just inverse square and never reach 0
165         public bool applyRangeAttenuation = true;
166
167         // This is specific for the LightEditor GUI and not use at runtime
168         public bool useOldInspector = false;
169         public bool useVolumetric = true;
170         public bool featuresFoldout = true;
171         public byte showAdditionalSettings = 0;
172         public float displayLightIntensity;
173
174         // When true, a mesh will be display to represent the area light (Can only be change in editor, component is added in Editor)
175         public bool displayAreaLightEmissiveMesh = false;
176
177         // Optional cookie for rectangular area lights
178         public Texture areaLightCookie = null;
179
180         [Range(0.0f, 179.0f)]
181         public float areaLightShadowCone = 120.0f;
182
183         // Flag that tells us if the shadow should be screen space
184         public bool useScreenSpaceShadows = false;
185
186 #if ENABLE_RAYTRACING
187         public bool useRayTracedShadows = false;
188         [Range(1, 32)]
189         public int numRayTracingSamples = 4;
190         public bool filterTracedShadow = true;
191         [Range(1, 32)]
192         public int filterSizeTraced = 16;
193         [Range(0.0f, 2.0f)]
194         public float sunLightConeAngle = 0.5f;
195 #endif
196
197         [Range(0.0f, 42.0f)]
198         public float evsmExponent = 15.0f;
199         [Range(0.0f, 1.0f)]
200         public float evsmLightLeakBias = 0.0f;
201         [Range(0.0f, 0.001f)]
202         public float evsmVarianceBias = 1e-5f;
203         [Range(0, 8)]
204         public int evsmBlurPasses = 0;
205
206         // Duplication of HDLightEditor.k_MinAreaWidth, maybe do something about that
207         const float k_MinAreaWidth = 0.01f; // Provide a small size of 1cm for line light
208
209         [Obsolete("Use Light.renderingLayerMask instead")]
210         public LightLayerEnum lightLayers = LightLayerEnum.LightLayerDefault;
211
212         // Now the renderingLayerMask is used for shadow layers and not light layers
213         public LightLayerEnum lightlayersMask = LightLayerEnum.LightLayerDefault;
214         public bool linkShadowLayers = true;
215
216         // This function return a mask of light layers as uint and handle the case of Everything as being 0xFF and not -1
217         public uint GetLightLayers()
218         {
219             int value = (int)lightlayersMask;
220             return value < 0 ? (uint)LightLayerEnum.Everything : (uint)value;
221         }
222
223         // Shadow Settings
224         public float    shadowNearPlane = 0.1f;
225
226         // PCSS settings
227         [Range(0, 1.0f)]
228         public float    shadowSoftness = .5f;
229         [Range(1, 64)]
230         public int      blockerSampleCount = 24;
231         [Range(1, 64)]
232         public int      filterSampleCount = 16;
233         [Range(0, 0.001f)]
234         public float minFilterSize = 0.00001f;
235
236         // Improved Moment Shadows settings
237         [Range(1, 32)]
238         public int kernelSize = 5;
239         [Range(0.0f, 9.0f)]
240         public float lightAngle = 1.0f;
241         [Range(0.0001f, 0.01f)]
242         public float maxDepthBias = 0.001f;
243
244         HDShadowRequest[]   shadowRequests;
245         bool                m_WillRenderShadowMap;
246         bool                m_WillRenderScreenSpaceShadow;
247 #if ENABLE_RAYTRACING
248         bool                m_WillRenderRayTracedShadow;
249 #endif
250         int[]               m_ShadowRequestIndices;
251
252         [System.NonSerialized]
253         Plane[]             m_ShadowFrustumPlanes = new Plane[6];
254
255         #if ENABLE_RAYTRACING
256         // Temporary index that stores the current shadow index for the light
257         [System.NonSerialized] public int shadowIndex;
258         #endif
259
260         [System.NonSerialized] HDShadowSettings    _ShadowSettings = null;
261         HDShadowSettings    m_ShadowSettings
262         {
263             get
264             {
265                 if (_ShadowSettings == null)
266                     _ShadowSettings = VolumeManager.instance.stack.GetComponent<HDShadowSettings>();
267                 return _ShadowSettings;
268             }
269         }
270
271         AdditionalShadowData _ShadowData;
272         AdditionalShadowData m_ShadowData
273         {
274             get
275             {
276                 if (_ShadowData == null)
277                     _ShadowData = GetComponent<AdditionalShadowData>();
278                 return _ShadowData;
279             }
280         }
281
282         int GetShadowRequestCount()
283         {
284             return (legacyLight.type == LightType.Point && lightTypeExtent == LightTypeExtent.Punctual) ? 6 : (legacyLight.type == LightType.Directional) ? m_ShadowSettings.cascadeShadowSplitCount.value : 1;
285         }
286
287         public void EvaluateShadowState(HDCamera hdCamera, CullingResults cullResults, FrameSettings frameSettings, int lightIndex)
288         {
289             Bounds bounds;
290             float cameraDistance = Vector3.Distance(hdCamera.camera.transform.position, transform.position);
291
292             m_WillRenderShadowMap = legacyLight.shadows != LightShadows.None && frameSettings.IsEnabled(FrameSettingsField.Shadow);
293
294             m_WillRenderShadowMap &= cullResults.GetShadowCasterBounds(lightIndex, out bounds);
295             // When creating a new light, at the first frame, there is no AdditionalShadowData so we can't really render shadows
296             m_WillRenderShadowMap &= m_ShadowData != null && m_ShadowData.shadowDimmer > 0;
297             // If the shadow is too far away, we don't render it
298             if (m_ShadowData != null)
299                 m_WillRenderShadowMap &= legacyLight.type == LightType.Directional || cameraDistance < (m_ShadowData.shadowFadeDistance);
300
301             // First we reset the ray tracing and screen space sahdow data
302             m_WillRenderScreenSpaceShadow = false;
303 #if ENABLE_RAYTRACING
304             m_WillRenderRayTracedShadow = false;
305 #endif
306
307             // If this camera does not allow screen space shadows we are done, set the target parameters to false and leave the function
308             if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.ScreenSpaceShadows) || !m_WillRenderShadowMap)
309                 return;
310
311 #if ENABLE_RAYTRACING
312             // We render screen space shadows if we are a ray traced rectangle area light or a screen space directional light shadow
313             if ((useRayTracedShadows && lightTypeExtent == LightTypeExtent.Rectangle)
314                 || (useScreenSpaceShadows && legacyLight.type == LightType.Directional))
315             {
316                 m_WillRenderScreenSpaceShadow = true;
317             }
318
319             // We will evaluate a ray traced shadow if we a ray traced area shadow
320             if ((useRayTracedShadows && lightTypeExtent == LightTypeExtent.Rectangle)
321                 || (useRayTracedShadows && legacyLight.type == LightType.Directional))
322             {
323                 m_WillRenderRayTracedShadow = true;
324             }
325 #endif
326         }
327
328         public void ReserveShadowMap(Camera camera, HDShadowManager shadowManager, HDShadowInitParameters initParameters, Rect screenRect)
329         {
330             if (!m_WillRenderShadowMap)
331                 return;
332
333             // Create shadow requests array using the light type
334             if (shadowRequests == null || m_ShadowRequestIndices == null)
335             {
336                 const int maxLightShadowRequestsCount = 6;
337                 shadowRequests = new HDShadowRequest[maxLightShadowRequestsCount];
338                 m_ShadowRequestIndices = new int[maxLightShadowRequestsCount];
339
340                 for (int i = 0; i < maxLightShadowRequestsCount; i++)
341                     shadowRequests[i] = new HDShadowRequest();
342             }
343
344             Vector2 viewportSize = new Vector2(m_ShadowData.shadowResolution, m_ShadowData.shadowResolution);
345
346             // Reserver wanted resolution in the shadow atlas
347             ShadowMapType shadowMapType = (lightTypeExtent == LightTypeExtent.Rectangle) ? ShadowMapType.AreaLightAtlas :
348                                           (legacyLight.type != LightType.Directional) ? ShadowMapType.PunctualAtlas : ShadowMapType.CascadedDirectional;
349
350             bool viewPortRescaling = false;
351             // Compute dynamic shadow resolution
352
353             viewPortRescaling |= (shadowMapType == ShadowMapType.PunctualAtlas && initParameters.punctualLightShadowAtlas.useDynamicViewportRescale);
354             viewPortRescaling |= (shadowMapType == ShadowMapType.AreaLightAtlas && initParameters.areaLightShadowAtlas.useDynamicViewportRescale);
355
356             if (viewPortRescaling)
357             {
358                 // resize viewport size by the normalized size of the light on screen
359                 float screenArea = screenRect.width * screenRect.height;
360                 viewportSize *= Mathf.Lerp(64f / viewportSize.x, 1f, screenArea);
361                 viewportSize = Vector2.Max(new Vector2(64f, 64f) / viewportSize, viewportSize);
362
363                 // Prevent flickering caused by the floating size of the viewport
364                 viewportSize.x = Mathf.Round(viewportSize.x);
365                 viewportSize.y = Mathf.Round(viewportSize.y);
366             }
367
368             viewportSize = Vector2.Max(viewportSize, new Vector2(HDShadowManager.k_MinShadowMapResolution, HDShadowManager.k_MinShadowMapResolution));
369
370             // Update the directional shadow atlas size
371             if (legacyLight.type == LightType.Directional)
372                 shadowManager.UpdateDirectionalShadowResolution((int)viewportSize.x, m_ShadowSettings.cascadeShadowSplitCount.value);
373
374             int count = GetShadowRequestCount();
375             for (int index = 0; index < count; index++)
376                 m_ShadowRequestIndices[index] = shadowManager.ReserveShadowResolutions(viewportSize, shadowMapType);
377         }
378
379         public bool WillRenderShadowMap()
380         {
381             return m_WillRenderShadowMap;
382         }
383
384         public bool WillRenderScreenSpaceShadow()
385         {
386             return m_WillRenderScreenSpaceShadow;
387         }
388
389 #if ENABLE_RAYTRACING
390         public bool WillRenderRayTracedShadow()
391         {
392             return m_WillRenderRayTracedShadow;
393         }
394 #endif
395
396         // This offset shift the position of the spotlight used to approximate the area light shadows. The offset is the minimum such that the full
397         // area light shape is included in the cone spanned by the spot light. 
398         public static float GetAreaLightOffsetForShadows(Vector2 shapeSize, float coneAngle)
399         {
400             float rectangleDiagonal = shapeSize.magnitude;
401             float halfAngle = coneAngle * 0.5f;
402             float cotanHalfAngle = 1.0f / Mathf.Tan(halfAngle * Mathf.Deg2Rad);
403             float offset = rectangleDiagonal * cotanHalfAngle;
404
405             return -offset;
406         }
407
408         // Must return the first executed shadow request
409         public int UpdateShadowRequest(HDCamera hdCamera, HDShadowManager manager, VisibleLight visibleLight, CullingResults cullResults, int lightIndex, out int shadowRequestCount)
410         {
411             int                 firstShadowRequestIndex = -1;
412             Vector3             cameraPos = hdCamera.mainViewConstants.worldSpaceCameraPos;
413             shadowRequestCount = 0;
414
415             int count = GetShadowRequestCount();
416             for (int index = 0; index < count; index++)
417             {
418                 var         shadowRequest = shadowRequests[index];
419                 Matrix4x4   invViewProjection = Matrix4x4.identity;
420                 int         shadowRequestIndex = m_ShadowRequestIndices[index];
421                 Vector2     viewportSize = manager.GetReservedResolution(shadowRequestIndex);
422
423                 if (shadowRequestIndex == -1)
424                     continue;
425
426                 if (lightTypeExtent == LightTypeExtent.Rectangle)
427                 {
428                     Vector2 shapeSize = new Vector2(shapeWidth, shapeHeight);
429                     float offset = GetAreaLightOffsetForShadows(shapeSize, areaLightShadowCone);
430                     Vector3 shadowOffset = offset * visibleLight.GetForward();
431                     HDShadowUtils.ExtractAreaLightData(hdCamera, visibleLight, lightTypeExtent, visibleLight.GetPosition() + shadowOffset, areaLightShadowCone, shadowNearPlane, shapeSize, viewportSize, m_ShadowData.normalBiasMax, out shadowRequest.view, out invViewProjection, out shadowRequest.deviceProjectionYFlip, out shadowRequest.deviceProjection, out shadowRequest.splitData);
432                 }
433                 else
434                 {
435                     // Write per light type matrices, splitDatas and culling parameters
436                     switch (legacyLight.type)
437                     {
438                         case LightType.Point:
439                             HDShadowUtils.ExtractPointLightData(
440                                 hdCamera, legacyLight.type, visibleLight, viewportSize, shadowNearPlane,
441                                 m_ShadowData.normalBiasMax, (uint)index, out shadowRequest.view,
442                                 out invViewProjection, out shadowRequest.deviceProjectionYFlip,
443                                 out shadowRequest.deviceProjection, out shadowRequest.splitData
444                             );
445                             break;
446                         case LightType.Spot:
447                             HDShadowUtils.ExtractSpotLightData(
448                                 hdCamera, legacyLight.type, spotLightShape, shadowNearPlane, aspectRatio, shapeWidth,
449                                 shapeHeight, visibleLight, viewportSize, m_ShadowData.normalBiasMax,
450                                 out shadowRequest.view, out invViewProjection, out shadowRequest.deviceProjectionYFlip,
451                                 out shadowRequest.deviceProjection, out shadowRequest.splitData
452                             );
453                             break;
454                         case LightType.Directional:
455                             Vector4 cullingSphere;
456                             float nearPlaneOffset = QualitySettings.shadowNearPlaneOffset;
457
458                             HDShadowUtils.ExtractDirectionalLightData(
459                                 visibleLight, viewportSize, (uint)index, m_ShadowSettings.cascadeShadowSplitCount.value,
460                                 m_ShadowSettings.cascadeShadowSplits, nearPlaneOffset, cullResults, lightIndex,
461                                 out shadowRequest.view, out invViewProjection, out shadowRequest.deviceProjectionYFlip,
462                                 out shadowRequest.deviceProjection, out shadowRequest.splitData
463                             );
464
465                             cullingSphere = shadowRequest.splitData.cullingSphere;
466
467                             // Camera relative for directional light culling sphere
468                             if (ShaderConfig.s_CameraRelativeRendering != 0)
469                             {
470                                 cullingSphere.x -= cameraPos.x;
471                                 cullingSphere.y -= cameraPos.y;
472                                 cullingSphere.z -= cameraPos.z;
473                             }
474                             manager.UpdateCascade(index, cullingSphere, m_ShadowSettings.cascadeShadowBorders[index]);
475                             break;
476                     }
477                 }
478
479                 // Assign all setting common to every lights
480                 SetCommonShadowRequestSettings(shadowRequest, cameraPos, invViewProjection, shadowRequest.deviceProjectionYFlip * shadowRequest.view, viewportSize, lightIndex);
481
482                 manager.UpdateShadowRequest(shadowRequestIndex, shadowRequest);
483
484                 // Store the first shadow request id to return it
485                 if (firstShadowRequestIndex == -1)
486                     firstShadowRequestIndex = shadowRequestIndex;
487
488                 shadowRequestCount++;
489             }
490
491             return firstShadowRequestIndex;
492         }
493
494         void SetCommonShadowRequestSettings(HDShadowRequest shadowRequest, Vector3 cameraPos, Matrix4x4 invViewProjection, Matrix4x4 viewProjection, Vector2 viewportSize, int lightIndex)
495         {
496             // zBuffer param to reconstruct depth position (for transmission)
497             float f = legacyLight.range;
498             float n = shadowNearPlane;
499             shadowRequest.zBufferParam = new Vector4((f-n)/n, 1.0f, (f-n)/n*f, 1.0f/f);
500             shadowRequest.viewBias = new Vector4(m_ShadowData.viewBiasMin, m_ShadowData.viewBiasMax, m_ShadowData.viewBiasScale, 2.0f / shadowRequest.deviceProjectionYFlip.m00 / viewportSize.x * 1.4142135623730950488016887242097f);
501             shadowRequest.normalBias = new Vector3(m_ShadowData.normalBiasMin, m_ShadowData.normalBiasMax, m_ShadowData.normalBiasScale);
502             shadowRequest.flags = 0;
503             shadowRequest.flags |= m_ShadowData.sampleBiasScale     ? (int)HDShadowFlag.SampleBiasScale : 0;
504             shadowRequest.flags |= m_ShadowData.edgeLeakFixup       ? (int)HDShadowFlag.EdgeLeakFixup : 0;
505             shadowRequest.flags |= m_ShadowData.edgeToleranceNormal ? (int)HDShadowFlag.EdgeToleranceNormal : 0;
506             shadowRequest.edgeTolerance = m_ShadowData.edgeTolerance;
507
508             // Make light position camera relative:
509             // TODO: think about VR (use different camera position for each eye)
510             if (ShaderConfig.s_CameraRelativeRendering != 0)
511             {
512                 var translation = Matrix4x4.Translate(cameraPos);
513                 shadowRequest.view *= translation;
514                 translation.SetColumn(3, -cameraPos);
515                 translation[15] = 1.0f;
516                 invViewProjection = translation * invViewProjection;
517             }
518
519             if (legacyLight.type == LightType.Directional || (legacyLight.type == LightType.Spot && spotLightShape == SpotLightShape.Box))
520                 shadowRequest.position = new Vector3(shadowRequest.view.m03, shadowRequest.view.m13, shadowRequest.view.m23);
521             else
522                 shadowRequest.position = (ShaderConfig.s_CameraRelativeRendering != 0) ? transform.position - cameraPos : transform.position;
523
524             shadowRequest.shadowToWorld = invViewProjection.transpose;
525             shadowRequest.zClip = (legacyLight.type != LightType.Directional);
526             shadowRequest.lightIndex = lightIndex;
527             // We don't allow shadow resize for directional cascade shadow
528             if (legacyLight.type == LightType.Directional)
529             {
530                 shadowRequest.shadowMapType = ShadowMapType.CascadedDirectional;
531             }
532             else if (lightTypeExtent == LightTypeExtent.Rectangle)
533             {
534                 shadowRequest.shadowMapType = ShadowMapType.AreaLightAtlas;
535             }
536             else
537             {
538                 shadowRequest.shadowMapType = ShadowMapType.PunctualAtlas;
539             }
540
541             shadowRequest.lightType = (int) legacyLight.type;
542
543             // shadow clip planes (used for tessellation clipping)
544             GeometryUtility.CalculateFrustumPlanes(viewProjection, m_ShadowFrustumPlanes);
545             if (shadowRequest.frustumPlanes?.Length != 6)
546                 shadowRequest.frustumPlanes = new Vector4[6];
547             // Left, right, top, bottom, near, far.
548             for (int i = 0; i < 6; i++)
549             {
550                 shadowRequest.frustumPlanes[i] = new Vector4(
551                     m_ShadowFrustumPlanes[i].normal.x,
552                     m_ShadowFrustumPlanes[i].normal.y,
553                     m_ShadowFrustumPlanes[i].normal.z,
554                     m_ShadowFrustumPlanes[i].distance
555                 );
556             }
557
558             // Shadow algorithm parameters
559             shadowRequest.shadowSoftness = shadowSoftness / 100f;
560             shadowRequest.blockerSampleCount = blockerSampleCount;
561             shadowRequest.filterSampleCount = filterSampleCount;
562             shadowRequest.minFilterSize = minFilterSize;
563
564             shadowRequest.kernelSize = (uint)kernelSize;
565             shadowRequest.lightAngle = (lightAngle * Mathf.PI / 180.0f);
566             shadowRequest.maxDepthBias = maxDepthBias;
567             // We transform it to base two for faster computation.
568             // So e^x = 2^y where y = x * log2 (e)
569             const float log2e = 1.44269504089f;
570             shadowRequest.evsmParams.x = evsmExponent * log2e;
571             shadowRequest.evsmParams.y = evsmLightLeakBias;
572             shadowRequest.evsmParams.z = evsmVarianceBias;
573             shadowRequest.evsmParams.w = evsmBlurPasses;
574         }
575
576         // We need these old states to make timeline and the animator record the intensity value and the emissive mesh changes
577         [System.NonSerialized]
578         TimelineWorkaround timelineWorkaround = new TimelineWorkaround();
579
580         // For light that used the old intensity system we update them
581         [System.NonSerialized]
582         bool needsIntensityUpdate_1_0 = false;
583
584         // Runtime datas used to compute light intensity
585         Light m_light;
586         internal Light legacyLight
587         {
588             get
589             {
590                 if (m_light == null)
591                     m_light = GetComponent<Light>();
592                 return m_light;
593             }
594         }
595
596         void SetLightIntensity(float intensity)
597         {
598             displayLightIntensity = intensity;
599
600             if (lightUnit == LightUnit.Lumen)
601             {
602                 if (lightTypeExtent == LightTypeExtent.Punctual)
603                     SetLightIntensityPunctual(intensity);
604                 else
605                     legacyLight.intensity = LightUtils.ConvertAreaLightLumenToLuminance(lightTypeExtent, intensity, shapeWidth, shapeHeight);
606             }
607             else if (lightUnit == LightUnit.Ev100)
608             {
609                 legacyLight.intensity = LightUtils.ConvertEvToLuminance(intensity);
610             }
611             else if ((legacyLight.type == LightType.Spot || legacyLight.type == LightType.Point) && lightUnit == LightUnit.Lux)
612             {
613                 // Box are local directional light with lux unity without at distance
614                 if ((legacyLight.type == LightType.Spot) && (spotLightShape == SpotLightShape.Box))
615                     legacyLight.intensity = intensity;
616                 else
617                     legacyLight.intensity = LightUtils.ConvertLuxToCandela(intensity, luxAtDistance);
618             }
619             else
620                 legacyLight.intensity = intensity;
621
622 #if UNITY_EDITOR
623             legacyLight.SetLightDirty(); // Should be apply only to parameter that's affect GI, but make the code cleaner
624 #endif
625         }
626
627         void SetLightIntensityPunctual(float intensity)
628         {
629             switch (legacyLight.type)
630             {
631                 case LightType.Directional:
632                     legacyLight.intensity = intensity; // Always in lux
633                     break;
634                 case LightType.Point:
635                     if (lightUnit == LightUnit.Candela)
636                         legacyLight.intensity = intensity;
637                     else
638                         legacyLight.intensity = LightUtils.ConvertPointLightLumenToCandela(intensity);
639                     break;
640                 case LightType.Spot:
641                     if (lightUnit == LightUnit.Candela)
642                     {
643                         // When using candela, reflector don't have any effect. Our intensity is candela = lumens/steradian and the user
644                         // provide desired value for an angle of 1 steradian.
645                         legacyLight.intensity = intensity;
646                     }
647                     else  // lumen
648                     {
649                         if (enableSpotReflector)
650                         {
651                             // If reflector is enabled all the lighting from the sphere is focus inside the solid angle of current shape
652                             if (spotLightShape == SpotLightShape.Cone)
653                             {
654                                 legacyLight.intensity = LightUtils.ConvertSpotLightLumenToCandela(intensity, legacyLight.spotAngle * Mathf.Deg2Rad, true);
655                             }
656                             else if (spotLightShape == SpotLightShape.Pyramid)
657                             {
658                                 float angleA, angleB;
659                                 LightUtils.CalculateAnglesForPyramid(aspectRatio, legacyLight.spotAngle * Mathf.Deg2Rad, out angleA, out angleB);
660
661                                 legacyLight.intensity = LightUtils.ConvertFrustrumLightLumenToCandela(intensity, angleA, angleB);
662                             }
663                             else // Box shape, fallback to punctual light.
664                             {
665                                 legacyLight.intensity = LightUtils.ConvertPointLightLumenToCandela(intensity);
666                             }
667                         }
668                         else
669                         {
670                             // No reflector, angle act as occlusion of point light.
671                             legacyLight.intensity = LightUtils.ConvertPointLightLumenToCandela(intensity);
672                         }
673                     }
674                     break;
675             }
676         }
677
678         public static bool IsAreaLight(LightTypeExtent lightType)
679         {
680             return lightType != LightTypeExtent.Punctual;
681         }
682
683 #if UNITY_EDITOR
684
685         // Force to retrieve color light's m_UseColorTemperature because it's private
686         [System.NonSerialized]
687         SerializedProperty useColorTemperatureProperty;
688         [System.NonSerialized]
689         SerializedObject lightSerializedObject;
690         public bool useColorTemperature
691         {
692             get
693             {
694                 if (useColorTemperatureProperty == null)
695                 {
696                     lightSerializedObject = new SerializedObject(legacyLight);
697                     useColorTemperatureProperty = lightSerializedObject.FindProperty("m_UseColorTemperature");
698                 }
699
700                 lightSerializedObject.Update();
701
702                 return useColorTemperatureProperty.boolValue;
703             }
704         }
705         
706         public static bool IsAreaLight(SerializedProperty lightType)
707         {
708             return IsAreaLight((LightTypeExtent)lightType.enumValueIndex);
709         }
710
711 #endif
712
713         [System.NonSerialized]
714         bool m_Animated;
715
716         private void Start()
717         {
718             // If there is an animator attached ot the light, we assume that some of the light properties
719             // might be driven by this animator (using timeline or animations) so we force the LateUpdate
720             // to sync the animated HDAdditionalLightData properties with the light component.
721             m_Animated = GetComponent<Animator>() != null;
722         }
723
724         // TODO: There are a lot of old != current checks and assignation in this function, maybe think about using another system ?
725         void LateUpdate()
726         {
727 // We force the animation in the editor and in play mode when there is an animator component attached to the light
728 #if !UNITY_EDITOR
729             if (!m_Animated)
730                 return;
731 #endif
732
733             Vector3 shape = new Vector3(shapeWidth, shapeHeight, shapeRadius);
734
735             // Check if the intensity have been changed by the inspector or an animator
736             if (displayLightIntensity != timelineWorkaround.oldDisplayLightIntensity
737                 || luxAtDistance != timelineWorkaround.oldLuxAtDistance
738                 || lightTypeExtent != timelineWorkaround.oldLightTypeExtent
739                 || transform.localScale != timelineWorkaround.oldLocalScale
740                 || shape != timelineWorkaround.oldShape
741                 || legacyLight.colorTemperature != timelineWorkaround.oldLightColorTemperature)
742             {
743                 RefreshLightIntensity();
744                 UpdateAreaLightEmissiveMesh();
745                 timelineWorkaround.oldDisplayLightIntensity = displayLightIntensity;
746                 timelineWorkaround.oldLuxAtDistance = luxAtDistance;
747                 timelineWorkaround.oldLocalScale = transform.localScale;
748                 timelineWorkaround.oldLightTypeExtent = lightTypeExtent;
749                 timelineWorkaround.oldLightColorTemperature = legacyLight.colorTemperature;
750                 timelineWorkaround.oldShape = shape;
751             }
752
753             // Same check for light angle to update intensity using spot angle
754             if (legacyLight.type == LightType.Spot && (timelineWorkaround.oldSpotAngle != legacyLight.spotAngle || timelineWorkaround.oldEnableSpotReflector != enableSpotReflector))
755             {
756                 RefreshLightIntensity();
757                 timelineWorkaround.oldSpotAngle = legacyLight.spotAngle;
758                 timelineWorkaround.oldEnableSpotReflector = enableSpotReflector;
759             }
760
761             if (legacyLight.color != timelineWorkaround.oldLightColor
762                 || transform.localScale != timelineWorkaround.oldLocalScale
763                 || displayAreaLightEmissiveMesh != timelineWorkaround.oldDisplayAreaLightEmissiveMesh
764                 || lightTypeExtent != timelineWorkaround.oldLightTypeExtent
765                 || legacyLight.colorTemperature != timelineWorkaround.oldLightColorTemperature
766                 || lightDimmer != timelineWorkaround.lightDimmer)
767             {
768                 UpdateAreaLightEmissiveMesh();
769                 timelineWorkaround.lightDimmer = lightDimmer;
770                 timelineWorkaround.oldLightColor = legacyLight.color;
771                 timelineWorkaround.oldLocalScale = transform.localScale;
772                 timelineWorkaround.oldDisplayAreaLightEmissiveMesh = displayAreaLightEmissiveMesh;
773                 timelineWorkaround.oldLightTypeExtent = lightTypeExtent;
774                 timelineWorkaround.oldLightColorTemperature = legacyLight.colorTemperature;
775             }
776         }
777
778         // The editor can only access displayLightIntensity (because of SerializedProperties) so we update the intensity to get the real value
779         void RefreshLightIntensity()
780         {
781             intensity = displayLightIntensity;
782         }
783
784         public void UpdateAreaLightEmissiveMesh()
785         {
786             MeshRenderer emissiveMeshRenderer = GetComponent<MeshRenderer>();
787             MeshFilter emissiveMeshFilter = GetComponent<MeshFilter>();
788
789             bool displayEmissiveMesh = IsAreaLight(lightTypeExtent) && displayAreaLightEmissiveMesh;
790
791             // Ensure that the emissive mesh components are here
792             if (displayEmissiveMesh)
793             {
794                 if (emissiveMeshRenderer == null)
795                     emissiveMeshRenderer = gameObject.AddComponent<MeshRenderer>();
796                 if (emissiveMeshFilter == null)
797                     emissiveMeshFilter = gameObject.AddComponent<MeshFilter>();
798             }
799             else // Or remove them if the option is disabled
800             {
801                 if (emissiveMeshRenderer != null)
802                     DestroyImmediate(emissiveMeshRenderer);
803                 if (emissiveMeshFilter != null)
804                     DestroyImmediate(emissiveMeshFilter);
805
806                 // We don't have anything to do left if the dislay emissive mesh option is disabled
807                 return;
808             }
809
810             Vector3 lightSize;
811
812             // Update light area size from GameObject transform scale if the transform have changed
813             // else we update the light size from the shape fields
814             if (timelineWorkaround.oldLocalScale != transform.localScale)
815                 lightSize = transform.localScale;
816             else
817                 lightSize = new Vector3(shapeWidth, shapeHeight, transform.localScale.z);
818
819             if (lightTypeExtent == LightTypeExtent.Tube)
820                 lightSize.y = k_MinAreaWidth;
821             lightSize.z = k_MinAreaWidth;
822
823             lightSize = Vector3.Max(Vector3.one * k_MinAreaWidth, lightSize);
824             legacyLight.transform.localScale = lightSize;
825 #if UNITY_EDITOR
826             legacyLight.areaSize = lightSize;
827 #endif
828
829             switch (lightTypeExtent)
830             {
831                 case LightTypeExtent.Rectangle:
832                     shapeWidth = lightSize.x;
833                     shapeHeight = lightSize.y;
834                     break;
835                 case LightTypeExtent.Tube:
836                     shapeWidth = lightSize.x;
837                     break;
838                 default:
839                     break;
840             }
841
842             // NOTE: When the user duplicates a light in the editor, the material is not duplicated and when changing the properties of one of them (source or duplication)
843             // It either overrides both or is overriden. Given that when we duplicate an object the name changes, this approach works. When the name of the game object is then changed again
844             // the material is not re-created until one of the light properties is changed again.
845             if (emissiveMeshRenderer.sharedMaterial == null || emissiveMeshRenderer.sharedMaterial.name != gameObject.name)
846             {
847                 emissiveMeshRenderer.sharedMaterial = new Material(Shader.Find("HDRP/Unlit"));
848                 emissiveMeshRenderer.sharedMaterial.SetFloat("_IncludeIndirectLighting", 0.0f);
849                 emissiveMeshRenderer.sharedMaterial.name = gameObject.name;
850             }
851
852             // Update Mesh emissive properties
853             emissiveMeshRenderer.sharedMaterial.SetColor("_UnlitColor", Color.black);
854
855             // m_Light.intensity is in luminance which is the value we need for emissive color
856             Color value = legacyLight.color.linear * legacyLight.intensity;
857
858 // We don't have access to the color temperature in the player because it's a private member of the Light component
859 #if UNITY_EDITOR
860             if (useColorTemperature)
861                 value *= Mathf.CorrelatedColorTemperatureToRGB(legacyLight.colorTemperature);
862 #endif
863
864             value *= lightDimmer;
865
866             emissiveMeshRenderer.sharedMaterial.SetColor("_EmissiveColor", value);
867
868             // Set the cookie (if there is one) and raise or remove the shader feature
869             emissiveMeshRenderer.sharedMaterial.SetTexture("_EmissiveColorMap", areaLightCookie);
870             CoreUtils.SetKeyword(emissiveMeshRenderer.sharedMaterial, "_EMISSIVE_COLOR_MAP", areaLightCookie != null);
871         }
872
873         public void CopyTo(HDAdditionalLightData data)
874         {
875 #pragma warning disable 618
876             data.directionalIntensity = directionalIntensity;
877             data.punctualIntensity = punctualIntensity;
878             data.areaIntensity = areaIntensity;
879 #pragma warning restore 618
880             data.enableSpotReflector = enableSpotReflector;
881             data.luxAtDistance = luxAtDistance;
882             data.m_InnerSpotPercent = m_InnerSpotPercent;
883             data.lightDimmer = lightDimmer;
884             data.volumetricDimmer = volumetricDimmer;
885             data.lightUnit = lightUnit;
886             data.fadeDistance = fadeDistance;
887             data.affectDiffuse = affectDiffuse;
888             data.affectSpecular = affectSpecular;
889             data.nonLightmappedOnly = nonLightmappedOnly;
890             data.lightTypeExtent = lightTypeExtent;
891             data.spotLightShape = spotLightShape;
892             data.shapeWidth = shapeWidth;
893             data.shapeHeight = shapeHeight;
894             data.aspectRatio = aspectRatio;
895             data.shapeRadius = shapeRadius;
896             data.maxSmoothness = maxSmoothness;
897             data.applyRangeAttenuation = applyRangeAttenuation;
898             data.useOldInspector = useOldInspector;
899             data.featuresFoldout = featuresFoldout;
900             data.showAdditionalSettings = showAdditionalSettings;
901             data.displayLightIntensity = displayLightIntensity;
902             data.displayAreaLightEmissiveMesh = displayAreaLightEmissiveMesh;
903             data.needsIntensityUpdate_1_0 = needsIntensityUpdate_1_0;
904
905 #if UNITY_EDITOR
906             data.timelineWorkaround = timelineWorkaround;
907 #endif
908         }
909
910         void SetSpotLightShape(SpotLightShape shape)
911         {
912             m_SpotLightShape = shape;
913             UpdateBounds();
914         }
915
916         void UpdateAreaLightBounds()
917         {
918             legacyLight.useShadowMatrixOverride = false;
919             legacyLight.useBoundingSphereOverride = true;
920             legacyLight.boundingSphereOverride = new Vector4(0.0f, 0.0f, 0.0f, legacyLight.range);
921         }
922
923         void UpdateBoxLightBounds()
924         {
925             legacyLight.useShadowMatrixOverride = true;
926             legacyLight.useBoundingSphereOverride = true;
927
928             // Need to inverse scale because culling != rendering convention apparently
929             Matrix4x4 scaleMatrix = Matrix4x4.Scale(new Vector3(1.0f, 1.0f, -1.0f));
930             legacyLight.shadowMatrixOverride = HDShadowUtils.ExtractBoxLightProjectionMatrix(legacyLight.range, shapeWidth, shapeHeight, shadowNearPlane) * scaleMatrix;
931
932             // Very conservative bounding sphere taking the diagonal of the shape as the radius
933             float diag = new Vector3(shapeWidth * 0.5f, shapeHeight * 0.5f, legacyLight.range * 0.5f).magnitude;
934             legacyLight.boundingSphereOverride = new Vector4(0.0f, 0.0f, legacyLight.range * 0.5f, diag);
935         }
936
937         void UpdatePyramidLightBounds()
938         {
939             legacyLight.useShadowMatrixOverride = true;
940             legacyLight.useBoundingSphereOverride = true;
941
942             // Need to inverse scale because culling != rendering convention apparently
943             Matrix4x4 scaleMatrix = Matrix4x4.Scale(new Vector3(1.0f, 1.0f, -1.0f));
944             legacyLight.shadowMatrixOverride = HDShadowUtils.ExtractSpotLightProjectionMatrix(legacyLight.range, legacyLight.spotAngle, shadowNearPlane, aspectRatio, 0.0f) * scaleMatrix;
945
946             // Very conservative bounding sphere taking the diagonal of the shape as the radius
947             float diag = new Vector3(shapeWidth * 0.5f, shapeHeight * 0.5f, legacyLight.range * 0.5f).magnitude;
948             legacyLight.boundingSphereOverride = new Vector4(0.0f, 0.0f, legacyLight.range * 0.5f, diag);
949         }
950
951         void UpdateBounds()
952         {
953             if (lightTypeExtent == LightTypeExtent.Punctual && legacyLight.type == LightType.Spot)
954             {
955                 switch (spotLightShape)
956                 {
957                     case SpotLightShape.Box:
958                         UpdateBoxLightBounds();
959                         break;
960                     case SpotLightShape.Pyramid:
961                         UpdatePyramidLightBounds();
962                         break;
963                     default: // Cone
964                         legacyLight.useBoundingSphereOverride = false;
965                         legacyLight.useShadowMatrixOverride = false;
966                         break;
967                 }
968             }
969             else if (lightTypeExtent == LightTypeExtent.Rectangle || lightTypeExtent == LightTypeExtent.Tube)
970             {
971                 UpdateAreaLightBounds();
972             }
973             else
974             {
975                 legacyLight.useBoundingSphereOverride = false;
976                 legacyLight.useShadowMatrixOverride = false;
977             }
978         }
979
980         // As we have our own default value, we need to initialize the light intensity correctly
981         public static void InitDefaultHDAdditionalLightData(HDAdditionalLightData lightData)
982         {
983             // Special treatment for Unity built-in area light. Change it to our rectangle light
984             var light = lightData.gameObject.GetComponent<Light>();
985
986             // Set light intensity and unit using its type
987             switch (light.type)
988             {
989                 case LightType.Directional:
990                     lightData.lightUnit = LightUnit.Lux;
991                     lightData.intensity = k_DefaultDirectionalLightIntensity;
992                     break;
993                 case LightType.Rectangle: // Rectangle by default when light is created
994                     lightData.lightUnit = LightUnit.Lumen;
995                     lightData.intensity = k_DefaultAreaLightIntensity;
996                     light.shadows = LightShadows.None;
997                     break;
998                 case LightType.Point:
999                 case LightType.Spot:
1000                     lightData.lightUnit = LightUnit.Lumen;
1001                     lightData.intensity = k_DefaultPunctualLightIntensity;
1002                     break;
1003             }
1004
1005             // Sanity check: lightData.lightTypeExtent is init to LightTypeExtent.Punctual (in case for unknow reasons we recreate additional data on an existing line)
1006             if (light.type == LightType.Rectangle && lightData.lightTypeExtent == LightTypeExtent.Punctual)
1007             {
1008                 lightData.lightTypeExtent = LightTypeExtent.Rectangle;
1009                 light.type = LightType.Point; // Same as in HDLightEditor
1010 #if UNITY_EDITOR
1011                 light.lightmapBakeType = LightmapBakeType.Realtime;
1012 #endif
1013             }
1014
1015             // We don't use the global settings of shadow mask by default
1016             light.lightShadowCasterMode = LightShadowCasterMode.Everything;
1017         }
1018
1019         void OnValidate()
1020         {
1021             UpdateBounds();
1022         }
1023
1024         public void OnBeforeSerialize()
1025         {
1026             UpdateBounds();
1027         }
1028
1029         public void OnAfterDeserialize()
1030         {
1031             // Note: the field version is deprecated but we keep it for retro-compatibility reasons, you should use m_Version instead
1032 #pragma warning disable 618
1033             if (version <= 1.0f)
1034 #pragma warning restore 618
1035             {
1036                 // Note: We can't access to the light component in OnAfterSerialize as it is not init() yet,
1037                 // so instead we use a boolean to do the upgrade in OnEnable().
1038                 // However OnEnable is not call when the light is disabled, so the HDLightEditor also call
1039                 // the UpgradeLight() code in this case
1040                 needsIntensityUpdate_1_0 = true;
1041             }
1042         }
1043
1044         private void OnEnable()
1045         {
1046             UpgradeLight();
1047         }
1048
1049         public void UpgradeLight()
1050         {
1051 // Disable the warning generated by deprecated fields (areaIntensity, directionalIntensity, ...)
1052 #pragma warning disable 618
1053
1054             // If we are deserializing an old version, convert the light intensity to the new system
1055             if (needsIntensityUpdate_1_0)
1056             {
1057                 switch (lightTypeExtent)
1058                 {
1059                     case LightTypeExtent.Punctual:
1060                         switch (legacyLight.type)
1061                         {
1062                             case LightType.Directional:
1063                                 lightUnit = LightUnit.Lux;
1064                                 intensity = directionalIntensity;
1065                                 break;
1066                             case LightType.Spot:
1067                             case LightType.Point:
1068                                 lightUnit = LightUnit.Lumen;
1069                                 intensity = punctualIntensity;
1070                                 break;
1071                         }
1072                         break;
1073                     case LightTypeExtent.Tube:
1074                     case LightTypeExtent.Rectangle:
1075                         lightUnit = LightUnit.Lumen;
1076                         intensity = areaIntensity;
1077                         break;
1078                 }
1079                 needsIntensityUpdate_1_0 = false;
1080             }
1081             if (m_Version <= 2)
1082             {
1083                 // ShadowNearPlane have been move to HDRP as default legacy unity clamp it to 0.1 and we need to be able to go below that
1084                 shadowNearPlane = legacyLight.shadowNearPlane;
1085             }
1086             if (m_Version <= 3)
1087             {
1088                 legacyLight.renderingLayerMask = LightLayerToRenderingLayerMask((int)lightLayers, legacyLight.renderingLayerMask);
1089             }
1090             if (m_Version <= 4)
1091             {
1092                 // When we upgrade the option to decouple light and shadow layers will be disabled
1093                 // so we can sync the shadow layer mask (from the legacyLight) and the new light layer mask
1094                 lightlayersMask = (LightLayerEnum)RenderingLayerMaskToLightLayer(legacyLight.renderingLayerMask);
1095             }
1096
1097             m_Version = currentVersion;
1098             version = currentVersion;
1099
1100 #pragma warning restore 0618
1101         }
1102
1103         /// <summary>
1104         /// Converts a light layer into a rendering layer mask.
1105         ///
1106         /// Light layer is stored in the first 8 bit of the rendering layer mask.
1107         ///
1108         /// NOTE: light layers are obsolete, use directly renderingLayerMask.
1109         /// </summary>
1110         /// <param name="lightLayer">The light layer, only the first 8 bits will be used.</param>
1111         /// <param name="renderingLayerMask">Current renderingLayerMask, only the last 24 bits will be used.</param>
1112         /// <returns></returns>
1113         internal static int LightLayerToRenderingLayerMask(int lightLayer, int renderingLayerMask)
1114         {
1115             var renderingLayerMask_u32 = (uint)renderingLayerMask;
1116             var lightLayer_u8 = (byte)lightLayer;
1117             return (int)((renderingLayerMask_u32 & 0xFFFFFF00) | lightLayer_u8);
1118         }
1119
1120         /// <summary>
1121         /// Converts a renderingLayerMask into a lightLayer.
1122         ///
1123         /// NOTE: light layers are obsolete, use directly renderingLayerMask.
1124         /// </summary>
1125         /// <param name="renderingLayerMask"></param>
1126         /// <returns></returns>
1127         internal static int RenderingLayerMaskToLightLayer(int renderingLayerMask)
1128             => (byte)renderingLayerMask;
1129     }
1130 }