Files
LowPolyRPG/Assets/Plugins/RaycastPro/Core/Utility/FOVMesh.cs
Caleb Sandford deQuincey 715fb68744 Initial commitment
2025-06-25 11:10:11 +01:00

201 lines
6.4 KiB
C#

namespace RaycastPro.Sensor
{
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
[RequireComponent(typeof(MeshCollider))]
public sealed class FOVMesh : BaseUtility
{
[Tooltip("Length of the view cone.")]
public float Length = 5f;
[Tooltip("Base size of the cone.")]
public float BaseSize = 0.5f;
[Range(1f, 180f)]
public float HorizontalFOV = 90f;
[Range(1f, 180f)]
public float VerticalFOV = 90f;
[Range(3, 32)]
public int SegmentCount = 8;
Mesh fovMesh = new Mesh();
public Mesh GetFOVMesh => fovMesh;
public MeshCollider meshCollider = new MeshCollider();
private void Reset()
{
// تلاش برای گرفتن MeshCollider
meshCollider = GetComponent<MeshCollider>();
// اگر وجود نداشت، خودش اضافه کند
if (meshCollider == null)
{
meshCollider = gameObject.AddComponent<MeshCollider>();
Debug.Log("MeshCollider was missing. A new one was added automatically to: " + gameObject.name);
}
}
// عرض مربع ابتدایی
public float BaseDepth = 0.001f; // چقدر عقب‌تر از نقطه شروع قرار بگیرد
void GenerateFOVMeshCollider()
{
// 4 vertex for base quad + 1 center + grid
int baseVertexCount = 4;
int baseTriangleCount = 2 * 3;
int gridVertexCount = 1 + SegmentCount * SegmentCount;
int gridTriangleCount = (SegmentCount - 1) * (SegmentCount - 1) * 2 * 3;
int totalVertices = baseVertexCount + gridVertexCount;
int totalTriangles = baseTriangleCount + gridTriangleCount;
Vector3[] vertices = new Vector3[totalVertices];
int[] triangles = new int[totalTriangles];
// 🟩 Base quad setup (مربع در پشت دید)
Vector3 baseDir = Quaternion.Euler(0, 0, 0) * Vector3.forward; // جهت وسط
Vector3 baseCenter = -baseDir * BaseDepth;
// بدست آوردن جهت‌های عمودی و افقی نسبت به جهت میانی
Vector3 right = Quaternion.Euler(0, 90, 0) * baseDir;
Vector3 up = Quaternion.Euler(-90, 0, 0) * baseDir;
float half = BaseSize * 0.5f;
vertices[0] = baseCenter + (-right - up) * half;
vertices[1] = baseCenter + (right - up) * half;
vertices[2] = baseCenter + (-right + up) * half;
vertices[3] = baseCenter + (right + up) * half;
// 🔺 دو مثلث پایه
int tri = 0;
triangles[tri++] = 0;
triangles[tri++] = 2;
triangles[tri++] = 1;
triangles[tri++] = 1;
triangles[tri++] = 2;
triangles[tri++] = 3;
// ⚙️ رأس مرکز مخروط
int offset = baseVertexCount;
vertices[offset] = Vector3.zero;
int index = offset + 1;
for (int y = 0; y < SegmentCount; y++)
{
float pitch = Mathf.Lerp(-VerticalFOV / 2f, VerticalFOV / 2f, y / (float)(SegmentCount - 1));
for (int x = 0; x < SegmentCount; x++)
{
float yaw = Mathf.Lerp(-HorizontalFOV / 2f, HorizontalFOV / 2f, x / (float)(SegmentCount - 1));
Vector3 dir = Quaternion.Euler(pitch, yaw, 0f) * Vector3.forward;
vertices[index++] = dir.normalized * Length;
}
}
// ⛓️ مثلث‌های مش اصلی
for (int y = 0; y < SegmentCount - 1; y++)
{
for (int x = 0; x < SegmentCount - 1; x++)
{
int i0 = offset + 1 + y * SegmentCount + x;
int i1 = i0 + 1;
int i2 = i0 + SegmentCount;
int i3 = i2 + 1;
triangles[tri++] = i0;
triangles[tri++] = i2;
triangles[tri++] = i1;
triangles[tri++] = i1;
triangles[tri++] = i2;
triangles[tri++] = i3;
}
}
// 📦 ساخت مش
if (fovMesh == null)
fovMesh = new Mesh { name = "FOV_Mesh" };
else
fovMesh.Clear();
// بررسی محدودیت کانکس مش
int triangleCount = triangles.Length / 3;
if (triangleCount > 255)
{
Debug.LogWarning($"FOV Mesh has {triangleCount} triangles, which exceeds Unity's convex mesh limit. Reducing SegmentCount.");
while (((SegmentCount - 1) * (SegmentCount - 1) * 2 + 2) > 255 && SegmentCount > 2)
SegmentCount--;
GenerateFOVMeshCollider(); // دوباره تولید کن
return;
}
fovMesh.vertices = vertices;
fovMesh.triangles = triangles;
fovMesh.RecalculateNormals();
fovMesh.RecalculateBounds();
// جلوگیری از تجاوز محدودیت کانکس
bool forceNonConvex = triangles.Length / 3 > 255;
if (forceNonConvex)
Debug.LogWarning($"FOV Mesh has too many triangles ({triangles.Length / 3}). Using non-convex collider.");
meshCollider.sharedMesh = fovMesh;
meshCollider.convex = !forceNonConvex;
meshCollider.isTrigger = true;
}
public override bool Performed { get; protected set; }
protected override void OnCast()
{
GenerateFOVMeshCollider();
}
#if UNITY_EDITOR
internal override string Info => "Auxiliary tool for creating dynamic view FOV Mesh. Best suitable for Mesh Detector" + HUtility + HDependent;
internal override void OnGizmos()
{
if (IsSceneView) OnCast();
if (fovMesh == null) return;
Gizmos.color = Color.green;
foreach (var v in fovMesh.vertices)
{
Gizmos.DrawSphere(transform.TransformPoint(v), 0.05f);
}
}
internal override void EditorPanel(SerializedObject _so, bool hasMain = true, bool hasGeneral = true,
bool hasEvents = true,
bool hasInfo = true)
{
if (hasMain)
{
EditorGUILayout.PropertyField(_so.FindProperty(nameof(meshCollider)));
EditorGUILayout.PropertyField(_so.FindProperty(nameof(Length)));
EditorGUILayout.PropertyField(_so.FindProperty(nameof(BaseSize)));
EditorGUILayout.PropertyField(_so.FindProperty(nameof(HorizontalFOV)));
EditorGUILayout.PropertyField(_so.FindProperty(nameof(VerticalFOV)));
EditorGUILayout.PropertyField(_so.FindProperty(nameof(SegmentCount)));
}
if (hasGeneral)
{
BaseField(_so);
}
}
#endif
}
}