pcl+vtk (9) QVTKOpenGLNativeWidget displays point cloud and model at the same time

1. Load point cloud

 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); //Create point cloud pointer
    QString fileName = QFileDialog::getOpenFileName(this, "Open PointCloud", ".", "Open PCD files(*.pcd)");
    if(fileName == "") return;
    pcl::io::loadPCDFile(fileName.toStdString(),*cloud);
    vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
    vtkSmartPointer<vtkCellArray> vertices = vtkSmartPointer<vtkCellArray>::New();

    for (int i = 0; i<cloud->size(); i + + )
    {
        vtkIdType pid[1];
        pid[0] = points->InsertNextPoint(cloud->at(i).x, cloud->at(i).y, cloud->at(i).z);
        vertices->InsertNextCell(1, pid);
    }

    vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
    polyData->SetPoints(points);
    polyData->SetVerts(vertices);

    //mapping
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetInputData(polyData);
    //actor
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
    actor->GetProperty()->SetColor(1.0, 0.0, 0.0);
    actor->GetProperty()->SetPointSize(2);
    renderer->AddActor(actor);

    renderer->ResetCamera();

Load the rgba information in the point cloud file and display it

 pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGBA>);
    QString fileName = QFileDialog::getOpenFileName(this, "Open PointCloud", ".", "Open PCD files(*.pcd)");
    if(fileName == "") return;
    pcl::io::loadPCDFile(fileName.toStdString(),*cloud);
    vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
    vtkSmartPointer<vtkCellArray> vertices = vtkSmartPointer<vtkCellArray>::New();
    vtkSmartPointer<vtkUnsignedCharArray> colors = vtkSmartPointer<vtkUnsignedCharArray>::New();
    colors->SetNumberOfComponents(4);
    for (int i = 0; i<cloud->size(); i + + )
    {
        vtkIdType pid[1];
        pid[0] = points->InsertNextPoint(cloud->at(i).x, cloud->at(i).y, cloud->at(i).z);
        vertices->InsertNextCell(1, pid);
        unsigned char col[4] = {cloud->at(i).r,cloud->at(i).g,cloud->at(i).b,cloud->at(i).a};
        colors->InsertNextTypedTuple(col);
    }
    vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
    polyData->SetPoints(points);
    polyData->SetVerts(vertices);
    polyData->GetPointData()->SetScalars(colors);

    //mapping
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetInputData(polyData);
    //actor
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
    actor->GetProperty()->SetPointSize(2);
    renderer->AddActor(actor);

    renderer->ResetCamera();

2. Load obj file model

 //Read OBJ file
    vtkSmartPointer<vtkOBJReader> OBJReader = vtkSmartPointer<vtkOBJReader>::New();
    QString fileName = QFileDialog::getOpenFileName(this, "Open OBJ", ".", "Open PCD files(*.obj)");
    if(fileName == "") return;
    OBJReader->SetFileName(fileName.toStdString().c_str());
    OBJReader->Update();
    // Create mappers and actors
    vtkSmartPointer<vtkPolyDataMapper> mapperOBJ = vtkSmartPointer<vtkPolyDataMapper>::New();
    mapperOBJ->SetInputConnection(OBJReader->GetOutputPort());
    vtkSmartPointer<vtkActor> actorOBJ = vtkSmartPointer<vtkActor>::New();
    actorOBJ->SetMapper(mapperOBJ);
    //Add actor to renderer
    renderer->AddActor(actorOBJ);
    renderer->ResetCamera();

