1. 下载和安装VTK
- 下载源码包, 保存到工作目录中. 比如, 我自己的目录为
c:/libs/vtk
. - 解压缩vtk的源码包. 默认解压缩当当前目录后是
VTK-9.3.0
, 我打算将这个目录用于构建后的版本目录, 因此将它改一下名字,VTK-9.3.0-src
- 建立两个同级的目录,
VTK-9.3.0-build
和VTK-9.3.0
, 第一个是构建时的工作目录, 这样cmake的所有生成文件都放在这里, 不会破坏源代码目录VTK-9.3.0-src
. 而VTK-9.3.0
用于安装VTK的目录. 将这些目录都和安装目录隔离开, 避免万一构建出了什么问题后清理起来麻烦.
1.1 修改bug
VTK9.3有一个bug, 会导致Debug模式下编译失败. 我们先修改一下.
打开Common\Core\vtkConstantImplicitBackend.h
,
VTK_ABI_NAMESPACE_BEGIN
template <typename ValueType>
struct VTKCOMMONCORE_EXPORT vtkConstantImplicitBackend final
{
/**
* A non-trivially contructible constructor
*
* \param val the constant value to return for all indeces
*/
vtkConstantImplicitBackend(ValueType val)
: Value(val)
{
}
...
我们需要将VTKCOMMONCORE_EXPORT
给删掉. 不然会重复导出符号.
1.2 配置CMake
-
启动CMAKE, 指定源目录为
C:/libs/vtk/VTK-9.3.0-src
, build目录为c:/libs/vtk/VTK-9.3.0-build
. -
按下
Configure
按钮. 此时, 也可以将Grouped
和Advanced
两个复选框勾上. 此时会弹出对话框, 选择工具. 在里面选择Visual Studio 17 2022
和x64
.
Qt6 编译使用的是Visual Studio 16 2019
, 可能选择它是更好的做法. 我的电脑里面只有2022, 因此只能选择这个. 不过, 我们可以为Visual Studio 2022安装2019的生成工具使用. 如下所示:
-
确认之后, CMAKE会进行配置分析. 取决于你的电脑, 这是一个很漫长的过程, 等完成后, 要进行下面的修改:
-
注意选中
BUILD_SHARED_LIBS
, 这个一定要选中 (默认是选中的, 要检查一下不要弄没了). -
寻找
VTK_LEGACY_REMOVE
, 选中它会禁用deprecated api. 我们会使用最新的API接口, 不会盲目抄网上的老东西, 所以这个最好是选中它. -
检查一下
VTK_MODULE_ENABLE_VTK_ioss
和VTK_MODULE_ENABLE_VTK_IOIOSS
, 据说要设置为NO
, 以前的版本会编译失败. 不过, 如果你打算生成测试数据, 那么这个最终还是要打开的, 而且也能编译通过. 所以网上的东西不一定是对的. -
寻找
CMAKE_INSTALL_PREFIX
, 把它设置为我们前面创建的目录C:/libs/vtk/VTK-9.3.0
. 这个一定要慎重, 一旦确定了就不要以后再乱动了. -
最后, 寻找
Qt
, 将VTK_GROUP_ENABLE_QT
给勾选上, 然后将其他几个都设置为WANT
. 我因为不用QML, 就没有选中Quick
的这一项. 注意的是, Qt6的新版本的目录结构有变化, 和VTK不怎么兼容, 如果选择了quick, 需要自己去修改几个目录的位置.
-
-
选择了之后, 就可以再次按下
Configure
按钮了. 这个时候还会有错误. 我们要如下修改:- 设置
Qt5_DIR
和Qt6_DIR
. 对于Qt6, 默认位置在C:\Qt\6.7.0\msvc2019_64\lib\cmake\Qt6
下面. Qt5也一样. - 确认一下
VTK_QTVERSION
的值, 因为这台电脑只装了Qt6, 我也只会在Qt6上面用VTK, 我就设置为6了. 注意, 我没有选择Quick
, 因为我不用QML. 如果你打开了, 又会有一堆错误出来. 还是找不到qt的目录, 手工一个个去修改就是了. 反正用qt6就会有这些烂事, 不知道是qt6烂还是vtk适配的不好.
- 设置
-
再次按下
Configure
按钮, 结果如下图所示. 红色的是给你确认的. 因为这台电脑上没有装vulkan, 所以会有警告. 我们不用它, 所以不用关心. 等以后需要的时候再重新安装Vulkan SDK就是了. 然后确认一下没问题了. 就可以按下Generate
按钮生成VC工程了. -
按下
Generate
, 会在build目录中生成VTK.sln
文件. 然后我们可以关闭CMAKE了.
1.3 编译VLK和安装
用Visual Studio打开VTK.sln
工程. 选择ALL BUILD
项目, 打开工程属性页:
- 选择
所有配置
, 然后选择常规/C++标准
, 将其改为C++17
或更新的版本. - 如果担心和Qt的版本不一致, 可以修改
平台工具集
, 改为2019的v142
版本. 据说这个版本不一致会影响plugin, 但是我基本上不拖拉控件, 所以也就不想改了.
然后, 激活Release
, 并开始Build. 这个过程很漫长, 我的11代i5的笔记本, 估计会跑上1个多小时.
编译完成后, 选择INSTALL
项目, 选择仅生成INSTALL
.
然后, 将配置切换到Debug, 并重新做一轮. 编译和安装就完成了.
修改完毕之后, 注意将VTK_DIR
放到环境变量里面去.
2. 在Qt的qmake项目中使用VTK
使用qmake,无法利用cmake,使用起来很麻烦,需要人工将库一个个地添加到工程里面。例如:
修改.pro
文件, 在文件按末尾增加vtk库:
INCLUDEPATH += /path/to/VTK/include/vtk-<version>
LIBS += -L/path/to/VTK/lib \
-lvtkCommonCore-<version> \
-lvtkFiltersSources-<version> \
-lvtkInteractionStyle-<version> \
-lvtkRenderingOpenGL2-<version> \
-lvtkGUISupportQt-<version>
这种做法太麻烦,尝试一次就不会再有做第二次的兴趣了。除非是在已有的qmake工程中增加VTK,否则还是不主张使用。
3. 在Qt的cmake项目中使用VTK
相对于Visual Studio, 我更喜欢使用QtCreator. 所以下面是针对的是使用QtCreator的方法.
3.1 创建一个纯Qt项目的CMake文件
首先注意一点的是,比较新的QtCreator自动创建的widget项目的cmake文件是有问题的,而且里面有很多做Windows用不到的东西,如果不跨平台,只做Windows上位机程序,还是按照它的文档手工写文件比较好,做出来的cmake文件更干净一些。
下面是一个支持GUI的CMakeLists.txt
文件:
# GUI和Console都需要的部分
cmake_minimum_required(VERSION 3.16)
project(exam01 VERSION 1.0.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Console项目只需要Core组件.
find_package(Qt6 REQUIRED COMPONENTS Core)
#如果是GUI, 至少要将Widgets加进去. Widgets自动包含Core了
find_package(Qt6 REQUIRED COMPONENTS Widgets)
# 如果需要添加多语种支持, 加入LinguistTools
find_package(Qt6 REQUIRED COMPONENTS LinguistTools)
# QtCreator模板生成的项目不再使用这个函数了. 但是文档中还是这个
qt_standard_project_setup()
# 我们可以自己定义多个变量来对源码自己做分类. 模板是直接加到qt_add_executable()里面.
# 我们自己分组分类更便于维护
# 按照cmake的说法, 不需要将.h文件加到makelist里面. 但是加进去也没啥.
set(PROJECT_SOURCES
main.cpp
mainwindow.cpp
mainwindow.h
mainwindow.ui
)
qt_add_executable(exam01
MANUAL_FINALIZATION
${PROJECT_SOURCES}
)
# 添加语言资源文件. 模板生成的也不用这个了. 感觉Qt团队做事情太随意了.
qt_add_translations(${PROJECT_NAME} TS_FILES exam01_zh_CN.ts)
# 如果是Core项目, 则使用Qt6::Core代替这里的Qt6::Widgets
target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Widgets
)
# Console项目不需要这个一段.
set_target_properties(${PROJECT_NAME} PROPERTIES
WIN32_EXECUTABLE ON
MACOSX_BUNDLE ON
)
3.2 添加VTK
然后, 要支持VTK,我们只需要将下面几行加到里面去:
# 添加对VTK的引用. 也可以使用COMPONENTS指定具体的组件. 对新手来说, 这个有点困难.
find_package(VTK REQUIRED)
# 在target_link_libraries里面加入${VTK_LIBRARIES}
target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Widgets
${VTK_LIBRARIES}
)
# 加入下面
vtk_module_autoinit(
TARGETS ${PROJECT_NAME}
MODULES ${VTK_LIBRARIES}
)
这样,CMake工程文件就完成了。
接下来,我们还需要找个地方实现auto_init
。这个活动需要在使用::New()
的前面进行,个人建议就放到main.cpp
里面。这样不管是Console还是GUI程序,都能利用它。比如:
...
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL2);
VTK_MODULE_INIT(vtkRenderingFreeType);
VTK_MODULE_INIT(vtkRenderingContextOpenGL2);
...
int main()
{
...
}
3.3 其他改进
接下来,我们可以考虑利用预编译头文件。这一点上,cmake做的比qmake,比VC都差了很多。尤其是VTK的头文件多如牛毛,好像也没有一个如OpenCV的opencv.hpp
这样的打包头文件,用起来很不友好。个人的建议是把你自己经常用到的头文件都定义在一起, 打包放到预编译里面, 这样自己的代码里面也用不着时不时跑到前面添加一行include了。反正预编译嘛, 头文件再多也不是什么大问题.
比如,下面我定义了一个变量PCH_FILES
,里面包含了经常用到的头文件,然后用target_precompile_headers
来声明它。如果是多子工程的项目,可以将PCH_FILES
定义到顶层文件中,每个子目录项目的cmakelists文件中使用target_precompile_headers
来引用它。
set(PCH_FILES
<QDebug>
#...
<vtkActor.h>
<vtkBMPReader.h>
<vtkImageActor.h>
<vtkJPEGReader.h>
<vtkMetaImageReader.h>
<vtkNamedColors.h>
<vtkPolyDataMapper.h>
<vtkProperty.h>
<vtkRenderer.h>
<vtkRenderWindow.h>
#...
)
target_precompile_headers(${PROJECT_NAME} PUBLIC
${PCH_FILES}
)