Having a problem with rotations (again)

I was able to solve my enemy forward vector to my pawn rotation angle after some help and its made me more confident in being able to code using UE4’s API.

For the past day I’ve been trying to get the next angle which is the rotation of the camera in world space (attached to my pawn) versus the world location of the enemy.

I’ve tried atan2, acos, vector math (dot products etc), rotator deltas, normalizing, clamping, ranges etc.

This is following clockwise 0-360 rotations with 0d world rotation being 0 (north I think)

So what I have in pseudo code is



float TrueTargetBearing::MyBPFuncLib(APawn* TargetShip, APawn* PlayerShip)
{
USceneComponent camera = PlayerShip()->GetComponentByTag("PeriscopeCamera");
FRotator TrueTargetBearing = [All the things above that I tried in blueprints I tried in code as well here to get the view of the camera]

return trueTargetBearing.Z; //Get camera yaw
}


Here is what I;m trying to emulate which is written in c++ edited with what I have gotten done in UE4’s API so far and bold what I;m trying to replace with right now && small font what I should be able to do since it uses less or no trig/vector maths.



// Simulation of the Torpedo Data Computer (TDC)

void tdc::simulate(double delta_t)
{
**	// turn bearing dial to set bearing, with max. 2.5 degrees per second
	double bearingturn = 2.5 * delta_t;
	if (bearing_dial.diff(bearing) <= bearingturn) {
		bearing_dial = bearing;
	} else {
		if (!bearing_dial.is_cw_nearer(bearing))
			bearingturn = -bearingturn;
		bearing_dial += angle(bearingturn);
	} //I HAVE IS_CW_NEARER REPRODUCED IN UE4 C++**

	// AoB tracker: updated by bearing
	if (angleonthebow_tracking) {
		compute_aob(bearing_dial);
	}

	// compute lead angle from data

	double sinrelleadangle = target_speed * angleonthebow.sin() / torpedo_speed;


	valid_solution = false;
	if (fabs(sinrelleadangle) <= 1.0) {
		// angle is relative to absolute bearing

		angle relative_lead_angle = angle::from_rad(asin(sinrelleadangle));
		if (target_bow_is_left) {
			lead_angle = bearing_dial - relative_lead_angle;
		} else {
			lead_angle = bearing_dial + relative_lead_angle;
		}

		// compute run time from target distance
		angle aob_on_hit = angle(180) - angleonthebow - relative_lead_angle;
		torpedo_runtime = (angleonthebow.sin() * target_distance) / (torpedo_speed * aob_on_hit.sin());
		
// check if torpedo can hit target
		if (torpedo_speed * torpedo_runtime <= torpedo_runlength) {
			valid_solution = true;
		}



Yes I’ve watched many trig and vector math courses. Youtube, KhanAcademy, Ebooks etc.

Basically I can only get it in blueprints, but it gives me 0-180 and 180-0 so I cant even verify if thats right.

I’d like to hire someone to convert this class for me :haha:

Thanks for any input: this is my biggest issue with ue4 is blueprint vs c++ rotations seem to be different and rotations just wont “work” without a ton of “aha” moments that arnt sticking/arnt clear.

Edit: Heres what I’m tryin to solve in picture form, I can link the whole 30 page manual with all teh equations if needed.

I have (~)A AngleOffBow which we solved a few days ago (thanks again!), Co (own course aka world rotation), C (Target course) and R (range), so I’m trying to solve Br (B actually but Br is just relative vs world) which will give me G I’m hoping fairly easily which will allow me to figure out the angle I need to fire an actor at to hit a moving target from a moving target.
Edit: I also have P (length) for both ships.

What has stuck so far is how to calculate an angle (~)x from the big yellow line R given as two points with a forward vector from R as one and a random vector as two.

Edit: Two. This is actually where I’m at also this shows B instead of Br (how they relatate is the following: just world rotation vs relative to pawn rotation…)
B :: The angle between the north and south line and the line of sight to the target, measured clockwise from north (0d to 360d)
Br :: The angle between the vertical plane of the fwd and aft axis of own ship and the vertical plane through the line of sight measured CW from the bow (0d to 360d)

After that I just have to find G (gyro angle) and a few others and I’m good to go.

http://www.maritime.org/doc/tdc/img/pg024.jpg

Edit3: Heres OpenSSN’s bearing code. It appears they have the same issue, is this a limitation of cpp AND ue4? I have latitude and longitude so I could make this work if the math would port fine to ue4



double Submarine::BearingToTarget(Submarine *Target){
	double latdif=0, londif=0, bearing = 0; //atan() needs doubles
	//LatLonDifference(observer, target, &latdif, &londif);

        if (! Target)
           return 0;
	if (Lat_TotalYards > Target->Lat_TotalYards){
		latdif = Lat_TotalYards - Target->Lat_TotalYards;
	}
	else{
		latdif = Target->Lat_TotalYards - Lat_TotalYards;
	}

	if (Lon_TotalYards > Target->Lon_TotalYards){
		londif = Lon_TotalYards - Target->Lon_TotalYards;
	}
	else{
		londif = Target->Lon_TotalYards - Lon_TotalYards;
	}

	if ((Lon_TotalYards < Target->Lon_TotalYards) &&
	(Lat_TotalYards < Target->Lat_TotalYards)){
		bearing = (360 - ((atan(latdif / londif) * 360) / 6.28318530717958647692));
	}
	else if ((Lon_TotalYards < Target->Lon_TotalYards) &&
	(Lat_TotalYards > Target->Lat_TotalYards)){
		bearing = (0 + ((atan(latdif / londif) * 360) / 6.28318530717958647692));
	}
	else if ((Lon_TotalYards > Target->Lon_TotalYards) &&
	(Lat_TotalYards < Target->Lat_TotalYards)){
		bearing = (180 + ((atan(latdif / londif) * 360) / 6.28318530717958647692));
	}
	else if ((Lon_TotalYards > Target->Lon_TotalYards) &&
	(Lat_TotalYards > Target->Lat_TotalYards)){
		bearing = (180 - ((atan(latdif / londif) * 360) / 6.28318530717958647692));
	}
	if (londif == 0){
		if (Lat_TotalYards > Target->Lat_TotalYards){
			bearing = 90;
		}else{
			bearing = 270;
		}
	}
	if (latdif == 0){
		if (Lon_TotalYards > Target->Lon_TotalYards){
			bearing = 180;
		}else{
			bearing = 0;
		}
	}
	return bearing;
}

Blueprints are built on C++ so there is no difference under the hood between the two (besides the overhead that comes with a BP), and math is just math - it’s the same no matter what language you are using. The fun thing with math is there is one correct answer and an infinite number of incorrect answers. :slight_smile:

I’m having trouble understanding what angle you are trying to find. You mention the Camera rotation relative to the Target Subs’ rotation (in which case I think you grab the FRotator for each and just subtract their respective yaws from each other), but then your pictures show many more angles that would require a bit more work to find.

I went and looked at OpenSSN and you’ll need to take care when porting that stuff over. OpenSSN is built using simple 2D math with a bit of trig. Bringing that over to 3D vector algebra means you need to interpret WHAT the function is trying to do and not just porting it line for line.

Yes openSSN has alot of the functions I’ll need for newer tech which are very similar and I can do the 2D math no problem (atan2 y-y, dot(x-x, y-y, x-x)) its going to 3d vectors and using FRotators or floats as degrees that gets me. The whole 0-180-0 kills me.

I’m trying to get the angle from north/south line (ship moving to the left of the screen is travelling north) to the current rotation yaw of the camera on the ship 0-360d (So the camera rotation is relative to the ships forward vector, but I dont tihnk that affects the math for B or Br) . Thats Br (bearing relative to the world) 0-360d, left of 0 being 359.999 and down to 0 and camera rotating right (clockwise) being 0.0001 up to 360.

More importantly, I need the bearing B which is the same thing but replace north/south with the forward/aft (bow/stern) line of the boat. Then I can get gyro angle and have a firing solution with 3 moving targets.

I managed to get the angle on the bow, which is the exact same math this way with 2 pawns, but now that im using camera views and now two points its not working for me…



//Returns the angle on the bow
float UBPFuncLib_TDChelper::AngleOnBow(APawn* TargetShip, APawn* PlyrShip)
{
	FVector LineSight = (PlyrShip->GetActorLocation() - TargetShip->GetActorLocation());
	LineSight.Normalize();
	float BowAngleInDeg = FMath::RadiansToDegrees(FGenericPlatformMath::Acos(FVector::DotProduct(TargetShip->GetActorForwardVector(), LineSight)));
	
	if (FVector::DotProduct(TargetShip->GetActorRightVector(), LineSight) < 0.0f) // We need one more dot product to actually figure out our winding
		{
			//BowAngleInDeg *= -1;
			//If pos then sub is to the left or starboard
			//bIsAoBToPort = true;
			return BowAngleInDeg *= -1;
		}
		if (BowAngleInDeg < 0.1f && BowAngleInDeg >-0.1f)
			{
				return BowAngleInDeg = 180.0f;
			}
			else
			{
				return BowAngleInDeg;
			}

	
}


//Tells if the player is to port or starboard aka if AoB is negative or not
bool UBPFuncLib_TDChelper::IsPlayerToPort(float AoB)
{
	if (AoB < 0.0f)
	{
		return true;
	} 
	else
	{
		return false;
	}

}


Unfortunatly it gives me 0-180 +/- for left/right (port/starboard) I need 0-360… Cartesian Euler or watever you call it.

If you want that to return 0 - 360, just change it as such:


//Returns the angle on the bow
float UBPFuncLib_TDChelper::AngleOnBow(APawn* TargetShip, APawn* PlyrShip)
{
	FVector LineSight = (PlyrShip->GetActorLocation() - TargetShip->GetActorLocation());
	LineSight.Normalize();
	float BowAngleInDeg = FMath::RadiansToDegrees(FGenericPlatformMath::Acos(FVector::DotProduct(TargetShip->GetActorForwardVector(), LineSight)));
	
	if (FVector::DotProduct(TargetShip->GetActorRightVector(), LineSight) < 0.0f) // We need one more dot product to actually figure out our winding
	{
		return 360.0f - BowAngleInDeg;
	}

       return BowAngleInDeg;	
}

I will try that using targetship get actor forward vector to player ship.

How would I turn the line of sight from ship to ship vectors to plyrShip->GetActorForwardVector() - plyrShip [GET.CAMERA[NAME==PERISCOPE_CAM]] ?
edit Also any tips for consildating the GetBearing and GetRelativeBearing funtions i’ll be making so it takes in two input pawns and returns two floats. Im trying static void Bearing(const APawn& TargetShip, const APAwn& PlyrShip, float &brg, float &brgRel); from googling but errors all over

Edit3: OOps I was forgetting my UMyClass::Myfunction and just calling MyFunction I think I got the multiple in.out now

If you want to swap the Line of Sight to use the Camera’s Forward/Position, etc. You can add something like the following to your Submarine actor class:



void ASubmarine::GetCameraView(FVector& outLocation, FRotator& outRotation)
{
	if (APlayerController* playerController = Cast<APlayerController>(Controller))
	{
		if (playerController->PlayerCameraManager)
		{
			playerController->PlayerCameraManager->GetCameraViewPoint(outLocation, outRotation);
		}
	}
}

A few notes on that: It only grabs the currently ACTIVE camera’s location and rotation, if your camera is actually a Camera Actor in the world, you could just grab that actor’s location/rotation instead of querying the PlayerCameraManager. Check out this link.

Will check it out I’ve enver actually used the playercameramanager in my 2 years of unreal.

This is my code ATM. It doesnt return 0-360 but rather 0-180 postiive. And bearingTrue returns 180 when im pointed north (+x aka FVector::forwardVector aka 0,0,0 rotation) when it should return 0.

I actually never realized my own course went negative when I calculated (Get world rotation) it and turned -x or east (270 should be, but I get -90). could I just add 720 and mod 360 or just add 360?



void UBPFuncLib_TDChelper::Bearing(const APawn* TgtShip, const APawn* PlyrSub, float &brgTrue, float &brgRel)
{
	FVector LoS = (PlyrSub->GetActorLocation() - TgtShip->GetActorLocation()); //Line of sight from playersub center to target ship center
	LoS.Normalize();
	brgRel = FMath::RadiansToDegrees(FGenericPlatformMath::Acos(FVector::DotProduct(PlyrSub->GetActorForwardVector(), LoS))); //Bearing relative temp
	
	brgTrue = FMath::RadiansToDegrees(FGenericPlatformMath::Acos(FVector::DotProduct(FVector::ForwardVector, LoS))); //Bearing true from ForwardVector, is that north south?
}


Thank you for th help so far. Going to get 0-360 if it kills me!

brgRel works correctly when me and the ship are parrallel (90) but the whole north being 180 instead of 0 breaks the rest.

Edit: For what its worth, get controller rotation works… I’ll have to try to work with that somehow.
Edit: worldRotation + 720 % 360 doesnt work to create 0->90->180->270->359.99999999
Edit: Get controller rotation does indeed work

So the big issue is Get Control Rotation works fine for this, but I wont always have a perfectly lined up camera active to get my ships heading… How might I solve that, there simply MUST BE a way to get the 0-360 rotation of a mesh/scene component etc

Edit: So using GetWorldRotation I almost had it via this…

If wRot > 0 {return wRot}
else return wRot - 180 * 2 + 180 % 360.

This gave me 0-180 clockwise and from 0-270 counter clockwise at which point it went to 180 going down again.

This is really bugging me, I never even realized all my angles that rely on 360d are wrong, now I only have 1 correct angle (angleOnBow code above) of 5 needed instead of 3 of 5.

How can I get a scene components world rotation in 0-360 cw/ccw?

wopuld it be possible to do vector math?

0-90 90-180 180-270 and 270-360 based on +/- fwd and right vectors

+Forward compared to 1,0,0 = 0,0,0 (0) to 1,0,0 (90) and
-Right = 90 to 180

  • forward = 180 to 270
    +right = 270 to 360

I beleive I got it, and this should apply to any world/actor/ any rotation thats not a control rotation.



float r1 = yourPawn->GetActorRotation.Yaw();
if(r1 < 0.0)
{
return r1 + 360;
}
else 
{
return r1;
}


It works for heading, going to try for these angles later! Ahhh and here I was going to code quats over my whole game…

I am pretty confused about what is being asked here. Is “FindLookatRotation” what you are finding for?

Yes I suppose to some degree, it needs the above applied to it though, I’ve stopped using it since it doesnt give proper results. Coding anyway. Will make sure my rot-360 if rot < 0.0f works tomorrow

Heres the kicker.

This code doesnt work it stays 0-180-0 (or worse)


void UBPFuncLib_TDChelper::Bearing(const APawn* TgtShip, const APawn* PlyrSub, const UCameraComponent* ScopeCam, float &brgTrue, float &brgRel)
{

	if (TgtShip == nullptr || PlyrSub == nullptr || ScopeCam == nullptr)
		{
			debug("TgtShip or PlyrSub or ScopeCam == nullptr in BPFuncLib_TDCHelper::Bearing");
		}
		else
			{
			FVector LoS = (PlyrSub->GetActorLocation() - TgtShip->GetActorLocation()); //Line of sight from playersub center to target ship center
			LoS.Normalize();
			brgRel = FMath::RadiansToDegrees(FGenericPlatformMath::Acos(FVector::DotProduct(PlyrSub->GetActorForwardVector(), LoS))); //Bearing relative temp

			brgTrue = FMath::RadiansToDegrees(FGenericPlatformMath::Acos(FVector::DotProduct(FVector::ForwardVector, LoS))); //Bearing true from ForwardVector, is that north south?

					if (brgRel < 0)
					{
						brgRel = brgRel + 360.f 
					} 
					if (brgTrue < 0)
					{
						brgTrue = brgTrue + 360;
					}

			}
}

Note I also tried using the UCameraComponent.GetForwardVector/location/upvector.

But the blueprint equivalent does work the following is PERFECT. (top is perfect, bottom using the code node gives wrong result as above)

So I guess I must ask for a gimme to continue learning, how do I repdouce the tpo half of the blueprint picture in code?