Open amplified1 opened 9 months ago
Gimbal lock is not a problem with quaternion-based rotation, and quaternions are the internal implementation of many 3D software for rotation. If you are attempting to avoid gimbal lock, probably the best bet is to not shift the problem.
Could you give a specific example where you are running into an issue?
I think you have misunderstood, have you ever tried to rotate something on the X-axis by 90 degrees using euler inputs? The game tries to automatically adapt but it can't be done normally, which can sometimes suck when you are directly driving rotations using euler with flux. The idea is giving more options for euler rotations in flux, and I reiterate, this is a pretty standard feature, it's present in blender, godot, etc. Quaternions don't have gimbal lock but people don't usually edit quaternion values directly because they are unintuitive, they use the rotation nodes to use another method that maps onto quaternions, one of those options is euler, and the current implementation of euler is incomplete when compared to other 3d software
Thanks for the elaboration @amplified1 , could you link to the documentation for GoDot or Blender regarding this added capability for that operation?
Blender Documentation on rotation modes. An example of a blender transform constraint that allows the changing of this setting in its operation Godot Node3D documentation, contains eulerOrder property The specific documentation on the eulerOrder input in godot
These were just the quickest ones I could find, I don't know if there is anything more technical that would be helpful for implementation. Screenshot of blender UI: Screenshot of Godot UI:
While these specific examples are more focused on their use in these program's respective scene inspectors these properties in these programs extend to the functionality of their scripting APIs, Blender's Python driver support, and Godot's GDscript/C#/C++ scripting, respectively. Having an option for this in the inspector would also be good, but it would be really helpful to have it represented in flux specifically.
Godot's documentation explicitly warns never to use Euler angles when programming and that the displayed rotation in the editor and their orders are purely for simple rotations in the editor only. Similarly in Blender, when you perform a rotation using the rotate command, it is converting that user provided Euler rotation in its current orientation into a quaternion and then applying a post rotation multiply on its current one. The only practical use in either of these programs for the changed order is for ease of the end user to specify which order to apply in a setting where they can't apply it to a current rotation directly.
I agree the rotation order should probably be included in the inspector, but not relied on in any capacity when programming.
By far the easiest and most user-friendly way to do this is to just simply specify one axis and a rotation to apply on that axis using the Axis Angle
node, analogous to the rotate
method in Godot.
In this case we choose the X axis: $<1,0,0>$, and the rotation $90$ degrees and it produces our corresponding rotation.
If you plug this into the box's rotation, it will be oriented how you expect.
In flux, just as in Godot, you can construct a basis orientation and turn this into a rotation using the DecomposedRotation
node. A basis is just a fancy way of saying "which axes point where". It is represented by a 3x3 matrix, each row corresponding to the direction that the X,Y,Z axes will be oriented in. Their magnitude corresponds to the scale, but that isn't relevant for rotations.
Here is the starting orientation of the box with the axes shown:
The starting basis is just each axis is oriented along its original axis so:
Right
Up
Forward
This corresponds to the following 3x3 matrix:
$$ \begin{bmatrix} 1 & 0 & 0 \ 0 & 1 & 0 \ 0 & 0 & 1 \end{bmatrix} $$
Imagine what the axes will look like after rotating the box 90 degrees on the X axis, noting which axis is Right
, Up
, and which is Forward
.
The new basis will have the following properties as observed in the image above:
This results in a basis matrix of:
$$ \begin{bmatrix} 1 & 0 & 0 \ 0 & 0 & -1 \ 0 & 1 & 0 \end{bmatrix} $$
You can plug this matrix into the DecomposedRotation
node to get a corresponding rotation for this orientation.
floatQ
inputA floatQ
even though it takes inputs as Euler angles, is really a quaternion. You never have to modify the quaternion values directly. If you want to rotate 90 degrees on the X axis, you input $<90,0,0>$.
In all of these solutions you get a nasty looking quaternion, but I would advise absolutely ignoring the values it shows in its quaternion representation. What matters most is that you are able to construct these in multiple user-oriented ways.
Don't you have to learn everything about quaternion math to know how to use them? I would argue not. There are only 2 operations practically you should know: Multiplication, and Inverse.
Let's say your cube is currently rotated some random weird initial amount $A$:
and you want to rotate it $90$ degrees on its local X axis.
First construct the 90 degree X axis rotation using any of the 3 methods above, let's call the result $B$. Now just multiply $A B$.
If you want to smoothly go from its current orientation to the final rotation, you can use the Slerp
node:
If you want to Undo a rotation, you take the rotation's inverse. Order of quaternion multiplication matters, so when you want to undo the rotation $B$ above, you would multiply the inverse $B^{-1}$ after $B$ was applied. The full operation $A B B^{-1}$ results in just $A$ since the rotation and its inverse cancel out. The most important thing to remember is that they only cancel out though when touching. A more complex example would be if you applied more rotations:
$$ A B C D $$
Let's say you want to go back to B, but you don't know what it was. You can perform the operation:
$$ A^{-1} A B C D D^{-1} C^{-1} $$
which cancels out to $B$. Step by step:
$$ \begin{gather} (A^{-1} A) B C D D^{-1} C^{-1} \ B C (D D^{-1}) C^{-1} \ B (C C^{-1}) \ B \end{gather} $$
You can already apply rotations in any arbitrary order you like by using the Axis Angle
method described above, and multiplying them in whichever order you want.
For example, if you want to perform ZYX order:
If you wanted a one node solution for this I would understand that as a request, but it would not allow arbitrary axes.
All of this is to say, I highly recommend against use Euler rotations while programming except in very specific circumstances, as do other game engines.
The inspector probably would benefit from axis order, or preferably even just a way to apply a rotation to a current rotation.
I use axis angles a lot when dealing with rotations in flux, but I do still think this should be a one node option, and also eventually included in the inspector (though from what I understand a full inspector rework is needed before the team adds too much to it), if not just for the sake of parity with other 3D programs.
For the sake of the inspector specifically I think this would be a nice option because rotating things 90 degrees on the X-axis is actually a very common operation, as it is the most straightforward way to make planar objects like the default plane, circle mesh, etc, face upwards towards the Y axis, since in the unity engine planar objects are traditionally oriented on a vertical plane facing the Z axis, while it's often more useful for these objects to be facing the Y axis in a 3D environment. The euler inputs in the inspector can be confusing as the lossy process of mapping between a quaternion and euler can be very inconsistent feeling from the end user perspective.
Anyways, this is just something I want to see considered, maybe in the inspector rework when that happens.
It should be possible to build a custom piece of UI for the inspector that allows you to enter a difference instead of modifying the existing rotation. So when a cube has the rotation (0, 129.53, 13.42) you can press a button to show a field with (0, 0, 0) and a "Confirm" button. When you enter (0, 90, 0) into that field and press confirm, the cube is rotated by 90 degrees on Y and the field is reset to default. And since you can "stack" multiple rotations temporally instead of having to mess with the entire Euler field at the same time, there is no confusing back-and-forth mapping. This could also feature a transform space selector, with a selection of "Local", "Parent", "World" and "Custom" (the latter showing a slot input field)
Is your feature request related to a problem? Please describe.
Gimbal lock is a near unavoidable issue, but it can be circumvented in many ways, one way I have seen used by a couple programs is allowing the user to change the order euler rotations are applied to move the locking to a different axis.
Describe the solution you'd like
Add an enum input to the euler angles and from euler flux nodes that allows the selection of an axis order for the node to use when converting between quaternions and euler.
Describe alternatives you've considered
There are many different ways of rotating things with flux, but they all have their quirks, more options would be helpful.
Additional Context
An example of this kind of feature implemented is Blender, where you can change the axis order of rotation constraints and rotation inputs through a dropdown.