The Rotation Wars: Euler vs Quaternion

Discuss modding questions and implementation details.
Post Reply
User avatar
BadLuckBurt
Posts: 948
Joined: Sun Nov 05, 2017 8:30 pm

The Rotation Wars: Euler vs Quaternion

Post by BadLuckBurt »

First off, Interkarma, I'm sorry for bringing this stuff up again so soon but I think I have cracked the problem once and for all thanks to that coffin in Scourg Barrow.

Your approach to applying the original rotation data from classic should never ever be touched again, it is the right way to apply them. I will try to describe and illustrate the problem below and then my solution.

Problem

In general: when applying Euler rotation angles to a Quaternion, the angles you put in are not the same angles that are returned when you query the Quaternion for the Euler angles afterwards. Since Unity only uses Quaternions for rotation internally, you can never ever get back the angles from classic data that you put in. It is one of those 'touch once, never look back' situations.

The rotation angles in Daggerfall's original data came from a system / editor that exclusively used Euler angles for rotation. By applying these rotations one axis at a time in Unity, you successfully created the corresponding Quaternion rotation in Unity. The fact vanilla layouts work perfectly proves this.

When the original RDB data gets dumped to JSON using the 'dumpblock' command, they still contain the original rotation values and should always be handled accordingly by applying the rotations one axis at a time in Z, X, Y order. So far so good.

However, when making a new RDB.json from scratch or editing an existing RDB.json in World Data Editor, the Euler rotation angles shown in the rotation fields when you select an object originate from the Quaternion of the objects transform and do not correspond to the angles in classic data. When saving the edited RDB, the rotations that are written will always originate from the object's Quaternion. I have attached two screenshots, one shows the coffin's original Euler rotation and the other shows the rotation values we get in Unity. Note how there is suddenly a rotation angle on the Z-axis that is NOT in the classic data.

I have also attached a ZIP with two RDB.jsons in it, it's the starting block for Scourg Barrow. The S0000205.RDB_ORIGINAL.json is the file I obtained with the `dumpblock` command, this contains the original Euler rotations from the classic data. The S0000205.RDB.json is the version that I opened in World Data Editor and then immediately saved. If you use a file compare tool and check the differences, you will see that the rotation values have changed.

Applying the WDE rotations in the way you handled the classic rotations therefore causes issues and as my PR showed, the reverse is also true so we need a way to distinguish between the two data sets.

Solution

As you may notice when comparing the two JSON files, I have added a boolean value named CustomBlock to the DFBlock struct which will be set to TRUE when the block is saved by the World Data Editor. I also enforce the boolean being TRUE when the block is loaded through WorldDataReplacement. When a block is loaded from the original game files, I set it to FALSE.

By passing this boolean to the RDBLayout.GetModelMatrix when it's called, we can either apply the Quaternion rotation or the classic rotation you implemented based on the boolean being TRUE or FALSE.

With this fix present, I am able to load the S0000205.RDB.json that has the Quaternion rotation values without the object rotations breaking.

This also fixes the WDE behaviour as that suffers from the same issue, you can see this by loading the S0000205.RDB_ORIGINAL.json into WDE and going to KoW's room, that dreaded coffin rotation is screwed atm because WDE sets the rotation in one pass.

Questions

I have not made a PR yet because I wanted to discuss how this should be approached:

The 'dumpblock' command gives us the original Euler rotation angles but once we start editing they will unavoidably end up as the Quaternion's Euler angles. In my opinion it may be a good idea to swap out the original rotation data for the Quaternion's data when dumping a block while at the same time setting the CustomBlock property on the DFBlock to TRUE.

Before WDE was a thing, I worked on a similar capability using Blender and Python scripts to import / export. I have had no issues importing the JSON files with the original Euler angles by applying them in the ZXY order but did discover that I had rotation issues with certain objects when exporting back to JSON format.

I did not fully grasp the cause of the problem at the time so I just worked around it but now that I do, I think it's time to kill this demon once and for all.

