Gimbal lock fix?

Want to edit the game, build your own craft and missions? Here you'll find help, tools, guides and people to discuss with.

Gimbal lock fix?

ZanElJOK
Rebel Alliance
Posts: 46
Joined: Fri Feb 13, 2009 3:30 am

Post by ZanElJOK » Wed Feb 12, 2020 8:51 pm

Hello everyone,

I have to say thank you to all of you for keeping such a great game alive. With all the improvements you continue to make I don't even bother going out to find the next game because of all the potential you all have been able to unlock here.

I know you all have a load of things you are working on already, but I was curious if anyone has ever looked at trying to solve the issue that I regularly run into. I will be setting up an attack run on a small target like a box/sphere containeror disabled starfighter or I will be mid dogfight and my adversary has found one of those sweet spots in space that makes it impossible to target them. I can get my target reticle all around them trying to get them but that one angle they are in is unreachable.

Ny thought is they are sitting right on the conjunction of the axis and for some reason I can't travel that same course. Thus making me adjust my course or extending the dog fight longer than it needed to go.

Zan
May the Force be with you all.

User avatar
blue_max
XWAU Member
Posts: 2295
Joined: Wed Mar 20, 2019 5:12 am

Post by blue_max » Wed Feb 12, 2020 9:58 pm

What you're describing sounds like something that happens when you either look "straight up" or "straight down". The easiest way to reproduce this problem is to start a skirmish mission with no enemies and then just pull up (or down) until you see a galaxy/sun/planet: you won't be able to keep moving or to target these elements directly.

AFAIK this is a relic of how the coordinate system was setup from predecessors of this game -- probably from a WWII sim; and it probably has to do with the way the game computes the orientation of the craft (yaw/pitch/roll).

I don't think there's a fix for this issue at the moment. And even if someone tries to fix this, it would imply modifying several places in the code. So the chances of getting this fixed are very small.

I would love to be proven wrong though. But right now, we're probably just going to have to live with this.

User avatar
DTM
Fleet Admiral (Administrator)
Posts: 2119
Joined: Tue Apr 22, 2003 11:01 pm
Contact:

Post by DTM » Thu Feb 13, 2020 5:48 am

Let's say it: it is a malfunction of the R2 units. The cosmic rays from the celestial bodies confuse the sensors and the guide units overload. Does it sound better? :D

User avatar
keiranhalcyon7
Lieutenant JG
Posts: 599
Joined: Tue Jan 02, 2018 6:41 am

Post by keiranhalcyon7 » Thu Feb 13, 2020 5:57 am

Zan, blue_max - Yes, that's exactly the problem. The system used to represent orientations results in "gimbal lock". I don't quite understand it myself, since all orientations are representable, but you can look it up if you're interested. Other representation systems that do not suffer from the problem do exist (quaternions), but patching it into the game would require such a massive overhaul that is not currently feasible.

And yes, the X-Wing series descends from a trio of WWII sims, the third of which was called Secret Weapons of the Luftwaffe, which was referenced obliquely in the XWA campaign.

ZanElJOK
Rebel Alliance
Posts: 46
Joined: Fri Feb 13, 2009 3:30 am

Post by ZanElJOK » Thu Feb 13, 2020 10:11 pm

I can't say i am surprised about the amount of work it would take to get such a small glitch fixed. I will just get and try to avoid the buffer from those darn solar wind storms :D .
May the Force be with you all.

User avatar
sedenion
Cadet 2nd Class
Posts: 78
Joined: Tue Feb 26, 2019 10:36 am

Post by sedenion » Thu Dec 08, 2022 10:18 am

Sorry to I dig up this post. I wondered if the question was already investigated.
Strangely, I don't remember this gimbal-lock spot was so large at the time, and I wonder why this seem so obvious and anoying noweaday.

Anyway, my sensation is that this pretty large no-go-zone si not the gimbal-lock itself but is rather "generated" to prevent gimbal-lock and make sure engine will never encounter math exception. This would mean that the radius of this spot depend on an arbitrary value which may be modified, so reduced.

Since the 3D engine maths works, if I well understoud, in 16 bits , I doubt the radius of this "spot" can be reduced much without risking math exception, but this could be interesting to find (if it exists) and modify this arbitrary value to check what happen.

