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;
};

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

相关推荐
凯子坚持 c39 分钟前
Qt 5.14.0 入门框架开发全流程深度解析
开发语言·qt
深蓝海拓1 小时前
PySide6从0开始学习的笔记(十四)创建一个简单的实用UI项目
开发语言·笔记·python·qt·学习·ui·pyqt
小尧嵌入式1 小时前
Linux网络介绍网络编程和数据库
linux·运维·服务器·网络·数据库·qt·php
海涛高软2 小时前
Qt中使用QListWidget列表
开发语言·qt
010米粉0102 小时前
Qt之构建方式
qt
凯子坚持 c3 小时前
Qt 信号与槽机制深度解析
开发语言·qt
世转神风-3 小时前
qt-初步编译运行报错-When executing step “Make“-无法启动进程“make“
开发语言·qt
一然明月14 小时前
QT之基础控件
开发语言·qt
深蓝海拓19 小时前
PySide6从0开始学习的笔记(十) 样式表(QSS)
笔记·python·qt·学习·pyqt
深蓝海拓20 小时前
PySide6从0开始学习的笔记(十三) IDE的选择
笔记·python·qt·学习·pyqt