160 lines
6.4 KiB
C#
160 lines
6.4 KiB
C#
using UnityEngine;
|
|
|
|
namespace VLB
|
|
{
|
|
[DisallowMultipleComponent]
|
|
[RequireComponent(typeof(VolumetricLightBeamAbstractBase))]
|
|
[HelpURL(Consts.Help.UrlTriggerZone)]
|
|
public class TriggerZone : MonoBehaviour
|
|
{
|
|
public const string ClassName = "TriggerZone";
|
|
|
|
/// <summary>
|
|
/// Define if the Collider will be created as a convex trigger (not physical, most common behavior) or as a regular collider (physical).
|
|
/// </summary>
|
|
public bool setIsTrigger = true;
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
public float rangeMultiplier = 1.0f;
|
|
|
|
enum TriggerZoneUpdateRate
|
|
{
|
|
/// <summary>Compute the Trigger Zone only once at startup</summary>
|
|
OnEnable,
|
|
/// <summary>Compute the Trigger Zone each time the dynamic occlusion has changed</summary>
|
|
OnOcclusionChange,
|
|
}
|
|
|
|
/// <summary>
|
|
/// How often will the Trigger Zone be computed?
|
|
/// </summary>
|
|
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<VolumetricLightBeamAbstractBase>();
|
|
Debug.Assert(m_Beam != null);
|
|
|
|
m_DynamicOcclusionRaycasting = GetComponent<DynamicOcclusionRaycasting>();
|
|
|
|
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<MeshCollider>();
|
|
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<PolygonCollider2D>();
|
|
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
|
|
}
|
|
}
|