Bug in vtkGLTFExporter

tl;dr vtkGLTFExporter ignores vtkAssembly in its export operation. If I create an assembly with various parts (where each part’s pose is relative to the hierarchy) and pose the assembly root, exporting that to a gltf will not create an empty node for the assembly, and each of the parts are output without the root node’s transform contributing.

In the code for vtkGLTFExporter, there is a worrying line. It expresses the understanding that a node’s transform is the node’s pose in the world frame. Admittedly, depending on where you look in the Khronos documentation, it can be a big confusing. For example, the section on the node data doesn’t mention one way or the other. But the conceptual overview is clear that the transform for each node is a local transform with respect to its parent node.

So, in this case, one would expect the vtkAssembly should result in a node (without “mesh” and without “camera”), but with a transform and one or more children.

@danlipsa

FYI glTF exporter needs to invert the camera model view transform · Kitware/VTK@39fd8d7 · GitHub we fixed that for drake, that is only affecting the camera matrix, it is correct and as of that commit adheres to the standard. Previously, the inverted matrix was being exported, meaning you could not export from a view and then import to view it in the same location.

https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#view-matrix

The view matrix is derived from the global transform of the node containing the camera with the scaling ignored. If the node’s global transform is identity, the location of the camera is at the origin.

This has nothing to do with node transforms, only the camera arrays.

Edit: sorry, for clarity, to the best of my understanding, vtkMatrix4x4* mat = ren->GetActiveCamera()->GetModelViewTransformMatrix(); is going to give us the properly transformed matrix in the event that there is a camera that is a child of something. But the only matrix that was getting inverted there was for the camera, it should not be affecting the other items in the scene being exported.

While I haven’t confirmed this yet, it’s worth noting this will probably also impact glTF importing as well. If I have a hierarchy rooted at an empty node with a non-identity transform, the other nodes will probably not have the correct pose w.r.t. the file’s frame.

And, by induction, any hierarchy with greater depth, such that the world transform of the parent node is not the identity, would suffer from having the wrong pose in the file frame. I’ll run some tests today and get back with some more concrete results.

Do you have such an file on hand to share ?

I just did a quick test on a glTF file that had the following hierarchy:

 empty
    |_ mesh 1
         |_ mesh 2
             |_ mesh 3

All nodes had non-identity transforms. If my hypothesis about import problems had been true, I would’ve expected all the pieces to be misaligned (as each of their poses depended on the concatenation of the full tree), but it presents itself correctly. Happy to be wrong.

If you want to explore yourself, I’ve got the glTF - a small pyramid that when imported correctly should be sitting on the world’s xy-plane, centered on the origin (as shown in the image).

image

Unfortunately, I’m classified as a “new user” and can’t attach the zipped up .glTF. Is there a good place to upload to?

you can share now :slight_smile:

Excellent. Enjoy.

rwb_pyramid.gltf.zip (1.5 KB)

VTK imports it on the XZ plane, I assume this is not expected ?

TBF 3dviewer shows the same behavior https://3dviewer.net/

Oh, sorry. That is correct. glTF is uses a y-up coordinate system. The domains I work routinely play in (Blender, Drake) live in a z-up world. So, this y-up is an honest and accurate result based strictly on the file contents. I’d addressed the rotation to z-up so long ago, I just take it for granted.

And speaking of taking it for granted, the importer and exporter would benefit from a configuration indicating whether things need to be rotated. Given glTF is definitely documented to be y-up, I suppose it would be enough if the caller could report what world the caller lives in and then VTK could perform any rotations necessary to get it into a y-up world as it goes.

If that information is contained in the file, VTK should respect it (and there may be a bug). If not, then VTK should open the file as it is and the user can perform any transformation of the data.

The problem with that becomes one of exporting.

If I construct a scene in a z-up world, then the only way I can write it to a compliant glTF file is to rotate it all, export, and then rotate it back.

And as far as importing, I may be using the importer wrong, but since it dumps things straight into a renderer, it’s problematic to go through and find all the bits that need rotating. Although, to be frank, that’s what I’m currently doing. And it’s a bit problematic, because I don’t get one actor per node in the scene (i.e., I lose the empty root node). But that might be attributable to errors on my part in understanding the “right” way to do that.

That may very well be true, but I don’t know much about the exporter, I’m afraid.

While this issue is predominantly about the exporter ignoring assemblies, if you’re an importer expert, I’d love to take any pointers you have to offer about importing (achieving the rotation). Shall I open another question and post my current code for critique? If there’s a better way to achieve what I’m doing, I’d happily take it.

Yes, please, open another thread.

BTW I’m not sure if I got the glyphs right, but the issue for the importer is: here.