Sphere sweeps ignore FSphere::Center rotation, returning wrong hit results for offset sphere collision shapes

When we try to sweep a sphere or a capsule toward a Sphere Primitive collision, the results are wrong when the collision has an offset from its mesh.

Hit results are incoherent, and are not located on the surface of the collision.

This also happens with Capsule Sweeps vs Sphere collision.

We came up with some code change in GeometryQueries.cpp, that I will attach to this request, that fixes the issues for Spheres and Capsules.

(Full change in attached .txt file)

Modified code is located between the following tags :

//++Tuque

//--Tuque

Do you think that this fix is legitimate ?

Thank you

FGJKSphereSingleSIMD ComputeLocalSphere(const FSphere& Sphere, const FRigidTransform3& SphereTM, const FRigidTransform3& OtherTM)
	{
		//++Tuque - Fix Sphere center offset not transformed during sphere sweeps
		//const FVec3 SphereWorldLocation = FVec3(Sphere.GetCenterf()) + SphereTM.GetLocation();
		const FVec3 SphereWorldLocation = SphereTM.TransformPositionNoScale(FVec3(Sphere.GetCenterf()));
		//--Tuque
		const FVec3 SphereLocation = OtherTM.InverseTransformPositionNoScale(SphereWorldLocation);
		return FGJKSphereSingleSIMD(SphereLocation, Sphere.GetRadiusf());
	}

//...

bool SweepSphereVsSphere(const FSphere& SweptSphere, const FRigidTransform3& SweptSphereTM, const FSphere& TestSphere, const FRigidTransform3& TestSphereTM,
		const FVec3& SweepDir, const FReal Length, const FReal Thickness, const bool bComputeMTD,
		FReal& OutTime, FVec3& OutPosition, FVec3& OutNormal, int32& OutFaceIndex, FVec3& OutFaceNormal)
	{
		const Sweeps::ESweepFlags Flags = bComputeMTD ? Sweeps::ESweepFlags::MTD : Sweeps::ESweepFlags::None;
		// Transform to the test shape's local space. Note: We can skip rotation which is much faster
		const FVec3 TestGeomLocalToWorld = TestSphereTM.GetLocation();
		const FVec3 SweptShapeLocalToWorld = SweptSphereTM.GetLocation();
		const FVec3 LocalSweepDir = SweepDir;
		//++Tuque - Fix Sphere center offset not transformed during sphere sweeps
		//const FVec3 LocalSweepStart = SweptSphere.GetCenterf() + SweptShapeLocalToWorld - TestGeomLocalToWorld;
		const FVec3 WorldSweptSphereOffset = SweptSphereTM.TransformVectorNoScale(FVec3(SweptSphere.GetCenterf()));
		const FVec3 LocalSweepStart = WorldSweptSphereOffset + SweptShapeLocalToWorld - TestGeomLocalToWorld;
		//--Tuque
		const FReal SweepRadius = Thickness + SweptSphere.GetRadiusf();

		//++Tuque - Fix Sphere center offset not transformed during sphere sweeps
		//const bool bResult = Sweeps::SweepSphereVsSphere(LocalSweepStart, LocalSweepDir, Length, SweepRadius, TestSphere.GetCenterf(), TestSphere.GetRadiusf(), Flags, OutTime, OutPosition, OutNormal);
		const FVec3 WorldTestSphereOffset = TestSphereTM.TransformVectorNoScale(FVec3(TestSphere.GetCenterf()));
		const bool bResult = Sweeps::SweepSphereVsSphere(LocalSweepStart, LocalSweepDir, Length, SweepRadius, WorldTestSphereOffset, TestSphere.GetRadiusf(), Flags, OutTime, OutPosition, OutNormal);
		//--Tuque
		TransformSweepResultsToWorld(bResult, OutTime, bComputeMTD, TestSphere, TestGeomLocalToWorld, LocalSweepDir, OutPosition, OutNormal, OutFaceIndex, OutPosition, OutNormal, OutFaceNormal);
		return bResult;
	}

[Attachment Removed]

Steps to Reproduce
Give a new Actor a sphere collision primitive with a non-zero FKSphereElem::Center (for instance Center = (100.0, 0.0, 0.0), Radius 50.0). Rotate the newly added actor (e.g. Rotation (45.0, 45.0, 45.0)) Sweep a sphere in the actor’s direction, and record the hits.

Recorded hits will not be on the sphere collision geometry.

[Attachment Removed]

Hi Hugo,

We ran into a similar issue a little while ago. The good news is that there is a fix you can pull in, but it isn’t due to come into UE5. You can find it at CL 55253585 which is on the UE6 trunk.

Best

Geoff Stacey

Developer Relations

EPIC Games

[Attachment Removed]

Hi Geoff,

Thanks for your answer.

We’ll integrate that change and try it out.

I just wanted to correct the CL number : On the ue6 branch, the CL for the fix is 55253601.

It can also be found on GitHub here.

Thanks again,

Hugo

[Attachment Removed]

Thanks for the correction Hugo - you are indeed correct!

[Attachment Removed]