3. Load stl file model

 //Read STL file
    vtkSmartPointer<vtkSTLReader> STLReader = vtkSmartPointer<vtkSTLReader>::New();
    QString fileName = QFileDialog::getOpenFileName(this, "Open STL", ".", "Open PCD files(*.stl)");
    if(fileName == "") return;
    STLReader->SetFileName(fileName.toStdString().c_str());
    STLReader->Update();
    // Create mappers and actors
    vtkSmartPointer<vtkPolyDataMapper> mapperSTL = vtkSmartPointer<vtkPolyDataMapper>::New();
    mapperSTL->SetInputConnection(STLReader->GetOutputPort());
    vtkSmartPointer<vtkActor> actorSTL = vtkSmartPointer<vtkActor>::New();
    actorSTL->SetMapper(mapperSTL);
    //Add actor to renderer
    renderer->AddActor(actorSTL);
    renderer->ResetCamera();

4. All code

.pro

#------------------------------------------------- ---
#
# Project created by QtCreator 2023-10-23T11:32:27
#
#------------------------------------------------

QT + = core gui

greaterThan(QT_MAJOR_VERSION, 4): QT + = widgets

TARGET = vtk_pointCloud_obj
TEMPLATE = app

# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES + = QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES + = QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0


SOURCES + = \
        main.cpp \
        widget.cpp

HEADERS + = \
        widget.h

FORMS + = \
        widget.ui

INCLUDEPATH + = /usr/include/eigen3

INCLUDEPATH + = /usr/local/include/vtk-8.2
LIBS + = /usr/local/lib/libvtk*.so

INCLUDEPATH + = /usr/local/include/pcl-1.13
LIBS + = /usr/local/lib/libpcl_*.so

main..cpp

#include "widget.h"
#include <QApplication>
#include <QSurfaceFormat>
#include "QVTKOpenGLNativeWidget.h"

int main(int argc, char *argv[])
{
    QSurfaceFormat::setDefaultFormat(QVTKOpenGLNativeWidget::defaultFormat());
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}

.ui

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "vtkAutoInit.h" // How to initialize vtk
VTK_MODULE_INIT(vtkRenderingOpenGL2); // Rendering
VTK_MODULE_INIT(vtkInteractionStyle); //Interaction mode
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL2); //
VTK_MODULE_INIT(vtkRenderingFreeType);
#include <pcl/io/pcd_io.h>
#include <vtkSmartPointer.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include "vtkPolyDataMapper.h"
#include "vtkRenderWindow.h"
#include "vtkRenderer.h"
#include "vtkActor.h"
#include "vtkProperty.h"
#include "vtkConeSource.h"
#include <vtkSTLReader.h>
#include <vtkOBJReader.h>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private slots:
    void on_load_pointCould_clicked();

    void on_load_obj_clicked();

    void on_load_stl_clicked();

private:
    Ui::Widget *ui;

    vtkSmartPointer<vtkRenderer> renderer;//renderer

};

#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

#include <QFileDialog>

Widget::Widget(QWidget *parent):
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    renderer = vtkSmartPointer<vtkRenderer>::New();

    vtkNew<vtkGenericOpenGLRenderWindow> renwindow;
    renwindow->AddRenderer(renderer);
    ui->vtk_widget->SetRenderWindow(renwindow.Get());
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_load_pointCould_clicked()
{
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); //Create a point cloud pointer
    QString fileName = QFileDialog::getOpenFileName(this, "Open PointCloud", ".", "Open PCD files(*.pcd)");
    if(fileName == "") return;
    pcl::io::loadPCDFile(fileName.toStdString(),*cloud);//"/home/li/pcd/bun_zipper.pcd"
    vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
    vtkSmartPointer<vtkCellArray> vertices = vtkSmartPointer<vtkCellArray>::New();

    for (int i = 0; i<cloud->size(); i + + )
    {
        vtkIdType pid[1];
        pid[0] = points->InsertNextPoint(cloud->at(i).x, cloud->at(i).y, cloud->at(i).z);
        vertices->InsertNextCell(1, pid);
    }

    vtkSmartPointer<vtkPolyData> polyData = vtkPolyData::New();
    polyData->SetPoints(points);
    polyData->SetVerts(vertices);

    //mapping
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkPolyDataMapper::New();
    mapper->SetInputData(polyData);
    //actor
    vtkSmartPointer<vtkActor> actor = vtkActor::New();
    actor->SetMapper(mapper);
    actor->GetProperty()->SetColor(1.0, 0.0, 0.0);
    actor->GetProperty()->SetPointSize(2);
    renderer->AddActor(actor);

    renderer->ResetCamera();
}

