Manifold Geometry // Многообразная Геометрия

Jumping into vtk.js

/ Просмотров: 202

Let's talk about 3D visualization on the web. Since I am not a WebGL guru whatsoever, we'll limit this discussion with higher-level libs and formats that allow getting work done without much effort.

Because Analysis Situs employs VTK as a visualization engine, it is logical to construct web visualization frontend also on VTK. Luckily, there is this vtk.js software package that is backed by WebGL API. Let's start by preparing a simple test case to give this framework a try. Previously we created a simple trapezoid block, and now we can render it using VTK on the web. Let's see what do we need for that.

To start off, there's this VTK Integration Services (VIS) package of OpenCascade. It is an alternative solution to AIS (the OpenGL-based module for visualization) that turns our shape into a VTK data structure that we can then dump to a VTK viewer (either desktop or web). To use it, make sure to compile OpenCascade having USE_VTK cmake flag enabled.

Actually, in Analysis Situs, we do not use VTK Integration Services because it's kinda limited. The key difference between OpenCascade's VIS and Analysis Situs is how an interactive picker is employed in a pipeline. In OpenCascade, the picker works on the initial state of geometry. In Analysis Situs, we use the native VTK pickers applied to the final state of data in an actor. Doing so is just more logical as you normally pick something you see on the display and not the original data source that could happen to have been modified in whatever ways (like deformed mesh). But it does not change anything for our current discussion, so let's rather stick to VIS in what follows, because it's interfaced with Draw.

To render any OpenCascade shape with VTK, use the following commands in Draw:

pload ALL
pload VIS
ivtkinit
ivtkdisplay <shape>
ivtksetdispmode <shape> 1
ivtksetselmode <shape> 4 on

Those of you familiar with AIS interface in Draw will find these ivtk commands similar to the native AIS ones. Indeed, they are more or less the same, although VIS commands are less developed and arguably less mature.

Render OpenCascade shapes with VTK on desktop.

The ivtkinit command initializes a render window, and ivtkdisplay command performs the visualization pipeline. Other useful commands are ivtksetdispmode and ivtksetselmode to set up the display and selection modes correspondingly.

We can render our shape using Geometry Viewer example of vtk.js. For that, we need to have our polygonal data as a VTP file format native to VTK. Unfortunately, OpenCascade cannot dump into this format, so let's add the corresponding command to the VIS package. In IVtkDraw.cxx file of OpenCascade, add the following instruction to register a new command in the Tcl interpreter:

void IVtkDraw::Commands (Draw_Interpretor& theCommands)
{
  ...
  
  // Add this:
  theCommands.Add("ivtkdumpvtp",
                  "ivtkdumpvtp name filename",
                  __FILE__, VtkDumpVtp, group);
  
  ...
}

Here we register a new command ivtkdumpvtp that accepts a shape of interest and the target filename. The "__FILE__" and "group" arguments are predefined. The "VtkDumpVtp" is a pointer to a static function that implements our command. We have to add this function somewhere above in IVtkDraw.cxx:

#include <vtkXMLPolyDataWriter.h>
  
static int VtkDumpVtp(Draw_Interpretor&,
                      int argc,
                      const char** argv)
{
  if ( !GetInteractor() || !GetInteractor()->IsEnabled() )
  {
    std::cout << "Error: call ivtkinit before." << std::endl;
    return 1;
  }
  
  // Get the actor in question.
  vtkSmartPointer<vtkActor> actor;
  if ( !GetMapOfActors().Find2(argv[1], actor) )
  {
    std::cout << "Cannot find actor with name '" << argv[1] << "'." << std::endl;
    return 1; // Error.
  }
  
  // Update mapper to actualize the state of data set.
  actor->GetMapper()->Update();
  
  // Get data from mapper.
  vtkPolyData* pData = vtkPolyData::SafeDownCast( actor->GetMapper()->GetInput() );
  
  // Dump to file.
  vtkSmartPointer<vtkXMLPolyDataWriter>
    writer = vtkSmartPointer<vtkXMLPolyDataWriter>::New();
  //
  writer->SetFileName(argv[2]);
  writer->SetInputData(pData);
  writer->Write();
  
  return 0;
}

It is likely that you'll get a linker error saying that vtkXMLWriter::SetInputData() function is not imported from the available set of VTK libraries. To fix it, we have to add vtkIOXML to the linker options. You can add this dependency to the EXTERNLIB file in TKIVtk directory of OpenCascade sources. Do not forget to reconfigure CMake once you're done. You can now use the newly added command to dump shapes as VTK polygonal data files and visualize them in tools like vtk.js or Paraview.

That was about the data format to use vtk.js. To plug the vtk.js viewer programmatically, the easiest way is to copy and paste the HTML code from its documentation. This sample code renders a predefined data set such as a cone, sphere or cylinder. You may want to build a simple server app (e.g., in Python) to make it all work for your custom files.