How to get the tangent vector from a hit.normal

Hello,
So I am working on a game involving somewhat odd shaped characters, some being quadrupeds and some being bipedal, but many of them having either tails or hunched forward bodies. Because of that, the standard capsule collision does not work perfectly for my uses. However, I decide to use the capsule collision for the ground movement, the only thing that does not work great when running headlong into a wall. My solution to run a sphere trace out to detect any walls. I can get it to stop the character in his tracks, but now I need him to slide off of the wall instead of just stopping. The way I think this needs to be done, is by finding the vector tangent to the collision and moving in that direction instead.

Originally I thought this would be as simple as just adding the normal vector to the original rotation vector, and it works great, for everything other than when moving to the left. (Pictures below along with code)

Moving Into the wall directly rotates the character parallel to the wall. Which is exactly what I need.

Moving into the wall from the right however rotates the character perpendicular to the wall.

The way I have my code set up is for a joystick-like movement. So in the forward/right movement I simply set my rotY and rotX values, then when I update:

if (movingY || movingX) {
		rotVector = FVector(rotY, rotX, 0);
		float dist = rotVector.Size();
		TArray<FHitResult> OutResults = CollisionTrace();
		DrawDebugSphere(GetWorld(), GetActorLocation() + rotVector * charLength, charSize, 12, FColor::Red);
		if (OutResults.Num() > 0) {
			for (int i = 0; i < OutResults.Num(); i++) {
				FVector norm = OutResults[i].Normal * wallAdjustment;
				rotVector += norm;
				DrawDebugDirectionalArrow(GetWorld(), OutResults[i].ImpactPoint,
                            OutResults[i].ImpactPoint + rotVector * 200, 
                            100, FColor::Blue);
			}
		}

		Controller->SetControlRotation(rotVector.ToOrientationRotator());
		AddMovementInput(rotVector, dist);

Thank You,

Hello! There is more simple way to calc that:

  • get Hit.Actor
  • calc vector dirVector = Hit.Actor->GetActorLocation() - Pawn->GetActorLocation()
  • get upVector = Pawn->GetActorUpVector;
  • now just use cross product FVector::CrossProduct(dirVector, upVector)

But his is only for one contact. Also, you can either rotate clockwise or not.