Sweep collision doesn't work if the start loc and end loc both collide with the same surface

FCollisionQueryParams TraceParams;
TraceParams.AddIgnoredActor(MyActor);
TraceParams.bTraceComplex = false;
TraceParams.bReturnPhysicalMaterial = false;

bool Hit =GetWorld()->SweepSingleByProfile(HitOut, SphereStartLoc, SphereEndLoc, FQuat(0.0f, 0.0f, 0.0f, 1.0f), TEXT("BlockAll"), FCollisionShape::MakeSphere(Radius), TraceParams);

If SphereStartLoc and SphereEndLoc both intersect the same surface, then I either get no collision, or HitOut.Location == HitOut.ImpactPoint == SphereStartLoc. Even if just the very edge of the spheres are the only things that collide. I think I should get a proper hit location based on the sphere.

If SphereStartLoc doesn’t intersect anything, but somewhere in between or at the end does, then I get a proper hit location.

HitOut.PenetrationDepth and HitOut.Normal seem to be set correctly.

In my test, I’m simply colliding with a basic cube (Modes->Place->Basic->Cube) static mesh actor.

Hey -

Could you provide more information on how you’re setting up and testing this? Where are you including this code? What surface are you colliding with in the editor? Please include detailed steps to help reproduce the bug locally.

What surface are you colliding with in the editor?

From my post: In my test, I’m simply colliding with a basic cube (Modes->Place->Basic->Cube) static mesh actor.

Where are you including this code?

Just the Tick function for a random actor.

SphereStartLoc is a world position I get form a reference target actor. For SphereEndLoc I simply add 10.0 to Z of the start loc.

	float Radius = 35.0f;
	FVector SphereLoc = RefActor->GetActorLocation();
	FVector EndLoc = SphereLoc;
	EndLoc.Z += 10.0f;

I use DrawDebugSphere to show where I’m doing the sphere collisions and it looks exactly right:

	DrawDebugSphere(GetWorld(), SphereLoc, Radius, 12, FColor::Red, false, -1.0f);
	DrawDebugSphere(GetWorld(), EndLoc, Radius, 12, FColor::Yellow, false, -1.0f);

Collision image:

Results:

90977-collres.jpg

Adding the code provided to a new class returns a number of compile errors. Can you provide the full code class you’re using for your test so that I can ensure that my setup matches yours.

There’s not much more to it. This is the full code, put it in any actor’s tick function, but you do need a uparameter for the target point:

FCollisionQueryParams TraceParams;
TraceParams.AddIgnoredActor(this);
TraceParams.bTraceComplex = false;
TraceParams.bReturnPhysicalMaterial = false;
FHitResult HitOut;

float Radius = 35.0f;
FVector SphereLoc = RefActor->GetActorLocation();
FVector EndLoc = SphereLoc;
EndLoc.Z += 10.0f;

DrawDebugSphere(GetWorld(), SphereLoc, Radius, 12, FColor::Red, false, -1.0f);
DrawDebugSphere(GetWorld(), EndLoc, Radius, 12, FColor::Yellow, false, -1.0f);

FCollisionResponseParams ResponseParam;

bool Hit = GetWorld()->SweepSingleByChannel(HitOut, SphereLoc, EndLoc, FQuat(0.0f, 0.0f, 0.0f, 1.0f), ECollisionChannel::ECC_Pawn, FCollisionShape::MakeSphere(Radius), TraceParams, ResponseParam);
if (Hit)
{
	DrawDebugSphere(GetWorld(), HitOut.Location, 10.0f, 12, FColor::Blue, false, -1.0f);
}

The uparameter in the header file:

UPROPERTY(Category = Node, EditAnywhere)
AActor *RefActor;

So in the editor I simply set thar RefActor to a TargetPoiont. I place the TargetPoint as you see in the image with the two spheres: close to a wall such that both intersect with the same surface.

In the.cpp file of the actor you need an include for the debug draws:

#include "DrawDebugHelpers.h"

Here’s the whole class files:

link text

I copied the class into a new project an added an on screen debug message inside of the if(hit) condition. In the editor (third person template project) I set RefActor to the floor which printed my debug message on PIE. I then created a new blueprint with a static mesh component and added it to the viewport. When I set RefActor to the new blueprint, it too printed my debug message. Since the debug circles you’re creating target the root of the actor, I tried repositioning the static mesh component and found that if the static mesh overlapped with the spheres in any amount, it would print my debug message. Here is a screenshot of my blueprint overlap.

91184-debugsphere.png

Yes it looks like you’re seeing the bug. Any idea why?

In case you’ve forgotten the original post, and followup comment showing the results, the problem is getting HitOut.Location == HitOut.ImpactPoint == SphereLoc

I can see in your image, the blue sphere in the middle should be at the intersection point, but instead it’s in the incorrect location – the SphereLoc.

When doing a sphere collision test, I need to know where the intersection point is. Penetration Depth and normal are not enough to calculate an intersection point because there are multiple symmetrical possibilities for any given penetration depth and normal.

All other collision calls give you a proper intersection point, except for the sweep functions. Is there a fix for this?

Hey -

I have entered a report for the behavior of Hit.Location and Hit.ImpactPoint when using a sweep sphere, UE-31047 .

Cheers

This is not a bug, the screenshot shows that “bStartPenetrating=true”, meaning the sphere started in penetration. We don’t have enough info in this case to provide a meaningful impact point because it’s a whole collection of points along the surface of the object.

I will update the documentation for FHitResult to make this clearer.

It’s possible to get this data, if you want to run another query (or multiple queries in the case of multiple overlapped shapes), though there are still failure cases or you might want even more info (point, normal, etc). Plus there is a potentially large hidden performance cost here so we don’t do this automatically.

We’ve recently added UBodySetup::GetClosestPointAndNormal() to the code, which could help.

Couldn’t you return the closest point of intersection? It’s what a normal sphere vs world test does in other engines. Is there a simple sphere vs world check in UE4 (C++)?