Rotate vector based on actor rotation - wall climbing system

I’m working on a game where we feature wall climbing. I have a working system for getting a ledge from my actor mathematically, but it only works when the actor is rotated in one axis and only on two of the sides.

Here is an image of the “wall”:
[SPOILER]

[/SPOILER]

I get the point where I want to grab the ledge by getting the location of the two arrows and tracing from the character to the wall. Then I do some vector math and the sinerule. But the problem I am facing is that I can’t really get the vector from the hit location along the face, pointing upwards to the sky. Right now it just traces perpendicular to the plane.



FVector APlayerCharacter::GetNormalPointFromB(FVector ForwardVector, FVector PointA, FVector PointB, FVector PointC)
{		
	FVector VectorAB = PointB - PointA;
	FVector VectorAC = PointC - PointA;
	FVector VectorBD = (PointB + ForwardVector) - PointB;
	FVector VectorBA = PointA - PointB;
	double AngleBAD = UKismetMathLibrary::Acos(FVector::DotProduct(VectorAB, VectorAC) / (VectorAB.Size() * VectorAC.Size()));
	double AngleABD = UKismetMathLibrary::Acos(FVector::DotProduct(VectorBA, VectorBD) / (VectorBA.Size() * VectorBD.Size()));
	double AngleADB = UKismetMathLibrary::GetPI() - AngleBAD - AngleABD;
	double BD = (VectorAB.Size() * UKismetMathLibrary::Sin(AngleBAD)) / UKismetMathLibrary::Sin(AngleADB);
	return PointB + VectorBD * BD;
}

Here is a representation of what is going on in geogebra:
[SPOILER]

[/SPOILER]

Which doesn’t really work when the ledge is not perpendicular to the horizon.
[SPOILER]

[/SPOILER]

The function takes a vector pointing towards line AC that is one unit long. And I simply need to rotate the vector slightly so that it points straight up the wall from the ground, not 90 degrees on line AC.

An example of what I am thinking of:
[SPOILER]


[/SPOILER]

Is there as simple way of rotating it that way based on the rotation of the actor or something? Rotators are basically french to me.

ok.
I tried to replicate what you wanted in a simple enough fashion so I could try things out.
(Im better at trail and error than math :stuck_out_tongue: )

I threw this together in my project’s Character’s Tick()



	FRotator CurrentRot =	FRotator(-45,-25,0);

	FVector CurrentVector = CurrentRot.Vector().GetSafeNormal();
	FRotator XRotation =	FRotator(0,0,0);
	FVector XDIR =		CurrentVector.Rotation().UnrotateVector(XRotation.Vector());
	FRotator YRotation =	FRotator(0,90,0);
	FVector YDIR =		CurrentVector.Rotation().UnrotateVector(YRotation.Vector());
	FRotator ZRotation =	FRotator(90,0,0);
	FVector ZDIR =		CurrentVector.Rotation().UnrotateVector(ZRotation.Vector());

DrawDebugLine(GetWorld(), PawnLocation, PawnLocation+ (XDIR * 2000), FColor::Red, true, 1000.0F, 0.0F, 48.0F);
DrawDebugLine(GetWorld(), PawnLocation, PawnLocation+ (YDIR * 2000), FColor::Yellow, true, 1000.0F, 0.0F, 48.0F);
DrawDebugLine(GetWorld(), PawnLocation, PawnLocation+ (ZDIR * 2000), FColor::Blue, true, 1000.0F, 0.0F, 48.0F);

	float AngleDifference =		FMath::RadiansToDegrees(acosf(FVector::DotProduct(CurrentVector, FVector::UpVector)));
	FRotator VectorAsRotation =	FRotator(0,CurrentVector.Rotation().Yaw,0);

	FVector FinVector =		CurrentVector.Rotation().UnrotateVector(VectorAsRotation.Vector());
	CurrentVector =			FinVector.GetSafeNormal();

DrawDebugLine(GetWorld(), PawnLocation, PawnLocation+ (CurrentVector * 5000), FColor::Green, true, 1000.0F, 0.0F, 32.0F);
GEngine->AddOnScreenDebugMessage(15000, 1.0f, FColor::Yellow, "  AngleDifference : " + FString::SanitizeFloat(AngleDifference));

Everything above the AngleDifference declaration is just a “tool” that makes it easier for me to dictate and visualize where CurrentVector is pointing.

Try:



	...
	double BD = (VectorAB.Size() * UKismetMathLibrary::Sin(AngleBAD)) / UKismetMathLibrary::Sin(AngleADB);
	
	float Angle =		FMath::RadiansToDegrees(acosf(FVector::DotProduct(VectorBD, FVector::UpVector)));
	FRotator DBAsRotation =	FRotator(0.0F, VectorBD.GetSafeNormal().Rotation().Yaw, 0.0F);
	FVector FinDBVector =	VectorBD.GetSafeNormal().Rotation().UnrotateVector(DBAsRotation.Vector());

	return PointB + FinDBVector * BD;


Hope this helps.

Thank you for the help, I didn’t end up using that amazing of a code. But you made me realize what I could do instead.

I simply get the trace normal, and rotate it along the right axis from the character. IE, I just have to rotate the character towards the ledge before doing the math again.


FVector UpNormal = WallTraceNormal.RotateAngleAxis(90, GetActorRightVector());

I simply fed that into the old function and it gives me a result that is pretty spot on if the character is rotated correctly, but if not a complete mess.