using System.Collections.Generic; using UnityEngine; public class FieldOfView : MonoBehaviour { public float viewRadius; [Range(0,360)] public float periAngle; [Range(0,180)] public float foveaAngle; public Transform eyeLeft; public Transform eyeRight; public LayerMask targetMask; public LayerMask obstacleMask; public float meshResolution; public MeshFilter periMeshFilter; public MeshFilter foveaMeshFilter; private Mesh periMesh; private Mesh foveaMesh; private void Start() { periMesh = new Mesh(); periMesh.name = "View Mesh"; periMeshFilter.mesh = periMesh; foveaMesh = new Mesh(); foveaMesh.name = "View Mesh"; foveaMeshFilter.mesh = foveaMesh; } private void LateUpdate() { Vector3 gazeDirection = ((eyeLeft.forward + eyeRight.forward) * 0.5f).normalized; float gazeAngle = AngleFromDir(gazeDirection, true); DrawFOV(transform.eulerAngles.y, periMesh, periAngle); DrawFOV(gazeAngle, foveaMesh, foveaAngle); } public Vector3 DirFromAngle(float angleDeg, bool angleIsGlobal) { if (!angleIsGlobal) { angleDeg += transform.eulerAngles.y; } return new Vector3(Mathf.Sin(angleDeg * Mathf.Deg2Rad), 0, Mathf.Cos(angleDeg * Mathf.Deg2Rad)); } public float AngleFromDir(Vector3 dir, bool angleIsGlobal) { // Sicherheitsnetz: y‑Komponente ignorieren und Vektor normalisieren dir.y = 0; if (dir.sqrMagnitude < 0.0001f) return 0f; // Atan2: (x, z) → Winkel in Rad, dann nach ° umrechnen float angleDeg = Mathf.Atan2(dir.x, dir.z) * Mathf.Rad2Deg; // Bereich schön sauber auf 0–360 bringen angleDeg = (angleDeg + 360f) % 360f; // Soll der Winkel relativ zum Objekt sein? if (!angleIsGlobal) angleDeg -= transform.eulerAngles.y; // Und noch einmal normalisieren, damit auch hier 0–360 garantiert ist return (angleDeg + 360f) % 360f; } void DrawFOV(float startAngle, Mesh viewMesh, float viewAngle) { int stepCount = Mathf.RoundToInt(foveaAngle * meshResolution); float stepAngleSize = viewAngle / stepCount; List viewPoints = new List(); for (int i = 0; i <= stepCount; i++) { float angle = startAngle - viewAngle / 2 + stepAngleSize * i; Debug.DrawLine(transform.position, transform.position + DirFromAngle(angle, true) * viewRadius, Color.red); ViewCastInfo newViewCast = ViewCast(angle); viewPoints.Add(newViewCast.hitPoint); } int vertexcount = viewPoints.Count + 1; Vector3[] vertices = new Vector3[vertexcount]; int[] triangles = new int[(vertexcount-2) * 3]; vertices[0] = Vector3.zero; for (int i = 0; i < vertexcount-1; i++) { vertices[i+1] = transform.InverseTransformPoint(viewPoints[i]); if (i < vertexcount - 2) { triangles[i * 3] = 0; triangles[i * 3 + 1] = i + 1; triangles[i * 3 + 2] = i + 2; } } viewMesh.Clear(); viewMesh.vertices = vertices; viewMesh.triangles = triangles; viewMesh.RecalculateNormals(); } ViewCastInfo ViewCast(float globalAngle) { Vector3 direction = DirFromAngle(globalAngle, true); RaycastHit hit; if (Physics.Raycast(transform.position, direction, out hit, viewRadius, obstacleMask)) { return new ViewCastInfo(true, hit.point, hit.distance, globalAngle); } else { return new ViewCastInfo(false, transform.position + direction * viewRadius, viewRadius, globalAngle); } } public struct ViewCastInfo { public bool didHit; public Vector3 hitPoint; public float distance; public float angle; public ViewCastInfo(bool _hit, Vector3 _hitPoint, float _distance, float _angle) { didHit = _hit; hitPoint = _hitPoint; distance = _distance; angle = _angle; } } }