To update this topic - to ensure a trigger works perfectly you need to ask “what side of the triggers plane are the points on”, as I have found a few scenarios where measuring the dotproduct etc fails, as relative to a 2D line and not a 3D plane.
So need to ask is point A and point B on same side of the triggers plane or different. You do this using the plane equation: ax+by+c*z+d=0. Once you work this out not so scary, I have tried to explain below in a simple way.
- Calculate the plane using the above equation. Use the planes normal, its location, and its distance from the world origin:
float Plane = NormalPlane.X * PlaneLocation.X + NormalPlane.Y * PlaneLocation.Y + NormalPlane.Z * PlaneLocation.Z + Dist;
Where:
FVector NormalPlane = this->GetActorRightVector(); //or forward vector depending on trigger width (i.e. if longer in X or Y)
FVector PlaneLocation = this->GetActorLocation();
float Dist = PlaneLocation.Length();
- Substitute the location of the point to compare into the equation, using its Location, the planes Normal and the planes distance the the origin. This gives the distance from and direction from the plane.
float PointAPlane = NormalPlane.X * PointA.X + NormalPlane.Y * PointA.Y + NormalPlane.Z * PointA.Z + Dist;
Where:
FVector PointA = OtherActor->GetActorLocation();
float Dist = PlaneLocation.Length();
-
by subtracting these you will get a negative or positive value.
i.e. Plane - PointAPlane = neg or positive value
-
compare the sign, if both the same they lie on the same side of the triggers plane, if different on different sides.
bTriggerSuccess = signbit(Plane - PointAPlane) == signbit(Plane - PointBPlane) ? false : true;
You can do some extra maths to simplify and also simplify the code but this works & demos the principle:
Here it is in code using a single function, a BeginOverlapEvent (to get PointA) and an EndOverlapEvent (to get PointB).
BeginOverlap(AActor* OtherActor)
{
BeginDistFromPlane = CalcDistFromPlane(OtherActor);
}
EndOverlap(AActor* OtherActor)
{
bTriggerSuccess = signbit(BeginDistFromPlane) == signbit(CalcDistFromPlane(OtherActor)) ? false : true;
}
CalcDistFromPlane(AActor* OtherActor)
{
if (!OtherActor) { return 0.0f; }
FVector NormalPlane = this->GetActorRightVector(); //or forward vector
FVector PointA = OtherActor->GetActorLocation();
FVector PlaneLocation = this->GetActorLocation();
float Dist = PlaneLocation.Length(); //constant d = distance from origin
return (NormalPlane.X * PlaneLocation.X + NormalPlane.Y * PlaneLocation.Y + NormalPlane.Z * PlaneLocation.Z + Dist) - (NormalPlane.X * PointA.X + NormalPlane.Y * PointA.Y + NormalPlane.Z * PointA.Z + Dist);
}
I’d be interested to know any thoughts on this - but my testing indicates it works and no longer has the issues of being related to a 2D line.
I have implemented this in my Dynamic Weather system for sale on FAB and done extensive testing: Ex Ultra Dynamic Weather System | Fab