Permanently change set of axes

No, it is not a bug in paraview (the other software), which is right handed and doesn’t modify the input at all. I have checked and the visualizzation is consistent between three.js and paraview.

My two cents: I think the issue is that the concept of handedness and “y up” / “z up” are mixed here when they are separate.

  1. loaders should take care of handedness because it affects operations. To do so, if Babylon uses the default left-handed system, they need only to change sign to z and transform so that points are invariant and objects maintain the same coordinates of bounding box vertices. If the latter isn’t done, there is an inconsistency with the input file and one has to constantly code around it in cases when the file is used again for other purposes.
    If Babylon is set to use a right-handed system, nothing should be done.

  2. there is no reason to go from z up to y up. This may be convenient, but it introduces an inconsistency with the input file. I think it should be left to the user to export with the desired vertical axis.

Your first picture from paraview shows Y-up,
STL data is expected to be Z-up, (this is not something a user desides, this is the STL format)

If we don’t follow the predefined formats when it comes to files import/export and everyone just does as they like, it would be chaos. :slight_smile:

If paraview and threejs are right-handed with Y-up and doesn’t convert from Z-up to Y-up, they are displaying the file wrongly, (mesh is standing up, not laying down).

If you load the file in a right handed Z-up environment, such as blender, you should see the mesh correctly laying down as it does in babylon.

Babylon is lacking the Z invert when left handed.
So actually displays the file correctly when scene.useRightHandedSystem = true.
And wrongly when scene.useRightHandedSystem = false.

Z invert (when left handed) would flip the mesh so it faces the opposite direction along the Z axis.

This would result in a consistent view between babylon left handed / right handed & display the exact same result as the blender example.
(*when cameras are in same position & facing same direction in both softwares)

I hope i explained it well enough, it is a lot to digest.

To break it down a bit.

Handedness(z / depth axis invert) determines the direction of the depth axis compared to the other two axes.
if we look past that.

We have three axes,
Vertical (up/down)
Horizontal (left/right)
Depth (forward/backward)

X - Horizontal
Y - Vertical
Z - Depth

X - Horizontal
Y - Depth
Z - Vertical

If we do not swap the Vertical and Depth axes from STL to Babylon,
the mesh will not be rendered correctly and cause inconsistencies such as in your screenshots.

I double checked threejs stl loader, and it is threejs and paraview that fails to swap these axes.
they use the STL depth axis for their vertical axis
and STL vertical axis for their depth axis.

The issue here isn’t understanding handedness and frame of references. It is how the input is modified to do the conversion.

Your first picture from paraview shows Y-up,
STL data is expected to be Z-up, (this is not something a user desides, this is the STL format)

The first figure only shows parallel axes to what babylon shows when loading the file. Importing the file in SolidWorks shows same as paraview and any other CAD:

And blender shows this:

The original file is here, for reference: (3.3 MB)

The bounding box is:

-439.811 < x < 445.505
-868.947 < y < 1532.24
-311.974 < z < 683.935

so both paraview and solidworks respect it, while babylon.js does not.

From the mathematical perspective, going from left to right-handed is the only step needed. How it is done depends on the goal (do you want to maintain chirality of the original frame of reference or not). The change in coordinate done by babylon is arbitrary and violates the content of the input file.

Blender screenshot shows exactly as babylon renders it.
you took the screenshot from top-down,
the whale is lying down along the depth axis (y in blender)
as it does in babylon (z in babylon)

maybe we are “talking past” each other,
Babylon imports, converts and renders the mesh as it is supposed to be rendered.
for visual consistency.

if you create a mesh in blender,
export to STL and import in Babylon,
it will look exactly the same and have the same orientation.
only the axes are named differently.

if you do the same, but import it in say, threejs, the mesh’s orientation will be changed and as your screenshots, suddenly the whale is standing on it’s nose and looking down along the vertical axis.

I don’t see how it is visually consistent with the file of coordinates are swapped, which leads to renaming the axes. In Babylon you see the tail at max z and the face at min z, opposite to what is in the file… I understand it is done for convenience, but it is an unwanted scene transformation imho.

Anyway, I don’t think we’ll find an agreement on this, also looking at other posts on the and topic and their conclusions. Hopefully in the future Babylon will move to a more common default (right handed) and stop changing inputs.

Handedness is not the issue here, handedness just changes the direction of the depth axis when compared to the other two axes.

you want
x === x,
y === y,
z === z,
but from stl to babylon, y & z are not used for the same axis.
in stl and blender Z is the up axis, in babylon Y is the up axis…

It is visually consistent to swap these two axes on import, so the mesh is still rendered the same when compared to the actual horizontal, vertical & depth of the scene.

as i mentioned before, the other softwares are actually importing the mesh so it is facing downwards along the vertical axis, but both blender and babylon shows it correctly facing along the depth axis, despite being differently named.

I think you’re right, we won’t agree :slight_smile:

Let’s start over once more, because I think there is some confusion (we need a blackboard! :rofl:)

Note: the STL standard does not say anything about the “world” frame of reference. It only specifies the ordering of the vertices to define the unit normal vector to the facet ( STL (file format) - Wikipedia ) So, any frame defined by an orthonormal basis and is right-handed works, in principle.
There is no concept of a specific coordinate being “up” in the file format, as long as the frame of reference used to define normals is right-handed. Consequently, swapping coordinates seems unexpected.

