Files
Shopping_UnityVR/Packages/com.baddog.rendering.arealight/Runtime/BGAreaLight.cs
2026-04-16 04:58:10 +09:00

312 lines
9.0 KiB
C#

using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace BadDog.Rendering.AreaLight
{
/// <summary>
/// Attach this component to a Light to enable area light calculations.
/// </summary>
[ExecuteAlways]
[RequireComponent(typeof(Light))]
[DisallowMultipleComponent]
[AddComponentMenu("BadDog/Rendering/BGAreaLight")]
public class BGAreaLight : MonoBehaviour
{
private Light m_Light;
[SerializeField]
[Tooltip("Enable shadow casting for this area light.")]
private bool m_CastShadows = true;
[SerializeField]
[Tooltip("Enable custom shadow settings for this area light.")]
private bool m_UseCustomShadow = false;
[SerializeField]
[Range(0, 8192)]
[Tooltip("Custom shadow map resolution for this area light. Set to 0 to use pipeline defaults.")]
private int m_CustomShadowResolution = 0;
[SerializeField]
[Range(AreaShadowUtils.k_MinAreaLightShadowCone, AreaShadowUtils.k_MaxAreaLightShadowCone)]
[Tooltip("Aperture of the cone used for shadowing the area light.")]
private float m_ShadowCone = AreaShadowUtils.k_DefaultAreaLightShadowCone;
[SerializeField]
[Range(0f, 1f)]
[Tooltip("Shadow strength for this area light. Applied to Light.shadowStrength.")]
private float m_ShadowStrength = 1f;
[SerializeField]
[Range(0f, 10f)]
[Tooltip("Normal bias used for area light shadowing.")]
private float m_ShadowNormalBias = 0.05f;
[SerializeField]
[Range(0f, 10f)]
[Tooltip("Depth bias used for area light shadowing. Acts like Light.shadowBias for rectangle lights.")]
private float m_ShadowDepthBias = 0.05f;
[SerializeField]
[Range(AreaShadowUtils.k_MinShadowNearPlane, AreaShadowUtils.k_MaxShadowNearPlane)]
[Tooltip("Shadow near plane for area light. Controls the starting distance of the shadow frustum.")]
private float m_ShadowNearPlane = 0.1f;
[SerializeField]
[Tooltip("Rendering Layer Mask used for area light lighting/shadow filtering.")]
private RenderingLayerMask m_RenderingLayerMask = (RenderingLayerMask)1;
[SerializeField, HideInInspector]
private bool m_PreBakeEnabled;
[SerializeField, HideInInspector]
private Vector2 m_CachedAreaSize = new Vector2(1.0f, 0.5f);
private void Awake()
{
OnValidate();
}
private void OnEnable()
{
OnValidate();
BGAreaLightManager.RegisterAreaLight(this);
#if UNITY_EDITOR
UnityEditor.Lightmapping.bakeStarted += OnBakeStarted;
UnityEditor.Lightmapping.bakeCompleted += OnBakeCompleted;
#endif
}
private void OnDisable()
{
BGAreaLightManager.UnRegisterAreaLight(this);
#if UNITY_EDITOR
UnityEditor.Lightmapping.bakeStarted -= OnBakeStarted;
UnityEditor.Lightmapping.bakeCompleted -= OnBakeCompleted;
#endif
}
private void OnDestroy()
{
BGAreaLightManager.UnRegisterAreaLight(this);
}
private void OnValidate()
{
EnsureLight();
EnsureRectangleType();
ForceRealtimeMode();
SyncCastShadowsToLight();
SetShadowCone(m_ShadowCone);
SetShadowDepthBias(m_ShadowDepthBias);
SetShadowNormalBias(m_ShadowNormalBias);
SetShadowNearPlane(m_ShadowNearPlane);
ApplyShadowStrength();
SyncRenderingLayerMaskToLight();
}
private void Update()
{
OnValidate();
}
private void ForceRealtimeMode()
{
#if UNITY_EDITOR
if (m_Light.lightmapBakeType != LightmapBakeType.Realtime)
{
m_Light.lightmapBakeType = LightmapBakeType.Realtime;
UnityEditor.EditorUtility.SetDirty(m_Light);
}
#endif
}
private void EnsureLight()
{
if (m_Light == null)
{
m_Light = GetComponent<Light>();
}
}
private void EnsureRectangleType()
{
if (m_Light.type != LightType.Rectangle)
{
m_Light.type = LightType.Rectangle;
#if UNITY_EDITOR
UnityEditor.EditorUtility.SetDirty(m_Light);
#endif
}
#if UNITY_EDITOR
if (m_Light.areaSize == Vector2.zero)
{
m_Light.areaSize = new Vector2(1.0f, 0.5f);
UnityEditor.EditorUtility.SetDirty(m_Light);
}
#endif
// Keep the runtime cache in sync with the Light's current area size.
m_CachedAreaSize = m_Light.areaSize;
}
private void ApplyShadowStrength()
{
float clamped = Mathf.Clamp01(m_ShadowStrength);
m_Light.shadowStrength = clamped;
#if UNITY_EDITOR
UnityEditor.EditorUtility.SetDirty(m_Light);
#endif
}
private void SyncCastShadowsToLight()
{
if (m_Light == null)
{
return;
}
LightShadows targetShadows = m_CastShadows ? LightShadows.Soft : LightShadows.None;
if (m_Light.shadows != targetShadows)
{
m_Light.shadows = targetShadows;
#if UNITY_EDITOR
UnityEditor.EditorUtility.SetDirty(m_Light);
#endif
}
}
private void SyncRenderingLayerMaskToLight()
{
if (m_Light == null)
{
return;
}
if (m_Light.renderingLayerMask != m_RenderingLayerMask)
{
m_Light.renderingLayerMask = m_RenderingLayerMask;
#if UNITY_EDITOR
UnityEditor.EditorUtility.SetDirty(m_Light);
#endif
}
}
public Light GetLight()
{
EnsureLight();
return m_Light;
}
public int GetCustomShadowResolution()
{
return m_CustomShadowResolution;
}
public Vector2 GetSize()
{
return m_CachedAreaSize;
}
public float GetShadowCone()
{
return Mathf.Clamp(m_ShadowCone, AreaShadowUtils.k_MinAreaLightShadowCone, AreaShadowUtils.k_MaxAreaLightShadowCone);
}
public float GetShadowDepthBias()
{
return Mathf.Max(0f, m_ShadowDepthBias);
}
public void SetShadowDepthBias(float value)
{
float clamped = Mathf.Max(0f, value);
m_ShadowDepthBias = clamped;
}
public float GetShadowNormalBias()
{
return Mathf.Max(0f, m_ShadowNormalBias);
}
public void SetShadowNormalBias(float value)
{
float clamped = Mathf.Max(0f, value);
m_ShadowNormalBias = clamped;
}
public float GetShadowNearPlane()
{
return Mathf.Clamp(m_ShadowNearPlane, AreaShadowUtils.k_MinShadowNearPlane, AreaShadowUtils.k_MaxShadowNearPlane);
}
public void SetShadowNearPlane(float value)
{
float clamped = Mathf.Clamp(value, AreaShadowUtils.k_MinShadowNearPlane, AreaShadowUtils.k_MaxShadowNearPlane);
m_ShadowNearPlane = clamped;
}
public void SetShadowCone(float value)
{
float clamped = Mathf.Clamp(value, AreaShadowUtils.k_MinAreaLightShadowCone, AreaShadowUtils.k_MaxAreaLightShadowCone);
m_ShadowCone = clamped;
}
public bool GetIsRectLight()
{
Vector2 size = GetSize();
return size.y > 0.001f;
}
public float GetRangeAttenuationScale()
{
if (m_Light == null)
{
return 1.0f;
}
float range = m_Light.range;
if (range <= 0f)
{
return 1.0f;
}
return 1.0f / (range * range);
}
public float GetRangeAttenuationBias()
{
return 1.0f;
}
#if UNITY_EDITOR
private void OnBakeStarted()
{
EnsureLight();
if (m_Light == null)
{
return;
}
m_PreBakeEnabled = m_Light.enabled;
m_Light.enabled = false;
}
private void OnBakeCompleted()
{
EnsureLight();
if (m_Light == null)
{
return;
}
m_Light.enabled = m_PreBakeEnabled;
m_Light.lightmapBakeType = LightmapBakeType.Realtime;
UnityEditor.EditorUtility.SetDirty(m_Light);
}
#endif
}
}