Line Of Sight - How To Go About It?

Over the past few days, I have decided that I need an easy way to tell whether an object is in the camera’s line of sight, or, more specifically whether is can be seen or not.

My ideas was to use an elaborate array of raycasts that cast to a length of 200 or something, and creating an array of objects caught by it, but that doesn’t technically provide any way of checking if an object is actually being looked at, it just provides the devs with, basically, a list of objects.

What I am looking to do, is have an easy way to check whether an object is visible, but as this is not something Unity has any tutorials on despite being quite a basic feature in theory, I am guessing it is a little less simple in practice.

so, I am here to ask about methods others have used, or any recommendations/pointers anyone can give me, or even a working model which would provide me with a simple detection method to build off of.

Thanks in advance for any posts :slight_smile:

There’s no need for an elaborate array…Just a single RaycastAll. The array returned is in order the ray hit.

1 Like

This would only cover a VERY narrow area of the viewport, the purpose of the array would be to cast a ray every 0.1 squared (assuming the viewport was calculated on a 0,1 scale) to create a grid-style layout.

Having a system which returns multiple objects along just 1 path isn’t too useful for this purpose.

If you meant something else, sorry :stuck_out_tongue:

never dealt with such a problem before, but this seems related, hope it helps

Thought that wasn’t guaranteed.

1 Like

It’s not in any tutorials, because it really is a non trivial problem.

To check if an object is visible at all you have to check the object pixel by pixel to see if any were rendered. As far as I’m aware there isn’t a cheap way to do that.

Maybe some sort of fancy shader magic might work. Basicly something that can set a flag if it draws any pixels on the object of concern. Transparency will be an issue, and will require more magic.

Otherwise fake it with half a dozen raycasts and be done.

1 Like

True fact. Not actually verifying the distances will probably lead to bugs. I’m too used to prototyping with RaycastAll.

Grid-style layout? I really think you’re overthinking this. You should know two parts of the equation.

  1. What’s looking
  2. What it’s looking for
    You need the third part
  3. Can it see what it’s looking for

A raycast from what’s looking to what it’s looking for tells you number 3.

Attempting to find the objects in the first place with raycasts is silly. You know the objects are there, you just need to test if they can be seen. For efficiency’s sake, you can have a trigger collider that maintains a list of objects around or in front of the player.

2 Likes

i would do 2 things, do the math to figure out what is in the current players camera frustum, than simply raycast to each object found, to make sure it is not being blocked by an other object.

to see if something is in the view frustrum you can use WorldToScreenPoint, and simply check if its location is between 0 and the screen width and height

Use OnBecameVisible and its invisible counterpart combined with a simple FOV check should be good enough.

Note that the editor camera will trigger OnBecameVisible as visible as well as the game camera. Also, for some reason it doesn’t show in my Console more than 2 times, even though it works.

Here’s how I used it to pause animations that weren’t visible in my scene:

void OnBecameInvisible()
    {
        IsVisible = false;
        //save animation state to use when visible again
        PreviousStaticFrameAnimationState = StaticFrameAnimationState;
        StaticFrameAnimationState = 0;
        Debug.Log("Invisible");
    }

    void OnBecameVisible()
    {
        IsVisible = true;
        StaticFrameAnimationState = PreviousStaticFrameAnimationState;
        Debug.Log("Visible");
    }

Yet “Visible” and “Invisible” show only once in my console, no matter how many times I change the camera’s view points. However, the bool (IsVisible) changes, and the Profiler shows a performance boost when I narrow my camera’s FOV, so it does work.

Overall I think it is a very strangely made but incredibly useful function.

You also have to check the Z, it’ll return a position for objects behind the camera. I did it this way using WorldToViewportPoint:

    public static bool IsVisibleToCamera(Transform transform)
    {
        Vector3 visTest = Camera.main.WorldToViewportPoint(transform.position);
        return (visTest.x >= 0 && visTest.y >= 0) && (visTest.x <= 1 && visTest.y <= 1) && visTest.z >= 0;
    }
        public static bool IsDirectLineBetweenTheseTwo(GameObject one, GameObject two)
        {
            var ray = new Ray(one.transform.position, two.transform.position - one.transform.position);
          
            var hits = Physics.RaycastAll(ray,ray.direction.magnitude);
            if (hits.Length > 0)
            {
                foreach (var hit in hits)
                {
                    //Ignore the two input objs
                    if (hit.collider.gameObject == one || hit.collider.gameObject == two) continue;
                    
                    //Debug.DrawLine(one.transform.position, hit.collider.transform.position,Color.red,1);
                    //Debug.DrawLine(one.transform.position, two.transform.position, Color.blue, 1);
                    //Debug.Log($"Interferred by {hit.collider.gameObject.name}");
                    return false;
                }
            }
            //Debug.DrawLine(one.transform.position, two.transform.position, Color.green,1);
            return true;
        }

Hey!!
There is a video series by sebastian league on this try it out

Would it be possible to define a viewport at runtime and raycast WITHIN it?
for example: define a maximum view height and width and as long as the raycast ‘looks into it’ then it registers a raycast?