#if UNITY_EDITOR using UnityEditor; #endif using System; namespace UnityEngine.Rendering { /// /// Data-Driven Lens Flare can be added on any gameobject /// [ExecuteAlways] [AddComponentMenu("Rendering/Lens Flare (SRP)")] public sealed class LensFlareComponentSRP : MonoBehaviour { [SerializeField] private LensFlareDataSRP m_LensFlareData = null; /// /// Lens flare asset used on this component /// public LensFlareDataSRP lensFlareData { get { return m_LensFlareData; } set { m_LensFlareData = value; OnValidate(); } } /// /// Intensity /// [Min(0.0f)] public float intensity = 1.0f; /// /// Distance used to scale the Distance Attenuation Curve /// [Min(1e-5f)] public float maxAttenuationDistance = 100.0f; /// /// Distance used to scale the Scale Attenuation Curve /// [Min(1e-5f)] public float maxAttenuationScale = 100.0f; /// /// Attenuation by distance /// public AnimationCurve distanceAttenuationCurve = new AnimationCurve(new Keyframe(0.0f, 1.0f), new Keyframe(1.0f, 0.0f)); /// /// Scale by distance, use the same distance as distanceAttenuationCurve /// public AnimationCurve scaleByDistanceCurve = new AnimationCurve(new Keyframe(0.0f, 1.0f), new Keyframe(1.0f, 0.0f)); /// /// If component attached to a light, attenuation the lens flare per light type /// public bool attenuationByLightShape = true; /// /// Attenuation used radially, which allow for instance to enable flare only on the edge of the screen /// public AnimationCurve radialScreenAttenuationCurve = new AnimationCurve(new Keyframe(0.0f, 1.0f), new Keyframe(1.0f, 1.0f)); /// /// Enable Occlusion feature /// public bool useOcclusion = false; /// /// Radius around the light used to occlude the flare (value in world space) /// [Min(0.0f)] public float occlusionRadius = 0.1f; /// /// Enable Occlusion using Background Cloud (for instance: CloudLayer) /// public bool useBackgroundCloudOcclusion = false; /// /// Random Samples Count used inside the disk with 'occlusionRadius' /// [Range(1, 64)] public uint sampleCount = 32; /// /// Z Occlusion Offset allow us to offset the plane where the disc of occlusion is place (closer to camera), value on world space. /// Useful for instance to sample occlusion outside a light bulb if we place a flare inside the light bulb /// public float occlusionOffset = 0.05f; /// /// Global Scale /// [Min(0.0f)] public float scale = 1.0f; /// /// If allowOffScreen is true then If the lens flare is outside the screen we still emit the flare on screen /// public bool allowOffScreen = false; /// /// If volumetricCloudOcclusion is true then use the volumetric cloud (on HDRP only) for the occlusion /// public bool volumetricCloudOcclusion = false; /// Our default celestial body will have an angular radius of 3.3 degrees. This is an arbitrary number, but must be kept constant /// so the occlusion radius for direct lights is consistent regardless of near / far clip plane configuration. private static float sCelestialAngularRadius = 3.3f * Mathf.PI / 180.0f; /// /// OcclusionRemapCurve allow the occlusion [from 0 to 1] to be remap with any desired shape. /// public TextureCurve occlusionRemapCurve = new TextureCurve(AnimationCurve.Linear(0.0f, 0.0f, 1.0f, 1.0f), 1.0f, false, new Vector2(0.0f, 1.0f)); /// /// Retrieves the projected occlusion radius from a particular celestial in the infinity plane with an angular radius. /// This is used for directional lights which require to have consistent occlusion radius regardless of the near/farplane configuration. /// /// The camera utilized to calculate the occlusion radius /// The value, in world units, of the occlusion angular radius. public float celestialProjectedOcclusionRadius(Camera mainCam) { float projectedRadius = (float)Math.Tan(sCelestialAngularRadius) * mainCam.farClipPlane; return occlusionRadius * projectedRadius; } /// /// Add or remove the lens flare to the queue of PostProcess /// void OnEnable() { if (lensFlareData) LensFlareCommonSRP.Instance.AddData(this); else LensFlareCommonSRP.Instance.RemoveData(this); } /// /// Remove the lens flare from the queue of PostProcess /// void OnDisable() { LensFlareCommonSRP.Instance.RemoveData(this); } /// /// Add or remove the lens flare from the queue of PostProcess /// void OnValidate() { if (isActiveAndEnabled && lensFlareData != null) { LensFlareCommonSRP.Instance.AddData(this); } else { LensFlareCommonSRP.Instance.RemoveData(this); } } #if UNITY_EDITOR private float sDebugClippingSafePercentage = 0.9f; //for debug gizmo, only push 90% further so we avoid clipping of debug lines. void OnDrawGizmosSelected() { Camera mainCam = Camera.current; if (mainCam != null && useOcclusion) { Vector3 positionWS; float adjustedOcclusionRadius = occlusionRadius; Light light = GetComponent(); if (light != null && light.type == LightType.Directional) { positionWS = -transform.forward * (mainCam.farClipPlane * sDebugClippingSafePercentage) + mainCam.transform.position; adjustedOcclusionRadius = celestialProjectedOcclusionRadius(mainCam); } else { positionWS = transform.position; } Color previousH = Handles.color; Color previousG = Gizmos.color; Handles.color = Color.red; Gizmos.color = Color.red; Vector3 dir = (mainCam.transform.position - positionWS).normalized; Handles.DrawWireDisc(positionWS + dir * occlusionOffset, dir, adjustedOcclusionRadius, 1.0f); Gizmos.DrawWireSphere(positionWS, occlusionOffset); Gizmos.color = previousG; Handles.color = previousH; } } #endif } }