User avatar
blue_max
XWAU Member
Posts: 2295
Joined: Wed Mar 20, 2019 5:12 am

Post by blue_max » Thu Dec 15, 2022 6:07 pm

There may yet be hope, @sedenion :

https://youtu.be/SgtpHsMICKg

Months ago, I was looking at the in-memory Object table in XWA for other reasons and noticed that it was possible to modify the position of the player's ship by writing directly to the proper entry in this table. The Object table also has yaw, pitch, roll; but I didn't pay attention back then. When you brought this up the other day, I wondered if maybe it would be possible to change the player's orientation by writing directly to this table. Apparently, the answer is yes, and as a bonus, I didn't see any gimbal lock either (so, we won't need quaternions either).

If this works, we're going to need to code a number of things on our own. For instance, the turn rate changes depending on the speed. Does anyone have any numbers for that?

Also, do we know the different rates of turn for each flyable ship? We're going to need to code that as well.

I'm not promising anything yet, but I'll try to get a proof-of-concept for this idea working soon. Finally, I quickly tested what happens when the external camera is active, and it didn't work (it made the camera spin instead of the ship). But hey, if we can get this working for the cockpit, that'll be something, right?

User avatar
sedenion
Cadet 2nd Class
Posts: 78
Joined: Tue Feb 26, 2019 10:36 am

Post by sedenion » Thu Dec 15, 2022 6:45 pm

blue_max wrote:
Thu Dec 15, 2022 6:07 pm
If this works, we're going to need to code a number of things on our own. For instance, the turn rate changes depending on the speed. Does anyone have any numbers for that?
Not only the speed, but also available engine power. Manoeuvrability values are known it seem, but what is missing is the flight model logic to produce the proper response curve.
Anyway, I am not sure trying to substitue the flight model is good approach. What you pointed out confirm my intuition: There is no real gimbal lock, the "no-go" zone at polar orientations are programatically generated, and this mean there certainly somewhere a value that define the radius this of this zone. Find this value, set it to 0 or a small value, and the problem is solved.

User avatar
blue_max
XWAU Member
Posts: 2295
Joined: Wed Mar 20, 2019 5:12 am

Post by blue_max » Thu Dec 15, 2022 7:04 pm

sedenion wrote:
Thu Dec 15, 2022 6:45 pm
There is no real gimbal lock, the "no-go" zone at polar orientations are programatically generated, and this mean there certainly somewhere a value that define the radius this of this zone. Find this value, set it to 0 or a small value, and the problem is solved.
Maybe, but I'm assuming the "no go zone" was added to avoid a division by 0, so maybe it can be reduced, but not removed. Plus, I'm not sure if anyone has found the relevant section of the code yet. This approach, on the other hand, appears to be within reach.

User avatar
sedenion
Cadet 2nd Class
Posts: 78
Joined: Tue Feb 26, 2019 10:36 am

Post by sedenion » Thu Dec 15, 2022 7:18 pm

blue_max wrote:
Thu Dec 15, 2022 7:04 pm
Maybe, but I'm assuming the "no go zone" was added to avoid a division by 0, so maybe it can be reduced, but not removed. Plus, I'm not sure if anyone has found the relevant section of the code yet. This approach, on the other hand, appears to be within reach.
If math exception must occure, it is in the computation to create the rotation matrix from the raw yaw-pitch-roll values that you manually injected in your test, or maybe in the subsequent vector-matrix multiplication to produce vertices world positions...In two words: in the computation that occurs "after" what you modified in memory. What you tested seem to prove that no math exception is thrown even if you force the yaw-pitch-roll to the critical orientation. Anyway further tests are obviously needed to ensure this is robust.
My intuition is that this zone is implemented for the software renderer while the DirectX renderer (more modern) don't care.

User avatar
blue_max
XWAU Member
Posts: 2295
Joined: Wed Mar 20, 2019 5:12 am

Post by blue_max » Thu Dec 15, 2022 7:24 pm

sedenion wrote:
Thu Dec 15, 2022 7:18 pm
What you tested seem to prove that no math exception is thrown even if you force the yaw-pitch-roll to the critical orientation. Anyway further tests are obviously needed to ensure this is robust.
You are correct. I was also half-expecting the engine to explode when I forced the critical pitch value, but it didn't. I now suspect the gimbal lock problem is in the joystick-to-ship-orientation code. But I need to test again using the smallest possible pitch increment to be sure.

User avatar
keiranhalcyon7
Lieutenant JG
Posts: 599
Joined: Tue Jan 02, 2018 6:41 am

Post by keiranhalcyon7 » Thu Dec 15, 2022 9:09 pm

FWIW, even without hacks, custom skirmishes will sometimes start the player craft facing one of the poles. The heading is meta-stable; leave the stick alone, and you fly straight, but if you input any slight attitude change, the gimbal-lock code pushes you strongly away from the pole.

User avatar
blue_max
XWAU Member
Posts: 2295
Joined: Wed Mar 20, 2019 5:12 am

Post by blue_max » Thu Dec 15, 2022 10:33 pm

keiranhalcyon7 wrote:
Thu Dec 15, 2022 9:09 pm
FWIW, even without hacks, custom skirmishes will sometimes start the player craft facing one of the poles. The heading is meta-stable; leave the stick alone, and you fly straight, but if you input any slight attitude change, the gimbal-lock code pushes you strongly away from the pole.
Thanks for the insight, I'll test this too.

User avatar
blue_max
XWAU Member
Posts: 2295
Joined: Wed Mar 20, 2019 5:12 am

Post by blue_max » Fri Dec 16, 2022 8:39 pm

I think this approach is very likely work. Yesterday I tested it going over the poles at the smallest possible increment: no crash. I also tested going close to the poles, but not exactly over them, again, no problem: no invisible force pushed me away from the pole either.

Now I just need Math and patience.

User avatar
keiranhalcyon7
Lieutenant JG
Posts: 599
Joined: Tue Jan 02, 2018 6:41 am

Post by keiranhalcyon7 » Sat Dec 17, 2022 3:05 am

If it seems to work, I have to wonder what the push code is there for in the first place. Maybe it was a mathematical problem in older versions of the engine? Or maybe the issue will be revealed once this change is in wide use?

User avatar
sedenion
Cadet 2nd Class
Posts: 78
Joined: Tue Feb 26, 2019 10:36 am

Post by sedenion » Sat Dec 17, 2022 8:01 am

I think this repulsive zone was indeed implemented to prevent gimbal lock in early version of the engine. The huge radius of the repulsive zone give us some clue about the epoch this was implemented... The gimbal lock problem is pretty straightforward to avoid even without quaternions, this is a problem of very rudimentary engines.

User avatar
blue_max
XWAU Member
Posts: 2295
Joined: Wed Mar 20, 2019 5:12 am

Post by blue_max » Tue Dec 20, 2022 1:34 am

I've been tinkering a little bit with this over the last few days and it's very tricky to get right.

My previous observation was simply that the engine doesn't explode if I artificially point the ship straight up or straight down. Meaning that a pitch of 0 or 180 degrees is just fine (for some reason, they chose to measure pitch from Z+, which is the Up direction in this game).

Yaw is measured from Y+, which is the forward direction. So, Yaw becomes undefined when Pitch is either 0 or 180. This isn't a problem in the video I posted, because I didn't modify the initial Yaw, but it becomes a problem when converting a generic orientation back to (yaw,pitch,roll) which is something I *have* to do because that's what the engine uses.

To avoid gimbal lock, I'm using a set of three unitary vectors representing the ship's forward, up, and right directions. Yaw is applied around the Up axis, transforming the whole system; then Pitch is applied around the (transformed) Right axis and finally Roll is applied around the (transformed^2) Forward axis. While this appears to work fine by itself, I still have to convert the Forward vector into yaw/pitch and use the Up vector to get the Roll. As you guys probably guessed already, when the Forward vector points straight up, Yaw is undefined. So, what do I feed XWA in that case? I guess I can probably set Yaw = 0 because in this situation, Yaw is controlled by Roll. However, I'm still seeing some weird behavior in my machine and I'm not sure I've found all the bugs. The other problem is cumulative precision errors that cause the unitary vectors to not be so unitary anymore, so I need to address that as well.

Another way to avoid this problem altogether is to use the Forward,Up,Right vectors to write the proper rotation matrix into the XWAObject itself. Thus avoiding yaw,pitch,roll. But I think we're going to need a new hook for that.

User avatar
keiranhalcyon7
Lieutenant JG
Posts: 599
Joined: Tue Jan 02, 2018 6:41 am

Post by keiranhalcyon7 » Tue Dec 20, 2022 2:47 am

If you're contemplating directly controlling the XWAObjects, I think you might as well go all the way and use quaternions in the back end of it.

User avatar
sedenion
Cadet 2nd Class
Posts: 78
Joined: Tue Feb 26, 2019 10:36 am

Post by sedenion » Tue Dec 20, 2022 10:44 am

blue_max wrote:
Tue Dec 20, 2022 1:34 am
To avoid gimbal lock, I'm using a set of three unitary vectors representing the ship's forward, up, and right directions. Yaw is applied around the Up axis, transforming the whole system; then Pitch is applied around the (transformed) Right axis and finally Roll is applied around the (transformed^2) Forward axis. While this appears to work fine by itself, I still have to convert the Forward vector into yaw/pitch and use the Up vector to get the Roll. As you guys probably guessed already, when the Forward vector points straight up, Yaw is undefined. So, what do I feed XWA in that case? I guess I can probably set Yaw = 0 because in this situation, Yaw is controlled by Roll. However, I'm still seeing some weird behavior in my machine and I'm not sure I've found all the bugs. The other problem is cumulative precision errors that cause the unitary vectors to not be so unitary anymore, so I need to address that as well.

Another way to avoid this problem altogether is to use the Forward,Up,Right vectors to write the proper rotation matrix into the XWAObject itself. Thus avoiding yaw,pitch,roll. But I think we're going to need a new hook for that.
What you explain sound very wierd to me. Can you please explain me what kind of initial data you have and what you want to achieve with ? I have plenty of C/C++ code for 3D transformations (euler angles and quaternion to/from matrix conversion etc..), including quaternions represtantions, so I probably already have all what you need, but I first need to understand what exactly you are trying to achieve using what "input" data for what "output".

For example you speak about "three unitary vectors representing the ship's forward, up, and right directions", this is the definition of a rotation matrix... So, I understand you are using a local (object space) rotation matrix to apply proper rotations along the object (ship) axes. I well understand ?

(mathematically speaking, yaw-pitch-roll paradigm is nothing but euler angles describing object rotations... what is important is how rotations are applyed to object, here lie the problem of world-space or object-space applied transformations)

User avatar
m0rgg
XWAU Member
Posts: 266
Joined: Wed Apr 01, 2020 10:33 pm

Post by m0rgg » Tue Dec 20, 2022 5:18 pm

From what I saw when hacking the head tracking improvements, the rotations in XWA are calculated based on (vector,rotation angle) inputs.

So my guess is that the world transform is applied to the objects in 3 successive vector rotations in the 3 world reference axes. For that, the transform needs to be decomposed in 3 rotations, which is subject to the gimbal lock issue.
The reason why @blue_max can hack directly the values is because it's probably applying it after the game engine transforms, at the rendering stage.

What I did to avoid it for the headtracking was to do a direct matrix multiplication, by composing a matrix from the 3 (up,right,forward) vectors stored by the engine for the camera, and multiplying directly with the transformation matrix from the head pose.

My guess (without having looked at the code for months) would be that something similar can be done for the ship heading, by hooking the calls to the functions applying the world transform to the player's ship, would receive the joystick data as input.
It would be probably more "sustainable" than hacking the values at rendering time, as this can generate other unexpected side effects (we can't be sure if the ship heading vector is used for something else before it's overwritten).

Just my 2 cents!

User avatar
blue_max
XWAU Member
Posts: 2295
Joined: Wed Mar 20, 2019 5:12 am

Post by blue_max » Tue Dec 20, 2022 5:37 pm

Looks like this approach might work after all?

https://youtu.be/IOs3v3ccMfE

User avatar
blue_max
XWAU Member
Posts: 2295
Joined: Wed Mar 20, 2019 5:12 am

Post by blue_max » Tue Dec 20, 2022 6:04 pm

sedenion wrote:
Tue Dec 20, 2022 10:44 am
What you explain sound very wierd to me. Can you please explain me what kind of initial data you have and what you want to achieve with?
The initial data is an orthonormal vector basis. R = [1,0,1], U = [0,0,1] and F = [0,1,0] corresponding to the World's Right, Up and Forward directions. When the joystick is applying yaw, I rotate the whole system around the U vector, creating a new orthonormal system, R', U', F'. To apply joystick pitch, I rotate everything about R' creating R'', U'', F'', and finally roll is applied around F''. Thus you end up with another orthonormal system R''', U''', F''' which is then converted to XWA's yaw, pitch, roll. On the next frame R = R''', U = U''', F = F''' and the process starts over.
For example you speak about "three unitary vectors representing the ship's forward, up, and right directions", this is the definition of a rotation matrix... So, I understand you are using a local (object space) rotation matrix to apply proper rotations along the object (ship) axes. I well understand ?
Yes, R,U,F is a rotation matrix and yes, we can totally write this information directly into XWA's memory instead of converting to yaw, pitch, roll; but we're going to need a hook for that because when I wrote RUF to XWA's memory it didn't work. Most likely because of what m0rgg explained above.

Speaking of m0rgg, he's right that we shouldn't be doing it this way, we should be hooking the function in XWA that computes this transformation; but... baby steps :)

