vtkGLTFImporter loads textures upside down

It appears that when vtkGLTFImporter reads texture data (at least texture data stored in a buffer as opposed to an external image file), the textures are upside down.

I’ve created and attached a small glTF file. It includes two textures (jpg and png to confirm that it’s not specifically related to a particular mimetype). I’ve also included screen captures of various different renderers importing the glTF file.

image
Blender glTF import

image
three.js

image
vtkGLTFImporter

I’d like to emphasize, I’m making no claims about other image types, or images whose contents are defined in the glTF by URIs to external files. However, I’ve observed this flipped behavior uniformly across all of my embedded glTF files (usually with png as that’s what I use).
texture_arrows.zip (3.7 KB)

cc @mwestphal

Looks fine here (using GLTFImporter example):

Presumably, you’re running against the newest version of VTK? What are the odds that I’m tripping over something old? I’m currently pinned against 9.1. (Apologies for not broaching that before.)

I’am indeed using master but I doubt that this was fixed recently.

I’ll do some more probing around my end to figure out what’s going on. I’m certainly not manipulating anything particular. But off the top of my head, I can imagine that I’m exercising some extra VTK APIs over that example. I’ll come back around when I’ve done more probing.

1 Like

tl;dr vtkAssembly does not play nicely with the textures. So, less a bug in the importer and more a bug with vtkAssembly.

Full investigation
I’ve done some exploring. Starting with the example, I made some minimum modifications that reproduced the error I’m seeing. I then dug a bit further and found a single point of failure. It’s whether I gather the actors created by the importer under an assembly or not. I’ve attached the code below.

To run it (assuming you’ve done cmake .. and make):

./GLTFImporter <path_to_gltf>

In this invocation,
the actors are added directly to the renderer and the textures appear correct.

===========================================

./GLTFImporter <path_to_gltf> 2

In this invocation, the actors are collected under an assembly and the assembly is added to the renderer; the texture are upside down. (Note: any second parameter is enough, I’m simply keying on the number of parameters.)

Here’s my code:

#include <functional>
#include <vector>

#include <vtkActor.h>
#include <vtkAssembly.h>
#include <vtkCamera.h>
#include <vtkGLTFImporter.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkLight.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkProp3D.h>
#include <vtkSmartPointer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>

void _LoadGltf(const char *file_name,
               std::function<void(vtkActor *)> add_actor)
{
  vtkNew<vtkGLTFImporter> importer;
  importer->SetFileName(file_name);
  importer->Update();

  auto *renderer = importer->GetRenderer();
  if (renderer->VisibleActorCount() == 0)
  {
    std::cerr << "No visible meshes found in glTF file: " << file_name << "\n";
  }
  auto *actors = renderer->GetActors();
  actors->InitTraversal();
  while (vtkActor *source_actor = actors->GetNextActor())
  {
    add_actor(source_actor);
  }
}

void LoadGltfActors(const char *file_name, vtkRenderer *renderer)
{
  _LoadGltf(file_name, [renderer](vtkActor *actor)
            { renderer->AddActor(actor); });
}

void LoadGltfAssembly(const char *file_name, vtkRenderer *renderer)
{
  vtkNew<vtkAssembly> assembly;
  _LoadGltf(file_name, [&assembly](vtkActor *actor)
            { assembly->AddPart(actor); });
  renderer->AddActor(assembly);
}

int main(int argc, char* argv[])
{
  if (argc <= 1)
  {
    std::cout << "Usage: " << argv[0] << " <gltf file> e.g. FlightHelmet.gltf"
              << std::endl;
    return EXIT_FAILURE;
  }

  vtkNew<vtkNamedColors> colors;

  vtkColor3d backgroundColor = colors->GetColor3d("SlateGray");

  vtkNew<vtkRenderer> renderer;
  renderer->SetBackground(backgroundColor.GetData());
  renderer->UseHiddenLineRemovalOn();

  const bool use_assembly = argc > 2;
  if (use_assembly) {
    LoadGltfAssembly(argv[1], renderer.Get());
  } else {
    LoadGltfActors(argv[1], renderer.Get());
  }

  vtkNew<vtkRenderWindow> renderWindow;
  renderWindow->SetSize(640, 512);
  renderWindow->AddRenderer(renderer);
  renderWindow->SetWindowName("GLTFImporter");

  vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
  renderWindowInteractor->SetRenderWindow(renderWindow);
  vtkNew<vtkInteractorStyleTrackballCamera> style;
  renderWindowInteractor->SetInteractorStyle(style);

  vtkNew<vtkLight> headLight;
  headLight->SetLightTypeToHeadlight();
  headLight->SwitchOn();
  renderer->AddLight(headLight);

  renderWindow->Render();
  renderer->ResetCamera();
  renderer->GetActiveCamera()->Azimuth(20);
  renderer->GetActiveCamera()->Elevation(30);
  renderer->ResetCameraClippingRange();

  renderWindow->Render();
  renderWindowInteractor->Start();

  return EXIT_SUCCESS;
}

(BTW I ran this all against version 9.1.0.)

Sounds like a vtkAssembly issue more than anything related to the GLTF importer.

One could make that argument (and I did).

However, it’s worth noting that if the glTF importer actually brought in the structure of the glTF, instead of flattening it out, the bug in the vtkAssembly would’ve been resolved some time ago.

For the record, this definitely impacts this other issue. Using an assembly to handle the rotations is going to cause problems here.

So, for now, I’ll have to work around vtkAssembly, it appears.

1 Like