2026-04-16 오브젝트 그림자
This commit is contained in:
311
Packages/com.baddog.rendering.arealight/Runtime/BGAreaLight.cs
Normal file
311
Packages/com.baddog.rendering.arealight/Runtime/BGAreaLight.cs
Normal file
@@ -0,0 +1,311 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user