How to check if an object is in a field of view? Not only check the center of the object but any part is fine.

Hello

I just make a field of view mesh, so I can check if any object is in it. I use Physics.OverlapSphereNonAlloc to check overlap, then remove object whose center is not in the field of view. I use a ray cast from origin to the object center to check if there’s any occlusion. However, they all treat the object as a point instead of an object with volume. How do I return true as long as any portion of an object overlaps the mesh? Or any portion is the the mesh and not occlued by others?

This is the part for checking if it’s in the field of view

bool IsInsight(GameObject gameObject)
     {
         Vector3 direction = gameObject.transform.position - transform.position;
         if (Vector3.Dot(direction, transform.up)<-detectHeight/2 | Vector3.Dot(direction, transform.up)>detectHeight/2)
             return false;
         direction.y = 0;
         Vector3 directionNormalToTransformUp = Vector3.Dot(direction, transform.right) * transform.right +
                                                Vector3.Dot(direction, transform.forward) * transform.forward;
         float deltaAngle = Vector3.Angle(directionNormalToTransformUp, transform.forward);
         if (deltaAngle > detectAngle)
             return false;
         if (Physics.Linecast(transform.position, gameObject.transform.position, LayerMask.NameToLayer("Hider")))
             return false;
         return true;
     }

The image is as attached [1]

This is the complete code

using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Mathematics;
using Unity.MLAgents.Actuators;
using UnityEditor;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.UIElements;

[ExecuteInEditMode]
public class TargetDetectingAgent : NavigationAgent
{
    public float detectHeight;
    public float detectAngle;
    public float detectDistance;
    private int segment=10;
    public Color meshColor=Color.cyan;
    private Collider[] detectColliders;
    private LayerMask hiderLayer;
    private int count;
    private List<GameObject> detectObjects;


    private Mesh mesh;
    private void Awake() 
    {
        moveInput.Enable();
        dirInput.Enable();
        MapGenerator mapGenerator = FindObjectOfType<MapGenerator>();
        mapSize = mapGenerator.CalculateMapSize()/2;
        PlayerSpawner playerSpawner = FindObjectOfType<PlayerSpawner>();
        path = new NavMeshPath();
        destinationSpawner = GameObject.Find("DestinationSpawner");
        detectColliders = new Collider[playerSpawner.numberOfHider];
        detectObjects = new List<GameObject>(playerSpawner.numberOfHider);
    }

    private void OnValidate()
    {
        mesh = CreateMesh();
    }

    private void OnDrawGizmos()
    {
        if (mesh)
        {
            Gizmos.color = meshColor;
            Gizmos.DrawMesh(mesh, transform.position,transform.rotation);
        }
        Gizmos.DrawWireSphere(transform.position,detectDistance);
        Gizmos.color = Color.magenta;
        foreach (var obj in detectObjects)
        {
            Gizmos.DrawSphere(obj.transform.position, 0.7f);  
        }
    }

    private void Update()
    {
        Scan();
    }

    void Scan()
    {
        count=Physics.OverlapSphereNonAlloc(transform.position, detectDistance, detectColliders, 1<<LayerMask.NameToLayer("Hider"), 
            QueryTriggerInteraction.Collide);
        detectObjects.Clear();
        for (int i=0;i<count;i++)
        {
            GameObject obj = detectColliders*.gameObject;*

if (IsInsight(obj))
{
detectObjects.Add(obj);
}
}
}

bool IsInsight(GameObject gameObject)
{
Vector3 direction = gameObject.transform.position - transform.position;
if (Vector3.Dot(direction, transform.up)<-detectHeight/2 | Vector3.Dot(direction, transform.up)>detectHeight/2)
return false;
direction.y = 0;
Vector3 directionNormalToTransformUp = Vector3.Dot(direction, transform.right) * transform.right +
Vector3.Dot(direction, transform.forward) * transform.forward;
float deltaAngle = Vector3.Angle(directionNormalToTransformUp, transform.forward);
if (deltaAngle > detectAngle)
return false;
if (Physics.Linecast(transform.position, gameObject.transform.position, LayerMask.NameToLayer(“Hider”)))
return false;
return true;
}
Mesh CreateMesh()
{
Mesh mesh = new Mesh();
int numTriangle = segment*4+4;
int numVeritices = numTriangle * 3;
Vector3[] vertices=new Vector3[numVeritices];
int[] triangles=new int[numVeritices];

int x=0;
float deltaAngle = detectAngle * 2 / segment;
float currentAngle = -detectAngle;
Vector3 bottomCenter = Vector3.zero + Vector3.down * detectHeight / 2;
Vector3 bottomLeft= Quaternion.Euler(0, -detectAngle, 0) * Vector3.forward * detectDistance +
Vector3.down * detectHeight / 2;;
Vector3 bottomRight= Quaternion.Euler(0, detectAngle, 0) * Vector3.forward * detectDistance +
Vector3.down * detectHeight / 2;;
Vector3 topCenter= Vector3.zero + Vector3.up * detectHeight / 2;
Vector3 topLeft = Quaternion.Euler(0, -detectAngle, 0) * Vector3.forward * detectDistance +
Vector3.up * detectHeight / 2;
Vector3 topRight = Quaternion.Euler(0, detectAngle, 0) * Vector3.forward * detectDistance +
Vector3.up * detectHeight / 2;
//Triangles on left side
vertices[x++] = bottomCenter;
vertices[x++] = bottomLeft;
vertices[x++] = topLeft;
vertices[x++] = bottomCenter;
vertices[x++] = topLeft;
vertices[x++] = topCenter;
//Triangles on right side
vertices[x++] = bottomCenter;
vertices[x++] = topRight;
vertices[x++] = bottomRight;
vertices[x++] = bottomCenter;
vertices[x++] = topCenter;
vertices[x++] = topRight;
for (int i=0;i<segment;i++)
{
bottomLeft = Quaternion.Euler(0, currentAngle, 0) * Vector3.forward * detectDistance +
Vector3.down * detectHeight / 2;
bottomRight = Quaternion.Euler(0, currentAngle+deltaAngle, 0) * Vector3.forward * detectDistance +
Vector3.down * detectHeight / 2;
topLeft = Quaternion.Euler(0, currentAngle, 0) * Vector3.forward * detectDistance +
Vector3.up * detectHeight / 2;
topRight = Quaternion.Euler(0, currentAngle+deltaAngle, 0) * Vector3.forward * detectDistance +
Vector3.up * detectHeight / 2;

//Triangles on far side
vertices[x++] = bottomRight;
vertices[x++] = topRight;
vertices[x++] = bottomLeft;
vertices[x++] = topRight;
vertices[x++] = topLeft;
vertices[x++] = bottomLeft;

//Triangles on top
vertices[x++] = topRight;
vertices[x++] = topCenter;
vertices[x++] = topLeft;
//Triangles at bottom
vertices[x++] = bottomRight;
vertices[x++] = bottomLeft;
vertices[x++] = bottomCenter;

//Update currentAngle
currentAngle += deltaAngle;
}

for (int i = 0; i < vertices.Length; i++)
triangles = i;
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.RecalculateNormals();
return mesh;
}
}

[1]: Screenshot.png - Google Drive

What I did was basically make an object(one of the Unity free assets allows you to create objects kinda like blender(UModelerLite)) and made a “slice of pizza” shaped mesh. Then made the mesh a child of my game object with sight, and used collisions to determine if it’s in it’s ‘view’. Also make the view box with no renderer so it’s invisible. I do this because the overlap sphere is basically an object anyway, so I’d rather have something I can see and edit properly in inspector, and also scale easily within the code of the parent.