void Widget::on_load_obj_clicked()
{
    //Read OBJ file
    vtkSmartPointer<vtkOBJReader> OBJReader = vtkSmartPointer<vtkOBJReader>::New();
    QString fileName = QFileDialog::getOpenFileName(this, "Open OBJ", ".", "Open PCD files(*.obj)");
    if(fileName == "") return;
    OBJReader->SetFileName(fileName.toStdString().c_str()); //"/home/li/pcd/RedLeaf.obj"
    OBJReader->Update();
    // Create mappers and actors
    vtkSmartPointer<vtkPolyDataMapper> mapperOBJ = vtkSmartPointer<vtkPolyDataMapper>::New();
    mapperOBJ->SetInputConnection(OBJReader->GetOutputPort());
    vtkSmartPointer<vtkActor> actorOBJ = vtkSmartPointer<vtkActor>::New();
    actorOBJ->SetMapper(mapperOBJ);
    //Add actor to renderer
    renderer->AddActor(actorOBJ);
    renderer->ResetCamera();
}

void Widget::on_load_stl_clicked()
{
    //Read STL file
    vtkSmartPointer<vtkSTLReader> STLReader = vtkSmartPointer<vtkSTLReader>::New();
    QString fileName = QFileDialog::getOpenFileName(this, "Open STL", ".", "Open PCD files(*.stl)");
    if(fileName == "") return;
    STLReader->SetFileName(fileName.toStdString().c_str()); //"/home/li/pcd/skull_50.stl"
    STLReader->Update();
    // Create mappers and actors
    vtkSmartPointer<vtkPolyDataMapper> mapperSTL = vtkSmartPointer<vtkPolyDataMapper>::New();
    mapperSTL->SetInputConnection(STLReader->GetOutputPort());
    vtkSmartPointer<vtkActor> actorSTL = vtkSmartPointer<vtkActor>::New();
    actorSTL->SetMapper(mapperSTL);
    //Add actor to renderer
    renderer->AddActor(actorSTL);
    renderer->ResetCamera();
}

Show results

5. 3D model download URL

Pro 3D Model :: TurboSquid

6. Question

There is a problem: the point cloud and model are displayed in the slot function. After loading, you need to click on the interface to display them. If they are all written in the constructor, they can be displayed directly. I tried all the update functions I could add, but they didn’t work. What I think is that if we know the source code and what function is executed when the interface is clicked, we can solve the problem. If anyone knows, please leave a message and let me know, thank you very much! ! !

Solved! ! ! ! ! !

Just add the following sentence at the end! ! ! !

ui->vtk_widget->GetRenderWindow()->Render();

For example:

 //Read OBJ file
    vtkSmartPointer<vtkOBJReader> OBJReader = vtkSmartPointer<vtkOBJReader>::New();
    QString fileName = QFileDialog::getOpenFileName(this, "Open OBJ", ".", "Open PCD files(*.obj)");
    if(fileName == "") return;
    OBJReader->SetFileName(fileName.toStdString().c_str()); //"/home/li/pcd/RedLeaf.obj"
    OBJReader->Update();
    // Create mappers and actors
    vtkSmartPointer<vtkPolyDataMapper> mapperOBJ = vtkSmartPointer<vtkPolyDataMapper>::New();
    mapperOBJ->SetInputConnection(OBJReader->GetOutputPort());
    vtkSmartPointer<vtkActor> actorOBJ = vtkSmartPointer<vtkActor>::New();
    actorOBJ->SetMapper(mapperOBJ);
    //Add actor to renderer
    renderer->AddActor(actorOBJ);
    renderer->ResetCamera();
    ui->vtk_widget->GetRenderWindow()->Render();