How can I check if an object is visible by a camera?

Hello!

I can’t find a way to do what I want… Well, the situation:

I have a topdown camera layout in my game, so some objects are hidden by other objects (basically, because they are behind other objects) - and that is totally understandable. What I want - is to get somehow a list of these objects which the camera can’t see at this exact point of view - maybe even using some kind of collision channel - I mean I want at every tick to “scan” the visible to the camera part of scene, get all objects which are present on this part of the scene and then get a list of all objects, which are present on this scene, but are not seen by the camera point of view. Then I want to get which objects are blocking vision to the ones which are invisible (or “obscured”?) to then try to make something.

So, how do I actually “scan” the whole viewport to get which objects are visible and which are not? There is a collection of “GetHitResult” functions, but they trace only one point, not the whole viewport, and it seems that they are a bit of overhead using each of them for every object I want.

The below functions will tell you which actors are being rendered, and which arent, and you can decide how recently they have to have been rendered to count :slight_smile:

default = 0.01 seconds recently

#Get Rendered Actors

void UVictoryBPFunctionLibrary::Visibility__GetRenderedActors(TArray<AActor*>& CurrentlyRenderedActors, float MinRecentTime)
{
	//Empty any previous entries
	CurrentlyRenderedActors.Empty();
	
	//Iterate Over Actors
	for ( TObjectIterator<AActor> Itr; Itr; ++Itr )
	{
		if (Itr->GetLastRenderTime() > MinRecentTime)
		{
			CurrentlyRenderedActors.Add( * Itr);
		}
	}
}

#Get Not Rendered Actors

void UVictoryBPFunctionLibrary::Visibility__GetNotRenderedActors(TArray<AActor*>& CurrentlyNotRenderedActors, float MinRecentTime)
{
	//Empty any previous entries
	CurrentlyNotRenderedActors.Empty();
	
	//Iterate Over Actors
	for ( TObjectIterator<AActor> Itr; Itr; ++Itr )
	{
		if (Itr->GetLastRenderTime() <= MinRecentTime)
		{
			CurrentlyNotRenderedActors.Add( * Itr);
		}
	}
}

Thanks, that is something to start with, but how can I check if they are unrendered because they are out of camera field of view or because they are hidden/obscured by other actors?

And also that won’t probably work for server side - I need to track what a character can view to send only required information via network (to disallow cheats).

I had the same problem but in blueprint. What I did is to use the node “Single Line trace by Chanel”. This node (function?) trace a line between a start point (the camera) to another point (the object or a distance for exemple) then retrun what the line hit at the end. I just take this value and ask if the actor who is hit by the line is equal to the actor i want … And that it, if its true you see the actor, if not you do not. The line dont pass solid walls but pass the glass (translucent material).

I hope this helped, sorry for my bad English :slight_smile:

1 Like

If this helps, I performed an alternative solution that results in something close, it’s also a lot simpler:

I got two unit vectors:

-Forward vector of the camera, which can just be obtained through the player camera manager.

-Unit Vector of the camera position to the object your are checking. Which is calculated just by subtracting the position of the object by the position of the camera, and then normalizing it.

Then I just performed a dot product using those two vectors. If the number you get is positive, the camera is facing a direction that the object would be in. If it’s negative, the object is behind the camera. Not exactly checking if it is within view, but it gets close. You can also adjust the range of the value you are checking for to get something more accurate.

This won’t work if you are doing dynamic occlusion masking where lets say you have half an object invisible and the other half of it visible. In such an example as half and half you would want the half visible to be selected/hit while the other half invisible to be ignored/not hit. I’m currently looking for a way to do this, editor seems to do this no issue but at runtime line trace doesn’t work this way by default.

EDIT: Also to add, objects that are occluded are still registering as visible.
If I linetrace and hit an occluded actor and then run this test to see if it is rendered it still says it is rendered.