Now let’s take a look at what babylon.js does with the STL file I attached above.

That file has a bounding box as follows, extracted parsing the STL:

-439 <= x <= 445
-868 <= y <= 1532
-311 <= z <= 683

Let’s see what babylon.js does.

Default settings: left-handed system

The STL loader, swaps y and z, so we get:

-439 <= x <= 445
-311 <= y <= 683
-868 <= z <= 1532

Now, as a user, I read this and try to apply it to the STL file externally to babylon.js, and find out it is incorrect.

Modified settings: right-handed system

Let’s repeat the experiment done above with the setting

scene.useRightHandedSystem = true;

The bounding box found by babylon.js is now:

-439 <= x <= 445
-311 <= y <= 683
-868 <= z <= 1532

the same as in the left-handed system, again unexpected

So to the very least, if you continue swapping coordinates, at least the frame of reference should be consistent: if a left-handed system is used, z needs to be changed in sign (the clean way to switch from z-up right-handed to y-up left-handed is a rotation of 90 around x followed by negating z).

On top of that, to me, aside from agreeing on what coordinate is up and down (it does not matter), the concern is that if I import a file, I expect to read coordinates that are consistent with the file I import because I may need to use those outside of the viewer. This has really nothing to do with the convention used for the frame of reference, which is an arbitrary choice, not specified in the input STL, but with the consistency between what information is provided (STL) and what is done by the code.

The same applies to OBJ: they specify handedness, not “up” direction ( Wavefront .obj file - Wikipedia ).

Well, first off, babylon is a rendering engine.
it’s job and primary goal is to render meshes as they are supposed to look, within the world space. :slight_smile:

While i understand where you’re coming from, you want the numbers to be the same and not swapped around or changed.

When you load a mesh into babylon, it should look exactly the same whether it was loaded from format A or format B, the format is just a method of storage, you shouldn’t have to rotate or transform a mesh post-load depending if you use .stl, .obj, .gltf or .babylon, etc. it has to visually display the same result.

As for the STL format, it is very simple, and very old, back when most coordinate systems used Z-up,
to this day most CAD and mesh creation programs, etc, continue to use Z-up.
Infact, the common definition of both left and right handed use Z-up as the example.
I believe this is the reasoning? It was z-up when it was created, it should continue to be so imo.
(right-hand rule)

I’m fairly sure (correct me if wrong) Y-up came much later (or atleast became more common) with webgl and JS developers wanting to stick with the familiar html/css coordinates where Y is the vertical axis and z is used for depth.

OK, let’s agree to disagree on changing inputs to fit an arbitrarily chosen “up” direction.

I guess a question remains: do we agree the behavior babylon.js has when reading an STL using a right-handed system is incorrect (it is exactly the same behavior it has when it uses a left-handed system…)?

I think so, we should not invert Y/Z if the scene is right-handed. Note that the stl serializer should also be updated as it is currently inverting Y/Z back unconditionnally.

At the risk of stirring the pot further. I’m confused by the inconsistent behavior of the gltf and stl imports. I would expect a gltf and an stl from the same source to create the same mesh. Is this not the desired behavior?

I created this playground to highlight the issue:

When viewing this playground, the two things that stick out to me are that:

  • The gltf loader does not change the axes handedness when “useRightHandedSystem” is changed, while the stl does change.
  • The stl loader does not load as expected with either right or left handed coordinates. (although from the discussion above, this seems to be subjective)

To make the stl behavior match gltf loader:

  1. unswap Y/Z
  2. negate X if “useRightHandedSystem=false” (or rotate 180 about Y and negate Z)

I would agree that is the solution, but after the discussion above I abandoned the idea of submitting a patch because I’m not sure about what would be acceptable, since any change would break the current behavior. Also, handedness seems managed with different logic in different loaders.

I don’t think it is subjective but there certainly is confusion between what changing the frame of reference from right handed to left handed implies, and the y-up convention. The latter is a choice and I don’t think the code should enforce it at all, or we end up constantly coding around it to avoid inconsistency between output of the library and data on the file. However there is disagreement about this because some think the “up” direction is prescribed.

In the end, the long term solution would be to default to a right-handed system and let the positive vertical direction be whatever the creator of the file decided. Rotating objects to fit a scene is a lot easier than reverting unexpected transformations, in my opinion. See what three.js does: much cleaner.

Perhaps a “stirct” flag could be added, or a “SceneLoader.StrictImport()”, that disables all additional manipulation for all loaders so that x=x, y=y, z=z. This would not break the current functionality, but would satisfy those of us who want our meshes “left alone”.

My experience aligns with Alberto, in that stl does not have an “up”. The mesh world is already chaos :slight_smile: Just look at all the import and export options blender has for stl. In practice, there is no standard :frowning:

That option would be nice.

The STL standard is there, and quite lax (it only prescribes to check normals are compatible with vertex ordering).
We probably should take a look at all loaders (is obj behaving as expected?) and try to find an agreement on how to proceed, so we can propose a patch and review it (as much as I know the math, I’m not that deep with Babylon.js structure and coding standards).