[UE4.10+] [AI] [Perception] Occlusion Based Perception

Hello,

Probably a question for MieszkoZ ,

I’m wondering if there is something foreseen (built-in) to avoid AIPerception to perceive Actors that are in fact occluded by an object while located within Sense-Sight Config and if apply, handle as well translucent cases?
Or this is supposed to be handled by use cases directly?

Br,

If I understand you correctly, you don’t want actors that are hidden behind something to be perceived. If that’s the case, here’s what I’ve found:

Firstly, the AIPerception sight sense does perform a line trace to determine if a target is occluded or not, but it only considers static objects - see here. You need to register your Epic user name on Github to access this page, so I’ll also add the relevant line below:

FHitResult HitResult;
const bool bHit = World->LineTraceSingleByObjectType(HitResult, Listener.CachedLocation, TargetLocation
	, FCollisionObjectQueryParams(ECC_WorldStatic)
	, FCollisionQueryParams(NAME_AILineOfSight, true, Listener.Listener->GetBodyActor()));

I couldn’t find any documentation for it, but after looking through the code I found that you could override this using the AISightTargetInterface interface, but this will require C++.
Here’s how to use it:

Step 1

First you need your pawn to implement AISightTargetInterface.
IMPORTANT: Your target pawn must implement this, ie. the pawn that is being detected, not the one doing the detecting.

Copy the relevant parts into your pawn class.

// Add this >>
#include "Perception/AISightTargetInterface.h"

class AMyCustomTargetPawn : public APawn, public IAISightTargetInterface // << Extend the 'IAISightTargetInterface' interface
{

public:
	
	// Add the 'CanBeSeenFrom' definition >>
	// IAISightTargetInterface:

	/**	Implementation should check whether from given ObserverLocation
	*	implementer can be seen. If so OutSeenLocation should contain
	*	first visible location
	*  Return sight strength for how well the target is seen.
	*/
	virtual bool CanBeSeenFrom(const FVector& ObserverLocation, FVector& OutSeenLocation, int32& NumberOfLoSChecksPerformed, float& OutSightStrength, const AActor* IgnoreActor = NULL) const;
	
};

Step 2

Then for the implementation in your .cpp file; this was copied straight from AISense_Sight.cpp (See the link I provided at the top), except I changed it to also check for dynamic objects:

bool AMyCustomTargetPawn::CanBeSeenFrom(const FVector& ObserverLocation, FVector& OutSeenLocation, int32& NumberOfLoSChecksPerformed, float& OutSightStrength, const AActor* IgnoreActor) const
{
	static const FName NAME_AILineOfSight = FName(TEXT("TestPawnLineOfSight"));

	FHitResult HitResult;
	const bool bHit = GetWorld()->LineTraceSingleByObjectType(HitResult, ObserverLocation, GetActorLocation()
		, FCollisionObjectQueryParams(ECC_TO_BITFIELD(ECC_WorldStatic) | ECC_TO_BITFIELD(ECC_WorldDynamic)) // << Changed this line
		, FCollisionQueryParams(NAME_AILineOfSight, true, IgnoreActor));

	NumberOfLoSChecksPerformed++;
	
	// Add any other checks you want to perform here
	// ...

	if (bHit == false || (HitResult.Actor.IsValid() && HitResult.Actor->IsOwnedBy(this)))
	{
		OutSeenLocation = GetActorLocation();
		OutSightStrength = 1;
		return true;
	}


	OutSightStrength = 0;
	return false;
}

Step 3

Change, or add in any other extra logic you want; and if you’re using blueprints, make sure that you change it so that your pawn blueprint’s parent is set to this new class instead of Pawn.
At this point it should work - dynamic objects should also block the perception component’s line of site.