I am sorry if I have melted brains with this post, I've tried to explain it as simple as possible but it is a major PITA to wrap your head around.
Attachments
ScourgBarrowTest.zip
(15.79 KiB) Downloaded 52 times
ScourgBarrowCoffinWDEAngles.png
ScourgBarrowCoffinWDEAngles.png (43.67 KiB) Viewed 1565 times
ScourgBarrowCoffinOriginalData.png
ScourgBarrowCoffinOriginalData.png (31.78 KiB) Viewed 1565 times
DFU on UESP: https://en.uesp.net/w/index.php?title=T ... fall_Unity
DFU Nexus Mods: https://www.nexusmods.com/daggerfallunity
My github repositories with mostly DFU related stuff: https://github.com/BadLuckBurt

.

User avatar
Hazelnut
Posts: 3016
Joined: Sat Aug 26, 2017 2:46 pm
Contact:

Re: The Rotation Wars: Euler vs Quaternion

Post by Hazelnut »

Thanks for the investigation Burt. I was aware that the WD editor changed rotation values but only is as much as it was essentially the same rotation but just a different direction and appeared to minimise the rotation numbers. I had no idea how this could be prevented, and was okay with it since it seemed to not cause issues. Beyond that I don't grasp what is going on, most of that code is from Uncanny's building editor that I used as the base.

I will take a look at this specific coffin and see if there's some code change that could avoid the Z rotation appearing for that coffin. I'd prefer to avoid the need for any special case handling of world data in DFU layout code to support world data overrides and editing if possible, but your solution might be the only one that will work.

One question I have is what's special about this coffin exactly? This stuff is working fine for 99.9% of DF models and RDBs, and I didn't get what is causing this issue exactly.
See my mod code for examples of how to change various aspects of DFU: https://github.com/ajrb/dfunity-mods

User avatar
BadLuckBurt
Posts: 948
Joined: Sun Nov 05, 2017 8:30 pm

Re: The Rotation Wars: Euler vs Quaternion

Post by BadLuckBurt »

Hazelnut wrote: Fri Mar 11, 2022 5:18 pm Thanks for the investigation Burt. I was aware that the WD editor changed rotation values but only is as much as it was essentially the same rotation but just a different direction and appeared to minimise the rotation numbers. I had no idea how this could be prevented, and was okay with it since it seemed to not cause issues. Beyond that I don't grasp what is going on, most of that code is from Uncanny's building editor that I used as the base.

I will take a look at this specific coffin and see if there's some code change that could avoid the Z rotation appearing for that coffin. I'd prefer to avoid the need for any special case handling of world data in DFU layout code to support world data overrides and editing if possible, but your solution might be the only one that will work.

One question I have is what's special about this coffin exactly? This stuff is working fine for 99.9% of DF models and RDBs, and I didn't get what is causing this issue exactly.
I don't have the energy to explain the difference between Euler and Quaternion any more than what I did here. Unity's documentation even warns that you may never get the original Euler rotation angles back from a Quaternion due to how a Quaternion works internally (and you really don't want to know about that).

The data saved by the World Data Editor needs to be treated differently than the original data when it comes to these rotations. You can get Ralzar's RDB from my closed PR, drop that in your World Data folder and go to Bish Mines in the Dragontail Mountains using the live build, you will spawn next to two beams that are standing upright. Then open the RDB in World Data Editor and you'll see that they are supposed to be slanted.

There's no need to look at the coffin specifically, Interkarma showed with his screenshots that it also happens with levers etc. Anything that is rotated around 2 or more axes has the potential of having this problem.
DFU on UESP: https://en.uesp.net/w/index.php?title=T ... fall_Unity
DFU Nexus Mods: https://www.nexusmods.com/daggerfallunity
My github repositories with mostly DFU related stuff: https://github.com/BadLuckBurt

.

User avatar
Interkarma
Posts: 7242
Joined: Sun Mar 22, 2015 1:51 am

Re: The Rotation Wars: Euler vs Quaternion

Post by Interkarma »

Hey Burt. :) Thank you for the detailed write up. I'm happy with the fix you've presented, it's all clear and makes sense.

