using UnityEngine; namespace VLB { [DisallowMultipleComponent] [RequireComponent(typeof(VolumetricLightBeamAbstractBase))] [HelpURL(Consts.Help.UrlTriggerZone)] public class TriggerZone : MonoBehaviour { public const string ClassName = "TriggerZone"; /// /// Define if the Collider will be created as a convex trigger (not physical, most common behavior) or as a regular collider (physical). /// public bool setIsTrigger = true; /// /// Change the length of the Collider. For example, set 2.0 to make the Collider 2x longer than the beam. Default value is 1.0. /// public float rangeMultiplier = 1.0f; enum TriggerZoneUpdateRate { /// Compute the Trigger Zone only once at startup OnEnable, /// Compute the Trigger Zone each time the dynamic occlusion has changed OnOcclusionChange, } /// /// How often will the Trigger Zone be computed? /// TriggerZoneUpdateRate updateRate { get { Debug.Assert(m_Beam != null); if(UtilsBeamProps.GetDimensions(m_Beam) == Dimensions.Dim3D) return TriggerZoneUpdateRate.OnEnable; // for 3D meshes, do it only once because it's too performance heavy return m_DynamicOcclusionRaycasting != null ? TriggerZoneUpdateRate.OnOcclusionChange : TriggerZoneUpdateRate.OnEnable; } } const int kMeshColliderNumSides = 8; VolumetricLightBeamAbstractBase m_Beam = null; DynamicOcclusionRaycasting m_DynamicOcclusionRaycasting = null; PolygonCollider2D m_PolygonCollider2D = null; void OnEnable() { m_Beam = GetComponent(); Debug.Assert(m_Beam != null); m_DynamicOcclusionRaycasting = GetComponent(); switch(updateRate) { case TriggerZoneUpdateRate.OnEnable: { ComputeZone(); enabled = false; break; } case TriggerZoneUpdateRate.OnOcclusionChange: { if(m_DynamicOcclusionRaycasting) m_DynamicOcclusionRaycasting.onOcclusionProcessed += OnOcclusionProcessed; break; } } } void OnOcclusionProcessed() { ComputeZone(); } void ComputeZone() { if (m_Beam) { var coneRadiusStart = UtilsBeamProps.GetConeRadiusStart(m_Beam); var rangeEnd = UtilsBeamProps.GetFallOffEnd(m_Beam) * rangeMultiplier; var lerpedRadiusEnd = Mathf.LerpUnclamped(coneRadiusStart, UtilsBeamProps.GetConeRadiusEnd(m_Beam), rangeMultiplier); if (UtilsBeamProps.GetDimensions(m_Beam) == Dimensions.Dim3D) { var meshCollider = gameObject.GetOrAddComponent(); Debug.Assert(meshCollider); int sides = Mathf.Min(UtilsBeamProps.GetGeomSides(m_Beam), kMeshColliderNumSides); var mesh = MeshGenerator.GenerateConeZ_Radii_DoubleCaps( lengthZ: rangeEnd, radiusStart: coneRadiusStart, radiusEnd: lerpedRadiusEnd, numSides: kMeshColliderNumSides, inverted: false); mesh.hideFlags = Consts.Internal.ProceduralObjectsHideFlags; meshCollider.sharedMesh = mesh; meshCollider.convex = setIsTrigger; meshCollider.isTrigger = setIsTrigger; } else { if (m_PolygonCollider2D == null) { m_PolygonCollider2D = gameObject.GetOrAddComponent(); Debug.Assert(m_PolygonCollider2D); } var polyCoordsLS = new Vector2[] // polygon coord in local space { new Vector2(0.0f, -coneRadiusStart), new Vector2(rangeEnd, -lerpedRadiusEnd), new Vector2(rangeEnd, lerpedRadiusEnd), new Vector2(0.0f, coneRadiusStart) }; if (m_DynamicOcclusionRaycasting && m_DynamicOcclusionRaycasting.planeEquationWS.IsValid()) { var plane3dWS = m_DynamicOcclusionRaycasting.planeEquationWS; if (Utils.IsAlmostZero(plane3dWS.normal.z)) { // Compute 2 points on the plane in world space // Use this technique instead of transforming the plane's normal to fully support scaling var ptOnPlane1 = plane3dWS.ClosestPointOnPlaneCustom(Vector3.zero); var ptOnPlane2 = plane3dWS.ClosestPointOnPlaneCustom(Vector3.up); if(Utils.IsAlmostZero(Vector3.SqrMagnitude(ptOnPlane1 - ptOnPlane2))) ptOnPlane1 = plane3dWS.ClosestPointOnPlaneCustom(Vector3.right); // Compute 2 points on the plane in local space ptOnPlane1 = transform.InverseTransformPoint(ptOnPlane1); ptOnPlane2 = transform.InverseTransformPoint(ptOnPlane2); // Compute plane equation in local space var plane2dLS = PolygonHelper.Plane2D.FromPoints(ptOnPlane1, ptOnPlane2); if (plane2dLS.normal.x > 0.0f) plane2dLS.Flip(); polyCoordsLS = plane2dLS.CutConvex(polyCoordsLS); } } m_PolygonCollider2D.points = polyCoordsLS; m_PolygonCollider2D.isTrigger = setIsTrigger; } } } #if UNITY_EDITOR void OnValidate() { rangeMultiplier = Mathf.Max(rangeMultiplier, 0.001f); } #endif } }