User avatar
sedenion
Cadet 2nd Class
Posts: 78
Joined: Tue Feb 26, 2019 10:36 am

Post by sedenion » Tue Dec 20, 2022 6:39 pm

Yes, R,U,F is a rotation matrix and yes, we can totally write this information directly into XWA's memory instead of converting to yaw, pitch, roll; but we're going to need a hook for that because when I wrote RUF to XWA's memory it didn't work. Most likely because of what m0rgg explained above.
Ok so I understand you implemented rotation mechanism using matrices, but you have trouble converting your matrix into euler angles (yaw pitch roll). I have code sample for that if you want... (and at this stage, why not using quaternions for the whole process...)
Speaking of m0rgg, he's right that we shouldn't be doing it this way, we should be hooking the function in XWA that computes this transformation; but... baby steps :)
Well... as I said previously, even if you implement whole transformation mechanism (and I have stuff an knowledge for that if you want), you'll need to implement the flight model that convert joystick input value into applyed rotations, so, you are about to code a whole new game...

User avatar
blue_max
XWAU Member
Posts: 2295
Joined: Wed Mar 20, 2019 5:12 am

Post by blue_max » Tue Dec 20, 2022 6:55 pm

sedenion wrote:
Tue Dec 20, 2022 6:39 pm
Ok so I understand you implemented rotation mechanism using matrices, but you have trouble converting your matrix into euler angles (yaw pitch roll). I have code sample for that if you want... (and at this stage, why not using quaternions for the whole process...)
I previously had some trouble converting RUF into yaw, pitch, roll, but -- apparently -- I got it right:

https://youtu.be/IOs3v3ccMfE

BTW, thanks for the offer, but I don't think quaternions are necessary at this point yet.
... you'll need to implement the flight model that convert joystick input value into applyed rotations, so, you are about to code a whole new game...
Yes, I'm going to need to re-implement a bit of the joystick code and flight engine, but I don't think this amounts to coding a whole new game. I'm going to need some data from XWA, things like rate of turn (per axis); how that changes according to current speed and engine settings; how much do ships roll when they yaw, etc -- small things like that. I don't think that would be too hard, though.

User avatar
sedenion
Cadet 2nd Class
Posts: 78
Joined: Tue Feb 26, 2019 10:36 am

Post by sedenion » Tue Dec 20, 2022 7:23 pm

blue_max wrote:
Tue Dec 20, 2022 6:55 pm
BTW, thanks for the offer, but I don't think quaternions are necessary at this point yet.
In fact they are never necessary...
Yes, I'm going to need to re-implement a bit of the joystick code and flight engine, but I don't think this amounts to coding a whole new game. I'm going to need some data from XWA, things like rate of turn (per axis); how that changes according to current speed and engine settings; how much do ships roll when they yaw, etc -- small things like that. I don't think that would be too hard, though.
What I mean, is that you are about to code new flight model that will not be the same as the existing one. Since, as far as I know, we simply don't know how the flight engine is coded, we cannot reproduce it accurately... There is seemely a rudimentary physics engine that convert inputs into torque and pushing forces with damping etc... I don't think it is as simple as roll rate according joystick input value.

Post Reply