PCL1.12.1+VTK9.1+Qt5.14.2VS creates Qt project to display point cloud on widget

After completing the compilation of the VTK9.1 source code and the related configuration of VS2019 , you can start using Qt5.12 for point cloud display.
Many blogs write about dragging a widget into the UI designer and then promoting it to QVTKOpenGLNativeWidget. Some are dragged into OpenGLwidget. After testing, it was found that both are possible. Because QVTKOpenGLNativeWidget inherits from QOpenGLWidget, and QOpenGLWidget inherits from QWidget.
Insert image description here
Insert image description here
Older versions such as PCL1.8 may upgrade QWidget to QVTKWidget, as introduced in this blog. But PCL1.12 and VTK9.1 will definitely be upgraded to QVTKOpenGLNativeWidget. This blog explains the differences between QVTKWidget, QVTKOpenGLWidget, QVTKOpenGLNativeWidget, and QVTKWidget2.
Just for reference:
Insert image description here

Then many blogs only use these three lines of code to implement the function of displaying point clouds in Qt. However, when I operate in this way, it cannot be displayed and an error is reported.

ui.qvtkWidget->SetRenderWindow(viewer->getRenderWindow());
viewer->setupInteractor(ui.qvtkWidget->GetInteractor(), ui.qvtkWidget->GetRenderWindow());
ui.qvtkWidget->update();

If you write according to these three lines of code, an error will be reported:
QVTKOpenGLNativeWidget requires a vtkGenericOpenGLRenderWindow. vtkWin32OpenGLRenderWindowis not supported.
An exception is raised: read access permission conflict.
win is nullptr.
Insert image description here
Some blogs explain that QVTKWidget has a default RenderWindow, but QVTKOpenGLWidget does not (it is a null pointer). For newer QVTKOpenGLNativeWidget it should also be a null pointer.
So I went to check the official VTK9.1 documentation about the QVTKOpenGLNativeWidget class, and click to view the official documentation introduction.
Insert image description here
The document talks about QOpenGLWidget subclass to house a vtkGenericOpenGLRenderWindow in a Qt application, that is, QVTKOpenGLNativeWidget is a subclass of QOpenGLWidget and needs to house a vtkGenericOpenGLRenderWindow rendering window in Qt. However, setRenderWindow has two overloaded methods, which can logically accommodate vtkRenderWindow.
Insert image description here
It stands to reason that when creating a viewer like this, viewer->getRenderWindow() returns a vtkRenderWindow, which should be reasonable, but an error is reported.

boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
ui.openGLWidget->SetRenderWindow(Viewer->getRenderWindow());

Insert image description here
This blog also encountered this problem. He believes that the renderWindow created by pcl_visualizer is a derived class of vtkwin32OpenGLRenderWindow. But I don't think so. vtkRenderWindow inherits from vtkWindow, vtkWindow inherits from vtkObject, and vtkObject inherits from vtkObjectBase. After continuous tracing, I did not find that vtkRenderWindow is a derived class of vtkwin32OpenGLRenderWindow (not sure).
Insert image description here
When I was almost about to recompile PCL as he said, I found that he had given an important URL, which was a discussion forum. When I carefully watched the discussions of these foreigners, I found that
Insert image description here
according to this person's method, the function of displaying point clouds on OpenGLWidget (QVTKOpenGLNativeWidget to be precise) was successfully implemented. In fact, it is a constructor of PCLVisualizer that is selectively called.
Insert image description here
At this point, the operation of displaying point clouds with Qt has finally been realized.
Later I discovered that someone actually did this, but I didn't look carefully before.
Insert image description here
In fact, the core are these few sentences for reference:

  auto renderer2 = vtkSmartPointer<vtkRenderer>::New();
  auto renderWindow2 = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
  renderWindow2->AddRenderer(renderer2);
  viewer.reset(new pcl::visualization::PCLVisualizer(renderer2, renderWindow2, "viewer", false));
  this->setRenderWindow(viewer->getRenderWindow());
  viewer->setupInteractor(this->interactor(), this->renderWindow());

1. This blog is worth recording - [VTK] About the RenderWindow setting issue of QVTKOpenGLWidget
2. Reference post
This blog mentioned the memory leak problem involved in using Qt combined with VTK to display point clouds.
Add the following two lines of code to the destructor for release (I have not specifically tested whether adding these two lines or not adding these two lines is really useful).

ui.qvtkWidget->GetInteractor()->SetRenderWindow(nullptr);
ui.qvtkWidget->GetInteractor()->SetInteractorStyle(nullptr);

Method 2
In addition to the above-mentioned promotion of QWidget or QOpenGLWidget to QVTKOpenGLNativeWidget, you can also display it by obtaining the ID of the Window. This method does not even require lifting the widget and can be used directly.

auto winId = QWindow::fromWinId((WId)viewer->getRenderWindow()->GetGenericWindowId());
ui.widget = QWidget::createWindowContainer(winId, nullptr);
ui.widget->setParent(this);
ui.widget->update();

QOpenGLWidget interface real-time refresh problem

After I realized the point cloud display through Qt, I thought about adding some buttons, Labels and other controls to Qt to operate the point cloud. However, I found that every time I manipulate the point cloud, the interface does not update in real time. It is usually necessary to click the displayed window with the mouse, that is, the widget that displays the point cloud to complete the window refresh. Use widget->update(), or viewer->updateCamera() or viewer->resetCamera(). Found it to be useless.

The final solution is to add a code after each operation to let the window re-render.

Viewer->getRenderWindow()->Render();

The solution comes from this post
Insert image description here

Guess you like

Origin blog.csdn.net/dyk4ever/article/details/126715543