Send me a PR and I'll give it a whirl. If I don't find any problems, happy to merge into future builds. Cheers!

User avatar
BadLuckBurt
Posts: 948
Joined: Sun Nov 05, 2017 8:30 pm

Re: The Rotation Wars: Euler vs Quaternion

Post by BadLuckBurt »

Interkarma wrote: Tue Mar 15, 2022 10:16 pm Hey Burt. :) Thank you for the detailed write up. I'm happy with the fix you've presented, it's all clear and makes sense.

Send me a PR and I'll give it a whirl. If I don't find any problems, happy to merge into future builds. Cheers!
You're welcome and thank you for remaining open to this. I was hesitant to make this post but on the other hand I knew it had to be done and using that coffin I was able to get to the bottom of it. I will prepare the PR and give it some more testing to make absolutely sure it works as intended but I'm 99.9% certain this is the way to relieve the pains.

I have to see if the interiors suffer the same issue, the classic ones all seem fine but I think the models there only rotate around 1 axis. I think the code that does exterior and interior layout also applies it in one pass.

I'll make a spreadsheet of all exterior and interior model rotations that have more than one axis involved and test it that way. I have a pretty good idea what to look for at this point.

Expect the PR to pop up later in the week when I've had a chance to confirm there are no further hicups.

Thanks again, I really appreciate it.
DFU on UESP: https://en.uesp.net/w/index.php?title=T ... fall_Unity
DFU Nexus Mods: https://www.nexusmods.com/daggerfallunity
My github repositories with mostly DFU related stuff: https://github.com/BadLuckBurt

.

l3lessed
Posts: 1403
Joined: Mon Aug 12, 2019 4:32 pm
Contact:

Re: The Rotation Wars: Euler vs Quaternion

Post by l3lessed »

Would this affect raycasting at all? I wouldn't think so, correct?

Curious, as I spent some time trying to figure out how to do proper rotations of my weapon raycast arcs, and this required messing with uelers and rotations and pushing them through a lerp system to calculate their position in relation to the weapon animation timing, and ensure it wasn't visually off sync enough that it is largely noticeable.
My Daggerfall Mod Github: l3lessed DFU Mod Github

My Beth Mods: l3lessed Nexus Page

Daggerfall Unity mods: Combat Overhaul Mod

Enjoy the free work I'm doing? Consider lending your support.

User avatar
BadLuckBurt
Posts: 948
Joined: Sun Nov 05, 2017 8:30 pm

Re: The Rotation Wars: Euler vs Quaternion

Post by BadLuckBurt »

I have no experience with raycasts, I thought those always went in a straight line.

What I described here is purely for model rotations.

It is possible, what I understand about quaternions is that they look for the shortest path to achieve a rotation. Due to the math (and the devilish rituals) it performs internally the results arent always what you expect
DFU on UESP: https://en.uesp.net/w/index.php?title=T ... fall_Unity
DFU Nexus Mods: https://www.nexusmods.com/daggerfallunity
My github repositories with mostly DFU related stuff: https://github.com/BadLuckBurt

.

l3lessed
Posts: 1403
Joined: Mon Aug 12, 2019 4:32 pm
Contact:

Re: The Rotation Wars: Euler vs Quaternion

Post by l3lessed »

Raycast are straight, but they use a vector3 for their placement within the world. In order to create a swing arc, I decide the swing arc start spot and end spot, usually somewhere around 60 degrees on each side for about 120 degree arc. I then use a quaternion.lookatrotation to set the rotation to the forward look of the player camera; this ensures no matter the players camera rotation, it calculates the proper vector3 rotations; I had to learn this trick to stop quaternion rotates from bleeding and miscalculating at very specific look angles. At that point, I run it through a vector3 lerp, using start and end rotation spots, to rotate it through the arc based on attack time percentage, which is used to also calculate the current render frame and offset for smoothing of animation.

