VTK 8.9 - Many (Multi) View Camera Capture Methods?

I’m currently working on integrating stereoscopic displays with some software developed using VTK (built heavily off of ParaView and in Qt, as well). I’m pretty new to graphics programming, so I may be missing some obvious details.

I’m having issues with getting the images to actually render when I change camera position. I think this is because my code relies on the images rendering instantaneously, but the rendering is delegated for when the process becomes idle. As such, when I collect my images, they are all the same image since no rendering has occurred yet.

It seems older versions of VTK had vtkMapper::SetGlobalImmediateModeRendering(), which sounds like what I’m looking for. Is there anything similar to use now? Is this a ParaView/Qt Issue and I’m on the wrong track? It is also worth knowing that I’m collecting any where between 30-45 images depending on user desire.

Potential Workarounds I’m looking through

  • Generate an animation path and then save an animation of my .pngs, which I can then read in.
  • Have multiple renderers (cameras), and then have each yield image data. I worry about this one since that would entail a large amount of renderers being created for the scene.
  • Use ParaView’s Simple python module to collect screenshots (which worked in past testing) and then read these .pngs in. I’d rather solve the C++ API issue, though

My code for reference
vtkImageData* ViewHoloDisplay::beginCollectingViews()
{
cout << “Beginning to Collect Views\n”;
cout << “Creating totalAppender\n”;
totalAppender = vtkSmartPointer::New();
totalAppender->SetAppendAxis(1);
cout << “Beginning for loops\n”;
int v_index = 0;
cout << qs_rows << " " << qs_columns << “\n”;

        // Collection Loop
        for(int currRow = 0; currRow < qs_rows; currRow++)
        {
          vtkSmartPointer<vtkImageAppend> currAppender = imgAppenders[currRow];
          currAppender->SetAppendAxis(0);
          for(int currColumn = 0; currColumn < qs_columns; currColumn++)
          {
            this->setViewIndex(v_index); // Move camera along view plane



            activeWindow->Render();
            activeRenderer->GetRenderWindow()->Render();
            cout << "Phi: " << cameraPhi_active <<"\n";
            //activeWindow->WaitForCompletion(); DOES NOT WORK

            vtkSmartPointer<vtkWindowToImageFilter> liveWin = vtkSmartPointer<vtkWindowToImageFilter>::New();
            liveWin->SetInput(activeWindow);
            liveWin->Modified();
            liveWin->Update();
            vtkImageData* currImg = winToImg->GetOutput();

            if(currAppender->GetNumberOfInputs() == qs_columns)
            {
              currAppender->ReplaceNthInputConnection(currColumn,liveWin->GetOutputPort());
              currAppender->Update();
            }
            else
            {
              currAppender->AddInputConnection(liveWin->GetOutputPort());
              currAppender->Update();
            }
            // Frame Output check
            std::stringstream outName;
            outName<<v_index<<".png";
            std::string str = outName.str();
            const char* outChar = str.c_str();
            vtkSmartPointer<vtkPNGWriter> myWriter = vtkSmartPointer<vtkPNGWriter>::New();
            myWriter->SetFileName(outChar);
            myWriter->SetInputData(liveWin->GetOutput());
            myWriter->Write();
            v_index++;
          } // currCol for

          // RowCheck for 1 row
          if(currRow == 0)
          {
            vtkSmartPointer<vtkPNGWriter> myWriter = vtkSmartPointer<vtkPNGWriter>::New();
            myWriter->SetFileName("RowCheck.png");
            myWriter->SetInputData(currAppender->GetOutput());
            myWriter->Write();
          }
          if(totalAppender->GetNumberOfInputs() == qs_rows)
          {
            totalAppender->ReplaceNthInputConnection(currRow,currAppender->GetOutputPort());
            totalAppender->Update();
          }
          else
          {
            totalAppender->AddInputConnection(currAppender->GetOutputPort()); //Builds first row
            totalAppender->Update();
          }
          }// currRow for

        this->setViewIndex(v_index);
        vtkSmartPointer<vtkPNGWriter> myWriter = vtkSmartPointer<vtkPNGWriter>::New();
        myWriter->SetFileName("QuiltCheck.png");
        myWriter->SetInputData(totalAppender->GetOutput());
        myWriter->Write();
        return totalAppender->GetOutput();

      }

I’m trying to figure out the code formatting here, sorry!

A simple solution is to use a rendering-request mechanism, as implemented in CTK’s render window - used in applications such as 3D Slicer and MITK. In 3D Slicer we use this for real-time rendering stereo virtual reality display and it works fine.

renderWindow->Render() is all you need. When that call returns, the rendering is already completed.

The error in the code snippet is that you set the same input into vtkImageAppend every time. Instead, you would need to make a deep-copy of the vtkWindowToImageFilter output and set those as inputs into vtkImageAppend. But instead of this of course it would be much better to render the scene directly to your display in real-time.

1 Like

@lassoan Thanks so much for the input! I’ll check out CTK and MITK to see if I can get that working for me.

I see, I think I might’ve misinterpreted how the input changes–I had assumed that because I had moved my camera and called a render each time, my .png outputs would have been been seeing new data. I’ll poke at it some more using deep-copies since I may have misunderstood how vtkSmartPointers work.

That’s the optimistic end-goal! I have to get more comfortable with openGL first.

Thanks again!

If you use VTK then you might not need to learn OpenGL at all.

What kind of stereoscopic display are you working with? Virtual reality headset, HoloLens, Looking glass, …? There may be others who have already implemented low-level VTK-based infrastructure to support these devices.