Problem with sky sphere and rotations

So, I’m kinda new to Unreal, and I’m trying to make an astronomy project where I have the sky, constelations, a sun, moon, etc., that must revolve correctly around the Earth’s center.

In my astronomy library, I can get horizontal coordinates for objects in Elevation/Azimuth angles, so I can set the Pitch (elevation) and Yaw (azimuth) accordingly for my rotator.

Problem is, in this context, (i’m using Set Relative Rotation), I stumbled on a gimbal lock when the Azimuth’s angle (Z) comes very close to the Roll (X), making all my objects in sky suddenly make an abrupt turn around, and all of it seems weird, especially for the moon and other planets (the sun isn’t a problem, since no one notices the rotation of a pure light sphere).

I searched everywhere for a solution, and the most I could come close is “use quaternions”. It happens no body told me how to use them, and especially in Unreal to make this work and I have no clue where to start. I don’t understand them very much also, but it for what I’ve read, internally when I call Make Rotator Unreal is already making a quaternion representation of this rotator. So why I still get this gimbal lock?

Any help appreciated.

Thanks.

It’s to do with how you’ve coded the rotation. It’s very easy to end up with a jump around +/-180.

Can you show the basic concept?

Sure, here is the basic blueprint concept.

Imgur

Imgur

Don’t worry too much with the second image, I put it there just to illustrate that for correct rendering I must invert the Y axis and displace the Azimuth to point to East instead of north, because the Sky Sphere is just an inverted normals sphere with the stars texture pre-rendered on it.

The “increment angle” function and limit to 360 is coded in C++.

1 Like

Yes, ‘set rotation’, that’s the problem :slight_smile:

You might have some joy using ‘combine rotators’. You have to work with the current rotation, and the delta between that and the required rotation. Something like

New to Unreal? Rotation can get tricky, right? Gimbal lock causing abrupt turns, huh? Quaternions might be the fix, but they’re tough.

Well, I tried the Add Relative Rotation, and… no, rotations still messes up.

Imgur

What really is happening is that when the moon gets close to 90º on Z, suddenly my North (X) flips to the South and then flips again close to 270º.

I am trying to figure out that quaternion stuff, but man. It is hard. :face_with_spiral_eyes:

Other way around

image

Tried that also… then when the moon gets to 90º it starts to jump all over the place. =\

The problem is, you’re making a rotator ( in your function ) that doesn’t take the current position into account.

Try putting the current roll ( relative ) in here

With rotation, you always have to respect the current orientation. You can’t just plug values in.

Ok, so after various failed attempts, switching to quaternion equations (yes, I did spend time studying at least the basics), etc., I finally figured out what is happening, and the problem is not with rotators, it is with the coordinate systems itself.

It escaped me that in 3D, the way horizontal coordinate systems work (elevation/azimuth), the azimuth’ s angle will always make your disk spin around no matter what you use (rotators or quaternions, or rotating matrices), because it is an angle between 0 and 360, where 0 points North and then it makes a full clockwise spin around your Z axis. So the fact that the meshes are spinning is because of the direct application of the angle on them - as suggested by most papers (apply elevation to pitch, azimutee to yaw).

While it accurately “works” for positining - I always can point to the middle of the sky with this, it doesn’t for rotation. So now, my problem is instead of a gimbal lock, I must map the coordinates in a way that Elevation can spin the pitch in a 360 degrees (cause visually, the sky revolves around the earth) but Yaw must only vary from -90º to +90º, or else my object will spin (and with reason). I guess no one who I visited was bothering with this before is because it is very hard to “see” stars spinning, they are all a bright point after all. But it is very noticeable with planets and moons.

Maybe I should apply some sins() and cos() between both elevation an azimuth coordinates so I can get a precise Pitch and Yaw values for me. Still working on that.

Meanwhile, I thank you all who answered here so quickly. You guys are amazing.

PS: If/when I find out the solution, I’ll come back here and leave it for posterity, but if any mathemathician around can still give me a hand, feel free to do it, cause I’m a C++ programmer, not a math guy. :smiley:

Thanks.

1 Like

Maybe, the problem with altitude and azimuth, is it just points to a location in the sky. It doesn’t say anything about the orientation of the body there.

Ok, I figured it out and as promised, I’m back to leave solution here for posterity.

The problem was indeed not with gimbal locks, but with Azimuth, because here is used to give objects positioning, not rotations. And since most papers tells us to map Azimuth to Yaw, this will simple make the object spin around the sky while also positioning it.

The solution? Instead of directly mapping Azimuth to Yaw, I used basic trigonometry to map it to ROLL instead. Then we rotate Pitch with elevation and add more Pitch based on which quadrant of the sphere we are (Azimuth helps here).

My sky sphere rotation setup is like the following:

Imgur

Hence, I came up with this code bellow:


FRotator UOrbitCalculations::GetRotatorForElevationAzimuth(double Elevation, double Azimuth)
{
	// Normalize Elevation to range [-90, 90] and Azimuth to range [0, 360]
	Elevation = FMath::Clamp(Elevation, -90.0, 90.0);
	Azimuth = FMath::Fmod(Azimuth, 360.0);
	if (Azimuth < 0) Azimuth += 360.0;

	double AzimuthRad = FMath::DegreesToRadians(Azimuth);
	double ElevationRad = FMath::DegreesToRadians(Elevation);

	double Pitch{}, Yaw{}, Roll{};
	FRotator FReturn;

	Roll = -FMath::Cos(AzimuthRad) * FMath::Cos(ElevationRad) * 180.0 / PI; // Roll is inverted
	Pitch = Elevation;
	Yaw = 0;

	// When Azimuth is past 180, we adjust Pitch
	if (Azimuth >= 180)
	{
		if (Elevation >= 0)
			Pitch = 180 - Elevation;
		if (Elevation < 0)
			Pitch = 180 + FMath::Abs(Elevation);
	}

	// Makes Pitch in 0-360 range
	if (Pitch < 0) Pitch += 360;

	// We also need to compensate Pitch by Azimuth's proximity to 0 or 180, 
	// since elevation would almost never reach 90º in a real world's sky.
	double PitchCorrection{};
	double AzimuthMod = FMath::Fmod(FMath::Abs(Azimuth), 180.0);
	double DistanceTo90 = FMath::Abs(90.0 - AzimuthMod) / 90.0;
	if (Elevation >= 0)
		PitchCorrection = (90 - Elevation) * DistanceTo90;
	else
		PitchCorrection = -(90 - FMath::Abs(Elevation)) * DistanceTo90;

	// Invert correction depending on sphere side (west side, elevation is inverted)
	if (Azimuth > 180.0)
		PitchCorrection *= -1;

	Pitch += PitchCorrection;

	FReturn.Roll = Roll;
	FReturn.Pitch = Pitch;
	FReturn.Yaw = Yaw;  // == 0;

	return FReturn;
}

Which I just invoke on a blueprint like this:

Imgur

Then, it will appears the same as the Horizontal Coordinations charts give, but avoiding objects to spin around while positioning.

And, thats is.

Thanks everyone here for your time.

Bye bye :slight_smile:

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.