I don't think it should affect it, looking back at the code.
My Daggerfall Mod Github: l3lessed DFU Mod Github

My Beth Mods: l3lessed Nexus Page

Daggerfall Unity mods: Combat Overhaul Mod

Enjoy the free work I'm doing? Consider lending your support.

User avatar
BadLuckBurt
Posts: 948
Joined: Sun Nov 05, 2017 8:30 pm

Re: The Rotation Wars: Euler vs Quaternion

Post by BadLuckBurt »

l3lessed wrote: Fri Mar 18, 2022 4:15 pm Raycast are straight, but they use a vector3 for their placement within the world. In order to create a swing arc, I decide the swing arc start spot and end spot, usually somewhere around 60 degrees on each side for about 120 degree arc. I then use a quaternion.lookatrotation to set the rotation to the forward look of the player camera; this ensures no matter the players camera rotation, it calculates the proper vector3 rotations; I had to learn this trick to stop quaternion rotates from bleeding and miscalculating at very specific look angles. At that point, I run it through a vector3 lerp, using start and end rotation spots, to rotate it through the arc based on attack time percentage, which is used to also calculate the current render frame and offset for smoothing of animation.

I don't think it should affect it, looking back at the code.
Wait, I may have misunderstood your question. I thought you just meant in general but are you asking if my fix would affect raycasts? If so, it wouldn't. I'm not doing anything to the quaternions, it just has to do with the positioning and orientation of the 3-d models that make up dungeons and stuff.

Quaternions are confusing and sometimes unpredictable, I still don't want to know how they work, as long as they work.
DFU on UESP: https://en.uesp.net/w/index.php?title=T ... fall_Unity
DFU Nexus Mods: https://www.nexusmods.com/daggerfallunity
My github repositories with mostly DFU related stuff: https://github.com/BadLuckBurt

.

User avatar
BadLuckBurt
Posts: 948
Joined: Sun Nov 05, 2017 8:30 pm

Re: The Rotation Wars: Euler vs Quaternion

Post by BadLuckBurt »

Interkarma wrote: Tue Mar 15, 2022 10:16 pm Hey Burt. :) Thank you for the detailed write up. I'm happy with the fix you've presented, it's all clear and makes sense.

Send me a PR and I'll give it a whirl. If I don't find any problems, happy to merge into future builds. Cheers!
I'm preparing the PR at the moment and it kind of restarted the debate in my head whether I should change the 'dumpblock' console command or not.

I'm leaning towards not changing it and leaving it as is because we already have RMB replacements out in the wild (Hazelnut's mods have a couple and Cliffworms has also used a bunch already) and those all use the original rotation data. The CustomBlock boolean should default to FALSE when it's not explicitly set in the serialized data (I will test to make sure) so it shouldn't interfere with any old JSON dumps.

I've also gone ahead and dumped every model rotation from the RMB block subrecords (exterior and interior) and they are all rotated around their Y-axis and nothing else which confirms my earlier assumption that they are all rotated around 1 axis exclusively.

The CustomBlock property would still be set to true once this data is loaded into World Data Editor and saved from there since that overwrites the original rotation values.

I have some ideas to allow complete RMB block building to become a thing in World Data Editor in the future, at which point we will probably start seeing models being rotated around more than one axis within that data so the individual subrecord for a building that you can dump using dumpbuilding will probably need the CustomBlock boolean property as well.

I will investigate and make the changes I deem necessary, they can be discussed once I submit the PR but I'm just putting this out here in case someone already spots an issue with what I have in mind.
DFU on UESP: https://en.uesp.net/w/index.php?title=T ... fall_Unity
DFU Nexus Mods: https://www.nexusmods.com/daggerfallunity
My github repositories with mostly DFU related stuff: https://github.com/BadLuckBurt

.

Post Reply