I have a question about changing the convention used for the frame of references. The default in babylon.js is to use a XZY, where Y is the vector product of X and Z. However, many CADs default to XYZ. Is there an option to globally change this in babylon.js without acting on each individual mesh?
I don’t know if it’s what you need but you can switch to a right handed coordinate system by setting scene.useRightHandedSystem = true;
just after scene creation.
Thank you. That helps, but there still seems to be an issue or I may be missing something. To give you a bit more context, I am loading STL models, and when I visualize them in another software, I see this
However, when I load in babylon, I see this:
so it seems axes coordinates are exchanged (Y in the correct picture has become Z in the other), even if the frame of reference should be the same (XYZ, right-handed, with third axis being Z) in both of them, after setting scene.useRightHandedSystem = true.
It seems your camera is not at the same place in both screenshots? There’s no camera data in a .stl file, so a default one is created by both softwares if you don’t create one yourself.
The camera is in different locations (the first software is paraview), but why would that lead to have axes swapped? The body of the whale is along y in the first figure, while it is along z in the second, which is what is confusing me.
The body seems to be in the Y direction in the Babylon screenshot(?)
However, that’s a bit hard to see what’s going on as it is full red in the screenshot…
A repro in the Playground would help for sure.
I’ll try to make a repro on the playground.
The Y axis should enter the face of the whale, in babylon the Z axes does. That is what I meant with “body along Z”.
I wasn’t able to upload the STL to the playground so I only have the camera setup Camera | Babylon.js Playground (babylonjs-playground.com)
I added a bounding box and AxesViewer to help visualize the issue. So, in paraview, which shows the geometry in the correct frame of referece, this is the configuration:
The same file imported in babylon.js is visualized this way (x is red, y is green and z is blue, aligned as in paraview):
What is unclear to me is what is causing that coordinates are interpreted differently, even though the axes appear oriented in the same way.
I think it’s because Babylon is left handed and STL data are right handed.
In STL loader there is this:
positions[offset] = reader.getFloat32(vertexstart, true);
positions[offset + 2] = reader.getFloat32(vertexstart + 4, true);
positions[offset + 1] = reader.getFloat32(vertexstart + 8, true);
So Y and Z are inverted at loading time.
What you can do to get the same result than in paraview is to apply a rotation and bakes the result in the vertices (mesh.bakeCurrentTransformIntoVertices()
).
Thank you. I’ll work on the rotation.
However, I am not sure if this is just an issue with the left-handed or right-handed frame of reference. If that’s the case, I would expect Z in a right-handed system to become -Z in the left-handed system, but X and Y should be unchanged, and there should be no rotation. Could this be considered a bug?
Related github issue: Exporting from Blender: Y and Z axes are flipped · Issue #31 · BabylonJS/Babylon.js (github.com)
I have implemented this workaround in the loader to restore the original content of the STL file:
let positions: BABYLON.FloatArray = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
mesh.setVerticesData(BABYLON.VertexBuffer.PositionKind, positions, true);
let numberOfVertices: number = positions.length / 3;
for (var i = 0; i < numberOfVertices; i++) {
let currentY : number = positions[i * 3 + 1];
let currentZ : number = positions[i * 3 + 2];
positions[i * 3 + 1] = currentZ;
positions[i * 3 + 2] = currentY;
}
mesh.updateVerticesData(BABYLON.VertexBuffer.PositionKind, positions);
mesh.bakeCurrentTransformIntoVertices();
This works and the correct bounding box shown in paraview is calculated by babylon too after the transformation. However, I still believe this is a bug: the loader should not modify the input. Please, let me know if I should report it.
Adding @Deltakosh as I’m not sure what to do here.
@AlbertoPa wanna try a PR to see how we could fix it?
Hi @Deltakosh
I will give it a try, but I need to take a better look at the code of the loader to avoid undesired side effects.
One concern: are Y and Z swapped in other loaders too? I have only worked with the STL loader so far.
The GLTF loader is doing a 180° rotation on Y + negate Z to handle handedness and the .obj loader is doing nothing it seems, the coordinates must already be left handed in the file (?).
I would say the issue is that loaders are not aware of the selected handedness. If I set
this.scene.useRightHandedSystem = true;
the frame of reference changes, but the loader keeps transforming the input. In the case of STL, which assume right-handedness ( STL (file format) - Wikipedia, the free encyclopedia (brandeis.edu) ), this leads to the issue. I would say the solution could be to make loaders aware of the handedness of the system, where needed. What do you think?
Side note: the change I made in my previous post is incomplete. It does not correct normals.
Yes, the stl/obj loaders should probably take into account the current handedness like the gltf loader does.
Looking at this PR related to .obj export, it seems the import should negate the Z axis if the current scene is left handed… However, it is a breaking change, so I don’t know how to handle it, except if we consider it to be a bug.
I agree with changing the sign of z when going from a right-handed to a left-handed frame of reference.
However, the doubt I have is this: do we want to change the frame of reference to left-handed but keep consistency with the loaded file? In other words, should point P(x, y, z) in the loaded file remain P(x, y, z) in the left-handed system, so also the vertices of bounding box remain the same? This seems important to me, if someone uses a GL canvas to visualize geometries and then some other part of the code (outside of babylon.js) will interact with the original file directly.
Adding @Drigax who is more knowledgeable than me regarding importers and loaders.
The lack of a common standard when it comes to coordinate systems can be frustrating sometimes…
right handed, left handed, and then both versions exist with either z or y up, etc
STL should be right-handed with Z up as far as i can see,
so i believe the STL loader and exporter both need to be updated to swap z & y axes ( & negate the z if !scene.useRightHandedSystem ) ?
Edit;
Sorry, saw the loader already inverts z & y… didn’t notise the ordering before
positions[offset] = reader.getFloat32(vertexstart, true);
positions[offset + 2] = reader.getFloat32(vertexstart + 4, true);
positions[offset + 1] = reader.getFloat32(vertexstart + 8, true);
so it should be fine in that regard… possibly a bug in the “other software” ?
only thing not accounted for in babylon is inverted Z axis, but that can’t make that rotation happen…