Open hamza-hajji opened 1 week ago
Hello @hamza-hajji,
first thing to remember is that Xeokit has a different coordinate system than the one in this website presented.
IMO in Xeokit it's like this (green one):
second thing to remember is that Euler angle itself doesn't specify the order in which you should rotate. On this website they rotate in order ZYX, but respectively to their coordinate system.
I'd advise to check the rotations e.g. in Blender where you can specify the order of rotations for Euler angles. Here is some tutorial there that explains the differences: https://www.youtube.com/watch?v=mcDHDfK2pXs
This way you can make sure if everything looks ok.
Also please check this example, click on the question mark at the top right and manipulate rotations by sliders to see how it works in Xeokit: https://xeokit.github.io/xeokit-sdk/examples/lidar/#xkt_MAP_alignPointCloud
@paireks thanks for your response, it seems in the rotation setter, you use an XYZ order when setting the quaternion
// Mesh.js
set rotation(value) {
this._rotation.set(value || [0, 0, 0]);
math.eulerToQuaternion(this._rotation, "XYZ", this._quaternion);
this._setLocalMatrixDirty();
this._setAABBDirty();
this.glRedraw();
this.fire("rotation", this._rotation);
}
Is it possible to override the XYZ order in this code (either by doing computation on my side or throught modifying the library)? Do the rotation angles care about the order you pass to quaternion setter or it's just in xeokit that you do only one order?
Thanks for taking the time to respond 🙏
Hi @hamza-hajji , there's an alternative way to control a Mesh
's rotation through the Mesh::quaternion
setter, as defined at
https://github.com/xeokit/xeokit-sdk/blob/master/src/viewer/scene/mesh/Mesh.js#L481-L494
This way you can transform a local euler angle with a local order to a quaternion, and have it assigned to the Mesh
, e.g.:
model.quaternion = math.eulerToQuaternion([30, 90, 0], "ZYX");
Hope this helps!
@MichalDybizbanskiCreoox won't this line override my quaternion value?
https://github.com/xeokit/xeokit-sdk/blob/master/src/viewer/scene/mesh/Mesh.js#L490
math.quaternionToEuler(this._quaternion, "XYZ", this._rotation);
@hamza-hajji
Both Mesh::quaternion
and Mesh::rotation
setters modify "private" Mesh::_quaternion
and Mesh::_rotation
properties, which are kept in sync.
The difference is a type of an input value either of the setters take.
@MichalDybizbanskiCreoox excuse me but if I do
model.quaternion = math.eulerToQuaternion([30, 90, 0], "ZYX");
the quaternion setter will override the rotation value with a XYZ rotation based on my quaternion, so they will be out of sync, no?
math.quaternionToEuler(this._quaternion, "XYZ", this._rotation);
since math.quaternionToEuler()
does set this._rotation
@hamza-hajji right, if that's what you mean then it's correct - Mesh::rotation
's value, which is defined in the "XYZ" order, might not be the same as your math.eulerToQuaternion
's argument if applied with the "ZYX" order.
If you wanted to get an arbitrarily ordered euler angle value from a Mesh
, you could use a symmetrical call:
const euler = math.quaternionToEuler(model.quaternion, "ZYX");
Please keep in mind however, that euler
value might not be what was initially used as the math.eulerToQuaternion
argument, because
quaternionToEuler(eulerToQuaternion(E, O), O)
does not necessarily equal E
.
@hamza-hajji right, if that's what you mean then it's correct -
Mesh::rotation
's value, which is defined in the "XYZ" order, might not be the same as yourmath.eulerToQuaternion
's argument if applied with the "ZYX" order.If you wanted to get an arbitrarily ordered euler angle value from a
Mesh
, you could use a symmetrical call:const euler = math.quaternionToEuler(model.quaternion, "ZYX");
Please keep in mind however, that
euler
value might not be what was initially used as themath.eulerToQuaternion
argument, becausequaternionToEuler(eulerToQuaternion(E, O), O)
does not necessarily equalE
.
@MichalDybizbanskiCreoox wouldn't it be simpler if instead of hardcofding the XYZ, there's a Mesh#eulerOrder that I can set like
model.eulerOrder = "ZYX";
model.quaternion = [x, y, z, w];
and in the rotation and quaternion setters you just use this.eulerOrder || "XYZ"
The thing is, once both Euler and Quaternion setters are exposed in the object's interface, you can no longer rely on the Euler angle returned by the getter to be identical with the one provided to the setter.
Consider the code where E
is an euler angle vector:
model.rotation = E;
model.quaternion = model.quaternion;
Now, even though logically the model's effective rotation didn't change, its rotation
property (as provided by the getter) will likely be different than E
.
In fact any quaternion
property assignment necessarily modifies the rotation
property, so the rotation
should only be considered as an effective value, i.e. as an angle that will have a specific effect on an object, regardless of its particular value (as in - there can be many different Euler angles that lead to the same object's rotation).
Truth be told - quaternion
property could be the only one exposed as an interface to set object's "rotation".
The rotation
property should be considered kinda as a convenience shortcut, in that is saves user a single math.eulerToQuaternion
call, but not as a value store, which would likely be lossy even if we added the eulerOrder
property (e.g. due to a limited floating-point precision if the values were obtained from some kind of a text-based interface).
If your viewer controls all places the object's rotation is being changed, you could "store" the input rotation value in some kind of and external object->rotation mapping, or as a custom property of the object being affected.
Describe the bug
Changing rotation coordinates does not work as expected, this visualization describes how euler angles work
https://danceswithcode.net/engineeringnotes/rotations_in_3d/demo3D/rotations_in_3d_tool.html
If I try the same thing in xeokit, I get very different results
To Reproduce Steps to reproduce the behavior:
Notice how the x and y rotations are always local to the object's axes
Expected behavior
I expect the rotation to work like this visualization of euler angles (yaw being y axis, x being pitch)
I'm not sure how xeokit calculates rotation, if anyone can provide me with a way to make the object's rotation global instead of local that would be appreciated
Thank you