VTK+Qt+Cmake+VS的环境搭建

VTK+Qt+Cmake+VS的环境搭建

本文的主要内容:简单介绍如何使用Cmake编译安装VTK源代码;如何配置VTK在Qt中的使用环境;如何以VS作为IDE在C++下使用Qt+VTK。
哪些人适合阅读本文:有一定Cmake、Qt和VS的基础,但是初次使用VTK的人。

一、准备工作

  1. 安装VS 2022
  2. 安装Cmake 3.28.3
  3. 安装Qt 5.15.2
  4. VTK 9.3.0 源代码,去官网下载

二、VTK源码安装过程

  1. 如果需要用Qt作为GUI,建议先把Qt装好,在Cmake Config的时候会自动识别出Qt的安装情况。
  2. 解压VTK源代码,在同级目录下新建两个文件夹,其中vtk-build用于存放编译文件,安装完之后可以删除,避免占用空间。vtk-install文件夹用于存放安装之后的库文件。
  3. 打开cmake-gui,源文件夹选择VTK-9.3.0,Build文件夹选择vtk-build,然后点Configure,选择对应的VS和X64。
  4. 在接下来出现的配置窗口里,有几个需要注意的地方,可以通过Search搜索栏直接找到需要修改的配置条目。
  • BUILD_SHARED_LIBS -- 默认是勾选的,表示是动态编译。如果把勾选去掉表示VTK是静态编译。如果是动态编译,vtk-install/bin文件夹下会生成dll动态库,需要把这个文件夹添加到环境变量,应用程序运行时会自动从环境变量找到这个库;或者在写应用程序时复制需要用到的dll文件到exe文件同目录,否则运行会报错。静态库则不用。
  • "静态编译"与"动态编译"的区别 :静态编译就是在编译的时候把所有的模块都编译进可执行文件(exe)里去,当启动这个可执行文件时所有的模块都已加载进来。动态编译则是编译的时候需要的模块都没有编译进去,一般情况下可以把这些模块都编译成动态链接库DLL,启动程序(初始化)的时候这些模块不会被加载,运行的时候用到那个模块就调用哪个DLL文件。静态链接库编译相当于你带着一个工具包到处跑,遇到有需要的地方不需要周围的环境提供相应的工具,自己用自己工具包的工具就行了,所以当环境发生变化可以尽可能的无视;动态链接库编译相当于不带任何东西,走到哪是哪。这两者的区别显然就是前者重量增加了,即程序的体积会比后者的大。所以,究竟是用"静态编译"还是"动态编译",关键看自己的需要。对于VTK初学者而言,所涉及到的工程可能都比较小,建议用"静态编译",也方便把VTK程序移植到其他没有安装VTK的计算机上运行。本书的VTK类库是采用静态编译。-- 引用自CSDN博客
  • CMAKE_INSTALL_PREFIX -- 这个选项表示VTK的安装路径,默认的路径是:C:/Program Files/VTK。将这个路径改成刚刚新建的vtk-install路径,安装完之后会在这个路径生成库文件。
  1. 改完上述配置之后,再点一下Configure,然后Generate,然后OpenProject将在VS中打开工程。
  2. 将Debug改为Release,在ALL BUILD右键->生成,等待编译完成。
  3. 完成之后在INSTALL右键->生成,完成之后会把需要的库文件复制到vtk-install文件夹。

    如果配置的是动态库,则bin文件夹下会有dll文件,如果是静态库则没有。
    至此,安装完成。如果想节约硬盘空间,可以将VTK9.3.0和vtk-build删除,只保留安装后的库文件vtk-install就可以了。

三、错误排查

  1. 使用VTK-9.3.0在VS2019里面编译会报错:
    vtkCommonCore-9.3d.lib(vtkSMPToolsAPI.obj) : error LNK2019: unresolved external symbol "public: bool __cdecl vtk::detail::smp::vtkSMPToolsImpl<1>::IsParallelScope(void)" (?IsParallelScope@?$vtkSMPToolsImpl@$00@smp@detail@vtk@@QEAA_NXZ) referenced in function "public: bool __cdecl vtk::detail::smp::vtkSMPToolsAPI::IsParallelScope(void)" (?IsParallelScope@vtkSMPToolsAPI@smp@detail@vtk@@QEAA_NXZ)

这个时候将下面这个选项勾选去掉重新编译安装一遍就可以了:

  1. 在结合Qt使用时会出现QVTKOpenGLNativeWidget.h找不到
    这两个选项要改成yes:

四、Cmake中引用VTK

  1. 上面已经说了,如果是动态编译,则要把vtk-install/bin这个文件夹添加到环境变量。如果是静态编译则不用。

  2. 然后在应用程序的CmakeLists.txt里面加入:

    set(VTK_DIR "D:/Software/VTK-install/lib/cmake/vtk-9.3")
    FIND_PACKAGE(VTK REQUIRED)
    target_link_libraries(${PROJECT_NAME} ${VTK_LIBRARIES})

    vtk_module_autoinit is needed

    vtk_module_autoinit(TARGETS ${PROJECT_NAME} MODULES ${VTK_LIBRARIES})

  3. 如果在CmakeLists.txt里面没有设置VTK_DIR,在通过Cmake配置应用程序时就会出现VTK_DIR NOT FOUND,将vtk-install/lib/cmake/vtk-9.3目录添加进去就可以了。

五、代码示例

接下来写一个最简单的VTK+Qt+Cmake+VS的工程示例。

工程的目录如下,build里面是编译输出的文件。

src文件夹里只有三个文件:

CMakeLists.txt

cpp 复制代码
# 设置cmake版本号
cmake_minimum_required(VERSION 3.10)

# 设置moc rcc uic
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)

# 设置工程名称
project(VTKTest)

# 使用VTK
set(VTK_DIR "D:/Software/VTK/vtk-install/lib/cmake/vtk-9.3")
FIND_PACKAGE(VTK REQUIRED)

# 使用QT
set(Qt5_DIR D:/Software/Qt/Qt5.12.10/5.12.10/msvc2017_64/lib/cmake/Qt5/)
find_package(Qt5 COMPONENTS Widgets Core Gui Network OpenGL REQUIRED) # 查找Qt库文件

# 查找源码
include_directories("src/")
FILE(GLOB SRC_FILES "src/*.cpp")
FILE(GLOB HEAD_FILES "src/*.h")
source_group("src" FILES ${SRC_FILES} ${HEAD_FILES})

# 添加可执行文件
add_executable(${PROJECT_NAME} ${SRC_FILES} ${HEAD_FILES} )
	
# 设置工程包含当前目录
set(CMAKE_INCLUDE_CURRENT_DIR ON)

# 添加依赖项
target_link_libraries(${PROJECT_NAME} Qt5::Widgets Qt5::Core Qt5::Gui Qt5::Network Qt5::OpenGL ${VTK_LIBRARIES})

# vtk_module_autoinit is needed
vtk_module_autoinit(
TARGETS ${PROJECT_NAME}
MODULES ${VTK_LIBRARIES}
)

main.cpp

cpp 复制代码
#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

Widget.cpp

cpp 复制代码
#include "widget.h"
#include <QHBoxLayout>
#include <vtkSphereSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkCubeSource.h>
#include <vtkProperty.h>
#include <vtkNamedColors.h>

Widget::Widget(QWidget *parent) :
    QWidget(parent)
{
    this->setGeometry(640, 360, 640, 360);
    QHBoxLayout* layout = new QHBoxLayout(this);
    qVTKWidget = new QVTKOpenGLStereoWidget(this);
    layout->addWidget(qVTKWidget);

    vtkShow();
}

Widget::~Widget()
{
    
}

void Widget::vtkShow()
{
    // 创建一个球体源
    vtkSmartPointer<vtkSphereSource> sphereSource = vtkSmartPointer<vtkSphereSource>::New();
    sphereSource->SetCenter(0, 0, 0);
    sphereSource->SetRadius(0.5);
    sphereSource->SetThetaResolution(20);
    sphereSource->SetPhiResolution(20);

    // 创建一个正方体源
    vtkSmartPointer<vtkCubeSource> cubeSource = vtkSmartPointer<vtkCubeSource>::New();
    cubeSource->SetCenter(1.5, 0, 0);
    cubeSource->SetXLength(1);
    cubeSource->SetYLength(1);
    cubeSource->SetZLength(1);

    // 创建一个多边形数据映射器
    vtkSmartPointer<vtkPolyDataMapper> sphereMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    sphereMapper->SetInputConnection(sphereSource->GetOutputPort());

    vtkSmartPointer<vtkPolyDataMapper> cubeMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    cubeMapper->SetInputConnection(cubeSource->GetOutputPort());

    vtkSmartPointer<vtkNamedColors> colors = vtkSmartPointer<vtkNamedColors>::New();
    // 创建一个演员
    vtkSmartPointer<vtkActor> sphereActor = vtkSmartPointer<vtkActor>::New();
    sphereActor->SetMapper(sphereMapper);
    sphereActor->GetProperty()->SetColor(colors->GetColor3d("red").GetData());

    vtkSmartPointer<vtkActor> cubeActor = vtkSmartPointer<vtkActor>::New();
    cubeActor->SetMapper(cubeMapper);
    cubeActor->GetProperty()->SetColor(colors->GetColor3d("green").GetData());

    // 创建一个渲染器
    vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
    renderer->AddActor(sphereActor);
    renderer->AddActor(cubeActor);
    renderer->ResetCamera();

    qVTKWidget->renderWindow()->AddRenderer(renderer);
    qVTKWidget->renderWindow()->Render();
}

Widget.h

cpp 复制代码
#pragma once

#include <QWidget>
#include <QVTKOpenGLStereoWidget.h>

class Widget : public QWidget
{
    Q_OBJECT

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

private:
    void vtkShow();

private:
    QVTKOpenGLStereoWidget* qVTKWidget;
};

运行之后输出的效果如下:

相关推荐
人才程序员4 小时前
QML z轴(z-order)前后层级
c语言·前端·c++·qt·软件工程·用户界面·界面
学习BigData4 小时前
【使用PyQt5和YOLOv11开发电脑屏幕区域的实时分类GUI】——选择检测区域
qt·yolo·分类
zhy2956310 小时前
【LIBS】开源库编译之OSQP
ubuntu·cmake·osqp·libs
yerennuo14 小时前
FFmpeg库之ffmpeg
qt·ffmpeg
冷眼看人间恩怨14 小时前
【Qt笔记】QComboBox控件详解
c++·笔记·qt
阿松のblog15 小时前
pyQt5实现页面切换操作
开发语言·qt
人才程序员15 小时前
【无标题】
c语言·前端·c++·qt·软件工程·qml·界面
无所谓จุ๊บ18 小时前
VTK知识学习(27)- 图像基本操作(二)
学习·vtk
牵牛老人19 小时前
Qt调用adb对嵌入式设备的配置文件进行修改,写入多行内容
数据库·qt·adb